From c00c65eeee2493c1fe47bd8cdedbddb7a042526e Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Thu, 10 Jul 2014 15:11:44 -0400 Subject: [PATCH] Reorganized Tick Receivers 1. Reorganized our code to initialize tick receivers each time the server starts rather than once when the mod is initialized. This is needed because reusing a single instance of each class across different single-player sessions could cause scheduled events for one world to leak into another world. This approach ensures that we discard all pending events. 2. Separated the implementation of Limbo decay from a tick receiver that periodically triggers fast decay. All of the decay code has been kept in LimboDecay, while the ticking is handled by LimboDecayScheduler. This change separates some functionality that should be independent, but also, it's needed so that BlockLimbo can have access to LimboDecay's methods without holding on to a tick receiver instance. 3. Minor change: renamed ChunkLoaderHelper.loadChunkForcedWorlds() to loadForcedChunkWorlds(). --- .../mod_pocketDim/blocks/BlockLimbo.java | 2 +- .../helpers/ChunkLoaderHelper.java | 2 +- .../mod_pocketDim/mod_pocketDim.java | 42 ++++++++++++------- .../ticking/CustomLimboPopulator.java | 2 +- .../ticking/FastRiftRegenerator.java | 3 +- .../ticking/IRegularTickSender.java | 3 +- .../ticking/LimboDecayScheduler.java | 28 +++++++++++++ .../ticking/RiftRegenerator.java | 2 +- .../ticking/ServerTickHandler.java | 9 +++- .../{ticking => world}/LimboDecay.java | 19 ++------- 10 files changed, 75 insertions(+), 37 deletions(-) create mode 100644 src/main/java/StevenDimDoors/mod_pocketDim/ticking/LimboDecayScheduler.java rename src/main/java/StevenDimDoors/mod_pocketDim/{ticking => world}/LimboDecay.java (91%) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockLimbo.java b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockLimbo.java index 8da0dfe..07f1247 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockLimbo.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockLimbo.java @@ -9,7 +9,7 @@ import net.minecraft.util.Icon; import net.minecraft.world.IBlockAccess; import net.minecraft.world.World; import StevenDimDoors.mod_pocketDim.mod_pocketDim; -import StevenDimDoors.mod_pocketDim.ticking.LimboDecay; +import StevenDimDoors.mod_pocketDim.world.LimboDecay; import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/helpers/ChunkLoaderHelper.java b/src/main/java/StevenDimDoors/mod_pocketDim/helpers/ChunkLoaderHelper.java index e866ec4..6483afd 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/helpers/ChunkLoaderHelper.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/helpers/ChunkLoaderHelper.java @@ -83,7 +83,7 @@ public class ChunkLoaderHelper implements LoadingCallback } } - public static void loadChunkForcedWorlds(FMLServerStartingEvent event) + public static void loadForcedChunkWorlds(FMLServerStartingEvent event) { for (NewDimData data : PocketManager.getDimensions()) { diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java b/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java index 9468678..8329d25 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java @@ -54,7 +54,7 @@ import StevenDimDoors.mod_pocketDim.items.ItemWorldThread; import StevenDimDoors.mod_pocketDim.items.itemRiftRemover; import StevenDimDoors.mod_pocketDim.ticking.CustomLimboPopulator; import StevenDimDoors.mod_pocketDim.ticking.FastRiftRegenerator; -import StevenDimDoors.mod_pocketDim.ticking.LimboDecay; +import StevenDimDoors.mod_pocketDim.ticking.LimboDecayScheduler; import StevenDimDoors.mod_pocketDim.ticking.MobMonolith; import StevenDimDoors.mod_pocketDim.ticking.RiftRegenerator; import StevenDimDoors.mod_pocketDim.ticking.ServerTickHandler; @@ -65,6 +65,7 @@ import StevenDimDoors.mod_pocketDim.tileentities.TileEntityTransTrapdoor; import StevenDimDoors.mod_pocketDim.world.BiomeGenLimbo; import StevenDimDoors.mod_pocketDim.world.BiomeGenPocket; import StevenDimDoors.mod_pocketDim.world.DDBiomeGenBase; +import StevenDimDoors.mod_pocketDim.world.LimboDecay; import StevenDimDoors.mod_pocketDim.world.LimboProvider; import StevenDimDoors.mod_pocketDim.world.PocketProvider; import StevenDimDoors.mod_pocketDim.world.gateways.GatewayGenerator; @@ -142,9 +143,13 @@ public class mod_pocketDim public static DDProperties properties; public static DDWorldProperties worldProperties; public static CustomLimboPopulator spawner; //Added this field temporarily. Will be refactored out later. + private static RiftRegenerator riftRegenerator; public static FastRiftRegenerator fastRiftRegenerator; public static GatewayGenerator gatewayGenerator; public static DeathTracker deathTracker; + private static ServerTickHandler serverTickHandler; + private static LimboDecayScheduler limboDecayScheduler; + private static LimboDecay limboDecay; private static EventHookContainer hooks; //TODO this is a temporary workaround for saving data @@ -182,16 +187,14 @@ public class mod_pocketDim @EventHandler public void onInitialization(FMLInitializationEvent event) { - ServerTickHandler commonTickHandler = new ServerTickHandler(); - TickRegistry.registerTickHandler(commonTickHandler, Side.SERVER); - - //MonolithSpawner should be initialized before any provider instances are created - //Register the other regular tick receivers as well - spawner = new CustomLimboPopulator(commonTickHandler, properties); - new RiftRegenerator(commonTickHandler); //No need to store the reference - LimboDecay decay = new LimboDecay(commonTickHandler, properties); - fastRiftRegenerator = new FastRiftRegenerator(commonTickHandler); + // Initialize ServerTickHandler instance + serverTickHandler = new ServerTickHandler(); + TickRegistry.registerTickHandler(serverTickHandler, Side.SERVER); + + // Initialize LimboDecay instance: required for BlockLimbo + limboDecay = new LimboDecay(properties); + // Initialize blocks and items transientDoor = new TransientDoor(properties.TransientDoorID, Material.iron, properties).setHardness(1.0F) .setUnlocalizedName("transientDoor"); goldenDimensionalDoor = new BlockGoldDimDoor(properties.GoldenDimensionalDoorID, Material.iron, properties).setHardness(1.0F) .setUnlocalizedName("dimDoorGold"); @@ -200,7 +203,7 @@ public class mod_pocketDim blockDimWallPerm = (new BlockDimWallPerm(properties.PermaFabricBlockID, 0, Material.iron)).setLightValue(1.0F).setBlockUnbreakable().setResistance(6000000.0F).setUnlocalizedName("blockDimWallPerm"); warpDoor = new WarpDoor(properties.WarpDoorID, Material.wood, properties).setHardness(1.0F) .setUnlocalizedName("dimDoorWarp"); blockRift = (BlockRift) (new BlockRift(properties.RiftBlockID, 0, Material.air, properties).setHardness(1.0F) .setUnlocalizedName("rift")); - blockLimbo = new BlockLimbo(properties.LimboBlockID, 15, Material.iron, properties.LimboDimensionID, decay).setHardness(.2F).setUnlocalizedName("BlockLimbo").setLightValue(.0F); + blockLimbo = new BlockLimbo(properties.LimboBlockID, 15, Material.iron, properties.LimboDimensionID, limboDecay).setHardness(.2F).setUnlocalizedName("BlockLimbo").setLightValue(.0F); unstableDoor = (new UnstableDoor(properties.UnstableDoorID, Material.iron, properties).setHardness(.2F).setUnlocalizedName("chaosDoor").setLightValue(.0F) ); dimensionalDoor = (DimensionalDoor) (new DimensionalDoor(properties.DimensionalDoorID, Material.iron, properties).setHardness(1.0F).setResistance(2000.0F) .setUnlocalizedName("dimDoor")); transTrapdoor = (TransTrapdoor) (new TransTrapdoor(properties.TransTrapdoorID, Material.wood).setHardness(1.0F) .setUnlocalizedName("dimHatch")); @@ -317,7 +320,11 @@ public class mod_pocketDim deathTracker.writeToFile(); deathTracker = null; worldProperties = null; - this.currrentSaveRootDirectory=null; + currrentSaveRootDirectory = null; + + // Unregister all tick receivers from serverTickHandler to avoid leaking + // scheduled tasks between single-player game sessions + serverTickHandler.unregisterReceivers(); } catch (Exception e) { @@ -333,9 +340,16 @@ public class mod_pocketDim // Load the config file that's specific to this world worldProperties = new DDWorldProperties(new File(currrentSaveRootDirectory + "/DimensionalDoors/DimDoorsWorld.cfg")); hooks.setWorldProperties(worldProperties); - + // Initialize a new DeathTracker deathTracker = new DeathTracker(currrentSaveRootDirectory + "/DimensionalDoors/data/deaths.txt"); + + // Register regular tick receivers + // CustomLimboPopulator should be initialized before any provider instances are created + spawner = new CustomLimboPopulator(serverTickHandler, properties); + riftRegenerator = new RiftRegenerator(serverTickHandler); + limboDecayScheduler = new LimboDecayScheduler(serverTickHandler, limboDecay); + fastRiftRegenerator = new FastRiftRegenerator(serverTickHandler); } @EventHandler @@ -353,7 +367,7 @@ public class mod_pocketDim try { - ChunkLoaderHelper.loadChunkForcedWorlds(event); + ChunkLoaderHelper.loadForcedChunkWorlds(event); } catch (Exception e) { diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/ticking/CustomLimboPopulator.java b/src/main/java/StevenDimDoors/mod_pocketDim/ticking/CustomLimboPopulator.java index ddc018c..231eec2 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/ticking/CustomLimboPopulator.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/ticking/CustomLimboPopulator.java @@ -30,7 +30,7 @@ public class CustomLimboPopulator implements IRegularTickReceiver { { this.properties = properties; this.locations = new ConcurrentLinkedQueue(); - sender.registerForTicking(this, MONOLITH_SPAWNING_INTERVAL, false); + sender.registerReceiver(this, MONOLITH_SPAWNING_INTERVAL, false); } @Override diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/ticking/FastRiftRegenerator.java b/src/main/java/StevenDimDoors/mod_pocketDim/ticking/FastRiftRegenerator.java index b0f203f..e680b2a 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/ticking/FastRiftRegenerator.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/ticking/FastRiftRegenerator.java @@ -20,7 +20,7 @@ public class FastRiftRegenerator implements IRegularTickReceiver { public FastRiftRegenerator(IRegularTickSender sender) { - sender.registerForTicking(this, RIFT_REGENERATION_INTERVAL, false); + sender.registerReceiver(this, RIFT_REGENERATION_INTERVAL, false); } @Override @@ -33,6 +33,7 @@ public class FastRiftRegenerator implements IRegularTickReceiver { { if (!locationsToRegen.isEmpty()) { + @SuppressWarnings("cast") List loadedWorlds = (List) Arrays.asList(DimensionManager.getIDs()); for (Point4D point: locationsToRegen) { diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/ticking/IRegularTickSender.java b/src/main/java/StevenDimDoors/mod_pocketDim/ticking/IRegularTickSender.java index 6ed2dca..7b5502c 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/ticking/IRegularTickSender.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/ticking/IRegularTickSender.java @@ -3,6 +3,7 @@ package StevenDimDoors.mod_pocketDim.ticking; public interface IRegularTickSender { - public void registerForTicking(IRegularTickReceiver receiver, int interval, boolean onTickStart); + public void registerReceiver(IRegularTickReceiver receiver, int interval, boolean onTickStart); + public void unregisterReceivers(); } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/ticking/LimboDecayScheduler.java b/src/main/java/StevenDimDoors/mod_pocketDim/ticking/LimboDecayScheduler.java new file mode 100644 index 0000000..73f275c --- /dev/null +++ b/src/main/java/StevenDimDoors/mod_pocketDim/ticking/LimboDecayScheduler.java @@ -0,0 +1,28 @@ +package StevenDimDoors.mod_pocketDim.ticking; + +import StevenDimDoors.mod_pocketDim.world.LimboDecay; + +/** + * Handles scheduling of periodic fast Limbo decay operations. + */ +public class LimboDecayScheduler implements IRegularTickReceiver { + + private static final int LIMBO_DECAY_INTERVAL = 10; //Apply fast decay every 10 ticks + + private LimboDecay decay; + + public LimboDecayScheduler(IRegularTickSender tickSender, LimboDecay decay) + { + this.decay = decay; + tickSender.registerReceiver(this, LIMBO_DECAY_INTERVAL, false); + } + + /** + * Applies fast Limbo decay periodically. + */ + @Override + public void notifyTick() + { + decay.applyRandomFastDecay(); + } +} diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/ticking/RiftRegenerator.java b/src/main/java/StevenDimDoors/mod_pocketDim/ticking/RiftRegenerator.java index 192669c..23b0f9b 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/ticking/RiftRegenerator.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/ticking/RiftRegenerator.java @@ -20,7 +20,7 @@ public class RiftRegenerator implements IRegularTickReceiver { public RiftRegenerator(IRegularTickSender sender) { - sender.registerForTicking(this, RIFT_REGENERATION_INTERVAL, false); + sender.registerReceiver(this, RIFT_REGENERATION_INTERVAL, false); } @Override diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/ticking/ServerTickHandler.java b/src/main/java/StevenDimDoors/mod_pocketDim/ticking/ServerTickHandler.java index 2e2ccb1..58da365 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/ticking/ServerTickHandler.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/ticking/ServerTickHandler.java @@ -14,18 +14,23 @@ public class ServerTickHandler implements ITickHandler, IRegularTickSender private int tickCount = 0; private ArrayList receivers; - public ServerTickHandler() { this.receivers = new ArrayList(); } @Override - public void registerForTicking(IRegularTickReceiver receiver, int interval, boolean onTickStart) + public void registerReceiver(IRegularTickReceiver receiver, int interval, boolean onTickStart) { RegularTickReceiverInfo info = new RegularTickReceiverInfo(receiver, interval, onTickStart); receivers.add(info); } + + @Override + public void unregisterReceivers() + { + receivers.clear(); + } @Override public void tickStart(EnumSet type, Object... tickData) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/ticking/LimboDecay.java b/src/main/java/StevenDimDoors/mod_pocketDim/world/LimboDecay.java similarity index 91% rename from src/main/java/StevenDimDoors/mod_pocketDim/ticking/LimboDecay.java rename to src/main/java/StevenDimDoors/mod_pocketDim/world/LimboDecay.java index e5c9420..13edb19 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/ticking/LimboDecay.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/world/LimboDecay.java @@ -1,4 +1,4 @@ -package StevenDimDoors.mod_pocketDim.ticking; +package StevenDimDoors.mod_pocketDim.world; import java.util.Random; @@ -13,13 +13,12 @@ import StevenDimDoors.mod_pocketDim.config.DDProperties; * Provides methods for applying Limbo decay. Limbo decay refers to the effect that most blocks placed in Limbo * naturally change into stone, then cobble, then gravel, and finally Unraveled Fabric as time passes. */ -public class LimboDecay implements IRegularTickReceiver { +public class LimboDecay { private static final int MAX_DECAY_SPREAD_CHANCE = 100; private static final int DECAY_SPREAD_CHANCE = 50; private static final int CHUNK_SIZE = 16; private static final int SECTION_HEIGHT = 16; - private static final int LIMBO_DECAY_INTERVAL = 10; //Apply spread decay every 10 ticks //Provides a reversed list of the block IDs that blocks cycle through during decay. private final int[] decaySequence; @@ -28,7 +27,7 @@ public class LimboDecay implements IRegularTickReceiver { private final DDProperties properties; private final int[] blocksImmuneToDecay; - public LimboDecay(IRegularTickSender tickSender, DDProperties properties) + public LimboDecay(DDProperties properties) { decaySequence = new int[] { properties.LimboBlockID, @@ -51,16 +50,6 @@ public class LimboDecay implements IRegularTickReceiver { this.properties = properties; this.random = new Random(); - tickSender.registerForTicking(this, LIMBO_DECAY_INTERVAL, false); - } - - /** - * Applies fast Limbo decay periodically. - */ - @Override - public void notifyTick() - { - applyRandomFastDecay(); } /** @@ -88,7 +77,7 @@ public class LimboDecay implements IRegularTickReceiver { * Picks random blocks from each active chunk in Limbo and, if decay is applicable, converts them directly to Unraveled Fabric. * This decay method is designed to stop players from avoiding Limbo decay by building floating structures. */ - private void applyRandomFastDecay() + public void applyRandomFastDecay() { int x, y, z; int sectionY;