mirror of
https://github.com/BlueMap-Minecraft/BlueMap.git
synced 2024-11-22 10:35:16 +01:00
Add debug command to save the world and flush scheduled changed chunks
Also change the status command messages a little
This commit is contained in:
parent
f6008ac4a3
commit
e62c5d5be3
@ -372,6 +372,15 @@ public MapUpdateHandler getUpdateHandler() {
|
||||
return updateHandler;
|
||||
}
|
||||
|
||||
public boolean flushWorldUpdates(UUID worldUUID) throws IOException {
|
||||
if (serverInterface.persistWorldChanges(worldUUID)) {
|
||||
updateHandler.onWorldSaveToDisk(worldUUID);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public WebServer getWebServer() {
|
||||
return webServer;
|
||||
}
|
||||
@ -380,4 +389,8 @@ public boolean isLoaded() {
|
||||
return loaded;
|
||||
}
|
||||
|
||||
public String getImplementationType() {
|
||||
return implementationType;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -42,6 +42,7 @@
|
||||
import de.bluecolored.bluemap.common.plugin.serverinterface.CommandSource;
|
||||
import de.bluecolored.bluemap.common.plugin.text.Text;
|
||||
import de.bluecolored.bluemap.common.plugin.text.TextColor;
|
||||
import de.bluecolored.bluemap.common.plugin.text.TextFormat;
|
||||
import de.bluecolored.bluemap.core.render.hires.HiresModelManager;
|
||||
import de.bluecolored.bluemap.core.world.World;
|
||||
|
||||
@ -62,12 +63,29 @@ public List<Text> createStatusMessage(){
|
||||
lines.add(Text.of(TextColor.BLUE, "Tile-Updates:"));
|
||||
|
||||
if (renderer.isRunning()) {
|
||||
lines.add(Text.of(TextColor.WHITE, " Render-Threads are ", Text.of(TextColor.GREEN, "running").setHoverText(Text.of("click to pause rendering")).setClickCommand("/bluemap pause"), TextColor.GRAY, "!"));
|
||||
lines.add(Text.of(TextColor.WHITE, " Render-Threads are ",
|
||||
Text.of(TextColor.GREEN, "running")
|
||||
.setHoverText(Text.of("click to pause rendering"))
|
||||
.setClickCommand("/bluemap pause"),
|
||||
TextColor.GRAY, "!"));
|
||||
} else {
|
||||
lines.add(Text.of(TextColor.WHITE, " Render-Threads are ", Text.of(TextColor.RED, "paused").setHoverText(Text.of("click to resume rendering")).setClickCommand("/bluemap resume"), TextColor.GRAY, "!"));
|
||||
lines.add(Text.of(TextColor.WHITE, " Render-Threads are ",
|
||||
Text.of(TextColor.RED, "paused")
|
||||
.setHoverText(Text.of("click to resume rendering"))
|
||||
.setClickCommand("/bluemap resume"),
|
||||
TextColor.GRAY, "!"));
|
||||
}
|
||||
|
||||
lines.add(Text.of(TextColor.WHITE, " Scheduled tile-updates: ", Text.of(TextColor.GOLD, renderer.getQueueSize()).setHoverText(Text.of("tiles waiting for a free render-thread")), TextColor.GRAY, " + " , Text.of(TextColor.GRAY, plugin.getUpdateHandler().getUpdateBufferCount()).setHoverText(Text.of("tiles waiting for world-save"))));
|
||||
lines.add(Text.of(
|
||||
TextColor.WHITE, " Scheduled tile-updates: ",
|
||||
TextColor.GOLD, renderer.getQueueSize()).setHoverText(
|
||||
Text.of(
|
||||
TextColor.WHITE, "Tiles waiting for a free render-thread: ", TextColor.GOLD, renderer.getQueueSize(),
|
||||
TextColor.WHITE, "\n\nChunks marked as changed: ", TextColor.GOLD, plugin.getUpdateHandler().getUpdateBufferCount(),
|
||||
TextColor.GRAY, TextFormat.ITALIC, "\n(Changed chunks will be rendered as soon as they are saved back to the world-files)"
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
RenderTask[] tasks = renderer.getRenderTasks();
|
||||
if (tasks.length > 0) {
|
||||
|
@ -119,6 +119,12 @@ public void init() {
|
||||
.then(argument("y", DoubleArgumentType.doubleArg())
|
||||
.then(argument("z", DoubleArgumentType.doubleArg())
|
||||
.executes(this::debugBlockCommand))))))
|
||||
|
||||
.then(literal("flush")
|
||||
.executes(this::debugFlushCommand)
|
||||
|
||||
.then(argument("world", StringArgumentType.string()).suggests(new WorldSuggestionProvider<>(plugin))
|
||||
.executes(this::debugFlushCommand)))
|
||||
|
||||
.then(literal("cache")
|
||||
.executes(this::debugClearCacheCommand))
|
||||
@ -377,6 +383,47 @@ public int debugClearCacheCommand(CommandContext<S> context) throws CommandSynta
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
public int debugFlushCommand(CommandContext<S> context) throws CommandSyntaxException {
|
||||
CommandSource source = commandSourceInterface.apply(context.getSource());
|
||||
|
||||
// parse arguments
|
||||
Optional<String> worldName = getOptionalArgument(context, "world", String.class);
|
||||
|
||||
final World world;
|
||||
if (worldName.isPresent()) {
|
||||
world = parseWorld(worldName.get()).orElse(null);
|
||||
|
||||
if (world == null) {
|
||||
source.sendMessage(Text.of(TextColor.RED, "There is no ", helper.worldHelperHover(), " with this name: ", TextColor.WHITE, worldName.get()));
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
world = source.getWorld().orElse(null);
|
||||
|
||||
if (world == null) {
|
||||
source.sendMessage(Text.of(TextColor.RED, "Can't detect a location from this command-source, you'll have to define a world!"));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
new Thread(() -> {
|
||||
source.sendMessage(Text.of(TextColor.GOLD, "Saving world and flushing changes..."));
|
||||
try {
|
||||
if (plugin.flushWorldUpdates(world.getUUID())) {
|
||||
source.sendMessage(Text.of(TextColor.GREEN, "Successfully saved and flushed all changes."));
|
||||
} else {
|
||||
source.sendMessage(Text.of(TextColor.RED, "This operation is not supported by this implementation (" + plugin.getImplementationType() + ")"));
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
source.sendMessage(Text.of(TextColor.RED, "There was an unexpected exception trying to save the world. Please check the console for more details..."));
|
||||
Logger.global.logError("Unexpected exception trying to save the world!", ex);
|
||||
}
|
||||
}).start();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
public int debugBlockCommand(CommandContext<S> context) throws CommandSyntaxException {
|
||||
final CommandSource source = commandSourceInterface.apply(context.getSource());
|
||||
|
||||
@ -515,10 +562,17 @@ public int renderCommand(CommandContext<S> context) {
|
||||
|
||||
// execute render
|
||||
new Thread(() -> {
|
||||
if (world != null) {
|
||||
helper.createWorldRenderTask(source, world, center, radius);
|
||||
} else {
|
||||
helper.createMapRenderTask(source, map, center, radius);
|
||||
try {
|
||||
if (world != null) {
|
||||
plugin.getServerInterface().persistWorldChanges(world.getUUID());
|
||||
helper.createWorldRenderTask(source, world, center, radius);
|
||||
} else {
|
||||
plugin.getServerInterface().persistWorldChanges(map.getWorld().getUUID());
|
||||
helper.createMapRenderTask(source, map, center, radius);
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
source.sendMessage(Text.of(TextColor.RED, "There was an unexpected exception trying to save the world. Please check the console for more details..."));
|
||||
Logger.global.logError("Unexpected exception trying to save the world!", ex);
|
||||
}
|
||||
}).start();
|
||||
|
||||
|
@ -63,6 +63,19 @@ default String getWorldName(UUID worldUUID) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to persist all changes that have been made in a world to disk.
|
||||
*
|
||||
* @param worldUUID The {@link UUID} of the world to be persisted.
|
||||
* @return <code>true</code> if the changes have been successfully persisted, <code>false</code> if this operation is not supported by the implementation
|
||||
*
|
||||
* @throws IOException if something went wrong trying to persist the changes
|
||||
* @throws IllegalArgumentException if there is no world with this UUID
|
||||
*/
|
||||
default boolean persistWorldChanges(UUID worldUUID) throws IOException, IllegalArgumentException {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Folder containing the configurations for the plugin
|
||||
*/
|
||||
|
@ -33,7 +33,9 @@
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
|
||||
@ -164,6 +166,37 @@ private UUID loadUUIDForWorld(ServerWorld world) throws IOException {
|
||||
File dimensionDir = world.getDimension().getType().getSaveDirectory(world.getSaveHandler().getWorldDir());
|
||||
return getUUIDForWorld(dimensionDir.getCanonicalFile());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean persistWorldChanges(UUID worldUUID) throws IOException, IllegalArgumentException {
|
||||
final CompletableFuture<Boolean> taskResult = new CompletableFuture<>();
|
||||
|
||||
serverInstance.execute(() -> {
|
||||
try {
|
||||
for (ServerWorld world : serverInstance.getWorlds()) {
|
||||
if (getUUIDForWorld(world).equals(worldUUID)) {
|
||||
world.save(null, true, false);
|
||||
}
|
||||
}
|
||||
|
||||
taskResult.complete(true);
|
||||
} catch (Exception e) {
|
||||
taskResult.completeExceptionally(e);
|
||||
}
|
||||
});
|
||||
|
||||
try {
|
||||
return taskResult.get();
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
throw new IOException(e);
|
||||
} catch (ExecutionException e) {
|
||||
Throwable t = e.getCause();
|
||||
if (t instanceof IOException) throw (IOException) t;
|
||||
if (t instanceof IllegalArgumentException) throw (IllegalArgumentException) t;
|
||||
throw new IOException(t);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public File getConfigFolder() {
|
||||
|
@ -33,7 +33,9 @@
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
|
||||
@ -169,6 +171,37 @@ private UUID loadUUIDForWorld(ServerWorld world) throws IOException {
|
||||
File dimensionDir = dimensionFolder.getCanonicalFile();
|
||||
return getUUIDForWorld(dimensionDir);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean persistWorldChanges(UUID worldUUID) throws IOException, IllegalArgumentException {
|
||||
final CompletableFuture<Boolean> taskResult = new CompletableFuture<>();
|
||||
|
||||
serverInstance.execute(() -> {
|
||||
try {
|
||||
for (ServerWorld world : serverInstance.getWorlds()) {
|
||||
if (getUUIDForWorld(world).equals(worldUUID)) {
|
||||
world.save(null, true, false);
|
||||
}
|
||||
}
|
||||
|
||||
taskResult.complete(true);
|
||||
} catch (Exception e) {
|
||||
taskResult.completeExceptionally(e);
|
||||
}
|
||||
});
|
||||
|
||||
try {
|
||||
return taskResult.get();
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
throw new IOException(e);
|
||||
} catch (ExecutionException e) {
|
||||
Throwable t = e.getCause();
|
||||
if (t instanceof IOException) throw (IOException) t;
|
||||
if (t instanceof IllegalArgumentException) throw (IllegalArgumentException) t;
|
||||
throw new IOException(t);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public File getConfigFolder() {
|
||||
|
@ -33,7 +33,9 @@
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
|
||||
@ -169,6 +171,37 @@ private UUID loadUUIDForWorld(ServerWorld world) throws IOException {
|
||||
File dimensionDir = dimensionFolder.getCanonicalFile();
|
||||
return getUUIDForWorld(dimensionDir);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean persistWorldChanges(UUID worldUUID) throws IOException, IllegalArgumentException {
|
||||
final CompletableFuture<Boolean> taskResult = new CompletableFuture<>();
|
||||
|
||||
serverInstance.execute(() -> {
|
||||
try {
|
||||
for (ServerWorld world : serverInstance.getWorlds()) {
|
||||
if (getUUIDForWorld(world).equals(worldUUID)) {
|
||||
world.save(null, true, false);
|
||||
}
|
||||
}
|
||||
|
||||
taskResult.complete(true);
|
||||
} catch (Exception e) {
|
||||
taskResult.completeExceptionally(e);
|
||||
}
|
||||
});
|
||||
|
||||
try {
|
||||
return taskResult.get();
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
throw new IOException(e);
|
||||
} catch (ExecutionException e) {
|
||||
Throwable t = e.getCause();
|
||||
if (t instanceof IOException) throw (IOException) t;
|
||||
if (t instanceof IllegalArgumentException) throw (IllegalArgumentException) t;
|
||||
throw new IOException(t);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public File getConfigFolder() {
|
||||
|
@ -33,7 +33,9 @@
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
|
||||
@ -185,6 +187,37 @@ private File getFolderForWorld(ServerWorld world) throws IOException {
|
||||
|
||||
return worldFolder.getCanonicalFile();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean persistWorldChanges(UUID worldUUID) throws IOException, IllegalArgumentException {
|
||||
final CompletableFuture<Boolean> taskResult = new CompletableFuture<>();
|
||||
|
||||
serverInstance.execute(() -> {
|
||||
try {
|
||||
for (ServerWorld world : serverInstance.getWorlds()) {
|
||||
if (getUUIDForWorld(world).equals(worldUUID)) {
|
||||
world.save(null, true, false);
|
||||
}
|
||||
}
|
||||
|
||||
taskResult.complete(true);
|
||||
} catch (Exception e) {
|
||||
taskResult.completeExceptionally(e);
|
||||
}
|
||||
});
|
||||
|
||||
try {
|
||||
return taskResult.get();
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
throw new IOException(e);
|
||||
} catch (ExecutionException e) {
|
||||
Throwable t = e.getCause();
|
||||
if (t instanceof IOException) throw (IOException) t;
|
||||
if (t instanceof IllegalArgumentException) throw (IllegalArgumentException) t;
|
||||
throw new IOException(t);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public File getConfigFolder() {
|
||||
|
@ -33,7 +33,9 @@
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
|
||||
@ -185,6 +187,37 @@ private File getFolderForWorld(ServerWorld world) throws IOException {
|
||||
|
||||
return worldFolder.getCanonicalFile();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean persistWorldChanges(UUID worldUUID) throws IOException, IllegalArgumentException {
|
||||
final CompletableFuture<Boolean> taskResult = new CompletableFuture<>();
|
||||
|
||||
serverInstance.execute(() -> {
|
||||
try {
|
||||
for (ServerWorld world : serverInstance.getWorlds()) {
|
||||
if (getUUIDForWorld(world).equals(worldUUID)) {
|
||||
world.save(null, true, false);
|
||||
}
|
||||
}
|
||||
|
||||
taskResult.complete(true);
|
||||
} catch (Exception e) {
|
||||
taskResult.completeExceptionally(e);
|
||||
}
|
||||
});
|
||||
|
||||
try {
|
||||
return taskResult.get();
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
throw new IOException(e);
|
||||
} catch (ExecutionException e) {
|
||||
Throwable t = e.getCause();
|
||||
if (t instanceof IOException) throw (IOException) t;
|
||||
if (t instanceof IllegalArgumentException) throw (IllegalArgumentException) t;
|
||||
throw new IOException(t);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public File getConfigFolder() {
|
||||
|
@ -33,7 +33,9 @@
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
|
||||
@ -183,6 +185,37 @@ private File getFolderForWorld(ServerWorld world) throws IOException {
|
||||
File dimensionFolder = DimensionType.func_236031_a_(world.func_234923_W_(), worldFolder);
|
||||
return dimensionFolder.getCanonicalFile();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean persistWorldChanges(UUID worldUUID) throws IOException, IllegalArgumentException {
|
||||
final CompletableFuture<Boolean> taskResult = new CompletableFuture<>();
|
||||
|
||||
serverInstance.execute(() -> {
|
||||
try {
|
||||
for (ServerWorld world : serverInstance.getWorlds()) {
|
||||
if (getUUIDForWorld(world).equals(worldUUID)) {
|
||||
world.save(null, true, false);
|
||||
}
|
||||
}
|
||||
|
||||
taskResult.complete(true);
|
||||
} catch (Exception e) {
|
||||
taskResult.completeExceptionally(e);
|
||||
}
|
||||
});
|
||||
|
||||
try {
|
||||
return taskResult.get();
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
throw new IOException(e);
|
||||
} catch (ExecutionException e) {
|
||||
Throwable t = e.getCause();
|
||||
if (t instanceof IOException) throw (IOException) t;
|
||||
if (t instanceof IllegalArgumentException) throw (IllegalArgumentException) t;
|
||||
throw new IOException(t);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public File getConfigFolder() {
|
||||
|
@ -259,6 +259,27 @@ public Optional<Player> getPlayer(UUID uuid) {
|
||||
return Optional.ofNullable(onlinePlayerMap.get(uuid));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean persistWorldChanges(UUID worldUUID) throws IOException, IllegalArgumentException {
|
||||
try {
|
||||
return Bukkit.getScheduler().callSyncMethod(this, () -> {
|
||||
World world = Bukkit.getWorld(worldUUID);
|
||||
if (world == null) throw new IllegalArgumentException("There is no world with this uuid: " + worldUUID);
|
||||
world.save();
|
||||
|
||||
return true;
|
||||
}).get();
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
throw new IOException(e);
|
||||
} catch (ExecutionException e) {
|
||||
Throwable t = e.getCause();
|
||||
if (t instanceof IOException) throw (IOException) t;
|
||||
if (t instanceof IllegalArgumentException) throw (IllegalArgumentException) t;
|
||||
throw new IOException(t);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Only update some of the online players each tick to minimize performance impact on the server-thread.
|
||||
* Only call this method on the server-thread.
|
||||
|
@ -72,10 +72,8 @@ public synchronized void removeAllListeners() {
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public synchronized void onChunkSaveToDisk(ChunkUnloadEvent evt) {
|
||||
if (evt.isSaveChunk()) {
|
||||
Vector2i chunkPos = new Vector2i(evt.getChunk().getX(), evt.getChunk().getZ());
|
||||
for (ServerEventListener listener : listeners) listener.onChunkSaveToDisk(evt.getWorld().getUID(), chunkPos);
|
||||
}
|
||||
Vector2i chunkPos = new Vector2i(evt.getChunk().getX(), evt.getChunk().getZ());
|
||||
for (ServerEventListener listener : listeners) listener.onChunkSaveToDisk(evt.getWorld().getUID(), chunkPos);
|
||||
}
|
||||
|
||||
/* Use ChunkSaveToDisk as it is the preferred event to use and more reliable on the chunk actually saved to disk
|
||||
|
@ -35,6 +35,7 @@
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
@ -84,6 +85,7 @@ public class SpongePlugin implements ServerInterface {
|
||||
private SpongeCommands commands;
|
||||
|
||||
private SpongeExecutorService asyncExecutor;
|
||||
private SpongeExecutorService syncExecutor;
|
||||
|
||||
private int playerUpdateIndex = 0;
|
||||
private Map<UUID, Player> onlinePlayerMap;
|
||||
@ -110,6 +112,7 @@ public SpongePlugin(org.slf4j.Logger logger) {
|
||||
@Listener
|
||||
public void onServerStart(GameStartingServerEvent evt) {
|
||||
asyncExecutor = Sponge.getScheduler().createAsyncExecutor(this);
|
||||
syncExecutor = Sponge.getScheduler().createSyncExecutor(this);
|
||||
|
||||
//save all world properties to generate level_sponge.dat files
|
||||
for (WorldProperties properties : Sponge.getServer().getAllWorldProperties()) {
|
||||
@ -237,6 +240,27 @@ public boolean isMetricsEnabled(boolean configValue) {
|
||||
return Sponge.getMetricsConfigManager().getGlobalCollectionState().asBoolean();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean persistWorldChanges(UUID worldUUID) throws IOException, IllegalArgumentException {
|
||||
try {
|
||||
return syncExecutor.submit(() -> {
|
||||
World world = Sponge.getServer().getWorld(worldUUID).orElse(null);
|
||||
if (world == null) throw new IllegalArgumentException("There is no world with this uuid: " + worldUUID);
|
||||
world.save();
|
||||
|
||||
return true;
|
||||
}).get();
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
throw new IOException(e);
|
||||
} catch (ExecutionException e) {
|
||||
Throwable t = e.getCause();
|
||||
if (t instanceof IOException) throw (IOException) t;
|
||||
if (t instanceof IllegalArgumentException) throw (IllegalArgumentException) t;
|
||||
throw new IOException(t);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Only update some of the online players each tick to minimize performance impact on the server-thread.
|
||||
* Only call this method on the server-thread.
|
||||
|
Loading…
Reference in New Issue
Block a user