2018-08-12 14:03:07 +00:00
|
|
|
package com.boydti.fawe;
|
|
|
|
|
2019-11-02 11:13:42 +00:00
|
|
|
import com.boydti.fawe.beta.implementation.queue.QueueHandler;
|
2019-11-21 20:37:56 +00:00
|
|
|
import com.boydti.fawe.config.Caption;
|
2018-08-12 14:03:07 +00:00
|
|
|
import com.boydti.fawe.config.Settings;
|
|
|
|
import com.boydti.fawe.object.brush.visualization.VisualQueue;
|
2019-10-23 04:23:52 +00:00
|
|
|
import com.boydti.fawe.regions.general.integrations.plotquared.PlotSquaredFeature;
|
2019-07-25 18:44:10 +00:00
|
|
|
import com.boydti.fawe.util.CachedTextureUtil;
|
|
|
|
import com.boydti.fawe.util.CleanTextureUtil;
|
|
|
|
import com.boydti.fawe.util.FaweTimer;
|
|
|
|
import com.boydti.fawe.util.MainUtil;
|
|
|
|
import com.boydti.fawe.util.MemUtil;
|
|
|
|
import com.boydti.fawe.util.RandomTextureUtil;
|
|
|
|
import com.boydti.fawe.util.TaskManager;
|
|
|
|
import com.boydti.fawe.util.TextureUtil;
|
|
|
|
import com.boydti.fawe.util.WEManager;
|
2019-09-14 03:05:16 +00:00
|
|
|
import com.github.luben.zstd.util.Native;
|
2018-08-21 17:22:37 +00:00
|
|
|
import com.sk89q.worldedit.WorldEdit;
|
2018-08-12 14:03:07 +00:00
|
|
|
import com.sk89q.worldedit.extension.factory.DefaultTransformParser;
|
|
|
|
import com.sk89q.worldedit.extension.platform.Actor;
|
|
|
|
import com.sk89q.worldedit.session.request.Request;
|
2019-07-25 18:44:10 +00:00
|
|
|
import java.io.BufferedReader;
|
|
|
|
import java.io.File;
|
|
|
|
import java.io.FileNotFoundException;
|
|
|
|
import java.io.IOException;
|
|
|
|
import java.io.InputStream;
|
|
|
|
import java.io.InputStreamReader;
|
2018-08-12 14:03:07 +00:00
|
|
|
import java.lang.management.ManagementFactory;
|
|
|
|
import java.lang.management.MemoryMXBean;
|
|
|
|
import java.lang.management.MemoryPoolMXBean;
|
|
|
|
import java.lang.management.MemoryUsage;
|
2019-07-25 18:44:10 +00:00
|
|
|
import java.util.Date;
|
|
|
|
import java.util.List;
|
2019-11-21 20:37:56 +00:00
|
|
|
import java.util.Locale;
|
2019-07-25 18:44:10 +00:00
|
|
|
import java.util.Objects;
|
2018-08-12 14:03:07 +00:00
|
|
|
import java.util.concurrent.TimeUnit;
|
2019-07-25 18:44:10 +00:00
|
|
|
import javax.annotation.Nullable;
|
|
|
|
import javax.management.InstanceAlreadyExistsException;
|
|
|
|
import javax.management.NotificationEmitter;
|
2019-11-11 21:02:28 +00:00
|
|
|
import org.slf4j.Logger;
|
|
|
|
import org.slf4j.LoggerFactory;
|
2018-08-12 14:03:07 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* [ WorldEdit action]
|
2019-04-28 15:44:59 +00:00
|
|
|
* |
|
2018-08-12 14:03:07 +00:00
|
|
|
* \|/
|
|
|
|
* [ EditSession ] - The change is processed (area restrictions, change limit, block type)
|
2019-04-28 15:44:59 +00:00
|
|
|
* |
|
2018-08-12 14:03:07 +00:00
|
|
|
* \|/
|
|
|
|
* [Block change] - A block change from some location
|
2019-04-28 15:44:59 +00:00
|
|
|
* |
|
2018-08-12 14:03:07 +00:00
|
|
|
* \|/
|
|
|
|
* [ Set Queue ] - The SetQueue manages the implementation specific queue
|
2019-04-28 15:44:59 +00:00
|
|
|
* |
|
2018-08-12 14:03:07 +00:00
|
|
|
* \|/
|
|
|
|
* [ Fawe Queue] - A queue of chunks - check if the queue has the chunk for a change
|
2019-04-28 15:44:59 +00:00
|
|
|
* |
|
2018-08-12 14:03:07 +00:00
|
|
|
* \|/
|
|
|
|
* [ Fawe Chunk Implementation ] - Otherwise create a new FaweChunk object which is a wrapper around the Chunk object
|
2019-04-28 15:44:59 +00:00
|
|
|
* |
|
2018-08-12 14:03:07 +00:00
|
|
|
* \|/
|
|
|
|
* [ Execution ] - When done, the queue then sets the blocks for the chunk, performs lighting updates and sends the chunk packet to the clients
|
|
|
|
* <p>
|
|
|
|
* Why it's faster:
|
|
|
|
* - The chunk is modified directly rather than through the API
|
|
|
|
* \ Removes some overhead, and means some processing can be done async
|
|
|
|
* - Lighting updates are performed on the chunk level rather than for every block
|
2019-11-11 21:02:28 +00:00
|
|
|
* \ e.g., A blob of stone: only the visible blocks need to have the lighting calculated
|
2018-08-12 14:03:07 +00:00
|
|
|
* - Block changes are sent with a chunk packet
|
|
|
|
* \ A chunk packet is generally quicker to create and smaller for large world edits
|
|
|
|
* - No physics updates
|
|
|
|
* \ Physics updates are slow, and are usually performed on each block
|
|
|
|
* - Block data shortcuts
|
2019-11-11 21:02:28 +00:00
|
|
|
* \ Some known blocks don't need to have the data set or accessed (e.g., air is never going to have data)
|
2018-08-12 14:03:07 +00:00
|
|
|
* - Remove redundant extents
|
|
|
|
* \ Up to 11 layers of extents can be removed
|
|
|
|
* - History bypassing
|
|
|
|
* \ FastMode bypasses history and means blocks in the world don't need to be checked and recorded
|
|
|
|
*/
|
|
|
|
public class Fawe {
|
2019-11-11 21:02:28 +00:00
|
|
|
|
|
|
|
private static final Logger log = LoggerFactory.getLogger(Fawe.class);
|
|
|
|
|
2018-08-12 14:03:07 +00:00
|
|
|
/**
|
|
|
|
* The FAWE instance;
|
|
|
|
*/
|
|
|
|
private static Fawe INSTANCE;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* TPS timer
|
|
|
|
*/
|
|
|
|
private final FaweTimer timer;
|
|
|
|
private FaweVersion version;
|
|
|
|
private VisualQueue visualQueue;
|
|
|
|
private TextureUtil textures;
|
|
|
|
private DefaultTransformParser transformParser;
|
|
|
|
|
2019-04-30 16:19:10 +00:00
|
|
|
private QueueHandler queueHandler;
|
|
|
|
|
2018-08-12 14:03:07 +00:00
|
|
|
/**
|
|
|
|
* Get the implementation specific class
|
|
|
|
*
|
|
|
|
* @return
|
|
|
|
*/
|
|
|
|
@SuppressWarnings("unchecked")
|
|
|
|
public static <T extends IFawe> T imp() {
|
|
|
|
return INSTANCE != null ? (T) INSTANCE.IMP : null;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the implementation independent class
|
|
|
|
*
|
|
|
|
* @return
|
|
|
|
*/
|
|
|
|
public static Fawe get() {
|
|
|
|
return INSTANCE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Setup Fawe
|
|
|
|
*
|
|
|
|
* @param implementation
|
|
|
|
* @throws InstanceAlreadyExistsException
|
|
|
|
*/
|
|
|
|
public static void set(final IFawe implementation) throws InstanceAlreadyExistsException, IllegalArgumentException {
|
|
|
|
if (INSTANCE != null) {
|
|
|
|
throw new InstanceAlreadyExistsException("FAWE has already been initialized with: " + INSTANCE.IMP);
|
|
|
|
}
|
|
|
|
if (implementation == null) {
|
|
|
|
throw new IllegalArgumentException("Implementation may not be null.");
|
|
|
|
}
|
|
|
|
INSTANCE = new Fawe(implementation);
|
|
|
|
}
|
|
|
|
|
|
|
|
public static void debugPlain(String s) {
|
2018-08-16 13:21:39 +00:00
|
|
|
if (INSTANCE != null) {
|
2018-08-12 14:03:07 +00:00
|
|
|
INSTANCE.IMP.debug(s);
|
|
|
|
} else {
|
2019-08-06 15:28:12 +00:00
|
|
|
System.out.println(s);
|
2018-08-12 14:03:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Write something to the console
|
|
|
|
*
|
|
|
|
* @param s
|
|
|
|
*/
|
|
|
|
public static void debug(Object s) {
|
2018-08-16 13:21:39 +00:00
|
|
|
Actor actor = Request.request().getActor();
|
|
|
|
if (actor != null && actor.isPlayer()) {
|
2019-08-06 15:28:12 +00:00
|
|
|
actor.print((String)s);
|
2018-08-16 13:21:39 +00:00
|
|
|
return;
|
|
|
|
}
|
2019-08-06 15:28:12 +00:00
|
|
|
debugPlain((String) s);
|
2018-08-12 14:03:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The platform specific implementation
|
|
|
|
*/
|
|
|
|
private final IFawe IMP;
|
2019-03-27 16:17:05 +00:00
|
|
|
private Thread thread;
|
2018-08-12 14:03:07 +00:00
|
|
|
|
|
|
|
private Fawe(final IFawe implementation) {
|
2019-03-27 16:17:05 +00:00
|
|
|
INSTANCE = this;
|
2018-08-12 14:03:07 +00:00
|
|
|
this.IMP = implementation;
|
|
|
|
this.thread = Thread.currentThread();
|
|
|
|
/*
|
|
|
|
* Implementation dependent stuff
|
|
|
|
*/
|
|
|
|
this.setupConfigs();
|
|
|
|
TaskManager.IMP = this.IMP.getTaskManager();
|
|
|
|
|
2019-03-27 16:17:05 +00:00
|
|
|
TaskManager.IMP.async(() -> {
|
|
|
|
MainUtil.deleteOlder(MainUtil.getFile(IMP.getDirectory(), Settings.IMP.PATHS.HISTORY), TimeUnit.DAYS.toMillis(Settings.IMP.HISTORY.DELETE_AFTER_DAYS), false);
|
|
|
|
MainUtil.deleteOlder(MainUtil.getFile(IMP.getDirectory(), Settings.IMP.PATHS.CLIPBOARD), TimeUnit.DAYS.toMillis(Settings.IMP.CLIPBOARD.DELETE_AFTER_DAYS), false);
|
2018-08-12 14:03:07 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Instance independent stuff
|
|
|
|
*/
|
|
|
|
this.setupMemoryListener();
|
|
|
|
this.timer = new FaweTimer();
|
|
|
|
Fawe.this.IMP.setupVault();
|
|
|
|
|
|
|
|
// Delayed worldedit setup
|
|
|
|
TaskManager.IMP.later(() -> {
|
|
|
|
try {
|
|
|
|
transformParser = new DefaultTransformParser(getWorldEdit());
|
|
|
|
visualQueue = new VisualQueue(3);
|
2019-02-27 13:09:04 +00:00
|
|
|
WEManager.IMP.managers.addAll(Fawe.this.IMP.getMaskManagers());
|
2019-10-23 04:23:52 +00:00
|
|
|
WEManager.IMP.managers.add(new PlotSquaredFeature());
|
2019-11-11 21:02:28 +00:00
|
|
|
log.debug("Plugin 'PlotSquared' found. Using it now.");
|
2019-03-27 16:17:05 +00:00
|
|
|
} catch (Throwable ignored) {}
|
2019-07-09 07:46:27 +00:00
|
|
|
try {
|
|
|
|
imp().startMetrics();
|
2019-09-14 03:05:16 +00:00
|
|
|
} catch (Throwable e) {
|
|
|
|
debug(e.getMessage());
|
2019-07-09 07:46:27 +00:00
|
|
|
}
|
2018-08-12 14:03:07 +00:00
|
|
|
}, 0);
|
|
|
|
|
|
|
|
TaskManager.IMP.repeat(timer, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
public void onDisable() {
|
|
|
|
}
|
|
|
|
|
2019-04-30 16:19:10 +00:00
|
|
|
public QueueHandler getQueueHandler() {
|
|
|
|
if (queueHandler == null) {
|
|
|
|
synchronized (this) {
|
|
|
|
if (queueHandler == null) {
|
|
|
|
queueHandler = IMP.getQueueHandler();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return queueHandler;
|
|
|
|
}
|
|
|
|
|
2018-08-12 14:03:07 +00:00
|
|
|
public DefaultTransformParser getTransformParser() {
|
|
|
|
return transformParser;
|
|
|
|
}
|
|
|
|
|
|
|
|
public TextureUtil getCachedTextureUtil(boolean randomize, int min, int max) {
|
2019-07-22 06:02:51 +00:00
|
|
|
// TODO NOT IMPLEMENTED - optimize this by caching the default true/0/100 texture util
|
2018-08-12 14:03:07 +00:00
|
|
|
TextureUtil tu = getTextureUtil();
|
|
|
|
try {
|
|
|
|
tu = min == 0 && max == 100 ? tu : new CleanTextureUtil(tu, min, max);
|
|
|
|
tu = randomize ? new RandomTextureUtil(tu) : new CachedTextureUtil(tu);
|
|
|
|
} catch (FileNotFoundException neverHappens) {
|
|
|
|
neverHappens.printStackTrace();
|
|
|
|
}
|
|
|
|
return tu;
|
|
|
|
}
|
|
|
|
|
|
|
|
public TextureUtil getTextureUtil() {
|
|
|
|
TextureUtil tmp = textures;
|
|
|
|
if (tmp == null) {
|
|
|
|
synchronized (this) {
|
|
|
|
tmp = textures;
|
|
|
|
if (tmp == null) {
|
|
|
|
try {
|
|
|
|
textures = tmp = new TextureUtil();
|
|
|
|
tmp.loadModTextures();
|
|
|
|
} catch (IOException e) {
|
|
|
|
throw new RuntimeException(e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return tmp;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The FaweTimer is a useful class for monitoring TPS
|
|
|
|
*
|
|
|
|
* @return FaweTimer
|
|
|
|
*/
|
|
|
|
public FaweTimer getTimer() {
|
|
|
|
return timer;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The visual queue is used to queue visualizations
|
|
|
|
*
|
|
|
|
* @return
|
|
|
|
*/
|
|
|
|
public VisualQueue getVisualQueue() {
|
|
|
|
return visualQueue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The FAWE version
|
|
|
|
* - Unofficial jars may be lacking version information
|
|
|
|
*
|
|
|
|
* @return FaweVersion
|
|
|
|
*/
|
|
|
|
public
|
|
|
|
@Nullable
|
|
|
|
FaweVersion getVersion() {
|
|
|
|
return version;
|
|
|
|
}
|
|
|
|
|
|
|
|
public double getTPS() {
|
|
|
|
return timer.getTPS();
|
|
|
|
}
|
|
|
|
|
|
|
|
public void setupConfigs() {
|
2019-11-21 20:37:56 +00:00
|
|
|
MainUtil.copyFile(MainUtil.getJarFile(), "lang/strings.json", null);
|
|
|
|
// MainUtil.copyFile(MainUtil.getJarFile(), "de/message.yml", null);
|
|
|
|
// MainUtil.copyFile(MainUtil.getJarFile(), "ru/message.yml", null);
|
|
|
|
// MainUtil.copyFile(MainUtil.getJarFile(), "ru/commands.yml", null);
|
|
|
|
// MainUtil.copyFile(MainUtil.getJarFile(), "tr/message.yml", null);
|
|
|
|
// MainUtil.copyFile(MainUtil.getJarFile(), "es/message.yml", null);
|
|
|
|
// MainUtil.copyFile(MainUtil.getJarFile(), "es/commands.yml", null);
|
|
|
|
// MainUtil.copyFile(MainUtil.getJarFile(), "nl/message.yml", null);
|
|
|
|
// MainUtil.copyFile(MainUtil.getJarFile(), "fr/message.yml", null);
|
|
|
|
// MainUtil.copyFile(MainUtil.getJarFile(), "cn/message.yml", null);
|
|
|
|
// MainUtil.copyFile(MainUtil.getJarFile(), "it/message.yml", null);
|
2018-08-12 14:03:07 +00:00
|
|
|
// Setting up config.yml
|
|
|
|
File file = new File(this.IMP.getDirectory(), "config.yml");
|
|
|
|
Settings.IMP.PLATFORM = IMP.getPlatform().replace("\"", "");
|
2019-04-16 22:35:39 +00:00
|
|
|
try (InputStream stream = getClass().getResourceAsStream("/fawe.properties");
|
|
|
|
BufferedReader br = new BufferedReader(new InputStreamReader(stream))) {
|
|
|
|
String versionString = br.readLine();
|
|
|
|
String commitString = br.readLine();
|
|
|
|
String dateString = br.readLine();
|
2019-06-06 22:39:51 +00:00
|
|
|
br.close();
|
2019-04-16 22:35:39 +00:00
|
|
|
this.version = FaweVersion.tryParse(versionString, commitString, dateString);
|
2018-08-12 14:03:07 +00:00
|
|
|
Settings.IMP.DATE = new Date(100 + version.year, version.month, version.day).toGMTString();
|
2019-11-17 19:30:28 +00:00
|
|
|
Settings.IMP.BUILD = "https://ci.athion.net/job/FastAsyncWorldEdit-commanding-pipeline/" + version.build;
|
2019-04-16 22:35:39 +00:00
|
|
|
Settings.IMP.COMMIT = "https://github.com/IntellectualSites/FastAsyncWorldEdit-1.13/commit/" + Integer.toHexString(version.hash);
|
2018-08-12 14:03:07 +00:00
|
|
|
} catch (Throwable ignore) {}
|
|
|
|
try {
|
|
|
|
Settings.IMP.reload(file);
|
|
|
|
// Setting up message.yml
|
|
|
|
String lang = Objects.toString(Settings.IMP.LANGUAGE);
|
2019-11-21 20:37:56 +00:00
|
|
|
if (!lang.isEmpty()) {
|
|
|
|
getWorldEdit().getTranslationManager().setDefaultLocale(Locale.forLanguageTag(lang));
|
|
|
|
}
|
2018-08-12 14:03:07 +00:00
|
|
|
} catch (Throwable e) {
|
|
|
|
debug("====== Failed to load config ======");
|
|
|
|
debug("Please validate your yaml files:");
|
|
|
|
debug("====================================");
|
|
|
|
e.printStackTrace();
|
|
|
|
debug("====================================");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public WorldEdit getWorldEdit() {
|
|
|
|
return WorldEdit.getInstance();
|
|
|
|
}
|
|
|
|
|
|
|
|
public static void setupInjector() {
|
|
|
|
/*
|
|
|
|
* Modify the sessions
|
2019-11-11 21:02:28 +00:00
|
|
|
* - EditSession supports a custom queue, and a lot of optimizations
|
2018-08-12 14:03:07 +00:00
|
|
|
* - LocalSession supports VirtualPlayers and undo on disk
|
|
|
|
*/
|
|
|
|
if (!Settings.IMP.EXPERIMENTAL.DISABLE_NATIVES) {
|
|
|
|
try {
|
2019-09-14 03:05:16 +00:00
|
|
|
Native.load();
|
2018-08-12 14:03:07 +00:00
|
|
|
} catch (Throwable e) {
|
|
|
|
if (Settings.IMP.CLIPBOARD.COMPRESSION_LEVEL > 6 || Settings.IMP.HISTORY.COMPRESSION_LEVEL > 6) {
|
|
|
|
Settings.IMP.CLIPBOARD.COMPRESSION_LEVEL = Math.min(6, Settings.IMP.CLIPBOARD.COMPRESSION_LEVEL);
|
|
|
|
Settings.IMP.HISTORY.COMPRESSION_LEVEL = Math.min(6, Settings.IMP.HISTORY.COMPRESSION_LEVEL);
|
|
|
|
debug("====== ZSTD COMPRESSION BINDING NOT FOUND ======");
|
|
|
|
debug(e);
|
|
|
|
debug("===============================================");
|
|
|
|
debug("FAWE will work but won't compress data as much");
|
|
|
|
debug("===============================================");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
try {
|
|
|
|
net.jpountz.util.Native.load();
|
|
|
|
} catch (Throwable e) {
|
|
|
|
e.printStackTrace();
|
|
|
|
debug("====== LZ4 COMPRESSION BINDING NOT FOUND ======");
|
|
|
|
debug(e);
|
|
|
|
debug("===============================================");
|
|
|
|
debug("FAWE will work but compression will be slower");
|
|
|
|
debug(" - Try updating your JVM / OS");
|
|
|
|
debug(" - Report this issue if you cannot resolve it");
|
|
|
|
debug("===============================================");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
try {
|
|
|
|
String arch = System.getenv("PROCESSOR_ARCHITECTURE");
|
|
|
|
String wow64Arch = System.getenv("PROCESSOR_ARCHITEW6432");
|
2019-06-28 15:19:58 +00:00
|
|
|
boolean x86OS = !(arch.endsWith("64") || wow64Arch != null && wow64Arch.endsWith("64"));
|
2018-08-12 14:03:07 +00:00
|
|
|
boolean x86JVM = System.getProperty("sun.arch.data.model").equals("32");
|
|
|
|
if (x86OS != x86JVM) {
|
|
|
|
debug("====== UPGRADE TO 64-BIT JAVA ======");
|
|
|
|
debug("You are running 32-bit Java on a 64-bit machine");
|
|
|
|
debug("====================================");
|
|
|
|
}
|
|
|
|
} catch (Throwable ignore) {}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void setupMemoryListener() {
|
|
|
|
if (Settings.IMP.MAX_MEMORY_PERCENT < 1 || Settings.IMP.MAX_MEMORY_PERCENT > 99) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
try {
|
|
|
|
final MemoryMXBean memBean = ManagementFactory.getMemoryMXBean();
|
|
|
|
final NotificationEmitter ne = (NotificationEmitter) memBean;
|
|
|
|
|
2019-03-27 16:17:05 +00:00
|
|
|
ne.addNotificationListener((notification, handback) -> {
|
|
|
|
final long heapSize = Runtime.getRuntime().totalMemory();
|
|
|
|
final long heapMaxSize = Runtime.getRuntime().maxMemory();
|
|
|
|
if (heapSize < heapMaxSize) {
|
|
|
|
return;
|
2018-08-12 14:03:07 +00:00
|
|
|
}
|
2019-03-27 16:17:05 +00:00
|
|
|
MemUtil.memoryLimitedTask();
|
2018-08-12 14:03:07 +00:00
|
|
|
}, null, null);
|
|
|
|
|
|
|
|
final List<MemoryPoolMXBean> memPools = ManagementFactory.getMemoryPoolMXBeans();
|
|
|
|
for (final MemoryPoolMXBean mp : memPools) {
|
|
|
|
if (mp.isUsageThresholdSupported()) {
|
|
|
|
final MemoryUsage mu = mp.getUsage();
|
|
|
|
final long max = mu.getMax();
|
|
|
|
if (max < 0) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
final long alert = (max * Settings.IMP.MAX_MEMORY_PERCENT) / 100;
|
|
|
|
mp.setUsageThreshold(alert);
|
|
|
|
}
|
|
|
|
}
|
2019-09-14 03:05:16 +00:00
|
|
|
} catch (Throwable ignored) {
|
2018-08-12 14:03:07 +00:00
|
|
|
debug("====== MEMORY LISTENER ERROR ======");
|
|
|
|
debug("===================================");
|
|
|
|
debug("FAWE needs access to the JVM memory system:");
|
|
|
|
debug(" - Change your Java security settings");
|
|
|
|
debug(" - Disable this with `max-memory-percent: -1`");
|
|
|
|
debug("===================================");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the main thread
|
|
|
|
*
|
|
|
|
* @return
|
|
|
|
*/
|
|
|
|
public Thread getMainThread() {
|
|
|
|
return this.thread;
|
|
|
|
}
|
|
|
|
|
|
|
|
public static boolean isMainThread() {
|
2019-06-04 15:48:30 +00:00
|
|
|
return INSTANCE == null || INSTANCE.thread == Thread.currentThread();
|
2018-08-12 14:03:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sets the main thread to the current thread
|
|
|
|
*
|
|
|
|
* @return
|
|
|
|
*/
|
|
|
|
public Thread setMainThread() {
|
|
|
|
return this.thread = Thread.currentThread();
|
|
|
|
}
|
|
|
|
}
|