2021-07-01 20:16:25 +00:00
|
|
|
package com.fastasyncworldedit.core;
|
2018-08-12 14:03:07 +00:00
|
|
|
|
2021-07-01 20:16:25 +00:00
|
|
|
import com.fastasyncworldedit.core.configuration.Settings;
|
2021-07-24 15:34:05 +00:00
|
|
|
import com.fastasyncworldedit.core.queue.implementation.QueueHandler;
|
2021-07-01 20:16:25 +00:00
|
|
|
import com.fastasyncworldedit.core.util.CachedTextureUtil;
|
|
|
|
import com.fastasyncworldedit.core.util.CleanTextureUtil;
|
|
|
|
import com.fastasyncworldedit.core.util.FaweTimer;
|
|
|
|
import com.fastasyncworldedit.core.util.MainUtil;
|
|
|
|
import com.fastasyncworldedit.core.util.MemUtil;
|
|
|
|
import com.fastasyncworldedit.core.util.RandomTextureUtil;
|
|
|
|
import com.fastasyncworldedit.core.util.TaskManager;
|
|
|
|
import com.fastasyncworldedit.core.util.TextureUtil;
|
|
|
|
import com.fastasyncworldedit.core.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;
|
2021-03-29 13:29:16 +00:00
|
|
|
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
|
|
|
import org.apache.logging.log4j.Logger;
|
2020-07-14 02:50:59 +00:00
|
|
|
|
2021-07-24 15:34:05 +00:00
|
|
|
import javax.annotation.Nullable;
|
|
|
|
import javax.management.InstanceAlreadyExistsException;
|
|
|
|
import javax.management.NotificationEmitter;
|
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;
|
2018-08-12 14:03:07 +00:00
|
|
|
import java.util.concurrent.TimeUnit;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* [ WorldEdit action]
|
2021-07-24 15:34:05 +00:00
|
|
|
* |
|
2018-08-12 14:03:07 +00:00
|
|
|
* \|/
|
|
|
|
* [ EditSession ] - The change is processed (area restrictions, change limit, block type)
|
2021-07-24 15:34:05 +00:00
|
|
|
* |
|
2018-08-12 14:03:07 +00:00
|
|
|
* \|/
|
|
|
|
* [Block change] - A block change from some location
|
2021-07-24 15:34:05 +00:00
|
|
|
* |
|
2018-08-12 14:03:07 +00:00
|
|
|
* \|/
|
|
|
|
* [ Set Queue ] - The SetQueue manages the implementation specific queue
|
2021-07-24 15:34:05 +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
|
2021-07-24 15:34:05 +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
|
2021-07-24 15:34:05 +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
|
|
|
|
2021-03-29 13:29:16 +00:00
|
|
|
private static final Logger LOGGER = LogManagerCompat.getLogger();
|
2019-11-11 21:02:28 +00:00
|
|
|
|
2020-10-05 17:41:41 +00:00
|
|
|
private static Fawe instance;
|
2018-08-12 14:03:07 +00:00
|
|
|
|
|
|
|
/**
|
2020-10-05 17:41:41 +00:00
|
|
|
* The ticks-per-second timer.
|
2018-08-12 14:03:07 +00:00
|
|
|
*/
|
|
|
|
private final FaweTimer timer;
|
|
|
|
private FaweVersion version;
|
|
|
|
private TextureUtil textures;
|
2020-10-05 17:41:41 +00:00
|
|
|
|
2018-08-12 14:03:07 +00:00
|
|
|
|
2019-04-30 16:19:10 +00:00
|
|
|
private QueueHandler queueHandler;
|
|
|
|
|
2018-08-12 14:03:07 +00:00
|
|
|
/**
|
2020-10-05 17:41:41 +00:00
|
|
|
* Get the implementation specific class.
|
2018-08-12 14:03:07 +00:00
|
|
|
*/
|
|
|
|
@SuppressWarnings("unchecked")
|
|
|
|
public static <T extends IFawe> T imp() {
|
2020-10-05 17:41:41 +00:00
|
|
|
return instance != null ? (T) instance.implementation : null;
|
2018-08-12 14:03:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2020-10-05 17:41:41 +00:00
|
|
|
* Get the implementation independent class.
|
2018-08-12 14:03:07 +00:00
|
|
|
*/
|
|
|
|
public static Fawe get() {
|
2020-10-05 17:41:41 +00:00
|
|
|
return instance;
|
2018-08-12 14:03:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2020-10-05 17:41:41 +00:00
|
|
|
* This method is not for public use. If you have to ask what it does then you shouldn't be using it.
|
2018-08-12 14:03:07 +00:00
|
|
|
*/
|
|
|
|
public static void set(final IFawe implementation) throws InstanceAlreadyExistsException, IllegalArgumentException {
|
2020-10-05 17:41:41 +00:00
|
|
|
if (instance != null) {
|
|
|
|
throw new InstanceAlreadyExistsException("FAWE has already been initialized with: " + instance.implementation);
|
2018-08-12 14:03:07 +00:00
|
|
|
}
|
|
|
|
if (implementation == null) {
|
|
|
|
throw new IllegalArgumentException("Implementation may not be null.");
|
|
|
|
}
|
2020-10-05 17:41:41 +00:00
|
|
|
instance = new Fawe(implementation);
|
2018-08-12 14:03:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2020-10-05 17:41:41 +00:00
|
|
|
* The platform specific implementation.
|
2018-08-12 14:03:07 +00:00
|
|
|
*/
|
2020-10-05 17:41:41 +00:00
|
|
|
private final IFawe implementation;
|
2020-01-23 19:41:57 +00:00
|
|
|
private Thread thread;
|
2018-08-12 14:03:07 +00:00
|
|
|
|
|
|
|
private Fawe(final IFawe implementation) {
|
2020-10-05 17:41:41 +00:00
|
|
|
instance = this;
|
|
|
|
this.implementation = implementation;
|
2018-08-12 14:03:07 +00:00
|
|
|
this.thread = Thread.currentThread();
|
|
|
|
/*
|
|
|
|
* Implementation dependent stuff
|
|
|
|
*/
|
|
|
|
this.setupConfigs();
|
2020-10-05 17:41:41 +00:00
|
|
|
TaskManager.IMP = this.implementation.getTaskManager();
|
2018-08-12 14:03:07 +00:00
|
|
|
|
2019-03-27 16:17:05 +00:00
|
|
|
TaskManager.IMP.async(() -> {
|
2021-07-24 15:34:05 +00:00
|
|
|
MainUtil.deleteOlder(
|
|
|
|
MainUtil.getFile(this.implementation
|
|
|
|
.getDirectory(), Settings.IMP.PATHS.HISTORY),
|
|
|
|
TimeUnit.DAYS.toMillis(Settings.IMP.HISTORY.DELETE_AFTER_DAYS),
|
|
|
|
false
|
|
|
|
);
|
|
|
|
MainUtil.deleteOlder(
|
|
|
|
MainUtil.getFile(this.implementation
|
|
|
|
.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();
|
|
|
|
|
|
|
|
// Delayed worldedit setup
|
|
|
|
TaskManager.IMP.later(() -> {
|
|
|
|
try {
|
2020-10-05 17:41:41 +00:00
|
|
|
WEManager.IMP.managers.addAll(Fawe.this.implementation.getMaskManagers());
|
|
|
|
} catch (Throwable ignored) {
|
|
|
|
}
|
2018-08-12 14:03:07 +00:00
|
|
|
}, 0);
|
|
|
|
|
|
|
|
TaskManager.IMP.repeat(timer, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
public void onDisable() {
|
2021-08-17 00:47:09 +00:00
|
|
|
if (imp().getPreloader(false) != null) {
|
|
|
|
imp().getPreloader(false).cancel();
|
|
|
|
}
|
2018-08-12 14:03:07 +00:00
|
|
|
}
|
|
|
|
|
2019-04-30 16:19:10 +00:00
|
|
|
public QueueHandler getQueueHandler() {
|
|
|
|
if (queueHandler == null) {
|
|
|
|
synchronized (this) {
|
|
|
|
if (queueHandler == null) {
|
2020-10-05 17:41:41 +00:00
|
|
|
queueHandler = implementation.getQueueHandler();
|
2019-04-30 16:19:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return queueHandler;
|
|
|
|
}
|
2018-08-12 14:03:07 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2020-10-05 17:41:41 +00:00
|
|
|
* Gets the TPS monitor.
|
2018-08-12 14:03:07 +00:00
|
|
|
*/
|
|
|
|
public FaweTimer getTimer() {
|
|
|
|
return timer;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2020-10-05 17:41:41 +00:00
|
|
|
* The FAWE version.
|
2018-08-12 14:03:07 +00:00
|
|
|
*
|
|
|
|
* @return FaweVersion
|
|
|
|
*/
|
|
|
|
@Nullable
|
2020-10-05 17:41:41 +00:00
|
|
|
public FaweVersion getVersion() {
|
2018-08-12 14:03:07 +00:00
|
|
|
return version;
|
|
|
|
}
|
|
|
|
|
|
|
|
public double getTPS() {
|
|
|
|
return timer.getTPS();
|
|
|
|
}
|
|
|
|
|
|
|
|
public void setupConfigs() {
|
2020-06-19 07:12:58 +00:00
|
|
|
MainUtil.copyFile(MainUtil.getJarFile(), "lang/strings.json", null);
|
2018-08-12 14:03:07 +00:00
|
|
|
// Setting up config.yml
|
2020-10-05 17:41:41 +00:00
|
|
|
File file = new File(this.implementation.getDirectory(), "config.yml");
|
|
|
|
Settings.IMP.PLATFORM = implementation.getPlatform().replace("\"", "");
|
2020-12-31 17:45:07 +00:00
|
|
|
try (InputStream stream = getClass().getResourceAsStream("/fawe.properties");
|
2021-07-24 15:34:05 +00:00
|
|
|
BufferedReader br = new BufferedReader(new InputStreamReader(stream))) {
|
2019-04-16 22:35:39 +00:00
|
|
|
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);
|
2020-10-15 16:23:10 +00:00
|
|
|
Settings.IMP.DATE = new Date(100 + version.year, version.month, version.day).toString();
|
2021-07-01 20:16:25 +00:00
|
|
|
Settings.IMP.BUILD = "https://ci.athion.net/job/FastAsyncWorldEdit-1.17/" + version.build;
|
2020-05-30 07:17:21 +00:00
|
|
|
Settings.IMP.COMMIT = "https://github.com/IntellectualSites/FastAsyncWorldEdit/commit/" + Integer.toHexString(version.hash);
|
2020-10-05 17:41:41 +00:00
|
|
|
} catch (Throwable ignored) {
|
|
|
|
}
|
2018-08-12 14:03:07 +00:00
|
|
|
try {
|
|
|
|
Settings.IMP.reload(file);
|
|
|
|
} catch (Throwable e) {
|
2021-03-29 13:29:16 +00:00
|
|
|
LOGGER.error("Failed to load config.", e);
|
2018-08-12 14:03:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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);
|
2021-03-29 13:29:16 +00:00
|
|
|
LOGGER.error("ZSTD Compression Binding Not Found.\n"
|
2021-07-24 15:34:05 +00:00
|
|
|
+ "FAWE will still work but compression won't work as well.\n", e);
|
2018-08-12 14:03:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
try {
|
|
|
|
net.jpountz.util.Native.load();
|
|
|
|
} catch (Throwable e) {
|
2021-03-29 13:29:16 +00:00
|
|
|
LOGGER.error("LZ4 Compression Binding Not Found.\n"
|
2021-07-24 15:34:05 +00:00
|
|
|
+ "FAWE will still work but compression will be slower.\n", e);
|
2018-08-12 14:03:07 +00:00
|
|
|
}
|
|
|
|
}
|
2020-03-29 22:47:32 +00:00
|
|
|
|
|
|
|
// Check Base OS Arch for Mismatching Architectures
|
|
|
|
boolean x86OS = System.getProperty("sun.arch.data.model").contains("32");
|
|
|
|
boolean x86JVM = System.getProperty("os.arch").contains("32");
|
2020-02-21 04:59:57 +00:00
|
|
|
if (x86OS != x86JVM) {
|
2021-03-29 13:29:16 +00:00
|
|
|
LOGGER.info("You are running 32-bit Java on a 64-bit machine. Please upgrade to 64-bit Java.");
|
2020-02-21 04:59:57 +00:00
|
|
|
}
|
2018-08-12 14:03:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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) {
|
2021-03-29 13:29:16 +00:00
|
|
|
LOGGER.error("FAWE encountered an error trying to listen to JVM memory.\n"
|
2021-07-24 15:34:05 +00:00
|
|
|
+ "Please change your Java security settings or disable this message by"
|
|
|
|
+ "changing 'max-memory-percent' in the config files to '-1'.");
|
2018-08-12 14:03:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2020-10-05 17:41:41 +00:00
|
|
|
* Get the main thread.
|
2018-08-12 14:03:07 +00:00
|
|
|
*/
|
|
|
|
public Thread getMainThread() {
|
|
|
|
return this.thread;
|
|
|
|
}
|
|
|
|
|
|
|
|
public static boolean isMainThread() {
|
2020-10-05 17:41:41 +00:00
|
|
|
return instance == null || instance.thread == Thread.currentThread();
|
2018-08-12 14:03:07 +00:00
|
|
|
}
|
|
|
|
|
2020-01-23 19:41:57 +00:00
|
|
|
/**
|
2020-10-05 17:41:41 +00:00
|
|
|
* Sets the main thread to the current thread.
|
2020-01-23 19:41:57 +00:00
|
|
|
*/
|
|
|
|
public Thread setMainThread() {
|
|
|
|
return this.thread = Thread.currentThread();
|
|
|
|
}
|
2021-07-24 15:34:05 +00:00
|
|
|
|
2018-08-12 14:03:07 +00:00
|
|
|
}
|