diff --git a/StevenDimDoors/mod_pocketDim/CommonTickHandler.java b/StevenDimDoors/mod_pocketDim/CommonTickHandler.java index aea89f5..11988bd 100644 --- a/StevenDimDoors/mod_pocketDim/CommonTickHandler.java +++ b/StevenDimDoors/mod_pocketDim/CommonTickHandler.java @@ -23,6 +23,7 @@ public class CommonTickHandler implements ITickHandler private static final Random rand = new Random(); public static final int MAX_MONOLITH_SPAWNING_CHANCE = 100; + private static final String label = "Dimensional Doors: Common Tick"; private static final int MAX_MONOLITH_SPAWN_Y = 245; private static final int CHUNK_SIZE = 16; private static final int RIFT_REGENERATION_INTERVAL = 100; //Regenerate random rifts every 100 ticks @@ -78,7 +79,7 @@ public class CommonTickHandler implements ITickHandler @Override public String getLabel() { - return null; + return label; //Used for profiling! } private void placeMonolithsInPockets(int worldID, int chunkX, int chunkZ) @@ -212,13 +213,14 @@ public class CommonTickHandler implements ITickHandler private void onServerTick() { - tickCount++; //There is no need to reset the counter. Let it overflow. + tickCount++; //There is no need to reset the counter. Let it overflow. Really. if (tickCount % RIFT_REGENERATION_INTERVAL == 0) { regenerateRifts(); } - + + LimboDecay.ApplyRandomFastDecay(); if (mod_pocketDim.teleTimer > 0) { @@ -230,7 +232,7 @@ public class CommonTickHandler implements ITickHandler { try { - //Replace rifts that have been replaced (not permanently removed) by players + //Regenerate rifts that have been replaced (not permanently removed) by players int i = 0; diff --git a/StevenDimDoors/mod_pocketDim/LimboDecay.java b/StevenDimDoors/mod_pocketDim/LimboDecay.java new file mode 100644 index 0000000..7d2f1e4 --- /dev/null +++ b/StevenDimDoors/mod_pocketDim/LimboDecay.java @@ -0,0 +1,170 @@ +package StevenDimDoors.mod_pocketDim; + +import java.util.Random; + +import net.minecraft.block.Block; +import net.minecraft.block.BlockContainer; +import net.minecraft.world.ChunkCoordIntPair; +import net.minecraft.world.World; +import StevenDimDoors.mod_pocketDim.helpers.dimHelper; + +/* + * Provides methods for applying the 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 { + + 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; + + //Provides a reversed list of the block IDs that blocks cycle through during decay. + //Must be initialized later since it requires DDProperties to be initialized (for LimboBlockID). + private static int[] decaySequence = null; + + private static Random random = new Random(); + private static DDProperties properties = null; + + private LimboDecay() { } + + /* + * Initializes the array containing the reversed sequence of block IDs that blocks cycle through during decay. + */ + private static void InitializeDecaySequence() + { + if (decaySequence == null) + { + if (properties == null) + properties = DDProperties.instance(); + + decaySequence = new int[] { + properties.LimboBlockID, + Block.gravel.blockID, + Block.cobblestone.blockID, + Block.stone.blockID + }; + } + } + + /* + * Checks the blocks orthogonally around a given location (presumably the location of an Unraveled Fabric block) + * and applies Limbo decay to them. This gives the impression that decay spreads outward from Unraveled Fabric. + */ + public static void ApplySpreadDecay(World world, int x, int y, int z) + { + if (properties == null) + properties = DDProperties.instance(); + + //Check if we randomly apply decay spread or not. This can be used to moderate the frequency of + //full spread decay checks, which can also shift its performance impact on the game. + if (random.nextInt(MAX_DECAY_SPREAD_CHANCE) < DECAY_SPREAD_CHANCE) + { + //Apply decay to the blocks above, below, and on all four sides. + //World.getBlockId() implements bounds checking, so we don't have to worry about reaching out of the world + DecayBlock(world, x - 1, y, z); + DecayBlock(world, x + 1, y, z); + DecayBlock(world, x, y, z - 1); + DecayBlock(world, x, y, z + 1); + DecayBlock(world, x, y - 1, z); + DecayBlock(world, x, y + 1, z); + } + } + + /* + * 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. + */ + public static void ApplyRandomFastDecay() + { + if (properties == null) + properties = DDProperties.instance(); + + int x, y, z; + int sectionY; + int limboHeight; + World limbo = dimHelper.getWorld(properties.LimboDimensionID); + + if (limbo != null) + { + limboHeight = limbo.getHeight(); + + //Obtain the coordinates of active chunks in Limbo. For each section of each chunk, + //pick a random block and try to apply fast decay. + for (Object coordObject : limbo.activeChunkSet) + { + ChunkCoordIntPair chunkCoord = (ChunkCoordIntPair) coordObject; + + //Loop through each chunk section and fast-decay a random block + //Apply the changes using the world object instead of directly to the chunk so that clients are always notified. + for (sectionY = 0; sectionY < limboHeight; sectionY += SECTION_HEIGHT) + { + x = chunkCoord.chunkXPos * CHUNK_SIZE + random.nextInt(CHUNK_SIZE); + z = chunkCoord.chunkZPos * CHUNK_SIZE + random.nextInt(CHUNK_SIZE); + y = sectionY + random.nextInt(SECTION_HEIGHT); + DecayBlockFast(limbo, x, y, z); + } + } + } + } + + /* + * Checks if a block can be decayed and, if so, changes it directly into Unraveled Fabric. + */ + private static boolean DecayBlockFast(World world, int x, int y, int z) + { + int blockID = world.getBlockId(x, y, z); + if (CanDecayBlock(blockID)) + { + world.setBlock(x, y, z, properties.LimboBlockID); + return true; + } + return false; + } + + /* + * Checks if a block can be decayed and, if so, changes it to the next block ID along the decay sequence. + */ + private static boolean DecayBlock(World world, int x, int y, int z) + { + //Make sure the decay sequence is initialized + InitializeDecaySequence(); + + int index; + int blockID = world.getBlockId(x, y, z); + if (CanDecayBlock(blockID)) + { + //Loop over the block IDs that decay can go through. + //Find an index matching the current blockID, if any. + for (index = 0; index < decaySequence.length; index++) + { + if (decaySequence[index] == blockID) + { + break; + } + } + + //Since the decay sequence is a reversed list, the block ID in the index before our match + //is the block ID we should change this block into. A trick in this approach is that if + //we loop over the array without finding a match, then (index - 1) will contain the + //last ID in the array, which is the first one that all blocks decay into. + //We assume that Unraveled Fabric is NOT decayable. Otherwise, this will go out of bounds! + + world.setBlock(x, y, z, decaySequence[index - 1]); + return true; + } + return false; + } + + /* + * Checks if a block can decay. We will not decay air, Unraveled Fabric, Eternal Fabric, or containers. + */ + private static boolean CanDecayBlock(int blockID) + { + if (blockID == 0 || blockID == properties.LimboBlockID || blockID == properties.PermaFabricBlockID) + return false; + + Block block = Block.blocksList[blockID]; + return (block == null || !(block instanceof BlockContainer)); + } +} diff --git a/StevenDimDoors/mod_pocketDim/blocks/BlockLimbo.java b/StevenDimDoors/mod_pocketDim/blocks/BlockLimbo.java index 4bc690e..bfbd133 100644 --- a/StevenDimDoors/mod_pocketDim/blocks/BlockLimbo.java +++ b/StevenDimDoors/mod_pocketDim/blocks/BlockLimbo.java @@ -1,20 +1,28 @@ package StevenDimDoors.mod_pocketDim.blocks; +import java.util.Random; + import net.minecraft.block.Block; import net.minecraft.block.material.Material; import net.minecraft.client.renderer.texture.IconRegister; import net.minecraft.util.Icon; import net.minecraft.world.IBlockAccess; +import net.minecraft.world.World; +import StevenDimDoors.mod_pocketDim.LimboDecay; import StevenDimDoors.mod_pocketDim.mod_pocketDim; import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; public class BlockLimbo extends Block { - public BlockLimbo(int i, int j, Material par2Material) + private final int limboDimensionID; + + public BlockLimbo(int i, int j, Material par2Material, int limboDimensionID) { super(i, Material.ground); - this.setCreativeTab(mod_pocketDim.dimDoorsCreativeTab); + this.limboDimensionID = limboDimensionID; + this.setTickRandomly(true); + this.setCreativeTab(mod_pocketDim.dimDoorsCreativeTab); } /** @@ -38,4 +46,17 @@ public class BlockLimbo extends Block { return this.blockIcon; } + + /** + * If the block is in Limbo, attempt to decay surrounding blocks upon receiving a random update tick. + */ + @Override + public void updateTick(World world, int x, int y, int z, Random random) + { + //Make sure this block is in Limbo + if (world.provider.dimensionId == limboDimensionID) + { + LimboDecay.ApplySpreadDecay(world, x, y, z); + } + } } diff --git a/StevenDimDoors/mod_pocketDim/mod_pocketDim.java b/StevenDimDoors/mod_pocketDim/mod_pocketDim.java index 89d6146..eadedad 100644 --- a/StevenDimDoors/mod_pocketDim/mod_pocketDim.java +++ b/StevenDimDoors/mod_pocketDim/mod_pocketDim.java @@ -182,7 +182,7 @@ public class mod_pocketDim blockDimWallPerm = (new BlockDimWallPerm(properties.PermaFabricBlockID, 0, Material.iron)).setLightValue(1.0F).setBlockUnbreakable().setResistance(6000000.0F).setUnlocalizedName("blockDimWallPerm"); ExitDoor = (new ExitDoor(properties.WarpDoorID, Material.wood)).setHardness(1.0F) .setUnlocalizedName("dimDoorWarp"); blockRift = (new BlockRift(properties.RiftBlockID, 0, Material.air).setHardness(1.0F) .setUnlocalizedName("rift")); - blockLimbo = (new BlockLimbo(properties.LimboBlockID, 15, Material.iron).setHardness(.2F).setUnlocalizedName("BlockLimbo").setLightValue(.0F)); + blockLimbo = (new BlockLimbo(properties.LimboBlockID, 15, Material.iron, properties.LimboDimensionID).setHardness(.2F).setUnlocalizedName("BlockLimbo").setLightValue(.0F)); chaosDoor = (new ChaosDoor(properties.UnstableDoorID, Material.iron).setHardness(.2F).setUnlocalizedName("chaosDoor").setLightValue(.0F) ); dimDoor = (new dimDoor(properties.DimensionalDoorID, Material.iron)).setHardness(1.0F).setResistance(2000.0F) .setUnlocalizedName("dimDoor"); dimHatch = (new dimHatch(properties.TransTrapdoorID, 84, Material.iron)).setHardness(1.0F) .setUnlocalizedName("dimHatch");