diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java b/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java index 1855963e..9fd2d418 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java @@ -8,6 +8,7 @@ import net.minecraft.item.ItemDoor; import net.minecraft.item.ItemStack; import net.minecraft.world.World; import net.minecraft.world.WorldProvider; +import net.minecraft.world.chunk.Chunk; import net.minecraftforge.client.event.sound.PlayBackgroundMusicEvent; import net.minecraftforge.client.event.sound.SoundLoadEvent; import net.minecraftforge.event.EventPriority; @@ -17,12 +18,16 @@ import net.minecraftforge.event.entity.living.LivingFallEvent; import net.minecraftforge.event.entity.player.PlayerInteractEvent; import net.minecraftforge.event.entity.player.PlayerInteractEvent.Action; import net.minecraftforge.event.terraingen.InitMapGenEvent; +import net.minecraftforge.event.world.ChunkEvent; import net.minecraftforge.event.world.WorldEvent; import StevenDimDoors.mod_pocketDim.config.DDProperties; import StevenDimDoors.mod_pocketDim.config.DDWorldProperties; import StevenDimDoors.mod_pocketDim.core.DDTeleporter; +import StevenDimDoors.mod_pocketDim.core.DimLink; +import StevenDimDoors.mod_pocketDim.core.NewDimData; import StevenDimDoors.mod_pocketDim.core.PocketManager; import StevenDimDoors.mod_pocketDim.items.BaseItemDoor; +import StevenDimDoors.mod_pocketDim.ticking.RiftRegenerator; import StevenDimDoors.mod_pocketDim.util.Point4D; import StevenDimDoors.mod_pocketDim.world.LimboProvider; import StevenDimDoors.mod_pocketDim.world.PocketProvider; @@ -36,18 +41,20 @@ public class EventHookContainer private final DDProperties properties; private DDWorldProperties worldProperties; + private RiftRegenerator regenerator; public EventHookContainer(DDProperties properties) { this.properties = properties; } - public void setWorldProperties(DDWorldProperties worldProperties) + public void setSessionFields(DDWorldProperties worldProperties, RiftRegenerator regenerator) { // SenseiKiwi: - // Why have a setter rather than accessing mod_pocketDim.worldProperties? + // Why have a setter rather than accessing mod_pocketDim directly? // I want to make this dependency explicit in our code. this.worldProperties = worldProperties; + this.regenerator = regenerator; } @ForgeSubscribe(priority = EventPriority.LOW) @@ -217,6 +224,22 @@ public class EventHookContainer } } } + + @ForgeSubscribe + public void onChunkLoad(ChunkEvent.Load event) + { + // Schedule rift regeneration for any links located in this chunk. + // This event runs on both the client and server. Allow server only. + Chunk chunk = event.getChunk(); + if (!chunk.worldObj.isRemote) + { + NewDimData dimension = PocketManager.getDimensionData(chunk.worldObj); + for (DimLink link : dimension.getChunkLinks(chunk.xPosition, chunk.zPosition)) + { + regenerator.scheduleSlowRegeneration(link); + } + } + } public void playMusicForDim(World world) { diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BaseDimDoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BaseDimDoor.java index d26a0e38..de8db5bc 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BaseDimDoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BaseDimDoor.java @@ -306,7 +306,7 @@ public abstract class BaseDimDoor extends BlockDoor implements IDimDoor, ITileEn { if (world.getBlockId(x, y - 1, z) != this.blockID) { - world.setBlock(x, y, z, 0); + world.setBlockToAir(x, y, z); } if (neighborID > 0 && neighborID != this.blockID) @@ -318,7 +318,7 @@ public abstract class BaseDimDoor extends BlockDoor implements IDimDoor, ITileEn { if (world.getBlockId(x, y + 1, z) != this.blockID) { - world.setBlock(x, y, z, 0); + world.setBlockToAir(x, y, z); if (!world.isRemote) { this.dropBlockAsItem(world, x, y, z, metadata, 0); @@ -354,18 +354,6 @@ public abstract class BaseDimDoor extends BlockDoor implements IDimDoor, ITileEn return isUpperDoorBlock(metadata) ? 0 : this.getDrops(); } - /** - * Called when the block is attempted to be harvested - */ - @Override - public void onBlockHarvested(World par1World, int par2, int par3, int par4, int par5, EntityPlayer par6EntityPlayer) - { - if (par6EntityPlayer.capabilities.isCreativeMode && (par5 & 8) != 0 && par1World.getBlockId(par2, par3 - 1, par4) == this.blockID) - { - par1World.setBlock(par2, par3 - 1, par4, 0); - } - } - @Override public TileEntity createNewTileEntity(World world) { @@ -445,4 +433,18 @@ public abstract class BaseDimDoor extends BlockDoor implements IDimDoor, ITileEn world.setBlockTileEntity(x, y, z, te); return te; } + + @Override + public void breakBlock(World world, int x, int y, int z, int oldBlockID, int oldMeta) + { + // This function runs on the server side after a block is replaced + // We MUST call super.breakBlock() since it involves removing tile entities + super.breakBlock(world, x, y, z, oldBlockID, oldMeta); + + // Schedule rift regeneration for this block if it was replaced + if (world.getBlockId(x, y, z) != oldBlockID) + { + mod_pocketDim.riftRegenerator.scheduleFastRegeneration(x, y, z, world); + } + } } \ No newline at end of file diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockLimbo.java b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockLimbo.java index 8da0dfec..07f1247b 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/blocks/BlockRift.java b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockRift.java index ada00b6f..64009782 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockRift.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockRift.java @@ -47,25 +47,27 @@ public class BlockRift extends Block implements ITileEntityProvider public static final int MAX_WORLD_THREAD_DROP_CHANCE = 1000; private final DDProperties properties; - private final ArrayList blocksImmuneToRift; + private final ArrayList blocksImmuneToRift; // List of Vanilla blocks immune to rifts + private final ArrayList modBlocksImmuneToRift; // List of DD blocks immune to rifts public BlockRift(int i, int j, Material par2Material, DDProperties properties) { super(i, par2Material); this.setTickRandomly(true); this.properties = properties; + this.modBlocksImmuneToRift = new ArrayList(); + this.modBlocksImmuneToRift.add(properties.FabricBlockID); + this.modBlocksImmuneToRift.add(properties.PermaFabricBlockID); + this.modBlocksImmuneToRift.add(properties.DimensionalDoorID); + this.modBlocksImmuneToRift.add(properties.WarpDoorID); + this.modBlocksImmuneToRift.add(properties.TransTrapdoorID); + this.modBlocksImmuneToRift.add(properties.UnstableDoorID); + this.modBlocksImmuneToRift.add(properties.RiftBlockID); + this.modBlocksImmuneToRift.add(properties.TransientDoorID); + this.modBlocksImmuneToRift.add(properties.GoldenDimensionalDoorID); + this.modBlocksImmuneToRift.add(properties.GoldenDoorID); + this.blocksImmuneToRift = new ArrayList(); - this.blocksImmuneToRift.add(properties.FabricBlockID); - this.blocksImmuneToRift.add(properties.PermaFabricBlockID); - this.blocksImmuneToRift.add(properties.DimensionalDoorID); - this.blocksImmuneToRift.add(properties.WarpDoorID); - this.blocksImmuneToRift.add(properties.TransTrapdoorID); - this.blocksImmuneToRift.add(properties.UnstableDoorID); - this.blocksImmuneToRift.add(properties.RiftBlockID); - this.blocksImmuneToRift.add(properties.TransientDoorID); - this.blocksImmuneToRift.add(properties.GoldenDimensionalDoorID); - this.blocksImmuneToRift.add(properties.GoldenDoorID); - this.blocksImmuneToRift.add(Block.blockLapis.blockID); this.blocksImmuneToRift.add(Block.blockIron.blockID); this.blocksImmuneToRift.add(Block.blockGold.blockID); @@ -84,9 +86,6 @@ public class BlockRift extends Block implements ITileEntityProvider { return false; } - - @Override - public void onBlockDestroyedByPlayer(World par1World, int par2, int par3, int par4, int par5) {} @Override public boolean isOpaqueCube() @@ -113,10 +112,10 @@ public class BlockRift extends Block implements ITileEntityProvider return true; } - //this doesnt do anything yet. @Override public int getRenderType() { + // This doesn't do anything yet if (mod_pocketDim.isPlayerWearingGoogles) { return 0; @@ -220,7 +219,7 @@ public class BlockRift extends Block implements ITileEntityProvider return targets; } - private void dropWorldThread(int blockID, World world, int x, int y, int z, Random random) + public void dropWorldThread(int blockID, World world, int x, int y, int z, Random random) { if (blockID != 0 && (random.nextInt(MAX_WORLD_THREAD_DROP_CHANCE) < properties.WorldThreadDropChance) && !(Block.blocksList[blockID] instanceof BlockFlowing || @@ -232,7 +231,7 @@ public class BlockRift extends Block implements ITileEntityProvider } } - private void addAdjacentBlocks(int x, int y, int z, int distance, HashMap pointDistances, Queue points) + private static void addAdjacentBlocks(int x, int y, int z, int distance, HashMap pointDistances, Queue points) { Point3D[] neighbors = new Point3D[] { new Point3D(x - 1, y, z), @@ -251,16 +250,6 @@ public class BlockRift extends Block implements ITileEntityProvider } } } - - public void regenerateRift(World world, int x, int y, int z, Random random) - { - if (!this.isBlockImmune(world, x, y, z) && world.getChunkProvider().chunkExists(x >> 4, z >> 4)) - { - int blockID = world.getBlockId(x, y, z); - if (world.setBlock(x, y, z, properties.RiftBlockID)) - dropWorldThread(blockID, world, x, y, z, random); - } - } public boolean spreadRift(NewDimData dimension, DimLink parent, World world, Random random) { @@ -412,6 +401,15 @@ public class BlockRift extends Block implements ITileEntityProvider } } } + + public boolean tryPlacingRift(World world, int x, int y, int z) + { + if (world != null && !isBlockImmune(world, x, y, z)) + { + return world.setBlock(x, y, z, mod_pocketDim.blockRift.blockID); + } + return false; + } public boolean isBlockImmune(World world, int x, int y, int z) { @@ -424,7 +422,21 @@ public class BlockRift extends Block implements ITileEntityProvider // is designed to receive an entity, the source of the blast. We have no entity so // I've set this to access blockResistance directly. Might need changing later. - return (block.blockResistance >= MIN_IMMUNE_RESISTANCE || blocksImmuneToRift.contains(block.blockID)); + return (block.blockResistance >= MIN_IMMUNE_RESISTANCE || + modBlocksImmuneToRift.contains(block.blockID) || + blocksImmuneToRift.contains(block.blockID)); + } + return false; + } + + public boolean isModBlockImmune(World world, int x, int y, int z) + { + // Check whether the block at the specified location is one of the + // rift-resistant blocks from DD. + Block block = Block.blocksList[world.getBlockId(x, y, z)]; + if (block != null) + { + return modBlocksImmuneToRift.contains(block.blockID); } return false; } @@ -446,4 +458,18 @@ public class BlockRift extends Block implements ITileEntityProvider { return new TileEntityRift(); } + + @Override + public void breakBlock(World world, int x, int y, int z, int oldBlockID, int oldMeta) + { + // This function runs on the server side after a block is replaced + // We MUST call super.breakBlock() since it involves removing tile entities + super.breakBlock(world, x, y, z, oldBlockID, oldMeta); + + // Schedule rift regeneration for this block if it was changed + if (world.getBlockId(x, y, z) != oldBlockID) + { + mod_pocketDim.riftRegenerator.scheduleSlowRegeneration(x, y, z, world); + } + } } \ No newline at end of file diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/TransTrapdoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/TransTrapdoor.java index 4a1df0d3..d2eda146 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/TransTrapdoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/TransTrapdoor.java @@ -63,14 +63,6 @@ public class TransTrapdoor extends BlockTrapDoor implements IDimDoor, ITileEntit { this.placeLink(world, x, y, z); world.setBlockTileEntity(x, y, z, this.createNewTileEntity(world)); - updateAttachedTile(world, x, y, z); - } - - @Override - public void updateTick(World world, int x, int y, int z, Random random) - { - TileEntityTransTrapdoor tile = (TileEntityTransTrapdoor) world.getBlockTileEntity(x, y, z); - tile.hasRift = PocketManager.getLink(x, y, z, world) != null; } @Override @@ -79,16 +71,6 @@ public class TransTrapdoor extends BlockTrapDoor implements IDimDoor, ITileEntit return new TileEntityTransTrapdoor(); } - public static void updateAttachedTile(World world, int x, int y, int z) - { - TileEntity tile = world.getBlockTileEntity(x, y, z); - if (tile instanceof TileEntityTransTrapdoor) - { - TileEntityTransTrapdoor trapdoorTile = (TileEntityTransTrapdoor) tile; - trapdoorTile.hasRift = (PocketManager.getLink(x, y, z, world) != null); - } - } - @Override public void placeLink(World world, int x, int y, int z) { @@ -98,7 +80,7 @@ public class TransTrapdoor extends BlockTrapDoor implements IDimDoor, ITileEntit DimLink link = dimension.getLink(x, y, z); if (link == null && dimension.isPocketDimension()) { - dimension.createLink(x, y, z, LinkTypes.UNSAFE_EXIT,0); + dimension.createLink(x, y, z, LinkTypes.UNSAFE_EXIT, 0); } } } @@ -140,4 +122,18 @@ public class TransTrapdoor extends BlockTrapDoor implements IDimDoor, ITileEntit world.setBlockTileEntity(x, y, z, te); return te; } + + @Override + public void breakBlock(World world, int x, int y, int z, int oldBlockID, int oldMeta) + { + // This function runs on the server side after a block is replaced + // We MUST call super.breakBlock() since it involves removing tile entities + super.breakBlock(world, x, y, z, oldBlockID, oldMeta); + + // Schedule rift regeneration for this block if it was replaced + if (world.getBlockId(x, y, z) != oldBlockID) + { + mod_pocketDim.riftRegenerator.scheduleFastRegeneration(x, y, z, world); + } + } } \ No newline at end of file diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/core/DimLink.java b/src/main/java/StevenDimDoors/mod_pocketDim/core/DimLink.java index 8b0e3d8f..abfed4d9 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/core/DimLink.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/core/DimLink.java @@ -3,6 +3,7 @@ package StevenDimDoors.mod_pocketDim.core; import java.util.LinkedList; import java.util.List; +import net.minecraft.world.ChunkCoordIntPair; import StevenDimDoors.mod_pocketDim.util.Point4D; import StevenDimDoors.mod_pocketDim.watcher.ClientLinkData; @@ -15,7 +16,6 @@ public abstract class DimLink protected DimLink(ClientLinkData link, DimLink parent) { - if (parent.link.point.getDimension() != link.point.getDimension()) { // Ban having children in other dimensions to avoid serialization issues with cross-dimensional tails @@ -63,12 +63,12 @@ public abstract class DimLink public int getDestinationOrientation() { - DimLink link = PocketManager.getLink(this.destination().getX(), this.destination().getY(), this.destination().getZ(), this.destination().getDimension()); - if(link !=null) + DimLink destinationLink = PocketManager.getLink(tail.getDestination()); + if (destinationLink != null) { - return link.orientation(); + return destinationLink.orientation(); } - return (this.orientation()+2)%4; + return (link.orientation + 2) % 4; } public boolean hasDestination() @@ -95,10 +95,15 @@ public abstract class DimLink { return tail.getLinkType(); } + + public ChunkCoordIntPair getChunkCoordinates() + { + return new ChunkCoordIntPair(link.point.getX() >> 4, link.point.getZ() >> 4); + } @Override public String toString() { - return link.point + " -> " + (hasDestination() ? destination() : ""); + return link.point + " -> " + (hasDestination() ? destination() : "()"); } } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/core/NewDimData.java b/src/main/java/StevenDimDoors/mod_pocketDim/core/NewDimData.java index 326b7d45..9a8a0b59 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/core/NewDimData.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/core/NewDimData.java @@ -1,19 +1,21 @@ package StevenDimDoors.mod_pocketDim.core; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Random; import java.util.Stack; import java.util.TreeMap; -import StevenDimDoors.mod_pocketDim.watcher.ClientLinkData; +import net.minecraft.world.ChunkCoordIntPair; import net.minecraft.world.World; import StevenDimDoors.mod_pocketDim.Point3D; import StevenDimDoors.mod_pocketDim.config.DDProperties; import StevenDimDoors.mod_pocketDim.dungeon.DungeonData; import StevenDimDoors.mod_pocketDim.dungeon.pack.DungeonPack; import StevenDimDoors.mod_pocketDim.util.Point4D; +import StevenDimDoors.mod_pocketDim.watcher.ClientLinkData; import StevenDimDoors.mod_pocketDim.watcher.IUpdateWatcher; public abstract class NewDimData @@ -116,6 +118,8 @@ public abstract class NewDimData } } + private static int EXPECTED_LINKS_PER_CHUNK = 2; + protected static Random random = new Random(); protected int id; @@ -134,6 +138,9 @@ public abstract class NewDimData protected boolean modified; public IUpdateWatcher linkWatcher; + // Don't write this field to a file - it should be recreated on startup + private Map> chunkMapping; + protected NewDimData(int id, NewDimData parent, boolean isPocket, boolean isDungeon, IUpdateWatcher linkWatcher) { @@ -159,6 +166,7 @@ public abstract class NewDimData this.origin = null; this.dungeon = null; this.linkWatcher = linkWatcher; + this.chunkMapping = new HashMap>(); this.modified = true; //Register with parent @@ -199,28 +207,26 @@ public abstract class NewDimData this.linkWatcher = null; this.depth = 0; this.root = root; + this.chunkMapping = null; } public DimLink findNearestRift(World world, int range, int x, int y, int z) { - //TODO: Rewrite this later to use an octtree - - //Sanity check... + // Sanity check... if (world.provider.dimensionId != id) { throw new IllegalArgumentException("Attempted to search for links in a World instance for a different dimension!"); } - //Note: Only detect rifts at a distance > 1, so we ignore the rift - //that called this function and any adjacent rifts. - - DimLink nearest = null; + // Note: Only detect rifts at a distance > 0, so we ignore the rift + // at the center of the search space. DimLink link; - + DimLink nearest = null; + + int i, j, k; int distance; int minDistance = Integer.MAX_VALUE; - int i, j, k; DDProperties properties = DDProperties.instance(); for (i = -range; i <= range; i++) @@ -232,7 +238,7 @@ public abstract class NewDimData distance = getAbsoluteSum(i, j, k); if (distance > 0 && distance < minDistance && world.getBlockId(x + i, y + j, z + k) == properties.RiftBlockID) { - link = getLink(x+i, y+j, z+k); + link = getLink(x + i, y + j, z + k); if (link != null) { nearest = link; @@ -248,24 +254,20 @@ public abstract class NewDimData public ArrayList findRiftsInRange(World world, int range, int x, int y, int z) { - ArrayList links = new ArrayList(); - //TODO: Rewrite this later to use an octtree - - //Sanity check... + // Sanity check... if (world.provider.dimensionId != id) { throw new IllegalArgumentException("Attempted to search for links in a World instance for a different dimension!"); } - - //Note: Only detect rifts at a distance > 1, so we ignore the rift - //that called this function and any adjacent rifts. - - DimLink link; - - int distance; - int i, j, k; - DDProperties properties = DDProperties.instance(); + // Note: Only detect rifts at a distance > 0, so we ignore the rift + // at the center of the search space. + int i, j, k; + int distance; + DimLink link; + DDProperties properties = DDProperties.instance(); + ArrayList links = new ArrayList(); + for (i = -range; i <= range; i++) { for (j = -range; j <= range; j++) @@ -275,7 +277,7 @@ public abstract class NewDimData distance = getAbsoluteSum(i, j, k); if (distance > 0 && world.getBlockId(x + i, y + j, z + k) == properties.RiftBlockID) { - link = getLink(x+i, y+j, z+k); + link = getLink(x + i, y + j, z + k); if (link != null) { links.add(link); @@ -300,13 +302,26 @@ public abstract class NewDimData public DimLink createLink(Point4D source, int linkType, int orientation) { - //Return an existing link if there is one to avoid creating multiple links starting at the same point. + // Return an existing link if there is one to avoid creating multiple links starting at the same point. InnerDimLink link = linkMapping.get(source); if (link == null) { link = new InnerDimLink(source, linkType, orientation); linkMapping.put(source, link); linkList.add(link); + + // If this code is running on the server side, add this link to chunkMapping. + if (linkType != LinkTypes.CLIENT_SIDE) + { + ChunkCoordIntPair chunk = link.getChunkCoordinates(); + List chunkLinks = chunkMapping.get(chunk); + if (chunkLinks == null) + { + chunkLinks = new ArrayList(EXPECTED_LINKS_PER_CHUNK); + chunkMapping.put(chunk, chunkLinks); + } + chunkLinks.add(link); + } } else { @@ -314,7 +329,7 @@ public abstract class NewDimData } modified = true; - //Link created! + // Link created! if (linkType != LinkTypes.CLIENT_SIDE) { linkWatcher.onCreated(link.link); @@ -334,8 +349,8 @@ public abstract class NewDimData private DimLink createChildLink(Point4D source, InnerDimLink parent) { - //To avoid having multiple links at a single point, if we find an existing link then we overwrite - //its destination data instead of creating a new instance. + // To avoid having multiple links at a single point, if we find an existing link then we overwrite + // its destination data instead of creating a new instance. InnerDimLink link = linkMapping.get(source); if (link == null) @@ -344,14 +359,28 @@ public abstract class NewDimData linkMapping.put(source, link); linkList.add(link); - //Link created! + // If this code is running on the server side, add this link to chunkMapping. + // Granted, the client side code should never create child links anyway... + if (link.linkType() != LinkTypes.CLIENT_SIDE) + { + ChunkCoordIntPair chunk = link.getChunkCoordinates(); + List chunkLinks = chunkMapping.get(chunk); + if (chunkLinks == null) + { + chunkLinks = new ArrayList(EXPECTED_LINKS_PER_CHUNK); + chunkMapping.put(chunk, chunkLinks); + } + chunkLinks.add(link); + } + + // Link created! linkWatcher.onCreated(link.link); } else { if (link.overwrite(parent, parent.link.orientation)) { - //Link created! + // Link created! linkWatcher.onCreated(link.link); } } @@ -369,7 +398,19 @@ public abstract class NewDimData if (target != null) { linkList.remove(target); - //Raise deletion event + + // If this code is running on the server side, remove this link to chunkMapping. + if (link.linkType() != LinkTypes.CLIENT_SIDE) + { + ChunkCoordIntPair chunk = target.getChunkCoordinates(); + List chunkLinks = chunkMapping.get(chunk); + if (chunkLinks != null) + { + chunkLinks.remove(target); + } + } + + // Raise deletion event linkWatcher.onDeleted(target.link); target.clear(); modified = true; @@ -377,9 +418,8 @@ public abstract class NewDimData return (target != null); } - public boolean deleteLink(int x, int y, int z) + public boolean deleteLink(Point4D location) { - Point4D location = new Point4D(x, y, z, id); return this.deleteLink(this.getLink(location)); } @@ -391,7 +431,7 @@ public abstract class NewDimData public DimLink getLink(Point3D location) { - return linkMapping.get(new Point4D(location.getX(),location.getY(),location.getZ(),this.id)); + return linkMapping.get(new Point4D(location.getX(), location.getY(), location.getZ(), this.id)); } public DimLink getLink(Point4D location) @@ -621,6 +661,16 @@ public abstract class NewDimData return linkList.get(0); } + public Iterable getChunkLinks(int chunkX, int chunkZ) + { + List chunkLinks = chunkMapping.get(new ChunkCoordIntPair(chunkX, chunkZ)); + if (chunkLinks != null) + { + return chunkLinks; + } + return new ArrayList(0); + } + public boolean isModified() { return modified; diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/core/PocketManager.java b/src/main/java/StevenDimDoors/mod_pocketDim/core/PocketManager.java index 5a1f1d68..1939e1d7 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/core/PocketManager.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/core/PocketManager.java @@ -171,9 +171,8 @@ public class PocketManager public void onDeleted(ClientLinkData link) { Point4D source = link.point; - NewDimData dimension = getDimensionData(source.getDimension()); - dimension.deleteLink(source.getX(), source.getY(), source.getZ()); - } + getDimensionData(source.getDimension()).deleteLink(source); + } } private static class ClientDimWatcher implements IUpdateWatcher diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/helpers/ChunkLoaderHelper.java b/src/main/java/StevenDimDoors/mod_pocketDim/helpers/ChunkLoaderHelper.java index e866ec49..6483afd3 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/helpers/yCoordHelper.java b/src/main/java/StevenDimDoors/mod_pocketDim/helpers/yCoordHelper.java index 3810c8b9..26aa1788 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/helpers/yCoordHelper.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/helpers/yCoordHelper.java @@ -215,10 +215,7 @@ public class yCoordHelper { for (int dz = -1; dz <= 1; dz++) { - if (!provider.chunkExists(chunkX + dx, chunkZ + dz)) - { - provider.loadChunk(chunkX, chunkZ); - } + provider.loadChunk(chunkX, chunkZ); } } return target; diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemRiftSignature.java b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemRiftSignature.java index 9cc5053f..84dbde65 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemRiftSignature.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemRiftSignature.java @@ -71,7 +71,8 @@ public class ItemRiftSignature extends Item int orientation = MathHelper.floor_double(((player.rotationYaw + 180.0F) * 4.0F / 360.0F) - 0.5D) & 3; if (source != null) { - //The link was used before and already has an endpoint stored. Create links connecting the two endpoints. + // The link was used before and already has an endpoint stored. + // Create links connecting the two endpoints. NewDimData sourceDimension = PocketManager.getDimensionData(source.getDimension()); NewDimData destinationDimension = PocketManager.getDimensionData(world); DimLink link = sourceDimension.createLink(source.getX(), source.getY(), source.getZ(), LinkTypes.NORMAL,source.getOrientation()); @@ -79,27 +80,21 @@ public class ItemRiftSignature extends Item destinationDimension.setLinkDestination(link, x, adjustedY, z); sourceDimension.setLinkDestination(reverse, source.getX(), source.getY(), source.getZ()); - //Try placing a rift at the destination point - if (!mod_pocketDim.blockRift.isBlockImmune(world, x, adjustedY, z)) - { - world.setBlock(x, adjustedY, z, mod_pocketDim.blockRift.blockID); - } + // Try placing a rift at the destination point + mod_pocketDim.blockRift.tryPlacingRift(world, x, adjustedY, z); - //Try placing a rift at the source point, but check if its world is loaded first + // Try placing a rift at the source point + // We don't need to check if sourceWorld is null - that's already handled. World sourceWorld = DimensionManager.getWorld(sourceDimension.id()); - if (sourceWorld != null && - !mod_pocketDim.blockRift.isBlockImmune(sourceWorld, source.getX(), source.getY(), source.getZ())) - { - sourceWorld.setBlock(source.getX(), source.getY(), source.getZ(), mod_pocketDim.blockRift.blockID); - } + mod_pocketDim.blockRift.tryPlacingRift(sourceWorld, source.getX(), source.getY(), source.getZ()); if (!player.capabilities.isCreativeMode) { stack.stackSize--; } clearSource(stack); - mod_pocketDim.sendChat(player,("Rift Created")); - world.playSoundAtEntity(player,mod_pocketDim.modid+":riftEnd", 0.6f, 1); + mod_pocketDim.sendChat(player, "Rift Created"); + world.playSoundAtEntity(player, mod_pocketDim.modid + ":riftEnd", 0.6f, 1); } else { diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemStabilizedRiftSignature.java b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemStabilizedRiftSignature.java index b47bff6b..c06d5984 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemStabilizedRiftSignature.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemStabilizedRiftSignature.java @@ -90,19 +90,13 @@ public class ItemStabilizedRiftSignature extends ItemRiftSignature sourceDimension.setLinkDestination(reverse, source.getX(), source.getY(), source.getZ()); // Try placing a rift at the destination point - if (!mod_pocketDim.blockRift.isBlockImmune(world, x, adjustedY, z)) - { - world.setBlock(x, adjustedY, z, mod_pocketDim.blockRift.blockID); - } + mod_pocketDim.blockRift.tryPlacingRift(world, x, adjustedY, z); } - - // Try placing a rift at the source point, but check if its world is loaded first + + // Try placing a rift at the source point + // We don't need to check if sourceWorld is null - that's already handled. World sourceWorld = DimensionManager.getWorld(sourceDimension.id()); - if (sourceWorld != null && - !mod_pocketDim.blockRift.isBlockImmune(sourceWorld, source.getX(), source.getY(), source.getZ())) - { - sourceWorld.setBlock(source.getX(), source.getY(), source.getZ(), mod_pocketDim.blockRift.blockID); - } + mod_pocketDim.blockRift.tryPlacingRift(sourceWorld, source.getX(), source.getY(), source.getZ()); mod_pocketDim.sendChat(player, "Rift Created"); world.playSoundAtEntity(player, "mods.DimDoors.sfx.riftEnd", 0.6f, 1); @@ -111,8 +105,8 @@ public class ItemStabilizedRiftSignature extends ItemRiftSignature { // The link signature has not been used. Store its current target as the first location. setSource(stack, x, adjustedY, z, orientation, PocketManager.getDimensionData(world)); - mod_pocketDim.sendChat(player,"Location Stored in Stabilized Rift Signature"); - world.playSoundAtEntity(player,"mods.DimDoors.sfx.riftStart", 0.6f, 1); + mod_pocketDim.sendChat(player, "Location Stored in Stabilized Rift Signature"); + world.playSoundAtEntity(player, "mods.DimDoors.sfx.riftStart", 0.6f, 1); } return true; } @@ -148,14 +142,11 @@ public class ItemStabilizedRiftSignature extends ItemRiftSignature // Only the source-to-destination link is needed. link = sourceDimension.createLink(source.getX(), source.getY(), source.getZ(), LinkTypes.NORMAL, source.getOrientation()); destinationDimension.setLinkDestination(link, x, adjustedY, z); - - // Try placing a rift at the source point, but check if its world is loaded first + + // Try placing a rift at the source point + // We don't need to check if sourceWorld is null - that's already handled. World sourceWorld = DimensionManager.getWorld(sourceDimension.id()); - if (sourceWorld != null && - !mod_pocketDim.blockRift.isBlockImmune(sourceWorld, source.getX(), source.getY(), source.getZ())) - { - sourceWorld.setBlock(source.getX(), source.getY(), source.getZ(), mod_pocketDim.blockRift.blockID); - } + mod_pocketDim.blockRift.tryPlacingRift(sourceWorld, source.getX(), source.getY(), source.getZ()); // This call doesn't seem to be working... world.playSoundEffect(x + 0.5, adjustedY + 0.5, z + 0.5, "mods.DimDoors.sfx.riftEnd", 0.6f, 1); diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java b/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java index a044a066..a8633d99 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java @@ -52,12 +52,11 @@ import StevenDimDoors.mod_pocketDim.items.ItemUnstableDoor; import StevenDimDoors.mod_pocketDim.items.ItemWarpDoor; import StevenDimDoors.mod_pocketDim.items.ItemWorldThread; import StevenDimDoors.mod_pocketDim.items.itemRiftRemover; -import StevenDimDoors.mod_pocketDim.ticking.CommonTickHandler; 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; import StevenDimDoors.mod_pocketDim.tileentities.TileEntityDimDoor; import StevenDimDoors.mod_pocketDim.tileentities.TileEntityDimDoorGold; import StevenDimDoors.mod_pocketDim.tileentities.TileEntityRift; @@ -65,11 +64,11 @@ 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; import StevenDimDoors.mod_pocketDimClient.ClientPacketHandler; -import StevenDimDoors.mod_pocketDimClient.ClientTickHandler; import cpw.mods.fml.common.Mod; import cpw.mods.fml.common.Mod.EventHandler; import cpw.mods.fml.common.Mod.Instance; @@ -143,9 +142,12 @@ 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. - public static FastRiftRegenerator fastRiftRegenerator; + public static RiftRegenerator riftRegenerator; 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 @@ -183,17 +185,14 @@ public class mod_pocketDim @EventHandler public void onInitialization(FMLInitializationEvent event) { - CommonTickHandler commonTickHandler = new CommonTickHandler(); - TickRegistry.registerTickHandler(new ClientTickHandler(), Side.CLIENT); - 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"); @@ -202,7 +201,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")); @@ -319,7 +318,14 @@ 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(); + spawner = null; + riftRegenerator = null; + limboDecayScheduler = null; } catch (Exception e) { @@ -334,10 +340,17 @@ 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, blockRift); + limboDecayScheduler = new LimboDecayScheduler(serverTickHandler, limboDecay); + + hooks.setSessionFields(worldProperties, riftRegenerator); } @EventHandler @@ -355,7 +368,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 ddc018cf..231eec2a 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 deleted file mode 100644 index b0f203ff..00000000 --- a/src/main/java/StevenDimDoors/mod_pocketDim/ticking/FastRiftRegenerator.java +++ /dev/null @@ -1,53 +0,0 @@ -package StevenDimDoors.mod_pocketDim.ticking; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Random; - -import net.minecraft.world.World; -import net.minecraftforge.common.DimensionManager; -import StevenDimDoors.mod_pocketDim.mod_pocketDim; -import StevenDimDoors.mod_pocketDim.core.PocketManager; -import StevenDimDoors.mod_pocketDim.util.Point4D; - -public class FastRiftRegenerator implements IRegularTickReceiver { - - private static final int RIFT_REGENERATION_INTERVAL = 10; //Regenerate scheduled rifts every 10 ticks - private static Random random = new Random(); - - private ArrayList locationsToRegen = new ArrayList(); - - public FastRiftRegenerator(IRegularTickSender sender) - { - sender.registerForTicking(this, RIFT_REGENERATION_INTERVAL, false); - } - - @Override - public void notifyTick() - { - regenerateScheduledRifts(); - } - - public void regenerateScheduledRifts() - { - if (!locationsToRegen.isEmpty()) - { - List loadedWorlds = (List) Arrays.asList(DimensionManager.getIDs()); - for (Point4D point: locationsToRegen) - { - if (loadedWorlds.contains(point.getDimension()) && PocketManager.getLink(point) != null) - { - World world = DimensionManager.getWorld(point.getDimension()); - mod_pocketDim.blockRift.regenerateRift(world, point.getX(), point.getY(), point.getZ(), random); - } - } - locationsToRegen.clear(); - } - } - - public void registerRiftForRegen(int x, int y, int z, int dimID) - { - this.locationsToRegen.add(new Point4D(x, y, z, dimID)); - } -} diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/ticking/IRegularTickSender.java b/src/main/java/StevenDimDoors/mod_pocketDim/ticking/IRegularTickSender.java index 6ed2dcaf..7b5502c4 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 00000000..73f275cd --- /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 192669cc..f23c38c3 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/ticking/RiftRegenerator.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/ticking/RiftRegenerator.java @@ -1,56 +1,121 @@ package StevenDimDoors.mod_pocketDim.ticking; -import java.util.Arrays; -import java.util.List; +import java.util.PriorityQueue; import java.util.Random; +import net.minecraft.util.MathHelper; import net.minecraft.world.World; import net.minecraftforge.common.DimensionManager; -import StevenDimDoors.mod_pocketDim.mod_pocketDim; +import StevenDimDoors.mod_pocketDim.blocks.BlockRift; import StevenDimDoors.mod_pocketDim.core.DimLink; -import StevenDimDoors.mod_pocketDim.core.NewDimData; import StevenDimDoors.mod_pocketDim.core.PocketManager; import StevenDimDoors.mod_pocketDim.util.Point4D; public class RiftRegenerator implements IRegularTickReceiver { - private static final int RIFT_REGENERATION_INTERVAL = 200; //Regenerate random rifts every 200 ticks - private static final int RIFTS_REGENERATED_PER_DIMENSION = 5; + // Ranges of regeneration delays, in seconds + private static final int MIN_FAST_DELAY = 1; + private static final int MAX_FAST_DELAY = 3; + private static final int MIN_SLOW_DELAY = 5; + private static final int MAX_SLOW_DELAY = 15; + private static final int MIN_RESCHEDULE_DELAY = 4 * 60; + private static final int MAX_RESCHEDULE_DELAY = 6 * 60; + + private static final int TICKS_PER_SECOND = 20; + private static final int RIFT_REGENERATION_INTERVAL = 1; // Check the regeneration queue every tick private static Random random = new Random(); - public RiftRegenerator(IRegularTickSender sender) + private long tickCount = 0; + private PriorityQueue ticketQueue; + private BlockRift blockRift; + + public RiftRegenerator(IRegularTickSender sender, BlockRift blockRift) { - sender.registerForTicking(this, RIFT_REGENERATION_INTERVAL, false); + this.ticketQueue = new PriorityQueue(); + this.blockRift = blockRift; + sender.registerReceiver(this, RIFT_REGENERATION_INTERVAL, false); } @Override public void notifyTick() { - regenerateRiftsInLoadedWorlds(); + processTicketQueue(); + tickCount++; } - private static void regenerateRiftsInLoadedWorlds() + public void scheduleSlowRegeneration(DimLink link) { - // Regenerate rifts that have been replaced (not permanently removed) by players - // Only do this in dimensions that are currently loaded - List loadedWorlds = Arrays.asList(DimensionManager.getIDs()); - for (Integer dimensionID : loadedWorlds) - { - NewDimData dimension = PocketManager.getDimensionData(dimensionID); - if (dimension.linkCount() > 0) - { - World world = DimensionManager.getWorld(dimension.id()); - - if (world != null) - { - for (int count = 0; count < RIFTS_REGENERATED_PER_DIMENSION; count++) - { - DimLink link = dimension.getRandomLink(); - Point4D source = link.source(); - mod_pocketDim.blockRift.regenerateRift(world, source.getX(), source.getY(), source.getZ(), random); - } - } - } - } + scheduleRegeneration(link, MIN_SLOW_DELAY, MAX_SLOW_DELAY); } + + public void scheduleSlowRegeneration(int x, int y, int z, World world) + { + scheduleRegeneration(PocketManager.getLink(x, y, z, world), MIN_SLOW_DELAY, MAX_SLOW_DELAY); + } + + public void scheduleFastRegeneration(int x, int y, int z, World world) + { + scheduleRegeneration(PocketManager.getLink(x, y, z, world), MIN_FAST_DELAY, MAX_FAST_DELAY); + } + + private void scheduleRegeneration(DimLink link, int minDelay, int maxDelay) + { + if (link != null) + { + int tickDelay = MathHelper.getRandomIntegerInRange(random, minDelay * TICKS_PER_SECOND, maxDelay * TICKS_PER_SECOND); + ticketQueue.add(new RiftTicket(link.source(), tickCount + tickDelay)); + } + } + + private void processTicketQueue() + { + RiftTicket ticket; + while (!ticketQueue.isEmpty() && ticketQueue.peek().timestamp() <= tickCount) + { + ticket = ticketQueue.remove(); + regenerateRift(ticket.location()); + } + } + + private void regenerateRift(Point4D location) + { + int x = location.getX(); + int y = location.getY(); + int z = location.getZ(); + + // Try to regenerate a rift, or possibly reschedule its regeneration. + // The world for the given location must be loaded. + World world = DimensionManager.getWorld(location.getDimension()); + if (world == null) + return; + + // There must be a link at the given location. + DimLink link = PocketManager.getLink(location); + if (link == null) + return; + + // The chunk at the given location must be loaded. + // Note: ChunkProviderServer.chunkExists() returns whether a chunk is + // loaded, not whether it has already been created. + if (!world.getChunkProvider().chunkExists(x >> 4, z >> 4)) + return; + + // If the location is occupied by an immune DD block, then don't regenerate. + if (blockRift.isModBlockImmune(world, x, y, z)) + return; + + // If the location is occupied by an immune block, then reschedule. + if (blockRift.isBlockImmune(world, x, y, z)) + { + scheduleRegeneration(link, MIN_RESCHEDULE_DELAY, MAX_RESCHEDULE_DELAY); + } + else + { + // All of the necessary conditions have been met. Restore the rift! + int blockID = world.getBlockId(x, y, z); + if (world.setBlock(x, y, z, blockRift.blockID)) + blockRift.dropWorldThread(blockID, world, x, y, z, random); + } + } + } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/ticking/RiftTicket.java b/src/main/java/StevenDimDoors/mod_pocketDim/ticking/RiftTicket.java new file mode 100644 index 00000000..d618a517 --- /dev/null +++ b/src/main/java/StevenDimDoors/mod_pocketDim/ticking/RiftTicket.java @@ -0,0 +1,40 @@ +package StevenDimDoors.mod_pocketDim.ticking; + +import StevenDimDoors.mod_pocketDim.util.Point4D; + +public class RiftTicket implements Comparable { + + private long timestamp; + private Point4D location; + + public RiftTicket(Point4D location, long timestamp) + { + this.timestamp = timestamp; + this.location = location; + } + + @Override + public int compareTo(RiftTicket other) + { + if (this.timestamp < other.timestamp) + { + return -1; + } + else if (this.timestamp > other.timestamp) + { + return 1; + } + return 0; + } + + public long timestamp() + { + return timestamp; + } + + public Point4D location() + { + return location; + } + +} diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/ticking/CommonTickHandler.java b/src/main/java/StevenDimDoors/mod_pocketDim/ticking/ServerTickHandler.java similarity index 85% rename from src/main/java/StevenDimDoors/mod_pocketDim/ticking/CommonTickHandler.java rename to src/main/java/StevenDimDoors/mod_pocketDim/ticking/ServerTickHandler.java index 26057b48..58da365f 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/ticking/CommonTickHandler.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/ticking/ServerTickHandler.java @@ -7,25 +7,30 @@ import StevenDimDoors.mod_pocketDim.core.DDTeleporter; import cpw.mods.fml.common.ITickHandler; import cpw.mods.fml.common.TickType; -public class CommonTickHandler implements ITickHandler, IRegularTickSender +public class ServerTickHandler implements ITickHandler, IRegularTickSender { - private static final String PROFILING_LABEL = "Dimensional Doors: Common Tick"; + private static final String PROFILING_LABEL = "Dimensional Doors: Server Tick"; private int tickCount = 0; private ArrayList receivers; - - public CommonTickHandler() + 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/tileentities/TileEntityDimDoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityDimDoor.java index fe478b65..881577c7 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityDimDoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityDimDoor.java @@ -1,17 +1,13 @@ package StevenDimDoors.mod_pocketDim.tileentities; import java.util.Random; -import StevenDimDoors.mod_pocketDim.ServerPacketHandler; -import StevenDimDoors.mod_pocketDim.mod_pocketDim; -import StevenDimDoors.mod_pocketDim.blocks.IDimDoor; -import StevenDimDoors.mod_pocketDim.core.NewDimData; -import StevenDimDoors.mod_pocketDim.core.PocketManager; -import net.minecraft.block.Block; + import net.minecraft.nbt.NBTTagCompound; import net.minecraft.network.packet.Packet; -import net.minecraft.network.packet.Packet130UpdateSign; -import net.minecraft.network.packet.Packet250CustomPayload; -import net.minecraft.tileentity.TileEntity; +import StevenDimDoors.mod_pocketDim.ServerPacketHandler; +import StevenDimDoors.mod_pocketDim.mod_pocketDim; +import StevenDimDoors.mod_pocketDim.core.DimLink; +import StevenDimDoors.mod_pocketDim.core.PocketManager; public class TileEntityDimDoor extends DDTileEntityBase { @@ -28,27 +24,14 @@ public class TileEntityDimDoor extends DDTileEntityBase } @Override - public Packet getDescriptionPacket() - { - if(PocketManager.getLink(xCoord, yCoord, zCoord, worldObj)!=null) - { - return ServerPacketHandler.createLinkPacket(PocketManager.getLink(xCoord, yCoord, zCoord, worldObj).link()); - } - return null; - } - - @Override - public void invalidate() + public Packet getDescriptionPacket() { - this.tileEntityInvalid = true; - - if(this.worldObj.getBlockId(xCoord, yCoord, zCoord)==0&&!this.worldObj.isRemote) + DimLink link = PocketManager.getLink(xCoord, yCoord, zCoord, worldObj); + if (link != null) { - if(PocketManager.getLink(xCoord, yCoord, zCoord, worldObj)!=null) - { - mod_pocketDim.fastRiftRegenerator.registerRiftForRegen(xCoord, yCoord, zCoord, this.worldObj.provider.dimensionId); - } + return ServerPacketHandler.createLinkPacket(link.link()); } + return null; } @Override @@ -74,7 +57,7 @@ public class TileEntityDimDoor extends DDTileEntityBase public void writeToNBT(NBTTagCompound nbt) { super.writeToNBT(nbt); - + nbt.setBoolean("openOrClosed", this.openOrClosed); nbt.setBoolean("hasExit", this.hasExit); nbt.setInteger("orientation", this.orientation); diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityTransTrapdoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityTransTrapdoor.java index d26b46fd..3df7f6c5 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityTransTrapdoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityTransTrapdoor.java @@ -1,14 +1,11 @@ package StevenDimDoors.mod_pocketDim.tileentities; import java.util.Random; + import StevenDimDoors.mod_pocketDim.mod_pocketDim; -import net.minecraft.nbt.NBTTagCompound; -import net.minecraft.tileentity.TileEntity; public class TileEntityTransTrapdoor extends DDTileEntityBase { - public boolean hasRift; - @Override public boolean canUpdate() { 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 e5c9420e..13edb19e 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; diff --git a/src/main/java/StevenDimDoors/mod_pocketDimClient/ClientTickHandler.java b/src/main/java/StevenDimDoors/mod_pocketDimClient/ClientTickHandler.java deleted file mode 100644 index cece273d..00000000 --- a/src/main/java/StevenDimDoors/mod_pocketDimClient/ClientTickHandler.java +++ /dev/null @@ -1,65 +0,0 @@ -package StevenDimDoors.mod_pocketDimClient; -import java.util.EnumSet; - -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.GuiScreen; -import cpw.mods.fml.common.ITickHandler; -import cpw.mods.fml.common.TickType; - -public class ClientTickHandler implements ITickHandler -{ - - @Override - public void tickStart(EnumSet type, Object... tickData) {} - - @Override - public void tickEnd(EnumSet type, Object... tickData) - { - if (type.equals(EnumSet.of(TickType.RENDER))) - { - onRenderTick(); - } - else if (type.equals(EnumSet.of(TickType.CLIENT))) - { - GuiScreen guiscreen = Minecraft.getMinecraft().currentScreen; - if (guiscreen != null) - { - onTickInGUI(guiscreen); - } else { - onTickInGame(); - } - } - } - - @Override - public EnumSet ticks() - { - return EnumSet.of(TickType.RENDER, TickType.CLIENT); - // In my testing only RENDER, CLIENT, & PLAYER did anything on the client side. - // Read 'cpw.mods.fml.common.TickType.java' for a full list and description of available types - } - - @Override - public String getLabel() { return null; } - - - public void onRenderTick() - { - //System.out.println("onRenderTick"); - //TODO: Your Code Here - } - - public void onTickInGUI(GuiScreen guiscreen) - { - //System.out.println("onTickInGUI"); - //TODO: Your Code Here - } - - public void onTickInGame() - { - - - //System.out.println("onTickInGame"); - //TODO: Your Code Here - } -} \ No newline at end of file diff --git a/src/main/java/StevenDimDoors/mod_pocketDimClient/RenderTransTrapdoor.java b/src/main/java/StevenDimDoors/mod_pocketDimClient/RenderTransTrapdoor.java index 0f3ea97d..98f8e886 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDimClient/RenderTransTrapdoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDimClient/RenderTransTrapdoor.java @@ -3,6 +3,7 @@ package StevenDimDoors.mod_pocketDimClient; import java.nio.FloatBuffer; import java.util.Random; +import net.minecraft.block.BlockTrapDoor; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.GLAllocation; import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer; @@ -38,21 +39,6 @@ public class RenderTransTrapdoor extends TileEntitySpecialRenderer */ public void renderTransTrapdoorTileEntity(TileEntityTransTrapdoor tile, double x, double y, double z, float par8) { - try - { - mod_pocketDim.transTrapdoor.updateAttachedTile(tile.worldObj, tile.xCoord, tile.yCoord, tile.zCoord); - } - catch(Exception e) - { - e.printStackTrace(); - } - - - // float playerX = (float)this.tileEntityRenderer.playerX; - // float playerY = (float)this.tileEntityRenderer.playerY; - // float playerZ = (float)this.tileEntityRenderer.playerZ; - - //float distance = (float) tile.getDistanceFrom(playerX, playerY, playerZ); GL11.glDisable(GL11.GL_LIGHTING); Random random = new Random(31100L); int metadata = tile.worldObj.getBlockMetadata(tile.xCoord, tile.yCoord, tile.zCoord); @@ -77,7 +63,6 @@ public class RenderTransTrapdoor extends TileEntitySpecialRenderer if (count == 1) { this.bindTexture(warpPath); - // move files into assets/modid and change to new ResourceLocation(modid:/WARP.png) GL11.glEnable(GL11.GL_BLEND); GL11.glBlendFunc(GL11.GL_ONE, GL11.GL_ONE); var16 = .5F; @@ -127,7 +112,7 @@ public class RenderTransTrapdoor extends TileEntitySpecialRenderer GL11.glColor4d(var21 * var17, var22 * var17, var23 * var17, 1.0F); if (TransTrapdoor.isTrapdoorSetLow(metadata)) { - if (TransTrapdoor.isTrapdoorOpen(metadata)) + if (BlockTrapDoor.isTrapdoorOpen(metadata)) { GL11.glVertex3d(x, y+0.2, z); GL11.glVertex3d(x, y+0.2, z+1); @@ -144,7 +129,7 @@ public class RenderTransTrapdoor extends TileEntitySpecialRenderer } else { - if (TransTrapdoor.isTrapdoorOpen(metadata)) + if (BlockTrapDoor.isTrapdoorOpen(metadata)) { GL11.glVertex3d(x, y+0.95, z); GL11.glVertex3d(x, y+0.95, z+1); @@ -180,7 +165,8 @@ public class RenderTransTrapdoor extends TileEntitySpecialRenderer return this.field_76908_a; } - public void renderTileEntityAt(TileEntity par1TileEntity, double par2, double par4, double par6, float par8) + @Override + public void renderTileEntityAt(TileEntity par1TileEntity, double par2, double par4, double par6, float par8) { if (properties.DoorRenderingEnabled) {