From 36792d4ddf3f7ef65c81411a372bffab4999597f Mon Sep 17 00:00:00 2001 From: EpicKnarvik97 Date: Tue, 23 Apr 2024 18:35:41 +0200 Subject: [PATCH] Removes applyStartupFixes, and adds controlUpdateDelay Now, all updating of Stargates' control blocks happens through a queue. The amount of ticks between each time the queue is polled from is configurable using controlUpdateDelay --- README.md | 1 + .../java/net/knarcraft/stargate/Stargate.java | 40 +++++++++++--- .../stargate/config/ConfigOption.java | 14 +++-- .../stargate/config/StargateConfig.java | 23 +++++--- .../stargate/config/StargateGateConfig.java | 20 ++++--- .../container/ControlBlockUpdateRequest.java | 12 ++++ .../stargate/listener/BlockEventListener.java | 2 +- .../stargate/portal/PortalOpener.java | 4 +- .../stargate/thread/BlockChangeThread.java | 4 +- .../thread/ControlBlocksUpdateThread.java | 50 +++++++++++++++++ .../stargate/utility/PortalFileHelper.java | 55 +++++-------------- src/main/resources/config.yml | 9 +-- 12 files changed, 154 insertions(+), 80 deletions(-) create mode 100644 src/main/java/net/knarcraft/stargate/container/ControlBlockUpdateRequest.java create mode 100644 src/main/java/net/knarcraft/stargate/thread/ControlBlocksUpdateThread.java diff --git a/README.md b/README.md index c631205..a59d518 100644 --- a/README.md +++ b/README.md @@ -434,6 +434,7 @@ gates: destroyedByExplosion - Whether to destroy a stargate with explosions, or stop an explosion if it contains a gates controls. verifyPortals - Whether or not all the non-sign blocks are checked to match the gate layout when an old stargate is loaded at startup. protectEntrance - If true, will protect from users breaking gate entrance blocks (This is more resource intensive than the usual check, and should only be enabled for servers that use solid open/close blocks) + controlUpdateDelay - The amount of ticks to wait between each Stargate control block update after startup. Increase this if Stargate loads too many chunks during startup. functionality: enableBungee - Enable this for BungeeCord support. This allows portals across Bungee servers. handleVehicles - Whether or not to handle vehicles going through gates. Set to false to disallow vehicles (Manned or not) going through gates. diff --git a/src/main/java/net/knarcraft/stargate/Stargate.java b/src/main/java/net/knarcraft/stargate/Stargate.java index 86be6df..95ae27b 100644 --- a/src/main/java/net/knarcraft/stargate/Stargate.java +++ b/src/main/java/net/knarcraft/stargate/Stargate.java @@ -11,6 +11,7 @@ import net.knarcraft.stargate.config.StargateGateConfig; import net.knarcraft.stargate.config.StargateYamlConfiguration; import net.knarcraft.stargate.container.BlockChangeRequest; import net.knarcraft.stargate.container.ChunkUnloadRequest; +import net.knarcraft.stargate.container.ControlBlockUpdateRequest; import net.knarcraft.stargate.listener.BlockEventListener; import net.knarcraft.stargate.listener.EntityEventListener; import net.knarcraft.stargate.listener.EntitySpawnListener; @@ -24,6 +25,7 @@ import net.knarcraft.stargate.portal.PortalHandler; import net.knarcraft.stargate.portal.PortalRegistry; import net.knarcraft.stargate.thread.BlockChangeThread; import net.knarcraft.stargate.thread.ChunkUnloadThread; +import net.knarcraft.stargate.thread.ControlBlocksUpdateThread; import net.knarcraft.stargate.thread.StarGateThread; import net.knarcraft.stargate.utility.BStatsHelper; import org.bukkit.Bukkit; @@ -78,7 +80,8 @@ along with this program. If not, see . public class Stargate extends JavaPlugin { private static final String CONFIG_FILE_NAME = "config.yml"; - private static final Queue blockChangeRequestQueue = new LinkedList<>(); + private static final Queue controlBlockUpdateRequestQueue = new LinkedList<>(); + private static final Queue CONTROL_BLOCK_UPDATE_REQUEST_QUEUE = new LinkedList<>(); private static final Queue chunkUnloadQueue = new PriorityQueue<>(); private static Logger logger; @@ -144,20 +147,41 @@ public class Stargate extends JavaPlugin { * * @param request

