diff --git a/sponge/src/main/java/net/year4000/utilities/sponge/Messages.java b/sponge/src/main/java/net/year4000/utilities/sponge/Messages.java index c944681..52c7da3 100644 --- a/sponge/src/main/java/net/year4000/utilities/sponge/Messages.java +++ b/sponge/src/main/java/net/year4000/utilities/sponge/Messages.java @@ -32,6 +32,12 @@ public enum Messages implements LocaleKeys { CMD_FLY_ON, CMD_FLY_OFF, + // Chunks Command + CMD_CHUNKS_UNLOADED, + CHUNKS_UNLOADING, + CHUNKS_UNLOADED, + CHUNKS_WORLD, + // System Command CMD_SYSTEM, CMD_UPTIME, diff --git a/sponge/src/main/java/net/year4000/utilities/sponge/Utilities.java b/sponge/src/main/java/net/year4000/utilities/sponge/Utilities.java index 5ebebff..95863c1 100644 --- a/sponge/src/main/java/net/year4000/utilities/sponge/Utilities.java +++ b/sponge/src/main/java/net/year4000/utilities/sponge/Utilities.java @@ -5,6 +5,7 @@ package net.year4000.utilities.sponge; import net.year4000.utilities.Tokens; +import net.year4000.utilities.sponge.command.ChunksCommand; import net.year4000.utilities.sponge.command.PluginCommand; import net.year4000.utilities.sponge.command.SystemCommand; import org.spongepowered.api.event.Listener; @@ -32,5 +33,6 @@ public void onUtilitiesInit(GameInitializationEvent event) { PluginCommand.register(this); // FlyCommand.register(this); todo disable, should be in drip SystemCommand.register(this); + ChunksCommand.register(this); } } diff --git a/sponge/src/main/java/net/year4000/utilities/sponge/command/ChunksCommand.java b/sponge/src/main/java/net/year4000/utilities/sponge/command/ChunksCommand.java new file mode 100644 index 0000000..71f2741 --- /dev/null +++ b/sponge/src/main/java/net/year4000/utilities/sponge/command/ChunksCommand.java @@ -0,0 +1,123 @@ +package net.year4000.utilities.sponge.command; + +import com.google.common.collect.Lists; +import net.year4000.utilities.sponge.Messages; +import net.year4000.utilities.sponge.Utilities; +import org.spongepowered.api.Sponge; +import org.spongepowered.api.command.CommandException; +import org.spongepowered.api.command.CommandPermissionException; +import org.spongepowered.api.command.CommandResult; +import org.spongepowered.api.command.CommandSource; +import org.spongepowered.api.command.args.CommandContext; +import org.spongepowered.api.command.spec.CommandExecutor; +import org.spongepowered.api.command.spec.CommandSpec; +import org.spongepowered.api.scheduler.Task; +import org.spongepowered.api.text.Text; +import org.spongepowered.api.text.action.TextActions; +import org.spongepowered.api.text.chat.ChatTypes; +import org.spongepowered.api.text.format.TextColors; +import org.spongepowered.api.text.format.TextStyles; +import org.spongepowered.api.world.Chunk; +import org.spongepowered.api.world.World; + +import java.util.List; +import java.util.concurrent.TimeUnit; + +import static net.year4000.utilities.sponge.Messages.CHUNKS_WORLD; + +/** View the status of the chunks of each world */ +public final class ChunksCommand implements CommandExecutor { + private static final String[] ALIAS = new String[] {"chunks", "memory"}; + private static final CommandSpec COMMAND_SPEC = CommandSpec.builder() + .child(ChunksUnloadCommand.COMMAND_SPEC, ChunksUnloadCommand.ALIAS) + .permission("utilities.command.chunks") + .executor(new ChunksCommand()) + .build(); + + /** Register this command with the manager */ + public static void register(Object object) { + Sponge.getCommandManager().register(object, COMMAND_SPEC, ALIAS); + } + + @Override + public CommandResult execute(CommandSource src, CommandContext args) throws CommandException { + List pendingUnload = loadedChunks().subList(1, 5); + src.sendMessage(CHUNKS_WORLD.get(src, pendingUnload.size())); + pendingUnload.forEach(chunk -> { + src.sendMessage(formatWorld(chunk.getWorld(), src)); + }); + return CommandResult.success(); + } + + /** Format the text line for the world */ + private Text formatWorld(World world,CommandSource src) { + Text worldPart = Text.builder(world.getName()).onHover(TextActions.showText(Text.of(world.getUniqueId()))).build(); + Text chunksPart = Text.builder(world.getDimension().getName()).onHover(TextActions.showText(Text.of(world.getDimension().getType().getName()))).build(); + return CHUNKS_WORLD.get(src, worldPart, chunksPart); + } + + /** Get all the loaded chunks at this point in time */ + private List loadedChunks() { + List chunks = Lists.newLinkedList(); + Sponge.getServer().getWorlds().stream() + .map(World::getLoadedChunks) + .forEach(iterator -> chunks.addAll(Lists.newLinkedList(iterator))); + return chunks; + } + + /** Command to unload all chunks on the server inorder to save memory */ + public static class ChunksUnloadCommand implements CommandExecutor { + private static final String[] ALIAS = new String[] {"unload"}; + private static final CommandSpec COMMAND_SPEC = CommandSpec.builder() + .description(Text.of("Unload all the chunks on the server.")) + .permission("utilities.command.chunks.unload") + .executor(new ChunksUnloadCommand()) + .build(); + + @Override + public CommandResult execute(CommandSource src, CommandContext args) throws CommandException { + if (Sponge.getScheduler().getTasksByName("utilities-chunk-unload").size() > 0) { + throw new CommandPermissionException(Text.of(Messages.ERROR, "Command already running...")); + } + + Task broadcast = Sponge.getScheduler().createTaskBuilder() + .async() + .interval(1, TimeUnit.SECONDS) + .name("utilities-chunk-unload") + .execute(() -> { + Sponge.getServer().getOnlinePlayers().forEach(player -> { + player.sendMessage(ChatTypes.ACTION_BAR, Text.of(Messages.NOTICE, "Unloading server chunks, use caution when building.")); + }); + }) + .submit(Utilities.get()); + + Sponge.getScheduler().createTaskBuilder() + .async() + .execute(() -> { + // Generate the list of chunks + List pendingUnload = Lists.newLinkedList(); + Sponge.getServer().getWorlds().stream() + .map(World::getLoadedChunks) + .forEach(iterator -> pendingUnload.addAll(Lists.newLinkedList(iterator))); + + // Unload the chunks + try { + Thread.sleep(10000); + } + catch (InterruptedException e) { + e.printStackTrace(); + } + //pendingUnload.stream().forEach(Chunk::unloadChunk); + + // Send completion notification + broadcast.cancel(); + Sponge.getServer().getOnlinePlayers().forEach(player -> { + player.sendMessage(ChatTypes.ACTION_BAR, Text.of(Messages.SUCCESS, TextColors.GOLD, TextStyles.BOLD, "It's OK, you may resume your work.")); + }); + }) + .submit(Utilities.get()); + + return CommandResult.success(); + } + } +}