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 * - * @returnA block change request queue
+ * @returnA control block update request queue
*/ @NotNull - public static QueueThe 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 + * + * @returnA button update request queue
+ */ + @NotNull + public static QueueThis only affects the queued control updates during startup. It does not affect normal gameplay.
+ * + * @returnThe 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 - * - * @returnWhether 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 portalThe 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 portalThe 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 { * @returnThe 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 | #