2018-08-12 14:03:07 +00:00
|
|
|
package com.boydti.fawe;
|
|
|
|
|
2020-01-16 01:38:46 +00:00
|
|
|
import com.boydti.fawe.beta.IQueueChunk;
|
2019-07-18 20:23:00 +00:00
|
|
|
import com.boydti.fawe.beta.IQueueExtent;
|
2020-05-27 10:45:08 +00:00
|
|
|
import com.boydti.fawe.beta.implementation.lighting.NMSRelighter;
|
|
|
|
import com.boydti.fawe.beta.implementation.queue.ParallelQueueExtent;
|
2018-08-12 14:03:07 +00:00
|
|
|
import com.boydti.fawe.config.Settings;
|
|
|
|
import com.boydti.fawe.object.RegionWrapper;
|
2020-05-27 10:45:08 +00:00
|
|
|
import com.boydti.fawe.object.RelightMode;
|
2018-08-12 14:03:07 +00:00
|
|
|
import com.boydti.fawe.object.changeset.DiskStorageHistory;
|
2020-01-07 00:41:41 +00:00
|
|
|
import com.boydti.fawe.object.changeset.SimpleChangeSetSummary;
|
2019-07-09 07:18:51 +00:00
|
|
|
import com.boydti.fawe.object.exception.FaweException;
|
2018-08-12 14:03:07 +00:00
|
|
|
import com.boydti.fawe.regions.FaweMaskManager;
|
|
|
|
import com.boydti.fawe.util.EditSessionBuilder;
|
|
|
|
import com.boydti.fawe.util.MainUtil;
|
|
|
|
import com.boydti.fawe.util.MemUtil;
|
|
|
|
import com.boydti.fawe.util.TaskManager;
|
|
|
|
import com.boydti.fawe.util.WEManager;
|
|
|
|
import com.boydti.fawe.wrappers.WorldWrapper;
|
2019-03-26 17:41:09 +00:00
|
|
|
import com.google.common.collect.Sets;
|
2018-08-12 14:03:07 +00:00
|
|
|
import com.sk89q.worldedit.EditSession;
|
|
|
|
import com.sk89q.worldedit.WorldEdit;
|
|
|
|
import com.sk89q.worldedit.WorldEditException;
|
2019-09-14 03:05:16 +00:00
|
|
|
import com.sk89q.worldedit.entity.Player;
|
2018-08-12 14:03:07 +00:00
|
|
|
import com.sk89q.worldedit.extension.platform.Capability;
|
|
|
|
import com.sk89q.worldedit.extension.platform.Platform;
|
2020-02-18 19:27:05 +00:00
|
|
|
import com.sk89q.worldedit.extent.AbstractDelegateExtent;
|
2018-08-12 14:03:07 +00:00
|
|
|
import com.sk89q.worldedit.extent.Extent;
|
|
|
|
import com.sk89q.worldedit.extent.clipboard.Clipboard;
|
|
|
|
import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat;
|
2019-01-31 15:08:58 +00:00
|
|
|
import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormats;
|
2020-05-27 10:45:08 +00:00
|
|
|
import com.sk89q.worldedit.math.BlockVector3;
|
2018-08-12 14:03:07 +00:00
|
|
|
import com.sk89q.worldedit.regions.Region;
|
2019-06-28 14:13:30 +00:00
|
|
|
import com.sk89q.worldedit.util.Location;
|
2020-01-03 17:02:18 +00:00
|
|
|
import com.sk89q.worldedit.util.formatting.text.Component;
|
2018-08-12 14:03:07 +00:00
|
|
|
import com.sk89q.worldedit.world.World;
|
2020-05-27 10:45:08 +00:00
|
|
|
|
2018-08-12 14:03:07 +00:00
|
|
|
import java.io.File;
|
|
|
|
import java.io.IOException;
|
|
|
|
import java.net.URL;
|
|
|
|
import java.util.ArrayList;
|
|
|
|
import java.util.HashSet;
|
|
|
|
import java.util.List;
|
2019-11-21 20:37:56 +00:00
|
|
|
import java.util.Locale;
|
|
|
|
import java.util.Map;
|
2018-08-12 14:03:07 +00:00
|
|
|
import java.util.Set;
|
|
|
|
import java.util.UUID;
|
2020-07-14 02:50:59 +00:00
|
|
|
import javax.annotation.Nullable;
|
2018-08-12 14:03:07 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* The FaweAPI class offers a few useful functions.<br>
|
|
|
|
* - This class is not intended to replace the WorldEdit API<br>
|
|
|
|
* - With FAWE installed, you can use the EditSession and other WorldEdit classes from an async thread.<br>
|
|
|
|
* <br>
|
|
|
|
* FaweAPI.[some method]
|
|
|
|
*/
|
|
|
|
public class FaweAPI {
|
2020-10-05 17:41:41 +00:00
|
|
|
|
2018-08-12 14:03:07 +00:00
|
|
|
/**
|
2020-10-05 17:41:41 +00:00
|
|
|
* Offers a lot of options for building an EditSession.
|
2018-08-12 14:03:07 +00:00
|
|
|
*
|
|
|
|
* @return A new EditSessionBuilder
|
2019-06-19 03:43:06 +00:00
|
|
|
* @see EditSessionBuilder
|
2018-08-12 14:03:07 +00:00
|
|
|
*/
|
2020-10-05 17:41:41 +00:00
|
|
|
@Deprecated
|
2018-08-12 14:03:07 +00:00
|
|
|
public static EditSessionBuilder getEditSessionBuilder(World world) {
|
|
|
|
return new EditSessionBuilder(world);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2020-10-05 17:41:41 +00:00
|
|
|
* The TaskManager has some useful methods for doing things asynchronously.
|
2018-08-12 14:03:07 +00:00
|
|
|
*
|
|
|
|
* @return TaskManager
|
|
|
|
*/
|
|
|
|
public static TaskManager getTaskManager() {
|
|
|
|
return TaskManager.IMP;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2020-10-05 17:41:41 +00:00
|
|
|
* You can either use a {@code IQueueExtent} or an {@code EditSession} to change blocks.
|
2018-08-12 14:03:07 +00:00
|
|
|
*
|
2020-10-05 17:41:41 +00:00
|
|
|
* <p>
|
|
|
|
* The {@link IQueueExtent} skips a bit of overhead, so it is marginally faster. {@link
|
|
|
|
* EditSession} can do a lot more. Remember to commit when you are done!
|
|
|
|
* </p>
|
|
|
|
*
|
|
|
|
* @param world The name of the world
|
2020-01-03 17:02:18 +00:00
|
|
|
* @param autoQueue If it should start dispatching before you enqueue it.
|
|
|
|
* @return the queue extent
|
2018-08-12 14:03:07 +00:00
|
|
|
*/
|
2020-01-16 01:38:46 +00:00
|
|
|
public static IQueueExtent<IQueueChunk> createQueue(World world, boolean autoQueue) {
|
|
|
|
IQueueExtent<IQueueChunk> queue = Fawe.get().getQueueHandler().getQueue(world);
|
2020-01-03 17:02:18 +00:00
|
|
|
if (!autoQueue) {
|
2019-07-18 20:23:00 +00:00
|
|
|
queue.disableQueue();
|
|
|
|
}
|
|
|
|
return queue;
|
2018-08-12 14:03:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public static World getWorld(String worldName) {
|
|
|
|
Platform platform = WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.WORLD_EDITING);
|
|
|
|
List<? extends World> worlds = platform.getWorlds();
|
|
|
|
for (World current : worlds) {
|
|
|
|
if (current.getName().equals(worldName)) {
|
2019-03-26 17:41:09 +00:00
|
|
|
return WorldWrapper.wrap(current);
|
2018-08-12 14:03:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2020-10-05 17:41:41 +00:00
|
|
|
* Upload the clipboard to the configured web interface.
|
2018-08-12 14:03:07 +00:00
|
|
|
*
|
|
|
|
* @param clipboard The clipboard (may not be null)
|
2020-10-05 17:41:41 +00:00
|
|
|
* @param format The format to use (some formats may not be supported)
|
2018-08-12 14:03:07 +00:00
|
|
|
* @return The download URL or null
|
|
|
|
*/
|
|
|
|
public static URL upload(final Clipboard clipboard, final ClipboardFormat format) {
|
2020-03-24 00:48:58 +00:00
|
|
|
return format.upload(clipboard);
|
2018-08-12 14:03:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2020-10-05 17:41:41 +00:00
|
|
|
* Just forwards to ClipboardFormat.SCHEMATIC.load(file).
|
2018-08-12 14:03:07 +00:00
|
|
|
*
|
2020-01-03 17:02:18 +00:00
|
|
|
* @param file the file to load
|
|
|
|
* @return a clipboard containing the schematic
|
2019-06-19 03:43:06 +00:00
|
|
|
* @see ClipboardFormat
|
2018-08-12 14:03:07 +00:00
|
|
|
*/
|
2019-11-02 11:13:42 +00:00
|
|
|
public static Clipboard load(File file) throws IOException {
|
2019-01-31 15:08:58 +00:00
|
|
|
return ClipboardFormats.findByFile(file).load(file);
|
2018-08-12 14:03:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get a list of supported protection plugin masks.
|
|
|
|
*
|
|
|
|
* @return Set of FaweMaskManager
|
|
|
|
*/
|
|
|
|
public static Set<FaweMaskManager> getMaskManagers() {
|
|
|
|
return new HashSet<>(WEManager.IMP.managers);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2020-10-05 17:41:41 +00:00
|
|
|
* Check if the server has more than the configured low memory threshold.
|
2018-08-12 14:03:07 +00:00
|
|
|
*
|
|
|
|
* @return True if the server has limited memory
|
|
|
|
*/
|
|
|
|
public static boolean isMemoryLimited() {
|
|
|
|
return MemUtil.isMemoryLimited();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2020-10-05 17:41:41 +00:00
|
|
|
* Get a player's allowed WorldEdit region.
|
2018-08-12 14:03:07 +00:00
|
|
|
*/
|
2019-09-14 03:05:16 +00:00
|
|
|
public static Region[] getRegions(Player player) {
|
2018-08-12 14:03:07 +00:00
|
|
|
return WEManager.IMP.getMask(player);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2020-10-05 17:41:41 +00:00
|
|
|
* Cancel the edit with the following extent.
|
2018-08-12 14:03:07 +00:00
|
|
|
*
|
2020-10-05 17:41:41 +00:00
|
|
|
* <p>
|
|
|
|
* The extent must be the one being used by an EditSession, otherwise an error will be thrown.
|
|
|
|
* Insert an extent into the EditSession using the EditSessionEvent.
|
|
|
|
* </p>
|
|
|
|
*
|
|
|
|
* @see EditSession#getRegionExtent() How to get the FaweExtent for an EditSession
|
2018-08-12 14:03:07 +00:00
|
|
|
*/
|
2020-02-18 19:27:05 +00:00
|
|
|
public static void cancelEdit(AbstractDelegateExtent extent, Component reason) {
|
2018-08-12 14:03:07 +00:00
|
|
|
try {
|
2019-07-09 07:18:51 +00:00
|
|
|
WEManager.IMP.cancelEdit(extent, new FaweException(reason));
|
2020-10-05 17:41:41 +00:00
|
|
|
} catch (WorldEditException ignored) {
|
2018-08-12 14:03:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public static void addMaskManager(FaweMaskManager maskMan) {
|
|
|
|
WEManager.IMP.managers.add(maskMan);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2020-10-05 17:41:41 +00:00
|
|
|
* Get the DiskStorageHistory object representing a File.
|
2018-08-12 14:03:07 +00:00
|
|
|
*/
|
|
|
|
public static DiskStorageHistory getChangeSetFromFile(File file) {
|
|
|
|
if (!file.exists() || file.isDirectory()) {
|
|
|
|
throw new IllegalArgumentException("Not a file!");
|
|
|
|
}
|
|
|
|
if (Settings.IMP.HISTORY.USE_DISK) {
|
|
|
|
throw new IllegalArgumentException("History on disk not enabled!");
|
|
|
|
}
|
2020-10-05 17:41:41 +00:00
|
|
|
if (!file.getName().toLowerCase(Locale.ROOT).endsWith(".bd")) {
|
2020-02-14 19:35:11 +00:00
|
|
|
throw new IllegalArgumentException("Not a BD file!");
|
|
|
|
}
|
2018-08-12 14:03:07 +00:00
|
|
|
String[] path = file.getPath().split(File.separator);
|
|
|
|
if (path.length < 3) {
|
|
|
|
throw new IllegalArgumentException("Not in history directory!");
|
|
|
|
}
|
|
|
|
String worldName = path[path.length - 3];
|
|
|
|
String uuidString = path[path.length - 2];
|
|
|
|
World world = getWorld(worldName);
|
|
|
|
if (world == null) {
|
|
|
|
throw new IllegalArgumentException("Corresponding world does not exist: " + worldName);
|
|
|
|
}
|
|
|
|
UUID uuid;
|
|
|
|
try {
|
|
|
|
uuid = UUID.fromString(uuidString);
|
|
|
|
} catch (IllegalArgumentException e) {
|
|
|
|
throw new IllegalArgumentException("Invalid UUID from file path: " + uuidString);
|
|
|
|
}
|
2020-02-14 19:35:11 +00:00
|
|
|
return new DiskStorageHistory(world, uuid, Integer.parseInt(file.getName().split("\\.")[0]));
|
2018-08-12 14:03:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2020-10-05 17:41:41 +00:00
|
|
|
* Used in the rollback to generate a list of {@link DiskStorageHistory} objects.
|
2018-08-12 14:03:07 +00:00
|
|
|
*
|
2020-10-05 17:41:41 +00:00
|
|
|
* @param origin - The origin location
|
|
|
|
* @param user - The uuid (may be null)
|
|
|
|
* @param radius - The radius from the origin of the edit
|
2018-08-12 14:03:07 +00:00
|
|
|
* @param timediff - The max age of the file in milliseconds
|
2020-10-05 17:41:41 +00:00
|
|
|
* @param shallow - If shallow is true, FAWE will only read the first {@link
|
|
|
|
* Settings.HISTORY#BUFFER_SIZE} bytes to obtain history info
|
2020-02-14 19:35:11 +00:00
|
|
|
* @return a list of DiskStorageHistory Objects
|
2020-10-05 17:41:41 +00:00
|
|
|
* @apiNote An edit outside the radius may be included if it overlaps with an edit inside
|
|
|
|
* that depends on it. Reading only part of the file will result in unreliable bounds info
|
|
|
|
* for large edits.
|
2018-08-12 14:03:07 +00:00
|
|
|
*/
|
2019-06-28 14:13:30 +00:00
|
|
|
public static List<DiskStorageHistory> getBDFiles(Location origin, UUID user, int radius, long timediff, boolean shallow) {
|
|
|
|
Extent extent = origin.getExtent();
|
|
|
|
if (!(extent instanceof World)) {
|
|
|
|
throw new IllegalArgumentException("Origin is not a valid world");
|
|
|
|
}
|
|
|
|
World world = (World) extent;
|
2020-02-12 21:18:36 +00:00
|
|
|
File history = MainUtil.getFile(Fawe.imp().getDirectory(), Settings.IMP.PATHS.HISTORY + File.separator + world.getName());
|
2018-08-12 14:03:07 +00:00
|
|
|
if (!history.exists()) {
|
|
|
|
return new ArrayList<>();
|
|
|
|
}
|
|
|
|
long now = System.currentTimeMillis();
|
|
|
|
ArrayList<File> files = new ArrayList<>();
|
|
|
|
for (File userFile : history.listFiles()) {
|
|
|
|
if (!userFile.isDirectory()) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
UUID userUUID;
|
|
|
|
try {
|
|
|
|
userUUID = UUID.fromString(userFile.getName());
|
|
|
|
} catch (IllegalArgumentException e) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (user != null && !userUUID.equals(user)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
ArrayList<Integer> ids = new ArrayList<>();
|
|
|
|
for (File file : userFile.listFiles()) {
|
|
|
|
if (file.getName().endsWith(".bd")) {
|
|
|
|
if (timediff >= Integer.MAX_VALUE || now - file.lastModified() <= timediff) {
|
|
|
|
files.add(file);
|
|
|
|
if (files.size() > 2048) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-03-26 17:41:09 +00:00
|
|
|
files.sort((a, b) -> {
|
|
|
|
String aName = a.getName();
|
|
|
|
String bName = b.getName();
|
|
|
|
int aI = Integer.parseInt(aName.substring(0, aName.length() - 3));
|
|
|
|
int bI = Integer.parseInt(bName.substring(0, bName.length() - 3));
|
|
|
|
long value = aI - bI;
|
|
|
|
return value == 0 ? 0 : value < 0 ? -1 : 1;
|
2018-08-12 14:03:07 +00:00
|
|
|
});
|
2019-06-28 14:13:30 +00:00
|
|
|
RegionWrapper bounds = new RegionWrapper(origin.getBlockX() - radius, origin.getBlockX() + radius, origin.getBlockZ() - radius, origin.getBlockZ() + radius);
|
2018-08-12 14:03:07 +00:00
|
|
|
RegionWrapper boundsPlus = new RegionWrapper(bounds.minX - 64, bounds.maxX + 512, bounds.minZ - 64, bounds.maxZ + 512);
|
2019-03-26 17:41:09 +00:00
|
|
|
HashSet<RegionWrapper> regionSet = Sets.<RegionWrapper>newHashSet(bounds);
|
2018-08-12 14:03:07 +00:00
|
|
|
ArrayList<DiskStorageHistory> result = new ArrayList<>();
|
|
|
|
for (File file : files) {
|
|
|
|
UUID uuid = UUID.fromString(file.getParentFile().getName());
|
|
|
|
DiskStorageHistory dsh = new DiskStorageHistory(world, uuid, Integer.parseInt(file.getName().split("\\.")[0]));
|
2020-01-06 08:36:16 +00:00
|
|
|
SimpleChangeSetSummary summary = dsh.summarize(boundsPlus, shallow);
|
2018-08-12 14:03:07 +00:00
|
|
|
RegionWrapper region = new RegionWrapper(summary.minX, summary.maxX, summary.minZ, summary.maxZ);
|
|
|
|
boolean encompassed = false;
|
|
|
|
boolean isIn = false;
|
|
|
|
for (RegionWrapper allowed : regionSet) {
|
|
|
|
isIn = isIn || allowed.intersects(region);
|
|
|
|
if (encompassed = allowed.isIn(region.minX, region.maxX) && allowed.isIn(region.minZ, region.maxZ)) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (isIn) {
|
|
|
|
result.add(0, dsh);
|
|
|
|
if (!encompassed) {
|
|
|
|
regionSet.add(region);
|
|
|
|
}
|
|
|
|
if (shallow && result.size() > 64) {
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The DiskStorageHistory class is what FAWE uses to represent the undo on disk.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
public static DiskStorageHistory getChangeSetFromDisk(World world, UUID uuid, int index) {
|
|
|
|
return new DiskStorageHistory(world, uuid, index);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2020-10-05 17:41:41 +00:00
|
|
|
* Fix the lighting in a selection. This is a multi-step process as outlined below.
|
2018-08-12 14:03:07 +00:00
|
|
|
*
|
2020-10-05 17:41:41 +00:00
|
|
|
* <ol>
|
|
|
|
* <li>Removes all lighting, then relights.</li>
|
|
|
|
* <li>Relights in parallel (if enabled) for best performance.</li>
|
|
|
|
* <li>Resends the chunks to the client.</li>
|
|
|
|
* </ol>
|
2018-08-12 14:03:07 +00:00
|
|
|
*
|
2020-05-27 10:45:08 +00:00
|
|
|
* @param world World to relight in
|
|
|
|
* @param selection Region to relight
|
|
|
|
* @param queue Queue to relight in/from
|
|
|
|
* @param mode The mode to relight with
|
|
|
|
* @return Chunks changed
|
2018-08-12 14:03:07 +00:00
|
|
|
*/
|
2020-05-27 10:45:08 +00:00
|
|
|
public static int fixLighting(World world, Region selection, @Nullable IQueueExtent<IQueueChunk> queue, final RelightMode mode) {
|
|
|
|
final BlockVector3 bot = selection.getMinimumPoint();
|
|
|
|
final BlockVector3 top = selection.getMaximumPoint();
|
|
|
|
|
|
|
|
final int minX = bot.getBlockX() >> 4;
|
|
|
|
final int minZ = bot.getBlockZ() >> 4;
|
|
|
|
|
|
|
|
final int maxX = top.getBlockX() >> 4;
|
|
|
|
final int maxZ = top.getBlockZ() >> 4;
|
|
|
|
|
|
|
|
int count = 0;
|
|
|
|
|
|
|
|
if (queue == null) {
|
|
|
|
World unwrapped = WorldWrapper.unwrap(world);
|
|
|
|
if (unwrapped instanceof IQueueExtent) {
|
|
|
|
queue = (IQueueExtent) unwrapped;
|
|
|
|
} else if (Settings.IMP.QUEUE.PARALLEL_THREADS > 1) {
|
|
|
|
ParallelQueueExtent parallel =
|
|
|
|
new ParallelQueueExtent(Fawe.get().getQueueHandler(), world, true);
|
|
|
|
queue = parallel.getExtent();
|
|
|
|
} else {
|
|
|
|
queue = Fawe.get().getQueueHandler().getQueue(world);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-14 13:19:23 +00:00
|
|
|
NMSRelighter relighter = new NMSRelighter(queue, Settings.IMP.LIGHTING.DO_HEIGHTMAPS);
|
2020-05-27 10:45:08 +00:00
|
|
|
for (int x = minX; x <= maxX; x++) {
|
|
|
|
for (int z = minZ; z <= maxZ; z++) {
|
|
|
|
relighter.addChunk(x, z, null, 65535);
|
|
|
|
count++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (mode != RelightMode.NONE) {
|
2020-09-13 14:36:36 +00:00
|
|
|
if (Settings.IMP.LIGHTING.REMOVE_FIRST) {
|
|
|
|
relighter.removeAndRelight(true);
|
|
|
|
} else {
|
|
|
|
relighter.fixSkyLighting();
|
|
|
|
relighter.fixBlockLighting();
|
|
|
|
}
|
2020-05-27 10:45:08 +00:00
|
|
|
} else {
|
|
|
|
relighter.removeLighting();
|
|
|
|
}
|
2021-01-11 19:29:16 +00:00
|
|
|
relighter.flush();
|
2020-05-27 10:45:08 +00:00
|
|
|
return count;
|
2018-08-12 14:03:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2020-10-05 17:41:41 +00:00
|
|
|
* Runs a task when the server is low on memory.
|
2018-08-12 14:03:07 +00:00
|
|
|
*/
|
|
|
|
public static void addMemoryLimitedTask(Runnable run) {
|
|
|
|
MemUtil.addMemoryLimitedTask(run);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2020-10-05 17:41:41 +00:00
|
|
|
* Runs a task when the server is no longer low on memory.
|
2018-08-12 14:03:07 +00:00
|
|
|
*/
|
|
|
|
public static void addMemoryPlentifulTask(Runnable run) {
|
|
|
|
MemUtil.addMemoryPlentifulTask(run);
|
|
|
|
}
|
|
|
|
|
2019-11-21 20:37:56 +00:00
|
|
|
public static Map<String, String> getTranslations(Locale locale) {
|
|
|
|
return WorldEdit.getInstance().getTranslationManager().getTranslationMap(locale);
|
2018-08-12 14:03:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|