The request to add

*/ - public static void addBlockChangeRequest(@Nullable BlockChangeRequest request) { + public static void addControlBlockUpdateRequest(@Nullable BlockChangeRequest request) { if (request != null) { - blockChangeRequestQueue.add(request); + controlBlockUpdateRequestQueue.add(request); } } /** - * Gets the queue containing block change requests + * Gets the queue containing control block update requests * - * @return

A block change request queue

+ * @return

A control block update request queue

*/ @NotNull - public static Queue getBlockChangeRequestQueue() { - return blockChangeRequestQueue; + public static Queue getControlBlockUpdateRequestQueue() { + return controlBlockUpdateRequestQueue; + } + + /** + * Adds a control block update request to the request queue + * + * @param request

The request to add

+ */ + public static void addControlBlockUpdateRequest(@Nullable ControlBlockUpdateRequest request) { + if (request != null) { + CONTROL_BLOCK_UPDATE_REQUEST_QUEUE.add(request); + } + } + + /** + * Gets the queue containing button update requests + * + * @return

A button update request queue

+ */ + @NotNull + public static Queue getButtonUpdateRequestQueue() { + return CONTROL_BLOCK_UPDATE_REQUEST_QUEUE; } /** @@ -448,6 +472,8 @@ public class Stargate extends JavaPlugin { BukkitScheduler scheduler = getServer().getScheduler(); scheduler.runTaskTimer(this, new StarGateThread(), 0L, 100L); scheduler.runTaskTimer(this, new BlockChangeThread(), 0L, 1L); + scheduler.runTaskTimer(this, new ControlBlocksUpdateThread(), 0L, + getStargateConfig().getStargateGateConfig().controlUpdateDelay()); scheduler.runTaskTimer(this, new ChunkUnloadThread(), 0L, 100L); } diff --git a/src/main/java/net/knarcraft/stargate/config/ConfigOption.java b/src/main/java/net/knarcraft/stargate/config/ConfigOption.java index b1f4137..cdd8563 100644 --- a/src/main/java/net/knarcraft/stargate/config/ConfigOption.java +++ b/src/main/java/net/knarcraft/stargate/config/ConfigOption.java @@ -66,11 +66,6 @@ public enum ConfigOption { */ DESTROYED_BY_EXPLOSION("gates.integrity.destroyedByExplosion", "Whether stargates should be destroyed by explosions", false), - /** - * Whether to fix incorrect signs, buttons or openings during startup - */ - APPLY_STARTUP_FIXES("gates.integrity.applyStartupFixes", "Whether Stargates should fix incorrect signs, buttons or openings during startup", true), - /** * Whether to verify each portal's gate layout after each load */ @@ -203,7 +198,14 @@ public enum ConfigOption { * Whether to hide Dynmap icons by default */ DYNMAP_ICONS_DEFAULT_HIDDEN("dynmap.dynmapIconsHiddenByDefault", - "Whether to hide Stargate's Dynmap icons by default, requiring the user to enable them.", true); + "Whether to hide Stargate's Dynmap icons by default, requiring the user to enable them.", true), + + /** + * The amount of ticks to wait when processing the Stargate control update queue + */ + CONTROL_UPDATE_QUEUE_DELAY("gates.integrity.controlUpdateDelay", + "The delay between each time a Stargate's controls are updated after startup", 3), + ; private final String configNode; private final String description; diff --git a/src/main/java/net/knarcraft/stargate/config/StargateConfig.java b/src/main/java/net/knarcraft/stargate/config/StargateConfig.java index 9caf1ce..8fcbf35 100644 --- a/src/main/java/net/knarcraft/stargate/config/StargateConfig.java +++ b/src/main/java/net/knarcraft/stargate/config/StargateConfig.java @@ -23,6 +23,7 @@ import org.jetbrains.annotations.NotNull; import java.io.File; import java.io.IOException; +import java.io.InputStream; import java.util.HashMap; import java.util.HashSet; import java.util.Map; @@ -232,10 +233,10 @@ public final class StargateConfig { //Perform all block change requests to prevent mismatch if a gate's open-material changes. Changing the // closed-material still requires a restart. - BlockChangeRequest firstElement = Stargate.getBlockChangeRequestQueue().peek(); + BlockChangeRequest firstElement = Stargate.getControlBlockUpdateRequestQueue().peek(); while (firstElement != null) { BlockChangeThread.pollQueue(); - firstElement = Stargate.getBlockChangeRequestQueue().peek(); + firstElement = Stargate.getControlBlockUpdateRequestQueue().peek(); } //Store the old enable bungee state in case it changes @@ -516,16 +517,24 @@ public final class StargateConfig { //Load old and new configuration Stargate.getInstance().reloadConfig(); FileConfiguration oldConfiguration = Stargate.getInstance().getConfig(); + InputStream configStream = FileHelper.getInputStreamForInternalFile("/config.yml"); + if (configStream == null) { + Stargate.logSevere("Could not migrate the configuration, as the internal configuration could not be read!"); + return; + } YamlConfiguration newConfiguration = StargateYamlConfiguration.loadConfiguration( - FileHelper.getBufferedReaderFromInputStream( - FileHelper.getInputStreamForInternalFile("/config.yml"))); + FileHelper.getBufferedReaderFromInputStream(configStream)); //Read all available config migrations Map migrationFields; try { - migrationFields = FileHelper.readKeyValuePairs(FileHelper.getBufferedReaderFromInputStream( - FileHelper.getInputStreamForInternalFile("/config-migrations.txt")), "=", - ColorConversion.NORMAL); + InputStream migrationStream = FileHelper.getInputStreamForInternalFile("/config-migrations.txt"); + if (migrationStream == null) { + Stargate.logSevere("Could not migrate the configuration, as the internal migration paths could not be read!"); + return; + } + migrationFields = FileHelper.readKeyValuePairs(FileHelper.getBufferedReaderFromInputStream(migrationStream), + "=", ColorConversion.NORMAL); } catch (IOException exception) { Stargate.debug(debugPath, "Unable to load config migration file"); return; diff --git a/src/main/java/net/knarcraft/stargate/config/StargateGateConfig.java b/src/main/java/net/knarcraft/stargate/config/StargateGateConfig.java index 32ff7a4..9a4c2fd 100644 --- a/src/main/java/net/knarcraft/stargate/config/StargateGateConfig.java +++ b/src/main/java/net/knarcraft/stargate/config/StargateGateConfig.java @@ -101,6 +101,17 @@ public final class StargateGateConfig { return (boolean) configOptions.get(ConfigOption.HANDLE_CREATURE_TRANSPORTATION); } + /** + * Gets the delay to wait between each update of a Stargate's control block + * + *

This only affects the queued control updates during startup. It does not affect normal gameplay.

+ * + * @return

The amount of ticks to delay control updates by

+ */ + public int controlUpdateDelay() { + return (int) configOptions.get(ConfigOption.CONTROL_UPDATE_QUEUE_DELAY); + } + /** * Gets whether vehicles containing a creature, but not a player should be handled * @@ -195,15 +206,6 @@ public final class StargateGateConfig { return (boolean) configOptions.get(ConfigOption.DESTROYED_BY_EXPLOSION); } - /** - * Gets whether to destroy portals when any blocks are broken by explosions - * - * @return

Whether to destroy portals when any blocks are broken by explosions

- */ - public boolean applyStartupFixes() { - return (boolean) configOptions.get(ConfigOption.APPLY_STARTUP_FIXES); - } - /** * Gets the default portal network to use if no other network is given * diff --git a/src/main/java/net/knarcraft/stargate/container/ControlBlockUpdateRequest.java b/src/main/java/net/knarcraft/stargate/container/ControlBlockUpdateRequest.java new file mode 100644 index 0000000..a68c0c9 --- /dev/null +++ b/src/main/java/net/knarcraft/stargate/container/ControlBlockUpdateRequest.java @@ -0,0 +1,12 @@ +package net.knarcraft.stargate.container; + +import net.knarcraft.stargate.portal.Portal; +import org.jetbrains.annotations.NotNull; + +/** + * A request for updating a portal's control blocks + * + * @param portal

The portal to update the control blocks for

+ */ +public record ControlBlockUpdateRequest(@NotNull Portal portal) { +} diff --git a/src/main/java/net/knarcraft/stargate/listener/BlockEventListener.java b/src/main/java/net/knarcraft/stargate/listener/BlockEventListener.java index 66b87d5..13e68da 100644 --- a/src/main/java/net/knarcraft/stargate/listener/BlockEventListener.java +++ b/src/main/java/net/knarcraft/stargate/listener/BlockEventListener.java @@ -91,7 +91,7 @@ public class BlockEventListener implements Listener { if (portal.getOptions().hasNoSign()) { Material replaceMaterial = PortalFileHelper.decideRemovalMaterial(portal.getSignLocation(), portal); BlockChangeRequest request = new BlockChangeRequest(portal.getSignLocation(), replaceMaterial, null); - Stargate.addBlockChangeRequest(request); + Stargate.addControlBlockUpdateRequest(request); } Stargate.getMessageSender().sendSuccessMessage(player, Stargate.getString(Message.CREATED)); diff --git a/src/main/java/net/knarcraft/stargate/portal/PortalOpener.java b/src/main/java/net/knarcraft/stargate/portal/PortalOpener.java index ac41741..aa2bcf3 100644 --- a/src/main/java/net/knarcraft/stargate/portal/PortalOpener.java +++ b/src/main/java/net/knarcraft/stargate/portal/PortalOpener.java @@ -100,7 +100,7 @@ public class PortalOpener { //Change the entrance blocks to the correct type for (BlockLocation inside : portal.getStructure().getEntrances()) { - Stargate.addBlockChangeRequest(new BlockChangeRequest(inside, openType, axis)); + Stargate.addControlBlockUpdateRequest(new BlockChangeRequest(inside, openType, axis)); } //Update the portal state to make is actually open @@ -183,7 +183,7 @@ public class PortalOpener { Axis axis = (closedType.createBlockData() instanceof Orientable) ? portal.getLocation().getRotationAxis() : null; for (BlockLocation entrance : portal.getStructure().getEntrances()) { - Stargate.addBlockChangeRequest(new BlockChangeRequest(entrance, closedType, axis)); + Stargate.addControlBlockUpdateRequest(new BlockChangeRequest(entrance, closedType, axis)); } //Update the portal state to make it actually closed diff --git a/src/main/java/net/knarcraft/stargate/thread/BlockChangeThread.java b/src/main/java/net/knarcraft/stargate/thread/BlockChangeThread.java index 8dd703c..089817a 100644 --- a/src/main/java/net/knarcraft/stargate/thread/BlockChangeThread.java +++ b/src/main/java/net/knarcraft/stargate/thread/BlockChangeThread.java @@ -13,7 +13,7 @@ import org.jetbrains.annotations.NotNull; /** * This thread changes gate blocks to display a gate as open or closed * - *

This thread fetches some entries from blockPopulateQueue each time it's called.

+ *

This thread fetches some entries from blockChangeRequestQueue each time it's called.

*/ public class BlockChangeThread implements Runnable { @@ -35,7 +35,7 @@ public class BlockChangeThread implements Runnable { */ public static boolean pollQueue() { //Abort if there's no work to be done - BlockChangeRequest blockChangeRequest = Stargate.getBlockChangeRequestQueue().poll(); + BlockChangeRequest blockChangeRequest = Stargate.getControlBlockUpdateRequestQueue().poll(); if (blockChangeRequest == null) { return true; } diff --git a/src/main/java/net/knarcraft/stargate/thread/ControlBlocksUpdateThread.java b/src/main/java/net/knarcraft/stargate/thread/ControlBlocksUpdateThread.java new file mode 100644 index 0000000..00ec422 --- /dev/null +++ b/src/main/java/net/knarcraft/stargate/thread/ControlBlocksUpdateThread.java @@ -0,0 +1,50 @@ +package net.knarcraft.stargate.thread; + +import net.knarcraft.stargate.Stargate; +import net.knarcraft.stargate.container.BlockChangeRequest; +import net.knarcraft.stargate.container.BlockLocation; +import net.knarcraft.stargate.container.ControlBlockUpdateRequest; +import net.knarcraft.stargate.portal.Portal; +import net.knarcraft.stargate.utility.DirectionHelper; +import net.knarcraft.stargate.utility.MaterialHelper; +import net.knarcraft.stargate.utility.PortalFileHelper; +import org.bukkit.Material; + +/** + * This thread updates the signs and buttons of Stargates, if deemed necessary + */ +public class ControlBlocksUpdateThread implements Runnable { + + @Override + public void run() { + //Abort if there's no work to be done + ControlBlockUpdateRequest controlBlockUpdateRequest = Stargate.getButtonUpdateRequestQueue().poll(); + if (controlBlockUpdateRequest == null) { + return; + } + + Portal portal = controlBlockUpdateRequest.portal(); + portal.drawSign(); + + BlockLocation buttonLocation = PortalFileHelper.getButtonLocation(portal); + if (buttonLocation == null) { + return; + } + + Stargate.debug("ControlBlocksUpdateThread", "Updating control blocks for portal " + portal); + + if (portal.getOptions().isAlwaysOn()) { + //Clear button if it exists + if (MaterialHelper.isButtonCompatible(buttonLocation.getType())) { + Material newMaterial = PortalFileHelper.decideRemovalMaterial(buttonLocation, portal); + Stargate.addControlBlockUpdateRequest(new BlockChangeRequest(buttonLocation, newMaterial, null)); + } + } else { + //Replace button if the material is not a button + if (!MaterialHelper.isButtonCompatible(buttonLocation.getType())) { + PortalFileHelper.generatePortalButton(portal, DirectionHelper.getBlockFaceFromYaw(portal.getYaw())); + } + } + } + +} diff --git a/src/main/java/net/knarcraft/stargate/utility/PortalFileHelper.java b/src/main/java/net/knarcraft/stargate/utility/PortalFileHelper.java index b983ecc..09dfd6b 100644 --- a/src/main/java/net/knarcraft/stargate/utility/PortalFileHelper.java +++ b/src/main/java/net/knarcraft/stargate/utility/PortalFileHelper.java @@ -3,6 +3,7 @@ package net.knarcraft.stargate.utility; import net.knarcraft.stargate.Stargate; import net.knarcraft.stargate.container.BlockChangeRequest; import net.knarcraft.stargate.container.BlockLocation; +import net.knarcraft.stargate.container.ControlBlockUpdateRequest; import net.knarcraft.stargate.container.RelativeBlockVector; import net.knarcraft.stargate.portal.Portal; import net.knarcraft.stargate.portal.PortalHandler; @@ -237,18 +238,15 @@ public final class PortalFileHelper { portalCount, openCount)); - if (Stargate.getGateConfig().applyStartupFixes()) { - //Re-draw the signs in case a bug in the config prevented the portal from loading and has been fixed since - Stargate.debug("PortalFileHelper::doPostLoadTasks::update", - String.format("Updating portal signs/buttons for %s", world)); - for (Portal portal : PortalRegistry.getAllPortals()) { - if (portal.isRegistered() && portal.getWorld() != null && portal.getWorld().equals(world) && - world.getWorldBorder().isInside(portal.getSignLocation())) { - portal.drawSign(); - updatePortalButton(portal); - Stargate.debug("UpdateSignsButtons", String.format("Updated sign and button for portal %s", - portal.getName())); - } + //Re-draw the signs in case a bug in the config prevented the portal from loading and has been fixed since + Stargate.debug("PortalFileHelper::doPostLoadTasks::update", + String.format("Queueing portal sign/button updates for %s", world)); + for (Portal portal : PortalRegistry.getAllPortals()) { + if (portal.isRegistered() && portal.getWorld() != null && portal.getWorld().equals(world) && + world.getWorldBorder().isInside(portal.getSignLocation())) { + Stargate.addControlBlockUpdateRequest(new ControlBlockUpdateRequest(portal)); + Stargate.debug("UpdateSignsButtons", String.format("Queued sign and button updates for portal %s", + portal.getName())); } } //Save the portals to disk to update with any changes @@ -302,37 +300,10 @@ public final class PortalFileHelper { //Register the portal, and close it in case it wasn't properly closed when the server stopped boolean buttonLocationChanged = updateButtonVector(portal); PortalHandler.registerPortal(portal); - if (Stargate.getGateConfig().applyStartupFixes()) { - portal.getPortalOpener().closePortal(true); - } + portal.getPortalOpener().closePortal(true); return buttonLocationChanged; } - /** - * Updates a portal's button if it does not match the correct material - * - * @param portal

The portal update the button of

- */ - private static void updatePortalButton(@NotNull Portal portal) { - BlockLocation buttonLocation = getButtonLocation(portal); - if (buttonLocation == null) { - return; - } - - if (portal.getOptions().isAlwaysOn()) { - //Clear button if it exists - if (MaterialHelper.isButtonCompatible(buttonLocation.getType())) { - Material newMaterial = decideRemovalMaterial(buttonLocation, portal); - Stargate.addBlockChangeRequest(new BlockChangeRequest(buttonLocation, newMaterial, null)); - } - } else { - //Replace button if the material is not a button - if (!MaterialHelper.isButtonCompatible(buttonLocation.getType())) { - generatePortalButton(portal, DirectionHelper.getBlockFaceFromYaw(portal.getYaw())); - } - } - } - /** * Decides the material to use for removing a portal's button/sign * @@ -388,7 +359,7 @@ public final class PortalFileHelper { BlockLocation oldButtonLocation = portal.getStructure().getButton(); if (oldButtonLocation != null && !oldButtonLocation.equals(buttonLocation)) { - Stargate.addBlockChangeRequest(new BlockChangeRequest(oldButtonLocation, Material.AIR, null)); + Stargate.addControlBlockUpdateRequest(new BlockChangeRequest(oldButtonLocation, Material.AIR, null)); portal.getStructure().setButton(buttonLocation); return true; } @@ -431,7 +402,7 @@ public final class PortalFileHelper { * @return

The location of the portal's button

*/ @Nullable - private static BlockLocation getButtonLocation(@NotNull Portal portal) { + public static BlockLocation getButtonLocation(@NotNull Portal portal) { BlockLocation topLeft = portal.getTopLeft(); RelativeBlockVector buttonVector = portal.getLocation().getButtonVector(); diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index ad27cad..e375987 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -107,10 +107,11 @@ gates: # Or if using an easily destroyable open/closed material. protectEntrance: false - # Should things like outdated signs, invalid button materials and not properly closed Stargates be fixed at startup? - # It is generally recommended to enable this, but for huge servers, the amount of chunks loaded might require way - # too much RAM. - applyStartupFixes: true + # How many ticks should go between each Stargate control update? This process updates any signs that have incorrect + # information, and buttons that are missing. While a value of one works fine for small servers with few Stargates, + # it has been known to cause lag and high initial RAM usage for huge servers. A value of 20 is one second, which + # should work no matter how many Stargates the server has. + controlUpdateDelay: 3 # +----------------------------------------------------------------------------------------------+ # # | Aesthetic Tweaks | #