diff --git a/build.gradle b/build.gradle index 487f821..1555934 100644 --- a/build.gradle +++ b/build.gradle @@ -13,14 +13,15 @@ buildscript { apply plugin: 'forge' - - -version = "2.2.2RC1-" + System.getenv("BUILD_NUMBER") -group= "com.stevenrs11.dimdoors" // http://maven.apache.org/guides/mini/guide-naming-conventions.html +version = "2.2.4-" + System.getenv("BUILD_NUMBER") +group = "com.stevenrs11.dimdoors" // http://maven.apache.org/guides/mini/guide-naming-conventions.html archivesBaseName = "DimensionalDoors" minecraft { - version = "1.6.4-9.11.1.964" + version = "1.6.4-9.11.1.964" + + replaceIn "mod_pocketDim.java" + replace "@VERSION@", project.version } targetCompatibility = '1.6' @@ -28,15 +29,15 @@ sourceCompatibility = '1.6' processResources { - // replace stuff in mcmod.info, nothing else + // Replace stuff $version and $mcversion in mcmod.info from(sourceSets.main.resources.srcDirs) { include 'mcmod.info' - - // replace version and mcversion + + // Replace version and mcversion expand 'version':project.version, 'mcversion':project.minecraft.version } - // copy everything else, thats not the mcmod.info + // Copy everything else from(sourceSets.main.resources.srcDirs) { exclude 'mcmod.info' } diff --git a/src/main/java/StevenDimDoors/experimental/SphereDecayOperation.java b/src/main/java/StevenDimDoors/experimental/SphereDecayOperation.java index 95587b6..0af0bac 100644 --- a/src/main/java/StevenDimDoors/experimental/SphereDecayOperation.java +++ b/src/main/java/StevenDimDoors/experimental/SphereDecayOperation.java @@ -12,8 +12,8 @@ import net.minecraft.tileentity.TileEntityChest; import net.minecraft.tileentity.TileEntityDispenser; import net.minecraft.world.World; import StevenDimDoors.mod_pocketDim.DDLoot; -import StevenDimDoors.mod_pocketDim.DDProperties; import StevenDimDoors.mod_pocketDim.Point3D; +import StevenDimDoors.mod_pocketDim.config.DDProperties; import StevenDimDoors.mod_pocketDim.schematic.WorldOperation; /** diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/CommonProxy.java b/src/main/java/StevenDimDoors/mod_pocketDim/CommonProxy.java index ada7b95..5f48227 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/CommonProxy.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/CommonProxy.java @@ -1,11 +1,14 @@ package StevenDimDoors.mod_pocketDim; import java.io.File; import java.io.FileOutputStream; +import StevenDimDoors.mod_pocketDim.blocks.BaseDimDoor; +import StevenDimDoors.mod_pocketDim.tileentities.TileEntityDimDoor; import net.minecraft.entity.Entity; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.nbt.CompressedStreamTools; import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; import net.minecraft.world.World; import cpw.mods.fml.common.FMLCommonHandler; import cpw.mods.fml.common.network.IGuiHandler; @@ -18,7 +21,6 @@ public class CommonProxy implements IGuiHandler public static String WARP_PNG = "/WARP.png"; public void registerRenderers() - { } public void registerEntity(Class entity, String entityname, int id, Object mod, int trackingrange, int updateFreq, boolean updatevelo) @@ -130,6 +132,20 @@ public class CommonProxy implements IGuiHandler { } + public void updateDoorTE(BaseDimDoor door, World world, int x, int y, int z) + { + TileEntity tile = world.getBlockTileEntity(x, y, z); + if (tile instanceof TileEntityDimDoor) + { + int metadata = world.getBlockMetadata(x, y, z); + TileEntityDimDoor dimTile = (TileEntityDimDoor) tile; + dimTile.openOrClosed = door.isDoorOnRift(world, x, y, z)&&door.isUpperDoorBlock(metadata); + dimTile.orientation = door.getFullMetadata(world, x, y, z) & 7; + dimTile.lockStatus = door.getLockStatus(world, x, y, z); + } + } + + } \ No newline at end of file diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/ConnectionHandler.java b/src/main/java/StevenDimDoors/mod_pocketDim/ConnectionHandler.java index 9a8a17a..156ecce 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/ConnectionHandler.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/ConnectionHandler.java @@ -1,17 +1,11 @@ package StevenDimDoors.mod_pocketDim; -import java.io.ByteArrayOutputStream; -import java.io.DataOutputStream; -import java.io.IOException; - -import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.network.INetworkManager; import net.minecraft.network.NetLoginHandler; import net.minecraft.network.packet.NetHandler; import net.minecraft.network.packet.Packet1Login; import net.minecraft.network.packet.Packet250CustomPayload; import net.minecraft.server.MinecraftServer; -import net.minecraft.server.integrated.IntegratedServer; import net.minecraftforge.common.DimensionManager; import net.minecraftforge.common.network.ForgePacket; import net.minecraftforge.common.network.packet.DimensionRegisterPacket; @@ -65,7 +59,8 @@ public class ConnectionHandler implements IConnectionHandler @Override public void playerLoggedIn(Player player, NetHandler netHandler, INetworkManager manager) { - PocketManager.getDimwatcher().onCreated(new ClientDimData(PocketManager.getDimensionData(0))); + // Hax... please don't do this! >_< + PocketManager.getDimwatcher().onCreated(new ClientDimData(PocketManager.createDimensionDataDangerously(0))); } } \ No newline at end of file diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/CraftingManager.java b/src/main/java/StevenDimDoors/mod_pocketDim/CraftingManager.java index 9109f16..cc48470 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/CraftingManager.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/CraftingManager.java @@ -1,97 +1,170 @@ package StevenDimDoors.mod_pocketDim; + import net.minecraft.block.Block; +import net.minecraft.block.BlockDispenser; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.IInventory; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; +import net.minecraftforge.oredict.ShapedOreRecipe; +import StevenDimDoors.mod_pocketDim.config.DDProperties; +import StevenDimDoors.mod_pocketDim.core.DDLock; +import StevenDimDoors.mod_pocketDim.items.ItemDDKey; +import StevenDimDoors.mod_pocketDim.items.behaviors.DispenserBehaviorStabilizedRS; +import cpw.mods.fml.common.ICraftingHandler; import cpw.mods.fml.common.registry.GameRegistry; -import static StevenDimDoors.mod_pocketDim.mod_pocketDim.*; -public class CraftingManager +public class CraftingManager implements ICraftingHandler { - + CraftingManager() { } + public static void registerRecipes(DDProperties properties) - { - if (properties.CraftingDimensionalDoorAllowed) - { - GameRegistry.addRecipe(new ItemStack(itemDimensionalDoor, 1), new Object[] - { - " ", "yxy", " ", 'x', mod_pocketDim.itemStableFabric, 'y', Item.doorIron - }); - } - if(properties.CraftingUnstableDoorAllowed) - { - GameRegistry.addRecipe(new ItemStack(itemUnstableDoor, 1), new Object[] - { - " ", "yxy", " ", 'x', Item.eyeOfEnder, 'y', mod_pocketDim.itemDimensionalDoor - }); - } - if(properties.CraftingWarpDoorAllowed) - { - GameRegistry.addRecipe(new ItemStack(itemWarpDoor, 1), new Object[] - { - " ", "yxy", " ", 'x', mod_pocketDim.itemStableFabric, 'y', Item.doorWood - }); - } - if(properties.CraftingTransTrapdoorAllowed) - { - GameRegistry.addRecipe(new ItemStack(transTrapdoor, 1), new Object[] - { - " y ", " x ", " y ", 'x', mod_pocketDim.itemStableFabric, 'y', Block.trapdoor - }); - } - if(properties.CraftingRiftSignatureAllowed) - { - GameRegistry.addRecipe(new ItemStack(itemRiftSignature, 1), new Object[] - { - " y ", "yxy", " y ", 'x', mod_pocketDim.itemStableFabric, 'y', Item.ingotIron - }); - } - - if(properties.CraftingRiftRemoverAllowed) - { - GameRegistry.addRecipe(new ItemStack(itemRiftRemover, 1), new Object[] - { - "yyy", "yxy", "yyy", 'x', mod_pocketDim.itemStableFabric, 'y', Item.ingotGold - }); - } - - if (properties.CraftingRiftBladeAllowed) - { - GameRegistry.addRecipe(new ItemStack(itemRiftBlade, 1), new Object[] - { - " x ", " x ", " y ", 'x', mod_pocketDim.itemStableFabric, 'y', Item.blazeRod - }); - } - + { if (properties.CraftingStableFabricAllowed) { - GameRegistry.addRecipe(new ItemStack(itemStableFabric, 1), new Object[] - { - "yyy", "yxy", "yyy", 'x', Item.enderPearl, 'y', mod_pocketDim.itemWorldThread - }); + switch (properties.WorldThreadRequirementLevel) + { + case 1: + GameRegistry.addShapelessRecipe(new ItemStack(mod_pocketDim.itemStableFabric, 1), + Item.enderPearl, mod_pocketDim.itemWorldThread); + break; + case 2: + GameRegistry.addRecipe(new ItemStack(mod_pocketDim.itemStableFabric, 1), + "yxy", 'x', Item.enderPearl, 'y', mod_pocketDim.itemWorldThread); + break; + case 3: + GameRegistry.addRecipe(new ItemStack(mod_pocketDim.itemStableFabric, 1), + " y ", "yxy", " y ", 'x', Item.enderPearl, 'y', mod_pocketDim.itemWorldThread); + break; + default: + GameRegistry.addRecipe(new ItemStack(mod_pocketDim.itemStableFabric, 1), + "yyy", "yxy", "yyy", 'x', Item.enderPearl, 'y', mod_pocketDim.itemWorldThread); + break; + } } + if (properties.CraftingDimensionalDoorAllowed) + { + GameRegistry.addRecipe(new ItemStack(mod_pocketDim.itemDimensionalDoor, 1), + "yxy", 'x', mod_pocketDim.itemStableFabric, 'y', Item.doorIron); + } + if (properties.CraftingUnstableDoorAllowed) + { + GameRegistry.addRecipe(new ItemStack(mod_pocketDim.itemUnstableDoor, 1), + "yxy", 'x', Item.eyeOfEnder, 'y', mod_pocketDim.itemDimensionalDoor); + } + if (properties.CraftingWarpDoorAllowed) + { + + GameRegistry.addRecipe(new ItemStack(mod_pocketDim.itemWarpDoor, 1), + "yxy", 'x', Item.enderPearl, 'y', Item.doorWood); + } + if (properties.CraftingTransTrapdoorAllowed) + { + + GameRegistry.addRecipe(new ItemStack(mod_pocketDim.transTrapdoor, 1), + "y", "x", "y", 'x', Item.enderPearl, 'y', Block.trapdoor); + } + if (properties.CraftingRiftSignatureAllowed) + { + + GameRegistry.addRecipe(new ItemStack(mod_pocketDim.itemRiftSignature, 1), + " y ", "yxy", " y ", 'x', Item.enderPearl, 'y', Item.ingotIron); + } + if (properties.CraftingRiftRemoverAllowed) + { + + GameRegistry.addRecipe(new ItemStack(mod_pocketDim.itemRiftRemover, 1), + "yyy", "yxy", "yyy", 'x', Item.enderPearl, 'y', Item.ingotGold); + } + if (properties.CraftingRiftBladeAllowed) + { + GameRegistry.addRecipe(new ItemStack(mod_pocketDim.itemRiftBlade, 1), + "x", "x", "y", 'x', mod_pocketDim.itemStableFabric, 'y', Item.blazeRod); + } if (properties.CraftingStabilizedRiftSignatureAllowed) { - GameRegistry.addRecipe(new ItemStack(mod_pocketDim.itemStabilizedLinkSignature,1), new Object[] - { - " y ", "yxy", " y ", 'x', mod_pocketDim.itemRiftSignature, 'y', mod_pocketDim.itemStableFabric - }); + + GameRegistry.addRecipe(new ItemStack(mod_pocketDim.itemStabilizedRiftSignature, 1), + " y ", "yxy", " y ", 'x', mod_pocketDim.itemStableFabric, 'y', Item.ingotIron); } if (properties.CraftingGoldenDimensionalDoorAllowed) { - GameRegistry.addRecipe(new ItemStack(mod_pocketDim.itemGoldenDimensionalDoor,1), new Object[] - { - " ", "xyx", " ", 'x', mod_pocketDim.itemGoldenDoor, 'y', Item.eyeOfEnder - }); + GameRegistry.addRecipe(new ItemStack(mod_pocketDim.itemGoldenDimensionalDoor, 1), + "yxy", 'x', mod_pocketDim.itemStableFabric, 'y', mod_pocketDim.itemGoldenDoor); } if (properties.CraftingGoldenDoorAllowed) { - GameRegistry.addRecipe(new ItemStack(mod_pocketDim.itemGoldenDoor, 1), new Object[] - { - "yy ", "yy ", "yy ", 'y', Item.ingotGold - }); + GameRegistry.addRecipe(new ItemStack(mod_pocketDim.itemGoldenDoor, 1), + "yy", "yy", "yy", 'y', Item.ingotGold); } + if (properties.CraftingPersonalDimDoorAllowed) + { + GameRegistry.addRecipe(new ItemStack(mod_pocketDim.itemPersonalDoor,1), + "yxy", 'y', mod_pocketDim.itemGoldenDoor, 'x', mod_pocketDim.itemStableFabric); + } + if (properties.CraftingQuartzDoorAllowed) + { + GameRegistry.addRecipe(new ShapedOreRecipe(mod_pocketDim.itemQuartzDoor, new Object[]{ + "yy", "yy", "yy", Character.valueOf('y'), "oreQuartz"})); + + + } + if (properties.CraftingDDKeysAllowed) + { + GameRegistry.addRecipe(new ItemStack(mod_pocketDim.itemDDKey, 1), + " z", " y ", "y ", 'y', Item.ingotGold, 'z', Item.enderPearl); + GameRegistry.addRecipe(new ItemStack(mod_pocketDim.itemDDKey, 1), + "z", "z", 'z', mod_pocketDim.itemDDKey); + } + + } + + @Override + public void onCrafting(EntityPlayer player, ItemStack item, IInventory craftMatrix) + { + if(item.getItem() instanceof ItemDDKey) + { + ItemDDKey keyItem = (ItemDDKey) item.getItem(); + ItemStack topKey = null; + ItemStack bottomKey = null; + int topKeySlot = 0; + + for(int i = 0; i 0 && properties.WorldRiftGenerationEnabled && - event.type == InitMapGenEvent.EventType.NETHER_BRIDGE) + * if (properties.FortressGatewayGenerationChance > 0 && + * properties.WorldRiftGenerationEnabled && event.type == + * InitMapGenEvent.EventType.NETHER_BRIDGE) { event.newGen = new + * DDNetherFortressGenerator(); } + */ + } + + @SideOnly(Side.CLIENT) + @ForgeSubscribe + public void onSoundLoad(SoundLoadEvent event) + { + event.manager.addSound(mod_pocketDim.modid + ":doorLockRemoved.ogg"); + event.manager.addSound(mod_pocketDim.modid + ":doorLocked.ogg"); + event.manager.addSound(mod_pocketDim.modid + ":keyLock.ogg"); + event.manager.addSound(mod_pocketDim.modid + ":keyUnlock.ogg"); + event.manager.addSound(mod_pocketDim.modid + ":monk.ogg"); + event.manager.addSound(mod_pocketDim.modid + ":crack.ogg"); + event.manager.addSound(mod_pocketDim.modid + ":tearing.ogg"); + event.manager.addSound(mod_pocketDim.modid + ":rift.ogg"); + event.manager.addSound(mod_pocketDim.modid + ":riftStart.ogg"); + event.manager.addSound(mod_pocketDim.modid + ":riftEnd.ogg"); + event.manager.addSound(mod_pocketDim.modid + ":riftClose.ogg"); + event.manager.addSound(mod_pocketDim.modid + ":riftDoor.ogg"); + event.manager.addSound(mod_pocketDim.modid + ":creepy.ogg"); + } + + @SideOnly(Side.CLIENT) + @ForgeSubscribe + public void onSoundEffectResult(PlayBackgroundMusicEvent event) + { + if (FMLClientHandler.instance().getClient().thePlayer.worldObj.provider.dimensionId == mod_pocketDim.properties.LimboDimensionID) { - event.newGen = new DDNetherFortressGenerator(); + this.playMusicForDim(FMLClientHandler.instance().getClient().thePlayer.worldObj); } - */ } - - @SideOnly(Side.CLIENT) - @ForgeSubscribe - public void onSoundLoad(SoundLoadEvent event) - { - event.manager.addSound(mod_pocketDim.modid+":monk.ogg"); - event.manager.addSound(mod_pocketDim.modid+":crack.ogg"); - event.manager.addSound(mod_pocketDim.modid+":tearing.ogg"); - event.manager.addSound(mod_pocketDim.modid+":rift.ogg"); - event.manager.addSound(mod_pocketDim.modid+":riftStart.ogg"); - event.manager.addSound(mod_pocketDim.modid+":riftEnd.ogg"); - event.manager.addSound(mod_pocketDim.modid+":riftClose.ogg"); - event.manager.addSound(mod_pocketDim.modid+":riftDoor.ogg"); - event.manager.addSound(mod_pocketDim.modid+":creepy.ogg"); - } - - @SideOnly(Side.CLIENT) - @ForgeSubscribe - public void onSoundEffectResult(PlayBackgroundMusicEvent event) - { - if (FMLClientHandler.instance().getClient().thePlayer.worldObj.provider.dimensionId==mod_pocketDim.properties.LimboDimensionID); - { - this.playMusicForDim(FMLClientHandler.instance().getClient().thePlayer.worldObj); - } - } - + @ForgeSubscribe public void onPlayerEvent(PlayerInteractEvent event) { - //Handle placement of vanilla doors on rifts - if(!event.entity.worldObj.isRemote) + // Handle all door placement here + if (event.action == Action.LEFT_CLICK_BLOCK) { - World world = event.entity.worldObj; - ItemStack item = event.entityPlayer.inventory.getCurrentItem(); - if(item!=null) + return; + } + World world = event.entity.worldObj; + ItemStack stack = event.entityPlayer.inventory.getCurrentItem(); + if (stack != null) + { + if(stack.getItem() instanceof ItemWarpDoor) { - if(item.getItem() instanceof ItemDoor&&!(item.getItem() instanceof BaseItemDoor)) + NewDimData data = PocketManager.getDimensionData(world); + + if(data.type() == DimensionType.PERSONAL) { - Block doorToPlace = null; - if(item.itemID == Item.doorIron.itemID) + mod_pocketDim.sendChat(event.entityPlayer,("Something prevents the Warp Door from tunneling out here")); + event.setCanceled(true); + return; + } + } + if (BaseItemDoor.tryToPlaceDoor(stack, event.entityPlayer, world, + event.x, event.y, event.z, event.face)) + { + // Cancel the event so that we don't get two doors from vanilla doors + event.setCanceled(true); + } + } + + } + + @ForgeSubscribe + public void onWorldLoad(WorldEvent.Load event) + { + // We need to initialize PocketManager here because onServerAboutToStart + // fires before we can use DimensionManager and onServerStarting fires + // after the game tries to generate terrain. If a gateway tries to + // generate before PocketManager has initialized, we get a crash. + if (!PocketManager.isLoaded()) + { + PocketManager.load(); + } + + if (event.world != null) + { + this.playMusicForDim(event.world); + } + } + + @ForgeSubscribe + public void onPlayerFall(LivingFallEvent event) + { + event.setCanceled(event.entity.worldObj.provider.dimensionId == properties.LimboDimensionID); + } + + @ForgeSubscribe(priority = EventPriority.HIGHEST) + public boolean onDeathWithHighPriority(LivingDeathEvent event) + { + // Teleport the entity to Limbo if it's a player in a pocket dimension + // and if Limbo preserves player inventories. We'll check again in a + // low-priority event handler to give other mods a chance to save the + // player if Limbo does _not_ preserve inventories. + + Entity entity = event.entity; + + if (properties.LimboEnabled && properties.LimboReturnsInventoryEnabled && + entity instanceof EntityPlayer && isValidSourceForLimbo(entity.worldObj.provider)) + { + if(entity.worldObj.provider instanceof PocketProvider) + { + EntityPlayer player = (EntityPlayer) entity; + mod_pocketDim.deathTracker.addUsername(player.username); + revivePlayerInLimbo(player); + event.setCanceled(true); + return false; + } + else if(entity.worldObj.provider instanceof LimboProvider && event.source == DamageSource.outOfWorld) + { + EntityPlayer player = (EntityPlayer) entity; + revivePlayerInLimbo(player); + mod_pocketDim.sendChat(player, "Search for the dark red pools which accumulate in the lower reaches of Limbo"); + event.setCanceled(true); + return false; + } + } + return true; + } + + @ForgeSubscribe(priority = EventPriority.LOWEST) + public boolean onDeathWithLowPriority(LivingDeathEvent event) + { + // This low-priority handler gives mods a chance to save a player from + // death before we apply teleporting them to Limbo _without_ preserving + // their inventory. We also check if the player died in a pocket + // dimension and record it, regardless of whether the player will be + // sent to Limbo. + + Entity entity = event.entity; + + if (entity instanceof EntityPlayer && isValidSourceForLimbo(entity.worldObj.provider)) + { + EntityPlayer player = (EntityPlayer) entity; + mod_pocketDim.deathTracker.addUsername(player.username); + + if (properties.LimboEnabled && !properties.LimboReturnsInventoryEnabled) + { + player.inventory.clearInventory(-1, -1); + revivePlayerInLimbo(player); + event.setCanceled(true); + } + return false; + } + return true; + } + + private boolean isValidSourceForLimbo(WorldProvider provider) + { + // Returns whether a given world is a valid place for sending a player + // to Limbo. We can send someone to Limbo from a certain dimension if + // Universal Limbo is enabled and the source dimension is not Limbo, or + // if the source dimension is a pocket dimension. + + return (worldProperties.UniversalLimboEnabled && provider.dimensionId != properties.LimboDimensionID) || + (provider instanceof PocketProvider); + } + + private void revivePlayerInLimbo(EntityPlayer player) + { + player.extinguish(); + player.clearActivePotions(); + player.setHealth(player.getMaxHealth()); + player.getFoodStats().addStats(MAX_FOOD_LEVEL, 0); + Point4D destination = LimboProvider.getLimboSkySpawn(player, properties); + DDTeleporter.teleportEntity(player, destination, false); + } + + @ForgeSubscribe + public void onWorldSave(WorldEvent.Save event) + { + if (event.world.provider.dimensionId == 0) + { + PocketManager.save(true); + + if (mod_pocketDim.deathTracker != null && mod_pocketDim.deathTracker.isModified()) + { + mod_pocketDim.deathTracker.writeToFile(); + } + } + } + + @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. + // Also, check that PocketManager is loaded, because onChunkLoad() can + // fire while chunks are being initialized in a new world, before + // onWorldLoad() fires. + Chunk chunk = event.getChunk(); + if (!chunk.worldObj.isRemote && PocketManager.isLoaded()) + { + NewDimData dimension = PocketManager.createDimensionData(chunk.worldObj); + for (DimLink link : dimension.getChunkLinks(chunk.xPosition, chunk.zPosition)) + { + regenerator.scheduleSlowRegeneration(link); + } + } + } + + public void playMusicForDim(World world) + { + if (world.isRemote) + { + SoundManager sndManager = FMLClientHandler.instance().getClient().sndManager; + + // SenseiKiwi: I've added the following check as a quick fix for a + // reported crash. This needs to work without a hitch or we have to + // stop trying to replace the background music... + if (sndManager != null && sndManager.sndSystem != null) + { + if (world.provider instanceof LimboProvider) + { + sndManager.sndSystem.stop("BgMusic"); + SoundPoolEntry soundPoolEntry = sndManager.soundPoolSounds.getRandomSoundFromSoundPool(mod_pocketDim.modid + ":creepy"); + if (soundPoolEntry != null) { - doorToPlace =mod_pocketDim.dimensionalDoor; - } - else if(item.itemID == Item.doorWood.itemID) - { - doorToPlace =mod_pocketDim.warpDoor; - } - else if(item.itemID == mod_pocketDim.itemGoldenDoor.itemID) - { - doorToPlace =mod_pocketDim.goldenDimensionalDoor; - } - if(((BaseItemDoor) mod_pocketDim.itemDimensionalDoor).tryPlacingDoor(doorToPlace, world, event.entityPlayer,item)) - { - if(!event.entityPlayer.capabilities.isCreativeMode) - { - item.stackSize--; - } - if(!event.entity.worldObj.isRemote) - { - event.setCanceled(true); - } - } - else - { - BaseItemDoor.tryItemUse(doorToPlace, item, event.entityPlayer, world, event.x, event.y, event.z, event.face, true, true); + sndManager.sndSystem.backgroundMusic("LimboMusic", soundPoolEntry.getSoundUrl(), soundPoolEntry.getSoundName(), false); + sndManager.sndSystem.play("LimboMusic"); } } + else if (!(world.provider instanceof LimboProvider)) + { + sndManager.sndSystem.stop("LimboMusic"); + } } } - } - - @ForgeSubscribe - public void onWorldLoad(WorldEvent.Load event) - { - // We need to initialize PocketManager here because onServerAboutToStart fires before we can - // use DimensionManager and onServerStarting fires after the game tries to generate terrain. - // If a gateway tries to generate before PocketManager has initialized, we get a crash. - if (!PocketManager.isLoaded()) - { - PocketManager.load(); - } - - if (event.world != null) - { - this.playMusicForDim(event.world); - } - } - - @ForgeSubscribe - public void onPlayerFall(LivingFallEvent event) - { - event.setCanceled(event.entity.worldObj.provider.dimensionId == properties.LimboDimensionID); - } - - @ForgeSubscribe(priority = EventPriority.HIGHEST) - public boolean onDeathWithHighPriority(LivingDeathEvent event) - { - // Teleport the entity to Limbo if it's a player in a pocket dimension and - // if Limbo preserves player inventories. We'll check again in a low-priority event handler - // to give other mods a chance to save the player if Limbo does _not_ preserve inventories. - - Entity entity = event.entity; - - if (entity instanceof EntityPlayer && properties.LimboEnabled && - entity.worldObj.provider instanceof PocketProvider && properties.LimboReturnsInventoryEnabled) - { - EntityPlayer player = (EntityPlayer) entity; - mod_pocketDim.deathTracker.addUsername(player.username); - revivePlayerInLimbo(player); - event.setCanceled(true); - return false; - } - return true; - } - - @ForgeSubscribe(priority = EventPriority.LOWEST) - public boolean onDeathWithLowPriority(LivingDeathEvent event) - { - // This low-priority handler gives mods a chance to save a player from death before we apply - // teleporting them to Limbo _without_ preserving their inventory. We also check if the player - // died in a pocket dimension and record it, regardless of whether the player will be sent to Limbo. - - Entity entity = event.entity; - - if (entity instanceof EntityPlayer && entity.worldObj.provider instanceof PocketProvider) - { - EntityPlayer player = (EntityPlayer) entity; - mod_pocketDim.deathTracker.addUsername(player.username); - - if (properties.LimboEnabled && !properties.LimboReturnsInventoryEnabled) - { - player.inventory.clearInventory(-1, -1); - revivePlayerInLimbo(player); - event.setCanceled(true); - } - return false; - } - return true; - } - - private void revivePlayerInLimbo(EntityPlayer player) - { - player.extinguish(); - player.clearActivePotions(); - player.setHealth(player.getMaxHealth()); - ChunkCoordinates coords = LimboProvider.getLimboSkySpawn(player.worldObj.rand); - Point4D destination = new Point4D((int) (coords.posX + player.posX), coords.posY, (int) (coords.posZ + player.posZ ), mod_pocketDim.properties.LimboDimensionID); - DDTeleporter.teleportEntity(player, destination, false); - } - - @ForgeSubscribe - public void onWorldSave(WorldEvent.Save event) - { - if (event.world.provider.dimensionId == 0) - { - PocketManager.save(); - - if (mod_pocketDim.deathTracker != null && mod_pocketDim.deathTracker.isModified()) - { - mod_pocketDim.deathTracker.writeToFile(); - } - } - } - - public void playMusicForDim(World world) - { - if(world.isRemote) - { - SoundManager sndManager = FMLClientHandler.instance().getClient().sndManager; - - if(world.provider instanceof LimboProvider) - { - sndManager.sndSystem.stop("BgMusic"); - SoundPoolEntry soundPoolEntry = sndManager.soundPoolSounds.getRandomSoundFromSoundPool(mod_pocketDim.modid+":creepy"); - if(soundPoolEntry!=null) - { - sndManager.sndSystem.backgroundMusic("LimboMusic", soundPoolEntry.getSoundUrl(), soundPoolEntry.getSoundName(), false); - sndManager.sndSystem.play("LimboMusic"); - } - } - else if(!(world.provider instanceof LimboProvider)) - { - sndManager.sndSystem.stop("LimboMusic"); - } - } - } + } } \ No newline at end of file diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/IChunkLoader.java b/src/main/java/StevenDimDoors/mod_pocketDim/IChunkLoader.java index bbe989e..06f0059 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/IChunkLoader.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/IChunkLoader.java @@ -4,5 +4,6 @@ import net.minecraftforge.common.ForgeChunkManager.Ticket; public interface IChunkLoader { - public void forceChunkLoading(Ticket ticket,int x, int z); + public boolean isInitialized(); + public void initialize(Ticket ticket); } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/PacketConstants.java b/src/main/java/StevenDimDoors/mod_pocketDim/PacketConstants.java index cc17208..ec8e45c 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/PacketConstants.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/PacketConstants.java @@ -12,5 +12,6 @@ public class PacketConstants public static final byte CREATE_LINK_PACKET_ID = 4; public static final byte DELETE_LINK_PACKET_ID = 5; public static final byte CLIENT_LOGIN_DIM_REGISTER = 6; + public static final byte UPDATE_LINK_PACKET_ID = 7; } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/ServerPacketHandler.java b/src/main/java/StevenDimDoors/mod_pocketDim/ServerPacketHandler.java index ed756a7..7ad11f9 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/ServerPacketHandler.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/ServerPacketHandler.java @@ -38,6 +38,13 @@ public class ServerPacketHandler implements IPacketHandler public void onDeleted(ClientDimData message) { sendDimPacket(PacketConstants.DELETE_DIM_PACKET_ID, message); + } + + @Override + public void update(ClientDimData message) + { + // TODO Auto-generated method stub + } } @@ -54,6 +61,12 @@ public class ServerPacketHandler implements IPacketHandler { sendLinkPacket(PacketConstants.DELETE_LINK_PACKET_ID, message); } + + @Override + public void update(ClientLinkData message) + { + sendLinkPacket(PacketConstants.UPDATE_LINK_PACKET_ID, message); + } } public static Packet250CustomPayload createLinkPacket(ClientLinkData data) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BaseDimDoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BaseDimDoor.java index 3233c6e..b6d24e5 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BaseDimDoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BaseDimDoor.java @@ -1,57 +1,68 @@ package StevenDimDoors.mod_pocketDim.blocks; import java.util.Random; - import net.minecraft.block.Block; import net.minecraft.block.BlockDoor; import net.minecraft.block.ITileEntityProvider; import net.minecraft.block.material.Material; +import net.minecraft.client.renderer.IconFlipped; import net.minecraft.client.renderer.texture.IconRegister; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemDoor; +import net.minecraft.item.ItemStack; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.Icon; import net.minecraft.util.MathHelper; import net.minecraft.world.IBlockAccess; import net.minecraft.world.World; -import StevenDimDoors.mod_pocketDim.DDProperties; import StevenDimDoors.mod_pocketDim.mod_pocketDim; +import StevenDimDoors.mod_pocketDim.config.DDProperties; import StevenDimDoors.mod_pocketDim.core.DDTeleporter; import StevenDimDoors.mod_pocketDim.core.DimLink; import StevenDimDoors.mod_pocketDim.core.PocketManager; -import StevenDimDoors.mod_pocketDim.schematic.BlockRotator; +import StevenDimDoors.mod_pocketDim.items.ItemDDKey; import StevenDimDoors.mod_pocketDim.tileentities.TileEntityDimDoor; import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; public abstract class BaseDimDoor extends BlockDoor implements IDimDoor, ITileEntityProvider { - protected final DDProperties properties; - private Icon blockIconBottom; + protected final DDProperties properties; + + @SideOnly(Side.CLIENT) + protected Icon[] upperTextures; + @SideOnly(Side.CLIENT) + protected Icon[] lowerTextures; public BaseDimDoor(int blockID, Material material, DDProperties properties) { super(blockID, material); - + this.properties = properties; } @Override - public void registerIcons(IconRegister par1IconRegister) + @SideOnly(Side.CLIENT) + public void registerIcons(IconRegister iconRegister) { - this.blockIcon = par1IconRegister.registerIcon(mod_pocketDim.modid + ":" + this.getUnlocalizedName()+"_top"); - this.blockIconBottom = par1IconRegister.registerIcon(mod_pocketDim.modid + ":" + this.getUnlocalizedName()+"_bottom"); + upperTextures = new Icon[2]; + lowerTextures = new Icon[2]; + upperTextures[0] = iconRegister.registerIcon(mod_pocketDim.modid + ":" + this.getUnlocalizedName() + "_upper"); + lowerTextures[0] = iconRegister.registerIcon(mod_pocketDim.modid + ":" + this.getUnlocalizedName() + "_lower"); + upperTextures[1] = new IconFlipped(upperTextures[0], true, false); + lowerTextures[1] = new IconFlipped(lowerTextures[0], true, false); } - /** + /** * From the specified side and block metadata retrieves the blocks texture. Args: side, metadata */ @Override @SideOnly(Side.CLIENT) - public Icon getIcon(int par1, int par2) + public Icon getIcon(int side, int metadata) { - return this.blockIcon; + return this.upperTextures[0]; } @Override @@ -63,22 +74,37 @@ public abstract class BaseDimDoor extends BlockDoor implements IDimDoor, ITileEn @Override public boolean onBlockActivated(World world, int x, int y, int z, EntityPlayer player, int side, float hitX, float hitY, float hitZ) { - int var10 = this.getFullMetadata(world, x, y, z); - int var11 = var10 & 7; - var11 ^= 4; - - if ((var10 & 8) == 0) + + ItemStack stack = player.inventory.getCurrentItem(); + if (stack != null && stack.getItem() instanceof ItemDDKey) { - world.setBlockMetadataWithNotify(x, y, z, var11,2); - world.markBlockRangeForRenderUpdate(x, y, z, x, y, z); + return false; + } + + if(!checkCanOpen(world, x, y, z, player)) + { + return false; + } + + final int MAGIC_CONSTANT = 1003; + + int metadata = this.getFullMetadata(world, x, y, z); + int lowMeta = metadata & 7; + lowMeta ^= 4; + + if (isUpperDoorBlock(metadata)) + { + world.setBlockMetadataWithNotify(x, y - 1, z, lowMeta, 2); + world.markBlockRangeForRenderUpdate(x, y - 1, z, x, y, z); } else { - world.setBlockMetadataWithNotify(x, y - 1, z, var11,2); - world.markBlockRangeForRenderUpdate(x, y - 1, z, x, y, z); + world.setBlockMetadataWithNotify(x, y, z, lowMeta, 2); + world.markBlockRangeForRenderUpdate(x, y, z, x, y, z); } - world.playAuxSFXAtEntity(player, 1003, x, y, z, 0); + world.playAuxSFXAtEntity(player, MAGIC_CONSTANT, x, y, z, 0); + return true; } @@ -90,37 +116,118 @@ public abstract class BaseDimDoor extends BlockDoor implements IDimDoor, ITileEn this.updateAttachedTile(world, x, y, z); } - /** - * Retrieves the block texture to use based on the display side. Args: iBlockAccess, x, y, z, side - */ + * Retrieves the block texture to use based on the display side. Args: iBlockAccess, x, y, z, side + */ @Override - @SideOnly(Side.CLIENT) - public Icon getBlockTexture(IBlockAccess par1IBlockAccess, int par2, int par3, int par4, int par5) - { - if(par1IBlockAccess.getBlockId(par2, par3-1, par4) == this.blockID) - { - return this.blockIcon; - } - else - { - return blockIconBottom; - } - } + @SideOnly(Side.CLIENT) + public Icon getBlockTexture(IBlockAccess blockAccess, int x, int y, int z, int side) + { + if (side != 1 && side != 0) + { + int fullMetadata = this.getFullMetadata(blockAccess, x, y, z); + int orientation = fullMetadata & 3; + boolean reversed = false; + + if (isDoorOpen(fullMetadata)) + { + if (orientation == 0 && side == 2) + { + reversed = !reversed; + } + else if (orientation == 1 && side == 5) + { + reversed = !reversed; + } + else if (orientation == 2 && side == 3) + { + reversed = !reversed; + } + else if (orientation == 3 && side == 4) + { + reversed = !reversed; + } + } + else + { + if (orientation == 0 && side == 5) + { + reversed = !reversed; + } + else if (orientation == 1 && side == 3) + { + reversed = !reversed; + } + else if (orientation == 2 && side == 4) + { + reversed = !reversed; + } + else if (orientation == 3 && side == 2) + { + reversed = !reversed; + } + + if ((fullMetadata & 16) != 0) + { + reversed = !reversed; + } + } + if (isUpperDoorBlock(fullMetadata)) + { + return this.upperTextures[reversed ? 1 : 0]; + } + return this.lowerTextures[reversed ? 1 : 0]; + } + return this.lowerTextures[0]; + } //Called to update the render information on the tile entity. Could probably implement a data watcher, //but this works fine and is more versatile I think. public BaseDimDoor updateAttachedTile(World world, int x, int y, int z) { + mod_pocketDim.proxy.updateDoorTE(this, world, x, y, z); TileEntity tile = world.getBlockTileEntity(x, y, z); if (tile instanceof TileEntityDimDoor) { + int metadata = world.getBlockMetadata(x, y, z); TileEntityDimDoor dimTile = (TileEntityDimDoor) tile; - dimTile.openOrClosed = PocketManager.getLink(x, y, z, world.provider.dimensionId) != null; + dimTile.openOrClosed = isDoorOnRift(world, x, y, z) && isUpperDoorBlock(metadata); dimTile.orientation = this.getFullMetadata(world, x, y, z) & 7; } return this; } + + public boolean isDoorOnRift(World world, int x, int y, int z) + { + return this.getLink(world, x, y, z) != null; + } + + public DimLink getLink(World world, int x, int y, int z) + { + DimLink link= PocketManager.getLink(x, y, z, world.provider.dimensionId); + if(link!=null) + { + return link; + } + + if(isUpperDoorBlock( world.getBlockMetadata(x, y, z))) + { + link = PocketManager.getLink(x, y-1, z, world.provider.dimensionId); + if(link!=null) + { + return link; + } + } + else + { + link = PocketManager.getLink(x, y+1, z, world.provider.dimensionId); + if(link != null) + { + return link; + } + } + return null; + } /** * Is this block (a) opaque and (b) a full 1m cube? This determines whether or not to render the shared face of two @@ -129,9 +236,7 @@ public abstract class BaseDimDoor extends BlockDoor implements IDimDoor, ITileEn @Override public void updateTick(World par1World, int par2, int par3, int par4, Random par5Random) { - TileEntityDimDoor tile = (TileEntityDimDoor) par1World.getBlockTileEntity(par2, par3, par4); - tile.openOrClosed = this.isDoorOpen( par1World, par2, par3, par4); - tile.orientation = this.getFullMetadata(par1World, par2, par3, par4) & 7; + this.updateAttachedTile(par1World, par2, par3, par4); } @Override @@ -229,60 +334,38 @@ public abstract class BaseDimDoor extends BlockDoor implements IDimDoor, ITileEn * their own) Args: x, y, z, neighbor blockID */ @Override - public void onNeighborBlockChange(World par1World, int par2, int par3, int par4, int par5) + public void onNeighborBlockChange(World world, int x, int y, int z, int neighborID) { - int var6 = par1World.getBlockMetadata(par2, par3, par4); - - if ((var6 & 8) == 0) + + int metadata = world.getBlockMetadata(x, y, z); + if (isUpperDoorBlock(metadata)) { - boolean var7 = false; - - if (par1World.getBlockId(par2, par3 + 1, par4) != this.blockID) + if (world.getBlockId(x, y - 1, z) != this.blockID) { - par1World.setBlock(par2, par3, par4, 0); - var7 = true; + world.setBlockToAir(x, y, z); } - - /** - if (!par1World.doesBlockHaveSolidTopSurface(par2, par3 - 1, par4)) - { - par1World.setBlockWithNotify(par2, par3, par4, 0); - var7 = true; - - if (par1World.getBlockId(par2, par3 + 1, par4) == this.blockID) - { - par1World.setBlockWithNotify(par2, par3 + 1, par4, 0); - } - } - **/ - - if (var7) + if (neighborID > 0 && neighborID != this.blockID) { - if (!par1World.isRemote) - { - this.dropBlockAsItem(par1World, par2, par3, par4, properties.DimensionalDoorID, 0); - } - } - else - { - boolean var8 = par1World.isBlockIndirectlyGettingPowered(par2, par3, par4) || par1World.isBlockIndirectlyGettingPowered(par2, par3 + 1, par4); - - if ((var8 || par5 > 0 && Block.blocksList[par5].canProvidePower()) && par5 != this.blockID) - { - this.onPoweredBlockChange(par1World, par2, par3, par4, var8); - } + this.onNeighborBlockChange(world, x, y - 1, z, neighborID); } } else { - if (par1World.getBlockId(par2, par3 - 1, par4) != this.blockID) + if (world.getBlockId(x, y + 1, z) != this.blockID) { - par1World.setBlock(par2, par3, par4, 0); + world.setBlockToAir(x, y, z); + if (!world.isRemote) + { + this.dropBlockAsItem(world, x, y, z, metadata, 0); + } } - - if (par5 > 0 && par5 != this.blockID) + else if(this.getLockStatus(world, x, y, z)<=1) { - this.onNeighborBlockChange(par1World, par2, par3 - 1, par4, par5); + boolean powered = world.isBlockIndirectlyGettingPowered(x, y, z) || world.isBlockIndirectlyGettingPowered(x, y + 1, z); + if ((powered || neighborID > 0 && Block.blocksList[neighborID].canProvidePower()) && neighborID != this.blockID) + { + this.onPoweredBlockChange(world, x, y, z, powered); + } } } } @@ -292,34 +375,20 @@ public abstract class BaseDimDoor extends BlockDoor implements IDimDoor, ITileEn */ @Override @SideOnly(Side.CLIENT) - public int idPicked(World par1World, int par2, int par3, int par4) + public int idPicked(World world, int x, int y, int z) { - return this.getDrops(); + return this.getDoorItem(); } - @Override - public int idDropped(int par1, Random par2Random, int par3) + /** + * Returns the ID of the items to drop on destruction. + */ + @Override + public int idDropped(int metadata, Random random, int fortune) { - //I have no idea, but sometimes this is returned as the blockID instead of metadata. - if(par1>100) - { - return this.getDrops(); - } - return (par1 & 8) != 0 ? 0 :getDrops(); + 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) { @@ -365,7 +434,6 @@ public abstract class BaseDimDoor extends BlockDoor implements IDimDoor, ITileEn // Close the door only after the entity goes through // so players don't have it slam in their faces. this.onPoweredBlockChange(world, x, y, z, false); - } } else if (world.getBlockId(x, y + 1, z) == this.blockID) @@ -374,17 +442,77 @@ public abstract class BaseDimDoor extends BlockDoor implements IDimDoor, ITileEn } } - @Override - public int getDrops() + public boolean isUpperDoorBlock(int metadata) { - return this.blockID; + return (metadata & 8) != 0; } - protected static boolean isDoorOpen(int metadata) + public boolean isDoorOpen(int metadata) { return (metadata & 4) != 0; } + /** + * 0 if link is no lock; + * 1 if there is a lock; + * 2 if the lock is locked. + * @param world + * @param x + * @param y + * @param z + * @return + */ + public byte getLockStatus(World world, int x, int y, int z) + { + byte status = 0; + DimLink link = getLink(world, x, y, z); + if(link!=null&&link.hasLock()) + { + status++; + if(link.getLockState()) + { + status++; + } + } + return status; + } + + + public boolean checkCanOpen(World world, int x, int y, int z) + { + return this.checkCanOpen(world, x, y, z, null); + } + + public boolean checkCanOpen(World world, int x, int y, int z, EntityPlayer player) + { + DimLink link = getLink(world, x, y, z); + if(link==null||player==null) + { + return link==null; + } + if(!link.getLockState()) + { + return true; + } + + for(ItemStack item : player.inventory.mainInventory) + { + if(item != null) + { + if(item.getItem() instanceof ItemDDKey) + { + if(link.tryToOpen(item)) + { + return true; + } + } + } + } + player.playSound(mod_pocketDim.modid + ":doorLocked", 1F, 1F); + return false; + } + + protected static boolean isEntityFacingDoor(int metadata, EntityLivingBase entity) { // Although any entity has the proper fields for this check, @@ -401,4 +529,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/BlockDimWall.java b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockDimWall.java index 8d90548..f17ef8e 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockDimWall.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockDimWall.java @@ -14,8 +14,10 @@ import net.minecraft.item.Item; import net.minecraft.item.ItemBlock; import net.minecraft.item.ItemStack; import net.minecraft.util.Icon; +import net.minecraft.world.IBlockAccess; import net.minecraft.world.World; import StevenDimDoors.mod_pocketDim.mod_pocketDim; +import StevenDimDoors.mod_pocketDimClient.PrivatePocketRender; import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; @@ -23,18 +25,18 @@ public class BlockDimWall extends Block { private static final float SUPER_HIGH_HARDNESS = 10000000000000F; private static final float SUPER_EXPLOSION_RESISTANCE = 18000000F; - private Icon[] blockIcon = new Icon[2]; + private Icon[] blockIcon = new Icon[3]; public BlockDimWall(int blockID, int j, Material par2Material) { - super(blockID, Material.ground); + super(blockID, par2Material); this.setCreativeTab(mod_pocketDim.dimDoorsCreativeTab); } @Override public float getBlockHardness(World world, int x, int y, int z) { - if (world.getBlockMetadata(x, y, z) == 0) + if (world.getBlockMetadata(x, y, z) != 1) { return this.blockHardness; } @@ -47,7 +49,7 @@ public class BlockDimWall extends Block @Override public float getExplosionResistance(Entity entity, World world, int x, int y, int z, double explosionX, double explosionY, double explosionZ) { - if (world.getBlockMetadata(x, y, z) == 0) + if (world.getBlockMetadata(x, y, z) != 1) { return super.getExplosionResistance(entity, world, x, y, z, explosionX, explosionY, explosionZ); } @@ -57,25 +59,41 @@ public class BlockDimWall extends Block } } + public int getRenderType() + { + return PrivatePocketRender.renderID; + } + @Override public void registerIcons(IconRegister par1IconRegister) { this.blockIcon[0] = par1IconRegister.registerIcon(mod_pocketDim.modid + ":" + this.getUnlocalizedName()); this.blockIcon[1] = par1IconRegister.registerIcon(mod_pocketDim.modid + ":" + this.getUnlocalizedName() + "Perm"); + this.blockIcon[2] = par1IconRegister.registerIcon(mod_pocketDim.modid + ":" + this.getUnlocalizedName() + "Personal"); } @SideOnly(Side.CLIENT) @Override public Icon getIcon(int par1, int par2) { - return (par2 != 1) ? blockIcon[0] : blockIcon[1]; + switch(par2) + { + case 0: + return blockIcon[0]; + case 1: + return blockIcon[1]; + case 2: + return blockIcon[2]; + default: + return blockIcon[0]; + } } @Override public int damageDropped(int metadata) { //Return 0 to avoid dropping Ancient Fabric even if the player somehow manages to break it - return 0; + return metadata == 1 ? 0 : metadata; } @Override @@ -83,11 +101,12 @@ public class BlockDimWall extends Block @SideOnly(Side.CLIENT) public void getSubBlocks(int unknown, CreativeTabs tab, List subItems) { - for (int ix = 0; ix < 2; ix++) + for (int ix = 0; ix < 3; ix++) { subItems.add(new ItemStack(this, 1, ix)); } } + @Override public void onBlockDestroyedByPlayer(World par1World, int par2, int par3, int par4, int par5) {} @@ -110,7 +129,7 @@ public class BlockDimWall extends Block public boolean onBlockActivated(World world, int x, int y, int z, EntityPlayer entityPlayer, int par6, float par7, float par8, float par9) { //Check if the metadata value is 0 -- we don't want the user to replace Ancient Fabric - if (entityPlayer.getCurrentEquippedItem() != null && world.getBlockMetadata(x, y, z) == 0) + if (entityPlayer.getCurrentEquippedItem() != null && world.getBlockMetadata(x, y, z) != 1) { Item playerEquip = entityPlayer.getCurrentEquippedItem().getItem(); diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockDimWallPerm.java b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockDimWallPerm.java index 5047d9e..d3dac45 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockDimWallPerm.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockDimWallPerm.java @@ -11,8 +11,8 @@ import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.util.MathHelper; import net.minecraft.world.World; import net.minecraftforge.common.DimensionManager; -import StevenDimDoors.mod_pocketDim.DDProperties; import StevenDimDoors.mod_pocketDim.mod_pocketDim; +import StevenDimDoors.mod_pocketDim.config.DDProperties; import StevenDimDoors.mod_pocketDim.core.DDTeleporter; import StevenDimDoors.mod_pocketDim.helpers.yCoordHelper; import StevenDimDoors.mod_pocketDim.util.Point4D; @@ -51,7 +51,8 @@ public class BlockDimWallPerm extends Block @Override public void onEntityWalking(World world, int x, int y, int z, Entity entity) { - if (!world.isRemote && world.provider.dimensionId == properties.LimboDimensionID) + if (!world.isRemote && world.provider.dimensionId == properties.LimboDimensionID + && mod_pocketDim.worldProperties.LimboEscapeEnabled) { World overworld = DimensionManager.getWorld(0); if (overworld != null && entity instanceof EntityPlayerMP) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockDoorGold.java b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockDoorGold.java index 5b20779..f535db3 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockDoorGold.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockDoorGold.java @@ -2,56 +2,34 @@ package StevenDimDoors.mod_pocketDim.blocks; import java.util.Random; -import cpw.mods.fml.relauncher.Side; -import cpw.mods.fml.relauncher.SideOnly; -import StevenDimDoors.mod_pocketDim.DDProperties; -import StevenDimDoors.mod_pocketDim.mod_pocketDim; import net.minecraft.block.BlockDoor; import net.minecraft.block.material.Material; +import net.minecraft.client.renderer.IconFlipped; import net.minecraft.client.renderer.texture.IconRegister; -import net.minecraft.item.Item; import net.minecraft.util.Icon; import net.minecraft.world.IBlockAccess; +import net.minecraft.world.World; +import StevenDimDoors.mod_pocketDim.mod_pocketDim; +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; public class BlockDoorGold extends BlockDoor { - private Icon blockIconBottom; - public BlockDoorGold(int par1, Material par2Material) { super(par1, par2Material); } + + @SideOnly(Side.CLIENT) + protected String getTextureName() + { + return mod_pocketDim.modid + ":" + this.getUnlocalizedName(); + } - @Override - public void registerIcons(IconRegister par1IconRegister) - { - this.blockIcon = par1IconRegister.registerIcon(mod_pocketDim.modid + ":" + this.getUnlocalizedName()+"_top"); - this.blockIconBottom = par1IconRegister.registerIcon(mod_pocketDim.modid + ":" + this.getUnlocalizedName()+"_bottom"); - } @Override public int idDropped(int par1, Random par2Random, int par3) { return (par1 & 8) != 0 ? 0 : mod_pocketDim.itemGoldenDoor.itemID; } - - @Override - public Icon getIcon(int par1, int par2) - { - return this.blockIcon; - } - - @Override - @SideOnly(Side.CLIENT) - public Icon getBlockTexture(IBlockAccess par1IBlockAccess, int par2, int par3, int par4, int par5) - { - if (par1IBlockAccess.getBlockId(par2, par3-1, par4) == this.blockID) - { - return this.blockIcon; - } - else - { - return blockIconBottom; - } - } } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockDoorQuartz.java b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockDoorQuartz.java new file mode 100644 index 0000000..fb06a00 --- /dev/null +++ b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockDoorQuartz.java @@ -0,0 +1,28 @@ +package StevenDimDoors.mod_pocketDim.blocks; + +import java.util.Random; +import StevenDimDoors.mod_pocketDim.mod_pocketDim; +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import net.minecraft.block.BlockDoor; +import net.minecraft.block.material.Material; + +public class BlockDoorQuartz extends BlockDoor +{ + public BlockDoorQuartz(int par1, Material par2Material) + { + super(par1, par2Material); + } + + @SideOnly(Side.CLIENT) + protected String getTextureName() + { + return mod_pocketDim.modid + ":" + this.getUnlocalizedName(); + } + + @Override + public int idDropped(int par1, Random par2Random, int par3) + { + return (par1 & 8) != 0 ? 0 : mod_pocketDim.itemGoldenDoor.itemID; + } +} diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockGoldDimDoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockGoldDimDoor.java index 7cd4e0c..22055a9 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockGoldDimDoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockGoldDimDoor.java @@ -1,9 +1,9 @@ package StevenDimDoors.mod_pocketDim.blocks; -import StevenDimDoors.mod_pocketDim.DDProperties; import StevenDimDoors.mod_pocketDim.mod_pocketDim; +import StevenDimDoors.mod_pocketDim.config.DDProperties; import StevenDimDoors.mod_pocketDim.core.DimLink; -import StevenDimDoors.mod_pocketDim.core.LinkTypes; +import StevenDimDoors.mod_pocketDim.core.LinkType; import StevenDimDoors.mod_pocketDim.core.NewDimData; import StevenDimDoors.mod_pocketDim.core.PocketManager; import StevenDimDoors.mod_pocketDim.tileentities.TileEntityDimDoorGold; @@ -25,15 +25,21 @@ public class BlockGoldDimDoor extends BaseDimDoor { if (!world.isRemote && world.getBlockId(x, y - 1, z) == this.blockID) { - NewDimData dimension = PocketManager.getDimensionData(world); + NewDimData dimension = PocketManager.createDimensionData(world); DimLink link = dimension.getLink(x, y, z); if (link == null) { - dimension.createLink(x, y, z, LinkTypes.POCKET,world.getBlockMetadata(x, y - 1, z)); + dimension.createLink(x, y, z, LinkType.POCKET,world.getBlockMetadata(x, y - 1, z)); } } - } + + @Override + public int getDoorItem() + { + return mod_pocketDim.itemGoldenDimensionalDoor.itemID; + } + @Override public int getDrops() { 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/blocks/BlockRift.java b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockRift.java index 5f6f896..5890b49 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockRift.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockRift.java @@ -7,7 +7,6 @@ import java.util.Queue; import java.util.Random; import net.minecraft.block.Block; -import net.minecraft.block.BlockContainer; import net.minecraft.block.BlockFlowing; import net.minecraft.block.BlockFluid; import net.minecraft.block.ITileEntityProvider; @@ -20,13 +19,14 @@ import net.minecraft.util.AxisAlignedBB; import net.minecraft.world.IBlockAccess; import net.minecraft.world.World; import net.minecraftforge.fluids.IFluidBlock; -import StevenDimDoors.mod_pocketDim.DDProperties; import StevenDimDoors.mod_pocketDim.Point3D; import StevenDimDoors.mod_pocketDim.mod_pocketDim; +import StevenDimDoors.mod_pocketDim.config.DDProperties; import StevenDimDoors.mod_pocketDim.core.DimLink; import StevenDimDoors.mod_pocketDim.core.NewDimData; import StevenDimDoors.mod_pocketDim.core.PocketManager; import StevenDimDoors.mod_pocketDim.tileentities.TileEntityRift; +import StevenDimDoors.mod_pocketDim.util.Point4D; import StevenDimDoors.mod_pocketDimClient.ClosingRiftFX; import StevenDimDoors.mod_pocketDimClient.GoggleRiftFX; import StevenDimDoors.mod_pocketDimClient.RiftFX; @@ -38,23 +38,37 @@ public class BlockRift extends Block implements ITileEntityProvider { private static final float MIN_IMMUNE_RESISTANCE = 5000.0F; private static final int BLOCK_DESTRUCTION_RANGE = 4; - private static final int BLOCK_DESTRUCTION_VOLUME = (int) Math.pow(2 * BLOCK_DESTRUCTION_RANGE + 1, 3); + private static final int RIFT_SPREAD_RANGE = 5; private static final int MAX_BLOCK_SEARCH_CHANCE = 100; private static final int BLOCK_SEARCH_CHANCE = 50; private static final int MAX_BLOCK_DESTRUCTION_CHANCE = 100; private static final int BLOCK_DESTRUCTION_CHANCE = 50; - private static final int WORLD_THREAD_CHANCE = 5; - private static final int MAX_WORLD_THREAD_CHANCE = 100; + + 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); @@ -65,7 +79,7 @@ public class BlockRift extends Block implements ITileEntityProvider this.blocksImmuneToRift.add(properties.TransientDoorID); this.blocksImmuneToRift.add(properties.GoldenDimensionalDoorID); this.blocksImmuneToRift.add(properties.GoldenDoorID); - + this.blocksImmuneToRift.add(properties.PersonalDimDoorID); this.blocksImmuneToRift.add(Block.blockLapis.blockID); this.blocksImmuneToRift.add(Block.blockIron.blockID); this.blocksImmuneToRift.add(Block.blockGold.blockID); @@ -84,9 +98,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 +124,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; @@ -164,11 +175,30 @@ public class BlockRift extends Block implements ITileEntityProvider private void destroyNearbyBlocks(World world, int x, int y, int z, Random random) { - HashMap pointDistances = new HashMap(BLOCK_DESTRUCTION_VOLUME); - Queue points = new LinkedList(); + // Find reachable blocks that are vulnerable to rift damage (ignoring air, of course) + ArrayList targets = findReachableBlocks(world, x, y, z, BLOCK_DESTRUCTION_RANGE, false); - //Perform a breadth-first search outwards from the point at which the rift is located. Record the distances - //of the points we visit to stop the search at its maximum range. + // For each block, randomly decide whether to destroy it. + // The randomness makes it so the destroyed area appears "noisy" if the rift is exposed to a large surface. + for (Point3D target : targets) + { + if (random.nextInt(MAX_BLOCK_DESTRUCTION_CHANCE) < BLOCK_DESTRUCTION_CHANCE) + { + dropWorldThread(world.getBlockId(target.getX(), target.getY(), target.getZ()), world, x, y, z, random); + world.destroyBlock(target.getX(), target.getY(), target.getZ(), false); + } + } + } + + private ArrayList findReachableBlocks(World world, int x, int y, int z, int range, boolean includeAir) + { + int searchVolume = (int) Math.pow(2 * range + 1, 3); + HashMap pointDistances = new HashMap(searchVolume); + Queue points = new LinkedList(); + ArrayList targets = new ArrayList(); + + // Perform a breadth-first search outwards from the point at which the rift is located. + // Record the distances of the points we visit to stop the search at its maximum range. pointDistances.put(new Point3D(x, y, z), 0); addAdjacentBlocks(x, y, z, 0, pointDistances, points); while (!points.isEmpty()) @@ -176,10 +206,14 @@ public class BlockRift extends Block implements ITileEntityProvider Point3D current = points.remove(); int distance = pointDistances.get(current); - //If the current block is air, continue searching. Otherwise, try destroying the block. + // If the current block is air, continue searching. Otherwise, add the block to our list. if (world.isAirBlock(current.getX(), current.getY(), current.getZ())) { - //Make sure we stay within the search range + if (includeAir) + { + targets.add(current); + } + // Make sure we stay within the search range if (distance < BLOCK_DESTRUCTION_RANGE) { addAdjacentBlocks(current.getX(), current.getY(), current.getZ(), distance, pointDistances, points); @@ -187,21 +221,19 @@ public class BlockRift extends Block implements ITileEntityProvider } else { - //Check if the current block is immune to destruction by rifts. If not, randomly decide whether to destroy it. - //The randomness makes it so the destroyed area appears "noisy" if the rift is exposed to a large surface. - if (!isBlockImmune(world, current.getX(), current.getY(), current.getZ()) && - random.nextInt(MAX_BLOCK_DESTRUCTION_CHANCE) < BLOCK_DESTRUCTION_CHANCE) + // Check if the current block is immune to destruction by rifts. If not, add it to our list. + if (!isBlockImmune(world, current.getX(), current.getY(), current.getZ())) { - this.spawnWorldThread(world.getBlockId(current.getX(), current.getY(), current.getZ()), world, x, y, z, random); - world.destroyBlock(current.getX(), current.getY(), current.getZ(), false); + targets.add(current); } } } + return targets; } - - private void spawnWorldThread(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_CHANCE) < WORLD_THREAD_CHANCE) + if (blockID != 0 && (random.nextInt(MAX_WORLD_THREAD_DROP_CHANCE) < properties.WorldThreadDropChance) && !(Block.blocksList[blockID] instanceof BlockFlowing || Block.blocksList[blockID] instanceof BlockFluid || Block.blocksList[blockID] instanceof IFluidBlock)) @@ -211,7 +243,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), @@ -230,15 +262,34 @@ public class BlockRift extends Block implements ITileEntityProvider } } } - - public void regenerateRift(World world, int x, int y, int z, Random random) + + public boolean spreadRift(NewDimData dimension, DimLink parent, World world, Random random) { - if (!this.isBlockImmune(world, x, y, z) && world.getChunkProvider().chunkExists(x >> 4, z >> 4)) + int x, y, z, blockID; + Point4D source = parent.source(); + + // Find reachable blocks that are vulnerable to rift damage and include air + ArrayList targets = findReachableBlocks(world, source.getX(), source.getY(), source.getZ(), + RIFT_SPREAD_RANGE, true); + + if (!targets.isEmpty()) { - int blockID = world.getBlockId(x, y, z); - world.setBlock(x, y, z, properties.RiftBlockID); - this.spawnWorldThread(blockID, world, x, y, z, random); + // Choose randomly from among the possible locations where we can spawn a new rift + Point3D target = targets.get( random.nextInt(targets.size()) ); + x = target.getX(); + y = target.getY(); + z = target.getZ(); + + // Create a child, replace the block with a rift, and consider dropping World Thread + blockID = world.getBlockId(x, y, z); + if (world.setBlock(x, y, z, properties.RiftBlockID)) + { + dimension.createChildLink(x, y, z, parent); + dropWorldThread(blockID, world, x, y, z, random); + return true; + } } + return false; } /** @@ -256,111 +307,37 @@ public class BlockRift extends Block implements ITileEntityProvider @Override @SideOnly(Side.CLIENT) - public void randomDisplayTick(World par1World, int par2, int par3, int par4, Random rand) + public void randomDisplayTick(World world, int x, int y, int z, Random rand) { - int count; - //growth in the direction towards the nearby rift - float xGrowth=0; - float yGrowth=0; - float zGrowth=0; - //growth away from the nearby rift - float xGrowthn=0; - float yGrowthn=0; - float zGrowthn=0; - //how far the particles are away from original rift. Used to decrease noise the farther they are away. - float xChange = 0; - float yChange = 0; - float zChange = 0; - - TileEntityRift tile = (TileEntityRift)par1World.getBlockTileEntity(par2, par3, par4); - - float Xoffset=0; - float Yoffset=0; - float Zoffset=0; - for (count = 0; count < 12 && tile!=null; ++count) - { - //TODO change to a switch statement for clarity - if(tile.xOffset>0) - { - if(rand.nextInt(tile.xOffset)==0) - { - xGrowth =xGrowth+.15F*tile.xOffset; - - } - } - else if(tile.xOffset<0) - { - if(rand.nextInt(-tile.xOffset)==0) - { - xGrowthn =xGrowthn-.15F*-tile.xOffset; - - } - } - - if(tile.yOffset>0) - { - if(rand.nextInt(tile.yOffset)==0) - { - yGrowth =yGrowth+.15F*tile.yOffset; - - } - } - else if(tile.yOffset<0) - { - if(rand.nextInt(-tile.yOffset)==0) - { - yGrowthn =yGrowthn-.15F*-tile.yOffset; - - } - } - - if(tile.zOffset>0) - { - if(rand.nextInt(tile.zOffset)==0) - { - zGrowth =zGrowth+.15F*tile.zOffset; - - } - } - else if(tile.zOffset<0) - { - if(rand.nextInt(-tile.zOffset)==0) - { - zGrowthn =zGrowthn-.15F*-tile.zOffset; - - } - } - - - xChange=(float) ((xGrowth+xGrowthn)+rand.nextGaussian()*.05F); - yChange=(float) ((yGrowth+yGrowthn)+rand.nextGaussian()*.05F); - zChange=(float) ((zGrowth+zGrowthn)+rand.nextGaussian()*.05F); - - Xoffset= ((0.25F/(1+Math.abs(xChange)))); - - Yoffset= ((0.25F/(1+Math.abs(yChange)))); - Zoffset= ((0.25F/(1+Math.abs(zChange)))); - - - - - FMLClientHandler.instance().getClient().effectRenderer.addEffect(new RiftFX(par1World,par2+.5+xChange+Xoffset*rand.nextGaussian(), par3+.5+yChange+Yoffset*rand.nextGaussian() , par4+.5+zChange+Zoffset*rand.nextGaussian(), rand.nextGaussian() * 0.001D, rand.nextGaussian() * 0.001D, rand.nextGaussian() * 0.001D, FMLClientHandler.instance().getClient().effectRenderer)); - FMLClientHandler.instance().getClient().effectRenderer.addEffect(new RiftFX(par1World,par2+.5-xChange-Xoffset*rand.nextGaussian(), par3+.5-yChange-Yoffset*rand.nextGaussian() , par4+.5-zChange-Zoffset*rand.nextGaussian(), rand.nextGaussian() * 0.001D, rand.nextGaussian() * 0.001D, rand.nextGaussian() * 0.001D, FMLClientHandler.instance().getClient().effectRenderer)); - - + + ArrayList targets=findReachableBlocks(world, x, y, z, 2, false); + + + TileEntityRift tile = (TileEntityRift)world.getBlockTileEntity(x, y, z); + + if(rand.nextBoolean()) { //renders an extra little blob on top of the actual rift location so its easier to find. Eventually will only render if the player has the goggles. - FMLClientHandler.instance().getClient().effectRenderer.addEffect(new GoggleRiftFX(par1World,par2+.5, par3+.5, par4+.5, rand.nextGaussian() * 0.01D, rand.nextGaussian() * 0.01D, rand.nextGaussian() * 0.01D, FMLClientHandler.instance().getClient().effectRenderer)); + FMLClientHandler.instance().getClient().effectRenderer.addEffect(new GoggleRiftFX(world,x+.5, y+.5, z+.5, rand.nextGaussian() * 0.01D, rand.nextGaussian() * 0.01D, rand.nextGaussian() * 0.01D, FMLClientHandler.instance().getClient().effectRenderer)); } if(tile.shouldClose) { //renders an opposite color effect if it is being closed by the rift remover - FMLClientHandler.instance().getClient().effectRenderer.addEffect(new ClosingRiftFX(par1World,par2+.5, par3+.5, par4+.5, rand.nextGaussian() * 0.01D, rand.nextGaussian() * 0.01D, rand.nextGaussian() * 0.01D, FMLClientHandler.instance().getClient().effectRenderer)); + FMLClientHandler.instance().getClient().effectRenderer.addEffect(new ClosingRiftFX(world,x+.5, y+.5, z+.5, rand.nextGaussian() * 0.01D, rand.nextGaussian() * 0.01D, rand.nextGaussian() * 0.01D, FMLClientHandler.instance().getClient().effectRenderer)); } + + } + + 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) @@ -374,7 +351,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; } @@ -396,4 +387,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/DimensionalDoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/DimensionalDoor.java index f8869ea..8416f5f 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/DimensionalDoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/DimensionalDoor.java @@ -3,16 +3,15 @@ package StevenDimDoors.mod_pocketDim.blocks; import net.minecraft.block.material.Material; import net.minecraft.item.Item; import net.minecraft.world.World; -import StevenDimDoors.mod_pocketDim.DDProperties; +import StevenDimDoors.mod_pocketDim.mod_pocketDim; +import StevenDimDoors.mod_pocketDim.config.DDProperties; import StevenDimDoors.mod_pocketDim.core.DimLink; -import StevenDimDoors.mod_pocketDim.core.LinkTypes; +import StevenDimDoors.mod_pocketDim.core.LinkType; import StevenDimDoors.mod_pocketDim.core.NewDimData; import StevenDimDoors.mod_pocketDim.core.PocketManager; -@SuppressWarnings("deprecation") public class DimensionalDoor extends BaseDimDoor { - public DimensionalDoor(int blockID, Material material, DDProperties properties) { super(blockID, material, properties); @@ -23,14 +22,21 @@ public class DimensionalDoor extends BaseDimDoor { if (!world.isRemote && world.getBlockId(x, y - 1, z) == this.blockID) { - NewDimData dimension = PocketManager.getDimensionData(world); + NewDimData dimension = PocketManager.createDimensionData(world); DimLink link = dimension.getLink(x, y, z); if (link == null) { - dimension.createLink(x, y, z, LinkTypes.POCKET,world.getBlockMetadata(x, y - 1, z)); + dimension.createLink(x, y, z, LinkType.POCKET,world.getBlockMetadata(x, y - 1, z)); } } } + + @Override + public int getDoorItem() + { + return mod_pocketDim.itemDimensionalDoor.itemID; + } + @Override public int getDrops() { diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/IDimDoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/IDimDoor.java index b3884dc..608eeb3 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/IDimDoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/IDimDoor.java @@ -6,11 +6,39 @@ import net.minecraft.world.World; public interface IDimDoor { + /** + * A function to enter a dim door and traverse its link, called when a player collides with an open door + * @param world + * @param x + * @param y + * @param z + * @param entity + */ public void enterDimDoor(World world, int x, int y, int z, Entity entity); + /** + * called when a door is placed to determine how it will place a link + * @param world + * @param x + * @param y + * @param z + */ public void placeLink(World world, int x, int y, int z); public int getDrops(); + public int getDoorItem(); + public TileEntity initDoorTE(World world, int x, int y, int z); + + /** + * checks if any of this doors blocks are overlapping with a rift + * @param world + * @param x + * @param y + * @param z + * @return + */ + public boolean isDoorOnRift(World world, int x, int y, int z); + } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/PersonalDimDoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/PersonalDimDoor.java new file mode 100644 index 0000000..4dfb501 --- /dev/null +++ b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/PersonalDimDoor.java @@ -0,0 +1,47 @@ +package StevenDimDoors.mod_pocketDim.blocks; + +import net.minecraft.block.material.Material; +import net.minecraft.world.World; +import StevenDimDoors.mod_pocketDim.mod_pocketDim; +import StevenDimDoors.mod_pocketDim.config.DDProperties; +import StevenDimDoors.mod_pocketDim.core.DimLink; +import StevenDimDoors.mod_pocketDim.core.LinkType; +import StevenDimDoors.mod_pocketDim.core.NewDimData; +import StevenDimDoors.mod_pocketDim.core.PocketManager; + +public class PersonalDimDoor extends BaseDimDoor +{ + + public PersonalDimDoor(int blockID, Material material, DDProperties properties) + { + super(blockID, material, properties); + // TODO Auto-generated constructor stub + } + + @Override + public void placeLink(World world, int x, int y, int z) + { + if (!world.isRemote && world.getBlockId(x, y - 1, z) == this.blockID) + { + NewDimData dimension = PocketManager.getDimensionData(world); + DimLink link = dimension.getLink(x, y, z); + if (link == null) + { + dimension.createLink(x, y, z, LinkType.PERSONAL, world.getBlockMetadata(x, y - 1, z)); + } + } + } + + @Override + public int getDrops() + { + return mod_pocketDim.itemQuartzDoor.itemID; + } + + @Override + public int getDoorItem() + { + return mod_pocketDim.itemPersonalDoor.itemID; + } + +} diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/TransTrapdoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/TransTrapdoor.java index d1b7fd4..453569b 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/TransTrapdoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/TransTrapdoor.java @@ -2,23 +2,28 @@ package StevenDimDoors.mod_pocketDim.blocks; import java.util.Random; +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + import net.minecraft.block.Block; import net.minecraft.block.BlockTrapDoor; import net.minecraft.block.ITileEntityProvider; import net.minecraft.block.material.Material; import net.minecraft.client.renderer.texture.IconRegister; import net.minecraft.entity.Entity; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; import net.minecraft.tileentity.TileEntity; import net.minecraft.world.World; import StevenDimDoors.mod_pocketDim.mod_pocketDim; import StevenDimDoors.mod_pocketDim.core.DDTeleporter; import StevenDimDoors.mod_pocketDim.core.DimLink; -import StevenDimDoors.mod_pocketDim.core.LinkTypes; +import StevenDimDoors.mod_pocketDim.core.LinkType; import StevenDimDoors.mod_pocketDim.core.NewDimData; import StevenDimDoors.mod_pocketDim.core.PocketManager; +import StevenDimDoors.mod_pocketDim.items.ItemDDKey; import StevenDimDoors.mod_pocketDim.tileentities.TileEntityTransTrapdoor; -@SuppressWarnings("deprecation") public class TransTrapdoor extends BlockTrapDoor implements IDimDoor, ITileEntityProvider { @@ -41,18 +46,66 @@ public class TransTrapdoor extends BlockTrapDoor implements IDimDoor, ITileEntit enterDimDoor(world, x, y, z, entity); } + public boolean checkCanOpen(World world, int x, int y, int z) + { + return this.checkCanOpen(world, x, y, z, null); + } + + public boolean checkCanOpen(World world, int x, int y, int z, EntityPlayer player) + { + DimLink link = PocketManager.getLink( x, y, z, world); + if(link==null||player==null) + { + return link==null; + } + if(!link.getLockState()) + { + return true; + } + + for(ItemStack item : player.inventory.mainInventory) + { + if(item != null) + { + if(item.getItem() instanceof ItemDDKey) + { + if(link.tryToOpen(item)) + { + return true; + } + } + } + } + return false; + } + + public boolean onBlockActivated(World par1World, int par2, int par3, int par4, EntityPlayer par5EntityPlayer, int par6, float par7, float par8, float par9) + { + if(this.checkCanOpen(par1World, par2, par3, par4, par5EntityPlayer)) + { + return super.onBlockActivated(par1World, par2, par3, par4, par5EntityPlayer, par6, par7, par8, par9); + } + return false; + } + + public void onPoweredBlockChange(World par1World, int par2, int par3, int par4, boolean par5) + { + if(this.checkCanOpen(par1World, par2, par3, par4)) + { + super.onPoweredBlockChange(par1World, par2, par3, par4, par5); + } + } @Override public void enterDimDoor(World world, int x, int y, int z, Entity entity) { if (!world.isRemote && isTrapdoorOpen(world.getBlockMetadata(x, y, z))) { - this.onPoweredBlockChange(world, x, y, z, false); - DimLink link = PocketManager.getLink(x, y, z, world); if (link != null) { DDTeleporter.traverseDimDoor(world, link, entity,this); } + super.onPoweredBlockChange(world, x, y, z, false); } } @@ -61,14 +114,6 @@ public class TransTrapdoor extends BlockTrapDoor implements IDimDoor, ITileEntit { this.placeLink(world, x, y, z); world.setBlockTileEntity(x, y, z, this.createNewTileEntity(world)); - this.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 @@ -76,42 +121,44 @@ public class TransTrapdoor extends BlockTrapDoor implements IDimDoor, ITileEntit { return new TileEntityTransTrapdoor(); } - - public 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) { if (!world.isRemote) { - NewDimData dimension = PocketManager.getDimensionData(world); + NewDimData dimension = PocketManager.createDimensionData(world); 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, LinkType.UNSAFE_EXIT,0); } } } - + + @Override + @SideOnly(Side.CLIENT) + public int idPicked(World world, int x, int y, int z) + { + return this.getDoorItem(); + } @Override public int idDropped(int metadata, Random random, int fortuneLevel) { - return getDrops(); + return this.getDrops(); } + + @Override + public int getDoorItem() + { + return mod_pocketDim.transTrapdoor.blockID; + } @Override public int getDrops() { - return Block.trapdoor.blockID; + return Block.trapdoor.blockID; } public static boolean isTrapdoorSetLow(int metadata) @@ -126,4 +173,24 @@ public class TransTrapdoor extends BlockTrapDoor implements IDimDoor, ITileEntit world.setBlockTileEntity(x, y, z, te); return te; } + + @Override + public boolean isDoorOnRift(World world, int x, int y, int z) + { + return PocketManager.getLink(x, y, z, world)!=null; + } + + @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/TransientDoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/TransientDoor.java index 0c00501..8364733 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/TransientDoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/TransientDoor.java @@ -1,19 +1,17 @@ package StevenDimDoors.mod_pocketDim.blocks; -import StevenDimDoors.mod_pocketDim.DDProperties; -import StevenDimDoors.mod_pocketDim.core.DDTeleporter; -import StevenDimDoors.mod_pocketDim.core.DimLink; -import StevenDimDoors.mod_pocketDim.core.LinkTypes; -import StevenDimDoors.mod_pocketDim.core.NewDimData; -import StevenDimDoors.mod_pocketDim.core.PocketManager; - import net.minecraft.block.material.Material; -import net.minecraft.client.particle.EntityFX; import net.minecraft.entity.Entity; -import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; import net.minecraft.util.AxisAlignedBB; import net.minecraft.world.World; +import StevenDimDoors.mod_pocketDim.config.DDProperties; +import StevenDimDoors.mod_pocketDim.core.DDTeleporter; +import StevenDimDoors.mod_pocketDim.core.DimLink; +import StevenDimDoors.mod_pocketDim.core.LinkType; +import StevenDimDoors.mod_pocketDim.core.NewDimData; +import StevenDimDoors.mod_pocketDim.core.PocketManager; public class TransientDoor extends BaseDimDoor { @@ -66,14 +64,20 @@ public class TransientDoor extends BaseDimDoor { if (!world.isRemote && world.getBlockId(x, y - 1, z) == this.blockID) { - NewDimData dimension = PocketManager.getDimensionData(world); + NewDimData dimension = PocketManager.createDimensionData(world); DimLink link = dimension.getLink(x, y, z); if (link == null && dimension.isPocketDimension()) { - dimension.createLink(x, y, z, LinkTypes.SAFE_EXIT,world.getBlockMetadata(x, y - 1, z)); + dimension.createLink(x, y, z, LinkType.SAFE_EXIT,world.getBlockMetadata(x, y - 1, z)); } } } + + @Override + public int getDoorItem() + { + return 0; + } @Override public int getDrops() diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/UnstableDoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/UnstableDoor.java index cf2b699..76b9911 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/UnstableDoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/UnstableDoor.java @@ -3,8 +3,9 @@ package StevenDimDoors.mod_pocketDim.blocks; import net.minecraft.block.material.Material; import net.minecraft.item.Item; import net.minecraft.world.World; -import StevenDimDoors.mod_pocketDim.DDProperties; -import StevenDimDoors.mod_pocketDim.core.LinkTypes; +import StevenDimDoors.mod_pocketDim.mod_pocketDim; +import StevenDimDoors.mod_pocketDim.config.DDProperties; +import StevenDimDoors.mod_pocketDim.core.LinkType; import StevenDimDoors.mod_pocketDim.core.NewDimData; import StevenDimDoors.mod_pocketDim.core.PocketManager; @@ -21,9 +22,16 @@ public class UnstableDoor extends BaseDimDoor if (!world.isRemote && world.getBlockId(x, y - 1, z) == this.blockID) { NewDimData dimension = PocketManager.getDimensionData(world); - dimension.createLink(x, y, z, LinkTypes.RANDOM,world.getBlockMetadata(x, y - 1, z)); + dimension.createLink(x, y, z, LinkType.RANDOM,world.getBlockMetadata(x, y - 1, z)); } } + + @Override + public int getDoorItem() + { + return mod_pocketDim.itemUnstableDoor.itemID; + } + @Override public int getDrops() { diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/WarpDoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/WarpDoor.java index 7decebf..45357e9 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/WarpDoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/WarpDoor.java @@ -3,13 +3,13 @@ package StevenDimDoors.mod_pocketDim.blocks; import net.minecraft.block.material.Material; import net.minecraft.item.Item; import net.minecraft.world.World; -import StevenDimDoors.mod_pocketDim.DDProperties; +import StevenDimDoors.mod_pocketDim.mod_pocketDim; +import StevenDimDoors.mod_pocketDim.config.DDProperties; import StevenDimDoors.mod_pocketDim.core.DimLink; -import StevenDimDoors.mod_pocketDim.core.LinkTypes; +import StevenDimDoors.mod_pocketDim.core.LinkType; import StevenDimDoors.mod_pocketDim.core.NewDimData; import StevenDimDoors.mod_pocketDim.core.PocketManager; -@SuppressWarnings("deprecation") public class WarpDoor extends BaseDimDoor { public WarpDoor(int blockID, Material material, DDProperties properties) @@ -22,15 +22,21 @@ public class WarpDoor extends BaseDimDoor { if (!world.isRemote && world.getBlockId(x, y - 1, z) == this.blockID) { - NewDimData dimension = PocketManager.getDimensionData(world); + NewDimData dimension = PocketManager.createDimensionData(world); DimLink link = dimension.getLink(x, y, z); if (link == null && dimension.isPocketDimension()) { - dimension.createLink(x, y, z, LinkTypes.SAFE_EXIT,world.getBlockMetadata(x, y - 1, z)); + dimension.createLink(x, y, z, LinkType.SAFE_EXIT,world.getBlockMetadata(x, y - 1, z)); } } } + @Override + public int getDoorItem() + { + return mod_pocketDim.itemWarpDoor.itemID; + } + @Override public int getDrops() { diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandCreateDungeonRift.java b/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandCreateDungeonRift.java index 791b4bb..4fa55a3 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandCreateDungeonRift.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandCreateDungeonRift.java @@ -1,27 +1,25 @@ package StevenDimDoors.mod_pocketDim.commands; +import java.util.Collection; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.util.MathHelper; import StevenDimDoors.mod_pocketDim.mod_pocketDim; import StevenDimDoors.mod_pocketDim.core.DimLink; -import StevenDimDoors.mod_pocketDim.core.LinkTypes; +import StevenDimDoors.mod_pocketDim.core.LinkType; import StevenDimDoors.mod_pocketDim.core.NewDimData; import StevenDimDoors.mod_pocketDim.core.PocketManager; import StevenDimDoors.mod_pocketDim.dungeon.DungeonData; import StevenDimDoors.mod_pocketDim.helpers.DungeonHelper; import StevenDimDoors.mod_pocketDim.world.PocketBuilder; -import java.util.Collection; - -import net.minecraft.command.ICommandSender; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.util.MathHelper; - public class CommandCreateDungeonRift extends DDCommandBase { private static CommandCreateDungeonRift instance = null; private CommandCreateDungeonRift() { - super("dd-rift", ""); + super("dd-rift", ""); } public static CommandCreateDungeonRift instance() @@ -32,24 +30,12 @@ public class CommandCreateDungeonRift extends DDCommandBase return instance; } - @Override - public String getCommandUsage(ICommandSender sender) - { - return "Usage: /dd-rift \r\n" + - " /dd-rift list\r\n" + - " /dd-rift random"; - } - @Override protected DDCommandResult processCommand(EntityPlayer sender, String[] command) { NewDimData dimension; DungeonHelper dungeonHelper = DungeonHelper.instance(); - if (sender.worldObj.isRemote) - { - return DDCommandResult.SUCCESS; - } if (command.length == 0) { return DDCommandResult.TOO_FEW_ARGUMENTS; @@ -58,61 +44,48 @@ public class CommandCreateDungeonRift extends DDCommandBase { return DDCommandResult.TOO_MANY_ARGUMENTS; } + + DimLink link; + DungeonData result; + int x = MathHelper.floor_double(sender.posX); + int y = MathHelper.floor_double(sender.posY); + int z = MathHelper.floor_double (sender.posZ); + int orientation = MathHelper.floor_double((sender.rotationYaw + 180.0F) * 4.0F / 360.0F - 0.5D) & 3; - if (command[0].equals("list")) + result = findDungeonByPartialName(command[0], dungeonHelper.getRegisteredDungeons()); + if (result == null) { - Collection dungeonNames = dungeonHelper.getDungeonNames(); - for (String name : dungeonNames) - { - sendChat(sender, name); - } - sendChat(sender, ""); + result = findDungeonByPartialName(command[0], dungeonHelper.getUntaggedDungeons()); } - else + + // Check if we found any matches + if (result != null) { - DimLink link; - DungeonData result; - int x = MathHelper.floor_double(sender.posX); - int y = MathHelper.floor_double(sender.posY); - int z = MathHelper.floor_double (sender.posZ); - int orientation = MathHelper.floor_double((sender.rotationYaw + 180.0F) * 4.0F / 360.0F - 0.5D) & 3; + dimension = PocketManager.getDimensionData(sender.worldObj); + link = dimension.createLink(x, y + 1, z, LinkType.DUNGEON, orientation); - if (command[0].equals("random")) + if (PocketBuilder.generateSelectedDungeonPocket(link, mod_pocketDim.properties, result)) { - - dimension = PocketManager.getDimensionData(sender.worldObj); - link = dimension.createLink(x, y + 1, z, LinkTypes.DUNGEON, orientation); - sender.worldObj.setBlock(x, y + 1, z,mod_pocketDim.blockRift.blockID, 0, 3); - sendChat(sender, "Created a rift to a random dungeon."); + // Create a rift to our selected dungeon and notify the player + sender.worldObj.setBlock(x, y + 1, z, mod_pocketDim.blockRift.blockID, 0, 3); + sendChat(sender, "Created a rift to \"" + result.schematicName() + "\" dungeon (Dimension ID = " + link.destination().getDimension() + ")."); } else { - result = findDungeonByPartialName(command[0], dungeonHelper.getRegisteredDungeons()); - if (result == null) - { - result = findDungeonByPartialName(command[0], dungeonHelper.getUntaggedDungeons()); - } - //Check if we found any matches - if (result != null) - { - //Create a rift to our selected dungeon and notify the player - dimension = PocketManager.getDimensionData(sender.worldObj); - link = dimension.createLink(x, y + 1, z, LinkTypes.DUNGEON, orientation); - PocketBuilder.generateSelectedDungeonPocket(link, mod_pocketDim.properties, result); - sender.worldObj.setBlock(x, y + 1, z, mod_pocketDim.blockRift.blockID, 0, 3); - sendChat(sender, "Created a rift to \"" + result.schematicName() + "\" dungeon (Dimension ID = " + link.destination().getDimension() + ")."); - } - else - { - //No matches! - return new DDCommandResult("Error: The specified dungeon was not found. Use 'list' to see a list of the available dungeons."); - } + // Dungeon generation failed somehow. Notify the user and remove the useless link. + dimension.deleteLink(link); + sendChat(sender, "Dungeon generation failed unexpectedly!"); } } + else + { + //No matches! + return new DDCommandResult("Error: The specified dungeon was not found. Use 'dd-list' to see a list of the available dungeons."); + } return DDCommandResult.SUCCESS; } - private DungeonData findDungeonByPartialName(String query, Collection dungeons) + private static DungeonData findDungeonByPartialName(String query, Collection dungeons) { //Search for the shortest dungeon name that contains the lowercase query string. String dungeonName; diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandCreatePocket.java b/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandCreatePocket.java index 1081a18..9de7a3a 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandCreatePocket.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandCreatePocket.java @@ -1,6 +1,5 @@ package StevenDimDoors.mod_pocketDim.commands; -import net.minecraft.command.ICommandSender; import net.minecraft.entity.player.EntityPlayer; import StevenDimDoors.mod_pocketDim.helpers.DungeonHelper; @@ -21,34 +20,24 @@ public class CommandCreatePocket extends DDCommandBase return instance; } - @Override - public String getCommandUsage(ICommandSender sender) { - return "Usage: /dd-create"; - } - @Override protected DDCommandResult processCommand(EntityPlayer sender, String[] command) { - //TODO: Some commands have isRemote checks, some do not. Why? Can commands even run locally anyway? - //What does it mean when you run a command locally? ~SenseiKiwi - - if (!sender.worldObj.isRemote) + if (command.length > 0) { - if (command.length > 0) - { - return DDCommandResult.TOO_MANY_ARGUMENTS; - } - - //Place a door leading to a pocket dimension where the player is standing. - //The pocket dimension will serve as a room for the player to build a dungeon. - int x = (int) sender.posX; - int y = (int) sender.posY; - int z = (int) sender.posZ; - DungeonHelper.instance().createCustomDungeonDoor(sender.worldObj, x, y, z); - - //Notify the player - sendChat(sender,("Created a door to a pocket dimension. Please build your dungeon there.")); + return DDCommandResult.TOO_MANY_ARGUMENTS; } + + //Place a door leading to a pocket dimension where the player is standing. + //The pocket dimension will serve as a room for the player to build a dungeon. + int x = (int) sender.posX; + int y = (int) sender.posY; + int z = (int) sender.posZ; + DungeonHelper.instance().createCustomDungeonDoor(sender.worldObj, x, y, z); + + //Notify the player + sendChat(sender, "Created a door to a pocket dimension. Please build your dungeon there."); + return DDCommandResult.SUCCESS; } } \ No newline at end of file diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandCreateRandomRift.java b/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandCreateRandomRift.java new file mode 100644 index 0000000..0c6672f --- /dev/null +++ b/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandCreateRandomRift.java @@ -0,0 +1,121 @@ +package StevenDimDoors.mod_pocketDim.commands; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Random; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.util.MathHelper; +import StevenDimDoors.mod_pocketDim.mod_pocketDim; +import StevenDimDoors.mod_pocketDim.core.DimLink; +import StevenDimDoors.mod_pocketDim.core.LinkType; +import StevenDimDoors.mod_pocketDim.core.NewDimData; +import StevenDimDoors.mod_pocketDim.core.PocketManager; +import StevenDimDoors.mod_pocketDim.dungeon.DungeonData; +import StevenDimDoors.mod_pocketDim.helpers.DungeonHelper; +import StevenDimDoors.mod_pocketDim.world.PocketBuilder; + +public class CommandCreateRandomRift extends DDCommandBase +{ + private static CommandCreateRandomRift instance = null; + private static Random random = new Random(); + + private CommandCreateRandomRift() + { + super("dd-random", ""); + } + + public static CommandCreateRandomRift instance() + { + if (instance == null) + instance = new CommandCreateRandomRift(); + + return instance; + } + + @Override + protected DDCommandResult processCommand(EntityPlayer sender, String[] command) + { + NewDimData dimension; + DungeonHelper dungeonHelper = DungeonHelper.instance(); + + if (command.length > 1) + { + return DDCommandResult.TOO_MANY_ARGUMENTS; + } + + DimLink link; + DungeonData result; + int x = MathHelper.floor_double(sender.posX); + int y = MathHelper.floor_double(sender.posY); + int z = MathHelper.floor_double (sender.posZ); + int orientation = MathHelper.floor_double((sender.rotationYaw + 180.0F) * 4.0F / 360.0F - 0.5D) & 3; + + if (command.length == 0) + { + dimension = PocketManager.getDimensionData(sender.worldObj); + link = dimension.createLink(x, y + 1, z, LinkType.DUNGEON, orientation); + + sender.worldObj.setBlock(x, y + 1, z,mod_pocketDim.blockRift.blockID, 0, 3); + sendChat(sender, "Created a rift to a random dungeon."); + } + else + { + result = getRandomDungeonByPartialName(command[0], dungeonHelper.getRegisteredDungeons()); + if (result == null) + { + result = getRandomDungeonByPartialName(command[0], dungeonHelper.getUntaggedDungeons()); + } + + // Check if we found any matches + if (result != null) + { + dimension = PocketManager.getDimensionData(sender.worldObj); + link = dimension.createLink(x, y + 1, z, LinkType.DUNGEON, orientation); + + if (PocketBuilder.generateSelectedDungeonPocket(link, mod_pocketDim.properties, result)) + { + // Create a rift to our selected dungeon and notify the player + sender.worldObj.setBlock(x, y + 1, z, mod_pocketDim.blockRift.blockID, 0, 3); + sendChat(sender, "Created a rift to \"" + result.schematicName() + "\" dungeon (Dimension ID = " + link.destination().getDimension() + ")."); + } + else + { + // Dungeon generation failed somehow. Notify the user and remove the useless link. + dimension.deleteLink(link); + sendChat(sender, "Dungeon generation failed unexpectedly!"); + } + } + else + { + //No matches! + return new DDCommandResult("Error: The specified dungeon was not found. Use 'list' to see a list of the available dungeons."); + } + } + return DDCommandResult.SUCCESS; + } + + private static DungeonData getRandomDungeonByPartialName(String query, Collection dungeons) + { + // Search for all dungeons that contain the lowercase query string. + String dungeonName; + String normalQuery = query.toLowerCase(); + ArrayList matches = new ArrayList(); + + for (DungeonData dungeon : dungeons) + { + // We need to extract the file's name. Comparing against schematicPath could + // yield false matches if the query string is contained within the path. + dungeonName = dungeon.schematicName().toLowerCase(); + if (dungeonName.contains(normalQuery)) + { + matches.add(dungeon); + } + } + if (matches.isEmpty()) + { + return null; + } + return matches.get( random.nextInt(matches.size()) ); + } +} \ No newline at end of file diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandDeleteAllLinks.java b/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandDeleteAllLinks.java deleted file mode 100644 index 2923716..0000000 --- a/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandDeleteAllLinks.java +++ /dev/null @@ -1,74 +0,0 @@ -package StevenDimDoors.mod_pocketDim.commands; - -import StevenDimDoors.mod_pocketDim.core.DimLink; -import StevenDimDoors.mod_pocketDim.core.NewDimData; -import StevenDimDoors.mod_pocketDim.core.PocketManager; - -import java.util.ArrayList; - -import net.minecraft.command.ICommandSender; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.world.World; - -@SuppressWarnings("deprecation") -public class CommandDeleteAllLinks extends DDCommandBase -{ - private static CommandDeleteAllLinks instance = null; - - private CommandDeleteAllLinks() - { - super("dd-deletelinks", "???"); - } - - public static CommandDeleteAllLinks instance() - { - if (instance == null) - instance = new CommandDeleteAllLinks(); - - return instance; - } - - @Override - public String getCommandUsage(ICommandSender sender) { - return "Usage: /dd-deletelinks "; - } - - @Override - protected DDCommandResult processCommand(EntityPlayer sender, String[] command) - { - int linksRemoved=0; - int targetDim; - boolean shouldGo= true; - - if(command.length==1) - { - targetDim = parseInt(sender, command[0]); - } - else - { - targetDim=0; - shouldGo=false; - sendChat(sender, ("Error-Invalid argument, delete_all_links ")); - } - - if(shouldGo) - { - - NewDimData dim = PocketManager.getDimensionData(targetDim); - ArrayList linksInDim = dim.getAllLinks(); - - for (DimLink link : linksInDim) - { - World targetWorld = PocketManager.loadDimension(targetDim); - targetWorld.setBlock(link.source().getX(), link.source().getY(), link.source().getZ(), 0); - dim.deleteLink(link); - //TODO Probably should check what the block is, but thats annoying so Ill do it later. - - linksRemoved++; - } - sendChat(sender,("Removed " + linksRemoved + " links.")); - - } - return DDCommandResult.SUCCESS; //TEMPORARY HACK - } -} \ No newline at end of file diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandDeleteRifts.java b/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandDeleteRifts.java index 7f6be30..9a50857 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandDeleteRifts.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandDeleteRifts.java @@ -2,22 +2,21 @@ package StevenDimDoors.mod_pocketDim.commands; import java.util.ArrayList; -import net.minecraft.command.ICommandSender; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.world.World; import StevenDimDoors.mod_pocketDim.mod_pocketDim; import StevenDimDoors.mod_pocketDim.core.DimLink; import StevenDimDoors.mod_pocketDim.core.NewDimData; import StevenDimDoors.mod_pocketDim.core.PocketManager; +import StevenDimDoors.mod_pocketDim.util.Point4D; -@SuppressWarnings("deprecation") public class CommandDeleteRifts extends DDCommandBase { private static CommandDeleteRifts instance = null; private CommandDeleteRifts() { - super("dd-???", "???"); + super("dd-deleterifts", "[dimension number]"); } public static CommandDeleteRifts instance() @@ -28,55 +27,67 @@ public class CommandDeleteRifts extends DDCommandBase return instance; } - @Override - public String getCommandUsage(ICommandSender sender) { - return "Usage: /dd-??? "; - } - @Override protected DDCommandResult processCommand(EntityPlayer sender, String[] command) { - int linksRemoved=0; - int targetDim; - boolean shouldGo= true; + int linksRemoved = 0; + int targetDimension; - if(command.length==1) + if (command.length > 1) { - targetDim = parseInt(sender, command[0]); + return DDCommandResult.TOO_MANY_ARGUMENTS; + } + if (command.length == 0) + { + targetDimension = sender.worldObj.provider.dimensionId; } else { - targetDim=0; - shouldGo=false; - sendChat(sender,("Error-Invalid argument, delete_all_links ")); + try + { + targetDimension = Integer.parseInt(command[0]); + } + catch (NumberFormatException e) + { + return DDCommandResult.INVALID_DIMENSION_ID; + } } - if(shouldGo) + World world = PocketManager.loadDimension(targetDimension); + if (world == null) { - - NewDimData dim = PocketManager.getDimensionData(targetDim); - ArrayList linksInDim = dim.getAllLinks(); - - for (DimLink link : linksInDim) - { - World targetWorld = PocketManager.loadDimension(targetDim); - - if(!mod_pocketDim.blockRift.isBlockImmune(sender.worldObj,link.source().getX(), link.source().getY(), link.source().getZ())|| - (targetWorld.getBlockId(link.source().getX(), link.source().getY(), link.source().getZ())==mod_pocketDim.blockRift.blockID)) - { - linksRemoved++; - targetWorld.setBlock(link.source().getX(), link.source().getY(), link.source().getZ(), 0); - dim.deleteLink(link); - - - } - //TODO Probably should check what the block is, but thats annoying so Ill do it later. - - - } - sendChat(sender,("Removed " + linksRemoved + " links.")); - + return DDCommandResult.UNREGISTERED_DIMENSION; } - return DDCommandResult.SUCCESS; //TEMPORARY HACK + + int x; + int y; + int z; + Point4D location; + NewDimData dimension = PocketManager.createDimensionData(world); + ArrayList links = dimension.getAllLinks(); + for (DimLink link : links) + { + location = link.source(); + x = location.getX(); + y = location.getY(); + z = location.getZ(); + if (world.getBlockId(x, y, z) == mod_pocketDim.blockRift.blockID) + { + // Remove the rift and its link + world.setBlockToAir(x, y, z); + dimension.deleteLink(link); + linksRemoved++; + } + else if (!mod_pocketDim.blockRift.isBlockImmune(world, x, y, z)) + { + // If a block is not immune, then it must not be a DD block. + // The link would regenerate into a rift eventually. + // We only need to remove the link. + dimension.deleteLink(link); + linksRemoved++; + } + } + sendChat(sender, "Removed " + linksRemoved + " links."); + return DDCommandResult.SUCCESS; } } \ No newline at end of file diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandExportDungeon.java b/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandExportDungeon.java index 7e7df1d..84b9584 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandExportDungeon.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandExportDungeon.java @@ -2,9 +2,8 @@ package StevenDimDoors.mod_pocketDim.commands; import java.io.File; -import net.minecraft.command.ICommandSender; import net.minecraft.entity.player.EntityPlayer; -import StevenDimDoors.mod_pocketDim.DDProperties; +import StevenDimDoors.mod_pocketDim.config.DDProperties; import StevenDimDoors.mod_pocketDim.helpers.DungeonHelper; public class CommandExportDungeon extends DDCommandBase @@ -26,13 +25,6 @@ public class CommandExportDungeon extends DDCommandBase return instance; } - @Override - public String getCommandUsage(ICommandSender sender) { - return "Usage: /dd-export open \r\n" + - " /dd-export closed \r\n" + - " /dd-export override"; - } - @Override protected DDCommandResult processCommand(EntityPlayer sender, String[] command) { @@ -67,66 +59,51 @@ public class CommandExportDungeon extends DDCommandBase //Export the schematic return exportDungeon(sender, command[0]); } - else - { - //The schematic name contains illegal characters. Inform the user. - return new DDCommandResult("Error: Invalid schematic name. Please use only letters, numbers, dashes, and underscores."); - } - } - else - { - //The command is malformed in some way. Assume that the user meant to use - //the 3-argument version and report an error. - return DDCommandResult.TOO_FEW_ARGUMENTS; + //The schematic name contains illegal characters. Inform the user. + return new DDCommandResult("Error: Invalid schematic name. Please use only letters, numbers, dashes, and underscores."); } + //The command is malformed in some way. Assume that the user meant to use + //the 3-argument version and report an error. + return DDCommandResult.TOO_FEW_ARGUMENTS; } //The user must have used the 3-argument version of this command - //TODO: Why do we check remoteness here but not before? And why not for the other export case? - //Something feels wrong... ~SenseiKiwi - if (!sender.worldObj.isRemote) + //TODO: This validation should be in DungeonHelper or in another class. We should move it + //during the save file format rewrite. ~SenseiKiwi + + if (!dungeonHelper.validateDungeonType(command[0], dungeonHelper.getDungeonPack("ruins"))) { - //TODO: This validation should be in DungeonHelper or in another class. We should move it - //during the save file format rewrite. ~SenseiKiwi - - if (!dungeonHelper.validateDungeonType(command[0], dungeonHelper.getDungeonPack("ruins"))) - { - return new DDCommandResult("Error: Invalid dungeon type. Please use one of the existing types."); - } - if (!DungeonHelper.DUNGEON_NAME_PATTERN.matcher(command[1]).matches()) - { - return new DDCommandResult("Error: Invalid dungeon name. Please use only letters, numbers, and dashes."); - } - if (!command[2].equalsIgnoreCase("open") && !command[2].equalsIgnoreCase("closed")) - { - return new DDCommandResult("Error: Please specify whether the dungeon is 'open' or 'closed'."); - } - - //If there are no more arguments, export the dungeon. - if (command.length == 3) - { - return exportDungeon(sender, join(command, "_", 0, 3)); - } - else - { - //Validate the weight argument - try - { - int weight = Integer.parseInt(command[3]); - if (weight >= DungeonHelper.MIN_DUNGEON_WEIGHT && weight <= DungeonHelper.MAX_DUNGEON_WEIGHT) - { - return exportDungeon(sender, join(command, "_", 0, 4)); - } - } - catch (Exception e) { } - } - - //If we've reached this point, then we must have an invalid weight. - return new DDCommandResult("Invalid dungeon weight. Please specify a weight between " - + DungeonHelper.MIN_DUNGEON_WEIGHT + " and " + DungeonHelper.MAX_DUNGEON_WEIGHT + ", inclusive."); + return new DDCommandResult("Error: Invalid dungeon type. Please use one of the existing types."); + } + if (!DungeonHelper.DUNGEON_NAME_PATTERN.matcher(command[1]).matches()) + { + return new DDCommandResult("Error: Invalid dungeon name. Please use only letters, numbers, and dashes."); + } + if (!command[2].equalsIgnoreCase("open") && !command[2].equalsIgnoreCase("closed")) + { + return new DDCommandResult("Error: Please specify whether the dungeon is 'open' or 'closed'."); } - return DDCommandResult.SUCCESS; + //If there are no more arguments, export the dungeon. + if (command.length == 3) + { + return exportDungeon(sender, join(command, "_", 0, 3)); + } + + //Validate the weight argument + try + { + int weight = Integer.parseInt(command[3]); + if (weight >= DungeonHelper.MIN_DUNGEON_WEIGHT && weight <= DungeonHelper.MAX_DUNGEON_WEIGHT) + { + return exportDungeon(sender, join(command, "_", 0, 4)); + } + } + catch (Exception e) { } + + //If we've reached this point, then we must have an invalid weight. + return new DDCommandResult("Invalid dungeon weight. Please specify a weight between " + + DungeonHelper.MIN_DUNGEON_WEIGHT + " and " + DungeonHelper.MAX_DUNGEON_WEIGHT + ", inclusive."); } private static DDCommandResult exportDungeon(EntityPlayer player, String name) @@ -144,10 +121,7 @@ public class CommandExportDungeon extends DDCommandBase dungeonHelper.registerDungeon(exportPath, dungeonHelper.getDungeonPack("ruins"), false, true); return DDCommandResult.SUCCESS; } - else - { - return new DDCommandResult("Error: Failed to save dungeon schematic!"); - } + return new DDCommandResult("Error: Failed to save dungeon schematic!"); } private static String join(String[] source, String delimiter, int start, int end) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandListDungeons.java b/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandListDungeons.java new file mode 100644 index 0000000..222b481 --- /dev/null +++ b/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandListDungeons.java @@ -0,0 +1,70 @@ +package StevenDimDoors.mod_pocketDim.commands; + +import java.util.ArrayList; + +import net.minecraft.entity.player.EntityPlayer; +import StevenDimDoors.mod_pocketDim.helpers.DungeonHelper; + +public class CommandListDungeons extends DDCommandBase +{ + private static CommandListDungeons instance = null; + + private CommandListDungeons() + { + super("dd-list", ""); + } + + public static CommandListDungeons instance() + { + if (instance == null) + instance = new CommandListDungeons(); + + return instance; + } + + @Override + protected DDCommandResult processCommand(EntityPlayer sender, String[] command) + { + int page; + int index; + int limit; + int pageCount; + ArrayList dungeonNames; + + if (command.length > 1) + { + return DDCommandResult.TOO_MANY_ARGUMENTS; + } + if (command.length == 0) + { + page = 1; + } + else + { + try + { + page = Integer.parseInt(command[0]); + } + catch (NumberFormatException e) + { + return DDCommandResult.INVALID_ARGUMENTS; + } + } + dungeonNames = DungeonHelper.instance().getDungeonNames(); + pageCount = (dungeonNames.size() - 1) / 10 + 1; + if (page < 1 || page > pageCount) + { + return DDCommandResult.INVALID_ARGUMENTS; + } + sendChat(sender, "List of dungeons (page " + page + " of " + pageCount + "):"); + index = (page - 1) * 10; + limit = Math.min(index + 10, dungeonNames.size()); + for (; index < limit; index++) + { + sendChat(sender, dungeonNames.get(index)); + } + sendChat(sender, ""); + + return DDCommandResult.SUCCESS; + } +} \ No newline at end of file diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandResetDungeons.java b/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandResetDungeons.java index 0f51851..b1ccadc 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandResetDungeons.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandResetDungeons.java @@ -1,16 +1,14 @@ package StevenDimDoors.mod_pocketDim.commands; import java.util.ArrayList; - -import net.minecraft.command.ICommandSender; +import java.util.HashSet; import net.minecraft.entity.player.EntityPlayer; -import net.minecraftforge.common.DimensionManager; import StevenDimDoors.mod_pocketDim.core.DimLink; -import StevenDimDoors.mod_pocketDim.core.LinkTypes; +import StevenDimDoors.mod_pocketDim.core.DimensionType; +import StevenDimDoors.mod_pocketDim.core.LinkType; import StevenDimDoors.mod_pocketDim.core.NewDimData; import StevenDimDoors.mod_pocketDim.core.PocketManager; -@SuppressWarnings("deprecation") public class CommandResetDungeons extends DDCommandBase { private static CommandResetDungeons instance = null; @@ -28,69 +26,81 @@ public class CommandResetDungeons extends DDCommandBase return instance; } - @Override - public String getCommandUsage(ICommandSender sender) { - return "/dd-resetdungeons"; - } - @Override protected DDCommandResult processCommand(EntityPlayer sender, String[] command) { - if(sender.worldObj.isRemote) - { - return DDCommandResult.SUCCESS; - } if (command.length > 0) { - return DDCommandResult.TOO_FEW_ARGUMENTS; + return DDCommandResult.TOO_MANY_ARGUMENTS; + } + + int id; + int resetCount = 0; + int dungeonCount = 0; + HashSet deletedDimensions = new HashSet(); + ArrayList loadedDungeons = new ArrayList(); + + // Copy the list of dimensions to iterate over the copy. Otherwise, + // we would trigger an exception by modifying the original list. + ArrayList dimensions = new ArrayList(); + for (NewDimData dimension : PocketManager.getDimensions()) + { + + dimensions.add(dimension); } - int dungeonCount = 0; - int resetCount = 0; - ArrayList dimsToDelete = new ArrayList(); - ArrayList dimsToFix = new ArrayList(); - - for (NewDimData data : PocketManager.getDimensions()) + // Iterate over the list of dimensions. Check which ones are dungeons. + // If a dungeon is found, try to delete it. If it can't be deleted, + // then it must be loaded and needs to be updated to prevent bugs. + for (NewDimData dimension : dimensions) { - - if(DimensionManager.getWorld(data.id())==null&&data.isDungeon()) + if (dimension.type() == DimensionType.DUNGEON) { - resetCount++; dungeonCount++; - dimsToDelete.add(data.id()); - } - else if(data.isDungeon()) - { - dimsToFix.add(data.id()); - dungeonCount++; - for(DimLink link : data.links()) + id = dimension.id(); + if (PocketManager.deletePocket(dimension, true)) { - if(link.linkType()==LinkTypes.REVERSE) + resetCount++; + deletedDimensions.add(id); + } + else + { + loadedDungeons.add(dimension); + } + } + + } + + // Modify the loaded dungeons to prevent bugs + for (NewDimData dungeon : loadedDungeons) + { + // Find top-most loaded dungeons and update their parents. + // They will automatically update their children. + // Dungeons with non-dungeon parents don't need to be fixed. + if (dungeon.parent() == null) + { + dungeon.setParentToRoot(); + } + + // Links to any deleted dungeons must be replaced + for (DimLink link : dungeon.links()) + { + if (link.hasDestination() && deletedDimensions.contains(link.destination().getDimension())) + { + + if (link.linkType() == LinkType.DUNGEON) { - data.createLink(link.source(), LinkTypes.DUNGEON_EXIT, link.orientation()); + dungeon.createLink(link.source(), LinkType.DUNGEON, link.orientation(), null); } - if(link.linkType()==LinkTypes.DUNGEON) + else if (link.linkType() == LinkType.REVERSE) { - data.createLink(link.source(), LinkTypes.DUNGEON, link.orientation()); + dungeon.createLink(link.source(), LinkType.DUNGEON_EXIT, link.orientation(), null); } } } } - - for(Integer dimID:dimsToDelete) - { - PocketManager.deletePocket(PocketManager.getDimensionData(dimID), true); - } - /** - * temporary workaround - */ - for(Integer dimID: dimsToFix) - { - PocketManager.getDimensionData(dimID).setParentToRoot(); - } - //TODO- for some reason the parent field of loaded dimenions get reset to null if I call .setParentToRoot() before I delete the pockets. - //TODO implement blackList - //Notify the user of the results + + // Notify the user of the results sendChat(sender,("Reset complete. " + resetCount + " out of " + dungeonCount + " dungeons were reset.")); return DDCommandResult.SUCCESS; } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandTeleportPlayer.java b/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandTeleportPlayer.java index 206df94..b001c7a 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandTeleportPlayer.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandTeleportPlayer.java @@ -1,143 +1,146 @@ package StevenDimDoors.mod_pocketDim.commands; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.server.MinecraftServer; +import net.minecraft.world.World; import StevenDimDoors.mod_pocketDim.core.DDTeleporter; +import StevenDimDoors.mod_pocketDim.core.NewDimData; import StevenDimDoors.mod_pocketDim.core.PocketManager; import StevenDimDoors.mod_pocketDim.util.Point4D; -import java.util.Arrays; -import java.util.List; - -import net.minecraft.command.ICommandSender; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraftforge.common.DimensionManager; - public class CommandTeleportPlayer extends DDCommandBase { private static CommandTeleportPlayer instance = null; private CommandTeleportPlayer() { - super("dd-tp", new String[] {" "," "} ); + super("dd-tp", new String[] { + " ", + " ", + " "} ); } public static CommandTeleportPlayer instance() { if (instance == null) - { instance = new CommandTeleportPlayer(); - } + return instance; } - - @Override - public String getCommandUsage(ICommandSender sender) { - return "Usage: /dd-tp "; - } - - /** - * TODO- Change to accept variety of input, like just coords, just dim ID, or two player names. - */ + @Override protected DDCommandResult processCommand(EntityPlayer sender, String[] command) { - EntityPlayer targetPlayer = sender; - int dimDestinationID = sender.worldObj.provider.dimensionId; + int x; + int y; + int z; + World world; + int dimensionID; + Point4D destination; + NewDimData dimension; + boolean checkOrientation; + EntityPlayer targetPlayer; - if(command.length == 5) + if (command.length < 2) { - for(int i= 1; i <5;i++) - { - if(!isInteger(command[i])) - { - return DDCommandResult.INVALID_ARGUMENTS; - } - } - if(sender.worldObj.getPlayerEntityByName(command[0])!=null) //Gets the targeted player - { - targetPlayer = sender.worldObj.getPlayerEntityByName(command[0]); - } - else - { - return DDCommandResult.INVALID_ARGUMENTS; - } - dimDestinationID=Integer.parseInt(command[1]);//gets the target dim ID from the command string - - if(!DimensionManager.isDimensionRegistered(dimDestinationID)) - { - return DDCommandResult.INVALID_DIMENSION_ID; - } - - PocketManager.loadDimension(dimDestinationID); - Point4D destination = new Point4D(Integer.parseInt(command[2]),Integer.parseInt(command[3]),Integer.parseInt(command[4]),dimDestinationID); - DDTeleporter.teleportEntity(targetPlayer, destination, false); + return DDCommandResult.TOO_FEW_ARGUMENTS; } - else if(command.length == 2 && isInteger(command[1])) + if (command.length > 5) { - if(sender.worldObj.getPlayerEntityByName(command[0])!=null) //Gets the targeted player - { - targetPlayer = sender.worldObj.getPlayerEntityByName(command[0]); - } - else - { - return DDCommandResult.INVALID_ARGUMENTS; - } - dimDestinationID=Integer.parseInt(command[1]);//gets the target dim ID from the command string - - if(!DimensionManager.isDimensionRegistered(dimDestinationID)) - { - return DDCommandResult.INVALID_DIMENSION_ID; - } - - - Point4D destination = PocketManager.getDimensionData(dimDestinationID).origin(); - if(!PocketManager.getDimensionData(dimDestinationID).isPocketDimension()) - { - destination = new Point4D(destination.getX(),PocketManager.loadDimension(dimDestinationID).getTopSolidOrLiquidBlock( - destination.getX(), destination.getZ()), - destination.getZ(),destination.getDimension()); - } - DDTeleporter.teleportEntity(targetPlayer, destination, false); + return DDCommandResult.TOO_MANY_ARGUMENTS; } - else if(command.length == 1 && isInteger(command[0])) - { - - targetPlayer = sender; - - dimDestinationID=Integer.parseInt(command[0]);//gets the target dim ID from the command string - - if(!DimensionManager.isDimensionRegistered(dimDestinationID)) - { - return DDCommandResult.INVALID_DIMENSION_ID; - } - - - Point4D destination = PocketManager.getDimensionData(dimDestinationID).origin(); - if(!PocketManager.getDimensionData(dimDestinationID).isPocketDimension()) - { - destination = new Point4D(destination.getX(),PocketManager.loadDimension(dimDestinationID).getTopSolidOrLiquidBlock( - destination.getX(), destination.getZ()), - destination.getZ(),destination.getDimension()); - } - DDTeleporter.teleportEntity(targetPlayer, destination, false); - } - else + if (command.length == 3) { return DDCommandResult.INVALID_ARGUMENTS; } + // Check that all arguments after the username are integers + for (int k = 1; k < command.length; k++) + { + if (!isInteger(command[k])) + { + return DDCommandResult.INVALID_ARGUMENTS; + } + } + // Check if the target player is logged in + targetPlayer = MinecraftServer.getServer().getConfigurationManager().getPlayerForUsername(command[0]); + if (targetPlayer == null) + { + return DDCommandResult.PLAYER_OFFLINE; + } + // If a dimension ID was provided, try to load it + if (command.length != 4) + { + dimensionID = Integer.parseInt(command[1]); + world = PocketManager.loadDimension(dimensionID); + if (world == null) + { + return DDCommandResult.UNREGISTERED_DIMENSION; + } + } + else + { + dimensionID = targetPlayer.worldObj.provider.dimensionId; + world = targetPlayer.worldObj; + } + + // If we teleport to a pocket dimension, set checkOrientation to true + // so the player is placed correctly relative to the entrance door. + checkOrientation = false; + + // Parse or calculate the destination as necessary + // The Y coordinate must be increased by 1 because of the way that + // DDTeleporter considers destination points. It assumes that the + // point provided is the upper block of a door. + if (command.length == 2) + { + // Check if the destination is a pocket dimension + dimension = PocketManager.createDimensionData(world); + if (dimension.isPocketDimension()) + { + // The destination is a pocket dimension. + // Teleport the player to its original entrance (the origin). + destination = dimension.origin(); + checkOrientation = true; + } + else + { + // The destination is not a pocket dimension, which means we + // don't automatically know a safe location where we can send + // the player. Send the player to (0, Y, 0), where Y is chosen + // by searching. Add 2 to place the player ABOVE the top block. + y = world.getTopSolidOrLiquidBlock(0, 0) + 2; + destination = new Point4D(0, y, 0, dimensionID); + } + } + else if (command.length == 4) + { + x = Integer.parseInt(command[1]); + y = Integer.parseInt(command[2]) + 1; // Correct the Y value + z = Integer.parseInt(command[3]); + destination = new Point4D(x, y, z, dimensionID); + } + else + { + x = Integer.parseInt(command[2]); + y = Integer.parseInt(command[3]) + 1; // Correct the Y value + z = Integer.parseInt(command[4]); + destination = new Point4D(x, y, z, dimensionID); + } + // Teleport! + DDTeleporter.teleportEntity(targetPlayer, destination, checkOrientation); return DDCommandResult.SUCCESS; } - public boolean isInteger( String input ) - { - try - { - Integer.parseInt( input ); - return true; - } - catch(Exception e ) - { - return false; - } - } - + private static boolean isInteger(String input) + { + try + { + Integer.parseInt(input); + return true; + } + catch(Exception e) + { + return false; + } + } } \ No newline at end of file diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/commands/DDCommandBase.java b/src/main/java/StevenDimDoors/mod_pocketDim/commands/DDCommandBase.java index b298e51..badb0a2 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/commands/DDCommandBase.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/commands/DDCommandBase.java @@ -5,7 +5,6 @@ import net.minecraft.command.ICommand; import net.minecraft.command.ICommandSender; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.util.ChatMessageComponent; -import cpw.mods.fml.common.event.FMLServerStartingEvent; /* * An abstract base class for our Dimensional Doors commands. This cleans up the code a little and provides @@ -40,12 +39,22 @@ public abstract class DDCommandBase extends CommandBase return name; } - /* - * Registers the command at server startup. - */ - public void register(FMLServerStartingEvent event) + @Override + public final String getCommandUsage(ICommandSender sender) { - event.registerServerCommand(this); + StringBuilder builder = new StringBuilder(); + builder.append('/'); + builder.append(name); + builder.append(' '); + builder.append(formats[0]); + for (int index = 1; index < formats.length; index++) + { + builder.append(" OR /"); + builder.append(name); + builder.append(' '); + builder.append(formats[index]); + } + return builder.toString(); } /* @@ -67,10 +76,10 @@ public abstract class DDCommandBase extends CommandBase //Send the argument formats for this command for (String format : formats) { - sendChat(player,("Usage: " + name + " " + format)); + sendChat(player, "Usage: " + name + " " + format); } } - sendChat(player,(result.getMessage())); + sendChat(player, result.getMessage()); } } @@ -79,12 +88,22 @@ public abstract class DDCommandBase extends CommandBase ChatMessageComponent cmp = new ChatMessageComponent(); cmp.addText(message); player.sendChatToPlayer(cmp); - } - - @Override - public int compareTo(Object par1Obj) + + /* + * The following two compareTo() methods are copied from CommandBase because it seems + * that Dryware and Technic Jenkins don't have those functions defined. How in the world? + * I have no idea. But it's breaking our builds. -_- ~SenseiKiwi + */ + @Override + public int compareTo(ICommand command) { - return this.getCommandName().compareTo(((ICommand)par1Obj).getCommandName()); + return this.getCommandName().compareTo(command.getCommandName()); + } + + @Override + public int compareTo(Object other) + { + return this.compareTo((ICommand) other); } } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/commands/DDCommandResult.java b/src/main/java/StevenDimDoors/mod_pocketDim/commands/DDCommandResult.java index 9ec0cf7..b6a31b9 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/commands/DDCommandResult.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/commands/DDCommandResult.java @@ -8,7 +8,8 @@ public class DDCommandResult { public static final DDCommandResult TOO_MANY_ARGUMENTS = new DDCommandResult(2, "Error: Too many arguments passed to the command", true); public static final DDCommandResult INVALID_DIMENSION_ID = new DDCommandResult(3, "Error: Invalid dimension ID", true); public static final DDCommandResult UNREGISTERED_DIMENSION = new DDCommandResult(4, "Error: Dimension is not registered", false); - public static final DDCommandResult INVALID_ARGUMENTS = new DDCommandResult(5, "Error: Invalid arguments passed to the command.", true); + public static final DDCommandResult INVALID_ARGUMENTS = new DDCommandResult(5, "Error: Invalid arguments passed to the command", true); + public static final DDCommandResult PLAYER_OFFLINE = new DDCommandResult(6, "Error: Player is not online", false); public static final int CUSTOM_ERROR_CODE = -1; diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/DDProperties.java b/src/main/java/StevenDimDoors/mod_pocketDim/config/DDProperties.java similarity index 78% rename from src/main/java/StevenDimDoors/mod_pocketDim/DDProperties.java rename to src/main/java/StevenDimDoors/mod_pocketDim/config/DDProperties.java index 622d107..4996764 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/DDProperties.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/config/DDProperties.java @@ -1,8 +1,9 @@ -package StevenDimDoors.mod_pocketDim; +package StevenDimDoors.mod_pocketDim.config; import java.io.File; import net.minecraftforge.common.Configuration; +import StevenDimDoors.mod_pocketDim.blocks.BlockRift; import StevenDimDoors.mod_pocketDim.ticking.CustomLimboPopulator; import StevenDimDoors.mod_pocketDim.world.fortresses.DDStructureNetherBridgeStart; import StevenDimDoors.mod_pocketDim.world.gateways.GatewayGenerator; @@ -22,6 +23,9 @@ public class DDProperties public final int TransientDoorID; public final int FabricBlockID; public final int RiftBlockID; + public final int QuartzDoorID; + public final int PersonalDimDoorID; + /** * World Generation Block IDs @@ -45,7 +49,9 @@ public class DDProperties public final int UnstableDoorItemID; public final int WarpDoorItemID; public final int WorldThreadItemID; - + public final int DDKeyItemID; + public final int ItemQuartzDoorID; + public final int ItemPersonalDimDoorID; /** * Other IDs @@ -56,6 +62,7 @@ public class DDProperties public final int LimboDimensionID; public final int LimboProviderID; public final int PocketProviderID; + public final int PersonalPocketProviderID; public final int DoorRenderEntityID; public final int MonolithEntityID; @@ -74,6 +81,9 @@ public class DDProperties public final boolean CraftingStableFabricAllowed; public final boolean CraftingGoldenDimensionalDoorAllowed; public final boolean CraftingGoldenDoorAllowed; + public final boolean CraftingDDKeysAllowed; + public final boolean CraftingQuartzDoorAllowed; + public final boolean CraftingPersonalDimDoorAllowed; /** * Loot Flags @@ -87,7 +97,6 @@ public class DDProperties * Other Flags */ - public final boolean WorldRiftGenerationEnabled; public final boolean RiftSpreadEnabled; public final boolean RiftGriefingEnabled; public final boolean RiftsSpawnEndermenEnabled; @@ -96,6 +105,7 @@ public class DDProperties public final boolean LimboReturnsInventoryEnabled; public final boolean DoorRenderingEnabled; public final boolean TNFREAKINGT_Enabled; + public final boolean MonolithTeleportationEnabled; /** @@ -107,7 +117,10 @@ public class DDProperties public final int GatewayGenerationChance; public final int FortressGatewayGenerationChance; public final int MonolithSpawningChance; + public final int WorldThreadDropChance; + public final int LimboEntryRange; public final int LimboReturnRange; + public final int WorldThreadRequirementLevel; public final String CustomSchematicDirectory; @@ -121,7 +134,7 @@ public class DDProperties private final String CATEGORY_DIMENSION = "dimension"; private final String CATEGORY_PROVIDER = "provider"; private final String CATEGORY_BIOME = "biome"; - private final String CATEGORY_LOOT = "loot"; + private final String CATEGORY_LOOT = "loot"; private DDProperties(File configFile) { @@ -143,6 +156,13 @@ public class DDProperties CraftingStableFabricAllowed = config.get(CATEGORY_CRAFTING, "Allow Crafting Stable Fabric", true).getBoolean(true); CraftingGoldenDoorAllowed = config.get(CATEGORY_CRAFTING, "Allow Crafting Golden Door", true).getBoolean(true); CraftingGoldenDimensionalDoorAllowed = config.get(CATEGORY_CRAFTING, "Allow Crafting Golden Dimensional Door", true).getBoolean(true); + CraftingDDKeysAllowed = config.get(CATEGORY_CRAFTING, "Allow Crafting Rift Keys", true).getBoolean(true); + CraftingQuartzDoorAllowed = config.get(CATEGORY_CRAFTING, "Allow Crafting Quartz Doors", true).getBoolean(true); + CraftingPersonalDimDoorAllowed = config.get(CATEGORY_CRAFTING, "Allow Crafting Personal Dim Doors", true).getBoolean(true); + + WorldThreadRequirementLevel = config.get(CATEGORY_CRAFTING, "World Thread Requirement Level", 4, + "Controls the amount of World Thread needed to craft Stable Fabric. The number must be an " + + "integer from 1 to 4. The levels change the recipe to use 1, 2, 4, or 8 threads, respectively. The default level is 4.").getInt(); RiftBladeLootEnabled = config.get(CATEGORY_LOOT, "Enable Rift Blade Loot", true).getBoolean(true); FabricOfRealityLootEnabled = config.get(CATEGORY_LOOT, "Enable Fabric of Reality Loot", true).getBoolean(true); @@ -156,13 +176,15 @@ public class DDProperties "Sets whether groups of connected rifts will spawn Endermen").getBoolean(true); LimboEnabled = config.get(Configuration.CATEGORY_GENERAL, "Enable Limbo", true, - "Sets whether the Limbo dimension is activated").getBoolean(true); + "Sets whether players are teleported to Limbo when they die in any pocket dimension").getBoolean(true); LimboReturnsInventoryEnabled = config.get(Configuration.CATEGORY_GENERAL, "Enable Limbo Returns Inventory", true, "Sets whether players keep their inventories upon dying and respawning in Limbo").getBoolean(true); HardcoreLimboEnabled = config.get(Configuration.CATEGORY_GENERAL, "Enable Hardcore Limbo", false, "Sets whether players that die in Limbo will respawn there").getBoolean(false); + LimboEntryRange = config.get(Configuration.CATEGORY_GENERAL, "Limbo Entry Range", 500, + "Sets the farthest distance that players may be moved at random when sent to Limbo. Must be greater than or equal to 0.").getInt(); LimboReturnRange = config.get(Configuration.CATEGORY_GENERAL, "Limbo Return Range", 500, - "Sets the farthest distance that Limbo can send you upon returning to the Overworld").getInt(); + "Sets the farthest distance that players may be moved at random when sent from Limbo to the Overworld. Must be greater than or equal to 0.").getInt(); DoorRenderingEnabled = config.get(Configuration.CATEGORY_GENERAL, "Enable Door Rendering", true).getBoolean(true); TNFREAKINGT_Enabled = config.get(Configuration.CATEGORY_GENERAL, "EXPLOSIONS!!???!!!?!?!!", false).getBoolean(false); @@ -182,6 +204,8 @@ public class DDProperties TransientDoorID = config.getBlock("Transient Door Block ID", 1979).getInt(); GoldenDoorID = config.getBlock("Gold Door Block ID", 1980).getInt(); GoldenDimensionalDoorID = config.getBlock("Gold Dim Door Block ID", 1981).getInt(); + QuartzDoorID = config.getBlock("Quartz Door Block ID", 1982).getInt(); + PersonalDimDoorID = config.getBlock("Personal Dim Door ID", 1983).getInt(); WarpDoorItemID = config.getItem("Warp Door Item ID", 5670).getInt(); RiftRemoverItemID = config.getItem("Rift Remover Item ID", 5671).getInt(); @@ -194,6 +218,9 @@ public class DDProperties GoldenDoorItemID = config.getItem("Gold Door Item ID", 5678).getInt(); GoldenDimensionalDoorItemID = config.getItem("Gold Dim Door Item ID", 5679).getInt(); WorldThreadItemID = config.getItem("World Thread Item ID", 5680).getInt(); + DDKeyItemID = config.getItem("Rift Key Item ID", 5681).getInt(); + ItemQuartzDoorID = config.getItem("Quartz Door Item ID", 5681).getInt(); + ItemPersonalDimDoorID = config.getItem("Personal Dim Door ID", 5681).getInt(); LimboBlockID = config.getTerrainBlock("World Generation Block IDs - must be less than 256", "Limbo Block ID", 217, "Blocks used for the terrain in Limbo").getInt(); @@ -201,11 +228,12 @@ public class DDProperties "Perma Fabric Block ID", 220, "Blocks used for enclosing pocket dimensions").getInt(); LimboDimensionID = config.get(CATEGORY_DIMENSION, "Limbo Dimension ID", -23).getInt(); - PocketProviderID = config.get(CATEGORY_PROVIDER, "Pocket Provider ID", 24).getInt(); - LimboProviderID = config.get(CATEGORY_PROVIDER, "Limbo Provider ID", 13).getInt(); - - WorldRiftGenerationEnabled = config.get(Configuration.CATEGORY_GENERAL, "Enable Rift World Generation", true, - "Sets whether dungeon rifts generate in dimensions other than Limbo").getBoolean(true); + PocketProviderID = config.get(CATEGORY_PROVIDER, "Pocket Provider ID", 124).getInt(); + LimboProviderID = config.get(CATEGORY_PROVIDER, "Limbo Provider ID", 113).getInt(); + PersonalPocketProviderID = config.get(CATEGORY_PROVIDER, "Personal Pocket Provider ID", 125).getInt(); + + MonolithTeleportationEnabled = config.get(Configuration.CATEGORY_GENERAL, "Enable Monolith Teleportation", true, + "Sets whether Monoliths can teleport players").getBoolean(true); MonolithSpawningChance = config.get(Configuration.CATEGORY_GENERAL, "Monolith Spawning Chance", 28, "Sets the chance (out of " + CustomLimboPopulator.MAX_MONOLITH_SPAWNING_CHANCE + ") that Monoliths will " + @@ -222,15 +250,19 @@ public class DDProperties FortressGatewayGenerationChance = config.get(Configuration.CATEGORY_GENERAL, "Fortress Gateway Generation Chance", 33, "Sets the chance (out of " + DDStructureNetherBridgeStart.MAX_GATEWAY_GENERATION_CHANCE + ") that a Rift Gateway will " + "generate as part of a Nether Fortress. The default chance is 33.").getInt(); + + WorldThreadDropChance = config.get(Configuration.CATEGORY_GENERAL, "World Thread Drop Chance", 50, + "Sets the chance (out of " + BlockRift.MAX_WORLD_THREAD_DROP_CHANCE + ") that a rift will " + + "drop World Thread when it destroys a block. The default chance is 50.").getInt(); - LimboBiomeID = config.get(CATEGORY_BIOME, "Limbo Biome ID", 251).getInt(); - PocketBiomeID = config.get(CATEGORY_BIOME, "Pocket Biome ID", 250).getInt(); + LimboBiomeID = config.get(CATEGORY_BIOME, "Limbo Biome ID", 148).getInt(); + PocketBiomeID = config.get(CATEGORY_BIOME, "Pocket Biome ID", 149).getInt(); config.save(); - //Unfortunately, there are users out there who have been misconfiguring the worldgen blocks to have IDs above 255. - //This leads to disastrous and cryptic errors in other areas of Minecraft. To prevent headaches, we'll throw - //an exception here if the blocks have invalid IDs. + // Unfortunately, there are users out there who have been misconfiguring the worldgen blocks to have IDs above 255. + // This leads to disastrous and cryptic errors in other areas of Minecraft. To prevent headaches, we'll throw + // an exception here if the blocks have invalid IDs. if (LimboBlockID > 255 || PermaFabricBlockID > 255) { throw new IllegalStateException("World generation blocks MUST have block IDs less than 256. Fix your configuration!"); diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/config/DDWorldProperties.java b/src/main/java/StevenDimDoors/mod_pocketDim/config/DDWorldProperties.java new file mode 100644 index 0000000..b2a4569 --- /dev/null +++ b/src/main/java/StevenDimDoors/mod_pocketDim/config/DDWorldProperties.java @@ -0,0 +1,84 @@ +package StevenDimDoors.mod_pocketDim.config; + +import java.io.File; + +import net.minecraftforge.common.Configuration; + +public class DDWorldProperties +{ + /** + * World Generation Settings + */ + public final DimensionFilter RiftClusterDimensions; + public final DimensionFilter RiftGatewayDimensions; + + /** + * General Flags + */ + public final boolean LimboEscapeEnabled; + public final boolean UniversalLimboEnabled; + + //Names of categories + private static final String CATEGORY_WORLD_GENERATION = "world generation"; + + public DDWorldProperties(File configFile) + { + // TODO: For the next major update (e.g. to MC 1.7), please move all world-specific settings + // into this config file instead of using the global ID file. + + Configuration config = new Configuration(configFile); + config.load(); + + config.addCustomCategoryComment(CATEGORY_WORLD_GENERATION, + "The following settings require lists of dimensions in a specific format. " + + "A list must consist of ranges separated by commas. A range may be a single number to indicate " + + "just one dimension or two numbers in the form \"X - Y\". Spaces are permitted " + + "but not required. Example: -100, -10 - -1, 20 - 30"); + + RiftClusterDimensions = loadFilter(config, "Rift Cluster", "Rift Clusters"); + RiftGatewayDimensions = loadFilter(config, "Rift Gateway", "Rift Gateways"); + + LimboEscapeEnabled = config.get(Configuration.CATEGORY_GENERAL, "Enable Limbo Escape", true, + "Sets whether players are teleported out of Limbo when walking over the Eternal Fabric that " + + "generates near the bottom of the dimension. If disabled, players could still leave through " + + "dungeons in Limbo or by dying (if Hardcore Limbo is disabled). The default value is true.").getBoolean(true); + + UniversalLimboEnabled = config.get(Configuration.CATEGORY_GENERAL, "Enable Universal Limbo", false, + "Sets whether players are teleported to Limbo when they die in any dimension (except Limbo). " + + "Normally, players only go to Limbo if they die in a pocket dimension. This setting will not " + + "affect deaths in Limbo, which can be set with the Hardcore Limbo option. " + + "The default value is false.").getBoolean(false); + + config.save(); + } + + private static DimensionFilter loadFilter(Configuration config, String prefix, String description) + { + boolean enableBlacklist = config.get(CATEGORY_WORLD_GENERATION, "Enable " + prefix + " Blacklist", true, + "Sets whether " + description + " will not generate in certain blacklisted dimensions. " + + "If set to false, then " + description + " will follow a whitelist instead.").getBoolean(true); + + String whitelist = config.get(CATEGORY_WORLD_GENERATION, prefix + " Whitelist", "", + "A list of the only dimensions in which " + description + " may generate.").getString(); + + String blacklist = config.get(CATEGORY_WORLD_GENERATION, prefix + " Blacklist", "", + "A list of dimensions in which " + description + " may not generate.").getString(); + + try + { + if (enableBlacklist) + { + return DimensionFilter.parseBlacklist(blacklist); + } + else + { + return DimensionFilter.parseWhitelist(whitelist); + } + } + catch (Exception inner) + { + throw new RuntimeException("An error occurred while loading a whitelist or blacklist setting for " + + description + ". Please make sure that your configuration file is set up correctly.", inner); + } + } +} \ No newline at end of file diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/config/DimensionFilter.java b/src/main/java/StevenDimDoors/mod_pocketDim/config/DimensionFilter.java new file mode 100644 index 0000000..53b8b3e --- /dev/null +++ b/src/main/java/StevenDimDoors/mod_pocketDim/config/DimensionFilter.java @@ -0,0 +1,93 @@ +package StevenDimDoors.mod_pocketDim.config; + +import com.google.common.collect.Range; +import com.google.common.collect.RangeSet; +import com.google.common.collect.TreeRangeSet; + +public class DimensionFilter +{ + private RangeSet blacklist; + + private DimensionFilter(RangeSet blacklist) + { + this.blacklist = blacklist; + } + + public boolean isAccepted(int dimensionID) + { + return !blacklist.contains(dimensionID); + } + + public boolean isRejected(int dimensionID) + { + return blacklist.contains(dimensionID); + } + + private static RangeSet parseRangeSet(String list) + { + int index; + int start; + int end; + String startPart; + String endPart; + String[] intervals; + RangeSet ranges = TreeRangeSet.create(); + + // Strip out all whitespace characters + list = list.replaceAll("\\s", ""); + if (list.isEmpty()) + { + return ranges; + } + intervals = list.split(","); + + // Iterate over all the interval strings + for (String interval : intervals) + { + // Check if the interval contains a minus sign after the first character + // That indicates that we're dealing with an interval and not a single number + if (interval.length() > 1) + { + index = interval.indexOf("-", 1); + } + else + { + index = -1; + } + try + { + if (index >= 0) + { + // Parse this as a range with two values as endpoints + startPart = interval.substring(0, index); + endPart = interval.substring(index + 1); + start = Integer.parseInt(startPart); + end = Integer.parseInt(endPart); + } + else + { + // Parse this as a single value + start = Integer.parseInt(interval); + end = start; + } + // Add the interval to the set of intervals + ranges.add( Range.closed(start, end) ); + } + catch (Exception e) + { + throw new IllegalArgumentException("\"" + interval + "\" is not a valid value or range for dimension IDs"); + } + } + return ranges; + } + + public static DimensionFilter parseWhitelist(String list) + { + return new DimensionFilter(parseRangeSet(list).complement()); + } + + public static DimensionFilter parseBlacklist(String list) + { + return new DimensionFilter(parseRangeSet(list)); + } +} diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/core/DDLock.java b/src/main/java/StevenDimDoors/mod_pocketDim/core/DDLock.java new file mode 100644 index 0000000..5b54904 --- /dev/null +++ b/src/main/java/StevenDimDoors/mod_pocketDim/core/DDLock.java @@ -0,0 +1,169 @@ +package StevenDimDoors.mod_pocketDim.core; + +import java.io.IOException; +import com.google.gson.stream.JsonReader; +import StevenDimDoors.mod_pocketDim.items.ItemDDKey; +import StevenDimDoors.mod_pocketDim.saving.IPackable; +import StevenDimDoors.mod_pocketDim.saving.PackedDimData; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagIntArray; +import net.minecraft.nbt.NBTTagList; + +public class DDLock +{ + private boolean lockState; + private final int lockKey; + + + public DDLock(boolean isLocked, int lockKey) + { + this.lockState = isLocked; + this.lockKey = lockKey; + } + + public int getLockKey() + { + return this.lockKey; + } + /** + * See if the lock is currently locked. False if there is no lock. + * @return + */ + public boolean getLockState() + { + return this.lockState; + } + + /** + * set the state of the lock. Returns false if there is no lock to set, + * otherwise returns true + * @param flag + */ + protected void setLockState(boolean flag) + { + this.lockState = flag; + } + + + /** + * see if we could unlock this door if it where locked. + * @param link + * @param itemStack + * @return + */ + public boolean doesKeyUnlock(ItemStack itemStack) + { + for(int key :getKeys(itemStack)) + { + if(this.lockKey == key) + { + return true; + } + } + return false; + } + + /** + * Tries to open this lock + * @param item + * @return + */ + public boolean tryToOpen(ItemStack itemStack) + { + return (!this.lockState)||this.doesKeyUnlock(itemStack); + } + + /** + * sets the key/s to the given key/s + * @return + * @return + */ + + /** + * gets all the keys stored on a single key item + * @return + */ + public static int[] getKeys(ItemStack itemStack) + { + if (!itemStack.hasTagCompound()) + { + initNBTTags(itemStack); + } + return itemStack.getTagCompound().getIntArray("DDKeys"); + } + + /** + * adds the key/s to the given key + * @return + * @return + */ + public static void addKeys(ItemStack itemStack, int[] keysToAdd) + { + int[] oldKeys = DDLock.getKeys(itemStack); + int[] newKeys = new int[keysToAdd.length+oldKeys.length]; + System.arraycopy(oldKeys, 0, newKeys, 0, oldKeys.length); + System.arraycopy(keysToAdd, 0, newKeys, oldKeys.length, keysToAdd.length); + setKeys(itemStack,newKeys); + } + + + /** + * sets the key/s to the given key/s + * @return + * @return + */ + public static void setKeys(ItemStack itemStack, int[] keys) + { + if (!itemStack.hasTagCompound()) + { + initNBTTags(itemStack); + } + NBTTagCompound tag = itemStack.getTagCompound(); + tag.setIntArray("DDKeys", keys); + itemStack.setTagCompound(tag); + } + + /** + * Gives the key a new NBTTag + * @param itemStack + */ + public static void initNBTTags(ItemStack itemStack) + { + itemStack.setTagCompound(new NBTTagCompound()); + NBTTagCompound tag = itemStack.getTagCompound(); + tag.setIntArray("DDKeys", new int[0]); + tag.setBoolean("HasCreatedLock", false); + itemStack.setTagCompound(tag); + } + + public static boolean hasCreatedLock(ItemStack key) + { + if(isItemKey(key)) + { + if(key.hasTagCompound()) + { + return key.getTagCompound().getBoolean("HasCreatedLock"); + } + initNBTTags(key); + } + return false; + } + + public static boolean isItemKey(ItemStack key) + { + return key.getItem() instanceof ItemDDKey; + } + + + + protected static DDLock generateLockKeyPair(ItemStack itemStack, int lockKey2) + { + itemStack.getTagCompound().setBoolean("HasCreatedLock", true); + DDLock.setKeys(itemStack, new int[]{lockKey2}); + return new DDLock(true, lockKey2); + + + } + +} diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/core/DDTeleporter.java b/src/main/java/StevenDimDoors/mod_pocketDim/core/DDTeleporter.java index e4e9c7a..3096f35 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/core/DDTeleporter.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/core/DDTeleporter.java @@ -2,15 +2,14 @@ package StevenDimDoors.mod_pocketDim.core; import java.util.ArrayList; import java.util.Random; - import net.minecraft.block.Block; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityList; import net.minecraft.entity.item.EntityMinecart; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.item.ItemDoor; import net.minecraft.nbt.NBTTagCompound; -import net.minecraft.network.packet.Packet250CustomPayload; import net.minecraft.network.packet.Packet41EntityEffect; import net.minecraft.network.packet.Packet43Experience; import net.minecraft.network.packet.Packet9Respawn; @@ -20,15 +19,12 @@ import net.minecraft.util.MathHelper; import net.minecraft.world.World; import net.minecraft.world.WorldServer; import net.minecraftforge.common.DimensionManager; -import net.minecraftforge.common.network.ForgePacket; -import net.minecraftforge.common.network.packet.DimensionRegisterPacket; -import StevenDimDoors.mod_pocketDim.DDProperties; import StevenDimDoors.mod_pocketDim.Point3D; import StevenDimDoors.mod_pocketDim.mod_pocketDim; import StevenDimDoors.mod_pocketDim.blocks.BaseDimDoor; +import StevenDimDoors.mod_pocketDim.blocks.IDimDoor; +import StevenDimDoors.mod_pocketDim.config.DDProperties; import StevenDimDoors.mod_pocketDim.helpers.yCoordHelper; -import StevenDimDoors.mod_pocketDim.items.BaseItemDoor; -import StevenDimDoors.mod_pocketDim.items.ItemDimensionalDoor; import StevenDimDoors.mod_pocketDim.schematic.BlockRotator; import StevenDimDoors.mod_pocketDim.tileentities.TileEntityDimDoor; import StevenDimDoors.mod_pocketDim.util.Point4D; @@ -40,70 +36,64 @@ public class DDTeleporter { private static final Random random = new Random(); private static final int NETHER_DIMENSION_ID = -1; + private static final int OVERWORLD_DIMENSION_ID = 0; private static final int END_DIMENSION_ID = 1; private static final int MAX_NETHER_EXIT_CHANCE = 100; private static final int NETHER_EXIT_CHANCE = 20; //20% chance to compensate for frequent exit failures - the Nether often doesn't have enough space for an exit + private static final int MAX_OVERWORLD_EXIT_CHANCE = 100; + private static final int OVERWORLD_EXIT_CHANCE = 15; private static final int MAX_ROOT_SHIFT_CHANCE = 100; private static final int START_ROOT_SHIFT_CHANCE = 0; private static final int ROOT_SHIFT_CHANCE_PER_LEVEL = 5; + private static final String SPIRIT_WORLD_NAME = "Spirit World"; public static int cooldown = 0; private DDTeleporter() { } - /**Checks if the destination supplied is valid, ie, filled by any non-replaceable block. - * - * @param entity - * @param world - * @param destination - * @param properties - * @return + /** + * Checks if the destination supplied is safe (i.e. filled by any replaceable or non-opaque blocks) */ - private static boolean checkDestination(Entity entity, WorldServer world, Point4D destination,DDProperties properties) + private static boolean checkDestination(WorldServer world, Point4D destination, int orientation) { int x = destination.getX(); int y = destination.getY(); int z = destination.getZ(); int blockIDTop; - int blockIDBottom; - + int blockIDBottom; Point3D point; - - int orientation; - orientation = getDestinationOrientation(destination, properties); - entity.rotationYaw = (orientation * 90) + 90; switch (orientation) { case 0: - point = new Point3D(MathHelper.floor_double(x - 0.5), y - 1, MathHelper.floor_double(z + 0.5)); + point = new Point3D(x - 1, y - 1, z); break; case 1: - point = new Point3D(MathHelper.floor_double(x + 0.5), y - 1, MathHelper.floor_double(z - 0.5)); + point = new Point3D(x, y - 1, z - 1); break; case 2: - point = new Point3D(MathHelper.floor_double(x + 1.5), y - 1, MathHelper.floor_double(z + 0.5)); + point = new Point3D(x + 1, y - 1, z); break; case 3: - point = new Point3D(MathHelper.floor_double(x + 0.5), y - 1, MathHelper.floor_double(z + 1.5)); + point = new Point3D(x, y - 1, z + 1); break; default: point = new Point3D(x, y - 1, z); break; } blockIDBottom = world.getBlockId(point.getX(), point.getY(), point.getZ()); - blockIDTop = world.getBlockId(point.getX(), point.getY()+1, point.getZ()); + blockIDTop = world.getBlockId(point.getX(), point.getY() + 1, point.getZ()); if (Block.blocksList[blockIDBottom] != null) { - if(!Block.blocksList[blockIDBottom].isBlockReplaceable(world, point.getX(), point.getY(), point.getZ())&&world.isBlockOpaqueCube(point.getX(), point.getY(), point.getZ())) + if (!Block.blocksList[blockIDBottom].isBlockReplaceable(world, point.getX(), point.getY(), point.getZ()) && world.isBlockOpaqueCube(point.getX(), point.getY(), point.getZ())) { return false; } } if (Block.blocksList[blockIDTop] != null) { - if (!Block.blocksList[blockIDTop].isBlockReplaceable(world, point.getX(), point.getY()+1, point.getZ())) + if (!Block.blocksList[blockIDTop].isBlockReplaceable(world, point.getX(), point.getY() + 1, point.getZ())) { return false; } @@ -125,56 +115,37 @@ public class DDTeleporter } else { - //Teleport the entity to the precise destination point + // Teleport the entity to the precise destination point orientation = -1; } - if (!checkDestination(entity, world, destination, properties)) - { - if (entity instanceof EntityPlayerMP) - { - EntityPlayer player = (EntityPlayer) entity; - player.rotationYaw = (orientation * 90) + 90; - switch (orientation) - { - case 0: - player.setPositionAndUpdate(x + 0.5, y - 1, z + 0.5); - break; - case 1: - player.setPositionAndUpdate(x + 0.5, y - 1, z + 0.5); - break; - case 2: - player.setPositionAndUpdate(x + 0.5, y - 1, z + 0.5); - break; - case 3: - player.setPositionAndUpdate(x + 0.5, y - 1, z + 0.5); - break; - default: - player.setPositionAndUpdate(x, y - 1, z); - break; - } - } - } - else if (entity instanceof EntityPlayer) + if (entity instanceof EntityPlayer) { EntityPlayer player = (EntityPlayer) entity; - switch (orientation) + if (checkDestination(world, destination, orientation)) { - case 0: - player.setPositionAndUpdate(x - 0.5, y - 1, z + 0.5); - break; - case 1: - player.setPositionAndUpdate(x + 0.5, y - 1, z - 0.5); - break; - case 2: - player.setPositionAndUpdate(x + 1.5, y - 1, z + 0.5); - break; - case 3: - player.setPositionAndUpdate(x + 0.5, y - 1, z + 1.5); - break; - default: - player.setPositionAndUpdate(x + 0.5, y - 1, z + 0.5); - break; + switch (orientation) + { + case 0: + player.setPositionAndUpdate(x - 0.5, y - 1, z + 0.5); + break; + case 1: + player.setPositionAndUpdate(x + 0.5, y - 1, z - 0.5); + break; + case 2: + player.setPositionAndUpdate(x + 1.5, y - 1, z + 0.5); + break; + case 3: + player.setPositionAndUpdate(x + 0.5, y - 1, z + 1.5); + break; + default: + player.setPositionAndUpdate(x + 0.5, y - 1, z + 0.5); + break; + } + } + else + { + player.setPositionAndUpdate(x + 0.5, y - 1, z + 0.5); } } else if (entity instanceof EntityMinecart) @@ -200,7 +171,7 @@ public class DDTeleporter entity.worldObj.updateEntityWithOptionalForce(entity, false); break; case 3: - DDTeleporter.setEntityPosition(entity, x + 0.5, y, z + 1.5 ); + DDTeleporter.setEntityPosition(entity, x + 0.5, y, z + 1.5); entity.motionZ = 0.39; entity.worldObj.updateEntityWithOptionalForce(entity, false); break; @@ -250,15 +221,14 @@ public class DDTeleporter } //Check if the block below that point is actually a door - int blockID = world.getBlockId(door.getX(), door.getY() - 1, door.getZ()); - if (blockID != properties.DimensionalDoorID && blockID != properties.WarpDoorID && - blockID != properties.TransientDoorID && blockID != properties.UnstableDoorID - && blockID != properties.GoldenDimensionalDoorID) + Block block = Block.blocksList[world.getBlockId(door.getX(), door.getY() - 1, door.getZ())]; + if (block==null || !(block instanceof IDimDoor)) { //Return the pocket's orientation instead - return PocketManager.getDimensionData(door.getDimension()).orientation(); + return PocketManager.createDimensionData(world).orientation(); } + //Return the orientation portion of its metadata return world.getBlockMetadata(door.getX(), door.getY() - 1, door.getZ()) & 3; } @@ -323,7 +293,7 @@ public class DDTeleporter // to prevent us from doing bad things. Moreover, no dimension is being created, so if we ever // tie code to that, it could cause confusing bugs. // No hacky for you! ~SenseiKiwi - PocketManager.getDimwatcher().onCreated(new ClientDimData(PocketManager.getDimensionData(destination.getDimension()))); + PocketManager.getDimwatcher().onCreated(new ClientDimData(PocketManager.createDimensionData(newWorld))); // Set the new dimension and inform the client that it's moving to a new world. player.dimension = destination.getDimension(); @@ -457,11 +427,11 @@ public class DDTeleporter return; } - if (!initializeDestination(link, DDProperties.instance(),door)) + if (!initializeDestination(link, DDProperties.instance(),entity,door)) { return; } - if (link.linkType() == LinkTypes.RANDOM) + if (link.linkType() == LinkType.RANDOM) { Point4D randomDestination = getRandomDestination(); if (randomDestination != null) @@ -470,21 +440,46 @@ public class DDTeleporter entity.worldObj.playSoundEffect(entity.posX, entity.posY, entity.posZ, "mob.endermen.portal", 1.0F, 1.0F); } } - else + else { buildExitDoor(door, link, DDProperties.instance()); - entity = teleportEntity(entity, link.destination(), link.linkType() != LinkTypes.UNSAFE_EXIT); + entity = teleportEntity(entity, link.destination(), link.linkType() != LinkType.UNSAFE_EXIT); entity.worldObj.playSoundEffect(entity.posX, entity.posY, entity.posZ, "mob.endermen.portal", 1.0F, 1.0F); } } - private static boolean initializeDestination(DimLink link, DDProperties properties, Block door) + private static boolean initializeDestination(DimLink link, DDProperties properties, Entity entity, Block door) { - if (link.hasDestination()) + if (link.hasDestination()&&link.linkType()!=LinkType.PERSONAL) { - if(PocketManager.isBlackListed(link.destination().getDimension())) + if (PocketManager.isBlackListed(link.destination().getDimension())) { - link=PocketManager.getDimensionData(link.source().getDimension()).createLink(link.link.point,LinkTypes.SAFE_EXIT,link.link.orientation); + + // This link leads to a dimension that has been blacklisted. + // That means that it was a pocket and it was deleted. + // Depending on the link type, we must overwrite it or cancel + // the teleport operation. We don't need to assign 'link' with + // a different value. NewDimData will overwrite it in-place. + NewDimData start = PocketManager.getDimensionData(link.source().getDimension()); + if (link.linkType() == LinkType.DUNGEON) + { + // Ovewrite the link into a dungeon link with no destination + start.createLink(link.source(), LinkType.DUNGEON, link.orientation(), null); + } + else + { + if (start.isPocketDimension()) + { + // Ovewrite the link into a safe exit link, because + // this could be the only way out from a pocket. + start.createLink(link.source(), LinkType.SAFE_EXIT, link.orientation(), null); + } + else + { + // Cancel the teleport attempt + return false; + } + } } else { @@ -495,24 +490,49 @@ public class DDTeleporter // Check the destination type and respond accordingly switch (link.linkType()) { - case LinkTypes.DUNGEON: + case DUNGEON: return PocketBuilder.generateNewDungeonPocket(link, properties); - case LinkTypes.POCKET: - return PocketBuilder.generateNewPocket(link, properties,door); - case LinkTypes.SAFE_EXIT: + case POCKET: + return PocketBuilder.generateNewPocket(link, properties, door, DimensionType.POCKET); + case PERSONAL: + return setupPersonalLink(link, properties, entity, door); + case SAFE_EXIT: return generateSafeExit(link, properties); - case LinkTypes.DUNGEON_EXIT: + case DUNGEON_EXIT: return generateDungeonExit(link, properties); - case LinkTypes.UNSAFE_EXIT: + case UNSAFE_EXIT: return generateUnsafeExit(link); - case LinkTypes.NORMAL: - case LinkTypes.REVERSE: - case LinkTypes.RANDOM: + case NORMAL: + case REVERSE: + case RANDOM: return true; default: throw new IllegalArgumentException("link has an unrecognized link type."); } } + + private static boolean setupPersonalLink(DimLink link, DDProperties properties,Entity player, Block door) + { + if(!(player instanceof EntityPlayer)) + { + return false; + } + + NewDimData dim = PocketManager.getPersonalDimensionForPlayer(player.getEntityName()); + if(dim == null) + { + return PocketBuilder.generateNewPersonalPocket(link, properties, player, door); + } + + DimLink personalHomeLink = dim.getLink(dim.origin()); + if(personalHomeLink!=null) + { + PocketManager.getDimensionData(link.source().getDimension()).setLinkDestination(personalHomeLink, link.source().getX(), link.source().getY(), link.source().getZ()); + } + + dim.setLinkDestination(link, dim.origin.getX(), dim.origin.getY(), dim.origin.getZ()); + return true; + } private static Point4D getRandomDestination() { @@ -531,7 +551,7 @@ public class DDTeleporter { for (DimLink link : dimension.getAllLinks()) { - if (link.linkType() != LinkTypes.RANDOM) + if (link.linkType() != LinkType.RANDOM) { matches.add(link.source()); } @@ -543,10 +563,7 @@ public class DDTeleporter { return matches.get( random.nextInt(matches.size()) ); } - else - { - return null; - } + return null; } private static boolean generateUnsafeExit(DimLink link) @@ -560,7 +577,8 @@ public class DDTeleporter // To avoid loops, don't generate a destination if the player is // already in a non-pocket dimension. - NewDimData current = PocketManager.getDimensionData(link.link.point.getDimension()); + NewDimData current = PocketManager.getDimensionData(link.point.getDimension()); + if (current.isPocketDimension()) { Point4D source = link.source(); @@ -573,7 +591,7 @@ public class DDTeleporter Point3D destination = yCoordHelper.findDropPoint(world, source.getX(), source.getY() + 1, source.getZ()); if (destination != null) { - current.root().setDestination(link, destination.getX(), destination.getY(), destination.getZ()); + current.root().setLinkDestination(link, destination.getX(), destination.getY(), destination.getZ()); return true; } } @@ -584,7 +602,7 @@ public class DDTeleporter { World startWorld = PocketManager.loadDimension(link.source().getDimension()); World destWorld = PocketManager.loadDimension(link.destination().getDimension()); - TileEntity doorTE = startWorld.getBlockTileEntity(link.source().getX(), link.source().getY(), link.link.point.getZ()); + TileEntity doorTE = startWorld.getBlockTileEntity(link.source().getX(), link.source().getY(), link.point.getZ()); if(doorTE instanceof TileEntityDimDoor) { if((TileEntityDimDoor.class.cast(doorTE).hasGennedPair)) @@ -602,7 +620,7 @@ public class DDTeleporter } } - BaseItemDoor.placeDoorBlock(destWorld, link.destination().getX(), link.destination().getY()-1, link.destination().getZ(),link.getDestinationOrientation(), door); + ItemDoor.placeDoorBlock(destWorld, link.destination().getX(), link.destination().getY()-1, link.destination().getZ(),link.getDestinationOrientation(), door); TileEntity doorDestTE = ((BaseDimDoor)door).initDoorTE(destWorld, link.destination().getX(), link.destination().getY(), link.destination().getZ()); @@ -614,9 +632,10 @@ public class DDTeleporter } } } + private static boolean generateSafeExit(DimLink link, DDProperties properties) { - NewDimData current = PocketManager.getDimensionData(link.link.point.getDimension()); + NewDimData current = PocketManager.getDimensionData(link.point.getDimension()); return generateSafeExit(current.root(), link, properties); } @@ -627,22 +646,25 @@ public class DDTeleporter // There is a chance of choosing the Nether first before other root dimensions // to compensate for servers with many Mystcraft ages or other worlds. - NewDimData current = PocketManager.getDimensionData(link.link.point.getDimension()); + NewDimData current = PocketManager.getDimensionData(link.point.getDimension()); + ArrayList roots = PocketManager.getRootDimensions(); int shiftChance = START_ROOT_SHIFT_CHANCE + ROOT_SHIFT_CHANCE_PER_LEVEL * (current.packDepth() - 1); if (random.nextInt(MAX_ROOT_SHIFT_CHANCE) < shiftChance) { - if (random.nextInt(MAX_NETHER_EXIT_CHANCE) < NETHER_EXIT_CHANCE) + if (current.root().id() != OVERWORLD_DIMENSION_ID && random.nextInt(MAX_OVERWORLD_EXIT_CHANCE) < OVERWORLD_EXIT_CHANCE) { - return generateSafeExit(PocketManager.getDimensionData(NETHER_DIMENSION_ID), link, properties); + return generateSafeExit(PocketManager.createDimensionDataDangerously(OVERWORLD_DIMENSION_ID), link, properties); + } + if (current.root().id() != NETHER_DIMENSION_ID && random.nextInt(MAX_NETHER_EXIT_CHANCE) < NETHER_EXIT_CHANCE) + { + return generateSafeExit(PocketManager.createDimensionDataDangerously(NETHER_DIMENSION_ID), link, properties); } for (int attempts = 0; attempts < 10; attempts++) { NewDimData selection = roots.get( random.nextInt(roots.size()) ); - if (selection.id() != END_DIMENSION_ID && - selection.id() != properties.LimboDimensionID && - selection != current.root()) + if (selection != current.root() && isValidForDungeonExit(selection, properties)) { return generateSafeExit(selection, link, properties); } @@ -653,6 +675,19 @@ public class DDTeleporter return generateSafeExit(current.root(), link, properties); } + private static boolean isValidForDungeonExit(NewDimData destination, DDProperties properties) + { + // Prevent exits to The End and Limbo + if (destination.id() == END_DIMENSION_ID || destination.id() == properties.LimboDimensionID) + { + return false; + } + // Prevent exits to Witchery's Spirit World; we need to load the dimension to retrieve its name. + // This is okay because the dimension would have to be loaded subsequently by generateSafeExit(). + World world = PocketManager.loadDimension(destination.id()); + return (world != null && !SPIRIT_WORLD_NAME.equals(world.provider.getDimensionName())); + } + private static boolean generateSafeExit(NewDimData destinationDim, DimLink link, DDProperties properties) { // A safe exit attempts to place a Warp Door in a dimension with @@ -728,16 +763,17 @@ public class DDTeleporter // Create a reverse link for returning int orientation = getDestinationOrientation(source, properties); NewDimData sourceDim = PocketManager.getDimensionData(link.source().getDimension()); - DimLink reverse = destinationDim.createLink(x, y + 2, z, LinkTypes.REVERSE,orientation); - sourceDim.setDestination(reverse, source.getX(), source.getY(), source.getZ()); + DimLink reverse = destinationDim.createLink(x, y + 2, z, LinkType.REVERSE,orientation); + + sourceDim.setLinkDestination(reverse, source.getX(), source.getY(), source.getZ()); // Set up the warp door at the destination orientation = BlockRotator.transformMetadata(orientation, 2, properties.WarpDoorID); - ItemDimensionalDoor.placeDoorBlock(world, x, y + 1, z, orientation, mod_pocketDim.warpDoor); + ItemDoor.placeDoorBlock(world, x, y + 1, z, orientation, mod_pocketDim.warpDoor); // Complete the link to the destination // This comes last so the destination isn't set unless everything else works first - destinationDim.setDestination(link, x, y + 2, z); + destinationDim.setLinkDestination(link, x, y + 2, z); } return (destination != null); diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/core/DimLink.java b/src/main/java/StevenDimDoors/mod_pocketDim/core/DimLink.java index 8ee3d9a..bed50a6 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/core/DimLink.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/core/DimLink.java @@ -2,73 +2,99 @@ package StevenDimDoors.mod_pocketDim.core; import java.util.LinkedList; import java.util.List; - +import net.minecraft.item.ItemStack; +import net.minecraft.world.ChunkCoordIntPair; import StevenDimDoors.mod_pocketDim.util.Point4D; -import StevenDimDoors.mod_pocketDim.watcher.ClientLinkData; public abstract class DimLink { - protected ClientLinkData link; + protected Point4D point; + protected int orientation; + protected DDLock lock; protected DimLink parent; protected LinkTail tail; protected List children; - protected DimLink(ClientLinkData link, DimLink parent) + protected DimLink(Point4D point, int orientation, DDLock lock, DimLink parent) { - if (parent.link.point.getDimension() != link.point.getDimension()) + if (parent.point.getDimension() != point.getDimension()) { // Ban having children in other dimensions to avoid serialization issues with cross-dimensional tails throw new IllegalArgumentException("source and parent.source must have the same dimension."); } + this.lock = lock; this.parent = parent; - this.link = link; + this.point = point; this.tail = parent.tail; + this.orientation = orientation; this.children = new LinkedList(); parent.children.add(this); } - protected DimLink(ClientLinkData link, int linkType) + protected DimLink(Point4D point, int orientation, DDLock lock, LinkType linkType) { + /**This really cant happen anymore, I guess. + * if ((linkType < LinkTypes.ENUM_MIN || linkType > LinkTypes.ENUM_MAX) && linkType != LinkTypes.CLIENT_SIDE) { throw new IllegalArgumentException("The specified link type is invalid."); } - + **/ + + this.lock = lock; this.parent = null; - this.link = link; + this.point = point; + this.orientation = orientation; this.tail = new LinkTail(linkType, null); this.children = new LinkedList(); } public Point4D source() { - return link.point; + return point; } + public void clear() + { + //Release children + for (DimLink child : children) + { + child.parent = null; + } + children.clear(); + + //Release parent + if (parent != null) + { + parent.children.remove(this); + } + + parent = null; + point = null; + tail = new LinkTail(LinkType.NORMAL, null); + } + public int orientation() { - return link.orientation; - } - - public ClientLinkData link() - { - return link; + return orientation; } public Point4D destination() { return tail.getDestination(); } + 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 (orientation + 2) % 4; } + public boolean hasDestination() { return (tail.getDestination() != null); @@ -89,13 +115,65 @@ public abstract class DimLink return parent; } - public int linkType() + public LinkType linkType() { return tail.getLinkType(); } + + + /** + * Tries to open this lock. Returns true if the lock is open or if the key can open it + * @return + */ + public boolean tryToOpen(ItemStack item) + { + return lock.tryToOpen(item); + } + + /** + * Tests if the given key item fits this lock + * @return + */ + public boolean doesKeyUnlock(ItemStack item) + { + return lock.doesKeyUnlock(item); + } + /** + * test if there is a lock, regardless if it is locked or not. + * @return + */ + public boolean hasLock() + { + return this.lock!=null; + } + + /** + * Tests if the lock is open or not + * + */ + public boolean getLockState() + { + return this.hasLock()&&this.lock.getLockState(); + } + + /** + * gets the actual lock object + * @return + */ + public DDLock getLock() + { + return this.lock; + } + + public ChunkCoordIntPair getChunkCoordinates() + { + return new ChunkCoordIntPair(point.getX() >> 4, point.getZ() >> 4); + } + + @Override public String toString() { - return link.point + " -> " + (hasDestination() ? destination() : ""); + return point + " -> " + (hasDestination() ? destination() : "()"); } } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/core/DimensionType.java b/src/main/java/StevenDimDoors/mod_pocketDim/core/DimensionType.java new file mode 100644 index 0000000..c7ba296 --- /dev/null +++ b/src/main/java/StevenDimDoors/mod_pocketDim/core/DimensionType.java @@ -0,0 +1,41 @@ +package StevenDimDoors.mod_pocketDim.core; + +public enum DimensionType +{ + // WARNING: Don't modify these values carelessly or you'll risk breaking existing worlds! + ROOT(0,false), + POCKET(1,true), + DUNGEON(2,true), + PERSONAL(3,true); + + DimensionType(int index, boolean isPocket) + { + this.index = index; + this.isPocket = isPocket; + } + + public final int index; + public final boolean isPocket; + + /** + * Get the DimensionType given an index. I feel like there should be a better way to do this. + * @param index + * @return + */ + public static DimensionType getTypeFromIndex(int index) + { + for(DimensionType type : DimensionType.values()) + { + if(type.index == index) + { + return type; + } + } + return null; + } + + public boolean isPocketDimension() + { + return this.isPocket; + } +} diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/core/IDimRegistrationCallback.java b/src/main/java/StevenDimDoors/mod_pocketDim/core/IDimRegistrationCallback.java index 04a0c38..f233096 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/core/IDimRegistrationCallback.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/core/IDimRegistrationCallback.java @@ -2,5 +2,5 @@ package StevenDimDoors.mod_pocketDim.core; public interface IDimRegistrationCallback { - public NewDimData registerDimension(int dimensionID, int rootID); + public NewDimData registerDimension(int dimensionID, int rootID, DimensionType type); } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/core/LinkTail.java b/src/main/java/StevenDimDoors/mod_pocketDim/core/LinkTail.java index 887f97e..d4a95c6 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/core/LinkTail.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/core/LinkTail.java @@ -5,9 +5,9 @@ import StevenDimDoors.mod_pocketDim.util.Point4D; class LinkTail { private Point4D destination; - private int linkType; + private LinkType linkType; - public LinkTail(int linkType, Point4D destination) + public LinkTail(LinkType linkType, Point4D destination) { this.linkType = linkType; this.destination = destination; @@ -21,12 +21,11 @@ class LinkTail this.destination = destination; } - public int getLinkType() { + public LinkType getLinkType() { return linkType; } - public void setLinkType(int linkType) { + public void setLinkType(LinkType linkType) { this.linkType = linkType; } - } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/core/LinkType.java b/src/main/java/StevenDimDoors/mod_pocketDim/core/LinkType.java new file mode 100644 index 0000000..2f0311f --- /dev/null +++ b/src/main/java/StevenDimDoors/mod_pocketDim/core/LinkType.java @@ -0,0 +1,42 @@ +package StevenDimDoors.mod_pocketDim.core; + +import java.util.HashMap; + +public enum LinkType +{ + // WARNING: Don't modify these values carelessly or you'll risk breaking links in existing worlds! + NORMAL(0), + POCKET(1), + DUNGEON(2), + RANDOM(3), + DUNGEON_EXIT(4), + SAFE_EXIT(5), + UNSAFE_EXIT(6), + REVERSE(7), + PERSONAL(8), + CLIENT(-1337); + + LinkType(int index) + { + this.index = index; + } + + public final int index; + + /** + * Get the LinkType given an index. I feel like there should be a better way to do this. + * @param index + * @return + */ + public static LinkType getLinkTypeFromIndex(int index) + { + for(LinkType type : LinkType.values()) + { + if(type.index == index) + { + return type; + } + } + return null; + } +} diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/core/LinkTypes.java b/src/main/java/StevenDimDoors/mod_pocketDim/core/LinkTypes.java deleted file mode 100644 index f7424b5..0000000 --- a/src/main/java/StevenDimDoors/mod_pocketDim/core/LinkTypes.java +++ /dev/null @@ -1,21 +0,0 @@ -package StevenDimDoors.mod_pocketDim.core; - -public class LinkTypes -{ - private LinkTypes() { } - - public static final int ENUM_MIN = 0; - public static final int ENUM_MAX = 7; - - public static final int CLIENT_SIDE = -1337; - - // WARNING: Don't modify these values carelessly or you'll risk breaking links in existing worlds! - public static final int NORMAL = 0; - public static final int POCKET = 1; - public static final int DUNGEON = 2; - public static final int RANDOM = 3; - public static final int DUNGEON_EXIT = 4; - public static final int SAFE_EXIT = 5; - public static final int UNSAFE_EXIT = 6; - public static final int REVERSE = 7; -} diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/core/NewDimData.java b/src/main/java/StevenDimDoors/mod_pocketDim/core/NewDimData.java index 46158a8..f0b646e 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/core/NewDimData.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/core/NewDimData.java @@ -1,33 +1,42 @@ 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.item.ItemStack; +import net.minecraft.world.ChunkCoordIntPair; import net.minecraft.world.World; -import StevenDimDoors.mod_pocketDim.DDProperties; 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.saving.IPackable; +import StevenDimDoors.mod_pocketDim.saving.PackedDimData; +import StevenDimDoors.mod_pocketDim.saving.PackedDungeonData; +import StevenDimDoors.mod_pocketDim.saving.PackedLinkData; +import StevenDimDoors.mod_pocketDim.saving.PackedLinkTail; import StevenDimDoors.mod_pocketDim.util.Point4D; +import StevenDimDoors.mod_pocketDim.watcher.ClientLinkData; import StevenDimDoors.mod_pocketDim.watcher.IUpdateWatcher; -@SuppressWarnings("deprecation") -public abstract class NewDimData +public abstract class NewDimData implements IPackable { private static class InnerDimLink extends DimLink { - public InnerDimLink(Point4D source, DimLink parent,int orientation) + public InnerDimLink(Point4D source, DimLink parent, int orientation, DDLock lock) { - super(new ClientLinkData(source, orientation), parent); + super(source, orientation, lock, parent); } - public InnerDimLink(Point4D source, int linkType, int orientation) + public InnerDimLink(Point4D source, LinkType linkType, int orientation, DDLock lock) { - super(new ClientLinkData(source, orientation), linkType); + super(source, orientation, lock, linkType); } public void setDestination(int x, int y, int z, NewDimData dimension) @@ -35,26 +44,6 @@ public abstract class NewDimData tail.setDestination(new Point4D(x, y, z, dimension.id())); } - public void clear() - { - //Release children - for (DimLink child : children) - { - ((InnerDimLink) child).parent = null; - } - children.clear(); - - //Release parent - if (parent != null) - { - parent.children.remove(this); - } - - parent = null; - link = null; - tail = new LinkTail(0, null); - } - public boolean overwrite(InnerDimLink nextParent,int orientation) { if (nextParent == null) @@ -66,7 +55,7 @@ public abstract class NewDimData //Ignore this request silently return false; } - if (nextParent.link.point.getDimension() != link.point.getDimension()) + if (nextParent.point.getDimension() != point.getDimension()) { // Ban having children in other dimensions to avoid serialization issues with cross-dimensional tails throw new IllegalArgumentException("source and parent.source must have the same dimension."); @@ -89,11 +78,11 @@ public abstract class NewDimData parent = nextParent; tail = nextParent.tail; nextParent.children.add(this); - this.link.orientation=orientation; + this.orientation=orientation; return true; } - public void overwrite(int linkType, int orientation) + public void overwrite(LinkType linkType, int orientation) { //Release children for (DimLink child : children) @@ -112,39 +101,73 @@ public abstract class NewDimData parent = null; tail = new LinkTail(linkType, null); //Set new orientation - this.link.orientation=orientation; + this.orientation=orientation; } + + /** + * only use this on the client to update errything + * @param lock + */ + public void setLock(DDLock lock) + { + this.lock = lock; + } + + /** + * create a lock from a key. Returns false if this door already has a lock, or if they has already locked a door + * @param itemStack + * @return + */ + public boolean createLock(ItemStack itemStack, int lockKey) + { + if(this.hasLock()||DDLock.hasCreatedLock(itemStack)) + { + return false; + } + this.lock = DDLock.generateLockKeyPair(itemStack, lockKey); + return true; + } + + public void removeLock(ItemStack itemStack, InnerDimLink link) + { + if(link.doesKeyUnlock(itemStack)) + { + link.lock = null; + } + } + } + + private static int EXPECTED_LINKS_PER_CHUNK = 2; protected static Random random = new Random(); protected int id; protected Map linkMapping; protected List linkList; - protected boolean isDungeon; protected boolean isFilled; protected int depth; protected int packDepth; + protected DimensionType type; protected NewDimData parent; protected NewDimData root; protected List children; protected Point4D origin; protected int orientation; protected DungeonData dungeon; + protected boolean modified; public IUpdateWatcher linkWatcher; - protected NewDimData(int id, NewDimData parent, boolean isPocket, boolean isDungeon, - 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, DimensionType type, IUpdateWatcher linkWatcher) { - // The isPocket flag is redundant. It's meant as an integrity safeguard. - if (isPocket && (parent == null)) + if (type != DimensionType.ROOT && (parent == null)) { throw new NullPointerException("Dimensions can be pocket dimensions if and only if they have a parent dimension."); } - if (isDungeon && !isPocket) - { - throw new IllegalArgumentException("A dimensional dungeon must also be a pocket dimension."); - } this.id = id; this.linkMapping = new TreeMap(); //Should be stored in oct tree -- temporary solution @@ -152,12 +175,14 @@ public abstract class NewDimData this.children = new ArrayList(); this.parent = parent; this.packDepth = 0; - this.isDungeon = isDungeon; + this.type = type; this.isFilled = false; this.orientation = 0; this.origin = null; this.dungeon = null; this.linkWatcher = linkWatcher; + this.chunkMapping = new HashMap>(); + this.modified = true; //Register with parent if (parent != null) @@ -166,6 +191,7 @@ public abstract class NewDimData this.root = parent.root; this.depth = parent.depth + 1; parent.children.add(this); + parent.modified = true; } else { @@ -174,7 +200,7 @@ public abstract class NewDimData } } - protected NewDimData(int id, NewDimData root) + protected NewDimData(int id, NewDimData root, DimensionType type) { // This constructor is meant for client-side code only if (root == null) @@ -188,7 +214,7 @@ public abstract class NewDimData this.children = new ArrayList(); this.parent = null; this.packDepth = 0; - this.isDungeon = false; + this.type = type; this.isFilled = false; this.orientation = 0; this.origin = null; @@ -196,28 +222,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++) @@ -229,7 +253,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; @@ -245,24 +269,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++) @@ -272,7 +292,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); @@ -289,66 +309,98 @@ public abstract class NewDimData { return Math.abs(i) + Math.abs(j) + Math.abs(k); } - public DimLink createLink(int x, int y, int z, int linkType,int orientation) + + public DimLink createLink(int x, int y, int z, LinkType linkType, int orientation) { - return createLink(new Point4D(x, y, z, id), linkType,orientation); + return createLink(new Point4D(x, y, z, id), linkType, orientation, null); } - public DimLink createLink(Point4D source, int linkType,int orientation) + public DimLink createLink(Point4D source, LinkType linkType, int orientation, DDLock locked) { - //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); + link = new InnerDimLink(source, linkType, orientation, locked); linkMapping.put(source, link); linkList.add(link); + + // If this code is running on the server side, add this link to chunkMapping. + if (linkType != LinkType.CLIENT) + { + 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 { - link.overwrite(linkType,orientation); + link.overwrite(linkType, orientation); } + modified = true; + //Link created! - if(linkType!=LinkTypes.CLIENT_SIDE) + if (linkType != LinkType.CLIENT) + { - linkWatcher.onCreated(link.link); + linkWatcher.onCreated(new ClientLinkData(link)); } return link; } public DimLink createChildLink(int x, int y, int z, DimLink parent) { + return createChildLink(new Point4D(x, y, z, id), (InnerDimLink) parent, null); + } + + public DimLink createChildLink(Point4D source, DimLink parent, DDLock locked) + { + // 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. + if (parent == null) { throw new IllegalArgumentException("parent cannot be null."); } - - return createChildLink(new Point4D(x, y, z, id), (InnerDimLink) parent); - } - - 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. - InnerDimLink link = linkMapping.get(source); if (link == null) { - link = new InnerDimLink(source, parent, parent.link.orientation); + link = new InnerDimLink(source, parent, parent.orientation, locked); linkMapping.put(source, link); linkList.add(link); - //Link created! - linkWatcher.onCreated(link.link); + + // 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() != LinkType.CLIENT) + { + 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(new ClientLinkData(link)); } else { - if (link.overwrite(parent, parent.link.orientation)) + if (link.overwrite((InnerDimLink) parent, parent.orientation)) { //Link created! - linkWatcher.onCreated(link.link); + linkWatcher.onCreated(new ClientLinkData(link)); } } + modified = true; return link; } @@ -362,16 +414,32 @@ public abstract class NewDimData if (target != null) { linkList.remove(target); - //Raise deletion event - linkWatcher.onDeleted(target.link); + + // If this code is running on the server side, remove this link to chunkMapping. + if (link.linkType() != LinkType.CLIENT) + { + ChunkCoordIntPair chunk = target.getChunkCoordinates(); + List chunkLinks = chunkMapping.get(chunk); + if (chunkLinks != null) + { + chunkLinks.remove(target); + } + } + + // Raise deletion event + linkWatcher.onDeleted(new ClientLinkData(link)); target.clear(); + modified = true; } return (target != null); } public boolean deleteLink(int x, int y, int z) { - Point4D location = new Point4D(x, y, z, id); + return this.deleteLink(this.getLink(x, y, z)); + } + public boolean deleteLink(Point4D location) + { return this.deleteLink(this.getLink(location)); } @@ -383,7 +451,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) @@ -406,11 +474,10 @@ public abstract class NewDimData return (root != this); } - public boolean isDungeon() + public DimensionType type() { - return isDungeon; + return this.type; } - public boolean isFilled() { return isFilled; @@ -419,6 +486,7 @@ public abstract class NewDimData public void setFilled(boolean isFilled) { this.isFilled = isFilled; + this.modified = true; } public int id() @@ -483,7 +551,7 @@ public abstract class NewDimData public void initializeDungeon(int originX, int originY, int originZ, int orientation, DimLink incoming, DungeonData dungeon) { - if (!isDungeon) + if (this.type != DimensionType.DUNGEON) { throw new IllegalStateException("Cannot invoke initializeDungeon() on a non-dungeon dimension."); } @@ -495,21 +563,55 @@ public abstract class NewDimData { throw new IllegalArgumentException("orientation must be between 0 and 3, inclusive."); } - setDestination(incoming, originX, originY, originZ); + setLinkDestination(incoming, originX, originY, originZ); this.origin = incoming.destination(); this.orientation = orientation; this.dungeon = dungeon; this.packDepth = calculatePackDepth(parent, dungeon); + this.modified = true; } /** - * effectivly moves the dungeon to the 'top' of a chain as far as dungeon generation is concerend. + * Effectively moves the dungeon to the 'top' of a chain as far as dungeon generation is concerned. */ public void setParentToRoot() { - this.depth=1; - this.parent=this.root; + // Update this dimension's information + if (parent != null) + { + parent.children.remove(this); + } + this.depth = 1; + this.parent = this.root; this.root.children.add(this); + this.root.modified = true; + this.modified = true; + if (this.type == DimensionType.DUNGEON) + { + this.packDepth = calculatePackDepth(this.parent, this.dungeon); + } + + // Update the depths for child dimensions using a depth-first traversal + Stack ordering = new Stack(); + ordering.addAll(this.children); + + while (!ordering.isEmpty()) + { + NewDimData current = ordering.pop(); + current.resetDepth(); + ordering.addAll(current.children); + } + } + + private void resetDepth() + { + // We assume that this is only applied to dimensions with parents + this.depth = this.parent.depth + 1; + if (this.type == DimensionType.DUNGEON) + { + this.packDepth = calculatePackDepth(this.parent, this.dungeon); + } + this.modified = true; } public static int calculatePackDepth(NewDimData parent, DungeonData current) @@ -538,10 +640,7 @@ public abstract class NewDimData { return parent.packDepth + 1; } - else - { - return 1; - } + return 1; } public void initializePocket(int originX, int originY, int originZ, int orientation, DimLink incoming) @@ -555,15 +654,45 @@ public abstract class NewDimData throw new IllegalStateException("The dimension has already been initialized."); } - setDestination(incoming, originX, originY, originZ); + setLinkDestination(incoming, originX, originY, originZ); this.origin = incoming.destination(); this.orientation = orientation; + this.modified = true; } - public void setDestination(DimLink incoming, int x, int y, int z) + public void setLinkDestination(DimLink incoming, int x, int y, int z) { InnerDimLink link = (InnerDimLink) incoming; link.setDestination(x, y, z, this); + this.modified = true; + } + + public void lock(DimLink link, boolean locked) + { + InnerDimLink innerLink = (InnerDimLink)link; + innerLink.lock.setLockState(locked); + modified = true; + } + + public void setLock(DimLink link, DDLock lock) + { + InnerDimLink innerLink = (InnerDimLink)link; + innerLink.setLock(lock); + modified = true; + } + + public void createLock(DimLink link, ItemStack item, int lockKey) + { + InnerDimLink innerLink = (InnerDimLink)link; + innerLink.createLock(item, lockKey); + modified = true; + } + + public void removeLock(DimLink link, ItemStack item) + { + InnerDimLink innerLink = (InnerDimLink)link; + innerLink.removeLock(item, innerLink); + modified = true; } public DimLink getRandomLink() @@ -576,14 +705,126 @@ public abstract class NewDimData { return linkList.get(random.nextInt(linkList.size())); } - else - { - return linkList.get(0); - } + 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; + } + + public void clearModified() + { + this.modified = false; + } + + public void clear() + { + // If this dimension has a parent, remove it from its parent's list of children + if (parent != null) + { + parent.children.remove(this); + } + // Remove this dimension as the parent of its children + for (NewDimData child : children) + { + child.parent = null; + } + // Clear all fields + id = Integer.MIN_VALUE; + linkMapping.clear(); + linkMapping = null; + linkList.clear(); + linkList = null; + children.clear(); + children = null; + type = null; + isFilled = false; + depth = Integer.MIN_VALUE; + packDepth = Integer.MIN_VALUE; + origin = null; + orientation = Integer.MIN_VALUE; + dungeon = null; + linkWatcher = null; + } + + public PackedDimData pack() + { + ArrayList ChildIDs = new ArrayList(); + ArrayList Links = new ArrayList(); + ArrayList Tails = new ArrayList(); + PackedDungeonData packedDungeon=null; + + if(this.dungeon!=null) + { + packedDungeon= new PackedDungeonData(dungeon.weight(), dungeon.isOpen(), dungeon.isInternal(), + dungeon.schematicPath(), dungeon.schematicName(), dungeon.dungeonType().Name, + dungeon.dungeonType().Owner.getName()); + } + //Make a list of children + for(NewDimData data : this.children) + { + ChildIDs.add(data.id); + } + for(DimLink link:this.links()) + { + ArrayList children = new ArrayList(); + Point3D parentPoint = new Point3D(-1,-1,-1); + if(link.parent!=null) + { + parentPoint=link.parent.point.toPoint3D(); + } + + for(DimLink childLink : link.children) + { + children.add(childLink.source().toPoint3D()); + } + PackedLinkTail tail = new PackedLinkTail(link.tail.getDestination(),link.tail.getLinkType()); + Links.add(new PackedLinkData(link.point,parentPoint,tail,link.orientation,children,link.lock)); + + PackedLinkTail tempTail = new PackedLinkTail(link.tail.getDestination(),link.tail.getLinkType()); + if(Tails.contains(tempTail)) + { + Tails.add(tempTail); + } + + + } + int parentID=this.id; + Point3D originPoint=new Point3D(0,0,0); + if(this.parent!=null) + { + parentID = this.parent.id; + } + if(this.origin!=null) + { + originPoint=this.origin.toPoint3D(); + } + return new PackedDimData(this.id, depth, this.packDepth, parentID, this.root().id(), orientation, + type, isFilled,packedDungeon, originPoint, ChildIDs, Links, Tails); + // FIXME: IMPLEMENTATION PLZTHX + //I tried + } + + @Override + public String name() + { + return String.valueOf(id); + } + + @Override public String toString() { - return "DimID= "+this.id; + return "DimID= " + this.id; } } \ No newline at end of file diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/core/PocketManager.java b/src/main/java/StevenDimDoors/mod_pocketDim/core/PocketManager.java index 29fbf75..209c2fc 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/core/PocketManager.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/core/PocketManager.java @@ -7,181 +7,94 @@ import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; - -import cpw.mods.fml.common.FMLCommonHandler; -import cpw.mods.fml.relauncher.Side; -import cpw.mods.fml.relauncher.SideOnly; - +import net.minecraft.entity.player.EntityPlayer; import net.minecraft.world.World; import net.minecraft.world.WorldServer; import net.minecraftforge.common.DimensionManager; -import StevenDimDoors.mod_pocketDim.DDProperties; -import StevenDimDoors.mod_pocketDim.Point3D; import StevenDimDoors.mod_pocketDim.mod_pocketDim; +import StevenDimDoors.mod_pocketDim.config.DDProperties; import StevenDimDoors.mod_pocketDim.helpers.Compactor; import StevenDimDoors.mod_pocketDim.helpers.DeleteFolder; import StevenDimDoors.mod_pocketDim.saving.DDSaveHandler; -import StevenDimDoors.mod_pocketDim.saving.IPackable; import StevenDimDoors.mod_pocketDim.saving.OldSaveImporter; import StevenDimDoors.mod_pocketDim.saving.PackedDimData; -import StevenDimDoors.mod_pocketDim.saving.PackedDungeonData; -import StevenDimDoors.mod_pocketDim.saving.PackedLinkData; -import StevenDimDoors.mod_pocketDim.saving.PackedLinkTail; import StevenDimDoors.mod_pocketDim.util.Point4D; import StevenDimDoors.mod_pocketDim.watcher.ClientDimData; import StevenDimDoors.mod_pocketDim.watcher.ClientLinkData; import StevenDimDoors.mod_pocketDim.watcher.IUpdateSource; import StevenDimDoors.mod_pocketDim.watcher.IUpdateWatcher; import StevenDimDoors.mod_pocketDim.watcher.UpdateWatcherProxy; +import cpw.mods.fml.common.FMLCommonHandler; +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; /** - * This class regulates all the operations involving the storage and manipulation of dimensions. - * It handles saving dim data, teleporting the player, and creating/registering new dimensions as - * well as loading old dimensions on startup + * This class regulates all the operations involving the storage and + * manipulation of dimensions. It handles saving dim data, teleporting the + * player, and creating/registering new dimensions as well as loading old + * dimensions on startup */ public class PocketManager -{ - private static class InnerDimData extends NewDimData implements IPackable +{ + private static class InnerDimData extends NewDimData { - // This class allows us to instantiate NewDimData indirectly without exposing - // a public constructor from NewDimData. It's meant to stop us from constructing - // instances of NewDimData going through PocketManager. In turn, that enforces - // that any link destinations must be real dimensions controlled by PocketManager. + // This class allows us to instantiate NewDimData indirectly without + // exposing + // a public constructor from NewDimData. It's meant to stop us from + // constructing + // instances of NewDimData going through PocketManager. In turn, that + // enforces + // that any link destinations must be real dimensions controlled by + // PocketManager. - public InnerDimData(int id, InnerDimData parent, boolean isPocket, boolean isDungeon, - IUpdateWatcher linkWatcher) + public InnerDimData(int id, InnerDimData parent, DimensionType type, IUpdateWatcher linkWatcher) { - super(id, parent, isPocket, isDungeon, linkWatcher); + super(id, parent, type, linkWatcher); } - - public InnerDimData(int id, InnerDimData root) + + public InnerDimData(int id, NewDimData root, DimensionType type) { // This constructor is meant for client-side code only - super(id, root); + super(id, root, type); } - - public void clear() + + } + + private static class ClientLinkWatcher implements IUpdateWatcher + { + @Override + public void onCreated(ClientLinkData link) { - // If this dimension has a parent, remove it from its parent's list of children - if (parent != null) - { - parent.children.remove(this); - } - // Remove this dimension as the parent of its children - for (NewDimData child : children) - { - child.parent = null; - } - // Clear all fields - id = Integer.MIN_VALUE; - linkMapping.clear(); - linkMapping = null; - linkList.clear(); - linkList = null; - children.clear(); - children = null; - isDungeon = false; - isFilled = false; - depth = Integer.MIN_VALUE; - packDepth = Integer.MIN_VALUE; - origin = null; - orientation = Integer.MIN_VALUE; - dungeon = null; - linkWatcher = null; + Point4D source = link.point; + NewDimData dimension = getDimensionData(source.getDimension()); + dimension.createLink(source, LinkType.CLIENT, 0, link.lock); } @Override - public String name() + public void onDeleted(ClientLinkData link) { - return String.valueOf(id); + Point4D source = link.point; + NewDimData dimension = getDimensionData(source.getDimension()); + dimension.deleteLink(source.getX(), source.getY(), source.getZ()); } @Override - public PackedDimData pack() + public void update(ClientLinkData link) { - ArrayList ChildIDs = new ArrayList(); - ArrayList Links = new ArrayList(); - ArrayList Tails = new ArrayList(); - PackedDungeonData packedDungeon=null; - - if(this.dungeon!=null) - { - packedDungeon= new PackedDungeonData(dungeon.weight(), dungeon.isOpen(), dungeon.isInternal(), - dungeon.schematicPath(), dungeon.schematicName(), dungeon.dungeonType().Name, - dungeon.dungeonType().Owner.getName()); - } - //Make a list of children - for(NewDimData data : this.children) - { - ChildIDs.add(data.id); - } - for(DimLink link:this.links()) - { - ArrayList children = new ArrayList(); - Point3D parentPoint = new Point3D(-1,-1,-1); - if(link.parent!=null) - { - parentPoint=link.parent.link.point.toPoint3D(); - } - - for(DimLink childLink : link.children) - { - children.add(childLink.source().toPoint3D()); - } - PackedLinkTail tail = new PackedLinkTail(link.tail.getDestination(),link.tail.getLinkType()); - Links.add(new PackedLinkData(link.link.point,parentPoint,tail,link.link.orientation,children)); - - PackedLinkTail tempTail = new PackedLinkTail(link.tail.getDestination(),link.tail.getLinkType()); - if(Tails.contains(tempTail)) - { - Tails.add(tempTail); + Point4D source = link.point; + NewDimData dimension = getDimensionData(source.getDimension()); + DimLink dLink = dimension.getLink(source); + dLink.lock = link.lock; - } - - - } - int parentID=this.id; - Point3D originPoint=new Point3D(0,0,0); - if(this.parent!=null) - { - parentID = this.parent.id; - } - if(this.origin!=null) - { - originPoint=this.origin.toPoint3D(); - } - return new PackedDimData(this.id, depth, this.packDepth, parentID, this.root().id(), orientation, - isDungeon, isFilled,packedDungeon, originPoint, ChildIDs, Links, Tails); - // FIXME: IMPLEMENTATION PLZTHX - //I tried } } - - private static class ClientLinkWatcher implements IUpdateWatcher - { - @Override - public void onCreated(ClientLinkData link) - { - Point4D source = link.point; - NewDimData dimension = getDimensionData(source.getDimension()); - dimension.createLink(source.getX(), source.getY(), source.getZ(), LinkTypes.CLIENT_SIDE,link.orientation); - } - @Override - public void onDeleted(ClientLinkData link) - { - Point4D source = link.point; - NewDimData dimension = getDimensionData(source.getDimension()); - dimension.deleteLink(source.getX(), source.getY(), source.getZ()); - } - } - private static class ClientDimWatcher implements IUpdateWatcher { @Override public void onCreated(ClientDimData data) { - registerClientDimension(data.ID, data.RootID); + registerClientDimension(data.ID, data.rootID, data.type); } @Override @@ -189,22 +102,31 @@ public class PocketManager { deletePocket(getDimensionData(data.ID), false); } + + @Override + public void update(ClientDimData message) + { + // TODO Auto-generated method stub + } } private static class DimRegistrationCallback implements IDimRegistrationCallback { - // We use this class to provide Compactor with the ability to send us dim data without - // having to instantiate a bunch of data containers and without exposing an "unsafe" - // creation method for anyone to call. Integrity protection for the win! It's like + // We use this class to provide Compactor with the ability to send us + // dim data without + // having to instantiate a bunch of data containers and without exposing + // an "unsafe" + // creation method for anyone to call. Integrity protection for the win! + // It's like // exposing a private constructor ONLY to a very specific trusted class. - + @Override - public NewDimData registerDimension(int dimensionID, int rootID) + public NewDimData registerDimension(int dimensionID, int rootID, DimensionType type) { - return registerClientDimension(dimensionID, rootID); + return registerClientDimension(dimensionID, rootID, type); } } - + private static int OVERWORLD_DIMENSION_ID = 0; private static volatile boolean isLoading = false; @@ -218,18 +140,25 @@ public class PocketManager private static final UpdateWatcherProxy dimWatcher = new UpdateWatcherProxy(); private static ArrayList rootDimensions = null; - //HashMap that maps all the dimension IDs registered with DimDoors to their DD data. + // HashMap that maps all the dimension IDs registered with DimDoors to their + // DD data. private static HashMap dimensionData = null; - //ArrayList that stores the dimension IDs of any dimension that has been deleted. + // ArrayList that stores the dimension IDs of any dimension that has been + // deleted. private static ArrayList dimensionIDBlackList = null; + // Stores all the personal pocket mappings + private static HashMap personalPocketsMapping = null; + public static boolean isLoaded() { return isLoaded; } /** - * simple method called on startup to register all dims saved in the dim list. Only tries to register pocket dims, though. Also calls load() + * simple method called on startup to register all dims saved in the dim + * list. Only tries to register pocket dims, though. Also calls load() + * * @return */ public static void load() @@ -243,59 +172,65 @@ public class PocketManager return; } isLoading = true; - + dimensionData = new HashMap(); rootDimensions = new ArrayList(); dimensionIDBlackList = new ArrayList(); - - if(FMLCommonHandler.instance().getEffectiveSide().isClient()) + personalPocketsMapping = new HashMap(); + + if (FMLCommonHandler.instance().getEffectiveSide().isClient()) { - //Shouldnt try to load everything if we are a client - //This was preventing onPacket from loading properly - isLoading=false; - isLoaded=true; + // Shouldnt try to load everything if we are a client + // This was preventing onPacket from loading properly + isLoading = false; + isLoaded = true; return; } - //Register Limbo + // Register Limbo DDProperties properties = DDProperties.instance(); - registerDimension(properties.LimboDimensionID, null, false, false); - + registerDimension(properties.LimboDimensionID, null, DimensionType.ROOT); + loadInternal(); - - //Register pocket dimensions + + // Register pocket dimensions registerPockets(properties); - + isLoaded = true; isLoading = false; } - + public static boolean registerPackedDimData(PackedDimData packedData) { - InnerDimData dimData; - //register roots - if(packedData.ID==packedData.ParentID) + DimensionType type = DimensionType.getTypeFromIndex(packedData.DimensionType); + if (type == null) { - dimData = new InnerDimData(packedData.ID, null, false, false, linkWatcher); - dimData.root=dimData; - dimData.parent=dimData; - dimData.depth=packedData.Depth; - dimData.isFilled=packedData.IsFilled; - dimData.origin = new Point4D(packedData.Origin.getX(),packedData.Origin.getY(),packedData.Origin.getZ(),packedData.ID); + throw new IllegalArgumentException("Invalid dimension type"); + } + // register roots + if (packedData.ID == packedData.ParentID) + { + dimData = new InnerDimData(packedData.ID, null, type, linkWatcher); + dimData.root = dimData; + dimData.parent = dimData; + dimData.depth = packedData.Depth; + dimData.isFilled = packedData.IsFilled; + dimData.origin = new Point4D(packedData.Origin.getX(), packedData.Origin.getY(), packedData.Origin.getZ(), packedData.ID); PocketManager.rootDimensions.add(dimData); } - else //register children + else + // register children { InnerDimData test = PocketManager.dimensionData.get(packedData.ParentID); - dimData = new InnerDimData(packedData.ID, test,true, packedData.IsDungeon, linkWatcher); - dimData.isFilled=packedData.IsFilled; - dimData.origin = new Point4D(packedData.Origin.getX(),packedData.Origin.getY(),packedData.Origin.getZ(),packedData.ID); - dimData.root=PocketManager.getDimensionData(packedData.RootID); - - if(packedData.DungeonData!=null) + dimData = new InnerDimData(packedData.ID, test, type, linkWatcher); + dimData.isFilled = packedData.IsFilled; + dimData.origin = new Point4D(packedData.Origin.getX(), packedData.Origin.getY(), packedData.Origin.getZ(), packedData.ID); + dimData.root = PocketManager.createDimensionData(packedData.RootID); + + if (packedData.DungeonData != null) { - dimData.dungeon=DDSaveHandler.unpackDungeonData(packedData.DungeonData); + dimData.dungeon = DDSaveHandler.unpackDungeonData(packedData.DungeonData); } } @@ -304,51 +239,63 @@ public class PocketManager return true; } + public static boolean deletePocket(NewDimData target, boolean deleteFolder) { - // We can't delete the dimension if it's currently loaded or if it's not actually a pocket. - // We cast to InnerDimData so that if anyone tries to be a smartass and create their + // We can't delete the dimension if it's currently loaded or if it's not + // actually a pocket. + // We cast to InnerDimData so that if anyone tries to be a smartass and + // create their // own version of NewDimData, this will throw an exception. InnerDimData dimension = (InnerDimData) target; if (dimension.isPocketDimension() && DimensionManager.getWorld(dimension.id()) == null) { if (deleteFolder) { - deleteDimensionFolder(target); + deleteDimensionFiles(dimension); } + // Note: We INTENTIONALLY don't unregister the dimensions that we + // delete with Forge. Instead, we keep them registered to stop Forge + // from reallocating those IDs to other mods such as Mystcraft. This + // is to prevent bugs. Blacklisted dimensions are still properly + // unregistered when the server shuts down. dimensionIDBlackList.add(dimension.id); - deleteDimensionData(dimension.id); + deleteDimensionData(dimension); return true; } return false; } - private static boolean deleteDimensionFolder(NewDimData target) - { - InnerDimData dimension = (InnerDimData) target; - if (dimension.isPocketDimension() && DimensionManager.getWorld(dimension.id()) == null) - { - File saveDirectory = new File(DimensionManager.getCurrentSaveRootDirectory() + "/DimensionalDoors/pocketDimID" + dimension.id()); - DeleteFolder.deleteFolder(saveDirectory); - return true; - } - return false; - } - private static boolean deleteDimensionData(int dimensionID) - { - if(dimensionData.containsKey(dimensionID)&& DimensionManager.getWorld(dimensionID) == null) - { - NewDimData target = PocketManager.getDimensionData(dimensionID); - InnerDimData dimension = (InnerDimData) target; - dimensionData.remove(dimensionID); + private static void deleteDimensionFiles(InnerDimData dimension) + { + // We assume that the caller checks if the dimension is loaded, for the + // sake of efficiency. Don't call this on a loaded dimension or bad + // things will happen! + String saveRootPath = DimensionManager.getCurrentSaveRootDirectory().getAbsolutePath(); + File saveDirectory = new File(saveRootPath + "/DimensionalDoors/pocketDimID" + dimension.id()); + DeleteFolder.deleteFolder(saveDirectory); + File dataFile = new File(saveRootPath + "/DimensionalDoors/data/dim_" + dimension.id() + ".txt"); + dataFile.delete(); + } + + private static void deleteDimensionData(InnerDimData dimension) + { + // We assume that the caller checks if the dimension is loaded, for the + // sake of efficiency. Don't call this on a loaded dimension or bad + // things will happen! + if (dimensionData.remove(dimension.id()) != null) + { // Raise the dim deleted event getDimwatcher().onDeleted(new ClientDimData(dimension)); dimension.clear(); - return true; } - return false; + else + { + // This should never happen. A simple sanity check. + throw new IllegalArgumentException("The specified dimension is not listed with PocketManager."); + } } - + private static void registerPockets(DDProperties properties) { for (NewDimData dimension : dimensionData.values()) @@ -357,11 +304,19 @@ public class PocketManager { try { - DimensionManager.registerDimension(dimension.id(), properties.PocketProviderID); + if (personalPocketsMapping.containsValue(dimension)) + { + DimensionManager.registerDimension(dimension.id(), properties.PersonalPocketProviderID); + } + else + { + DimensionManager.registerDimension(dimension.id(), properties.PocketProviderID); + } } catch (Exception e) { - System.err.println("Could not register pocket dimension #" + dimension.id() + ". Probably caused by a version update/save data corruption/other mods."); + System.err.println("Could not register pocket dimension #" + dimension.id() + + ". Probably caused by a version update/save data corruption/other mods."); e.printStackTrace(); } } @@ -383,9 +338,9 @@ public class PocketManager System.err.println("An unexpected error occurred while unregistering pocket dimension #" + dimension.id() + ":"); e.printStackTrace(); } - } + } } - for(Integer dimID : dimensionIDBlackList) + for (Integer dimID : dimensionIDBlackList) { try { @@ -400,37 +355,37 @@ public class PocketManager } /** - * loads the dim data from the saved hashMap. Also handles compatibility with old saves, see OldSaveHandler + * loads the dim data from the saved hashMap. Also handles compatibility + * with old saves, see OldSaveHandler */ private static void loadInternal() - { - //System.out.println(!FMLCommonHandler.instance().getSide().isClient()); - + { File saveDir = DimensionManager.getCurrentSaveRootDirectory(); if (saveDir != null) { - //Try to import data from old DD versions - //TODO - remove this code in a few versions - File oldSaveData = new File(saveDir+"/DimensionalDoorsData"); - if(oldSaveData.exists()) + // Try to import data from old DD versions + // TODO - remove this code in a few versions + File oldSaveData = new File(saveDir + "/DimensionalDoorsData"); + if (oldSaveData.exists()) { try { System.out.println("Importing old DD save data..."); OldSaveImporter.importOldSave(oldSaveData); - oldSaveData.delete(); + + oldSaveData.renameTo(new File(oldSaveData.getAbsolutePath() + "_IMPORTED")); System.out.println("Import Succesful!"); } catch (Exception e) { - //TODO handle fail cases + // TODO handle fail cases System.out.println("Import failed!"); e.printStackTrace(); } return; } - + // Load save data System.out.println("Loading Dimensional Doors save data..."); if (DDSaveHandler.loadAll()) @@ -439,28 +394,23 @@ public class PocketManager } } } - - public static void save() + + public static void save(boolean checkModified) { if (!isLoaded) { return; } - World world = DimensionManager.getWorld(OVERWORLD_DIMENSION_ID); - if (world == null || world.isRemote || DimensionManager.getCurrentSaveRootDirectory() == null) - { - return; - } - //Check this last to make sure we set the flag shortly after. + // Check this last to make sure we set the flag shortly after. if (isSaving) { return; } isSaving = true; - + try { - DDSaveHandler.saveAll(dimensionData.values(), dimensionIDBlackList); + DDSaveHandler.saveAll(dimensionData.values(), dimensionIDBlackList, checkModified); } catch (Exception e) { @@ -474,9 +424,14 @@ public class PocketManager isSaving = false; } } - + public static WorldServer loadDimension(int id) { + if (!DimensionManager.isDimensionRegistered(id)) + { + return null; + } + WorldServer world = DimensionManager.getWorld(id); if (world == null) { @@ -493,61 +448,104 @@ public class PocketManager public static NewDimData registerDimension(World world) { - return registerDimension(world.provider.dimensionId, null, false, false); + return registerDimension(world.provider.dimensionId, null, DimensionType.ROOT); } - public static NewDimData registerPocket(NewDimData parent, boolean isDungeon) + /** + * method to register a new pocket with DD and with forge. + * + * @param parent + * @param type + * @param playername + * @return + */ + public static NewDimData registerPocket(NewDimData parent, DimensionType type, String playername) { if (parent == null) { throw new IllegalArgumentException("parent cannot be null. A pocket dimension must always have a parent dimension."); } - + DDProperties properties = DDProperties.instance(); int dimensionID = DimensionManager.getNextFreeDimId(); - DimensionManager.registerDimension(dimensionID, properties.PocketProviderID); - return registerDimension(dimensionID, (InnerDimData) parent, true, isDungeon); + + // register a personal pocket + if (type == DimensionType.PERSONAL) + { + if (playername == null) + { + throw new IllegalArgumentException("A personal pocket must be attached to a playername"); + } + DimensionManager.registerDimension(dimensionID, properties.PersonalPocketProviderID); + NewDimData data = registerDimension(dimensionID, (InnerDimData) parent, type); + personalPocketsMapping.put(playername, data); + return data; + } + else + { // register a pocket as personal if its parents are personal, but + // without a mapping. + if (parent.type == DimensionType.PERSONAL) + { + DimensionManager.registerDimension(dimensionID, properties.PersonalPocketProviderID); + NewDimData data = registerDimension(dimensionID, (InnerDimData) parent, DimensionType.PERSONAL); + return data; + } + + // register a standard pocket + DimensionManager.registerDimension(dimensionID, properties.PocketProviderID); + return registerDimension(dimensionID, (InnerDimData) parent, type); + } + } + + public static NewDimData registerPocket(NewDimData parent, DimensionType type) + { + return registerPocket(parent, type, null); + } + /** * Registers a dimension with DD but NOT with forge. + * * @param dimensionID * @param parent * @param isPocket * @param isDungeon * @return */ - private static NewDimData registerDimension(int dimensionID, InnerDimData parent, boolean isPocket, boolean isDungeon) - { + private static NewDimData registerDimension(int dimensionID, InnerDimData parent, DimensionType type) + { if (dimensionData.containsKey(dimensionID)) { - if(PocketManager.dimensionIDBlackList.contains(dimensionID)) + if (PocketManager.dimensionIDBlackList.contains(dimensionID)) { throw new IllegalArgumentException("Cannot register a dimension with ID = " + dimensionID + " because it has been blacklisted."); } throw new IllegalArgumentException("Cannot register a dimension with ID = " + dimensionID + " because it has already been registered."); } - InnerDimData dimension = new InnerDimData(dimensionID, parent, isPocket, isDungeon, linkWatcher); + InnerDimData dimension = new InnerDimData(dimensionID, parent, type, linkWatcher); dimensionData.put(dimensionID, dimension); if (!dimension.isPocketDimension()) { rootDimensions.add(dimension); } getDimwatcher().onCreated(new ClientDimData(dimension)); - + return dimension; } - - @SideOnly(Side.CLIENT) - private static NewDimData registerClientDimension(int dimensionID, int rootID) - { - System.out.println("Registered dim "+dimensionID+" on the client."); - // No need to raise events heres since this code should only run on the client side - // getDimensionData() always handles root dimensions properly, even if the weren't defined before - // SenseiKiwi: I'm a little worried about how getDimensionData will raise + @SideOnly(Side.CLIENT) + private static NewDimData registerClientDimension(int dimensionID, int rootID, DimensionType type) + + { + // No need to raise events heres since this code should only run on the + // client side. createDimensionData() always handles root dimensions + // properly, even if they weren't defined before. + + // SenseiKiwi: I'm a little worried about how createDimensionData will + // raise // an event when it creates any root dimensions... Needs checking later. - - InnerDimData root = (InnerDimData) getDimensionData(rootID); + + InnerDimData root = (InnerDimData) createDimensionData(rootID); InnerDimData dimension; if (rootID != dimensionID) @@ -555,7 +553,7 @@ public class PocketManager dimension = dimensionData.get(dimensionID); if (dimension == null) { - dimension = new InnerDimData(dimensionID, root); + dimension = new InnerDimData(dimensionID, root, type); dimensionData.put(dimension.id(), dimension); } } @@ -563,41 +561,58 @@ public class PocketManager { dimension = root; } - if(dimension.isPocketDimension()&&!DimensionManager.isDimensionRegistered(dimension.id())) + if (dimension.isPocketDimension() && !DimensionManager.isDimensionRegistered(dimension.id())) { - //Im registering pocket dims here. I *think* we can assume that if its a pocket and we are - //registering its dim data, we also need to register it with forge. - - //New packet stuff prevents this from always being true, unfortuantly. I send the dimdata to the client when they teleport. - //Steven + // Im registering pocket dims here. I *think* we can assume that if + // its a pocket and we are + // registering its dim data, we also need to register it with forge. + + // New packet stuff prevents this from always being true, + // unfortuantly. I send the dimdata to the client when they + // teleport. + // Steven DimensionManager.registerDimension(dimensionID, mod_pocketDim.properties.PocketProviderID); } - return dimension; - } - - public static NewDimData getDimensionData(World world) - { - return getDimensionData(world.provider.dimensionId); + return dimension; } public static NewDimData getDimensionData(int dimensionID) { - //Retrieve the data for a dimension. If we don't have a record for that dimension, - //assume it's a non-pocket dimension that hasn't been initialized with us before - //and create a NewDimData instance for it. - //Any pocket dimension must be listed with PocketManager to have a dimension ID - //assigned, so it's safe to assume that any unknown dimensions don't belong to us. - - //FIXME: What's the point of this condition? Most calls to this function will crash anyway! ~SenseiKiwi - if(PocketManager.dimensionData == null) - { - System.out.println("Something odd happend during shutdown"); - return null; - } + return PocketManager.dimensionData.get(dimensionID); + } + + public static NewDimData getDimensionData(World dimension) + { + return PocketManager.dimensionData.get(dimension.provider.dimensionId); + } + + public static NewDimData createDimensionData(World world) + { + return createDimensionData(world.provider.dimensionId); + } + + public static NewDimData createDimensionDataDangerously(int dimensionID) + { + // Same as createDimensionData(int), but public. Meant to discourage + // anyone from + // using it unless absolutely needed! We'll probably phase this out + // eventually. + return createDimensionData(dimensionID); + } + + protected static NewDimData createDimensionData(int dimensionID) + { + // Retrieve the data for a dimension. If we don't have a record for that + // dimension, + // assume it's a non-pocket dimension that hasn't been initialized with + // us before + // and create a NewDimData instance for it. NewDimData dimension = PocketManager.dimensionData.get(dimensionID); + + // if we do not have a record of it, then it must be a root if (dimension == null) { - dimension = registerDimension(dimensionID, null, false, false); + dimension = registerDimension(dimensionID, null, DimensionType.ROOT); } return dimension; } @@ -621,14 +636,14 @@ public class PocketManager throw new IllegalStateException("Pocket dimensions have already been unloaded!"); } - save(); unregisterPockets(); dimensionData = null; + personalPocketsMapping = null; rootDimensions = null; isLoaded = false; isConnected = false; } - + public static DimLink getLink(int x, int y, int z, World world) { return getLink(x, y, z, world.provider.dimensionId); @@ -638,7 +653,7 @@ public class PocketManager { return getLink(point.getX(), point.getY(), point.getZ(), point.getDimension()); } - + public static DimLink getLink(int x, int y, int z, int dimensionID) { NewDimData dimension = dimensionData.get(dimensionID); @@ -646,30 +661,29 @@ public class PocketManager { return dimension.getLink(x, y, z); } - else - { - return null; - } + return null; } - + public static boolean isBlackListed(int dimensionID) { return PocketManager.dimensionIDBlackList.contains(dimensionID); } + public static void registerDimWatcher(IUpdateWatcher watcher) { getDimwatcher().registerReceiver(watcher); } + public static boolean unregisterDimWatcher(IUpdateWatcher watcher) { return getDimwatcher().unregisterReceiver(watcher); } - + public static void registerLinkWatcher(IUpdateWatcher watcher) { linkWatcher.registerReceiver(watcher); } - + public static boolean unregisterLinkWatcher(IUpdateWatcher watcher) { return linkWatcher.unregisterReceiver(watcher); @@ -679,33 +693,35 @@ public class PocketManager { updateSource.registerWatchers(new ClientDimWatcher(), new ClientLinkWatcher()); } - + public static void writePacket(DataOutputStream output) throws IOException { - // Write a very compact description of our dimensions and links to be sent to a client + // Write a very compact description of our dimensions and links to be + // sent to a client Compactor.write(dimensionData.values(), output); } - + public static boolean isRegisteredInternally(int dimensionID) { return dimensionData.containsKey(dimensionID); } - + public static void createAndRegisterBlacklist(List blacklist) { - //TODO - create a special blacklist provider - for(Integer dimID : blacklist) + // TODO - create a special blacklist provider + for (Integer dimID : blacklist) { PocketManager.dimensionIDBlackList.add(dimID); DimensionManager.registerDimension(dimID, DDProperties.instance().PocketProviderID); } - } + } + public static void readPacket(DataInputStream input) throws IOException { - //TODO- figure out why this is getting called so frequently + // TODO- figure out why this is getting called so frequently if (isLoaded) { - return; + return; } if (isLoading) { @@ -714,17 +730,39 @@ public class PocketManager // Load compacted client-side dimension data load(); Compactor.readDimensions(input, new DimRegistrationCallback()); - - // Register pocket dimensions - DDProperties properties = DDProperties.instance(); - + isLoaded = true; isLoading = false; isConnected = true; } - public static UpdateWatcherProxy getDimwatcher() + public static UpdateWatcherProxy getDimwatcher() { return dimWatcher; } + + public static UpdateWatcherProxy getLinkWatcher() + { + return linkWatcher; + } + + public static NewDimData getPersonalDimensionForPlayer(String name) + { + if (personalPocketsMapping.containsKey(name)) + { + return personalPocketsMapping.get(name); + } + return null; + } + + public static void setPersonalPocketsMapping(HashMap ppMap) + { + personalPocketsMapping = ppMap; + } + + public static HashMap getPersonalPocketMapping() + { + // TODO Auto-generated method stub + return personalPocketsMapping; + } } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/dungeon/DungeonSchematic.java b/src/main/java/StevenDimDoors/mod_pocketDim/dungeon/DungeonSchematic.java index 8395d9b..afcbc0e 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/dungeon/DungeonSchematic.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/dungeon/DungeonSchematic.java @@ -9,18 +9,17 @@ import java.util.Map; import java.util.Map.Entry; import java.util.Random; import java.util.TreeMap; - import net.minecraft.block.Block; import net.minecraft.entity.Entity; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntitySign; import net.minecraft.world.World; -import StevenDimDoors.mod_pocketDim.DDProperties; import StevenDimDoors.mod_pocketDim.Point3D; import StevenDimDoors.mod_pocketDim.blocks.IDimDoor; +import StevenDimDoors.mod_pocketDim.config.DDProperties; import StevenDimDoors.mod_pocketDim.core.DimLink; -import StevenDimDoors.mod_pocketDim.core.LinkTypes; +import StevenDimDoors.mod_pocketDim.core.LinkType; import StevenDimDoors.mod_pocketDim.core.NewDimData; import StevenDimDoors.mod_pocketDim.core.PocketManager; import StevenDimDoors.mod_pocketDim.schematic.BlockRotator; @@ -162,7 +161,7 @@ public class DungeonSchematic extends Schematic { applyFilter(standardizer); } - private Map getAssignedToStandardIDMapping(DDProperties properties) + private static Map getAssignedToStandardIDMapping(DDProperties properties) { //If we ever need this broadly or support other mods, this should be moved to a separate class TreeMap mapping = new TreeMap(); @@ -184,11 +183,11 @@ public class DungeonSchematic extends Schematic { { if (notifyClients) { - copyToWorld(world, pocketCenter, targetOrientation, entryLink, random, properties, new WorldBlockSetter(false, true)); + copyToWorld(world, pocketCenter, targetOrientation, entryLink, random, properties, new WorldBlockSetter(false, true, false)); } else { - copyToWorld(world, pocketCenter, targetOrientation, entryLink, random, properties, new ChunkBlockSetter()); + copyToWorld(world, pocketCenter, targetOrientation, entryLink, random, properties, new ChunkBlockSetter(false)); } } @@ -247,7 +246,7 @@ public class DungeonSchematic extends Schematic { world.setBlockTileEntity(pocketPoint.getX(), pocketPoint.getY(), pocketPoint.getZ(), TileEntity.createAndLoadEntity(tileTag)); } - setUpDungeon(PocketManager.getDimensionData(world), world, pocketCenter, turnAngle, entryLink, random, properties, blockSetter); + setUpDungeon(PocketManager.createDimensionData(world), world, pocketCenter, turnAngle, entryLink, random, properties, blockSetter); } private void setUpDungeon(NewDimData dimension, World world, Point3D pocketCenter, int turnAngle, DimLink entryLink, Random random, DDProperties properties, IBlockSetter blockSetter) @@ -322,10 +321,10 @@ public class DungeonSchematic extends Schematic { private static void createEntranceReverseLink(World world, NewDimData dimension, Point3D pocketCenter, DimLink entryLink) { int orientation = world.getBlockMetadata(pocketCenter.getX(), pocketCenter.getY() - 1, pocketCenter.getZ()); - DimLink reverseLink = dimension.createLink(pocketCenter.getX(), pocketCenter.getY(), pocketCenter.getZ(), LinkTypes.REVERSE, orientation); + DimLink reverseLink = dimension.createLink(pocketCenter.getX(), pocketCenter.getY(), pocketCenter.getZ(), LinkType.REVERSE, orientation); Point4D destination = entryLink.source(); NewDimData prevDim = PocketManager.getDimensionData(destination.getDimension()); - prevDim.setDestination(reverseLink, destination.getX(), destination.getY(), destination.getZ()); + prevDim.setLinkDestination(reverseLink, destination.getX(), destination.getY(), destination.getZ()); initDoorTileEntity(world, pocketCenter); } @@ -335,7 +334,7 @@ public class DungeonSchematic extends Schematic { Point3D location = point.clone(); BlockRotator.transformPoint(location, entrance, rotation, pocketCenter); int orientation = world.getBlockMetadata(location.getX(), location.getY() - 1, location.getZ()); - dimension.createLink(location.getX(), location.getY(), location.getZ(), LinkTypes.DUNGEON_EXIT, orientation); + dimension.createLink(location.getX(), location.getY(), location.getZ(), LinkType.DUNGEON_EXIT, orientation); //Replace the sandstone block under the exit door with the same block as the one underneath it int x = location.getX(); int y = location.getY() - 3; @@ -356,7 +355,7 @@ public class DungeonSchematic extends Schematic { BlockRotator.transformPoint(location, entrance, rotation, pocketCenter); int orientation = world.getBlockMetadata(location.getX(), location.getY() - 1, location.getZ()); - dimension.createLink(location.getX(), location.getY(), location.getZ(), LinkTypes.DUNGEON, orientation); + dimension.createLink(location.getX(), location.getY(), location.getZ(), LinkType.DUNGEON, orientation); initDoorTileEntity(world, location); } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/dungeon/FillContainersOperation.java b/src/main/java/StevenDimDoors/mod_pocketDim/dungeon/FillContainersOperation.java index 62bec13..e44a58b 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/dungeon/FillContainersOperation.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/dungeon/FillContainersOperation.java @@ -12,7 +12,7 @@ import net.minecraft.tileentity.TileEntityChest; import net.minecraft.tileentity.TileEntityDispenser; import net.minecraft.world.World; import StevenDimDoors.mod_pocketDim.DDLoot; -import StevenDimDoors.mod_pocketDim.DDProperties; +import StevenDimDoors.mod_pocketDim.config.DDProperties; import StevenDimDoors.mod_pocketDim.schematic.WorldOperation; public class FillContainersOperation extends WorldOperation @@ -20,8 +20,8 @@ public class FillContainersOperation extends WorldOperation private Random random; private DDProperties properties; - private static final int GRAVE_CHEST_CHANCE = 100; - private static final int MAX_GRAVE_CHEST_CHANCE = 700; + private static final int GRAVE_CHEST_CHANCE = 1; + private static final int MAX_GRAVE_CHEST_CHANCE = 6; public FillContainersOperation(Random random, DDProperties properties) { @@ -57,16 +57,6 @@ public class FillContainersOperation extends WorldOperation } } } - - // Fill dispensers - if (tileEntity instanceof TileEntityDispenser) - { - TileEntityDispenser dispenser = (TileEntityDispenser) tileEntity; - if (isInventoryEmpty(dispenser)) - { - dispenser.addItem(new ItemStack(Item.arrow, 64)); - } - } } return true; } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/dungeon/pack/DungeonPack.java b/src/main/java/StevenDimDoors/mod_pocketDim/dungeon/pack/DungeonPack.java index af997fa..732f5df 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/dungeon/pack/DungeonPack.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/dungeon/pack/DungeonPack.java @@ -21,6 +21,7 @@ public class DungeonPack //FIXME: Do not release this code as an update without dealing with disowned types! private static final int MAX_HISTORY_LENGTH = 30; + private static final int MAX_SUBTREE_LIST_SIZE = 30; private final String name; private final HashMap nameToTypeMapping; @@ -122,7 +123,7 @@ public class DungeonPack } } - public DungeonData getNextDungeon(NewDimData dimension, Random random) + public DungeonData getNextDungeon(NewDimData parent, Random random) { if (allDungeons.isEmpty()) { @@ -135,16 +136,36 @@ public class DungeonPack //for dungeon packs that can extend arbitrarily deep. We should probably set a reasonable limit anyway. int maxSearchLength = config.allowDuplicatesInChain() ? maxRuleLength : MAX_HISTORY_LENGTH; - ArrayList history = DungeonHelper.getDungeonChainHistory(dimension, this, maxSearchLength); - return getNextDungeon(history, random); + ArrayList history = DungeonHelper.getDungeonChainHistory(parent, this, maxSearchLength); + + ArrayList subtreeHistory = null; + if (config.getDuplicateSearchLevels() > 0) + { + // Search over (DuplicateSearchLevels - 1); zero means don't search at all, + // one means search only up to the level of the immediate parent, and so on. + // Since we start with the parent, we need to drop the max levels by one. + NewDimData ancestor = DungeonHelper.getAncestor(parent, this, config.getDuplicateSearchLevels() - 1); + if (ancestor != null) + { + subtreeHistory = DungeonHelper.listDungeonsInTree(ancestor, this, MAX_SUBTREE_LIST_SIZE); + } + } + if (subtreeHistory == null) + { + subtreeHistory = new ArrayList(); + } + subtreeHistory = new ArrayList(); + + return getNextDungeon(history, subtreeHistory, random); } - private DungeonData getNextDungeon(ArrayList history, Random random) + private DungeonData getNextDungeon(ArrayList history, ArrayList subtreeHistory, Random random) { //Extract the dungeon types that have been used from history and convert them into an array of IDs int index; int[] typeHistory = new int[history.size()]; HashSet excludedDungeons = null; + boolean doExclude = !config.allowDuplicatesInChain() || !subtreeHistory.isEmpty(); for (index = 0; index < typeHistory.length; index++) { typeHistory[index] = history.get(index).dungeonType().ID; @@ -163,9 +184,19 @@ public class DungeonPack if (nextType != null) { //Initialize the set of excluded dungeons if needed - if (excludedDungeons == null && !config.allowDuplicatesInChain()) + if (excludedDungeons == null && doExclude) { - excludedDungeons = new HashSet(history); + if (config.allowDuplicatesInChain()) + { + excludedDungeons = new HashSet(subtreeHistory); + excludedDungeons.addAll(subtreeHistory); + } + else + { + excludedDungeons = new HashSet(2 * (history.size() + subtreeHistory.size())); + excludedDungeons.addAll(history); + excludedDungeons.addAll(subtreeHistory); + } } //List which dungeons are allowed @@ -267,4 +298,9 @@ public class DungeonPack WeightedContainer resultContainer = (WeightedContainer) WeightedRandom.getRandomItem(random, weights); return (resultContainer != null) ? resultContainer.getData() : null; } + @Override + public String toString() + { + return this.name; + } } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/dungeon/pack/DungeonPackConfig.java b/src/main/java/StevenDimDoors/mod_pocketDim/dungeon/pack/DungeonPackConfig.java index 0074545..e5eaa54 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/dungeon/pack/DungeonPackConfig.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/dungeon/pack/DungeonPackConfig.java @@ -11,6 +11,7 @@ public class DungeonPackConfig private boolean allowPackChangeOut; private boolean distortDoorCoordinates; private int packWeight; + private int duplicateSearchLevels; private ArrayList rules; public DungeonPackConfig() { } @@ -25,6 +26,7 @@ public class DungeonPackConfig this.allowPackChangeOut = source.allowPackChangeOut; this.distortDoorCoordinates = source.distortDoorCoordinates; this.packWeight = source.packWeight; + this.duplicateSearchLevels = source.duplicateSearchLevels; this.rules = (source.rules != null) ? (ArrayList) source.rules.clone() : null; } @@ -114,6 +116,16 @@ public class DungeonPackConfig this.packWeight = packWeight; } + public int getDuplicateSearchLevels() + { + return duplicateSearchLevels; + } + + public void setDuplicateSearchLevels(int duplicateSearchLevels) + { + this.duplicateSearchLevels = duplicateSearchLevels; + } + public boolean doDistortDoorCoordinates() { return distortDoorCoordinates; diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/dungeon/pack/DungeonPackConfigReader.java b/src/main/java/StevenDimDoors/mod_pocketDim/dungeon/pack/DungeonPackConfigReader.java index e24ecc6..0f8b05c 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/dungeon/pack/DungeonPackConfigReader.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/dungeon/pack/DungeonPackConfigReader.java @@ -35,6 +35,8 @@ public class DungeonPackConfigReader extends BaseConfigurationProcessor= MIN_DUPLICATE_SEARCH_LEVELS && levels <= MAX_DUPLICATE_SEARCH_LEVELS) + { + config.setDuplicateSearchLevels(levels); + } + else + { + valid = false; + } + } else { valid = false; diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/dungeon/pack/DungeonType.java b/src/main/java/StevenDimDoors/mod_pocketDim/dungeon/pack/DungeonType.java index 50e5921..98c0a14 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/dungeon/pack/DungeonType.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/dungeon/pack/DungeonType.java @@ -45,4 +45,9 @@ public class DungeonType implements Comparable final int prime = 2039; return prime * ID; } + @Override + public String toString() + { + return this.Name+" owned by "+this.Owner; + } } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/helpers/ChunkLoaderHelper.java b/src/main/java/StevenDimDoors/mod_pocketDim/helpers/ChunkLoaderHelper.java index 06d22d5..6483afd 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/helpers/ChunkLoaderHelper.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/helpers/ChunkLoaderHelper.java @@ -1,54 +1,98 @@ package StevenDimDoors.mod_pocketDim.helpers; -import StevenDimDoors.mod_pocketDim.IChunkLoader; -import StevenDimDoors.mod_pocketDim.mod_pocketDim; -import StevenDimDoors.mod_pocketDim.core.NewDimData; -import StevenDimDoors.mod_pocketDim.core.PocketManager; - -import cpw.mods.fml.common.event.FMLServerStartingEvent; - import java.io.File; import java.util.List; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.world.ChunkCoordIntPair; import net.minecraft.world.World; import net.minecraftforge.common.DimensionManager; import net.minecraftforge.common.ForgeChunkManager; import net.minecraftforge.common.ForgeChunkManager.LoadingCallback; import net.minecraftforge.common.ForgeChunkManager.Ticket; +import net.minecraftforge.common.ForgeChunkManager.Type; +import StevenDimDoors.experimental.BoundingBox; +import StevenDimDoors.mod_pocketDim.IChunkLoader; +import StevenDimDoors.mod_pocketDim.Point3D; +import StevenDimDoors.mod_pocketDim.mod_pocketDim; +import StevenDimDoors.mod_pocketDim.core.NewDimData; +import StevenDimDoors.mod_pocketDim.core.PocketManager; +import StevenDimDoors.mod_pocketDim.world.PocketBuilder; +import cpw.mods.fml.common.event.FMLServerStartingEvent; public class ChunkLoaderHelper implements LoadingCallback { - @Override public void ticketsLoaded(List tickets, World world) { for (Ticket ticket : tickets) { - int goldDimDoorX = ticket.getModData().getInteger("goldDimDoorX"); - int goldDimDoorY = ticket.getModData().getInteger("goldDimDoorY"); - int goldDimDoorZ = ticket.getModData().getInteger("goldDimDoorZ"); - if(world.getBlockId(goldDimDoorX, goldDimDoorY, goldDimDoorZ) != mod_pocketDim.properties.GoldenDimensionalDoorID) + boolean loaded = false; + int x = ticket.getModData().getInteger("goldDimDoorX"); + int y = ticket.getModData().getInteger("goldDimDoorY"); + int z = ticket.getModData().getInteger("goldDimDoorZ"); + + if (world.getBlockId(x, y, z) == mod_pocketDim.properties.GoldenDimensionalDoorID) + { + IChunkLoader loader = (IChunkLoader) world.getBlockTileEntity(x, y, z); + if (!loader.isInitialized()) + { + loader.initialize(ticket); + loaded = true; + } + } + if (!loaded) { ForgeChunkManager.releaseTicket(ticket); } - else - { - IChunkLoader tile = (IChunkLoader) world.getBlockTileEntity(goldDimDoorX, goldDimDoorY, goldDimDoorZ); - tile.forceChunkLoading(ticket,goldDimDoorX,goldDimDoorZ); - } } } - public static void loadChunkForcedWorlds(FMLServerStartingEvent event) + public static Ticket createTicket(int x, int y, int z, World world) { - for(NewDimData data : PocketManager.getDimensions()) + NBTTagCompound data; + Ticket ticket = ForgeChunkManager.requestTicket(mod_pocketDim.instance, world, Type.NORMAL); + if (ticket != null) + { + data = ticket.getModData(); + data.setInteger("goldDimDoorX", x); + data.setInteger("goldDimDoorY", y); + data.setInteger("goldDimDoorZ", z); + } + return ticket; + } + + public static void forcePocketChunks(NewDimData pocket, Ticket ticket) + { + BoundingBox bounds = PocketBuilder.calculateDefaultBounds(pocket); + Point3D minCorner = bounds.minCorner(); + Point3D maxCorner = bounds.maxCorner(); + int minX = minCorner.getX() >> 4; + int minZ = minCorner.getZ() >> 4; + int maxX = maxCorner.getX() >> 4; + int maxZ = maxCorner.getZ() >> 4; + int chunkX; + int chunkZ; + + for (chunkX = minX; chunkX <= maxX; chunkX++) + { + for (chunkZ = minZ; chunkZ <= maxZ; chunkZ++) + { + ForgeChunkManager.forceChunk(ticket, new ChunkCoordIntPair(chunkX, chunkZ)); + } + } + } + + public static void loadForcedChunkWorlds(FMLServerStartingEvent event) + { + for (NewDimData data : PocketManager.getDimensions()) { if(data.isPocketDimension()) { String chunkDir = DimensionManager.getCurrentSaveRootDirectory()+"/DimensionalDoors/pocketDimID" + data.id(); - + File file = new File(chunkDir); - + if(file.exists()) { if(ForgeChunkManager.savedWorldHasForcedChunkTickets(file)) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/helpers/Compactor.java b/src/main/java/StevenDimDoors/mod_pocketDim/helpers/Compactor.java index 1f3d0c9..a19dc9f 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/helpers/Compactor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/helpers/Compactor.java @@ -6,10 +6,10 @@ import java.io.IOException; import java.util.Collection; import java.util.Comparator; import java.util.HashSet; - import StevenDimDoors.mod_pocketDim.core.DimLink; +import StevenDimDoors.mod_pocketDim.core.DimensionType; import StevenDimDoors.mod_pocketDim.core.IDimRegistrationCallback; -import StevenDimDoors.mod_pocketDim.core.LinkTypes; +import StevenDimDoors.mod_pocketDim.core.LinkType; import StevenDimDoors.mod_pocketDim.core.NewDimData; import StevenDimDoors.mod_pocketDim.util.Point4D; import StevenDimDoors.mod_pocketDim.watcher.ClientLinkData; @@ -68,19 +68,20 @@ public class Compactor { int id = input.readInt(); int rootID = input.readInt(); + DimensionType type = DimensionType.getTypeFromIndex(input.readInt()); if (rootIDs.add(rootID)) { - callback.registerDimension(rootID, rootID); + callback.registerDimension(rootID, rootID, type); } // Don't check if (id != rootID) - we want to retrieve the reference anyway - NewDimData dimension = callback.registerDimension(id, rootID); + NewDimData dimension = callback.registerDimension(id, rootID, type); int linkCount = input.readInt(); for (int h = 0; h < linkCount; h++) { ClientLinkData link = ClientLinkData.read(input); Point4D source = link.point; - dimension.createLink(source.getX(), source.getY(), source.getZ(), LinkTypes.CLIENT_SIDE,link.orientation); + dimension.createLink(source.getX(), source.getY(), source.getZ(), LinkType.CLIENT,0); } } } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/helpers/DeleteFolder.java b/src/main/java/StevenDimDoors/mod_pocketDim/helpers/DeleteFolder.java index 3f835be..495ca6b 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/helpers/DeleteFolder.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/helpers/DeleteFolder.java @@ -2,31 +2,33 @@ package StevenDimDoors.mod_pocketDim.helpers; import java.io.File; - public class DeleteFolder { - public static boolean deleteFolder(File file) + public static boolean deleteFolder(File directory) { try { - File[] files = file.listFiles(); - - if(files==null) + File[] contents = directory.listFiles(); + if (contents != null) { - file.delete(); - return true; + for (File entry : contents) + { + if (entry.isDirectory()) + { + deleteFolder(entry); + } + else + { + entry.delete(); + } + } } - for(File inFile : files) - { - DeleteFolder.deleteFolder(inFile); - } - + return directory.delete(); } catch (Exception e) { e.printStackTrace(); return false; } - return true; } } \ No newline at end of file diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/helpers/DungeonHelper.java b/src/main/java/StevenDimDoors/mod_pocketDim/helpers/DungeonHelper.java index 3f8e7a3..05a9b64 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/helpers/DungeonHelper.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/helpers/DungeonHelper.java @@ -4,10 +4,10 @@ import java.io.BufferedReader; import java.io.File; import java.io.FileFilter; import java.io.FileNotFoundException; +import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.ArrayList; -import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; @@ -16,13 +16,12 @@ import java.util.List; import java.util.Queue; import java.util.Random; import java.util.regex.Pattern; - import net.minecraft.util.WeightedRandom; import net.minecraft.world.World; -import StevenDimDoors.mod_pocketDim.DDProperties; import StevenDimDoors.mod_pocketDim.mod_pocketDim; +import StevenDimDoors.mod_pocketDim.config.DDProperties; import StevenDimDoors.mod_pocketDim.core.DimLink; -import StevenDimDoors.mod_pocketDim.core.LinkTypes; +import StevenDimDoors.mod_pocketDim.core.LinkType; import StevenDimDoors.mod_pocketDim.core.NewDimData; import StevenDimDoors.mod_pocketDim.core.PocketManager; import StevenDimDoors.mod_pocketDim.dungeon.DungeonData; @@ -32,7 +31,6 @@ import StevenDimDoors.mod_pocketDim.dungeon.pack.DungeonPackConfig; import StevenDimDoors.mod_pocketDim.dungeon.pack.DungeonPackConfigReader; import StevenDimDoors.mod_pocketDim.dungeon.pack.DungeonType; import StevenDimDoors.mod_pocketDim.items.ItemDimensionalDoor; -import StevenDimDoors.mod_pocketDim.util.ConfigurationProcessingException; import StevenDimDoors.mod_pocketDim.util.FileFilters; import StevenDimDoors.mod_pocketDim.util.WeightedContainer; @@ -47,11 +45,8 @@ public class DungeonHelper public static final String SCHEMATIC_FILE_EXTENSION = ".schematic"; private static final String DEFAULT_ERROR_SCHEMATIC_PATH = "/schematics/core/somethingBroke.schematic"; - private static final String DUNGEON_CREATION_GUIDE_SOURCE_PATH = "/mods/DimDoors/text/How_to_add_dungeons.txt"; - private static final String RUINS_PACK_PATH = "/schematics/ruins"; - private static final String BUNDLED_RUINS_LIST_PATH = "/schematics/ruins.txt"; - private static final String NETHER_PACK_PATH = "/schematics/nether"; - private static final String BUNDLED_NETHER_LIST_PATH = "/schematics/nether.txt"; + private static final String DUNGEON_CREATION_GUIDE_SOURCE_PATH = "/assets/dimdoors/text/How_to_add_dungeons.txt"; + private static final String BUNDLED_PACK_BASE_PATH = "/schematics/"; private static final String STANDARD_CONFIG_FILE_NAME = "rules.txt"; private static final int NETHER_DIMENSION_ID = -1; @@ -158,7 +153,7 @@ public class DungeonHelper return null; } - private void registerDungeonPack(String directory, Iterable schematics, boolean isInternal, boolean verbose, DungeonPackConfigReader reader) + private DungeonPack registerDungeonPack(String directory, Iterable schematics, boolean isInternal, boolean verbose, DungeonPackConfigReader reader) { //First determine the pack's name and validate it File packDirectory = new File(directory); @@ -187,7 +182,7 @@ public class DungeonHelper if (config == null) { System.err.println("Could not load config file: " + configPath); - return; + return null; } //Register the pack @@ -208,6 +203,7 @@ public class DungeonHelper { registerDungeon(schematicPath, pack, isInternal, verbose); } + return pack; } public List getRegisteredDungeons() @@ -231,10 +227,14 @@ public class DungeonHelper return dungeonPackMapping.get(name.toUpperCase()); } - private DungeonPack getDimDungeonPack(NewDimData data) + private DungeonPack getDimDungeonPack(NewDimData dimension) { + // TODO: Drop support for dim-based packs and switch to embedding the pack + // in the link data itself. That would solve the dungeon pre-generation issue. + // Gateways should dictate which packs are being used, not the dimensions. + DungeonPack pack; - DungeonData dungeon = data.dungeon(); + DungeonData dungeon = dimension.dungeon(); if (dungeon != null) { pack = dungeon.dungeonType().Owner; @@ -247,7 +247,7 @@ public class DungeonHelper } else { - if (data.id() == NETHER_DIMENSION_ID) + if (dimension.id() == NETHER_DIMENSION_ID) { pack = NetherPack; } @@ -263,8 +263,8 @@ public class DungeonHelper { //Create a link above the specified position. Link to a new pocket dimension. NewDimData dimension = PocketManager.getDimensionData(world); - DimLink link = dimension.createLink(x, y + 1, z, LinkTypes.POCKET, 3); - + DimLink link = dimension.createLink(x, y + 1, z, LinkType.POCKET, 3); + //Place a Warp Door linked to that pocket ItemDimensionalDoor.placeDoorBlock(world, x, y, z, 3, mod_pocketDim.warpDoor); @@ -433,32 +433,30 @@ public class DungeonHelper defaultError = new DungeonData(DEFAULT_ERROR_SCHEMATIC_PATH, true, DungeonType.UNKNOWN_TYPE, true, DEFAULT_DUNGEON_WEIGHT); //Open the list of dungeons packaged with our mod and register their schematics - registerBundledPack(BUNDLED_RUINS_LIST_PATH, RUINS_PACK_PATH, "Ruins", reader); - RuinsPack = getDungeonPack("Ruins"); - - registerBundledPack(BUNDLED_NETHER_LIST_PATH, NETHER_PACK_PATH, "Nether", reader); - NetherPack = getDungeonPack("Nether"); + RuinsPack = registerBundledPack("Ruins", reader); + NetherPack = registerBundledPack("Nether", reader); System.out.println("Finished registering bundled dungeon packs"); } - private void registerBundledPack(String listPath, String packPath, String name, DungeonPackConfigReader reader) + private DungeonPack registerBundledPack(String name, DungeonPackConfigReader reader) { System.out.println("Registering bundled dungeon pack: " + name); + String packPath = BUNDLED_PACK_BASE_PATH + name.toLowerCase(); + String listPath = packPath + ".txt"; InputStream listStream = this.getClass().getResourceAsStream(listPath); - // chance of leak? + if (listStream == null) { - System.err.println("Unable to open list of bundled dungeon schematics for " + name); - return; + throw new IllegalStateException("Failed to open the list of bundled dungeon schematics for " + name); } + ArrayList schematics = new ArrayList(); try { - //Read the list of schematics that come with a bundled pack + // Read the list of schematics that come with a bundled pack BufferedReader listReader = new BufferedReader(new InputStreamReader(listStream)); - ArrayList schematics = new ArrayList(); String schematicPath = listReader.readLine(); while (schematicPath != null) { @@ -470,15 +468,19 @@ public class DungeonHelper schematicPath = listReader.readLine(); } listReader.close(); - - //Register the pack - registerDungeonPack(packPath, schematics, true, false, reader); } - catch (Exception e) + catch (IOException e) { - System.err.println("An exception occurred while reading the list of bundled dungeon schematics for " + name); - e.printStackTrace(); + throw new RuntimeException("An unexpected error occured while trying to read the list of schematics for the " + name + " bundled dungeon pack. This would inevitably cause Dimensional Doors to crash during runtime.", e); } + + // Register the pack + DungeonPack pack = registerDungeonPack(packPath, schematics, true, false, reader); + if (pack == null) + { + throw new RuntimeException("Failed to load the " + name + " bundled dungeon pack. This would inevitably cause Dimensional Doors to crash during runtime."); + } + return pack; } public boolean exportDungeon(World world, int centerX, int centerY, int centerZ, String exportPath) @@ -500,9 +502,9 @@ public class DungeonHelper } } - public DungeonData selectDungeon(NewDimData dimension, Random random) + public DungeonData selectNextDungeon(NewDimData parent, Random random) { - DungeonPack pack = getDimDungeonPack(dimension.parent()); + DungeonPack pack = getDimDungeonPack(parent); DungeonData selection; DungeonPackConfig config; DungeonPack selectedPack; @@ -512,30 +514,30 @@ public class DungeonHelper config = pack.getConfig(); selectedPack = pack; - //Are we allowed to switch to another dungeon pack? + // Are we allowed to switch to another dungeon pack? if (config.allowPackChangeOut()) { - //Calculate the chance of switching to a different pack type + // Calculate the chance of switching to a different pack type int packSwitchChance; - if (dimension.depth() == 1) + if (parent.isPocketDimension()) { - packSwitchChance = START_PACK_SWITCH_CHANCE; + packSwitchChance = MIN_PACK_SWITCH_CHANCE + parent.packDepth() * PACK_SWITCH_CHANCE_PER_LEVEL; } else { - packSwitchChance = MIN_PACK_SWITCH_CHANCE + dimension.parent().packDepth() * PACK_SWITCH_CHANCE_PER_LEVEL; + packSwitchChance = START_PACK_SWITCH_CHANCE; } - //Decide randomly whether to switch packs or not + // Decide randomly whether to switch packs or not if (random.nextInt(MAX_PACK_SWITCH_CHANCE) < packSwitchChance) { - //Find another pack + // Find another pack selectedPack = getRandomDungeonPack(pack, random); } } //Pick the next dungeon - selection = selectedPack.getNextDungeon(dimension, random); + selection = selectedPack.getNextDungeon(parent, random); } catch (Exception e) { @@ -577,11 +579,11 @@ public class DungeonHelper return selection; } - public Collection getDungeonNames() { - - //Use a HashSet to guarantee that all dungeon names will be distinct. - //This shouldn't be necessary if we keep proper lists without repetitions, - //but it's a fool-proof workaround. + public ArrayList getDungeonNames() + { + // Use a HashSet to guarantee that all dungeon names will be distinct. + // This shouldn't be necessary if we keep proper lists without repetitions, + // but it's a fool-proof workaround. HashSet dungeonNames = new HashSet(); dungeonNames.addAll( parseDungeonNames(registeredDungeons) ); dungeonNames.addAll( parseDungeonNames(untaggedDungeons) ); @@ -609,59 +611,95 @@ public class DungeonHelper return names; } - public static ArrayList getDungeonChainHistory(NewDimData dimension, DungeonPack pack, int maxSize) + /** + * Lists all of the dungeons found by iterating through a dimension's ancestors. The search stops when a non-dungeon dimension is found or when the pack of a dungeon differs from the specified pack. + * @param start - the first dimension to include in the history + * @param pack - the pack to which any dungeons must belong in order to be listed + * @param maxSize - the maximum number of dungeons that can be listed + * @return a list of dungeons used in a given chain + */ + public static ArrayList getDungeonChainHistory(NewDimData start, DungeonPack pack, int maxSize) { - if (dimension == null) + if (start == null) { throw new IllegalArgumentException("dimension cannot be null."); } - if(dimension.parent()==null) - { - return new ArrayList(); - } int count = 0; - NewDimData tail = dimension.parent(); - DungeonData dungeon = tail.dungeon(); + NewDimData current = start; + DungeonData dungeon = current.dungeon(); ArrayList history = new ArrayList(); while (count < maxSize && dungeon != null && dungeon.dungeonType().Owner == pack) { history.add(dungeon); - tail = tail.parent(); - dungeon = tail.dungeon(); + current = current.parent(); + dungeon = current.dungeon(); count++; } return history; } - public static ArrayList getFlatDungeonTree(NewDimData dimension, int maxSize) + /** + * Performs a breadth-first listing of all dungeons rooted at a specified dimension. Only dungeons from the specified pack will be included. + * @param root - the pocket dimension that serves as the root for the dungeon tree + * @param pack - the pack to which any dungeons must belong in order to be listed + * @param maxSize - the maximum number of dungeons that can be listed + * @return a list of the dungeons used in a given dungeon tree + */ + public static ArrayList listDungeonsInTree(NewDimData root, DungeonPack pack, int maxSize) { - NewDimData root = dimension; + int count = 0; + NewDimData current; + DungeonData dungeon; ArrayList dungeons = new ArrayList(); - Queue pendingDimensions = new LinkedList(); - - if (root.dungeon() == null) - { - return dungeons; - } + Queue pendingDimensions = new LinkedList(); pendingDimensions.add(root); + // Perform a breadth-first search through the dungeon graph while (dungeons.size() < maxSize && !pendingDimensions.isEmpty()) { - NewDimData current = pendingDimensions.remove(); - for (NewDimData child : current.children()) + current = pendingDimensions.remove(); + dungeon = current.dungeon(); + // Check that this is a dungeon, and if so, that it belongs to the pack that we want + if (dungeon != null && dungeon.dungeonType().Owner == pack) { - if (child.dungeon() != null) + dungeons.add(dungeon); + // Add all child dungeons for checking later + for (NewDimData child : current.children()) { - dungeons.add(child.dungeon()); pendingDimensions.add(child); } - if (dungeons.size() == maxSize) - { - break; - } } } return dungeons; } + + /** + * Gets the highest ancestor of a dimension with a dungeon that belongs to the specified pack. + * @param dimension - the first dimension to include in the search + * @param pack - the pack to which the ancestors must belong + * @param maxLevels - the maximum number of ancestors to check + * @return the highest ancestor that belongs to the specified pack within the specified levels, or null if none exists + */ + public static NewDimData getAncestor(NewDimData dimension, DungeonPack pack, int maxLevels) + { + // Find the ancestor of a dimension located a specified number of levels up. + NewDimData parent = dimension; + NewDimData current = null; + + // We solve this inductively. We begin with null as the first valid ancestor, + // like a kind of virtual child dimension. Then "current" references the + // highest valid ancestor found so far and "parent" references its parent + for (int levels = 0; levels <= maxLevels; levels++) + { + if (parent == null || parent.dungeon() == null || + parent.dungeon().dungeonType().Owner != pack) + { + break; + } + current = parent; + parent = parent.parent(); + } + return current; + } } \ No newline at end of file diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/helpers/PersonalPocketHelper.java b/src/main/java/StevenDimDoors/mod_pocketDim/helpers/PersonalPocketHelper.java new file mode 100644 index 0000000..967fc43 --- /dev/null +++ b/src/main/java/StevenDimDoors/mod_pocketDim/helpers/PersonalPocketHelper.java @@ -0,0 +1,6 @@ +package StevenDimDoors.mod_pocketDim.helpers; + +public class PersonalPocketHelper +{ + +} diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/helpers/yCoordHelper.java b/src/main/java/StevenDimDoors/mod_pocketDim/helpers/yCoordHelper.java index 3810c8b..26aa178 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/BaseItemDoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/items/BaseItemDoor.java index 8651270..3ad3a4b 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/items/BaseItemDoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/items/BaseItemDoor.java @@ -1,34 +1,53 @@ package StevenDimDoors.mod_pocketDim.items; +import java.util.HashMap; import java.util.List; import net.minecraft.block.Block; import net.minecraft.block.material.Material; import net.minecraft.client.renderer.texture.IconRegister; import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.item.Item; import net.minecraft.item.ItemDoor; import net.minecraft.item.ItemStack; import net.minecraft.util.MathHelper; import net.minecraft.util.MovingObjectPosition; +import net.minecraft.util.Vec3; import net.minecraft.world.World; -import StevenDimDoors.mod_pocketDim.DDProperties; import StevenDimDoors.mod_pocketDim.mod_pocketDim; +import StevenDimDoors.mod_pocketDim.blocks.BaseDimDoor; +import StevenDimDoors.mod_pocketDim.config.DDProperties; import StevenDimDoors.mod_pocketDim.core.DimLink; import StevenDimDoors.mod_pocketDim.core.PocketManager; import StevenDimDoors.mod_pocketDim.tileentities.TileEntityDimDoor; - public abstract class BaseItemDoor extends ItemDoor { + // Maps non-dimensional door items to their corresponding dimensional door item + // Also maps dimensional door items to themselves for simplicity + private static HashMap doorItemMapping = new HashMap(); private static DDProperties properties = null; - public BaseItemDoor(int itemID, Material material) + /** + * door represents the non-dimensional door this item is associated with. Leave null for none. + * @param itemID + * @param material + * @param door + */ + public BaseItemDoor(int itemID, Material material, ItemDoor vanillaDoor) { super(itemID, material); this.setMaxStackSize(64); this.setCreativeTab(mod_pocketDim.dimDoorsCreativeTab); if (properties == null) properties = DDProperties.instance(); + + doorItemMapping.put(this, this); + if (vanillaDoor != null) + { + doorItemMapping.put(vanillaDoor, this); + } } @Override @@ -41,12 +60,78 @@ public abstract class BaseItemDoor extends ItemDoor @Override public abstract void addInformation(ItemStack par1ItemStack, EntityPlayer par2EntityPlayer, List par3List, boolean par4); + /** + * Overriden in subclasses to specify which door block that door item will + * place + * + * @return + */ + protected abstract BaseDimDoor getDoorBlock(); + + /** + * Overriden here to remove vanilla block placement functionality from + * dimensional doors, we handle this in the EventHookContainer + */ @Override - public abstract boolean onItemUse(ItemStack stack, EntityPlayer player, World world, int x, int y, int z, int side, float hitX, float hitY, float hitZ); - - public static boolean tryItemUse(Block doorBlock, ItemStack stack, EntityPlayer player, World world, int x, int y, int z, int side, boolean requireLink, boolean reduceStack) + public boolean onItemUse(ItemStack stack, EntityPlayer player, World world, int x, int y, int z, int side, float hitX, float hitY, float hitZ) { - // Only place doors on top of blocks - check if we're targeting the top side + return false; + } + + /** + * Tries to place a door as a dimensional door + * + * @param stack + * @param player + * @param world + * @param x + * @param y + * @param z + * @param side + * @return + */ + public static boolean tryToPlaceDoor(ItemStack stack, EntityPlayer player, World world, int x, int y, int z, int side) + { + if (world.isRemote) + { + return false; + } + // Retrieve the actual door type that we want to use here. + // It's okay if stack isn't an ItemDoor. In that case, the lookup will + // return null, just as if the item was an unrecognized door type. + BaseItemDoor mappedItem = doorItemMapping.get(stack.getItem()); + if (mappedItem == null) + { + return false; + } + BaseDimDoor doorBlock = mappedItem.getDoorBlock(); + if (BaseItemDoor.placeDoorOnBlock(doorBlock, stack, player, world, x, y, z, side)) + { + return true; + } + return BaseItemDoor.placeDoorOnRift(doorBlock, world, player, stack); + } + + /** + * try to place a door block on a block + * @param doorBlock + * @param stack + * @param player + * @param world + * @param x + * @param y + * @param z + * @param side + * @return + */ + public static boolean placeDoorOnBlock(Block doorBlock, ItemStack stack, EntityPlayer player, World world, int x, int y, int z, int side) + { + if (world.isRemote) + { + return false; + } + // Only place doors on top of blocks - check if we're targeting the top + // side if (side == 1 && !world.isRemote) { int blockID = world.getBlockId(x, y, z); @@ -58,14 +143,14 @@ public abstract class BaseItemDoor extends ItemDoor } } - if (canPlace(world, x, y, z) && canPlace(world, x, y + 1, z) && - player.canPlayerEdit(x, y, z, side, stack) && player.canPlayerEdit(x, y + 1, z, side, stack) && - (!requireLink || PocketManager.getLink(x, y + 1, z, world) != null)&&stack.stackSize>0) + if (canPlace(world, x, y, z) && canPlace(world, x, y + 1, z) && player.canPlayerEdit(x, y, z, side, stack) + && (player.canPlayerEdit(x, y + 1, z, side, stack) && stack.stackSize > 0) + &&((stack.getItem() instanceof BaseItemDoor) || PocketManager.getLink(x, y + 1, z, world) != null)) { int orientation = MathHelper.floor_double((player.rotationYaw + 180.0F) * 4.0F / 360.0F - 0.5D) & 3; placeDoorBlock(world, x, y, z, orientation, doorBlock); - if (!player.capabilities.isCreativeMode && reduceStack) + if (!player.capabilities.isCreativeMode) { stack.stackSize--; } @@ -75,17 +160,23 @@ public abstract class BaseItemDoor extends ItemDoor return false; } - @Override - public abstract ItemStack onItemRightClick(ItemStack stack, World world, EntityPlayer player); - - public boolean tryPlacingDoor(Block doorBlock, World world, EntityPlayer player, ItemStack item) + /** + * uses a raytrace to try and place a door on a rift + * + * @param doorBlock + * @param world + * @param player + * @param stack + * @return + */ + public static boolean placeDoorOnRift(Block doorBlock, World world, EntityPlayer player, ItemStack stack) { if (world.isRemote) { return false; } - MovingObjectPosition hit = getMovingObjectPositionFromPlayer(player.worldObj, player, true); + MovingObjectPosition hit = BaseItemDoor.doRayTrace(player.worldObj, player, true); if (hit != null) { if (world.getBlockId(hit.blockX, hit.blockY, hit.blockZ) == properties.RiftBlockID) @@ -97,15 +188,19 @@ public abstract class BaseItemDoor extends ItemDoor int y = hit.blockY; int z = hit.blockZ; - if (player.canPlayerEdit(x, y, z, hit.sideHit, item) && player.canPlayerEdit(x, y - 1, z, hit.sideHit, item)) + if (player.canPlayerEdit(x, y, z, hit.sideHit, stack) && player.canPlayerEdit(x, y - 1, z, hit.sideHit, stack)) { if (canPlace(world, x, y, z) && canPlace(world, x, y - 1, z)) { int orientation = MathHelper.floor_double(((player.rotationYaw + 180.0F) * 4.0F / 360.0F) - 0.5D) & 3; placeDoorBlock(world, x, y - 1, z, orientation, doorBlock); - if(!(item.getItem() instanceof BaseItemDoor)) + if (!(stack.getItem() instanceof BaseItemDoor)) { - ((TileEntityDimDoor)world.getBlockTileEntity(x, y, z)).hasGennedPair=true; + ((TileEntityDimDoor) world.getBlockTileEntity(x, y, z)).hasGennedPair = true; + } + if (!player.capabilities.isCreativeMode) + { + stack.stackSize--; } return true; } @@ -122,4 +217,38 @@ public abstract class BaseItemDoor extends ItemDoor return (id == properties.RiftBlockID || id == 0 || Block.blocksList[id].blockMaterial.isReplaceable()); } + + /** + * Copied from minecraft Item.class + * TODO we probably can improve this + * + * @param par1World + * @param par2EntityPlayer + * @param par3 + * @return + */ + protected static MovingObjectPosition doRayTrace(World par1World, EntityPlayer par2EntityPlayer, boolean par3) + { + float f = 1.0F; + float f1 = par2EntityPlayer.prevRotationPitch + (par2EntityPlayer.rotationPitch - par2EntityPlayer.prevRotationPitch) * f; + float f2 = par2EntityPlayer.prevRotationYaw + (par2EntityPlayer.rotationYaw - par2EntityPlayer.prevRotationYaw) * f; + double d0 = par2EntityPlayer.prevPosX + (par2EntityPlayer.posX - par2EntityPlayer.prevPosX) * (double) f; + double d1 = par2EntityPlayer.prevPosY + (par2EntityPlayer.posY - par2EntityPlayer.prevPosY) * (double) f + + (double) (par1World.isRemote ? par2EntityPlayer.getEyeHeight() - par2EntityPlayer.getDefaultEyeHeight() : par2EntityPlayer.getEyeHeight()); + double d2 = par2EntityPlayer.prevPosZ + (par2EntityPlayer.posZ - par2EntityPlayer.prevPosZ) * (double) f; + Vec3 vec3 = par1World.getWorldVec3Pool().getVecFromPool(d0, d1, d2); + float f3 = MathHelper.cos(-f2 * 0.017453292F - (float) Math.PI); + float f4 = MathHelper.sin(-f2 * 0.017453292F - (float) Math.PI); + float f5 = -MathHelper.cos(-f1 * 0.017453292F); + float f6 = MathHelper.sin(-f1 * 0.017453292F); + float f7 = f4 * f5; + float f8 = f3 * f5; + double d3 = 5.0D; + if (par2EntityPlayer instanceof EntityPlayerMP) + { + d3 = ((EntityPlayerMP) par2EntityPlayer).theItemInWorldManager.getBlockReachDistance(); + } + Vec3 vec31 = vec3.addVector((double) f7 * d3, (double) f6 * d3, (double) f8 * d3); + return par1World.rayTraceBlocks_do_do(vec3, vec31, par3, !par3); + } } \ No newline at end of file diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemBlockDimWall.java b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemBlockDimWall.java index a97d9f0..50e62fe 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemBlockDimWall.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemBlockDimWall.java @@ -7,7 +7,7 @@ import StevenDimDoors.mod_pocketDim.mod_pocketDim; public class ItemBlockDimWall extends ItemBlock { - private final static String[] subNames = {"Fabric of Reality", "Ancient Fabric"}; + private final static String[] subNames = {"Fabric of Reality", "Ancient Fabric" , "Altered Fabric"}; public ItemBlockDimWall(int par1) { diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemDDKey.java b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemDDKey.java new file mode 100644 index 0000000..78d38cd --- /dev/null +++ b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemDDKey.java @@ -0,0 +1,213 @@ +package StevenDimDoors.mod_pocketDim.items; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import net.minecraft.block.Block; +import net.minecraft.client.renderer.texture.IconRegister; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.EnumAction; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTBase; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagList; +import net.minecraft.util.EnumMovingObjectType; +import net.minecraft.util.MovingObjectPosition; +import net.minecraft.util.StatCollector; +import net.minecraft.world.World; +import StevenDimDoors.mod_pocketDim.mod_pocketDim; +import StevenDimDoors.mod_pocketDim.blocks.IDimDoor; +import StevenDimDoors.mod_pocketDim.core.DDLock; +import StevenDimDoors.mod_pocketDim.core.DimLink; +import StevenDimDoors.mod_pocketDim.core.PocketManager; +import StevenDimDoors.mod_pocketDim.watcher.ClientLinkData; + +public class ItemDDKey extends Item +{ + public static final int TIME_TO_UNLOCK = 30; + + public ItemDDKey(int itemID) + { + super(itemID); + this.setCreativeTab(mod_pocketDim.dimDoorsCreativeTab); + this.setMaxStackSize(1); + + } + + public void onCreated(ItemStack par1ItemStack, World par2World, EntityPlayer par3EntityPlayer) + { + + } + + public void addInformation(ItemStack par1ItemStack, EntityPlayer par2EntityPlayer, List par3List, boolean par4) + { + if (DDLock.hasCreatedLock(par1ItemStack)) + { + par3List.add("Bound"); + } + else + { + par3List.add("Unbound"); + } + } + + @Override + public void registerIcons(IconRegister par1IconRegister) + { + this.itemIcon = par1IconRegister.registerIcon(mod_pocketDim.modid + ":" + this.getUnlocalizedName().replace("item.", "")); + } + + @Override + @SideOnly(Side.CLIENT) + public boolean hasEffect(ItemStack par1ItemStack) + { + return !DDLock.hasCreatedLock(par1ItemStack); + } + + public boolean onItemUse(ItemStack itemStack, EntityPlayer player, World par3World, int par4, int par5, int par6, int par7, float par8, float par9, + float par10) + { + player.setItemInUse(itemStack, this.getMaxItemUseDuration(itemStack)); + + return false; + } + + public boolean onItemUseFirst(ItemStack itemStack, EntityPlayer player, World world, int x, int y, int z, int side, float playerX, float playerY, + float playerZ) + { + if (world.isRemote) + { + return false; + } + + if (player.getItemInUse() != null) + { + return true; + } + int blockID = world.getBlockId(x, y, z); + // make sure we are dealing with a door + if (!(Block.blocksList[blockID] instanceof IDimDoor)) + { + return false; + } + + DimLink link = PocketManager.getLink(x, y, z, world); + // dont do anything to doors without links + if (link == null) + { + return false; + } + + // what to do if the door has a lock already + if (link.hasLock()) + { + if (link.doesKeyUnlock(itemStack)) + { + if (link.getLockState()) + { + world.playSoundAtEntity(player, mod_pocketDim.modid + ":keyUnlock", 1F, 1F); + } + else + { + world.playSoundAtEntity(player, mod_pocketDim.modid + ":keyLock", 1F, 1F); + } + PocketManager.getDimensionData(world).lock(link, !link.getLockState()); + PocketManager.getLinkWatcher().update(new ClientLinkData(link)); + + } + else + { + world.playSoundAtEntity(player, mod_pocketDim.modid + ":doorLocked", 1F, 1F); + } + } + else + { + if (!DDLock.hasCreatedLock(itemStack)) + { + world.playSoundAtEntity(player, mod_pocketDim.modid + ":keyLock", 1F, 1F); + PocketManager.getDimensionData(world).createLock(link, itemStack, world.rand.nextInt(Integer.MAX_VALUE)); + PocketManager.getLinkWatcher().update(new ClientLinkData(link)); + } + } + return false; + } + + /** + * Handle removal of locks here + */ + @Override + public void onPlayerStoppedUsing(ItemStack itemStack, World world, EntityPlayer player, int heldTime) + { + int j = this.getMaxItemUseDuration(itemStack) - heldTime; + if (j >= TIME_TO_UNLOCK) + { + //Raytrace to make sure we are still looking at a door + MovingObjectPosition pos = getMovingObjectPositionFromPlayer(player.worldObj, player, true); + if (pos != null && pos.typeOfHit == EnumMovingObjectType.TILE) + { + //make sure we have a link and it has a lock + DimLink link = PocketManager.getLink(pos.blockX, pos.blockY, pos.blockZ, player.worldObj); + if (link != null && link.hasLock()) + { + //make sure the given key is able to access the lock + if (link.doesKeyUnlock(itemStack) && !world.isRemote) + { + PocketManager.getDimensionData(world).removeLock(link, itemStack); + world.playSoundAtEntity(player, mod_pocketDim.modid + ":doorLockRemoved", 1F, 1F); + + } + } + } + } + player.clearItemInUse(); + + } + + /** + * Raytrace to make sure we are still looking at the right block while preparing to remove the lock + */ + @Override + public void onUsingItemTick(ItemStack stack, EntityPlayer player, int count) + { + // no need to check every tick, twice a second instead + if (count % 10 == 0) + { + MovingObjectPosition pos = getMovingObjectPositionFromPlayer(player.worldObj, player, true); + if (pos != null && pos.typeOfHit == EnumMovingObjectType.TILE) + { + DimLink link = PocketManager.getLink(pos.blockX, pos.blockY, pos.blockZ, player.worldObj); + if (link != null && link.hasLock()) + { + if (link.doesKeyUnlock(stack)) + { + return; + } + } + } + player.clearItemInUse(); + } + } + + public EnumAction getItemUseAction(ItemStack par1ItemStack) + { + return EnumAction.bow; + } + + public ItemStack onEaten(ItemStack par1ItemStack, World par2World, EntityPlayer par3EntityPlayer) + { + return par1ItemStack; + } + + public int getMaxItemUseDuration(ItemStack par1ItemStack) + { + return 72000; + } + + public String getItemStackDisplayName(ItemStack par1ItemStack) + { + return StatCollector.translateToLocal(this.getUnlocalizedName(par1ItemStack)); + } +} diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemDimensionalDoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemDimensionalDoor.java index 6804e28..18f123d 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemDimensionalDoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemDimensionalDoor.java @@ -4,16 +4,18 @@ import java.util.List; import net.minecraft.block.material.Material; import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemDoor; import net.minecraft.item.ItemStack; import net.minecraft.world.World; import StevenDimDoors.mod_pocketDim.mod_pocketDim; +import StevenDimDoors.mod_pocketDim.blocks.BaseDimDoor; public class ItemDimensionalDoor extends BaseItemDoor { - public ItemDimensionalDoor(int itemID, Material material) - { - super(itemID, material); - } + public ItemDimensionalDoor(int itemID, Material material, ItemDoor door) + { + super(itemID, material, door); + } @SuppressWarnings({ "rawtypes", "unchecked" }) @Override @@ -26,23 +28,8 @@ public class ItemDimensionalDoor extends BaseItemDoor } @Override - public ItemStack onItemRightClick(ItemStack stack, World world, EntityPlayer player) + protected BaseDimDoor getDoorBlock() { - if (!world.isRemote) - { - if (tryPlacingDoor(mod_pocketDim.dimensionalDoor, world, player, stack) && - !player.capabilities.isCreativeMode) - { - stack.stackSize--; - } - } - return stack; - } - - @Override - public boolean onItemUse(ItemStack stack, EntityPlayer player, World world, int x, int y, - int z, int par7, float par8, float par9, float par10) - { - return tryItemUse(mod_pocketDim.dimensionalDoor, stack, player, world, x, y, z, par7, false, true); + return (BaseDimDoor) mod_pocketDim.dimensionalDoor; } } \ No newline at end of file diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemGoldDimDoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemGoldDimDoor.java index a39a24a..abf9f09 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemGoldDimDoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemGoldDimDoor.java @@ -4,19 +4,20 @@ import java.util.List; import net.minecraft.block.material.Material; import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemDoor; import net.minecraft.item.ItemStack; import net.minecraft.world.World; import StevenDimDoors.mod_pocketDim.mod_pocketDim; +import StevenDimDoors.mod_pocketDim.blocks.BaseDimDoor; public class ItemGoldDimDoor extends BaseItemDoor { - public ItemGoldDimDoor(int itemID, Material material) { - super(itemID, material); - // TODO Auto-generated constructor stub - } + public ItemGoldDimDoor(int itemID, Material material, ItemDoor door) + { + super(itemID, material, door); + } - @SuppressWarnings({ "rawtypes", "unchecked" }) @Override public void addInformation(ItemStack par1ItemStack, EntityPlayer par2EntityPlayer, List par3List, boolean par4) @@ -27,26 +28,8 @@ public class ItemGoldDimDoor extends BaseItemDoor } @Override - public boolean onItemUse(ItemStack stack, EntityPlayer player, World world, int x, int y, - int z, int par7, float par8, float par9, float par10) + protected BaseDimDoor getDoorBlock() { - return tryItemUse(mod_pocketDim.goldenDimensionalDoor, stack, player, world, x, y, z, par7, false, true); + return (BaseDimDoor) mod_pocketDim.goldenDimensionalDoor; } - - @Override - public ItemStack onItemRightClick(ItemStack stack, World world, EntityPlayer player) - { - if (!world.isRemote) - { - if (tryPlacingDoor(mod_pocketDim.goldenDimensionalDoor, world, player, stack) && - !player.capabilities.isCreativeMode) - { - stack.stackSize--; - } - } - return stack; - } - - - } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemGoldDoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemGoldDoor.java index 204343d..252c1b6 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemGoldDoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemGoldDoor.java @@ -15,6 +15,7 @@ public class ItemGoldDoor extends ItemDoor public ItemGoldDoor(int par1, Material par2Material) { super(par1, par2Material); + this.setMaxStackSize(16); } @Override diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemPersonalDoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemPersonalDoor.java new file mode 100644 index 0000000..02d6b8a --- /dev/null +++ b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemPersonalDoor.java @@ -0,0 +1,35 @@ +package StevenDimDoors.mod_pocketDim.items; + +import java.util.List; + +import net.minecraft.block.material.Material; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemDoor; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; +import StevenDimDoors.mod_pocketDim.mod_pocketDim; +import StevenDimDoors.mod_pocketDim.blocks.BaseDimDoor; + +public class ItemPersonalDoor extends BaseItemDoor +{ + public ItemPersonalDoor(int itemID, Material material, ItemDoor door) + { + super(itemID, material, door); + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Override + public void addInformation(ItemStack par1ItemStack, EntityPlayer par2EntityPlayer, List par3List, boolean par4) + { + par3List.add("Creates a pathway to"); + par3List.add("Your personal pocket"); + + + } + + @Override + protected BaseDimDoor getDoorBlock() + { + return (BaseDimDoor) mod_pocketDim.personalDimDoor; + } +} \ No newline at end of file diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemQuartzDoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemQuartzDoor.java new file mode 100644 index 0000000..34d226d --- /dev/null +++ b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemQuartzDoor.java @@ -0,0 +1,58 @@ +package StevenDimDoors.mod_pocketDim.items; + +import StevenDimDoors.mod_pocketDim.mod_pocketDim; +import net.minecraft.block.Block; +import net.minecraft.block.material.Material; +import net.minecraft.client.renderer.texture.IconRegister; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemDoor; +import net.minecraft.item.ItemStack; +import net.minecraft.util.MathHelper; +import net.minecraft.world.World; + +public class ItemQuartzDoor extends ItemDoor +{ + public ItemQuartzDoor(int par1, Material par2Material) + { + super(par1, par2Material); + } + + @Override + public void registerIcons(IconRegister par1IconRegister) + { + this.itemIcon = par1IconRegister.registerIcon(mod_pocketDim.modid + ":" + this.getUnlocalizedName().replace("item.", "")); + } + + @Override + public boolean onItemUse(ItemStack par1ItemStack, EntityPlayer par2EntityPlayer, World par3World, int par4, int par5, int par6, int par7, float par8, float par9, float par10) + { + if (par7 != 1) + { + return false; + } + else + { + ++par5; + Block block = mod_pocketDim.quartzDoor; + + if (par2EntityPlayer.canPlayerEdit(par4, par5, par6, par7, par1ItemStack) && par2EntityPlayer.canPlayerEdit(par4, par5 + 1, par6, par7, par1ItemStack)) + { + if (!block.canPlaceBlockAt(par3World, par4, par5, par6)) + { + return false; + } + else + { + int i1 = MathHelper.floor_double((par2EntityPlayer.rotationYaw + 180.0F) * 4.0F / 360.0F - 0.5D) & 3; + placeDoorBlock(par3World, par4, par5, par6, i1, block); + --par1ItemStack.stackSize; + return true; + } + } + else + { + return false; + } + } + } +} diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemRiftBlade.java b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemRiftBlade.java index ceee388..d846251 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemRiftBlade.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemRiftBlade.java @@ -20,8 +20,8 @@ import net.minecraft.util.MathHelper; import net.minecraft.util.MovingObjectPosition; import net.minecraft.util.Vec3; import net.minecraft.world.World; -import StevenDimDoors.mod_pocketDim.DDProperties; import StevenDimDoors.mod_pocketDim.mod_pocketDim; +import StevenDimDoors.mod_pocketDim.config.DDProperties; import StevenDimDoors.mod_pocketDim.core.PocketManager; import com.google.common.collect.Multimap; import cpw.mods.fml.relauncher.Side; @@ -36,41 +36,9 @@ public class ItemRiftBlade extends ItemSword super(itemID, EnumToolMaterial.EMERALD); this.setCreativeTab(mod_pocketDim.dimDoorsCreativeTab); - this.setMaxStackSize(1); - this.setMaxDamage(500); - this.hasSubtypes = false; this.properties = properties; } - - @Override - @SideOnly(Side.CLIENT) - public boolean isFull3D() - { - return true; - } - - @Override - public float getStrVsBlock(ItemStack par1ItemStack, Block par2Block) - { - if (par2Block.blockID == Block.web.blockID) - { - return 15.0F; - } - else - { - Material material = par2Block.blockMaterial; - return material != Material.plants && material != Material.vine && material != Material.coral && material != Material.leaves && material != Material.pumpkin ? 1.0F : 1.5F; - } - } - - @Override - public Multimap getItemAttributeModifiers() - { - Multimap multimap = super.getItemAttributeModifiers(); - multimap.put(SharedMonsterAttributes.attackDamage.getAttributeUnlocalizedName(), new AttributeModifier(field_111210_e, "Weapon modifier", (double)7, 0)); - return multimap; - } - + @Override @SideOnly(Side.CLIENT) public boolean hasEffect(ItemStack par1ItemStack) @@ -78,13 +46,6 @@ public class ItemRiftBlade extends ItemSword return true; } - @Override - public boolean hitEntity(ItemStack par1ItemStack, EntityLivingBase par2EntityLiving, EntityLivingBase par3EntityLiving) - { - par1ItemStack.damageItem(1, par3EntityLiving); - return true; - } - @Override public MovingObjectPosition getMovingObjectPositionFromPlayer(World par1World, EntityPlayer par2EntityPlayer, boolean par3) { @@ -147,7 +108,7 @@ public class ItemRiftBlade extends ItemSword if (!world.isRemote) { @SuppressWarnings("unchecked") - List list = world.getEntitiesWithinAABB(EntityLiving.class, AxisAlignedBB.getBoundingBox(player.posX-8,player.posY-8, player.posZ-8, player.posX+8,player.posY+8, player.posZ+8)); + List list = world.getEntitiesWithinAABB(EntityLiving.class, AxisAlignedBB.getBoundingBox(player.posX-10,player.posY-10, player.posZ-10, player.posX+10,player.posY+10, player.posZ+10)); list.remove(player); for (EntityLiving ent : list) @@ -223,8 +184,7 @@ public class ItemRiftBlade extends ItemSword @SideOnly(Side.CLIENT) public void addInformation(ItemStack par1ItemStack, EntityPlayer par2EntityPlayer, List par3List, boolean par4) { - par3List.add("Creates temporary doors"); - par3List.add("on rifts, rotates doors,"); + par3List.add("Opens temporary doors on rifts"); par3List.add("and has a teleport attack."); } } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemRiftSignature.java b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemRiftSignature.java index 6f5c5b8..c3b58d8 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemRiftSignature.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemRiftSignature.java @@ -1,7 +1,6 @@ package StevenDimDoors.mod_pocketDim.items; import java.util.List; - import net.minecraft.block.Block; import net.minecraft.client.renderer.texture.IconRegister; import net.minecraft.entity.player.EntityPlayer; @@ -14,7 +13,7 @@ import net.minecraftforge.common.DimensionManager; import StevenDimDoors.mod_pocketDim.mod_pocketDim; import StevenDimDoors.mod_pocketDim.blocks.BaseDimDoor; import StevenDimDoors.mod_pocketDim.core.DimLink; -import StevenDimDoors.mod_pocketDim.core.LinkTypes; +import StevenDimDoors.mod_pocketDim.core.LinkType; import StevenDimDoors.mod_pocketDim.core.NewDimData; import StevenDimDoors.mod_pocketDim.core.PocketManager; import StevenDimDoors.mod_pocketDim.util.Point4D; @@ -34,12 +33,13 @@ public class ItemRiftSignature extends Item @SideOnly(Side.CLIENT) @Override - public boolean hasEffect(ItemStack stack) + public boolean hasEffect(ItemStack stack, int pass) { //Make the item glow if it has one endpoint stored return (stack.getItemDamage() != 0); } + @Override public void registerIcons(IconRegister par1IconRegister) { this.itemIcon = par1IconRegister.registerIcon(mod_pocketDim.modid + ":" + this.getUnlocalizedName().replace("item.", "")); @@ -60,50 +60,47 @@ public class ItemRiftSignature extends Item return false; } - y += 2; //Increase y by 2 to place the rift at head level - if (!player.canPlayerEdit(x, y, z, side, stack)) + //Increase y by 2 to place the rift at head level + int adjustedY = adjustYForSpecialBlocks(world, x, y + 2, z); + if (!player.canPlayerEdit(x, adjustedY, z, side, stack)) { return true; } - int adjustedY = adjustYForSpecialBlocks(world,x,y,z); Point4DOrientation source = getSource(stack); - int orientation = MathHelper.floor_double((double) ((player.rotationYaw + 180.0F) * 4.0F / 360.0F) - 0.5D) & 3; + 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()); - DimLink reverse = destinationDimension.createLink(x, adjustedY, z, LinkTypes.NORMAL,orientation); - destinationDimension.setDestination(link, x, adjustedY, z); - sourceDimension.setDestination(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); - } + DimLink link = sourceDimension.createLink(source.getX(), source.getY(), source.getZ(), LinkType.NORMAL,source.getOrientation()); + DimLink reverse = destinationDimension.createLink(x, adjustedY, z, LinkType.NORMAL,orientation); - //Try placing a rift at the source point, but check if its world is loaded first + destinationDimension.setLinkDestination(link, x, adjustedY, z); + sourceDimension.setLinkDestination(reverse, source.getX(), source.getY(), source.getZ()); + + // Try placing a rift at the destination point + mod_pocketDim.blockRift.tryPlacingRift(world, x, adjustedY, z); + + // 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 { //The link signature has not been used. Store its current target as the first location. - setSource(stack, x, adjustedY, z,orientation, PocketManager.getDimensionData(world)); + setSource(stack, x, adjustedY, z, orientation, PocketManager.createDimensionData(world)); mod_pocketDim.sendChat(player,("Location Stored in Rift Signature")); world.playSoundAtEntity(player,mod_pocketDim.modid+":riftStart", 0.6f, 1); } @@ -113,6 +110,7 @@ public class ItemRiftSignature extends Item /** * allows items to add custom lines of information to the mouseover description */ + @Override @SuppressWarnings({ "unchecked", "rawtypes" }) @SideOnly(Side.CLIENT) public void addInformation(ItemStack par1ItemStack, EntityPlayer par2EntityPlayer, List par3List, boolean par4) @@ -140,22 +138,28 @@ public class ItemRiftSignature extends Item */ public static int adjustYForSpecialBlocks(World world, int x, int y, int z) { - y=y-2;//get the block the player actually clicked on - Block block = Block.blocksList[world.getBlockId(x, y, z)]; - if(block.isBlockReplaceable(world, x, y, z)) + int targetY = y - 2; // Get the block the player actually clicked on + Block block = Block.blocksList[world.getBlockId(x, targetY, z)]; + if (block == null) { - return y+1;//move block placement down (-2+1) one so its directly over things like snow + return targetY + 2; } - if(block instanceof BaseDimDoor) + if (block.isBlockReplaceable(world, x, targetY, z)) { - if(world.getBlockId(x, y-1, z)==block.blockID&&world.getBlockMetadata(x, y, z)==8) + return targetY + 1; // Move block placement down (-2+1) one so its directly over things like snow + } + if (block instanceof BaseDimDoor) + { + if (((BaseDimDoor) block).isUpperDoorBlock(world.getBlockMetadata(x, targetY, z))) { - return y;//move rift placement down two so its in the right place on the door. + return targetY; // Move rift placement down two so its in the right place on the door. } - return y+1; + // Move rift placement down one so its in the right place on the door. + return targetY + 1; } - return y+2; + return targetY + 2; } + public static void setSource(ItemStack itemStack, int x, int y, int z, int orientation, NewDimData dimension) { NBTTagCompound tag = new NBTTagCompound(); @@ -196,11 +200,12 @@ public class ItemRiftSignature extends Item Integer orientation = tag.getInteger("orientation"); Integer dimID = tag.getInteger("linkDimID"); - if (x != null && y != null && z != null && dimID != null) + if (x != null && y != null && z != null && orientation != null && dimID != null) { - return new Point4DOrientation(x, y, z,orientation, dimID); + return new Point4DOrientation(x, y, z, orientation, dimID); } } + // Mark the item as uninitialized if its source couldn't be read itemStack.setItemDamage(0); } return null; @@ -210,10 +215,11 @@ public class ItemRiftSignature extends Item { private Point4D point; private int orientation; + Point4DOrientation(int x, int y, int z, int orientation, int dimID) { - this.point= new Point4D(x,y,z,dimID); - this.orientation=orientation; + this.point = new Point4D(x, y, z, dimID); + this.orientation = orientation; } int getX() @@ -235,10 +241,16 @@ public class ItemRiftSignature extends Item { return point.getDimension(); } + int getOrientation() { return orientation; } + + Point4D getPoint() + { + return point; + } } } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemStabilizedRiftSignature.java b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemStabilizedRiftSignature.java index c17da83..f97bb8c 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemStabilizedRiftSignature.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemStabilizedRiftSignature.java @@ -1,7 +1,6 @@ package StevenDimDoors.mod_pocketDim.items; import java.util.List; - import net.minecraft.client.renderer.texture.IconRegister; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.Item; @@ -11,10 +10,9 @@ import net.minecraft.world.World; import net.minecraftforge.common.DimensionManager; import StevenDimDoors.mod_pocketDim.mod_pocketDim; import StevenDimDoors.mod_pocketDim.core.DimLink; -import StevenDimDoors.mod_pocketDim.core.LinkTypes; +import StevenDimDoors.mod_pocketDim.core.LinkType; import StevenDimDoors.mod_pocketDim.core.NewDimData; import StevenDimDoors.mod_pocketDim.core.PocketManager; -import StevenDimDoors.mod_pocketDim.util.Point4D; import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; @@ -40,69 +38,124 @@ public class ItemStabilizedRiftSignature extends ItemRiftSignature return false; } - // We don't check for replaceable blocks. The user can deal with that. <_< - y += 2; //Increase y by 2 to place the rift at head level - if (!player.canPlayerEdit(x, y, z, side, stack)) + // Adjust Y so the rift is at head level, depending on the presence of certain blocks + int adjustedY = adjustYForSpecialBlocks(world, x, y + 2, z); + if (!player.canPlayerEdit(x, adjustedY, z, side, stack)) { return true; } - Point4DOrientation source = getSource(stack); - int adjustedY = adjustYForSpecialBlocks(world,x,y,z); + int orientation = MathHelper.floor_double((player.rotationYaw + 180.0F) * 4.0F / 360.0F - 0.5D) & 3; // Check if the Stabilized Rift Signature has been initialized - int orientation = MathHelper.floor_double((player.rotationYaw + 180.0F) * 4.0F / 360.0F - 0.5D) & 3; + Point4DOrientation source = getSource(stack); if (source != null) { - // Yes, it's initialized. Check if the player is in creative - // or if the player can pay with Stable Fabric to create a rift. - if (!player.capabilities.isCreativeMode && !player.inventory.hasItem(mod_pocketDim.itemStableFabric.itemID)) - { - mod_pocketDim.sendChat(player, "You don't have any Stable Fabric!"); - // I won't do this, but this is the chance to localize chat - // messages sent to the player; look at ChatMessageComponent - // and how MFR does it with items like the safari net launcher - return true; - } - //The link was used before and already has an endpoint stored. Create links connecting the two endpoints. + // Yes, it's initialized. 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()); - DimLink reverse = destinationDimension.createLink(x, adjustedY, z, LinkTypes.NORMAL,orientation); - destinationDimension.setDestination(link, x, adjustedY, z); - sourceDimension.setDestination(reverse, source.getX(), source.getY(), source.getZ()); - - //Try placing a rift at the destination point - if (!mod_pocketDim.blockRift.isBlockImmune(world, x, adjustedY, z)) + NewDimData destinationDimension = PocketManager.createDimensionData(world); + DimLink reverse = destinationDimension.getLink(x, adjustedY, z); + DimLink link; + + // Check whether the SRS is being used to restore one of its previous + // link pairs. In other words, the SRS is being used on a location + // that already has a link pointing to the SRS's source, with the + // intention of overwriting the source-side link to point there. + // Those benign redirection operations will be handled for free. + + if (reverse != null && source.getPoint().equals(reverse.destination())) { - world.setBlock(x, adjustedY, z, mod_pocketDim.blockRift.blockID); + // Only the source-to-destination link is needed. + link = sourceDimension.createLink(source.getX(), source.getY(), source.getZ(), LinkType.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 + else + { + // Check if the player is in creative mode, + // or if the player can pay with an Ender Pearl to create a rift. + if (!player.capabilities.isCreativeMode && + !player.inventory.consumeInventoryItem(Item.enderPearl.itemID)) + { + mod_pocketDim.sendChat(player, "You don't have any Ender Pearls!"); + // I won't do this, but this is the chance to localize chat + // messages sent to the player; look at ChatMessageComponent + // and how MFR does it with items like the safari net launcher + return true; + } + + // Create links connecting the two endpoints. + link = sourceDimension.createLink(source.getX(), source.getY(), source.getZ(), LinkType.NORMAL, source.getOrientation()); + reverse = destinationDimension.createLink(x, adjustedY, z, LinkType.NORMAL, orientation); + destinationDimension.setLinkDestination(link, x, adjustedY, z); + sourceDimension.setLinkDestination(reverse, source.getX(), source.getY(), source.getZ()); + + // Try placing a rift at the destination point + mod_pocketDim.blockRift.tryPlacingRift(world, x, adjustedY, z); + } + + // 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); - } - - if (!player.capabilities.isCreativeMode) - { - player.inventory.consumeInventoryItem(mod_pocketDim.itemStableFabric.itemID); - } - mod_pocketDim.sendChat(player,"Rift Created"); - world.playSoundAtEntity(player,"mods.DimDoors.sfx.riftEnd", 0.6f, 1); + + 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); } else { - //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); + // The link signature has not been used. Store its current target as the first location. + setSource(stack, x, adjustedY, z, orientation, PocketManager.createDimensionData(world)); + mod_pocketDim.sendChat(player, "Location Stored in Stabilized Rift Signature"); + world.playSoundAtEntity(player, "mods.DimDoors.sfx.riftStart", 0.6f, 1); } return true; } + public static boolean useFromDispenser(ItemStack stack, World world, int x, int y, int z) + { + // Stabilized Rift Signatures can only be used from dispensers to restore + // a previous link pair. The operation would be free for a player, so + // dispensers can also perform it for free. Otherwise, the item does nothing. + if (world.isRemote) + { + return false; + } + + // Adjust Y so the rift is at head level, depending on the presence of certain blocks + int adjustedY = adjustYForSpecialBlocks(world, x, y + 2, z); + Point4DOrientation source = getSource(stack); + + // The SRS must have been initialized + if (source != null) + { + NewDimData sourceDimension = PocketManager.getDimensionData(source.getDimension()); + NewDimData destinationDimension = PocketManager.createDimensionData(world); + DimLink reverse = destinationDimension.getLink(x, adjustedY, z); + DimLink link; + + // Check whether the SRS is being used to restore one of its previous + // link pairs. In other words, the SRS is being used on a location + // that already has a link pointing to the SRS's source, with the + // intention of overwriting the source-side link to point there. + if (reverse != null && source.getPoint().equals(reverse.destination())) + { + // Only the source-to-destination link is needed. + link = sourceDimension.createLink(source.getX(), source.getY(), source.getZ(), LinkType.NORMAL, source.getOrientation()); + destinationDimension.setLinkDestination(link, x, adjustedY, z); + + // 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()); + 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); + return true; + } + } + return false; + } + /** * allows items to add custom lines of information to the mouseover description */ @@ -119,8 +172,8 @@ public class ItemStabilizedRiftSignature extends ItemRiftSignature else { par3List.add("First click stores a location,"); - par3List.add("second click creates two rifts"); - par3List.add("that link the locations together."); + par3List.add("other clicks create rifts linking"); + par3List.add("the first and last locations together."); } } } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemUnstableDoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemUnstableDoor.java index a7d63ec..e51bcaa 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemUnstableDoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemUnstableDoor.java @@ -4,15 +4,17 @@ import java.util.List; import net.minecraft.block.material.Material; import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemDoor; import net.minecraft.item.ItemStack; import net.minecraft.world.World; import StevenDimDoors.mod_pocketDim.mod_pocketDim; +import StevenDimDoors.mod_pocketDim.blocks.BaseDimDoor; public class ItemUnstableDoor extends BaseItemDoor { - public ItemUnstableDoor(int itemID, Material material) + public ItemUnstableDoor(int itemID, Material material, ItemDoor door) { - super(itemID, material); + super(itemID, material, door); } @SuppressWarnings({ "unchecked", "rawtypes" }) @@ -23,23 +25,8 @@ public class ItemUnstableDoor extends BaseItemDoor } @Override - public ItemStack onItemRightClick(ItemStack stack, World world, EntityPlayer player) + protected BaseDimDoor getDoorBlock() { - if (!world.isRemote) - { - if (tryPlacingDoor(mod_pocketDim.unstableDoor, world, player, stack) && - !player.capabilities.isCreativeMode) - { - stack.stackSize--; - } - } - return stack; - } - - @Override - public boolean onItemUse(ItemStack stack, EntityPlayer player, World world, int x, int y, - int z, int par7, float par8, float par9, float par10) - { - return tryItemUse(mod_pocketDim.unstableDoor, stack, player, world, x, y, z, par7, false, true); + return (BaseDimDoor) mod_pocketDim.unstableDoor; } } \ No newline at end of file diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemWarpDoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemWarpDoor.java index 0309a3f..403bbc1 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemWarpDoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemWarpDoor.java @@ -4,15 +4,17 @@ import java.util.List; import net.minecraft.block.material.Material; import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemDoor; import net.minecraft.item.ItemStack; import net.minecraft.world.World; import StevenDimDoors.mod_pocketDim.mod_pocketDim; +import StevenDimDoors.mod_pocketDim.blocks.BaseDimDoor; public class ItemWarpDoor extends BaseItemDoor { - public ItemWarpDoor(int itemID, Material material) + public ItemWarpDoor(int itemID, Material material, ItemDoor door) { - super(itemID, material); + super(itemID, material, door); } @SuppressWarnings({ "unchecked", "rawtypes" }) @@ -26,23 +28,8 @@ public class ItemWarpDoor extends BaseItemDoor } @Override - public ItemStack onItemRightClick(ItemStack stack, World world, EntityPlayer player) + protected BaseDimDoor getDoorBlock() { - if (!world.isRemote) - { - if (tryPlacingDoor(mod_pocketDim.warpDoor, world, player, stack) && - !player.capabilities.isCreativeMode) - { - stack.stackSize--; - } - } - return stack; - } - - @Override - public boolean onItemUse(ItemStack stack, EntityPlayer player, World world, int x, int y, - int z, int par7, float par8, float par9, float par10) - { - return tryItemUse(mod_pocketDim.warpDoor, stack, player, world, x, y, z, par7, false, true); + return (BaseDimDoor) mod_pocketDim.warpDoor; } } \ No newline at end of file diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/items/behaviors/DispenserBehaviorStabilizedRS.java b/src/main/java/StevenDimDoors/mod_pocketDim/items/behaviors/DispenserBehaviorStabilizedRS.java new file mode 100644 index 0000000..f79fe26 --- /dev/null +++ b/src/main/java/StevenDimDoors/mod_pocketDim/items/behaviors/DispenserBehaviorStabilizedRS.java @@ -0,0 +1,42 @@ +package StevenDimDoors.mod_pocketDim.items.behaviors; + +import net.minecraft.block.BlockDispenser; +import net.minecraft.dispenser.BehaviorDefaultDispenseItem; +import net.minecraft.dispenser.IBlockSource; +import net.minecraft.item.ItemStack; +import net.minecraft.util.EnumFacing; +import net.minecraft.world.World; +import StevenDimDoors.mod_pocketDim.items.ItemStabilizedRiftSignature; + +public class DispenserBehaviorStabilizedRS extends BehaviorDefaultDispenseItem +{ + @Override + public ItemStack dispenseStack(IBlockSource dispenser, ItemStack stack) + { + // Search for a non-air block up to 3 blocks in front of a dispenser. + // If it's found, call ItemStabilizedRiftSignature.useFromDispenser(). + int x = dispenser.getXInt(); + int y = dispenser.getYInt(); + int z = dispenser.getZInt(); + EnumFacing facing = BlockDispenser.getFacing(dispenser.getBlockMetadata()); + int dx = facing.getFrontOffsetX(); + int dy = facing.getFrontOffsetY(); + int dz = facing.getFrontOffsetZ(); + World world = dispenser.getWorld(); + + for (int k = 1; k <= 3; k++) + { + x += dx; + y += dy; + z += dz; + if (!world.isAirBlock(x, y, z)) + { + // Found a block. Activate the item. + ItemStabilizedRiftSignature.useFromDispenser(stack, world, x, y, z); + break; + } + } + // The item stack isn't modified + return stack; + } +} diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/items/itemRiftRemover.java b/src/main/java/StevenDimDoors/mod_pocketDim/items/itemRiftRemover.java index c95b472..e1ecef9 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/items/itemRiftRemover.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/items/itemRiftRemover.java @@ -54,7 +54,7 @@ public class itemRiftRemover extends Item int hx = hit.blockX; int hy = hit.blockY; int hz = hit.blockZ; - NewDimData dimension = PocketManager.getDimensionData(world); + NewDimData dimension = PocketManager.createDimensionData(world); DimLink link = dimension.getLink(hx, hy, hz); if (world.getBlockId(hx, hy, hz) == mod_pocketDim.blockRift.blockID && link != null && player.canPlayerEdit(hx, hy, hz, hit.sideHit, stack)) @@ -85,7 +85,7 @@ public class itemRiftRemover extends Item y = hit.blockY; z = hit.blockZ; - NewDimData dimension = PocketManager.getDimensionData(world); + NewDimData dimension = PocketManager.createDimensionData(world); DimLink link = dimension.getLink(x, y, z); if (world.getBlockId(x, y, z) == mod_pocketDim.blockRift.blockID && link != null && player.canPlayerEdit(x, y, z, side, stack)) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java b/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java index c52aa5f..b4d6069 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java @@ -1,7 +1,6 @@ package StevenDimDoors.mod_pocketDim; import java.io.File; - import net.minecraft.block.Block; import net.minecraft.block.material.Material; import net.minecraft.creativetab.CreativeTabs; @@ -9,38 +8,46 @@ import net.minecraft.entity.EntityEggInfo; import net.minecraft.entity.EntityList; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.Item; +import net.minecraft.item.ItemDoor; import net.minecraft.item.ItemStack; import net.minecraft.util.ChatMessageComponent; import net.minecraft.world.biome.BiomeGenBase; import net.minecraftforge.common.DimensionManager; import net.minecraftforge.common.ForgeChunkManager; import net.minecraftforge.common.MinecraftForge; -import net.minecraftforge.fluids.Fluid; import StevenDimDoors.mod_pocketDim.blocks.BlockDimWall; import StevenDimDoors.mod_pocketDim.blocks.BlockDimWallPerm; import StevenDimDoors.mod_pocketDim.blocks.BlockDoorGold; +import StevenDimDoors.mod_pocketDim.blocks.BlockDoorQuartz; import StevenDimDoors.mod_pocketDim.blocks.BlockGoldDimDoor; import StevenDimDoors.mod_pocketDim.blocks.BlockLimbo; import StevenDimDoors.mod_pocketDim.blocks.BlockRift; import StevenDimDoors.mod_pocketDim.blocks.DimensionalDoor; +import StevenDimDoors.mod_pocketDim.blocks.PersonalDimDoor; import StevenDimDoors.mod_pocketDim.blocks.TransTrapdoor; import StevenDimDoors.mod_pocketDim.blocks.TransientDoor; import StevenDimDoors.mod_pocketDim.blocks.UnstableDoor; import StevenDimDoors.mod_pocketDim.blocks.WarpDoor; import StevenDimDoors.mod_pocketDim.commands.CommandCreateDungeonRift; import StevenDimDoors.mod_pocketDim.commands.CommandCreatePocket; -import StevenDimDoors.mod_pocketDim.commands.CommandDeleteAllLinks; +import StevenDimDoors.mod_pocketDim.commands.CommandCreateRandomRift; import StevenDimDoors.mod_pocketDim.commands.CommandDeleteRifts; import StevenDimDoors.mod_pocketDim.commands.CommandExportDungeon; +import StevenDimDoors.mod_pocketDim.commands.CommandListDungeons; import StevenDimDoors.mod_pocketDim.commands.CommandResetDungeons; import StevenDimDoors.mod_pocketDim.commands.CommandTeleportPlayer; +import StevenDimDoors.mod_pocketDim.config.DDProperties; +import StevenDimDoors.mod_pocketDim.config.DDWorldProperties; import StevenDimDoors.mod_pocketDim.core.PocketManager; import StevenDimDoors.mod_pocketDim.helpers.ChunkLoaderHelper; import StevenDimDoors.mod_pocketDim.helpers.DungeonHelper; import StevenDimDoors.mod_pocketDim.items.ItemBlockDimWall; +import StevenDimDoors.mod_pocketDim.items.ItemDDKey; import StevenDimDoors.mod_pocketDim.items.ItemDimensionalDoor; import StevenDimDoors.mod_pocketDim.items.ItemGoldDimDoor; import StevenDimDoors.mod_pocketDim.items.ItemGoldDoor; +import StevenDimDoors.mod_pocketDim.items.ItemPersonalDoor; +import StevenDimDoors.mod_pocketDim.items.ItemQuartzDoor; import StevenDimDoors.mod_pocketDim.items.ItemRiftBlade; import StevenDimDoors.mod_pocketDim.items.ItemRiftSignature; import StevenDimDoors.mod_pocketDim.items.ItemStabilizedRiftSignature; @@ -49,23 +56,25 @@ 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; import StevenDimDoors.mod_pocketDim.tileentities.TileEntityTransTrapdoor; +import StevenDimDoors.mod_pocketDim.util.l_systems.LSystem; 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.PersonalPocketProvider; 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; @@ -73,8 +82,9 @@ import cpw.mods.fml.common.SidedProxy; import cpw.mods.fml.common.event.FMLInitializationEvent; import cpw.mods.fml.common.event.FMLPostInitializationEvent; import cpw.mods.fml.common.event.FMLPreInitializationEvent; +import cpw.mods.fml.common.event.FMLServerAboutToStartEvent; import cpw.mods.fml.common.event.FMLServerStartingEvent; -import cpw.mods.fml.common.event.FMLServerStoppingEvent; +import cpw.mods.fml.common.event.FMLServerStoppedEvent; import cpw.mods.fml.common.network.NetworkMod; import cpw.mods.fml.common.network.NetworkMod.SidedPacketHandler; import cpw.mods.fml.common.registry.EntityRegistry; @@ -92,16 +102,21 @@ serverPacketHandlerSpec = @SidedPacketHandler(channels = {PacketConstants.CHANNEL_NAME}, packetHandler = ServerPacketHandler.class)) public class mod_pocketDim { - public static final String version = "1.6.4R2.2.2RC1"; + public static final String version = "@VERSION@"; public static final String modid = "dimdoors"; + + //TODO need a place to stick all these constants + public static final int NETHER_DIMENSION_ID = -1; //need to clean up @SidedProxy(clientSide = "StevenDimDoors.mod_pocketDimClient.ClientProxy", serverSide = "StevenDimDoors.mod_pocketDim.CommonProxy") public static CommonProxy proxy; - @Instance("PocketDimensions") - public static mod_pocketDim instance = new mod_pocketDim(); + @Instance(mod_pocketDim.modid) + public static mod_pocketDim instance; + public static Block quartzDoor; + public static Block personalDimDoor; public static Block transientDoor; public static Block warpDoor; public static Block goldenDoor; @@ -119,13 +134,16 @@ public class mod_pocketDim public static Item itemWorldThread; public static Item itemRiftBlade; - public static Item itemDimensionalDoor; + public static ItemDimensionalDoor itemDimensionalDoor; public static Item itemWarpDoor; public static Item itemRiftRemover; public static Item itemRiftSignature; public static Item itemStableFabric; public static Item itemUnstableDoor; - public static Item itemStabilizedLinkSignature; + public static Item itemDDKey; + public static Item itemQuartzDoor; + public static Item itemPersonalDoor; + public static Item itemStabilizedRiftSignature; public static BiomeGenBase limboBiome; public static BiomeGenBase pocketBiome; @@ -133,10 +151,18 @@ public class mod_pocketDim public static boolean isPlayerWearingGoogles = false; 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 + private String currrentSaveRootDirectory; public static CreativeTabs dimDoorsCreativeTab = new CreativeTabs("dimDoorsCreativeTab") { @@ -156,14 +182,13 @@ public class mod_pocketDim @EventHandler public void onPreInitialization(FMLPreInitializationEvent event) { - instance = this; //This should be the FIRST thing that gets done. String path = event.getSuggestedConfigurationFile().getAbsolutePath().replace(modid, "DimDoors"); properties = DDProperties.initialize(new File(path)); //Now do other stuff - EventHookContainer hooks = new EventHookContainer(properties); + hooks = new EventHookContainer(properties); MinecraftForge.EVENT_BUS.register(hooks); MinecraftForge.TERRAIN_GEN_BUS.register(hooks); } @@ -171,45 +196,55 @@ 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"); + quartzDoor = new BlockDoorQuartz(properties.QuartzDoorID, Material.rock).setHardness(0.1F).setUnlocalizedName("doorQuartz"); + personalDimDoor = new PersonalDimDoor(properties.PersonalDimDoorID, Material.rock,properties).setHardness(0.1F).setUnlocalizedName("dimDoorPersonal"); + goldenDoor = new BlockDoorGold(properties.GoldenDoorID, Material.iron).setHardness(0.1F).setUnlocalizedName("doorGold"); blockDimWall = new BlockDimWall(properties.FabricBlockID, 0, Material.iron).setLightValue(1.0F).setHardness(0.1F).setUnlocalizedName("blockDimWall"); 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")); - itemGoldenDimensionalDoor = (new ItemGoldDimDoor(properties.GoldenDimensionalDoorItemID, Material.iron)).setUnlocalizedName("itemGoldDimDoor"); - itemGoldenDoor = (new ItemGoldDoor(properties.GoldenDoorID, Material.wood)).setUnlocalizedName("itemGoldDoor"); - itemDimensionalDoor = (new ItemDimensionalDoor(properties.DimensionalDoorItemID, Material.iron)).setUnlocalizedName("itemDimDoor"); - itemWarpDoor = (new ItemWarpDoor(properties.WarpDoorItemID, Material.wood)).setUnlocalizedName("itemDimDoorWarp"); + itemDDKey = (new ItemDDKey(properties.DDKeyItemID)).setUnlocalizedName("itemDDKey"); + itemQuartzDoor = (new ItemQuartzDoor(properties.QuartzDoorID, Material.rock)).setUnlocalizedName("itemQuartzDoor"); + itemPersonalDoor = (new ItemPersonalDoor(properties.PersonalDimDoorID, Material.rock, (ItemDoor)this.itemQuartzDoor)).setUnlocalizedName("itemQuartzDimDoor"); + itemGoldenDoor = (new ItemGoldDoor(properties.GoldenDoorItemID, Material.wood)).setUnlocalizedName("itemGoldDoor"); + itemGoldenDimensionalDoor = (new ItemGoldDimDoor(properties.GoldenDimensionalDoorItemID, Material.iron, (ItemDoor)this.itemGoldenDoor)).setUnlocalizedName("itemGoldDimDoor"); + itemDimensionalDoor = (ItemDimensionalDoor) (new ItemDimensionalDoor(properties.DimensionalDoorItemID, Material.iron, (ItemDoor)Item.doorIron)).setUnlocalizedName("itemDimDoor"); + itemWarpDoor = (new ItemWarpDoor(properties.WarpDoorItemID, Material.wood,(ItemDoor)Item.doorWood)).setUnlocalizedName("itemDimDoorWarp"); itemRiftSignature = (new ItemRiftSignature(properties.RiftSignatureItemID)).setUnlocalizedName("itemLinkSignature"); itemRiftRemover = (new itemRiftRemover(properties.RiftRemoverItemID, Material.wood)).setUnlocalizedName("itemRiftRemover"); itemStableFabric = (new ItemStableFabric(properties.StableFabricItemID, 0)).setUnlocalizedName("itemStableFabric"); - itemUnstableDoor = (new ItemUnstableDoor(properties.UnstableDoorItemID, Material.iron)).setUnlocalizedName("itemChaosDoor"); + itemUnstableDoor = (new ItemUnstableDoor(properties.UnstableDoorItemID, Material.iron, null)).setUnlocalizedName("itemChaosDoor"); itemRiftBlade = (new ItemRiftBlade(properties.RiftBladeItemID, properties)).setUnlocalizedName("ItemRiftBlade"); - itemStabilizedLinkSignature = (new ItemStabilizedRiftSignature(properties.StabilizedRiftSignatureItemID)).setUnlocalizedName("itemStabilizedRiftSig"); + itemStabilizedRiftSignature = (new ItemStabilizedRiftSignature(properties.StabilizedRiftSignatureItemID)).setUnlocalizedName("itemStabilizedRiftSig"); itemWorldThread = (new ItemWorldThread(properties.WorldThreadItemID)).setUnlocalizedName("itemWorldThread"); + // Check if other biomes have been registered with the same IDs we want. If so, crash Minecraft + // to notify the user instead of letting it pass and conflicting with Biomes o' Plenty. + DDBiomeGenBase.checkBiomes( new int[] { properties.LimboBiomeID, properties.PocketBiomeID } ); + + // Initialize our biomes mod_pocketDim.limboBiome = (new BiomeGenLimbo(properties.LimboBiomeID)); mod_pocketDim.pocketBiome = (new BiomeGenPocket(properties.PocketBiomeID)); + GameRegistry.registerBlock(quartzDoor, "Quartz Door"); + GameRegistry.registerBlock(personalDimDoor, "Personal Dimensional Door"); GameRegistry.registerBlock(goldenDoor, "Golden Door"); GameRegistry.registerBlock(goldenDimensionalDoor, "Golden Dimensional Door"); GameRegistry.registerBlock(unstableDoor, "Unstable Door"); @@ -223,8 +258,13 @@ public class mod_pocketDim GameRegistry.registerBlock(blockDimWall, ItemBlockDimWall.class, "Fabric of Reality"); - DimensionManager.registerProviderType(properties.PocketProviderID, PocketProvider.class, false); - DimensionManager.registerProviderType(properties.LimboProviderID, LimboProvider.class, false); + if (!DimensionManager.registerProviderType(properties.PocketProviderID, PocketProvider.class, false)) + throw new IllegalStateException("There is a provider ID conflict between PocketProvider from Dimensional Doors and another provider type. Fix your configuration!"); + if (!DimensionManager.registerProviderType(properties.LimboProviderID, LimboProvider.class, false)) + throw new IllegalStateException("There is a provider ID conflict between LimboProvider from Dimensional Doors and another provider type. Fix your configuration!"); + if (!DimensionManager.registerProviderType(properties.PersonalPocketProviderID, PersonalPocketProvider.class, false)) + throw new IllegalStateException("There is a provider ID conflict between PersonalPocketProvider from Dimensional Doors and another provider type. Fix your configuration!"); + DimensionManager.registerDimension(properties.LimboDimensionID, properties.LimboProviderID); LanguageRegistry.addName(goldenDoor, "Golden Door"); @@ -243,19 +283,24 @@ public class mod_pocketDim LanguageRegistry.addName(itemRiftSignature, "Rift Signature"); LanguageRegistry.addName(itemGoldenDoor, "Golden Door"); LanguageRegistry.addName(itemGoldenDimensionalDoor, "Golden Dimensional Door"); - LanguageRegistry.addName(itemStabilizedLinkSignature, "Stabilized Rift Signature"); + LanguageRegistry.addName(itemStabilizedRiftSignature, "Stabilized Rift Signature"); LanguageRegistry.addName(itemRiftRemover, "Rift Remover"); LanguageRegistry.addName(itemStableFabric, "Stable Fabric"); LanguageRegistry.addName(itemUnstableDoor, "Unstable Door"); LanguageRegistry.addName(itemDimensionalDoor, "Dimensional Door"); LanguageRegistry.addName(itemRiftBlade, "Rift Blade"); LanguageRegistry.addName(itemWorldThread, "World Thread"); + LanguageRegistry.addName(itemDDKey, "Rift Key"); + LanguageRegistry.addName(itemQuartzDoor, "Quartz Door"); + LanguageRegistry.addName(itemPersonalDoor, "Personal Dimensional Door"); + /** * Add names for multiblock inventory item */ LanguageRegistry.addName(new ItemStack(blockDimWall, 1, 0), "Fabric of Reality"); LanguageRegistry.addName(new ItemStack(blockDimWall, 1, 1), "Ancient Fabric"); + LanguageRegistry.addName(new ItemStack(blockDimWall, 1, 2), "Altered Fabric"); LanguageRegistry.instance().addStringLocalization("itemGroup.dimDoorsCustomTab", "en_US", "Dimensional Doors Items"); @@ -267,9 +312,12 @@ public class mod_pocketDim EntityRegistry.registerModEntity(MobMonolith.class, "Monolith", properties.MonolithEntityID, this, 70, 1, true); EntityList.IDtoClassMapping.put(properties.MonolithEntityID, MobMonolith.class); EntityList.entityEggs.put(properties.MonolithEntityID, new EntityEggInfo(properties.MonolithEntityID, 0, 0xffffff)); - LanguageRegistry.instance().addStringLocalization("entity.DimDoors.Obelisk.name", "Monolith"); + LanguageRegistry.instance().addStringLocalization("entity.dimdoors.Monolith.name", "Monolith"); CraftingManager.registerRecipes(properties); + CraftingManager.registerDispenserBehaviors(); + GameRegistry.registerCraftingHandler(new CraftingManager()); + DungeonHelper.initialize(); gatewayGenerator = new GatewayGenerator(properties); GameRegistry.registerWorldGenerator(mod_pocketDim.gatewayGenerator); @@ -278,60 +326,120 @@ public class mod_pocketDim DDLoot.registerInfo(properties); proxy.loadTextures(); proxy.registerRenderers(); + + LSystem.generateLSystem("terdragon", LSystem.TERDRAGON, 4); + LSystem.generateLSystem("terdragon", LSystem.TERDRAGON, 5); + // LSystem.generateLSystem("terdragon", LSystem.TERDRAGON, 6); //degenerate + LSystem.generateLSystem("terdragon", LSystem.TERDRAGON, 7); + // LSystem.generateLSystem("terdragon", LSystem.TERDRAGON, 8); + // LSystem.generateLSystem("terdragon", LSystem.TERDRAGON, 9); + + + // LSystem.generateLSystem("vortex", LSystem.VORTEX, 8); + LSystem.generateLSystem("vortex", LSystem.VORTEX, 9); + LSystem.generateLSystem("vortex", LSystem.VORTEX, 10); + LSystem.generateLSystem("vortex", LSystem.VORTEX, 11); + // LSystem.generateLSystem("vortex", LSystem.VORTEX, 12); + + LSystem.generateLSystem("twindragon", LSystem.TWINDRAGON, 7); + LSystem.generateLSystem("twindragon", LSystem.TWINDRAGON, 8); + LSystem.generateLSystem("twindragon", LSystem.TWINDRAGON, 9); + LSystem.generateLSystem("twindragon", LSystem.TWINDRAGON, 10); + // LSystem.generateLSystem("twindragon", LSystem.TWINDRAGON, 11); + + + LSystem.generateLSystem("dragon", LSystem.DRAGON, 8); + LSystem.generateLSystem("dragon", LSystem.DRAGON, 9); + LSystem.generateLSystem("dragon", LSystem.DRAGON, 10); + LSystem.generateLSystem("dragon", LSystem.DRAGON, 11); + // LSystem.generateLSystem("dragon", LSystem.DRAGON, 12); + // LSystem.generateLSystem("dragon", LSystem.DRAGON, 13); + + } @EventHandler public void onPostInitialization(FMLPostInitializationEvent event) - { + { + // Check in case other mods have registered over our biome IDs + DDBiomeGenBase.checkBiomes( new int[] { properties.LimboBiomeID, properties.PocketBiomeID } ); + ForgeChunkManager.setForcedChunkLoadingCallback(instance, new ChunkLoaderHelper()); } @EventHandler - public void onServerStopping(FMLServerStoppingEvent event) + public void onServerStopped(FMLServerStoppedEvent event) { try { PocketManager.unload(); deathTracker.writeToFile(); deathTracker = null; + worldProperties = 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) { e.printStackTrace(); } } + + @EventHandler + public void onServerAboutToStart(FMLServerAboutToStartEvent event) + { + currrentSaveRootDirectory = DimensionManager.getCurrentSaveRootDirectory().getAbsolutePath(); + + // Load the config file that's specific to this world + worldProperties = new DDWorldProperties(new File(currrentSaveRootDirectory + "/DimensionalDoors/DimDoorsWorld.cfg")); + + // 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 public void onServerStarting(FMLServerStartingEvent event) { - //TODO- load dims with forced chunks on server startup here - // Register commands with the server - CommandResetDungeons.instance().register(event); - CommandCreateDungeonRift.instance().register(event); - CommandDeleteAllLinks.instance().register(event); - //CommandDeleteDimensionData.instance().register(event); - CommandDeleteRifts.instance().register(event); - CommandExportDungeon.instance().register(event); - //CommandPrintDimensionData.instance().register(event); - //CommandPruneDimensions.instance().register(event); - CommandCreatePocket.instance().register(event); - CommandTeleportPlayer.instance().register(event); - - // Initialize a new DeathTracker - String deathTrackerFile = DimensionManager.getCurrentSaveRootDirectory() + "/DimensionalDoors/data/deaths.txt"; - deathTracker = new DeathTracker(deathTrackerFile); + event.registerServerCommand( CommandResetDungeons.instance() ); + event.registerServerCommand( CommandCreateDungeonRift.instance() ); + event.registerServerCommand( CommandListDungeons.instance() ); + event.registerServerCommand( CommandCreateRandomRift.instance() ); + event.registerServerCommand( CommandDeleteRifts.instance() ); + event.registerServerCommand( CommandExportDungeon.instance() ); + event.registerServerCommand( CommandCreatePocket.instance() ); + event.registerServerCommand( CommandTeleportPlayer.instance() ); try { - ChunkLoaderHelper.loadChunkForcedWorlds(event); + ChunkLoaderHelper.loadForcedChunkWorlds(event); } catch (Exception e) { - System.out.println("Loading chunkloaders failed"); + System.err.println("Failed to load chunk loaders for Dimensional Doors. The following error occurred:"); + System.err.println(e.toString()); } } + public String getCurrentSavePath() + { + return this.currrentSaveRootDirectory; + } + public static void sendChat(EntityPlayer player, String message) { ChatMessageComponent cmp = new ChatMessageComponent(); diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/saving/DDSaveHandler.java b/src/main/java/StevenDimDoors/mod_pocketDim/saving/DDSaveHandler.java index fb39f5b..0d9cd8a 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/saving/DDSaveHandler.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/saving/DDSaveHandler.java @@ -2,29 +2,25 @@ package StevenDimDoors.mod_pocketDim.saving; import java.io.File; import java.io.FileFilter; -import java.io.FileNotFoundException; import java.io.IOException; import java.util.ArrayList; -import java.util.Deque; import java.util.HashMap; -import java.util.Iterator; import java.util.LinkedList; import java.util.List; - +import java.util.Map.Entry; import net.minecraftforge.common.DimensionManager; import StevenDimDoors.mod_pocketDim.Point3D; +import StevenDimDoors.mod_pocketDim.mod_pocketDim; import StevenDimDoors.mod_pocketDim.core.DimLink; -import StevenDimDoors.mod_pocketDim.core.LinkTypes; +import StevenDimDoors.mod_pocketDim.core.DimensionType; +import StevenDimDoors.mod_pocketDim.core.LinkType; import StevenDimDoors.mod_pocketDim.core.NewDimData; import StevenDimDoors.mod_pocketDim.core.PocketManager; import StevenDimDoors.mod_pocketDim.dungeon.DungeonData; -import StevenDimDoors.mod_pocketDim.dungeon.pack.DungeonPack; -import StevenDimDoors.mod_pocketDim.dungeon.pack.DungeonType; import StevenDimDoors.mod_pocketDim.helpers.DungeonHelper; -import StevenDimDoors.mod_pocketDim.util.ConfigurationProcessingException; +import StevenDimDoors.mod_pocketDim.util.DDLogger; import StevenDimDoors.mod_pocketDim.util.FileFilters; import StevenDimDoors.mod_pocketDim.util.Point4D; - import com.google.common.io.Files; public class DDSaveHandler @@ -42,6 +38,8 @@ public class DDSaveHandler // Don't surround this code with try-catch. Our mod should crash if an error // occurs at this level, since it could lead to some nasty problems. + DDLogger.startTimer("Loading data"); + String basePath = DimensionManager.getCurrentSaveRootDirectory() + "/DimensionalDoors/data/"; File dataDirectory = new File(basePath); @@ -61,16 +59,30 @@ public class DDSaveHandler PocketManager.createAndRegisterBlacklist(blacklist); } + // Load the personal pockets mapping + File personalPocketMap = new File(basePath+"personalPockets.txt"); + HashMap ppMap = new HashMap(); + if(personalPocketMap.exists()) + { + PersonalPocketMappingProcessor ppMappingProcessor = new PersonalPocketMappingProcessor(); + ppMap = readPersonalPocketsMapping(personalPocketMap,ppMappingProcessor); + } + // List any dimension data files and read each dimension DimDataProcessor reader = new DimDataProcessor(); - HashMap packedDims = new HashMap(); + HashMap packedDims = new HashMap(); FileFilter dataFileFilter = new FileFilters.RegexFileFilter("dim_-?\\d+\\.txt"); File[] dataFiles = dataDirectory.listFiles(dataFileFilter); for (File dataFile : dataFiles) { PackedDimData packedDim = readDimension(dataFile, reader); + if(packedDim == null) + { + throw new IllegalStateException("The DD data for "+dataFile.getName().replace(".txt", "")+" at "+dataFile.getPath()+" is corrupted. Please report this on the MCF or on the DD github issues tracker."); + } packedDims.put(packedDim.ID,packedDim); + } List linksToUnpack = new ArrayList(); @@ -79,7 +91,17 @@ public class DDSaveHandler { linksToUnpack.addAll(packedDim.Links); } - return unpackDimData(packedDims)&&unpackLinkData(linksToUnpack); + unpackDimData(packedDims); + unpackLinkData(linksToUnpack); + + HashMap personalPocketsMap = new HashMap(); + for(Entry pair : ppMap.entrySet()) + { + personalPocketsMap.put(pair.getKey(), PocketManager.getDimensionData(pair.getValue())); + } + PocketManager.setPersonalPocketsMapping(personalPocketsMap); + + return true; } /** @@ -136,7 +158,7 @@ public class DDSaveHandler } if(isMissing) { - packedDim=(new PackedDimData(packedDim.ID, packedDim.Depth, packedDim.PackDepth, packedDim.ParentID, packedDim.RootID, packedDim.Orientation, packedDim.IsDungeon, packedDim.IsFilled, packedDim.DungeonData, packedDim.Origin, children, packedDim.Links, packedDim.Tails)); + packedDim=(new PackedDimData(packedDim.ID, packedDim.Depth, packedDim.PackDepth, packedDim.ParentID, packedDim.RootID, packedDim.Orientation, DimensionType.getTypeFromIndex(packedDim.DimensionType), packedDim.IsFilled, packedDim.DungeonData, packedDim.Origin, children, packedDim.Links, packedDim.Tails)); packedDims.put(packedDim.ID, packedDim); } return children; @@ -154,12 +176,12 @@ public class DDSaveHandler { ArrayList fosterChildren = new ArrayList(); fosterChildren.add(packedDim.ID); - + DimensionType type = DimensionType.getTypeFromIndex(packedDim.DimensionType); //fix pockets without parents if(!packedDims.containsKey(packedDim.ParentID)) { //Fix the orphan by changing its root to its parent, re-connecting it to the list - packedDim=(new PackedDimData(packedDim.ID, 1, packedDim.PackDepth, packedDim.RootID, packedDim.RootID, packedDim.Orientation, packedDim.IsDungeon, packedDim.IsFilled, packedDim.DungeonData, packedDim.Origin, packedDim.ChildIDs, packedDim.Links, packedDim.Tails)); + packedDim=(new PackedDimData(packedDim.ID, 1, packedDim.PackDepth, packedDim.RootID, packedDim.RootID, packedDim.Orientation,type, packedDim.IsFilled, packedDim.DungeonData, packedDim.Origin, packedDim.ChildIDs, packedDim.Links, packedDim.Tails)); packedDims.put(packedDim.ID, packedDim); } //fix pockets whose parents have forgotten about them @@ -168,7 +190,7 @@ public class DDSaveHandler { //find the root, and fix it by adding the orphan's ID to its children fosterChildren.addAll(fosterParent.ChildIDs); - fosterParent=(new PackedDimData(fosterParent.ID, fosterParent.Depth, fosterParent.PackDepth, fosterParent.ParentID, fosterParent.RootID, fosterParent.Orientation, fosterParent.IsDungeon, fosterParent.IsFilled, fosterParent.DungeonData, fosterParent.Origin, fosterChildren, fosterParent.Links, fosterParent.Tails)); + fosterParent=(new PackedDimData(fosterParent.ID, fosterParent.Depth, fosterParent.PackDepth, fosterParent.ParentID, fosterParent.RootID, fosterParent.Orientation, type, fosterParent.IsFilled, fosterParent.DungeonData, fosterParent.Origin, fosterChildren, fosterParent.Links, fosterParent.Tails)); packedDims.put(fosterParent.ID, fosterParent); } @@ -187,18 +209,14 @@ public class DDSaveHandler if(packedLink.parent.equals(fakePoint)) { NewDimData data = PocketManager.getDimensionData(packedLink.source.getDimension()); - int linkType = packedLink.tail.linkType; + LinkType linkType = LinkType.getLinkTypeFromIndex(packedLink.tail.linkType); + - if((linkType < LinkTypes.ENUM_MIN || linkType > LinkTypes.ENUM_MAX) && linkType != LinkTypes.CLIENT_SIDE) - { - linkType = LinkTypes.NORMAL; - } - - DimLink link = data.createLink(packedLink.source, linkType, packedLink.orientation); + DimLink link = data.createLink(packedLink.source, linkType, packedLink.orientation, packedLink.lock); Point4D destination = packedLink.tail.destination; if(destination!=null) { - PocketManager.getDimensionData(destination.getDimension()).setDestination(link, destination.getX(),destination.getY(),destination.getZ()); + PocketManager.createDimensionDataDangerously(destination.getDimension()).setLinkDestination(link, destination.getX(),destination.getY(),destination.getZ()); } unpackedLinks.add(packedLink); } @@ -210,10 +228,10 @@ public class DDSaveHandler { for(PackedLinkData packedLink : linksToUnpack) { - NewDimData data = PocketManager.getDimensionData(packedLink.source.getDimension()); + NewDimData data = PocketManager.createDimensionDataDangerously(packedLink.source.getDimension()); if(data.getLink(packedLink.parent)!=null) { - data.createChildLink(packedLink.source.getX(), packedLink.source.getY(), packedLink.source.getZ(), data.getLink(packedLink.parent)); + data.createChildLink(packedLink.source, data.getLink(packedLink.parent), packedLink.lock); } unpackedLinks.add(packedLink); } @@ -221,7 +239,7 @@ public class DDSaveHandler } return true; } - + private static PackedDimData readDimension(File dataFile, DimDataProcessor reader) { @@ -238,48 +256,67 @@ public class DDSaveHandler } } - public static boolean saveAll(Iterable> dimensions, List blacklist) throws IOException + public static boolean saveAll(Iterable> dimensions, + List blacklist, boolean checkModified) throws IOException { // Create the data directory for our dimensions // Don't catch exceptions here. If we can't create this folder, // the mod should crash to let the user know early on. - String basePath = DimensionManager.getCurrentSaveRootDirectory() + "/DimensionalDoors/data/"; - File basePathFile = new File(basePath); - Files.createParentDirs(basePathFile); - basePathFile.mkdir(); - - BlacklistProcessor blacklistReader = new BlacklistProcessor(); - writeBlacklist(blacklist, blacklistReader,basePath); - - FileFilter dataFileFilter = new FileFilters.RegexFileFilter("dim_-?\\d+\\.txt"); - - //TODO Deal with temp files correctly - File[] dataFiles = basePathFile.listFiles(dataFileFilter); - for (File dataFile : dataFiles) + // Get the save directory path + File saveDirectory = new File(mod_pocketDim.instance.getCurrentSavePath() + "/DimensionalDoors/data/"); + String savePath = saveDirectory.getAbsolutePath(); + String baseSavePath = savePath + "/dim_"; + File backupDirectory = new File(savePath + "/backup"); + String baseBackupPath = backupDirectory.getAbsolutePath() + "/dim_"; + + if (!saveDirectory.exists()) { - dataFile.delete(); + // Create the save directory + Files.createParentDirs(saveDirectory); + saveDirectory.mkdir(); + } + if (!backupDirectory.exists()) + { + // Create the backup directory + backupDirectory.mkdir(); } + // Create and write the blackList + writeBlacklist(blacklist, savePath); - basePathFile = null; - basePath += "dim_"; + //create and write personal pocket mapping + writePersonalPocketMap(PocketManager.getPersonalPocketMapping(), savePath); + // Write the dimension save data boolean succeeded = true; DimDataProcessor writer = new DimDataProcessor(); for (IPackable dimension : dimensions) { - succeeded &= writeDimension(dimension, writer, basePath); + // Check if the dimension should be saved + if (!checkModified || dimension.isModified()) + { + if (writeDimension(dimension, writer, baseSavePath, baseBackupPath)) + { + dimension.clearModified(); + } + else + { + succeeded = false; + } + } } + return succeeded; } - private static boolean writeBlacklist(List blacklist, BlacklistProcessor writer, String basePath) + private static boolean writeBlacklist(List blacklist, String savePath) { try { - File tempFile = new File(basePath + "blacklist.tmp"); - File saveFile = new File(basePath + "blacklist.txt"); + BlacklistProcessor writer = new BlacklistProcessor(); + File tempFile = new File(savePath + "/blacklist.tmp"); + File saveFile = new File(savePath + "/blacklist.txt"); writer.writeToFile(tempFile, blacklist); saveFile.delete(); tempFile.renameTo(saveFile); @@ -290,21 +327,51 @@ public class DDSaveHandler System.err.println("Could not save blacklist. The following error occurred:"); printException(e, true); return false; - } - + } } - private static boolean writeDimension(IPackable dimension, DimDataProcessor writer, String basePath) + + private static boolean writePersonalPocketMap(HashMap hashMap, String savePath) { try { - File tempFile = new File(basePath + (dimension.name() + ".tmp")); - File saveFile = new File(basePath + (dimension.name() + ".txt")); - writer.writeToFile(tempFile, dimension.pack()); + HashMap ppMap = new HashMap(); + + for(Entry pair : hashMap.entrySet()) + { + ppMap.put(pair.getKey(), pair.getValue().id()); + } + PersonalPocketMappingProcessor writer = new PersonalPocketMappingProcessor(); + File tempFile = new File(savePath + "/personalPockets.tmp"); + File saveFile = new File(savePath + "/personalPockets.txt"); + writer.writeToFile(tempFile, ppMap); saveFile.delete(); tempFile.renameTo(saveFile); return true; } catch (Exception e) + { + System.err.println("Could not save personal pockets mapping. The following error occurred:"); + printException(e, true); + return false; + } + } + + private static boolean writeDimension(IPackable dimension, DimDataProcessor writer, String basePath, String backupPath) + { + try + { + File saveFile = new File(basePath + dimension.name() + ".txt"); + + // If the save file already exists, back it up. + if (saveFile.exists()) + { + Files.move(saveFile, new File(backupPath + dimension.name() + ".txt")); + } + + writer.writeToFile(saveFile, dimension.pack()); + return true; + } + catch (Exception e) { System.err.println("Could not save data for dimension #" + dimension.name() + ". The following error occurred:"); printException(e, true); @@ -355,7 +422,6 @@ public class DDSaveHandler public static List readBlacklist(File blacklistFile, BlacklistProcessor reader) { - try { return reader.readFromFile(blacklistFile); @@ -365,6 +431,18 @@ public class DDSaveHandler e.printStackTrace(); return null; } - + } + + public static HashMap readPersonalPocketsMapping(File ppMap, PersonalPocketMappingProcessor reader) + { + try + { + return reader.readFromFile(ppMap); + } + catch (Exception e) + { + e.printStackTrace(); + return null; + } } } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/saving/DimDataProcessor.java b/src/main/java/StevenDimDoors/mod_pocketDim/saving/DimDataProcessor.java index 7b3dd39..1c6f248 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/saving/DimDataProcessor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/saving/DimDataProcessor.java @@ -4,33 +4,60 @@ import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; -import java.util.ArrayList; -import java.util.List; - -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.google.gson.stream.JsonReader; -import com.google.gson.stream.JsonToken; - -import StevenDimDoors.mod_pocketDim.Point3D; +import java.util.HashMap; +import StevenDimDoors.mod_pocketDim.core.DimensionType; import StevenDimDoors.mod_pocketDim.util.BaseConfigurationProcessor; import StevenDimDoors.mod_pocketDim.util.ConfigurationProcessingException; -import StevenDimDoors.mod_pocketDim.util.Point4D; +import StevenDimDoors.mod_pocketDim.util.JSONValidator; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import com.google.gson.stream.JsonReader; public class DimDataProcessor extends BaseConfigurationProcessor { + //The name of the version ID where it is stored in the JSON + public final String JSON_VERSION_PROPERTY_NAME = "SAVE_DATA_VERSION_ID_INSTANCE"; + + //mapping of version IDs to their corresponding schema. Prevents reloading of schema during save/load cycles + private HashMap SAVE_DATA_SCHEMA; + + //The parser used to read in the JSON Files + private static final JsonParser jsonParser = new JsonParser(); + + //The directory for JSON schema files + public static final String BASE_SCHEMA_PATH = "/assets/dimdoors/text/"; + + /** + * Need to manually include a schema defintion for every save file version currently supported + */ + public DimDataProcessor() + { + SAVE_DATA_SCHEMA = new HashMap(); + + //Load the old schema/s + SAVE_DATA_SCHEMA.put(982405775, loadSchema(BASE_SCHEMA_PATH+"Dim_Data_Schema_v982405775.json")); + + //load the schema representing the current save data format + SAVE_DATA_SCHEMA.put(PackedDimData.SAVE_DATA_VERSION_ID, loadSchema(BASE_SCHEMA_PATH+"Dim_Data_Schema_v1-0-0.json")); + + } @Override public PackedDimData readFromStream(InputStream inputStream) throws ConfigurationProcessingException { try { + //read in the json save file represeting a single dimension JsonReader reader = new JsonReader(new InputStreamReader(inputStream, "UTF-8")); - PackedDimData data = this.createDImDataFromJson(reader); + PackedDimData data = this.readDimDataJson(reader); reader.close(); return data; + } - catch (IOException e) + catch (Exception e) { e.printStackTrace(); throw new ConfigurationProcessingException("Could not read packedDimData"); @@ -42,259 +69,143 @@ public class DimDataProcessor extends BaseConfigurationProcessor public void writeToStream(OutputStream outputStream, PackedDimData data) throws ConfigurationProcessingException { - /** Print out dimData using the GSON built in serializer. I dont feel bad doing this because - * 1- We can read it - * 2- We are manually reading the data in. - * 3- The error messages tell us exactly where its failing, so its easy to fix - */ - + //create a json object from a packedDimData instance GsonBuilder gsonBuilder = new GsonBuilder(); - Gson gson = gsonBuilder.setPrettyPrinting().create(); - + gsonBuilder.setPrettyPrinting(); + Gson gson = gsonBuilder.create(); + JsonElement ele = gson.toJsonTree(data); + try { - outputStream.write(gson.toJson(data).getBytes("UTF-8")); + //ensure our json object corresponds to our schema + JSONValidator.validate(getSaveDataSchema(ele.getAsJsonObject()), ele); + outputStream.write(gson.toJson(ele).getBytes("UTF-8")); outputStream.close(); } - catch (IOException e) + catch (Exception e) { // not sure if this is kosher, we need it to explode, but not by throwing the IO exception. - throw new ConfigurationProcessingException("Incorrectly formatted save data"); - } + throw new ConfigurationProcessingException("Could not access save data"); + } + } + /** - * Nightmare method that takes a JsonReader pointed at a serialized instance of PackedDimData + * validates the save file against it's current version, then updates and validates it again if it needs it + * then it loads it * @param reader * @return * @throws IOException */ - public PackedDimData createDImDataFromJson(JsonReader reader) throws IOException + public PackedDimData readDimDataJson(JsonReader reader) throws IOException { - int ID; - boolean IsDungeon; - boolean IsFilled; - int Depth; - int PackDepth; - int ParentID; - int RootID; - PackedDungeonData Dungeon = null; - Point3D Origin; - int Orientation; - List ChildIDs; - List Links; - List Tails = new ArrayList(); + //read the save file into a Json element + JsonElement ele = jsonParser.parse(reader); - reader.beginObject(); + //get the schema that corresponds to the save file's listed version number + JsonObject schema = this.getSaveDataSchema(ele.getAsJsonObject()); - reader.nextName(); - if (reader.nextLong() != PackedDimData.SAVE_DATA_VERSION_ID) + //validate the save file against its schema + JSONValidator.validate(schema, ele); + + //handle updating old save data + ele = processSaveData(schema, ele.getAsJsonObject()); + + //convert the updated and verified json into an instance of PackedDimData + GsonBuilder gsonBuilder = new GsonBuilder(); + return gsonBuilder.create().fromJson(ele, PackedDimData.class); + } + + /** + * Gets the schema that corresponds to a version of our save data + * @param obj + * @return + * @throws IOException + */ + public JsonObject getSaveDataSchema(JsonObject obj) + { + JsonObject schema = this.SAVE_DATA_SCHEMA.get(obj.get(JSON_VERSION_PROPERTY_NAME).getAsInt()); + + if(schema == null) { - throw new IOException("Save data version mismatch"); + throw new IllegalStateException("Invalid save data version"); } - reader.nextName(); - ID = reader.nextInt(); - - reader.nextName(); - IsDungeon = reader.nextBoolean(); - - reader.nextName(); - IsFilled = reader.nextBoolean(); - - reader.nextName(); - Depth = reader.nextInt(); - - reader.nextName(); - PackDepth = reader.nextInt(); - - reader.nextName(); - ParentID=reader.nextInt(); - - reader.nextName(); - RootID= reader.nextInt(); - - if(reader.nextName().equals("DungeonData")) + return schema; + } + + /** + * Internally load the save data schema so we dont load them every single time we validate save data + * @param path + * @return + */ + private JsonObject loadSchema(String path) + { + InputStream in = this.getClass().getResourceAsStream(path); + JsonReader reader = new JsonReader(new InputStreamReader(in)); + + JsonObject schema = jsonParser.parse(reader).getAsJsonObject(); + try { - Dungeon = createDungeonDataFromJson(reader); - reader.nextName(); + reader.close(); + in.close(); + } + catch (IOException e) + { + System.err.println("Could not load Json Save Data definitions"); + e.printStackTrace(); + throw new IllegalStateException("Could not load Json Save Data definitions"); } - Origin = createPointFromJson(reader); - - reader.nextName(); - Orientation = reader.nextInt(); - - reader.nextName(); - ChildIDs = this.createIntListFromJson(reader); - - reader.nextName(); - Links = this.createLinksListFromJson(reader); - - return new PackedDimData(ID, Depth, PackDepth, ParentID, RootID, Orientation, IsDungeon, IsFilled, Dungeon, Origin, ChildIDs, Links, Tails); + return schema; } - private Point3D createPointFromJson(JsonReader reader) throws IOException + /** + * I use this method to update old save data files to the new format before actually loading them. + * @return + */ + public JsonObject processSaveData(JsonObject schema, JsonObject save) { - reader.beginObject(); + int incomingSaveVersionID = save.get(JSON_VERSION_PROPERTY_NAME).getAsInt(); - reader.nextName(); - int x = reader.nextInt(); - - reader.nextName(); - int y = reader.nextInt(); - - reader.nextName(); - int z = reader.nextInt(); - - reader.endObject(); - - return new Point3D(x,y,z); - } - - private Point4D createPoint4DFromJson(JsonReader reader) throws IOException - { - reader.beginObject(); - - reader.nextName(); - int x = reader.nextInt(); - - reader.nextName(); - int y = reader.nextInt(); - - reader.nextName(); - int z = reader.nextInt(); - - reader.nextName(); - int dimension = reader.nextInt(); - - reader.endObject(); - - return new Point4D(x,y,z,dimension); - } - - private List createIntListFromJson(JsonReader reader) throws IOException - { - List list = new ArrayList(); - reader.beginArray(); - - while (reader.peek() != JsonToken.END_ARRAY) + // Handle save data versions that are current + if(incomingSaveVersionID == PackedDimData.SAVE_DATA_VERSION_ID) { - list.add(reader.nextInt()); + JSONValidator.validate(this.getSaveDataSchema(save), save); + return save; + } + + // Handle save data versions that are older, starting with the random one. + // We have to + if(incomingSaveVersionID== 982405775) + { + DimensionType type; - } - reader.endArray(); - return list; - } - - private List createLinksListFromJson(JsonReader reader) throws IOException - { - List list = new ArrayList(); - - reader.beginArray(); - - while (reader.peek() != JsonToken.END_ARRAY) - { - list.add(createLinkDataFromJson(reader)); - } - reader.endArray(); - return list; - } - - private PackedLinkData createLinkDataFromJson(JsonReader reader) throws IOException - { - Point4D source; - Point3D parent; - PackedLinkTail tail; - int orientation; - List children = new ArrayList(); - - reader.beginObject(); - - reader.nextName(); - source = this.createPoint4DFromJson(reader); - - reader.nextName(); - parent = this.createPointFromJson(reader); - - reader.nextName(); - tail = this.createLinkTailFromJson(reader); - - reader.nextName(); - orientation = reader.nextInt(); - - reader.nextName(); - reader.beginArray(); - - while (reader.peek() != JsonToken.END_ARRAY) - { - children.add(this.createPointFromJson(reader)); - } - reader.endArray(); - reader.endObject(); - - return new PackedLinkData(source, parent, tail, orientation, children); - } - private PackedDungeonData createDungeonDataFromJson(JsonReader reader) throws IOException - { - int Weight; - boolean IsOpen; - boolean IsInternal; - String SchematicPath; - String SchematicName; - String DungeonTypeName; - String DungeonPackName; - - reader.beginObject(); - @SuppressWarnings("unused") - JsonToken test = reader.peek(); - - if(reader.peek() == JsonToken.END_OBJECT) - { - return null; + //see if the dim is a pocket + if(save.get("RootID").getAsInt() != save.get("ID").getAsInt()) + { + if(save.get("IsDungeon").getAsBoolean()) + { + type = DimensionType.DUNGEON; + } + else + { + type = DimensionType.POCKET; + } + } + else + { + type = DimensionType.ROOT; + } + + save.remove("IsDungeon"); + save.addProperty("DimensionType",type.index); + save.remove(this.JSON_VERSION_PROPERTY_NAME); + + //Need to hardcode the version number here, so if we change the current version then this still updates to the proper version + save.addProperty(this.JSON_VERSION_PROPERTY_NAME, 100); } - reader.nextName(); - Weight=reader.nextInt(); - - reader.nextName(); - IsOpen=reader.nextBoolean(); - - reader.nextName(); - IsInternal=reader.nextBoolean(); - - reader.nextName(); - SchematicPath=reader.nextString(); - - reader.nextName(); - SchematicName=reader.nextString(); - - reader.nextName(); - DungeonTypeName=reader.nextString(); - - reader.nextName(); - DungeonPackName=reader.nextString(); - - reader.endObject(); - return new PackedDungeonData(Weight, IsOpen, IsInternal, SchematicPath, SchematicName, DungeonTypeName, DungeonPackName); - } - private PackedLinkTail createLinkTailFromJson(JsonReader reader) throws IOException - { - Point4D destination = null; - int linkType; - reader.beginObject(); - reader.nextName(); - - @SuppressWarnings("unused") - JsonToken test = reader.peek(); - if (reader.peek() == JsonToken.BEGIN_OBJECT) - { - destination = this.createPoint4DFromJson(reader); - reader.nextName(); - } - - linkType = reader.nextInt(); - reader.endObject(); - - return new PackedLinkTail(destination, linkType); + return processSaveData(this.getSaveDataSchema(save), save); } } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/saving/IPackable.java b/src/main/java/StevenDimDoors/mod_pocketDim/saving/IPackable.java index 78908d8..687ca08 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/saving/IPackable.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/saving/IPackable.java @@ -4,4 +4,6 @@ public interface IPackable { public String name(); public T pack(); + public boolean isModified(); + public void clearModified(); } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/saving/OldSaveImporter.java b/src/main/java/StevenDimDoors/mod_pocketDim/saving/OldSaveImporter.java index 42b8d01..31940e8 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/saving/OldSaveImporter.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/saving/OldSaveImporter.java @@ -2,17 +2,16 @@ package StevenDimDoors.mod_pocketDim.saving; import java.io.File; import java.io.FileInputStream; -import java.io.FileNotFoundException; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; - import StevenDimDoors.mod_pocketDim.DimData; import StevenDimDoors.mod_pocketDim.LinkData; -import StevenDimDoors.mod_pocketDim.Point3D; - import StevenDimDoors.mod_pocketDim.ObjectSaveInputStream; +import StevenDimDoors.mod_pocketDim.Point3D; +import StevenDimDoors.mod_pocketDim.core.DimensionType; +import StevenDimDoors.mod_pocketDim.core.LinkType; import StevenDimDoors.mod_pocketDim.util.Point4D; public class OldSaveImporter @@ -39,35 +38,83 @@ public class OldSaveImporter return; } + //build the child list + HashMap> parentChildMapping = new HashMap>(); + for(DimData data : dimMap.values()) + { + if(data.isPocket) + { + LinkData link = data.exitDimLink; + + if(parentChildMapping.containsKey(link.destDimID)) + { + parentChildMapping.get(link.destDimID).add(data.dimID); + } + else + { + parentChildMapping.put(link.destDimID, new ArrayList()); + parentChildMapping.get(link.destDimID).add(data.dimID); + } + parentChildMapping.remove(data.dimID); + } + } + for(DimData data : dimMap.values()) { List newPackedLinkData = new ArrayList(); - List childDims = new ArrayList(); + List childDims; + if(parentChildMapping.containsKey(data.dimID)) + { + childDims =parentChildMapping.get(data.dimID); + } + else + { + childDims = new ArrayList(); + } for(LinkData link : data.getLinksInDim()) { Point4D source = new Point4D(link.locXCoord,link.locYCoord,link.locZCoord,link.locDimID); Point4D destintion = new Point4D(link.destXCoord,link.destYCoord,link.destZCoord,link.destDimID); - PackedLinkTail tail = new PackedLinkTail(destintion, link.linkOrientation); + PackedLinkTail tail = new PackedLinkTail(destintion, LinkType.NORMAL); List children = new ArrayList(); - PackedLinkData newPackedLink = new PackedLinkData(source, new Point3D(-1,-1,-1), tail, link.linkOrientation,children); + PackedLinkData newPackedLink = new PackedLinkData(source, new Point3D(-1,-1,-1), tail, link.linkOrientation,children, null); newPackedLinkData.add(newPackedLink); allPackedLinks.add(newPackedLink); - } + PackedDimData dim; + DimensionType type; - PackedDimData dim = new PackedDimData(data.dimID, data.depth, data.depth, data.exitDimLink.locDimID, data.exitDimLink.locDimID, 0, data.dungeonGenerator!=null, data.hasBeenFilled, null, new Point3D(0,64,0), childDims, newPackedLinkData, null); + if(data.isPocket) + { + if(data.dungeonGenerator!=null) + { + type = DimensionType.DUNGEON; + } + else + { + type = DimensionType.POCKET; + } + } + else + { + type = DimensionType.ROOT; + } + if(data.isPocket) + { + dim = new PackedDimData(data.dimID, data.depth, data.depth, data.exitDimLink.locDimID, data.exitDimLink.locDimID, 0, type, data.hasBeenFilled, null, new Point3D(0,64,0), childDims, newPackedLinkData, null); + } + else + { + dim = new PackedDimData(data.dimID, data.depth, data.depth, data.dimID, data.dimID, 0, type, data.hasBeenFilled, null, new Point3D(0,64,0), childDims, newPackedLinkData, null); + } newPackedDimData.put(dim.ID,dim); - - DDSaveHandler.unpackDimData(newPackedDimData); - DDSaveHandler.unpackLinkData(allPackedLinks); - - } - - + + DDSaveHandler.unpackDimData(newPackedDimData); + DDSaveHandler.unpackLinkData(allPackedLinks); } } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/saving/PackedDimData.java b/src/main/java/StevenDimDoors/mod_pocketDim/saving/PackedDimData.java index fb058d3..3a026b7 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/saving/PackedDimData.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/saving/PackedDimData.java @@ -3,14 +3,15 @@ package StevenDimDoors.mod_pocketDim.saving; import java.util.List; import StevenDimDoors.mod_pocketDim.Point3D; +import StevenDimDoors.mod_pocketDim.core.DimensionType; public class PackedDimData { // These fields will be public since this is a simple data container - public final static long SAVE_DATA_VERSION_ID = 982405775L; + public final static int SAVE_DATA_VERSION_ID = 100; public final long SAVE_DATA_VERSION_ID_INSTANCE = SAVE_DATA_VERSION_ID; public final int ID; - public final boolean IsDungeon; + public final int DimensionType; public final boolean IsFilled; public final int Depth; public final int PackDepth; @@ -26,7 +27,7 @@ public class PackedDimData // FIXME Missing dungeon data, not sure how to include it public PackedDimData(int id, int depth, int packDepth, int parentID, int rootID, int orientation, - boolean isDungeon, boolean isFilled,PackedDungeonData dungeonData, Point3D origin, List childIDs, List links, + DimensionType type, boolean isFilled,PackedDungeonData dungeonData, Point3D origin, List childIDs, List links, List tails) { ID = id; @@ -35,7 +36,7 @@ public class PackedDimData ParentID = parentID; RootID = rootID; Orientation = orientation; - IsDungeon = isDungeon; + DimensionType = type.index; IsFilled = isFilled; DungeonData = dungeonData; Origin = origin; @@ -49,4 +50,6 @@ public class PackedDimData { return "ID= "+this.ID; } + + } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/saving/PackedLinkData.java b/src/main/java/StevenDimDoors/mod_pocketDim/saving/PackedLinkData.java index a98b448..d08ca0f 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/saving/PackedLinkData.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/saving/PackedLinkData.java @@ -3,6 +3,7 @@ package StevenDimDoors.mod_pocketDim.saving; import java.util.List; import StevenDimDoors.mod_pocketDim.Point3D; +import StevenDimDoors.mod_pocketDim.core.DDLock; import StevenDimDoors.mod_pocketDim.util.Point4D; public class PackedLinkData @@ -12,13 +13,15 @@ public class PackedLinkData public final PackedLinkTail tail; public final int orientation; public final List children; + public final DDLock lock; - public PackedLinkData(Point4D source, Point3D parent, PackedLinkTail tail, int orientation, List children) + public PackedLinkData(Point4D source, Point3D parent, PackedLinkTail tail, int orientation, List children, DDLock lock) { this.source=source; this.parent=parent; this.tail=tail; this.orientation=orientation; this.children=children; + this.lock = lock; } } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/saving/PackedLinkTail.java b/src/main/java/StevenDimDoors/mod_pocketDim/saving/PackedLinkTail.java index 64c2466..f5521c7 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/saving/PackedLinkTail.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/saving/PackedLinkTail.java @@ -1,5 +1,6 @@ package StevenDimDoors.mod_pocketDim.saving; +import StevenDimDoors.mod_pocketDim.core.LinkType; import StevenDimDoors.mod_pocketDim.util.Point4D; public class PackedLinkTail @@ -7,10 +8,10 @@ public class PackedLinkTail public final Point4D destination; public final int linkType; - public PackedLinkTail(Point4D destination, int linkType) + public PackedLinkTail(Point4D destination, LinkType linkType) { this.destination=destination; - this.linkType=linkType; + this.linkType=linkType.index; } } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/saving/PersonalPocketMappingProcessor.java b/src/main/java/StevenDimDoors/mod_pocketDim/saving/PersonalPocketMappingProcessor.java new file mode 100644 index 0000000..e8be7ad --- /dev/null +++ b/src/main/java/StevenDimDoors/mod_pocketDim/saving/PersonalPocketMappingProcessor.java @@ -0,0 +1,79 @@ +package StevenDimDoors.mod_pocketDim.saving; + +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonToken; + +import StevenDimDoors.mod_pocketDim.util.BaseConfigurationProcessor; +import StevenDimDoors.mod_pocketDim.util.ConfigurationProcessingException; + +public class PersonalPocketMappingProcessor extends BaseConfigurationProcessor> +{ + + @Override + public HashMap readFromStream(InputStream inputStream) throws ConfigurationProcessingException + { + try + { + JsonReader reader = new JsonReader(new InputStreamReader(inputStream, "UTF-8")); + HashMap data = this.createPersonalPocketsMapFromJson(reader); + reader.close(); + return data; + } + catch (IOException e) + { + e.printStackTrace(); + throw new ConfigurationProcessingException("Could not read personal pocket mapping"); + } + } + + private HashMap createPersonalPocketsMapFromJson(JsonReader reader) throws IOException + { + HashMap ppMap; + ppMap = this.createMapFromJson(reader); + return ppMap; + } + + private HashMap createMapFromJson(JsonReader reader) throws IOException + { + HashMap map = new HashMap(); + + reader.beginObject(); + while(reader.peek()!= JsonToken.END_OBJECT) + { + map.put(reader.nextName(), reader.nextInt()); + } + reader.endObject(); + + return map; + } + + @Override + public void writeToStream(OutputStream outputStream, HashMap data) throws ConfigurationProcessingException + { + GsonBuilder gsonBuilder = new GsonBuilder(); + Gson gson = gsonBuilder.setPrettyPrinting().create(); + + try + { + outputStream.write(gson.toJson(data).getBytes("UTF-8")); + outputStream.close(); + } + catch (IOException e) + { + // not sure if this is kosher, we need it to explode, but not by throwing the IO exception. + throw new ConfigurationProcessingException("Incorrectly formatted save data"); + } + + } + +} diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/schematic/BlockRotator.java b/src/main/java/StevenDimDoors/mod_pocketDim/schematic/BlockRotator.java index bbf1251..98ae89c 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/schematic/BlockRotator.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/schematic/BlockRotator.java @@ -22,6 +22,7 @@ public class BlockRotator static { hasOrientations[Block.dispenser.blockID] = true; + hasOrientations[Block.dropper.blockID] = true; hasOrientations[Block.stairsStoneBrick.blockID] = true; hasOrientations[Block.lever.blockID] = true; hasOrientations[Block.stoneButton.blockID] = true; @@ -69,6 +70,8 @@ public class BlockRotator hasOrientations[mod_pocketDim.dimensionalDoor.blockID] = true; hasOrientations[mod_pocketDim.warpDoor.blockID] = true; + hasOrientations[mod_pocketDim.goldenDimensionalDoor.blockID] = true; + hasOrientations[mod_pocketDim.personalDimDoor.blockID] = true; } @@ -241,7 +244,7 @@ public class BlockRotator break; } } - else if (blockID == Block.chest.blockID || blockID == Block.chestTrapped.blockID || blockID == Block.ladder.blockID || blockID == Block.hopperBlock.blockID|| blockID == Block.furnaceBurning.blockID|| blockID == Block.furnaceIdle.blockID) + else if (blockID == Block.chest.blockID || blockID == Block.chestTrapped.blockID || blockID == Block.ladder.blockID || blockID == Block.furnaceBurning.blockID|| blockID == Block.furnaceIdle.blockID) { switch (metadata) { @@ -258,7 +261,36 @@ public class BlockRotator metadata = 3; break; } - + } + else if (blockID == Block.hopperBlock.blockID) + { + switch (metadata) + { + case 2: + metadata = 5; + break; + case 3: + metadata = 4; + break; + case 4: + metadata = 2; + break; + case 5: + metadata = 3; + break; + case 10: + metadata = 13; + break; + case 11: + metadata = 12; + break; + case 12: + metadata = 10; + break; + case 13: + metadata = 11; + break; + } } else if (blockID==Block.vine.blockID) { @@ -352,7 +384,7 @@ public class BlockRotator break; } } - else if(blockID== Block.lever.blockID||blockID== Block.stoneButton.blockID||blockID== Block.stoneButton.blockID||blockID== Block.woodenButton.blockID||blockID== Block.torchWood.blockID||blockID== Block.torchRedstoneIdle.blockID||blockID== Block.torchRedstoneActive.blockID) + else if(blockID== Block.lever.blockID || blockID == Block.stoneButton.blockID || blockID == Block.woodenButton.blockID || blockID== Block.torchWood.blockID||blockID== Block.torchRedstoneIdle.blockID||blockID== Block.torchRedstoneActive.blockID) { switch (metadata) { @@ -382,7 +414,7 @@ public class BlockRotator break; } } - else if(blockID== Block.pistonBase.blockID||blockID==Block.pistonExtension.blockID||blockID==Block.pistonStickyBase.blockID||blockID==Block.dispenser.blockID||blockID==Block.dropper.blockID) + else if(blockID== Block.pistonBase.blockID||blockID==Block.pistonExtension.blockID||blockID==Block.pistonStickyBase.blockID || blockID == Block.dispenser.blockID || blockID == Block.dropper.blockID) { switch (metadata) { diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/schematic/ChunkBlockSetter.java b/src/main/java/StevenDimDoors/mod_pocketDim/schematic/ChunkBlockSetter.java index e7203fb..b00195c 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/schematic/ChunkBlockSetter.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/schematic/ChunkBlockSetter.java @@ -7,11 +7,16 @@ import net.minecraft.world.chunk.storage.ExtendedBlockStorage; public class ChunkBlockSetter implements IBlockSetter { - public ChunkBlockSetter() { } + private boolean ignoreAir; + + public ChunkBlockSetter(boolean ignoreAir) + { + this.ignoreAir = ignoreAir; + } public void setBlock(World world, int x, int y, int z, int blockID, int metadata) { - if (blockID != 0 && Block.blocksList[blockID] == null) + if ((blockID == 0 && ignoreAir) || (blockID != 0 && Block.blocksList[blockID] == null)) { return; } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/schematic/Schematic.java b/src/main/java/StevenDimDoors/mod_pocketDim/schematic/Schematic.java index 8bf7dbb..dbb912f 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/schematic/Schematic.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/schematic/Schematic.java @@ -362,15 +362,15 @@ public class Schematic { return filter.apply(this, this.blocks, this.metadata); } - public void copyToWorld(World world, int x, int y, int z, boolean notifyClients) + public void copyToWorld(World world, int x, int y, int z, boolean notifyClients, boolean ignoreAir) { if (notifyClients) { - copyToWorld(world, x, y, z, new WorldBlockSetter(false, true)); + copyToWorld(world, x, y, z, new WorldBlockSetter(false, true, ignoreAir)); } else { - copyToWorld(world, x, y, z, new ChunkBlockSetter()); + copyToWorld(world, x, y, z, new ChunkBlockSetter(ignoreAir)); } } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/schematic/WorldBlockSetter.java b/src/main/java/StevenDimDoors/mod_pocketDim/schematic/WorldBlockSetter.java index 3ac4563..2ff9e08 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/schematic/WorldBlockSetter.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/schematic/WorldBlockSetter.java @@ -11,16 +11,21 @@ public class WorldBlockSetter implements IBlockSetter public final int NOTIFY_CLIENT_FLAG = 2; private int flags; + private boolean ignoreAir; - public WorldBlockSetter(boolean doBlockUpdates, boolean notifyClients) + public WorldBlockSetter(boolean doBlockUpdates, boolean notifyClients, boolean ignoreAir) { - flags = 0; - flags += doBlockUpdates ? BLOCK_UPDATES_FLAG : 0; - flags += notifyClients ? NOTIFY_CLIENT_FLAG : 0; + this.flags = 0; + this.flags += doBlockUpdates ? BLOCK_UPDATES_FLAG : 0; + this.flags += notifyClients ? NOTIFY_CLIENT_FLAG : 0; + this.ignoreAir = ignoreAir; } public void setBlock(World world, int x, int y, int z, int blockID, int metadata) { - world.setBlock(x, y, z, blockID, metadata, flags); + if (!ignoreAir || blockID != 0) + { + world.setBlock(x, y, z, blockID, metadata, flags); + } } } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/ticking/CustomLimboPopulator.java b/src/main/java/StevenDimDoors/mod_pocketDim/ticking/CustomLimboPopulator.java index 908e2e9..231eec2 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/ticking/CustomLimboPopulator.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/ticking/CustomLimboPopulator.java @@ -1,6 +1,5 @@ package StevenDimDoors.mod_pocketDim.ticking; -import java.util.ArrayList; import java.util.Random; import java.util.concurrent.ConcurrentLinkedQueue; @@ -9,8 +8,8 @@ import net.minecraft.server.MinecraftServer; import net.minecraft.world.GameRules; import net.minecraft.world.World; import net.minecraftforge.common.DimensionManager; -import StevenDimDoors.mod_pocketDim.DDProperties; import StevenDimDoors.mod_pocketDim.mod_pocketDim; +import StevenDimDoors.mod_pocketDim.config.DDProperties; import StevenDimDoors.mod_pocketDim.core.NewDimData; import StevenDimDoors.mod_pocketDim.core.PocketManager; import StevenDimDoors.mod_pocketDim.helpers.yCoordHelper; @@ -31,30 +30,42 @@ 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 public void notifyTick() { - //Check if any new spawning requests have come in + World limboWorld = null; + + // Check if any new spawning requests have come in if (!locations.isEmpty()) { - //Check if mob spawning is allowed + // Check if mob spawning is allowed if (isMobSpawningAllowed()) { - //Loop over the locations and call the appropriate function depending - //on whether the request is for Limbo or for a pocket dimension. + // Loop over the locations and call the appropriate function depending + // on whether the request is for Limbo or for a pocket dimension. for (ChunkLocation location : locations) { if (location.DimensionID == properties.LimboDimensionID) { - //Limbo chunk - placeMonolithsInLimbo(location.DimensionID, location.ChunkX, location.ChunkZ); + // Limbo chunk - World world = DimensionManager.getWorld(location.DimensionID); + // SenseiKiwi: Check if we haven't loaded Limbo for another request in this request + // cycle. If so, try to load Limbo up. This solves a strange issue with ChickenChunks + // where CC somehow forces chunks to generate in Limbo if LimboProvider.canRespawnHere() + // is true, yet when execution reaches this point, Limbo isn't loaded anymore! My theory + // is that CC force-loads a chunk for some reason, but since there are no players around, + // Limbo immediately unloads after standard world gen runs, and before this code can run. - mod_pocketDim.instance.gatewayGenerator.generate(world.rand, location.ChunkX, location.ChunkZ,world, world.getChunkProvider(), world.getChunkProvider()); + if (limboWorld == null) + { + limboWorld = PocketManager.loadDimension(properties.LimboDimensionID); + } + placeMonolithsInLimbo(limboWorld, location.ChunkX, location.ChunkZ); + mod_pocketDim.gatewayGenerator.generate(limboWorld.rand, location.ChunkX, location.ChunkZ, + limboWorld, limboWorld.getChunkProvider(), limboWorld.getChunkProvider()); } else { @@ -145,15 +156,8 @@ public class CustomLimboPopulator implements IRegularTickReceiver { while (sanity < 5 && !didSpawn); } - private void placeMonolithsInLimbo(int dimensionID, int chunkX, int chunkZ) + private void placeMonolithsInLimbo(World limbo, int chunkX, int chunkZ) { - World limbo = DimensionManager.getWorld(dimensionID); - - if (limbo == null) - { - return; - } - //The following initialization code is based on code from ChunkProviderGenerate. //It makes our generation depend on the world seed. Random random = new Random(limbo.getSeed() ^ 0xB5130C4ACC71A822L); 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 b0f203f..0000000 --- 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 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/MobMonolith.java b/src/main/java/StevenDimDoors/mod_pocketDim/ticking/MobMonolith.java index de4103e..279c123 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/ticking/MobMonolith.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/ticking/MobMonolith.java @@ -2,24 +2,18 @@ package StevenDimDoors.mod_pocketDim.ticking; import java.util.List; -import net.minecraft.block.Block; -import net.minecraft.block.material.Material; -import net.minecraft.entity.DataWatcher; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityFlying; -import net.minecraft.entity.EntityLiving; import net.minecraft.entity.SharedMonsterAttributes; import net.minecraft.entity.monster.IMob; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.AxisAlignedBB; -import net.minecraft.util.ChunkCoordinates; import net.minecraft.util.DamageSource; import net.minecraft.util.MathHelper; import net.minecraft.world.World; -import net.minecraftforge.common.ForgeHooks; -import StevenDimDoors.mod_pocketDim.DDProperties; import StevenDimDoors.mod_pocketDim.mod_pocketDim; +import StevenDimDoors.mod_pocketDim.config.DDProperties; import StevenDimDoors.mod_pocketDim.core.DDTeleporter; import StevenDimDoors.mod_pocketDim.util.Point4D; import StevenDimDoors.mod_pocketDim.world.LimboProvider; @@ -27,21 +21,31 @@ import StevenDimDoors.mod_pocketDim.world.PocketProvider; public class MobMonolith extends EntityFlying implements IMob { - public int aggro = 0; - private float soundTime = 0; - private byte textureState = 0; - private float scaleFactor = 0; - private int aggroMax; + private static final short MAX_AGGRO = 250; + private static final short MAX_AGGRO_CAP = 100; + private static final short MIN_AGGRO_CAP = 25; + private static final int MAX_TEXTURE_STATE = 18; + private static final int MAX_SOUND_COOLDOWN = 200; + private static final int MAX_AGGRO_RANGE = 35; + private static final int AGGRO_WATCHER_INDEX = 16; + + private static final float WIDTH = 3f; + private static final float HEIGHT = 3f; + private static final float EYE_HEIGHT = HEIGHT / 2; + + public float pitchLevel; + private short aggro = 0; + private int soundTime = 0; + private final short aggroCap; private static DDProperties properties = null; - public MobMonolith(World par1World) + public MobMonolith(World world) { - super(par1World); - this.setSize(3F, 9.0F); - this.noClip=true; - this.scaleFactor = (float) ((rand.nextDouble()/2)+1); - this.aggroMax = rand.nextInt(245)+200; + super(world); + this.setSize(WIDTH, HEIGHT); + this.noClip = true; + this.aggroCap = (short) MathHelper.getRandomIntegerInRange(this.rand, MIN_AGGRO_CAP, MAX_AGGRO_CAP); if (properties == null) properties = DDProperties.instance(); } @@ -55,8 +59,19 @@ public class MobMonolith extends EntityFlying implements IMob @Override public boolean attackEntityFrom(DamageSource par1DamageSource, float par2) { + if (par1DamageSource != DamageSource.inWall) + { + this.aggro = MAX_AGGRO; + } return false; } + + @Override + public boolean canBreatheUnderwater() + { + return true; + } + @Override public AxisAlignedBB getBoundingBox() { @@ -79,62 +94,29 @@ public class MobMonolith extends EntityFlying implements IMob protected void applyEntityAttributes() { super.applyEntityAttributes(); - this.getAttributeMap().getAttributeInstance(SharedMonsterAttributes.maxHealth).setAttribute(10); + this.getAttributeMap().getAttributeInstance(SharedMonsterAttributes.maxHealth).setAttribute(57005); } + @Override public boolean canBePushed() { return false; } - + @Override - public float getRenderSizeModifier() + public float getEyeHeight() { - return this.scaleFactor; - } - - public void setEntityPosition(Entity entity, double x, double y, double z) - { - entity.lastTickPosX = entity.prevPosX = entity.posX = x; - entity.lastTickPosY = entity.prevPosY = entity.posY = y + entity.yOffset; - entity.lastTickPosZ = entity.prevPosZ = entity.posZ = z; - entity.setPosition(x, y, z); + return EYE_HEIGHT; } @Override protected void entityInit() { super.entityInit(); - this.dataWatcher.addObject(16, Byte.valueOf((byte)0)); + // Add a short for the aggro level + this.dataWatcher.addObject(AGGRO_WATCHER_INDEX, Short.valueOf((short) 0)); } - public boolean isClipping() - { - - int i = MathHelper.floor_double(this.boundingBox.minX); - int j = MathHelper.floor_double(this.boundingBox.maxX + 1.0D); - int k = MathHelper.floor_double(this.boundingBox.minY); - int l = MathHelper.floor_double(this.boundingBox.maxY + 1.0D); - int i1 = MathHelper.floor_double(this.boundingBox.minZ); - int j1 = MathHelper.floor_double(this.boundingBox.maxZ + 1.0D); - - for (int k1 = i; k1 < j; ++k1) - { - for (int l1 = k; l1 < l; ++l1) - { - for (int i2 = i1; i2 < j1; ++i2) - { - if(!this.worldObj.isAirBlock(k1, l1, i2)) - { - return true; - } - } - } - } - - - return false; - } @Override public boolean isEntityAlive() { @@ -144,186 +126,177 @@ public class MobMonolith extends EntityFlying implements IMob @Override public void onEntityUpdate() { + // Remove this Monolith if it's not in Limbo or in a pocket dimension if (!(this.worldObj.provider instanceof LimboProvider || this.worldObj.provider instanceof PocketProvider)) { this.setDead(); + super.onEntityUpdate(); + return; } - + super.onEntityUpdate(); - if(this.isClipping()) + + // Check for players and update aggro levels even if there are no players in range + EntityPlayer player = this.worldObj.getClosestPlayerToEntity(this, MAX_AGGRO_RANGE); + boolean visibility = (player != null) ? player.canEntityBeSeen(this) : false; + this.updateAggroLevel(player, visibility); + + // Change orientation and face a player if one is in range + if (player != null) { - this.moveEntity(0, .1, 0); - } - - EntityPlayer entityPlayer = this.worldObj.getClosestPlayerToEntity(this, 35); - - if (entityPlayer != null) - { - if(this.soundTime<=0) + this.facePlayer(player); + if (!this.worldObj.isRemote && !(this.worldObj.provider instanceof LimboProvider)) { - this.playSound(mod_pocketDim.modid+":monk", 1F, 1F); - this.soundTime=100; + // Play sounds on the server side, if the player isn't in Limbo. + // Limbo is excluded to avoid drowning out its background music. + // Also, since it's a large open area with many Monoliths, some + // of the sounds that would usually play for a moment would + // keep playing constantly and would get very annoying. + this.playSounds(player); } - this.faceEntity(entityPlayer, 1, 1); - - if (shouldAttackPlayer(entityPlayer)) + if (visibility) { - if (aggro<470) + // Only spawn particles on the client side and outside Limbo + if (this.worldObj.isRemote && !(this.worldObj.provider instanceof LimboProvider)) { - if (rand.nextInt(11)>this.textureState||this.aggro>=300||rand.nextInt(13)>this.textureState&&this.aggroMax>this.aggro) - { - aggro++; - aggro++; - - } - if (this.worldObj.provider instanceof PocketProvider||this.worldObj.getClosestPlayerToEntity(this, 5)!=null) - { - aggro++; - - } - if (aggro>430&&this.soundTime<100) - { - this.worldObj.playSoundEffect(entityPlayer.posX, entityPlayer.posY, entityPlayer.posZ,mod_pocketDim.modid+":tearing",2F, 1F); - this.soundTime=100; - } - if (aggro>445&&this.soundTime<200) - { - this.worldObj.playSoundEffect(entityPlayer.posX, entityPlayer.posY, entityPlayer.posZ,mod_pocketDim.modid+":tearing",5F, 1F); - this.soundTime=200; - } + this.spawnParticles(player); } - else if (!this.worldObj.isRemote && !entityPlayer.capabilities.isCreativeMode) + + // Teleport the target player if various conditions are met + if (aggro >= MAX_AGGRO && !this.worldObj.isRemote && + properties.MonolithTeleportationEnabled && !player.capabilities.isCreativeMode && + !(this.worldObj.provider instanceof LimboProvider)) { - ChunkCoordinates coords = LimboProvider.getLimboSkySpawn(entityPlayer.worldObj.rand); - Point4D destination = new Point4D((int) (coords.posX+entityPlayer.posX), coords.posY, (int) (coords.posZ+entityPlayer.posZ ), mod_pocketDim.properties.LimboDimensionID); - DDTeleporter.teleportEntity(entityPlayer, destination, false); - this.aggro = 0; - entityPlayer.worldObj.playSoundAtEntity(entityPlayer,mod_pocketDim.modid+":crack",13, 1); - } - if (!(this.worldObj.provider instanceof LimboProvider || this.worldObj.getClosestPlayerToEntity(this, 5) != null) || this.aggro > 300) - { - for (int i = 0; i < -1+this.textureState/2; ++i) - { - entityPlayer.worldObj.spawnParticle("portal", entityPlayer.posX + (this.rand.nextDouble() - 0.5D) * this.width, entityPlayer.posY + this.rand.nextDouble() * entityPlayer.height - 0.75D, entityPlayer.posZ + (this.rand.nextDouble() - 0.5D) * entityPlayer.width, (this.rand.nextDouble() - 0.5D) * 2.0D, -this.rand.nextDouble(), (this.rand.nextDouble() - 0.5D) * 2.0D); - } + Point4D destination = LimboProvider.getLimboSkySpawn(player, properties); + DDTeleporter.teleportEntity(player, destination, false); + player.worldObj.playSoundAtEntity(player, mod_pocketDim.modid + ":crack", 13, 1); } } - else if(this.worldObj.provider instanceof PocketProvider) + } + } + + private void updateAggroLevel(EntityPlayer player, boolean visibility) + { + // If we're working on the server side, adjust aggro level + // If we're working on the client side, retrieve aggro level from dataWatcher + if (!this.worldObj.isRemote) + { + // Server side... + // Rapidly increase the aggro level if this Monolith can see the player + if (visibility) { - if(aggro0) - { - aggro--; - } + // Aggro increases faster outside of Limbo + aggro += 3; } } - } - else - { - if(aggro>0) + else { - aggro--; - - if(rand.nextBoolean()) + if (aggro > aggroCap) { + // Decrease aggro over time aggro--; } + else if (player != null && (aggro < aggroCap)) + { + // Increase aggro if a player is within range and aggro < aggroCap + aggro++; + } } - } - if (soundTime>=0) - { - soundTime--; - } - this.textureState= (byte) (this.aggro/25); - if (!this.worldObj.isRemote) - { - this.dataWatcher.updateObject(16, Byte.valueOf(this.textureState)); - } - } - - - private boolean shouldAttackPlayer(EntityPlayer par1EntityPlayer) - { - return par1EntityPlayer.canEntityBeSeen(this); - } - - public boolean attackEntityFrom(DamageSource par1DamageSource, int par2) - { - if (par1DamageSource == DamageSource.inWall) - { - this.posY = posY + 1; + // Clamp the aggro level + aggro = (short) MathHelper.clamp_int(aggro, 0, MAX_AGGRO); + this.dataWatcher.updateObject(AGGRO_WATCHER_INDEX, Short.valueOf(aggro)); } else { - this.aggro = this.aggroMax; + // Client side... + aggro = this.dataWatcher.getWatchableObjectShort(AGGRO_WATCHER_INDEX); } - return false; } - - @Override - public void faceEntity(Entity par1Entity, float par2, float par3) + + public int getTextureState() { - double d0 = par1Entity.posX - this.posX; - double d1 = par1Entity.posZ - this.posZ; - double d2; - - if (par1Entity instanceof EntityLiving) + // Determine texture state from aggro progress + return MathHelper.clamp_int(MAX_TEXTURE_STATE * aggro / MAX_AGGRO, 0, MAX_TEXTURE_STATE); + } + + /** + * Plays sounds at different levels of aggro, using soundTime to prevent too many sounds at once. + * @param entityPlayer + */ + private void playSounds(EntityPlayer entityPlayer) + { + float aggroPercent = this.getAggroProgress(); + if (this.soundTime <= 0) { - EntityLiving entityliving = (EntityLiving)par1Entity; - d2 = entityliving.posY + entityliving.getEyeHeight() - (this.posY + this.getEyeHeight()); + this.playSound(mod_pocketDim.modid + ":monk", 1F, 1F); + this.soundTime = 100; } - else + if ((aggroPercent > 0.70) && this.soundTime < 100) { - d2 = (par1Entity.boundingBox.minY + par1Entity.boundingBox.maxY) - (this.posY + this.getEyeHeight()); + this.worldObj.playSoundEffect(entityPlayer.posX, entityPlayer.posY, entityPlayer.posZ, mod_pocketDim.modid + ":tearing", 1F, (float) (1 + this.rand.nextGaussian())); + this.soundTime = 100 + this.rand.nextInt(75); } - + if ((aggroPercent > 0.80) && this.soundTime < 200) + { + this.worldObj.playSoundEffect(entityPlayer.posX, entityPlayer.posY, entityPlayer.posZ, mod_pocketDim.modid + ":tearing", 7, 1F); + this.soundTime = 250; + } + this.soundTime--; + } + + private void spawnParticles(EntityPlayer player) + { + int count = 10 * aggro / MAX_AGGRO; + for (int i = 1; i < count; ++i) + { + player.worldObj.spawnParticle("portal", player.posX + (this.rand.nextDouble() - 0.5D) * this.width, + player.posY + this.rand.nextDouble() * player.height - 0.75D, + player.posZ + (this.rand.nextDouble() - 0.5D) * player.width, + (this.rand.nextDouble() - 0.5D) * 2.0D, -this.rand.nextDouble(), + (this.rand.nextDouble() - 0.5D) * 2.0D); + } + } + + public float getAggroProgress() + { + return ((float) aggro) / MAX_AGGRO; + } + + private void facePlayer(EntityPlayer player) + { + double d0 = player.posX - this.posX; + double d1 = player.posZ - this.posZ; + double d2 = (player.posY + player.getEyeHeight()) - (this.posY + this.getEyeHeight()); double d3 = MathHelper.sqrt_double(d0 * d0 + d1 * d1); float f2 = (float)(Math.atan2(d1, d0) * 180.0D / Math.PI) - 90.0F; - float f3 = (float)(-(Math.atan2(d2, d3) * 180.0D / Math.PI)); - this.rotationPitch = f3; + this.pitchLevel = (float) -((Math.atan(d2/d3) )* 180.0D / Math.PI); this.rotationYaw = f2; - - this.rotationYaw = f2; - this.rotationYawHead=f2; - this.renderYawOffset=this.rotationYaw; + this.rotationYawHead = f2; + this.renderYawOffset = this.rotationYaw; } @Override - public float getRotationYawHead() + public void writeEntityToNBT(NBTTagCompound rootTag) { - return 0.0F; + super.writeEntityToNBT(rootTag); + rootTag.setInteger("Aggro", this.aggro); } @Override - public void writeEntityToNBT(NBTTagCompound par1NBTTagCompound) + public void readEntityFromNBT(NBTTagCompound rootTag) { - super.writeEntityToNBT(par1NBTTagCompound); - par1NBTTagCompound.setFloat("soundTime", this.soundTime); - par1NBTTagCompound.setInteger("aggro", this.aggro); - par1NBTTagCompound.setInteger("aggroMax", this.aggroMax); - par1NBTTagCompound.setByte("textureState", this.textureState); - par1NBTTagCompound.setFloat("scaleFactor", this.scaleFactor); - } - - @Override - public void readEntityFromNBT(NBTTagCompound par1NBTTagCompound) - { - super.readEntityFromNBT(par1NBTTagCompound); - this.soundTime = par1NBTTagCompound.getFloat("soundTime"); - this.aggro = par1NBTTagCompound.getInteger("aggro"); - this.aggroMax = par1NBTTagCompound.getInteger("aggroMax"); - this.textureState = par1NBTTagCompound.getByte("textureState"); - this.scaleFactor = par1NBTTagCompound.getFloat("scaleFactor"); + super.readEntityFromNBT(rootTag); + + // Load Monoliths with half aggro so they don't teleport players instantly + this.aggro = (short) (rootTag.getInteger("Aggro") / 2); } @Override @@ -332,7 +305,7 @@ public class MobMonolith extends EntityFlying implements IMob @SuppressWarnings("rawtypes") List list = this.worldObj.getEntitiesWithinAABBExcludingEntity(this, AxisAlignedBB.getBoundingBox( this.posX-15, posY-4, this.posZ-15, this.posX+15, this.posY+15, this.posZ+15)); - if(this.worldObj.provider.dimensionId==DDProperties.instance().LimboDimensionID) + if (this.worldObj.provider.dimensionId == DDProperties.instance().LimboDimensionID) { if(list.size()>0) { @@ -340,7 +313,7 @@ public class MobMonolith extends EntityFlying implements IMob } } - else if(this.worldObj.provider instanceof PocketProvider) + else if(this.worldObj.provider instanceof PocketProvider) { if (list.size() > 5 || this.worldObj.canBlockSeeTheSky((int)this.posX, (int)this.posY, (int)this.posZ)) @@ -352,9 +325,4 @@ public class MobMonolith extends EntityFlying implements IMob this.worldObj.getCollidingBoundingBoxes(this, this.boundingBox).isEmpty() && !this.worldObj.isAnyLiquid(this.boundingBox); } - - public DataWatcher getDataWatcher() - { - return this.dataWatcher; - } } \ No newline at end of file diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/ticking/RiftRegenerator.java b/src/main/java/StevenDimDoors/mod_pocketDim/ticking/RiftRegenerator.java index a50907b..f23c38c 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 = (List) 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 0000000..d618a51 --- /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 26057b4..58da365 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/DDTileEntityBase.java b/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/DDTileEntityBase.java new file mode 100644 index 0000000..a8cff85 --- /dev/null +++ b/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/DDTileEntityBase.java @@ -0,0 +1,13 @@ +package StevenDimDoors.mod_pocketDim.tileentities; +import java.util.Random; +import net.minecraft.tileentity.TileEntity; + +public abstract class DDTileEntityBase extends TileEntity +{ + /** + * + * @return an array of floats representing RGBA color where 1.0 = 255. + */ + public abstract float[] getRenderColor(Random rand); + +} diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityDimDoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityDimDoor.java index 923ecb1..57c10a8 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityDimDoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityDimDoor.java @@ -1,9 +1,15 @@ package StevenDimDoors.mod_pocketDim.tileentities; +import java.util.Random; + +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.network.packet.Packet; import StevenDimDoors.mod_pocketDim.ServerPacketHandler; import StevenDimDoors.mod_pocketDim.mod_pocketDim; -import StevenDimDoors.mod_pocketDim.blocks.IDimDoor; +import StevenDimDoors.mod_pocketDim.core.DimLink; import StevenDimDoors.mod_pocketDim.core.PocketManager; + +import StevenDimDoors.mod_pocketDim.watcher.ClientLinkData; import net.minecraft.block.Block; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.network.packet.Packet; @@ -11,46 +17,32 @@ import net.minecraft.network.packet.Packet130UpdateSign; import net.minecraft.network.packet.Packet250CustomPayload; import net.minecraft.tileentity.TileEntity; -public class TileEntityDimDoor extends TileEntity + + +public class TileEntityDimDoor extends DDTileEntityBase { public boolean openOrClosed; public int orientation; public boolean hasExit; + public byte lockStatus; public boolean isDungeonChainLink; public boolean hasGennedPair=false; @Override public boolean canUpdate() { - return true; + return false; } - @Override - public void updateEntity() - { - } @Override public Packet getDescriptionPacket() { if(PocketManager.getLink(xCoord, yCoord, zCoord, worldObj)!=null) { - return ServerPacketHandler.createLinkPacket(PocketManager.getLink(xCoord, yCoord, zCoord, worldObj).link()); + return ServerPacketHandler.createLinkPacket(new ClientLinkData(PocketManager.getLink(xCoord, yCoord, zCoord, worldObj))); } return null; } - - public void invalidate() - { - this.tileEntityInvalid = true; - - if(this.worldObj.getBlockId(xCoord, yCoord, zCoord)==0&&!this.worldObj.isRemote) - { - if(PocketManager.getLink(xCoord, yCoord, zCoord, worldObj)!=null) - { - mod_pocketDim.instance.fastRiftRegenerator.registerRiftForRegen(xCoord, yCoord, zCoord, this.worldObj.provider.dimensionId); - } - } - } @Override public void readFromNBT(NBTTagCompound nbt) @@ -75,7 +67,7 @@ public class TileEntityDimDoor extends TileEntity public void writeToNBT(NBTTagCompound nbt) { super.writeToNBT(nbt); - + nbt.setBoolean("openOrClosed", this.openOrClosed); nbt.setBoolean("hasExit", this.hasExit); nbt.setInteger("orientation", this.orientation); @@ -83,5 +75,22 @@ public class TileEntityDimDoor extends TileEntity nbt.setBoolean("hasGennedPair", hasGennedPair); } - + @Override + public float[] getRenderColor(Random rand) + { + float[] rgbaColor = {1,1,1,1}; + if (this.worldObj.provider.dimensionId == mod_pocketDim.NETHER_DIMENSION_ID) + { + rgbaColor[0] = rand.nextFloat() * 0.5F + 0.4F; + rgbaColor[1] = rand.nextFloat() * 0.05F; + rgbaColor[2] = rand.nextFloat() * 0.05F; + } + else + { + rgbaColor[0] = rand.nextFloat() * 0.5F + 0.1F; + rgbaColor[1] = rand.nextFloat() * 0.4F + 0.4F; + rgbaColor[2] = rand.nextFloat() * 0.6F + 0.5F; + } + return rgbaColor; + } } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityDimDoorGold.java b/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityDimDoorGold.java index 7dc1c64..6b9696e 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityDimDoorGold.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityDimDoorGold.java @@ -1,85 +1,93 @@ package StevenDimDoors.mod_pocketDim.tileentities; -import net.minecraft.world.ChunkCoordIntPair; import net.minecraftforge.common.ForgeChunkManager; import net.minecraftforge.common.ForgeChunkManager.Ticket; -import net.minecraftforge.common.ForgeChunkManager.Type; import StevenDimDoors.mod_pocketDim.IChunkLoader; -import StevenDimDoors.mod_pocketDim.mod_pocketDim; +import StevenDimDoors.mod_pocketDim.core.NewDimData; import StevenDimDoors.mod_pocketDim.core.PocketManager; -import StevenDimDoors.mod_pocketDim.util.Point4D; +import StevenDimDoors.mod_pocketDim.helpers.ChunkLoaderHelper; import StevenDimDoors.mod_pocketDim.world.PocketBuilder; public class TileEntityDimDoorGold extends TileEntityDimDoor implements IChunkLoader { private Ticket chunkTicket; + private boolean initialized = false; @Override public boolean canUpdate() { - return true; + return !initialized; + } + + @Override + public boolean isInitialized() + { + return initialized; } @Override public void updateEntity() - { // every tick? - if (PocketManager.getDimensionData(this.worldObj) != null && - PocketManager.getDimensionData(this.worldObj).isPocketDimension() && - !this.worldObj.isRemote) - { - if(PocketManager.getLink(this.xCoord,this.yCoord,this.zCoord,this.worldObj)==null) + { + if (!initialized) + { + initialize(null); + } + } + + @Override + public void initialize(Ticket ticket) + { + initialized = true; + chunkTicket = ticket; + + // Only do anything if this function is running on the server side + // NOTE: We don't have to check whether this block is the upper door + // block or the lower one because only one of them should have a + // link associated with it. + if (!worldObj.isRemote) + { + NewDimData dimension = PocketManager.createDimensionData(worldObj); + + // Check whether a ticket has already been assigned to this door + if (chunkTicket == null) { - return; - } - if (this.chunkTicket == null) - { - chunkTicket = ForgeChunkManager.requestTicket(mod_pocketDim.instance, worldObj, Type.NORMAL); - if(chunkTicket == null) + // No ticket yet. + // Check if this area should be loaded and request a new ticket. + if (isValidChunkLoaderSetup(dimension)) { - return; + chunkTicket = ChunkLoaderHelper.createTicket(xCoord, yCoord, zCoord, worldObj); } - chunkTicket.getModData().setInteger("goldDimDoorX", xCoord); - chunkTicket.getModData().setInteger("goldDimDoorY", yCoord); - chunkTicket.getModData().setInteger("goldDimDoorZ", zCoord); - forceChunkLoading(chunkTicket,this.xCoord,this.zCoord); + } + else + { + // A ticket has already been provided. + // Check if this area should be loaded. If not, release the ticket. + if (!isValidChunkLoaderSetup(dimension)) + { + ForgeChunkManager.releaseTicket(chunkTicket); + chunkTicket = null; + } + } + + // If chunkTicket isn't null at this point, then this is a valid door setup. + // The last step is to request force loading of the pocket's chunks. + if (chunkTicket != null) + { + ChunkLoaderHelper.forcePocketChunks(dimension, chunkTicket); } } } - - @Override - public void forceChunkLoading(Ticket chunkTicket,int x,int z) + + private boolean isValidChunkLoaderSetup(NewDimData dimension) { - Point4D origin = PocketManager.getDimensionData(this.worldObj).origin(); - int orientation = PocketManager.getDimensionData(this.worldObj).orientation(); + // Check the various conditions that make this a valid door setup. + // 1. The door must be inside the pocket's XZ boundaries, + // to prevent loading of chunks with a distant door + // 2. The dimension must be a pocket dimension + // 3. The door must be linked so that it's clear that it's not a normal door - int xOffset=0; - int zOffset=0; - - switch(orientation) - { - case 0: - xOffset = PocketBuilder.DEFAULT_POCKET_SIZE/2; - break; - case 1: - zOffset = PocketBuilder.DEFAULT_POCKET_SIZE/2; - - break; - case 2: - xOffset = -PocketBuilder.DEFAULT_POCKET_SIZE/2; - - break; - case 3: - zOffset = -PocketBuilder.DEFAULT_POCKET_SIZE/2; - - break; - } - for(int chunkX = -2; chunkX<3;chunkX++) - { - for(int chunkZ = -2; chunkZ<3;chunkZ++) - { - ForgeChunkManager.forceChunk(chunkTicket, new ChunkCoordIntPair((origin.getX()+xOffset >> 4)+chunkX, (origin.getZ()+zOffset >> 4)+chunkZ)); - } - } + return (dimension.isPocketDimension() && dimension.getLink(xCoord, yCoord, zCoord) != null && + PocketBuilder.calculateDefaultBounds(dimension).contains(xCoord, yCoord, zCoord)); } @Override diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityRift.java b/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityRift.java index 6432062..b5ee488 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityRift.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityRift.java @@ -1,17 +1,8 @@ package StevenDimDoors.mod_pocketDim.tileentities; - - import java.util.ArrayList; -import java.util.HashMap; import java.util.List; import java.util.Random; - -import cpw.mods.fml.common.FMLCommonHandler; -import cpw.mods.fml.common.network.PacketDispatcher; - -import net.minecraft.block.Block; -import net.minecraft.entity.DataWatcher; import net.minecraft.entity.Entity; import net.minecraft.entity.monster.EntityEnderman; import net.minecraft.entity.player.EntityPlayer; @@ -19,147 +10,118 @@ import net.minecraft.nbt.NBTTagCompound; import net.minecraft.network.INetworkManager; import net.minecraft.network.packet.Packet; import net.minecraft.network.packet.Packet132TileEntityData; -import net.minecraft.tileentity.TileEntity; import net.minecraft.util.AxisAlignedBB; import net.minecraft.util.MathHelper; -import net.minecraft.util.MovingObjectPosition; -import net.minecraft.util.Vec3; -import net.minecraft.world.World; -import StevenDimDoors.mod_pocketDim.DDProperties; import StevenDimDoors.mod_pocketDim.ServerPacketHandler; import StevenDimDoors.mod_pocketDim.mod_pocketDim; +import StevenDimDoors.mod_pocketDim.config.DDProperties; import StevenDimDoors.mod_pocketDim.core.DimLink; import StevenDimDoors.mod_pocketDim.core.NewDimData; import StevenDimDoors.mod_pocketDim.core.PocketManager; import StevenDimDoors.mod_pocketDim.util.Point4D; +import StevenDimDoors.mod_pocketDim.util.l_systems.LSystem; +import StevenDimDoors.mod_pocketDim.util.l_systems.LSystem.PolygonStorage; +import StevenDimDoors.mod_pocketDim.watcher.ClientLinkData; -public class TileEntityRift extends TileEntity +public class TileEntityRift extends DDTileEntityBase { - private static final int MAX_SPREAD_ATTEMPTS = 3; - private static final int MAX_SEARCH_ATTEMPTS = 50; - private static final int MAX_ANCESTOR_LINKS = 3; + private static final int RIFT_INTERACTION_RANGE = 5; + private static final int MAX_ANCESTOR_LINKS = 2; + private static final int MAX_CHILD_LINKS = 1; private static final int ENDERMAN_SPAWNING_CHANCE = 1; private static final int MAX_ENDERMAN_SPAWNING_CHANCE = 32; private static final int RIFT_SPREAD_CHANCE = 1; private static final int MAX_RIFT_SPREAD_CHANCE = 256; - + private static final int HOSTILE_ENDERMAN_CHANCE = 1; + private static final int MAX_HOSTILE_ENDERMAN_CHANCE = 3; + private static final int UPDATE_PERIOD = 200; + private static final int CLOSING_PERIOD = 40; + private static Random random = new Random(); - private int age = 0; - private int updateTimer = 0; - private int riftCloseTimer = 0; + private int updateTimer; + private int closeTimer = 0; public int xOffset = 0; public int yOffset = 0; public int zOffset = 0; public boolean shouldClose = false; - private boolean hasUpdated = false; - private boolean hasGrownRifts = false; - - public DimLink nearestRiftData; + public Point4D nearestRiftLocation = null; public int spawnedEndermenID = 0; - public HashMap renderingCenters = new HashMap(); + + public int riftRotation = random.nextInt(360); + public int renderKey = random.nextInt(LSystem.curves.size()); + public float growth = 0; + + public TileEntityRift() + { + // Vary the update times of rifts to prevent all the rifts in a cluster + // from updating at the same time. + updateTimer = random.nextInt(UPDATE_PERIOD); + } + @Override public void updateEntity() { - //Determines if rift should render white closing particles and spread closing effect to other rifts nearby - if (this.shouldClose) + if (PocketManager.getLink(xCoord, yCoord, zCoord, worldObj.provider.dimensionId) == null) { - closeRift(); - } - else if( PocketManager.getLink(xCoord, yCoord, zCoord, worldObj.provider.dimensionId) == null) - { - this.invalidate(); if (worldObj.getBlockId(xCoord, yCoord, zCoord) == mod_pocketDim.blockRift.blockID) { worldObj.setBlockToAir(xCoord, yCoord, zCoord); - worldObj.removeBlockTileEntity(xCoord, yCoord, zCoord); - this.invalidate(); - return; } + else + { + invalidate(); + } + return; } - + if (worldObj.getBlockId(xCoord, yCoord, zCoord) != mod_pocketDim.blockRift.blockID) { - worldObj.removeBlockTileEntity(xCoord, yCoord, zCoord); - this.invalidate(); + invalidate(); return; } + - //The code for the new rift rendering hooks in here, as well as in the ClientProxy to bind the TESR to the rift. - //It is inactive for now. - /** - if(rand.nextInt(15) == 1) - { - age = age + 1; - this.calculateNextRenderQuad(age, rand); - } - this.clearBlocksOnRift(); - **/ - - //This code should execute once every 10 seconds - if (updateTimer > 200) + // Check if this rift should render white closing particles and + // spread the closing effect to other rifts nearby. + if (shouldClose) { - this.spawnEndermen(); - this.grow(mod_pocketDim.properties); + closeRift(); + return; + } + + if (updateTimer >= UPDATE_PERIOD) + { + spawnEndermen(mod_pocketDim.properties); updateTimer = 0; } - else if(updateTimer==0) + else if (updateTimer == UPDATE_PERIOD / 2) { - this.calculateOldParticleOffset(); //this also calculates the distance for the particle stuff. + updateNearestRift(); + spread(mod_pocketDim.properties); } + growth += 1F/(growth+1); updateTimer++; - - } - @Override - public boolean canUpdate() + private void spawnEndermen(DDProperties properties) { - return true; - } - - private void clearBlocksOnRift() - { - //clears blocks for the new rending effect - for (double[] coord : this.renderingCenters.values()) - { - int x = MathHelper.floor_double(coord[0] + 0.5); - int y = MathHelper.floor_double(coord[1] + 0.5); - int z = MathHelper.floor_double(coord[2] + 0.5); - - // Right side - if (!mod_pocketDim.blockRift.isBlockImmune(worldObj, this.xCoord + x, this.yCoord + y, this.zCoord + z)) - { - worldObj.setBlockToAir(this.xCoord + x, this.yCoord + y, this.zCoord + z); - } - // Left side - if (!mod_pocketDim.blockRift.isBlockImmune(worldObj, this.xCoord - x, this.yCoord - y, this.zCoord - z)) - { - worldObj.setBlockToAir(this.xCoord - x, this.yCoord - y, this.zCoord - z); - } - } - } - - private void spawnEndermen() - { - if (worldObj.isRemote) + if (worldObj.isRemote || !properties.RiftsSpawnEndermenEnabled) { return; } - NewDimData dimension = PocketManager.getDimensionData(worldObj); - - //Ensure that this rift is only spawning one enderman at a time, to prevent hordes of endermen + // Ensure that this rift is only spawning one Enderman at a time, to prevent hordes of Endermen Entity entity = worldObj.getEntityByID(this.spawnedEndermenID); if (entity != null && entity instanceof EntityEnderman) { return; } - //enderman will only spawn in groups of rifts if (random.nextInt(MAX_ENDERMAN_SPAWNING_CHANCE) < ENDERMAN_SPAWNING_CHANCE) { + // Endermen will only spawn from groups of rifts if (updateNearestRift()) { List list = worldObj.getEntitiesWithinAABB(EntityEnderman.class, @@ -171,10 +133,10 @@ public class TileEntityRift extends TileEntity enderman.setLocationAndAngles(xCoord + 0.5, yCoord - 1, zCoord + 0.5, 5, 6); worldObj.spawnEntityInWorld(enderman); - if(this.worldObj.rand.nextInt(3)==0) + if (random.nextInt(MAX_HOSTILE_ENDERMAN_CHANCE) < HOSTILE_ENDERMAN_CHANCE) { EntityPlayer player = this.worldObj.getClosestPlayerToEntity(enderman, 50); - if(player!=null) + if (player != null) { enderman.setTarget(player); } @@ -183,123 +145,71 @@ public class TileEntityRift extends TileEntity } } } - - public boolean updateNearestRift() - { - nearestRiftData = PocketManager.getDimensionData(worldObj).findNearestRift(this.worldObj, 5, xCoord, yCoord, zCoord); - return (nearestRiftData != null); - } private void closeRift() { - NewDimData dimension = PocketManager.getDimensionData(worldObj); - if (riftCloseTimer == 20) + NewDimData dimension = PocketManager.createDimensionData(worldObj); + if (growth < CLOSING_PERIOD / 2) { - ArrayList rifts= dimension.findRiftsInRange(worldObj, 6, xCoord, yCoord, zCoord); - if (rifts.size()>0) + for (DimLink riftLink : dimension.findRiftsInRange(worldObj, 6, xCoord, yCoord, zCoord)) { - for(DimLink riftToClose : rifts) + Point4D location = riftLink.source(); + TileEntityRift rift = (TileEntityRift) worldObj.getBlockTileEntity(location.getX(), location.getY(), location.getZ()); + if (rift != null && !rift.shouldClose) { - Point4D location = riftToClose.source(); - TileEntityRift rift = (TileEntityRift) worldObj.getBlockTileEntity(location.getX(), location.getY(), location.getZ()); - if (rift != null) - { - rift.shouldClose = true; - rift.onInventoryChanged(); - } + rift.shouldClose = true; + rift.onInventoryChanged(); } } } - if (riftCloseTimer > 40) + if (growth == 0 && !worldObj.isRemote) { - this.invalidate(); - if(!this.worldObj.isRemote) + DimLink link = PocketManager.getLink(this.xCoord, this.yCoord, this.zCoord, worldObj); + if (link != null) { - DimLink link = PocketManager.getLink(this.xCoord, this.yCoord, this.zCoord, worldObj); - if(link!=null) - { - dimension.deleteLink(link); - } + dimension.deleteLink(link); } worldObj.setBlockToAir(xCoord, yCoord, zCoord); - worldObj.playSound(xCoord, yCoord, zCoord, "mods.DimDoors.sfx.riftClose", (float) .7, 1, true); - this.worldObj.removeBlockTileEntity(xCoord, yCoord, zCoord); - return; + worldObj.playSound(xCoord + 0.5, yCoord + 0.5, zCoord + 0.5, "mods.DimDoors.sfx.riftClose", 0.7f, 1, false); } - riftCloseTimer++; + + growth --; + } + + public boolean updateNearestRift() + { + Point4D previousNearest = nearestRiftLocation; + DimLink nearestRiftLink = PocketManager.createDimensionData(worldObj).findNearestRift( + worldObj, RIFT_INTERACTION_RANGE, xCoord, yCoord, zCoord); + + nearestRiftLocation = (nearestRiftLink == null) ? null : nearestRiftLink.source(); + + // If the nearest rift location changed, then update particle offsets + if (previousNearest != nearestRiftLocation && + (previousNearest == null || nearestRiftLocation == null || !previousNearest.equals(nearestRiftLocation))) + { + updateParticleOffsets(); + } + return (nearestRiftLocation != null); } - private void calculateOldParticleOffset() + private void updateParticleOffsets() { - updateNearestRift(); - if (nearestRiftData != null) + if (nearestRiftLocation != null) { - Point4D location = nearestRiftData.source(); - this.xOffset = this.xCoord - location.getX(); - this.yOffset = this.yCoord - location.getY(); - this.zOffset = this.zCoord - location.getZ(); - int distance = Math.abs(xOffset) + Math.abs(yOffset) + Math.abs(zOffset); + this.xOffset = this.xCoord - nearestRiftLocation.getX(); + this.yOffset = this.yCoord - nearestRiftLocation.getY(); + this.zOffset = this.zCoord - nearestRiftLocation.getZ(); } else { - this.xOffset=0; - this.yOffset=0; - this.xOffset=0; + this.xOffset = 0; + this.yOffset = 0; + this.xOffset = 0; } this.onInventoryChanged(); } - - private void calculateNextRenderQuad(float age, Random rand) - { - int maxSize = MathHelper.floor_double((Math.log(Math.pow(age+1,2)))); - int iteration=0; - while(iteration< maxSize) - { - iteration++; - double fl =Math.log(iteration+1)/(iteration); - double[] coords= new double[4]; - double noise = ((rand.nextGaussian())/(2+iteration/3+1)); - - if(!this.renderingCenters.containsKey(iteration-1)) - { - if (rand.nextBoolean()) - { - coords[0] = fl*1.5; - coords[1] = rand.nextGaussian()/5; - coords[2] = 0; - coords[3] = 1; - } - else - { - coords[0] = 0; - coords[1] = rand.nextGaussian()/5; - coords[2] = fl*1.5; - coords[3] = 0; - } - this.renderingCenters.put(iteration-1,coords); - iteration--; - } - else if(!this.renderingCenters.containsKey(iteration)) - { - if(this.renderingCenters.get(iteration-1)[3]==0) - { - coords[0]=noise/2+this.renderingCenters.get(iteration-1)[0]; - coords[1]=noise/2+this.renderingCenters.get(iteration-1)[1]; - coords[2]= this.renderingCenters.get(iteration-1)[2]+fl; - coords[3] = 0; - } - else - { - coords[0]=this.renderingCenters.get(iteration-1)[0]+fl; - coords[1]=noise/2+this.renderingCenters.get(iteration-1)[1]; - coords[2]=noise/2+this.renderingCenters.get(iteration-1)[2]; - coords[3] = 1; - } - this.renderingCenters.put(iteration,coords); - } - } - } - + @Override public boolean shouldRenderInPass(int pass) { @@ -312,113 +222,74 @@ public class TileEntityRift extends TileEntity { return countAncestorLinks(link.parent()) + 1; } - else - { - return 0; - } + return 0; } - public void grow(DDProperties properties) + public void spread(DDProperties properties) { - if (worldObj.isRemote || hasGrownRifts || !properties.RiftSpreadEnabled + if (worldObj.isRemote || !properties.RiftSpreadEnabled || random.nextInt(MAX_RIFT_SPREAD_CHANCE) < RIFT_SPREAD_CHANCE || this.shouldClose) { return; } - NewDimData dimension = PocketManager.getDimensionData(worldObj); + NewDimData dimension = PocketManager.createDimensionData(worldObj); DimLink link = dimension.getLink(xCoord, yCoord, zCoord); - if (countAncestorLinks(link) > MAX_ANCESTOR_LINKS) + if (link.childCount() >= MAX_CHILD_LINKS || countAncestorLinks(link) >= MAX_ANCESTOR_LINKS) { return; } - // The probability of rifts trying to spread increases if more rifts are nearby - // Players should see rifts spread faster within clusters than at the edges of clusters + // The probability of rifts trying to spread increases if more rifts are nearby. + // Players should see rifts spread faster within clusters than at the edges of clusters. // Also, single rifts CANNOT spread. - int nearRifts = dimension.findRiftsInRange(this.worldObj, 5, xCoord, yCoord, zCoord).size(); + int nearRifts = dimension.findRiftsInRange(worldObj, RIFT_INTERACTION_RANGE, xCoord, yCoord, zCoord).size(); if (nearRifts == 0 || random.nextInt(nearRifts) == 0) { return; } - - int x, y, z; - int spreadAttempts = 0; - for (int searchAttempts = 0; searchAttempts < MAX_SEARCH_ATTEMPTS; searchAttempts++) - { - x = xCoord + MathHelper.getRandomIntegerInRange(random, -6, 6); - y = yCoord + MathHelper.getRandomIntegerInRange(random, -4, 4); - z = zCoord + MathHelper.getRandomIntegerInRange(random, -6, 6); - - if (y >= 0 && y < worldObj.getActualHeight() && worldObj.isAirBlock(x, y, z)) - { - Vec3 position = worldObj.getWorldVec3Pool().getVecFromPool(xCoord, yCoord, zCoord); - Vec3 spreadTarget = worldObj.getWorldVec3Pool().getVecFromPool(x, y, z); - MovingObjectPosition hit = worldObj.clip(position, spreadTarget, false); - if (hit == null || !mod_pocketDim.blockRift.isBlockImmune(worldObj, hit.blockX, hit.blockY, hit.blockZ)) - { - if(hit!=null) - { - dimension.createChildLink(hit.blockX, hit.blockY, hit.blockZ, link); - this.worldObj.setBlock(hit.blockX, hit.blockY, hit.blockZ, mod_pocketDim.blockRift.blockID); - } - else - { - dimension.createChildLink(x,y,z,link); - this.worldObj.setBlock(x,y,z, mod_pocketDim.blockRift.blockID); - } - hasGrownRifts = true; - break; - } - else - { - spreadAttempts++; - if (spreadAttempts >= MAX_SPREAD_ATTEMPTS) - { - break; - } - } - } - } + mod_pocketDim.blockRift.spreadRift(dimension, link, worldObj, random); } @Override public void readFromNBT(NBTTagCompound nbt) { super.readFromNBT(nbt); - this.renderingCenters = new HashMap(); - this.updateTimer = nbt.getInteger("count"); - this.riftCloseTimer = nbt.getInteger("count2"); + this.updateTimer = nbt.getInteger("updateTimer"); this.xOffset = nbt.getInteger("xOffset"); this.yOffset = nbt.getInteger("yOffset"); this.zOffset = nbt.getInteger("zOffset"); - this.hasGrownRifts = nbt.getBoolean("grownRifts"); - this.age = nbt.getInteger("age"); this.shouldClose = nbt.getBoolean("shouldClose"); this.spawnedEndermenID = nbt.getInteger("spawnedEndermenID"); + this.riftRotation = nbt.getInteger("riftRotation"); + this.renderKey = nbt.getInteger("renderKey"); + this.growth = nbt.getFloat("growth"); + } @Override public void writeToNBT(NBTTagCompound nbt) { super.writeToNBT(nbt); - nbt.setInteger("age", this.age); - nbt.setInteger("count", this.updateTimer); - nbt.setInteger("count2", this.riftCloseTimer); - nbt.setBoolean("grownRifts",this.hasGrownRifts); + nbt.setInteger("updateTimer", this.updateTimer); nbt.setInteger("xOffset", this.xOffset); nbt.setInteger("yOffset", this.yOffset); nbt.setInteger("zOffset", this.zOffset); nbt.setBoolean("shouldClose", this.shouldClose); nbt.setInteger("spawnedEndermenID", this.spawnedEndermenID); + nbt.setInteger("renderKey", this.renderKey); + nbt.setInteger("riftRotation", this.riftRotation); + nbt.setFloat("growth", this.growth); + } + @Override public Packet getDescriptionPacket() { if (PocketManager.getLink(xCoord, yCoord, zCoord, worldObj) != null) { - return ServerPacketHandler.createLinkPacket(PocketManager.getLink(xCoord, yCoord, zCoord, worldObj).link()); + return ServerPacketHandler.createLinkPacket(new ClientLinkData(PocketManager.getLink(xCoord, yCoord, zCoord, worldObj))); } return null; } @@ -428,4 +299,17 @@ public class TileEntityRift extends TileEntity { readFromNBT(pkt.data); } + + @Override + public float[] getRenderColor(Random rand) + { + return null; + } + + public PolygonStorage getCurve() + { + + + return (LSystem.curves.get(renderKey)); + } } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityTransTrapdoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityTransTrapdoor.java index 125a225..3df7f6c 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityTransTrapdoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityTransTrapdoor.java @@ -1,44 +1,33 @@ package StevenDimDoors.mod_pocketDim.tileentities; -import net.minecraft.nbt.NBTTagCompound; -import net.minecraft.tileentity.TileEntity; +import java.util.Random; -public class TileEntityTransTrapdoor extends TileEntity +import StevenDimDoors.mod_pocketDim.mod_pocketDim; + +public class TileEntityTransTrapdoor extends DDTileEntityBase { - public boolean hasRift; - - - @Override public boolean canUpdate() { - return true; + return false; } @Override - public void updateEntity() + public float[] getRenderColor(Random rand) { - - } - - @Override - public void readFromNBT(NBTTagCompound nbt) - { - super.readFromNBT(nbt); - try + float[] rgbaColor = {1,1,1,1}; + if (this.worldObj.provider.dimensionId == mod_pocketDim.NETHER_DIMENSION_ID) { - this.hasRift = nbt.getBoolean("hasRift"); + rgbaColor[0] = worldObj.rand.nextFloat() * 0.5F + 0.4F; + rgbaColor[1] = worldObj.rand.nextFloat() * 0.05F; + rgbaColor[2] = worldObj.rand.nextFloat() * 0.05F; } - catch (Exception e) + else { - + rgbaColor[0] = worldObj.rand.nextFloat() * 0.5F + 0.1F; + rgbaColor[1] = worldObj.rand.nextFloat() * 0.4F + 0.4F; + rgbaColor[2] = worldObj.rand.nextFloat() * 0.6F + 0.5F; } - } - - @Override - public void writeToNBT(NBTTagCompound nbt) - { - super.writeToNBT(nbt); - nbt.setBoolean("hasRift", this.hasRift); + return rgbaColor; } } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/util/DDLogger.java b/src/main/java/StevenDimDoors/mod_pocketDim/util/DDLogger.java new file mode 100644 index 0000000..18ebda0 --- /dev/null +++ b/src/main/java/StevenDimDoors/mod_pocketDim/util/DDLogger.java @@ -0,0 +1,106 @@ +package StevenDimDoors.mod_pocketDim.util; + +import java.util.ArrayList; +import java.util.HashMap; + +public class DDLogger +{ + private static DDLogger instance; + private StringBuilder log; + private HashMap timers = new HashMap(); + + private DDLogger() + { + this.log = new StringBuilder(); + this.log.append("Logger started.\n"); + } + + // SenseiKiwi: I changed this to private to guarantee that the logger isn't being used anywhere. + private static DDLogger logger() + { + if( instance == null) + { + instance = new DDLogger(); + } + return instance; + } + + private class DDTimer + { + final String description; + Long startTime; + Long endTime; + boolean stopped = false; + + private DDTimer(String description) + { + this.description=description; + } + private void start() + { + this.startTime=System.nanoTime(); + } + private void stop(long endTime) + { + this.endTime=endTime; + if(!this.stopped) + { + this.stopped=true; + log.append(this.description+" took "+this.getDuration()+" seconds to execute.\n"); + } + } + /** + * @return the duration in seconds, returns -1 if it still running + */ + public double getDuration() + { + if(this.stopped) + { + return (this.endTime-this.startTime)/1000000000D; + } + return -1; + } + } + + /** + * Creates and starts a timer. + * + * @param description: The string used to identify the timer + * @return + */ + public static void startTimer(String description) + { + DDTimer timer = logger().new DDTimer(description); + logger().timers.put(description, timer); + timer.start(); + } + + /**Stops and records a timer to the log + * + * @param description + * @return + */ + public static double stopTimer(String description) + { + long endTime = System.nanoTime(); + DDTimer timer = logger().timers.get(description); + if(timer==null) + { + return -1; + } + timer.stop(endTime); + logger().timers.remove(description); + return timer.getDuration(); + } + + public String printLog() + { + return this.log.toString(); + } + + public void clearLog() + { + this.log = new StringBuilder(); + } + +} diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/util/JSONValidator.java b/src/main/java/StevenDimDoors/mod_pocketDim/util/JSONValidator.java new file mode 100644 index 0000000..449db41 --- /dev/null +++ b/src/main/java/StevenDimDoors/mod_pocketDim/util/JSONValidator.java @@ -0,0 +1,544 @@ +package StevenDimDoors.mod_pocketDim.util; + +import static java.util.Collections.singleton; +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; +import com.google.gson.JsonPrimitive; + +public class JSONValidator +{ + + static final public String TYPE = "type"; + static final public String ANY = "any"; + static final public String PROPERTIES = "properties"; + static final public String OPTIONAL = "optional"; + static final public String ADDITIONAL_PROPERTIES = "additionalProperties"; + static final public String MIN_LENGTH = "minLength"; + static final public String MAX_LENGTH = "maxLength"; + static final public String MINIMUM = "minimum"; + static final public String MAXIMUM = "maximum"; + static final public String PATTERN = "pattern"; + static final public String ITEMS = "items"; + static final public String ENUM = "enum"; + static final public String REQUIRED = "required"; + + + JsonObject schema; + + public JsonObject getSchema() + { + return schema; + } + + public JSONValidator(JsonObject schema) + { + this.schema = schema; + } + + static class WrongType extends JsonParseException + { + /** + * + */ + private static final long serialVersionUID = 1L; + + WrongType(String msg) + { + super(msg); + } + + static WrongType generate(String path, Set types, Type found) + { + boolean first = true; + String typeList = "'unknown'"; + for (Type type : types) + { + if (first) + { + typeList = "'" + type.getTypeString() + "'"; + first = false; + } + else + { + typeList += " or '" + type.getTypeString() + "'"; + } + } + + return new WrongType("Invalid: Expected type " + typeList + " at '" + path + "', but " + "found type '" + found.getTypeString() + "'"); + } + } + + static enum Type + { + STRING("string"), NUMBER("number"), INTEGER("integer"), BOOLEAN("boolean"), OBJECT("object"), ARRAY("array"), NULL("null"); + + String typeString; + + Type(String typeString) + { + this.typeString = typeString; + } + + public String getTypeString() + { + return typeString; + } + } + + static Set anyTypeSet() + { + HashSet hashSet = new HashSet(); + hashSet.add(Type.STRING); + hashSet.add(Type.NUMBER); + hashSet.add(Type.INTEGER); + hashSet.add(Type.BOOLEAN); + hashSet.add(Type.OBJECT); + hashSet.add(Type.ARRAY); + hashSet.add(Type.NULL); + return hashSet; + } + + static Set getSimpleType(String path, String type) + { + for (Type t : Type.values()) + { + if (t.getTypeString().equals(type)) + { + if (t != Type.NUMBER) + { + return singleton(t); + } + else + { + HashSet set = new HashSet(); + set.add(Type.NUMBER); + set.add(Type.INTEGER); + return set; + } + } + } + + if (ANY.equals(type)) + { + return anyTypeSet(); + } + + // Unknown type, spec says to allow any. + return anyTypeSet(); + } + + static Set getTypeSet(String path, JsonObject schema) throws JsonParseException + { + JsonElement typeElement = schema.get(TYPE); + + if (typeElement == null) + { + // Spec says that a missing type object means accept any type. + return anyTypeSet(); + } + + if (typeElement.isJsonPrimitive()) + { + JsonPrimitive primitive = typeElement.getAsJsonPrimitive(); + if (primitive.isString()) + { + return getSimpleType(path, primitive.getAsString()); + } + } + + if (typeElement.isJsonArray()) + { + HashSet set = new HashSet(); + JsonArray array = typeElement.getAsJsonArray(); + for (JsonElement element : array) + { + if (element.isJsonPrimitive()) + { + JsonPrimitive primitive = element.getAsJsonPrimitive(); + if (primitive.isString()) + { + set.addAll(getSimpleType(path, primitive.getAsString())); + } + } + + // Unknown type. Accept all. + return anyTypeSet(); + } + } + + // Don't know what this is, assume any. + return anyTypeSet(); + } + + static Type getType(JsonElement element) + { + if (element.isJsonArray()) + { + return Type.ARRAY; + } + if (element.isJsonObject()) + { + return Type.OBJECT; + } + if (element.isJsonNull()) + { + return Type.NULL; + } + JsonPrimitive primitive = element.getAsJsonPrimitive(); + if (primitive.isString()) + { + return Type.STRING; + } + if (primitive.isBoolean()) + { + return Type.BOOLEAN; + } + if (primitive.isNumber()) + { + BigDecimal decimal = primitive.getAsBigDecimal(); + int scale = decimal.scale(); + if (scale > 0) + { + return Type.NUMBER; + } + else + { + return Type.INTEGER; + } + } + + // Don't know. Punt and call it a string. + return Type.STRING; + } + + static void validateObject(String path, JsonObject schema, JsonObject obj) throws JsonParseException + { + Set propertiesSeen = new HashSet(); + + JsonArray required = schema.getAsJsonArray(REQUIRED); + JsonObject properties = schema.getAsJsonObject(PROPERTIES); + + if (properties == null) + { + return; + } + + Set> propertySet = properties.entrySet(); + ArrayList requiredFields = new ArrayList(); + + for(JsonElement st : required.getAsJsonArray()) + { + requiredFields.add(st.getAsString()); + } + + for (Map.Entry property : propertySet) + { + String name = property.getKey(); + String newPath = path + "['" + name + "']"; + JsonElement element = property.getValue(); + propertiesSeen.add(name); + + if (!element.isJsonObject()) + { + throw new JsonParseException("Bad Schema: property definition not an object at '" + newPath + "'"); + } + + JsonObject definition = element.getAsJsonObject(); + + JsonElement newTarget = obj.get(name); + + if (newTarget == null) + { + JsonPrimitive optional = definition.getAsJsonPrimitive(OPTIONAL); + boolean needed = ((optional==null) && requiredFields.contains(name)) || (optional != null && !optional.getAsBoolean()); + + if (needed) + { + throw new JsonParseException("Invalid: Required property '" + newPath + "' not found"); + } + } + else + { + validate(newPath, definition, newTarget); + } + } + + JsonElement additionalProperties = schema.get(ADDITIONAL_PROPERTIES); + JsonObject additionalSchema = null; + if (additionalProperties == null) + { + additionalSchema = new JsonObject(); + } + else + { + if (additionalProperties.isJsonObject()) + { + additionalSchema = additionalProperties.getAsJsonObject(); + } + } + + /* + * if (additionalSchema == null) { + * logger.debug("No additional schema for '"+path+"'"); } else { + * logger.debug("Additional schema for '"+path+"': "+ + * additionalSchema.toString()); } + */ + + Set> objectProperties = obj.entrySet(); + for (Map.Entry property : objectProperties) + { + String name = property.getKey(); + String newPath = path + "['" + name + "']"; + if (!propertiesSeen.contains(name)) + { + if (additionalSchema == null) + { + throw new JsonParseException("Invalid: Found additional property '" + newPath + "'"); + } + validate(newPath, additionalSchema, property.getValue()); + } + } + } + + static Integer getInt(String path, String attributeName, JsonObject schema) throws JsonParseException + { + JsonElement attributeElement = schema.get(attributeName); + + if (attributeElement == null) + { + return null; + } + + if (!attributeElement.isJsonPrimitive()) + { + throw new JsonParseException("Bad Schema: '" + attributeName + "' attribute is not an integer at '" + path + "'"); + } + JsonPrimitive attributePrimitive = attributeElement.getAsJsonPrimitive(); + if (!attributePrimitive.isNumber()) + { + throw new JsonParseException("Bad Schema: '" + attributeName + "' attribute is not an integer at '" + path + "'"); + } + + return attributePrimitive.getAsInt(); + } + + static String getString(String path, String attributeName, JsonObject schema) throws JsonParseException + { + JsonElement attributeElement = schema.get(attributeName); + + if (attributeElement == null) + { + return null; + } + + if (!attributeElement.isJsonPrimitive()) + { + throw new JsonParseException("Bad Schema: '" + attributeName + "' attribute is not a string at '" + path + "'"); + } + JsonPrimitive attributePrimitive = attributeElement.getAsJsonPrimitive(); + if (!attributePrimitive.isString()) + { + throw new JsonParseException("Bad Schema: '" + attributeName + "' attribute is not a string at '" + path + "'"); + } + + return attributePrimitive.getAsString(); + } + + static BigDecimal getBigDecimal(String path, String attributeName, JsonObject schema) throws JsonParseException + { + JsonElement attributeElement = schema.get(attributeName); + + if (attributeElement == null) + { + return null; + } + + if (!attributeElement.isJsonPrimitive()) + { + throw new JsonParseException("Bad Schema: '" + attributeName + "' attribute is not a number at '" + path + "'"); + } + JsonPrimitive attributePrimitive = attributeElement.getAsJsonPrimitive(); + if (!attributePrimitive.isNumber()) + { + throw new JsonParseException("Bad Schema: '" + attributeName + "' attribute is not a number at '" + path + "'"); + } + + return attributePrimitive.getAsBigDecimal(); + } + + static void validateString(String path, JsonObject schema, String str) throws JsonParseException + { + Integer minLength = getInt(path, MIN_LENGTH, schema); + Integer maxLength = getInt(path, MAX_LENGTH, schema); + + if ((minLength != null) && (str.length() < minLength)) + { + throw new JsonParseException("Invalid: String '" + path + "' is too short. The string needs to be more than " + minLength + " characters"); + } + + if ((maxLength != null) && (str.length() > maxLength)) + { + throw new JsonParseException("Invalid: String '" + path + "' is too long. The string needs to be less than " + maxLength + " characters"); + } + + String pattern = getString(path, PATTERN, schema); + if ((pattern != null) && (!str.matches(pattern))) + { + throw new JsonParseException("Invalid: String '" + path + "' does not match pattern '" + pattern + "'"); + } + } + + static void validateTuple(String path, JsonArray tupleSchema, JsonObject additionalSchema, JsonArray array) throws JsonParseException + { + return; + } + + static void validateArray(String path, JsonObject schema, JsonArray array) throws JsonParseException + { + JsonElement additionalProperties = schema.get(ADDITIONAL_PROPERTIES); + JsonObject additionalSchema = null; + if (additionalProperties == null) + { + additionalSchema = new JsonObject(); + } + else + { + if (additionalProperties.isJsonObject()) + { + additionalSchema = additionalProperties.getAsJsonObject(); + } + } + + JsonElement itemsElement = schema.get(ITEMS); + if (itemsElement == null) + { + return; + } + + if (itemsElement.isJsonArray()) + { + validateTuple(path, itemsElement.getAsJsonArray(), additionalSchema, array); + return; + } + + JsonObject itemsSchema = null; + if (itemsElement.isJsonObject()) + { + itemsSchema = itemsElement.getAsJsonObject(); + } + else + { + // Bogus items parameter, assume everything is valid. + itemsSchema = new JsonObject(); + } + + int i = 0; + for (JsonElement element : array) + { + ++i; + String curPath = path + "[" + i + "]"; + validate(curPath, itemsSchema, element); + } + } + + static void validateEnum(String path, JsonObject schema, JsonElement element) throws JsonParseException + { + JsonElement enumElement = schema.get(ENUM); + if (enumElement == null) + { + return; + } + + if (!enumElement.isJsonArray()) + {} + + JsonArray enumArray = enumElement.getAsJsonArray(); + + for (JsonElement curElement : enumArray) + { + if (element.equals(curElement)) + { + // We found a valid value. + return; + } + } + + throw new JsonParseException("Invalid: Property '" + path + "' is not one of the enum values."); + } + + static void validateNumber(String path, JsonObject schema, BigDecimal number) throws JsonParseException + { + BigDecimal minimum = getBigDecimal(path, MINIMUM, schema); + if (minimum != null) + { + if (number.compareTo(minimum) < 0) + { + throw new JsonParseException("Invalid: Property '" + path + "' has a value of '" + number + "' which is less than the minimum of '" + minimum + + "'."); + } + } + + BigDecimal maximum = getBigDecimal(path, MAXIMUM, schema); + if (maximum != null) + { + if (number.compareTo(maximum) > 0) + { + throw new JsonParseException("Invalid: Property '" + path + "' has a value of '" + number + "' which is greater than the maximum of '" + + maximum + "'."); + } + } + } + + static void validate(String path, JsonObject schema, JsonElement element) throws JsonParseException + { + Set typeSet = getTypeSet(path, schema); + + Type type = getType(element); + if (!typeSet.contains(type)) + { + throw WrongType.generate(path, typeSet, type); + } + + switch (type) + { + case BOOLEAN: + case NULL: + break; + case NUMBER: + case INTEGER: + validateNumber(path, schema, element.getAsBigDecimal()); + break; + case ARRAY: + validateArray(path, schema, element.getAsJsonArray()); + break; + case STRING: + validateString(path, schema, element.getAsString()); + break; + case OBJECT: + validateObject(path, schema, element.getAsJsonObject()); + break; + default: + // Unknown type + throw new JsonParseException("Internal Error"); + } + + validateEnum(path, schema, element); + } + + static public void validate(JsonObject schema, JsonElement element) throws JsonParseException + { + validate("$", schema, element); + } + + public void validate(JsonElement element) throws JsonParseException + { + validate(getSchema(), element); + } +} diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/util/Point4D.java b/src/main/java/StevenDimDoors/mod_pocketDim/util/Point4D.java index 2b6c4c0..2693e63 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/util/Point4D.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/util/Point4D.java @@ -141,12 +141,14 @@ public final class Point4D implements Comparable public Point3D toPoint3D() { - return new Point3D(this.x,this.y,this.z); + return new Point3D(this.x, this.y, this.z); } + public int[] toIntArray() { - return new int[]{x,y,z,dimension}; + return new int[] {x, y, z, dimension}; } + public boolean equals(Point4D other) { if (this == other) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/util/l_systems/LSystem.java b/src/main/java/StevenDimDoors/mod_pocketDim/util/l_systems/LSystem.java new file mode 100644 index 0000000..46d83ec --- /dev/null +++ b/src/main/java/StevenDimDoors/mod_pocketDim/util/l_systems/LSystem.java @@ -0,0 +1,557 @@ +package StevenDimDoors.mod_pocketDim.util.l_systems; + +import java.awt.Point; +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import javax.swing.SwingUtilities; +import org.poly2tri.Poly2Tri; +import org.poly2tri.geometry.polygon.Polygon; +import org.poly2tri.geometry.polygon.PolygonPoint; +import org.poly2tri.triangulation.TriangulationPoint; +import org.poly2tri.triangulation.delaunay.DelaunayTriangle; + + +public class LSystem +{ + public static ArrayList curves = new ArrayList(); + + /** + * An array containing the args to generate a curve. + * index 0 = rules + * index 1 = angle + * index 2 = start string + */ + public static final String[] TERDRAGON = {"F>+F----F++++F-","60","F"}; + public static final String[] DRAGON = {"X>X+YF:Y>FX-Y","90","FX"}; + public static final String[] TWINDRAGON = {"X>X+YF:Y>FX-Y","90","FX--FX"}; + public static final String[] VORTEX = {"X>X+YF:Y>FX-Y","90","FX---FX"}; + + + + /** + * Generates a fractal curve + * @param args: 0 = rules, 1 = angle, 2 = start + * @param steps + * @return + */ + public static void generateLSystem(String key, String[] args, int steps) + { + //Parse the rules from the first index + String[] rules = args[0].split(":"); + HashMap lSystemsRule = new HashMap(); + + for (String rule : rules) + { + String[] parts = rule.split(">"); + lSystemsRule.put(parts[0], parts[1]); + } + + //get the angle for each turn + int angle = Integer.parseInt(args[1]); + + + //String to hold the output + //Initialize with starting string + String output = args[2]; + + //generate the l-system + output = (generate(args[2], steps, lSystemsRule)); + + //get the boundary of the polygon + PolygonStorage polygon = getBoundary(convertToPoints(angle, output, (steps))); + + //replace the boundary of the polygon with a series of points representing triangles for rendering + polygon.points = tesselate(polygon); + + curves.add(polygon); + + } + + /** + * Naively returns all of the points comprising the fractal + * @param input + * @return + */ + public static PolygonStorage getSpaceFillingCurve(ArrayList input) + { + // store max x and y values to create bounding box + int maxY = Integer.MIN_VALUE; + int maxX = Integer.MIN_VALUE; + int minY = Integer.MAX_VALUE; + int minX = Integer.MAX_VALUE; + + // store confirmed duplicates here + HashSet duplicates = new HashSet(); + + // store possible singles here + HashSet singles = new HashSet(); + + // list to store confirmed singles and output in the correct order + ArrayList output = new ArrayList(); + + // sort into Hashmaps and hashsets to make contains operations possible, + // while testing for duplicates + for (double[] point : input) + { + // convert doubles to ints and record min/max values + + int xCoord = (int) Math.round(point[0]); + int yCoord = (int) Math.round(point[1]); + + if (xCoord > maxX) + { + maxX = xCoord; + } + if (xCoord < minX) + { + minX = xCoord; + } + + if (yCoord > maxY) + { + maxY = yCoord; + } + if (yCoord < minY) + { + minY = yCoord; + } + output.add(new Point(xCoord, yCoord)); + } + return new PolygonStorage(output, maxX, maxY, minX, minY); + + } + + /** + * Takes an unordered list of points comprising a fractal curve and builds a + * closed polygon around it + * + * @param input + * @return + */ + public static PolygonStorage getBoundary(ArrayList input) + { + // store max x and y values to create bounding box + int maxY = Integer.MIN_VALUE; + int maxX = Integer.MIN_VALUE; + int minY = Integer.MAX_VALUE; + int minX = Integer.MAX_VALUE; + + // store confirmed duplicates here + HashSet duplicates = new HashSet(); + + // store possible singles here + HashSet singles = new HashSet(); + + // list to store confirmed singles and output in the correct order + ArrayList output = new ArrayList(); + + // sort into Hashmaps and hashsets to make contains operations possible, + // while testing for duplicates + for (double[] point : input) + { + // convert doubles to ints and record min/max values + + int xCoord = (int) Math.round(point[0]); + int yCoord = (int) Math.round(point[1]); + + if (xCoord > maxX) + { + maxX = xCoord; + } + if (xCoord < minX) + { + minX = xCoord; + } + + if (yCoord > maxY) + { + maxY = yCoord; + } + if (yCoord < minY) + { + minY = yCoord; + } + singles.add(new Point(xCoord, yCoord)); + + } + + // find a suitable starting point + Point startPoint = new Point(minX, minY); + Point prevPoint = (Point) startPoint.clone(); + + while (startPoint.y < maxY) + { + if (singles.contains(startPoint)) + { + break; + } + startPoint.y++; + } + + // record the first point so we know where to stop + final Point firstPoint = (Point) startPoint.clone(); + + // determine the direction to start searching from + Point direction = getVector(prevPoint, startPoint); + + //output.add(startPoint); + + // loop around in a clockwise circle, jumping to the next point when we + // find it and resetting the direction to start seaching from + // to the last found point. This ensures we always find the next + // *outside* point + do + { + // get the next point + direction = rotateCounterClockwise(direction); + Point target = new Point(startPoint.x + direction.x, startPoint.y + direction.y); + + // see if that point is part of our fractal curve + if (singles.contains(target)) + { + if(target.equals(firstPoint)) + { + output.remove(output.get(output.size()-1)); + break; + } + // get the vector to start from for the next cycle + direction = getVector(startPoint, target); + + // prune zero width spikes + if ((output.size() > 1 && output.get(output.size() - 2).equals(target))) + { + output.remove(output.size() - 1); + } + else + { + + if(output.contains(target)&&!target.equals(output.get(0))) + { + int index = output.indexOf(target); + while(output.size()>index) + { + output.remove(output.size()-1); + } + + } + output.add(target); + } + startPoint = target; + } + } + while (!(output.get(output.size() - 1).equals(firstPoint) && output.size() > 1) && output.size() < singles.size()); + + return new PolygonStorage(output, maxX, maxY, minX, minY); + } + + /** + * using a point as a 2d vector, normalize it (sorta) + * + * @param origin + * @param destination + * @return + */ + public static Point getVector(Point origin, Point destination) + { + int[] normals = { origin.x - destination.x, origin.y - destination.y }; + + for (int i = 0; i < normals.length; i++) + { + if (normals[i] > 0) + { + normals[i] = 1; + } + else if (normals[i] == 0) + { + normals[i] = 0; + } + else if (normals[i] < 0) + { + normals[i] = -1; + } + } + return new Point(normals[0], normals[1]); + } + + /** + * rotate a normal around the origin + * + * @param previous + * @return + */ + public static Point rotateCounterClockwise(Point previous) + { + Point point = new Point(); + + point.x = (int) (previous.x * Math.cos(Math.toRadians(90)) - previous.y * Math.sin(Math.toRadians(90))); + point.y = (int) (previous.x * Math.sin(Math.toRadians(90)) + previous.y * Math.cos(Math.toRadians(90))); + + return point; + } + + /** + * Take an l-system string and convert it into a series of points on a + * cartesian grid. Designed to keep terdragons oriented the same direction + * regardless of iterations + * + * @param angle + * @param system + * @param generations + * @return + */ + public static ArrayList convertToPoints(double angle, String system, int generations) + { + + // determine the starting point and rotation to begin drawing from + int rotation = (generations % 2) == 0 ? 2 : 4; + double[] currentState = { ((generations + rotation) % 4) * 90, 0, 0 }; + + // the output for a totally unordered list of points defining the curve + ArrayList output = new ArrayList(); + + // the stack used to deal with branching l-systems that use [ and ] + ArrayDeque state = new ArrayDeque(); + + // perform the rules corresponding to each symbol in the l-system + for (Character ch : system.toCharArray()) + { + double motion = 1; + + // move forward + if (ch == 'F') + { + currentState[1] -= (Math.cos(Math.toRadians(currentState[0])) * motion); + currentState[2] -= (Math.sin(Math.toRadians(currentState[0])) * motion); + output.add(new double[] { currentState[1], currentState[2] }); + + } + // start branch + if (ch == '[') + { + + state.push(currentState.clone()); + } + // turn left + if (ch == '-') + { + currentState = new double[] { (double) ((currentState[0] - angle) % 360), currentState[1], currentState[2] }; + } + // turn right + if (ch == '+') + { + currentState[0] = ((currentState[0] + angle) % 360); + + } + // end branch and return to previous fork + if (ch == ']') + { + currentState = state.pop(); + } + } + return output; + + } + + /** + * grow and l-system string based on the rules provided in the args + * + * @param start + * @param steps + * @param lSystemsRule + * @return + */ + public static String generate(String start, int steps, HashMap lSystemsRule) + { + + while (steps > 0) + { + StringBuilder output = new StringBuilder(); + + for (Character ch : start.toCharArray()) + { + // get the rule applicable for the variable + String data = lSystemsRule.get(ch.toString()); + + // handle constants for rule-less symbols + if (data == null) + { + data = ch.toString(); + } + output.append(data); + } + steps--; + start = output.toString(); + } + return start; + } + + // a data container class to transmit the important information about the polygon + public static class PolygonStorage + { + public PolygonStorage(ArrayList points, int maxX, int maxY, int minX, int minY) + { + this.points = points; + this.maxX = maxX; + this.maxY = maxY; + this.minX = minX; + this.minY = minY; + } + public ArrayList points; + + public int maxX; + public int maxY; + public int minX; + public int minY; + } + + + public static ArrayList tesselate(PolygonStorage polygon) + { + ArrayList points = new ArrayList(); + + ArrayList polyPoints = new ArrayList(); + + for(int i = 0; i tris =(ArrayList) poly.getTriangles(); + + for(DelaunayTriangle tri : tris) + { + for(TriangulationPoint tpoint : tri.points) + { + points.add(new Point((int)tpoint.getX(),(int) tpoint.getY())); + } + } + return points; + + } + + /** + public static ArrayList tesselate(Polygon polygon) + { + ArrayList points = new ArrayList(); + + Tessellator tess = new Tessellator(); + double[] verticesC1 = new double[polygon.points.size()*3]; + for(int i = 0; i< verticesC1.length; i+=3) + { + Point point = polygon.points.get(i/3); + verticesC1[i]= point.x; + verticesC1[i+1]= point.y; + verticesC1[i+2]= 0; + + } + + tess.gluBeginPolygon(); + + for(int i = 0; i vIndex = prim.vertices; + + if(prim.type==GL11.GL_TRIANGLE_STRIP) + { + for(Integer ii = 0; ii < vIndex.size()-1;ii++) + { + points.add(new Point((int)verticesC1[vIndex.get(ii)*3],(int) verticesC1[vIndex.get(ii)*3+1])); + points.add(new Point((int)verticesC1[vIndex.get(ii+1)*3],(int) verticesC1[vIndex.get(ii+1)*3+1])); + + + } + } + + if(prim.type==GL11.GL_TRIANGLES) + { + for(Integer ii = 0; ii < vIndex.size();ii++) + { + points.add(new Point((int)verticesC1[vIndex.get(ii)*3],(int) verticesC1[vIndex.get(ii)*3+1])); + } + } + + + + + + { + if(prim.type==GL11.GL_TRIANGLE_FAN) + { + Integer firstIndex = vIndex.get(0); + // points.add(new Point((int)verticesC1[vIndex.get(firstIndex)],(int) verticesC1[vIndex.get(firstIndex)+1])); + + Integer[] vertexList = new Integer[vIndex.size()*3]; + for(Integer ii = 0; ii < vIndex.size()-2;ii++) + { + vertexList[ii*3] = vIndex.get(0); + vertexList[ii*3+1] = vIndex.get(ii+1); + vertexList[ii*3+2] = vIndex.get(ii+2); + + + + + } + + for(Integer vertex : vertexList) + { + if(vertex!=null) + { + points.add(new Point((int)(verticesC1[vertex*3]),(int)(verticesC1[vertex*3+1]))); + + } + else + { + break; + } + } + System.out.println(vertexList); + + + } + + //points.add(new Point((int)verticesC1[vIndex.get(firstIndex)],(int) verticesC1[vIndex.get(firstIndex)+1])); + // points.add(new Point((int)verticesC1[vIndex.get(ii)*3],(int) verticesC1[vIndex.get(ii)+1])); + // points.add(new Point((int)verticesC1[vIndex.get(ii+1)*3],(int) verticesC1[vIndex.get(ii+1)*3+1])); + + // points.add(new Point((int)verticesC1[index],(int)verticesC1[index+1])); + // System.out.println(verticesC1[index]+","+verticesC1[index+1]+","+verticesC1[index+2]); + + + + } + //System.out.println(tess.primitives.get(i).toString()); + } + return points; + + } + **/ +} diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/watcher/ClientDimData.java b/src/main/java/StevenDimDoors/mod_pocketDim/watcher/ClientDimData.java index c0df886..aaf6aef 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/watcher/ClientDimData.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/watcher/ClientDimData.java @@ -3,37 +3,42 @@ package StevenDimDoors.mod_pocketDim.watcher; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; - +import StevenDimDoors.mod_pocketDim.core.DimensionType; import StevenDimDoors.mod_pocketDim.core.NewDimData; public class ClientDimData { //We'll use public fields since this is just a data container and it's immutable public final int ID; - public final int RootID; + public final int rootID; + public final DimensionType type; - public ClientDimData(int id, int rootID) + public ClientDimData(int id, int rootID, DimensionType type) { ID = id; - RootID = rootID; + this.rootID = rootID; + this.type = type; } public ClientDimData(NewDimData dimension) { ID = dimension.id(); - RootID = dimension.root().id(); + this.rootID = dimension.root().id(); + this.type = dimension.type(); } public void write(DataOutputStream output) throws IOException { output.writeInt(ID); - output.writeInt(RootID); + output.writeInt(rootID); + output.writeInt(type.index); } public static ClientDimData read(DataInputStream input) throws IOException { int id = input.readInt(); - int rootId = input.readInt(); - return new ClientDimData(id, rootId); + int rootID = input.readInt(); + int index = input.readInt(); + return new ClientDimData(id, rootID, DimensionType.getTypeFromIndex(index)); } } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/watcher/ClientLinkData.java b/src/main/java/StevenDimDoors/mod_pocketDim/watcher/ClientLinkData.java index 5670542..c23c137 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/watcher/ClientLinkData.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/watcher/ClientLinkData.java @@ -3,38 +3,62 @@ package StevenDimDoors.mod_pocketDim.watcher; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; - +import StevenDimDoors.mod_pocketDim.core.DDLock; import StevenDimDoors.mod_pocketDim.core.DimLink; +import StevenDimDoors.mod_pocketDim.core.LinkType; import StevenDimDoors.mod_pocketDim.util.Point4D; public class ClientLinkData { - public Point4D point; - public int orientation; - - public ClientLinkData(DimLink link) - { - this.point= link.source(); - this.orientation=link.orientation(); - } - - public ClientLinkData(Point4D point, int orientation) - { - this.point = point; - this.orientation=orientation; - } - - public void write(DataOutputStream output) throws IOException - { - Point4D.write(point, output); - output.writeInt(orientation); - } - - public static ClientLinkData read(DataInputStream input) throws IOException - { - Point4D point = Point4D.read(input); - int orientation = input.readInt(); - return new ClientLinkData(point, orientation); - } - + public final Point4D point; + public final DDLock lock; + public final LinkType type; + + public ClientLinkData(DimLink link) + { + this.point = link.source(); + this.type = link.linkType(); + if (link.hasLock()) + { + lock = link.getLock(); + } + else + { + lock = null; + } + } + + public ClientLinkData(Point4D point, LinkType type, DDLock lock) + { + this.point = point; + this.lock = lock; + this.type = type; + + } + + public void write(DataOutputStream output) throws IOException + { + Point4D.write(point, output); + output.writeInt(this.type.index); + boolean hasLock = this.lock != null; + output.writeBoolean(hasLock); + + if (hasLock) + { + output.writeBoolean(lock.getLockState()); + output.writeInt(lock.getLockKey()); + } + } + + public static ClientLinkData read(DataInputStream input) throws IOException + { + Point4D point = Point4D.read(input); + LinkType type = LinkType.getLinkTypeFromIndex(input.readInt()); + DDLock lock = null; + if (input.readBoolean()) + { + lock = new DDLock(input.readBoolean(), input.readInt()); + } + return new ClientLinkData(point, type, lock); + } } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/watcher/IUpdateWatcher.java b/src/main/java/StevenDimDoors/mod_pocketDim/watcher/IUpdateWatcher.java index eb8f920..5e3cd04 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/watcher/IUpdateWatcher.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/watcher/IUpdateWatcher.java @@ -3,5 +3,6 @@ package StevenDimDoors.mod_pocketDim.watcher; public interface IUpdateWatcher { public void onCreated(T message); + public void update(T message); public void onDeleted(T message); } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/watcher/UpdateWatcherProxy.java b/src/main/java/StevenDimDoors/mod_pocketDim/watcher/UpdateWatcherProxy.java index e105476..9981169 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/watcher/UpdateWatcherProxy.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/watcher/UpdateWatcherProxy.java @@ -39,4 +39,13 @@ public class UpdateWatcherProxy implements IUpdateWatcher { return watchers.remove(receiver); } + + @Override + public void update(T message) + { + for (IUpdateWatcher receiver : watchers) + { + receiver.update(message); + } + } } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/world/BiomeGenLimbo.java b/src/main/java/StevenDimDoors/mod_pocketDim/world/BiomeGenLimbo.java index 243baf1..77eef46 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/world/BiomeGenLimbo.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/world/BiomeGenLimbo.java @@ -2,38 +2,10 @@ package StevenDimDoors.mod_pocketDim.world; import net.minecraft.world.biome.BiomeGenBase; -public class BiomeGenLimbo extends BiomeGenBase +public class BiomeGenLimbo extends DDBiomeGenBase { - public BiomeGenLimbo(int par1) + public BiomeGenLimbo(int biomeID) { - super(par1); - this.theBiomeDecorator.treesPerChunk = 0; - this.theBiomeDecorator.flowersPerChunk = 0; - this.theBiomeDecorator.grassPerChunk = 0; - this.setBiomeName("Limbo"); - this.setDisableRain(); - - this.spawnableMonsterList.clear(); - this.spawnableCreatureList.clear(); - this.spawnableWaterCreatureList.clear(); - this.spawnableCaveCreatureList.clear(); - // this.spawnableMonsterList.add(new SpawnListEntry(MobObelisk.class, 1, 1, 1)); - // this.spawnableMonsterList.add(new SpawnListEntry(MobObelisk.class, 300, 0, 0)); - - // this.spawnableCreatureList.add(new SpawnListEntry(MobObelisk.class, 1, 1, 1)); - // this.spawnableCreatureList.add(new SpawnListEntry(MobObelisk.class, 300, 0, 0)); - - // this.spawnableCaveCreatureList.add(new SpawnListEntry(MobObelisk.class, 1, 1, 1)); - // this.spawnableCaveCreatureList.add(new SpawnListEntry(MobObelisk.class, 300, 0, 0)); - - - - - } - - @Override - public float getSpawningChance() - { - return 0.00001F; + super(biomeID, "Limbo"); } } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/world/BiomeGenPocket.java b/src/main/java/StevenDimDoors/mod_pocketDim/world/BiomeGenPocket.java index e9dbdb7..8d09b7b 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/world/BiomeGenPocket.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/world/BiomeGenPocket.java @@ -2,26 +2,10 @@ package StevenDimDoors.mod_pocketDim.world; import net.minecraft.world.biome.BiomeGenBase; -public class BiomeGenPocket extends BiomeGenBase +public class BiomeGenPocket extends DDBiomeGenBase { - public BiomeGenPocket(int par1) + public BiomeGenPocket(int biomeID) { - super(par1); - this.theBiomeDecorator.treesPerChunk = 0; - this.theBiomeDecorator.flowersPerChunk = 0; - this.theBiomeDecorator.grassPerChunk = 0; - this.setBiomeName("Pocket Dimension"); - this.setDisableRain(); - - this.spawnableMonsterList.clear(); - this.spawnableCreatureList.clear(); - this.spawnableWaterCreatureList.clear(); - this.spawnableCaveCreatureList.clear(); - // this.spawnableMonsterList.add(new SpawnListEntry(MobObelisk.class, 1, 1, 1)); - // this.spawnableCreatureList.add(new SpawnListEntry(MobObelisk.class, 1, 1, 1)); -// - // this.spawnableCaveCreatureList.add(new SpawnListEntry(MobObelisk.class, 1, 1, 1)); - - + super(biomeID, "Pocket Dimension"); } } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/world/CustomCaveGen.java b/src/main/java/StevenDimDoors/mod_pocketDim/world/CustomCaveGen.java index 3e892be..1f9b680 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/world/CustomCaveGen.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/world/CustomCaveGen.java @@ -6,7 +6,7 @@ import net.minecraft.block.Block; import net.minecraft.util.MathHelper; import net.minecraft.world.World; import net.minecraft.world.gen.MapGenBase; -import StevenDimDoors.mod_pocketDim.DDProperties; +import StevenDimDoors.mod_pocketDim.config.DDProperties; public class CustomCaveGen extends MapGenBase { diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/world/DDBiomeGenBase.java b/src/main/java/StevenDimDoors/mod_pocketDim/world/DDBiomeGenBase.java new file mode 100644 index 0000000..f6e3428 --- /dev/null +++ b/src/main/java/StevenDimDoors/mod_pocketDim/world/DDBiomeGenBase.java @@ -0,0 +1,34 @@ +package StevenDimDoors.mod_pocketDim.world; + +import net.minecraft.world.biome.BiomeGenBase; + +public class DDBiomeGenBase extends BiomeGenBase +{ + public DDBiomeGenBase(int biomeID, String name) + { + super(biomeID); + this.setBiomeName(name); + this.theBiomeDecorator.treesPerChunk = 0; + this.theBiomeDecorator.flowersPerChunk = 0; + this.theBiomeDecorator.grassPerChunk = 0; + this.setDisableRain(); + + this.spawnableMonsterList.clear(); + this.spawnableCreatureList.clear(); + this.spawnableWaterCreatureList.clear(); + this.spawnableCaveCreatureList.clear(); + } + + public static void checkBiomes(int[] biomes) + { + for (int k = 0; k < biomes.length; k++) + { + if (biomeList[biomes[k]] != null && !(biomeList[biomes[k]] instanceof DDBiomeGenBase)) + { + // Crash Minecraft to avoid having people complain to us about strange things + // that are really the result of silent biome ID conflicts. + throw new IllegalStateException("There is a biome ID conflict between a biome from Dimensional Doors and another biome type. Fix your configuration!"); + } + } + } +} diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/ticking/LimboDecay.java b/src/main/java/StevenDimDoors/mod_pocketDim/world/LimboDecay.java similarity index 90% rename from src/main/java/StevenDimDoors/mod_pocketDim/ticking/LimboDecay.java rename to src/main/java/StevenDimDoors/mod_pocketDim/world/LimboDecay.java index c325109..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; @@ -7,19 +7,18 @@ import net.minecraft.block.BlockContainer; import net.minecraft.world.ChunkCoordIntPair; import net.minecraft.world.World; import net.minecraftforge.common.DimensionManager; -import StevenDimDoors.mod_pocketDim.DDProperties; +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_pocketDim/world/LimboGenerator.java b/src/main/java/StevenDimDoors/mod_pocketDim/world/LimboGenerator.java index a53faaf..dd3185f 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/world/LimboGenerator.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/world/LimboGenerator.java @@ -17,7 +17,7 @@ import net.minecraft.world.gen.feature.MapGenScatteredFeature; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.event.Event.Result; import net.minecraftforge.event.terraingen.ChunkProviderEvent; -import StevenDimDoors.mod_pocketDim.DDProperties; +import StevenDimDoors.mod_pocketDim.config.DDProperties; import StevenDimDoors.mod_pocketDim.ticking.CustomLimboPopulator; public class LimboGenerator extends ChunkProviderGenerate diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/world/LimboProvider.java b/src/main/java/StevenDimDoors/mod_pocketDim/world/LimboProvider.java index 71e587d..9e22053 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/world/LimboProvider.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/world/LimboProvider.java @@ -3,8 +3,10 @@ package StevenDimDoors.mod_pocketDim.world; import java.util.Random; import net.minecraft.entity.Entity; +import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.util.ChunkCoordinates; +import net.minecraft.util.MathHelper; import net.minecraft.util.Vec3; import net.minecraft.world.WorldProvider; import net.minecraft.world.biome.BiomeGenBase; @@ -12,9 +14,10 @@ import net.minecraft.world.biome.WorldChunkManagerHell; import net.minecraft.world.chunk.IChunkProvider; import net.minecraftforge.client.IRenderHandler; import StevenDimDoors.mod_pocketDim.CloudRenderBlank; -import StevenDimDoors.mod_pocketDim.DDProperties; import StevenDimDoors.mod_pocketDim.mod_pocketDim; +import StevenDimDoors.mod_pocketDim.config.DDProperties; import StevenDimDoors.mod_pocketDim.ticking.CustomLimboPopulator; +import StevenDimDoors.mod_pocketDim.util.Point4D; import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; @@ -59,7 +62,7 @@ public class LimboProvider extends WorldProvider @Override public boolean canRespawnHere() { - return properties.HardcoreLimboEnabled && properties.LimboEnabled; + return properties.HardcoreLimboEnabled; } @Override @@ -174,26 +177,18 @@ public class LimboProvider extends WorldProvider return false; } - public static ChunkCoordinates getLimboSkySpawn(Random rand) + public static Point4D getLimboSkySpawn(EntityPlayer player, DDProperties properties) { - ChunkCoordinates var5 = new ChunkCoordinates(0,0,0); - - - int spawnFuzz = 1000; - int spawnFuzzHalf = spawnFuzz / 2; - - { - var5.posX += rand.nextInt(spawnFuzz) - spawnFuzzHalf; - var5.posZ += rand.nextInt(spawnFuzz) - spawnFuzzHalf; - var5.posY = 700; - } - - return var5; + int x = (int) (player.posX) + MathHelper.getRandomIntegerInRange(player.worldObj.rand, -properties.LimboEntryRange, properties.LimboEntryRange); + int z = (int) (player.posZ) + MathHelper.getRandomIntegerInRange(player.worldObj.rand, -properties.LimboEntryRange, properties.LimboEntryRange); + return new Point4D(x, 700, z, properties.LimboDimensionID); } @Override public ChunkCoordinates getRandomizedSpawnPoint() { - return getLimboSkySpawn(this.worldObj.rand); + int x = MathHelper.getRandomIntegerInRange(this.worldObj.rand, -500, 500); + int z = MathHelper.getRandomIntegerInRange(this.worldObj.rand, -500, 500); + return new ChunkCoordinates(x, 700, z); } } \ No newline at end of file diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/world/PersonalPocketProvider.java b/src/main/java/StevenDimDoors/mod_pocketDim/world/PersonalPocketProvider.java new file mode 100644 index 0000000..8f1b824 --- /dev/null +++ b/src/main/java/StevenDimDoors/mod_pocketDim/world/PersonalPocketProvider.java @@ -0,0 +1,72 @@ +package StevenDimDoors.mod_pocketDim.world; + +import net.minecraft.entity.Entity; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.util.Vec3; +import net.minecraft.world.WorldProvider; +import net.minecraft.world.biome.WorldChunkManagerHell; +import net.minecraft.world.chunk.IChunkProvider; +import net.minecraftforge.client.IRenderHandler; +import net.minecraftforge.common.DimensionManager; +import StevenDimDoors.mod_pocketDim.CloudRenderBlank; +import StevenDimDoors.mod_pocketDim.mod_pocketDim; +import StevenDimDoors.mod_pocketDim.config.DDProperties; +import StevenDimDoors.mod_pocketDim.core.PocketManager; +import StevenDimDoors.mod_pocketDim.ticking.CustomLimboPopulator; +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +public class PersonalPocketProvider extends PocketProvider +{ + private DDProperties properties; + private CustomLimboPopulator spawner; + private IRenderHandler skyRenderer; + + public PersonalPocketProvider() + { + super(); + } + + @Override + public Vec3 getSkyColor(Entity cameraEntity, float partialTicks) + { + setCloudRenderer( new CloudRenderBlank()); + return this.worldObj.getWorldVec3Pool().getVecFromPool(1,1,1); + } + + public boolean isSurfaceWorld() + { + return false; + } + + @Override + protected void generateLightBrightnessTable() + { + float f = 0.0F; + + for (int i = 0; i <= 15; ++i) + { + float f1 = 1.0F - (float)i / 15.0F; + this.lightBrightnessTable[i] = (15); + } + } + + @Override + public double getHorizon() + { + return worldObj.getHeight()-256; + } + + @SideOnly(Side.CLIENT) + @Override + public Vec3 getFogColor(float par1, float par2) + { + return this.worldObj.getWorldVec3Pool().getVecFromPool(1,1,1); + } + + @Override + public int getActualHeight() + { + return -256; + } +} diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/world/PocketBuilder.java b/src/main/java/StevenDimDoors/mod_pocketDim/world/PocketBuilder.java index 8a30d34..6f9b946 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/world/PocketBuilder.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/world/PocketBuilder.java @@ -1,19 +1,22 @@ package StevenDimDoors.mod_pocketDim.world; import java.util.Random; - import net.minecraft.block.Block; +import net.minecraft.entity.Entity; +import net.minecraft.entity.player.EntityPlayer; import net.minecraft.util.MathHelper; import net.minecraft.world.World; import net.minecraft.world.chunk.Chunk; import net.minecraft.world.chunk.storage.ExtendedBlockStorage; import net.minecraftforge.common.DimensionManager; -import StevenDimDoors.experimental.MazeBuilder; -import StevenDimDoors.mod_pocketDim.DDProperties; +import StevenDimDoors.experimental.BoundingBox; import StevenDimDoors.mod_pocketDim.Point3D; +import StevenDimDoors.mod_pocketDim.mod_pocketDim; import StevenDimDoors.mod_pocketDim.blocks.IDimDoor; +import StevenDimDoors.mod_pocketDim.config.DDProperties; import StevenDimDoors.mod_pocketDim.core.DimLink; -import StevenDimDoors.mod_pocketDim.core.LinkTypes; +import StevenDimDoors.mod_pocketDim.core.DimensionType; +import StevenDimDoors.mod_pocketDim.core.LinkType; import StevenDimDoors.mod_pocketDim.core.NewDimData; import StevenDimDoors.mod_pocketDim.core.PocketManager; import StevenDimDoors.mod_pocketDim.dungeon.DungeonData; @@ -21,13 +24,13 @@ import StevenDimDoors.mod_pocketDim.dungeon.DungeonSchematic; import StevenDimDoors.mod_pocketDim.dungeon.pack.DungeonPackConfig; import StevenDimDoors.mod_pocketDim.helpers.DungeonHelper; import StevenDimDoors.mod_pocketDim.helpers.yCoordHelper; +import StevenDimDoors.mod_pocketDim.items.ItemDimensionalDoor; import StevenDimDoors.mod_pocketDim.schematic.BlockRotator; import StevenDimDoors.mod_pocketDim.util.Pair; import StevenDimDoors.mod_pocketDim.util.Point4D; -import StevenDimDoors.mod_pocketDim.items.ItemDimensionalDoor; public class PocketBuilder -{ +{ public static final int MIN_POCKET_SIZE = 5; public static final int MAX_POCKET_SIZE = 51; public static final int DEFAULT_POCKET_SIZE = 39; @@ -40,82 +43,6 @@ public class PocketBuilder private PocketBuilder() { } - /** - * Method that takes an arbitrary link into a dungeon pocket and tries to regenerate it. First uses the origin to find that link, - * then uses that link to find the link that originally created the dungeon. If it cant find any of these, it - * instead makes the link that lead to this point into an exit door style link, sending the player to the overworld. - * @param dimension The dungeon to be regenerated - * @param linkIn The link leading somewhere into the dungeon. - * @param properties - * @return - */ - - public static boolean regenerateDungeonPocket(NewDimData dimension, DimLink linkIn, DDProperties properties) - { - if (linkIn == null) - { - throw new IllegalArgumentException("link cannot be null."); - } - if (properties == null) - { - throw new IllegalArgumentException("properties cannot be null."); - } - //The link that is at the origin of the dungeon - DimLink originLink = dimension.getLink(dimension.origin()); - Point4D oldLinkPos = linkIn.source(); - if(originLink==null) - { - int orientation = linkIn.orientation(); - originLink=dimension.createLink(oldLinkPos, LinkTypes.SAFE_EXIT, (orientation+2)%4); - return false; - } - //The link that originally created the dungeon on the way in - DimLink incomingLink = PocketManager.getLink(originLink.destination()); - if(incomingLink==null||incomingLink.linkType()!=LinkTypes.DUNGEON||!(originLink.linkType()==LinkTypes.REVERSE)) - { - int orientation = linkIn.orientation(); - dimension.deleteLink(originLink); - dimension.createLink(oldLinkPos, LinkTypes.SAFE_EXIT, (orientation+2)%4); - return false; - } - NewDimData parent = PocketManager.getDimensionData(incomingLink.source().getDimension()); - - if (!dimension.isDungeon()) - { - throw new IllegalArgumentException("destination must be dungeon"); - } - if (dimension.isFilled()) - { - throw new IllegalArgumentException("destination must be empty"); - } - if (!dimension.isInitialized()) - { - throw new IllegalArgumentException("destination must already exist"); - } - - try - { - //Load a world - World world = PocketManager.loadDimension(dimension.id()); - - if (world == null || world.provider == null) - { - System.err.println("Could not initialize dimension for a dungeon!"); - return false; - } - - Point3D destination = new Point3D(incomingLink.destination()); - loadAndValidateDungeon(dimension.dungeon(), properties).copyToWorld(world, destination, originLink.orientation(), incomingLink, random, properties, false); - dimension.setFilled(true); - return true; - } - catch (Exception e) - { - e.printStackTrace(); - return false; - } - } - private static boolean buildDungeonPocket(DungeonData dungeon, NewDimData dimension, DimLink link, DungeonSchematic schematic, World world, DDProperties properties) { //Calculate the destination point @@ -145,7 +72,7 @@ public class PocketBuilder return true; } - public static boolean generateSelectedDungeonPocket(DimLink link, DDProperties properties, DungeonData data) + public static boolean generateSelectedDungeonPocket(DimLink link, DDProperties properties, DungeonData dungeon) { if (link == null) { @@ -155,15 +82,26 @@ public class PocketBuilder { throw new IllegalArgumentException("properties cannot be null."); } - if (link.hasDestination()) { throw new IllegalArgumentException("link cannot have a destination assigned already."); } + if (dungeon == null) + { + throw new IllegalArgumentException("dungeon cannot be null."); + } - //Register a new dimension + // Try to load up the schematic + DungeonSchematic schematic = null; + schematic = loadAndValidateDungeon(dungeon, properties); + if (schematic == null) + { + return false; + } + + // Register a new dimension NewDimData parent = PocketManager.getDimensionData(link.source().getDimension()); - NewDimData dimension = PocketManager.registerPocket(parent, true); + NewDimData dimension = PocketManager.registerPocket(parent, DimensionType.DUNGEON); //Load a world World world = PocketManager.loadDimension(dimension.id()); @@ -174,19 +112,7 @@ public class PocketBuilder return false; } - DungeonData dungeon = null; - DungeonSchematic schematic = null; - - dungeon = data; - if (data == null) - { - System.err.println("Could not select a dungeon for generation!"); - return false; - } - schematic = loadAndValidateDungeon(dungeon, properties); - return PocketBuilder.buildDungeonPocket(dungeon, dimension, link, schematic, world, properties); - } @@ -206,11 +132,19 @@ public class PocketBuilder throw new IllegalArgumentException("link cannot have a destination assigned already."); } - + //Choose a dungeon to generate + NewDimData parent = PocketManager.getDimensionData(link.source().getDimension()); + Pair pair = selectNextDungeon(parent, random, properties); + if (pair == null) + { + System.err.println("Could not select a dungeon for generation!"); + return false; + } + DungeonData dungeon = pair.getFirst(); + DungeonSchematic schematic = pair.getSecond(); //Register a new dimension - NewDimData parent = PocketManager.getDimensionData(link.source().getDimension()); - NewDimData dimension = PocketManager.registerPocket(parent, true); + NewDimData dimension = PocketManager.registerPocket(parent, DimensionType.DUNGEON); //Load a world World world = PocketManager.loadDimension(dimension.id()); @@ -220,17 +154,7 @@ public class PocketBuilder System.err.println("Could not initialize dimension for a dungeon!"); return false; } - - //Choose a dungeon to generate - Pair pair = selectDungeon(dimension, random, properties); - if (pair == null) - { - System.err.println("Could not select a dungeon for generation!"); - return false; - } - DungeonData dungeon = pair.getFirst(); - DungeonSchematic schematic = pair.getSecond(); - + return buildDungeonPocket(dungeon, dimension, link, schematic, world, properties); } @@ -251,18 +175,12 @@ public class PocketBuilder return linkDestination; } - private static Pair selectDungeon(NewDimData dimension, Random random, DDProperties properties) + private static Pair selectNextDungeon(NewDimData parent, Random random, DDProperties properties) { - //We assume the dimension doesn't have a dungeon assigned - if (dimension.dungeon() != null) - { - throw new IllegalArgumentException("dimension cannot have a dungeon assigned already."); - } - DungeonData dungeon = null; DungeonSchematic schematic = null; - dungeon = DungeonHelper.instance().selectDungeon(dimension, random); + dungeon = DungeonHelper.instance().selectNextDungeon(parent, random); if (dungeon != null) { @@ -332,9 +250,9 @@ public class PocketBuilder schematic.getLength() <= DungeonHelper.MAX_DUNGEON_LENGTH); } - public static boolean generateNewPocket(DimLink link, DDProperties properties, Block door) + public static boolean generateNewPocket(DimLink link, DDProperties properties, Block door, DimensionType type) { - return generateNewPocket(link, DEFAULT_POCKET_SIZE, DEFAULT_POCKET_WALL_THICKNESS, properties, door); + return generateNewPocket(link, DEFAULT_POCKET_SIZE, DEFAULT_POCKET_WALL_THICKNESS, properties, door, type); } private static int getDoorOrientation(Point4D source, DDProperties properties) @@ -346,10 +264,8 @@ public class PocketBuilder } //Check if the block below that point is actually a door - int blockID = world.getBlockId(source.getX(), source.getY() - 1, source.getZ()); - if (blockID != properties.DimensionalDoorID && blockID != properties.WarpDoorID && - blockID != properties.TransientDoorID && - blockID != properties.GoldenDimensionalDoorID) + Block block = Block.blocksList[world.getBlockId(source.getX(), source.getY() - 1, source.getZ())]; + if (block==null || !(block instanceof IDimDoor)) { throw new IllegalStateException("The link's source is not a door block. It should be impossible to traverse a rift without a door!"); } @@ -358,8 +274,8 @@ public class PocketBuilder int orientation = world.getBlockMetadata(source.getX(), source.getY() - 1, source.getZ()) & 3; return orientation; } - - public static boolean generateNewPocket(DimLink link, int size, int wallThickness, DDProperties properties, Block door) + + public static void validatePocketSetup(DimLink link, int size, int wallThickness, DDProperties properties, Block door) { if (link == null) { @@ -396,12 +312,79 @@ public class PocketBuilder { throw new IllegalArgumentException("size must be large enough to fit the specified wall thickness and some air space."); } - + } + + /**I know this is almost a copy of generateNewPocket, but we might want to change other things. + * + * @param link + * @param properties + * @param player + * @param door + * @return + */ + public static boolean generateNewPersonalPocket(DimLink link, DDProperties properties,Entity player, Block door) + { + //incase a chicken walks in or something + if(!(player instanceof EntityPlayer)) + { + return false; + } + int wallThickness = DEFAULT_POCKET_WALL_THICKNESS; + int size = DEFAULT_POCKET_SIZE; + + validatePocketSetup(link, size, wallThickness, properties, door); + try { //Register a new dimension NewDimData parent = PocketManager.getDimensionData(link.source().getDimension()); - NewDimData dimension = PocketManager.registerPocket(parent, false); + NewDimData dimension = PocketManager.registerPocket(parent, DimensionType.PERSONAL, player.getEntityName()); + + + //Load a world + World world = PocketManager.loadDimension(dimension.id()); + + if (world == null || world.provider == null) + { + System.err.println("Could not initialize dimension for a pocket!"); + return false; + } + + //Calculate the destination point + Point4D source = link.source(); + int destinationY = yCoordHelper.adjustDestinationY(link.source().getY(), world.getHeight(), wallThickness + 1, size); + int orientation = getDoorOrientation(source, properties); + + //Place a link leading back out of the pocket + DimLink reverseLink = dimension.createLink(source.getX(), destinationY, source.getZ(), LinkType.REVERSE,(link.orientation()+2)%4); + parent.setLinkDestination(reverseLink, source.getX(), source.getY(), source.getZ()); + + //Build the actual pocket area + buildPocket(world, source.getX(), destinationY, source.getZ(), orientation, size, wallThickness, properties, door); + + //Finish up destination initialization + dimension.initializePocket(source.getX(), destinationY, source.getZ(), orientation, link); + dimension.setFilled(true); + + return true; + } + catch (Exception e) + { + e.printStackTrace(); + return false; + } + } + + public static boolean generateNewPocket(DimLink link, int size, int wallThickness, DDProperties properties, Block door, DimensionType type) + { + validatePocketSetup(link, size, wallThickness, properties, door); + + try + { + //Register a new dimension + NewDimData parent = PocketManager.getDimensionData(link.source().getDimension()); + NewDimData dimension = PocketManager.registerPocket(parent, type); + //Load a world World world = PocketManager.loadDimension(dimension.id()); @@ -418,8 +401,9 @@ public class PocketBuilder int orientation = getDoorOrientation(source, properties); //Place a link leading back out of the pocket - DimLink reverseLink = dimension.createLink(source.getX(), destinationY, source.getZ(), LinkTypes.REVERSE,(link.orientation()+2)%4); - parent.setDestination(reverseLink, source.getX(), source.getY(), source.getZ()); + + DimLink reverseLink = dimension.createLink(source.getX(), destinationY, source.getZ(), LinkType.REVERSE,(link.orientation()+2)%4); + parent.setLinkDestination(reverseLink, source.getX(), source.getY(), source.getZ()); //Build the actual pocket area buildPocket(world, source.getX(), destinationY, source.getZ(), orientation, size, wallThickness, properties, door); @@ -470,23 +454,31 @@ public class PocketBuilder BlockRotator.transformPoint(center, door, orientation - BlockRotator.EAST_DOOR_METADATA, door); //Build the outer layer of Eternal Fabric - buildBox(world, center.getX(), center.getY(), center.getZ(), (size / 2), properties.PermaFabricBlockID, false, 0); + buildBox(world, center.getX(), center.getY(), center.getZ(), (size / 2), properties.PermaFabricBlockID, 0, false, 0); + //check if we are building a personal pocket + int metadata = 0; + if(world.provider instanceof PersonalPocketProvider) + { + metadata = 2; + } + //Build the (wallThickness - 1) layers of Fabric of Reality for (int layer = 1; layer < wallThickness; layer++) { - buildBox(world, center.getX(), center.getY(), center.getZ(), (size / 2) - layer, properties.FabricBlockID, + buildBox(world, center.getX(), center.getY(), center.getZ(), (size / 2) - layer, mod_pocketDim.blockDimWall.blockID, metadata, layer < (wallThickness - 1) && properties.TNFREAKINGT_Enabled, properties.NonTntWeight); } //MazeBuilder.generate(world, x, y, z, random); //Build the door - int doorOrientation = BlockRotator.transformMetadata(BlockRotator.EAST_DOOR_METADATA, orientation - BlockRotator.EAST_DOOR_METADATA + 2, properties.DimensionalDoorID); + int doorOrientation = BlockRotator.transformMetadata(BlockRotator.EAST_DOOR_METADATA, orientation - BlockRotator.EAST_DOOR_METADATA + 2, doorBlock.blockID); ItemDimensionalDoor.placeDoorBlock(world, x, y - 1, z, doorOrientation, doorBlock); + } - private static void buildBox(World world, int centerX, int centerY, int centerZ, int radius, int blockID, boolean placeTnt, int nonTntWeight) + private static void buildBox(World world, int centerX, int centerY, int centerZ, int radius, int blockID, int metadata, boolean placeTnt, int nonTntWeight) { int x, y, z; @@ -503,14 +495,14 @@ public class PocketBuilder { for (z = startZ; z <= endZ; z++) { - setBlockDirectlySpecial(world, x, startY, z, blockID, 0, placeTnt, nonTntWeight); - setBlockDirectlySpecial(world, x, endY, z, blockID, 0, placeTnt, nonTntWeight); + setBlockDirectlySpecial(world, x, startY, z, blockID, metadata, placeTnt, nonTntWeight); + setBlockDirectlySpecial(world, x, endY, z, blockID, metadata, placeTnt, nonTntWeight); } for (y = startY; y <= endY; y++) { - setBlockDirectlySpecial(world, x, y, startZ, blockID, 0, placeTnt, nonTntWeight); - setBlockDirectlySpecial(world, x, y, endZ, blockID, 0, placeTnt, nonTntWeight); + setBlockDirectlySpecial(world, x, y, startZ, blockID, metadata, placeTnt, nonTntWeight); + setBlockDirectlySpecial(world, x, y, endZ, blockID, metadata, placeTnt, nonTntWeight); } } @@ -518,8 +510,8 @@ public class PocketBuilder { for (z = startZ; z <= endZ; z++) { - setBlockDirectlySpecial(world, startX, y, z, blockID, 0, placeTnt, nonTntWeight); - setBlockDirectlySpecial(world, endX, y, z, blockID, 0, placeTnt, nonTntWeight); + setBlockDirectlySpecial(world, startX, y, z, blockID, metadata, placeTnt, nonTntWeight); + setBlockDirectlySpecial(world, endX, y, z, blockID, metadata, placeTnt, nonTntWeight); } } } @@ -563,4 +555,39 @@ public class PocketBuilder extBlockStorage.setExtBlockMetadata(localX, y & 15, localZ, metadata); chunk.setChunkModified(); } + + public static BoundingBox calculateDefaultBounds(NewDimData pocket) + { + // Calculate the XZ bounds of this pocket assuming that it has the default size + // The Y bounds will be set to encompass the height of a chunk. + + int minX = 0; + int minZ = 0; + Point4D origin = pocket.origin(); + int orientation = pocket.orientation(); + if (orientation < 0 || orientation > 3) + { + throw new IllegalArgumentException("pocket has an invalid orientation value."); + } + switch (orientation) + { + case 0: + minX = origin.getX() - DEFAULT_POCKET_WALL_THICKNESS + 1; + minZ = origin.getZ() - DEFAULT_POCKET_SIZE / 2; + break; + case 1: + minX = origin.getX() - DEFAULT_POCKET_SIZE / 2; + minZ = origin.getZ() - DEFAULT_POCKET_WALL_THICKNESS + 1; + break; + case 2: + minX = origin.getX() + DEFAULT_POCKET_WALL_THICKNESS - DEFAULT_POCKET_SIZE; + minZ = origin.getZ() - DEFAULT_POCKET_SIZE / 2; + break; + case 3: + minX = origin.getX() - DEFAULT_POCKET_SIZE / 2; + minZ = origin.getZ() + DEFAULT_POCKET_WALL_THICKNESS - DEFAULT_POCKET_SIZE; + break; + } + return new BoundingBox(minX, 0, minZ, DEFAULT_POCKET_SIZE, 255, DEFAULT_POCKET_SIZE); + } } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/world/PocketGenerator.java b/src/main/java/StevenDimDoors/mod_pocketDim/world/PocketGenerator.java index 2299677..df99d03 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/world/PocketGenerator.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/world/PocketGenerator.java @@ -68,7 +68,7 @@ public class PocketGenerator extends ChunkProviderGenerate @Override public List getPossibleCreatures(EnumCreatureType var1, int var2, int var3, int var4) { - NewDimData dimension = PocketManager.getDimensionData(this.worldObj); + NewDimData dimension = PocketManager.createDimensionData(this.worldObj); if (dimension != null && dimension.dungeon() != null && !dimension.dungeon().isOpen()) { return this.worldObj.getBiomeGenForCoords(var2, var3).getSpawnableList(var1); diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/world/PocketProvider.java b/src/main/java/StevenDimDoors/mod_pocketDim/world/PocketProvider.java index 33f8c70..dd6e787 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/world/PocketProvider.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/world/PocketProvider.java @@ -7,10 +7,10 @@ import net.minecraft.world.WorldProvider; import net.minecraft.world.biome.WorldChunkManagerHell; import net.minecraft.world.chunk.IChunkProvider; import net.minecraftforge.client.IRenderHandler; -import net.minecraftforge.common.DimensionManager; import StevenDimDoors.mod_pocketDim.CloudRenderBlank; -import StevenDimDoors.mod_pocketDim.DDProperties; import StevenDimDoors.mod_pocketDim.mod_pocketDim; +import StevenDimDoors.mod_pocketDim.config.DDProperties; +import StevenDimDoors.mod_pocketDim.core.DimensionType; import StevenDimDoors.mod_pocketDim.core.PocketManager; import StevenDimDoors.mod_pocketDim.ticking.CustomLimboPopulator; import cpw.mods.fml.relauncher.Side; @@ -19,8 +19,8 @@ import cpw.mods.fml.relauncher.SideOnly; public class PocketProvider extends WorldProvider { private DDProperties properties; - private CustomLimboPopulator spawner; - private IRenderHandler skyRenderer; + protected CustomLimboPopulator spawner; + protected IRenderHandler skyRenderer; public PocketProvider() { @@ -81,6 +81,28 @@ public class PocketProvider extends WorldProvider return false; } + public float calculateCelestialAngle(long par1, float par3) + { + return .5F; + } + + @Override + protected void generateLightBrightnessTable() + { + if(PocketManager.getDimensionData(this.dimensionId).type() == DimensionType.POCKET) + { + super.generateLightBrightnessTable(); + return; + } + float modifier = 0.0F; + + for (int steps = 0; steps <= 15; ++steps) + { + float var3 = (float) (Math.pow(steps,1.5) / Math.pow(15.0F,1.5)); + this.lightBrightnessTable[15-steps] = var3; + System.out.println( this.lightBrightnessTable[steps]+"light"); + } + } @Override public String getDimensionName() { @@ -103,11 +125,8 @@ public class PocketProvider extends WorldProvider { respawnDim = PocketManager.getDimensionData(this.dimensionId).root().id(); } - - if (DimensionManager.getWorld(respawnDim) == null) - { - DimensionManager.initDimension(respawnDim); - } + // TODO: Are we sure we need to load the dimension as well? Why can't the game handle that? + PocketManager.loadDimension(respawnDim); return respawnDim; } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/world/fortresses/ComponentNetherGateway.java b/src/main/java/StevenDimDoors/mod_pocketDim/world/fortresses/ComponentNetherGateway.java index d8c149e..245071e 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/world/fortresses/ComponentNetherGateway.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/world/fortresses/ComponentNetherGateway.java @@ -2,18 +2,17 @@ package StevenDimDoors.mod_pocketDim.world.fortresses; import java.util.List; import java.util.Random; - import net.minecraft.block.Block; +import net.minecraft.item.ItemDoor; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.world.World; import net.minecraft.world.gen.structure.StructureBoundingBox; import net.minecraft.world.gen.structure.StructureComponent; import StevenDimDoors.mod_pocketDim.mod_pocketDim; import StevenDimDoors.mod_pocketDim.core.DimLink; -import StevenDimDoors.mod_pocketDim.core.LinkTypes; +import StevenDimDoors.mod_pocketDim.core.LinkType; import StevenDimDoors.mod_pocketDim.core.NewDimData; import StevenDimDoors.mod_pocketDim.core.PocketManager; -import StevenDimDoors.mod_pocketDim.items.BaseItemDoor; public class ComponentNetherGateway extends StructureComponent { @@ -66,7 +65,8 @@ public class ComponentNetherGateway extends StructureComponent * second Part of Structure generating, this for example places Spiderwebs, Mob Spawners, it closes Mineshafts at * the end, it adds Fences... */ - public boolean addComponentParts(World world, Random random, StructureBoundingBox bounds) + @Override + public boolean addComponentParts(World world, Random random, StructureBoundingBox bounds) { int NETHER_SLAB_METADATA = 6; @@ -153,13 +153,13 @@ public class ComponentNetherGateway extends StructureComponent if (bounds.isVecInside(x, y, z) && bounds.isVecInside(x, y + 1, z)) { orientation = this.getMetadataWithOffset(Block.doorWood.blockID, 1); - dimension = PocketManager.getDimensionData(world); + dimension = PocketManager.createDimensionData(world); link = dimension.getLink(x, y + 1, z); if (link == null) { - link = dimension.createLink(x, y + 1, z, LinkTypes.DUNGEON, orientation); + link = dimension.createLink(x, y + 1, z, LinkType.DUNGEON, orientation); } - BaseItemDoor.placeDoorBlock(world, x, y, z, orientation, mod_pocketDim.transientDoor); + ItemDoor.placeDoorBlock(world, x, y, z, orientation, mod_pocketDim.transientDoor); } for (x = 0; x <= 6; ++x) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/world/fortresses/DDNetherFortressGenerator.java b/src/main/java/StevenDimDoors/mod_pocketDim/world/fortresses/DDNetherFortressGenerator.java index c34c5fe..9531939 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/world/fortresses/DDNetherFortressGenerator.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/world/fortresses/DDNetherFortressGenerator.java @@ -1,6 +1,6 @@ package StevenDimDoors.mod_pocketDim.world.fortresses; -import StevenDimDoors.mod_pocketDim.DDProperties; +import StevenDimDoors.mod_pocketDim.config.DDProperties; import net.minecraft.world.gen.structure.MapGenNetherBridge; import net.minecraft.world.gen.structure.MapGenStructureIO; import net.minecraft.world.gen.structure.StructureStart; @@ -18,7 +18,8 @@ public class DDNetherFortressGenerator extends MapGenNetherBridge MapGenStructureIO.func_143034_b(DDStructureNetherBridgeStart.class, "Fortress"); } - protected StructureStart getStructureStart(int chunkX, int chunkZ) + @Override + protected StructureStart getStructureStart(int chunkX, int chunkZ) { return new DDStructureNetherBridgeStart(this.worldObj, this.rand, chunkX, chunkZ, DDProperties.instance()); } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/world/fortresses/DDStructureNetherBridgeStart.java b/src/main/java/StevenDimDoors/mod_pocketDim/world/fortresses/DDStructureNetherBridgeStart.java index 5736e36..2778197 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/world/fortresses/DDStructureNetherBridgeStart.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/world/fortresses/DDStructureNetherBridgeStart.java @@ -10,7 +10,7 @@ import net.minecraft.world.gen.structure.ComponentNetherBridgeThrone; import net.minecraft.world.gen.structure.StructureBoundingBox; import net.minecraft.world.gen.structure.StructureComponent; import net.minecraft.world.gen.structure.StructureNetherBridgeStart; -import StevenDimDoors.mod_pocketDim.DDProperties; +import StevenDimDoors.mod_pocketDim.config.DDProperties; public class DDStructureNetherBridgeStart extends StructureNetherBridgeStart { @@ -105,7 +105,8 @@ public class DDStructureNetherBridgeStart extends StructureNetherBridgeStart /** * Keeps iterating Structure Pieces and spawning them until the checks tell it to stop */ - public void generateStructure(World world, Random random, StructureBoundingBox generationBounds) + @Override + public void generateStructure(World world, Random random, StructureBoundingBox generationBounds) { if (hasGateway) { diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/world/gateways/BaseGateway.java b/src/main/java/StevenDimDoors/mod_pocketDim/world/gateways/BaseGateway.java index 0a2b47d..58567b0 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/world/gateways/BaseGateway.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/world/gateways/BaseGateway.java @@ -1,136 +1,41 @@ package StevenDimDoors.mod_pocketDim.world.gateways; -import java.util.ArrayList; -import java.util.Map; -import java.util.Random; -import java.util.TreeMap; -import java.util.Map.Entry; - -import StevenDimDoors.mod_pocketDim.DDProperties; -import StevenDimDoors.mod_pocketDim.Point3D; -import StevenDimDoors.mod_pocketDim.mod_pocketDim; -import StevenDimDoors.mod_pocketDim.core.DimLink; -import StevenDimDoors.mod_pocketDim.core.LinkTypes; -import StevenDimDoors.mod_pocketDim.core.NewDimData; -import StevenDimDoors.mod_pocketDim.core.PocketManager; -import StevenDimDoors.mod_pocketDim.dungeon.DungeonData; -import StevenDimDoors.mod_pocketDim.dungeon.DungeonSchematic; -import StevenDimDoors.mod_pocketDim.dungeon.ModBlockFilter; -import StevenDimDoors.mod_pocketDim.dungeon.SpecialBlockFinder; -import StevenDimDoors.mod_pocketDim.dungeon.pack.DungeonPack; -import StevenDimDoors.mod_pocketDim.schematic.BlockRotator; -import StevenDimDoors.mod_pocketDim.schematic.CompoundFilter; -import StevenDimDoors.mod_pocketDim.schematic.InvalidSchematicException; -import StevenDimDoors.mod_pocketDim.schematic.ReplacementFilter; -import StevenDimDoors.mod_pocketDim.schematic.Schematic; -import StevenDimDoors.mod_pocketDim.schematic.SchematicFilter; -import StevenDimDoors.mod_pocketDim.world.PocketBuilder; -import net.minecraft.block.Block; import net.minecraft.world.World; import net.minecraft.world.biome.BiomeGenBase; +import StevenDimDoors.mod_pocketDim.config.DDProperties; public abstract class BaseGateway { - DDProperties properties; + protected DDProperties properties; public BaseGateway(DDProperties properties) { - this.properties=properties; + this.properties = properties; } /** - * Generates the gateway centered on the given coords - * @param world - * @param x - * @param y - * @param z + * Generates the gateway centered on the given coordinates + * @param world - the world in which to generate the gateway + * @param x - the x-coordinate at which to center the gateway; usually where the door is placed + * @param y - the y-coordinate of the block on which the gateway may be built + * @param z - the z-coordinate at which to center the gateway; usually where the door is placed */ - public boolean generate(World world, int x, int y, int z) - { - int orientation = 0; - - if (this.getSchematicPath()!=null) - { - //Get the correct filters - GatewayBlockFilter filter = new GatewayBlockFilter(); - DungeonSchematic schematic = this.getSchematicToBuild(world, x, y, z); - - //apply filters - schematic.applyFilter(filter); - schematic.applyImportFilters(properties); - - Point3D doorLocation = filter.getEntranceDoorLocation(); - orientation = filter.getEntranceOrientation(); - - // I suspect that the location used below is wrong. Gateways should be placed vertically based on - // the Y position of the surface where they belong. I'm pretty sure including doorLocation.getY() - // messes up the calculation. ~SenseiKiwi - - //schematic.copyToWorld(world, x - doorLocation.getX(), y, z - doorLocation.getZ()); - schematic.copyToWorld(world, x - doorLocation.getX(), y + 1 - doorLocation.getY(), z - doorLocation.getZ(), true); - } - - this.generateRandomBits(world, x, y, z); - - DimLink link = PocketManager.getDimensionData(world).createLink(x, y + 1, z, LinkTypes.DUNGEON, orientation); - PocketBuilder.generateSelectedDungeonPocket(link, mod_pocketDim.properties, this.getStartingDungeon(PocketManager.getDimensionData(world),world.rand)); - - return true; - } + public abstract boolean generate(World world, int x, int y, int z); /** - * Gets a .schematic to generate for this gateway - * @param world - * @param x - * @param y - * @param z - * @return + * Determines whether the specified biome is a valid biome in which to generate this gateway + * @param biome - the biome to be checked + * @return true true if the specified biome is a valid for generating this gateway, otherwise false */ - public DungeonSchematic getSchematicToBuild(World world, int x, int y, int z) + protected boolean isBiomeValid(BiomeGenBase biome) { - //TODO- refine selection criteria here, this is the default case - try + String biomeName = biome.biomeName.toLowerCase(); + String[] keywords = this.getBiomeKeywords(); + if (keywords != null) { - return DungeonSchematic.readFromResource(this.getSchematicPath()); - } - catch (Exception e) - { - e.printStackTrace(); - System.err.println("Could not load schematic for gateway"); - return null; - } - } - - /** - * returns a dungeon from the assigned pack to start with - * @return - */ - public DungeonData getStartingDungeon(NewDimData dimension, Random random) - { - return getStartingPack().getNextDungeon(dimension,random); - } - - /** - * determines if a given location is valid for the gateway to be generated, based on height, biome, and world. - * @param world - * @param x - * @param y - * @param z - * @param biome - * @return - */ - public boolean isLocationValid(World world, int x, int y, int z, BiomeGenBase biome) - { - return this.isBiomeValid(biome)&&areCoordsValid(world, x, y, z); - } - - public boolean isBiomeValid(BiomeGenBase biome) - { - if(this.getBiomeNames()!=null) - { - for(String biomeName : this.getBiomeNames()) + for (String keyword : keywords) { - if(biome.biomeName.contains(biomeName)) + if (biomeName.contains(keyword)) { return true; } @@ -141,43 +46,33 @@ public abstract class BaseGateway } /** - * Use this function to generate randomized bits of the structure. - * @param world - * @param x - * @param y - * @param z + * Determines whether the specified world and coordinates are a valid location for generating this gateway + * @param world - the world in which to generate the gateway + * @param x - the x-coordinate at which to center the gateway; usually where the door is placed + * @param y - the y-coordinate of the block on which the gateway may be built + * @param z - the z-coordinate at which to center the gateway; usually where the door is placed + * @return true if the location is valid, otherwise false */ - abstract void generateRandomBits(World world, int x, int y, int z); - - /** - * Decides if the given coords/world are valid - * @param world - * @param x - * @param y - * @param z - * @return - */ - public abstract boolean areCoordsValid(World world, int x, int y, int z); + public boolean isLocationValid(World world, int x, int y, int z) + { + return isBiomeValid(world.getBiomeGenForCoords(x, z)); + } /** - * @return the pack the dungeon initially generates into from this gateway. + * Gets the dungeon pack associated with this gateway + * @return the dungeon pack to use for this gateway */ - public abstract DungeonPack getStartingPack(); + /*protected DungeonPack getDungeonPack() + { + return DungeonHelper.instance().getDungeonPack("RUINS"); + }*/ /** - * Is by default a whitelist, but the isBiomeValid method - * can be overriden for specific gateways. For example, any biome containing 'forest' would be valid if we added 'forest', - * even from other mods. - * @return List of biome names that we check against. + * Gets the lowercase keywords to be used in checking whether a given biome is a valid location for this gateway + * @return an array of biome keywords to match against */ - public abstract String[] getBiomeNames(); - - /** - * @return List containing all the .schematics attached to this gateway. Selection is random by default - */ - public abstract String getSchematicPath(); - - //TODO not yet implemented - public abstract boolean isSurfaceGateway(); - + public String[] getBiomeKeywords() + { + return new String[] { "" }; + } } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/world/gateways/BaseSchematicGateway.java b/src/main/java/StevenDimDoors/mod_pocketDim/world/gateways/BaseSchematicGateway.java new file mode 100644 index 0000000..e0d8634 --- /dev/null +++ b/src/main/java/StevenDimDoors/mod_pocketDim/world/gateways/BaseSchematicGateway.java @@ -0,0 +1,66 @@ +package StevenDimDoors.mod_pocketDim.world.gateways; + +import net.minecraft.world.World; +import StevenDimDoors.mod_pocketDim.Point3D; +import StevenDimDoors.mod_pocketDim.config.DDProperties; +import StevenDimDoors.mod_pocketDim.core.LinkType; +import StevenDimDoors.mod_pocketDim.core.PocketManager; +import StevenDimDoors.mod_pocketDim.dungeon.DungeonSchematic; +import StevenDimDoors.mod_pocketDim.schematic.InvalidSchematicException; + +public abstract class BaseSchematicGateway extends BaseGateway +{ + public BaseSchematicGateway(DDProperties properties) + { + super(properties); + } + + @Override + public boolean generate(World world, int x, int y, int z) + { + DungeonSchematic schematic; + + try + { + schematic = DungeonSchematic.readFromResource(this.getSchematicPath()); + } + catch (InvalidSchematicException e) + { + System.err.println("Could not load the schematic for a gateway. The following exception occurred:"); + e.printStackTrace(); + return false; + } + + // Apply filters - the order is important! + GatewayBlockFilter gatewayFilter = new GatewayBlockFilter(); + schematic.applyFilter(gatewayFilter); + schematic.applyImportFilters(properties); + + Point3D doorLocation = gatewayFilter.getEntranceDoorLocation(); + int orientation = gatewayFilter.getEntranceOrientation(); + + // Build the gateway into the world + schematic.copyToWorld(world, x - doorLocation.getX(), y, z - doorLocation.getZ(), true, true); + this.generateRandomBits(world, x, y, z); + + // Generate a dungeon link in the door + PocketManager.getDimensionData(world).createLink(x, y + doorLocation.getY(), z, LinkType.DUNGEON, orientation); + + return true; + } + + /** + * Generates randomized portions of the gateway structure (e.g. rubble, foliage) + * @param world - the world in which to generate the gateway + * @param x - the x-coordinate at which to center the gateway; usually where the door is placed + * @param y - the y-coordinate of the block on which the gateway may be built + * @param z - the z-coordinate at which to center the gateway; usually where the door is placed + */ + protected void generateRandomBits(World world, int x, int y, int z) { } + + /** + * Gets the path for the schematic file to be used for this gateway. Subsequent calls to this method may return other schematic paths. + * @return the path to the schematic file for this gateway + */ + protected abstract String getSchematicPath(); +} diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/world/gateways/GatewayGenerator.java b/src/main/java/StevenDimDoors/mod_pocketDim/world/gateways/GatewayGenerator.java index 0257be3..4e2c756 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/world/gateways/GatewayGenerator.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/world/gateways/GatewayGenerator.java @@ -2,19 +2,17 @@ package StevenDimDoors.mod_pocketDim.world.gateways; import java.util.ArrayList; import java.util.Random; - import net.minecraft.block.Block; import net.minecraft.block.material.Material; import net.minecraft.world.World; import net.minecraft.world.chunk.IChunkProvider; import net.minecraftforge.common.DimensionManager; -import StevenDimDoors.mod_pocketDim.DDProperties; import StevenDimDoors.mod_pocketDim.mod_pocketDim; +import StevenDimDoors.mod_pocketDim.config.DDProperties; import StevenDimDoors.mod_pocketDim.core.DimLink; -import StevenDimDoors.mod_pocketDim.core.LinkTypes; +import StevenDimDoors.mod_pocketDim.core.LinkType; import StevenDimDoors.mod_pocketDim.core.NewDimData; import StevenDimDoors.mod_pocketDim.core.PocketManager; -import StevenDimDoors.mod_pocketDim.items.ItemDimensionalDoor; import StevenDimDoors.mod_pocketDim.world.PocketProvider; import cpw.mods.fml.common.IWorldGenerator; @@ -25,13 +23,14 @@ public class GatewayGenerator implements IWorldGenerator private static final int CLUSTER_GROWTH_CHANCE = 80; private static final int MAX_CLUSTER_GROWTH_CHANCE = 100; private static final int MIN_RIFT_Y = 4; - private static final int MAX_RIFT_Y = 250; + private static final int MAX_RIFT_Y = 240; private static final int CHUNK_LENGTH = 16; private static final int GATEWAY_RADIUS = 4; private static final int MAX_GATEWAY_GENERATION_ATTEMPTS = 10; private static final int OVERWORLD_DIMENSION_ID = 0; private static final int NETHER_DIMENSION_ID = -1; private static final int END_DIMENSION_ID = 1; + private static final String SPIRIT_WORLD_NAME = "Spirit World"; private ArrayList gateways; private BaseGateway defaultGateway; @@ -50,7 +49,6 @@ public class GatewayGenerator implements IWorldGenerator defaultGateway = new GatewayTwoPillars(properties); // Add gateways here - gateways.add(defaultGateway); gateways.add(new GatewaySandstonePillars(properties)); gateways.add(new GatewayLimbo(properties)); } @@ -58,15 +56,19 @@ public class GatewayGenerator implements IWorldGenerator @Override public void generate(Random random, int chunkX, int chunkZ, World world, IChunkProvider chunkGenerator, IChunkProvider chunkProvider) { - //Don't generate rifts or gateways if the rift generation flag is disabled, - //the current world is a pocket dimension, or the world is remote. - //Also don't generate anything in The End. - if (world.isRemote || (!properties.WorldRiftGenerationEnabled) || - (world.provider instanceof PocketProvider) || (world.provider.dimensionId == END_DIMENSION_ID)||(world.provider.dimensionId == NETHER_DIMENSION_ID)) + // Don't generate rifts or gateways if the current world is a pocket dimension or the world is remote. + // Also don't generate anything in the Nether, The End, or in Witchery's Spirit World. + // We only match against Spirit World using hashing to speed up the process a little (hopefully). + int dimensionID = world.provider.dimensionId; + if (world.isRemote + || (world.provider instanceof PocketProvider) + || (dimensionID == END_DIMENSION_ID) + || (dimensionID == NETHER_DIMENSION_ID) + || (world.provider.getDimensionName().hashCode() == SPIRIT_WORLD_NAME.hashCode())) { return; } - //This check prevents a crash related to superflat worlds not loading World 0 + // This check prevents a crash related to superflat worlds not loading World 0 if (DimensionManager.getWorld(OVERWORLD_DIMENSION_ID) == null) { return; @@ -78,8 +80,10 @@ public class GatewayGenerator implements IWorldGenerator DimLink link; NewDimData dimension; - //Randomly decide whether to place a cluster of rifts here - if (random.nextInt(MAX_CLUSTER_GENERATION_CHANCE) < properties.ClusterGenerationChance) + // Check if we're allowed to generate rift clusters in this dimension. + // If so, randomly decide whether to one. + if (mod_pocketDim.worldProperties.RiftClusterDimensions.isAccepted(dimensionID) + && random.nextInt(MAX_CLUSTER_GENERATION_CHANCE) < properties.ClusterGenerationChance) { link = null; dimension = null; @@ -101,7 +105,7 @@ public class GatewayGenerator implements IWorldGenerator if (link == null) { dimension = PocketManager.getDimensionData(world); - link = dimension.createLink(x, y + 1, z, LinkTypes.DUNGEON,0); + link = dimension.createLink(x, y + 1, z, LinkType.DUNGEON,0); } else { @@ -113,10 +117,10 @@ public class GatewayGenerator implements IWorldGenerator while (random.nextInt(MAX_CLUSTER_GROWTH_CHANCE) < CLUSTER_GROWTH_CHANCE); } - //Check if generating structures is enabled and randomly decide whether to place a Rift Gateway here. - //This only happens if a rift cluster was NOT generated. - else if (random.nextInt(MAX_GATEWAY_GENERATION_CHANCE) < properties.GatewayGenerationChance && - isStructureGenerationAllowed()) + // Check if we can place a Rift Gateway in this dimension, then randomly decide whether to place one. + // This only happens if a rift cluster was NOT generated. + else if (mod_pocketDim.worldProperties.RiftGatewayDimensions.isAccepted(dimensionID) && + random.nextInt(MAX_GATEWAY_GENERATION_CHANCE) < properties.GatewayGenerationChance) { valid = false; x = y = z = 0; //Stop the compiler from freaking out @@ -131,26 +135,24 @@ public class GatewayGenerator implements IWorldGenerator valid = checkGatewayLocation(world, x, y, z); } - //Build the gateway if we found a valid location + // Build the gateway if we found a valid location if (valid) { - //TODO I feel like this is slow and should be optimized. We are linear time with total # of generation restrictions - //Create an array and copy valid gateways into it ArrayList validGateways = new ArrayList(); - for(BaseGateway gateway:gateways) + for (BaseGateway gateway : gateways) { - if(gateway.isLocationValid(world, x, y, z, world.getBiomeGenForCoords(x, z))) + if (gateway.isLocationValid(world, x, y, z)) { validGateways.add(gateway); } } - //Add default gateway if we where unable to find a suitable gateway - if(validGateways.isEmpty()) + // Add the default gateway if the rest were rejected + if (validGateways.isEmpty()) { - validGateways.add(this.defaultGateway); + validGateways.add(defaultGateway); } - //randomly select a gateway from the pool of viable gateways - validGateways.get(random.nextInt(validGateways.size())).generate(world, x, y, z); + // Randomly select a gateway from the pool of viable gateways + validGateways.get(random.nextInt(validGateways.size())).generate(world, x, y - 1, z); } } } @@ -177,9 +179,4 @@ public class GatewayGenerator implements IWorldGenerator return (material != Material.leaves && material != Material.wood && material != Material.pumpkin && world.isBlockOpaqueCube(x, y, z) && world.getBlockId(x, y, z) != Block.bedrock.blockID); } - - private static boolean isStructureGenerationAllowed() - { - return DimensionManager.getWorld(OVERWORLD_DIMENSION_ID).getWorldInfo().isMapFeaturesEnabled(); - } } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/world/gateways/GatewayLimbo.java b/src/main/java/StevenDimDoors/mod_pocketDim/world/gateways/GatewayLimbo.java index 8c54e2c..6a3ec04 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/world/gateways/GatewayLimbo.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/world/gateways/GatewayLimbo.java @@ -1,69 +1,43 @@ package StevenDimDoors.mod_pocketDim.world.gateways; +import net.minecraft.item.ItemDoor; import net.minecraft.world.World; -import StevenDimDoors.mod_pocketDim.DDProperties; import StevenDimDoors.mod_pocketDim.mod_pocketDim; -import StevenDimDoors.mod_pocketDim.dungeon.pack.DungeonPack; -import StevenDimDoors.mod_pocketDim.helpers.DungeonHelper; -import StevenDimDoors.mod_pocketDim.items.BaseItemDoor; +import StevenDimDoors.mod_pocketDim.config.DDProperties; +import StevenDimDoors.mod_pocketDim.core.LinkType; +import StevenDimDoors.mod_pocketDim.core.PocketManager; import StevenDimDoors.mod_pocketDim.world.LimboProvider; public class GatewayLimbo extends BaseGateway { - - public GatewayLimbo(DDProperties properties) { + public GatewayLimbo(DDProperties properties) + { super(properties); - // TODO Auto-generated constructor stub } @Override - void generateRandomBits(World world, int x, int y, int z) + public boolean generate(World world, int x, int y, int z) { int blockID = mod_pocketDim.blockLimbo.blockID; - //Build the gateway out of Unraveled Fabric. Since nearly all the blocks in Limbo are of - //that type, there is no point replacing the ground. - world.setBlock(x, y + 2, z + 1, blockID, 0, 3); - world.setBlock(x, y + 2, z - 1, blockID, 0, 3); + // Build the gateway out of Unraveled Fabric. Since nearly all the blocks in Limbo are of + // that type, there is no point replacing the ground. + world.setBlock(x, y + 3, z + 1, blockID, 0, 3); + world.setBlock(x, y + 3, z - 1, blockID, 0, 3); - //Build the columns around the door + // Build the columns around the door + world.setBlock(x, y + 2, z - 1, blockID, 0, 3); + world.setBlock(x, y + 2, z + 1, blockID, 0, 3); world.setBlock(x, y + 1, z - 1, blockID, 0, 3); world.setBlock(x, y + 1, z + 1, blockID, 0, 3); - world.setBlock(x, y, z - 1, blockID, 0, 3); - world.setBlock(x, y, z + 1, blockID, 0, 3); - - BaseItemDoor.placeDoorBlock(world, x, y, z, 0, mod_pocketDim.transientDoor); + PocketManager.getDimensionData(world).createLink(x, y + 2, z, LinkType.DUNGEON, 0); - } - - @Override - public DungeonPack getStartingPack() { - // TODO Auto-generated method stub - return DungeonHelper.instance().getDungeonPack("RUINS"); - } - - @Override - public String[] getBiomeNames() { - // TODO Auto-generated method stub - return null; - } - - @Override - public String getSchematicPath() { - // TODO Auto-generated method stub - return null; - } - - @Override - public boolean isSurfaceGateway() { - // TODO Auto-generated method stub + ItemDoor.placeDoorBlock(world, x, y + 1, z, 0, mod_pocketDim.transientDoor); return true; } @Override - public boolean areCoordsValid(World world, int x, int y, int z) { - // TODO Auto-generated method stub - return world.provider instanceof LimboProvider; + public boolean isLocationValid(World world, int x, int y, int z) { + return (world.provider instanceof LimboProvider); } - } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/world/gateways/GatewaySandstonePillars.java b/src/main/java/StevenDimDoors/mod_pocketDim/world/gateways/GatewaySandstonePillars.java index 32b0bfa..65e53a8 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/world/gateways/GatewaySandstonePillars.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/world/gateways/GatewaySandstonePillars.java @@ -1,61 +1,23 @@ package StevenDimDoors.mod_pocketDim.world.gateways; -import java.util.ArrayList; -import java.util.Random; +import StevenDimDoors.mod_pocketDim.config.DDProperties; -import StevenDimDoors.mod_pocketDim.DDProperties; -import StevenDimDoors.mod_pocketDim.mod_pocketDim; -import StevenDimDoors.mod_pocketDim.dungeon.pack.DungeonPack; -import StevenDimDoors.mod_pocketDim.helpers.DungeonHelper; -import net.minecraft.block.Block; -import net.minecraft.world.World; -import net.minecraft.world.chunk.IChunkProvider; - -public class GatewaySandstonePillars extends BaseGateway +public class GatewaySandstonePillars extends BaseSchematicGateway { - - private static final int GATEWAY_RADIUS = 4; - public GatewaySandstonePillars(DDProperties properties) { super(properties); - } + @Override - public boolean generate(World world, int x, int y, int z) + public String[] getBiomeKeywords() { - //simple to transform the generation location here. - //Do you think this is the best way to do this? - return super.generate(world, x, y+2, z); - } - @Override - public void generateRandomBits(World world, int x, int y, int z) - { - } - @Override - public DungeonPack getStartingPack() - { - return DungeonHelper.instance().getDungeonPack("RUINS"); - } - @Override - public String[] getBiomeNames() - { - return new String[]{"desert"}; + return new String[] { "desert" }; } + @Override public String getSchematicPath() { return "/schematics/gateways/sandstonePillars.schematic"; } - @Override - public boolean isSurfaceGateway() - { - return true; - } - @Override - public boolean areCoordsValid(World world, int x, int y, int z) { - // TODO Auto-generated method stub - return true; - } - } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/world/gateways/GatewayTwoPillars.java b/src/main/java/StevenDimDoors/mod_pocketDim/world/gateways/GatewayTwoPillars.java index 595d522..13507a4 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/world/gateways/GatewayTwoPillars.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/world/gateways/GatewayTwoPillars.java @@ -1,26 +1,20 @@ package StevenDimDoors.mod_pocketDim.world.gateways; -import java.util.ArrayList; - -import StevenDimDoors.mod_pocketDim.DDProperties; -import StevenDimDoors.mod_pocketDim.mod_pocketDim; -import StevenDimDoors.mod_pocketDim.dungeon.pack.DungeonPack; -import StevenDimDoors.mod_pocketDim.helpers.DungeonHelper; -import StevenDimDoors.mod_pocketDim.world.LimboProvider; import net.minecraft.block.Block; import net.minecraft.world.World; +import StevenDimDoors.mod_pocketDim.config.DDProperties; -public class GatewayTwoPillars extends BaseGateway +public class GatewayTwoPillars extends BaseSchematicGateway { - private static final int GATEWAY_RADIUS = 4; public GatewayTwoPillars(DDProperties properties) { super(properties); } + @Override - void generateRandomBits(World world, int x, int y, int z) + protected void generateRandomBits(World world, int x, int y, int z) { final int blockID = Block.stoneBrick.blockID; @@ -32,48 +26,27 @@ public class GatewayTwoPillars extends BaseGateway //Check that the block is supported by an opaque block. //This prevents us from building over a cliff, on the peak of a mountain, //or the surface of the ocean or a frozen lake. - if (world.isBlockOpaqueCube(x + xc, y - 2, z + zc)) + if (world.isBlockOpaqueCube(x + xc, y - 1, z + zc)) { //Randomly choose whether to place bricks or not. The math is designed so that the //chances of placing a block decrease as we get farther from the gateway's center. if (Math.abs(xc) + Math.abs(zc) < world.rand.nextInt(2) + 3) { //Place Stone Bricks - world.setBlock(x + xc, y - 1, z + zc, blockID, 0, 3); + world.setBlock(x + xc, y, z + zc, blockID, 0, 3); } else if (Math.abs(xc) + Math.abs(zc) < world.rand.nextInt(3) + 3) { //Place Cracked Stone Bricks - world.setBlock(x + xc, y - 1, z + zc, blockID, 2, 3); + world.setBlock(x + xc, y, z + zc, blockID, 2, 3); } } } } } - @Override - public DungeonPack getStartingPack() { - // TODO Auto-generated method stub - return DungeonHelper.instance().getDungeonPack("RUINS"); - } - @Override - public String[] getBiomeNames() { - // TODO Auto-generated method stub - return null; - } + @Override public String getSchematicPath() { - // TODO Auto-generated method stub return "/schematics/gateways/twoPillars.schematic"; } - @Override - public boolean isSurfaceGateway() { - // TODO Auto-generated method stub - return true; - } - @Override - public boolean areCoordsValid(World world, int x, int y, int z) { - // TODO Auto-generated method stub - return !(world.provider instanceof LimboProvider); - } - } diff --git a/src/main/java/StevenDimDoors/mod_pocketDimClient/ClientPacketHandler.java b/src/main/java/StevenDimDoors/mod_pocketDimClient/ClientPacketHandler.java index b9057f4..eda68a4 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDimClient/ClientPacketHandler.java +++ b/src/main/java/StevenDimDoors/mod_pocketDimClient/ClientPacketHandler.java @@ -68,6 +68,9 @@ public class ClientPacketHandler implements IPacketHandler, IUpdateSource case PacketConstants.DELETE_LINK_PACKET_ID: linkWatcher.onDeleted( ClientLinkData.read(input) ); break; + case PacketConstants.UPDATE_LINK_PACKET_ID: + linkWatcher.update( ClientLinkData.read(input) ); + break; } } catch (Exception e) diff --git a/src/main/java/StevenDimDoors/mod_pocketDimClient/ClientProxy.java b/src/main/java/StevenDimDoors/mod_pocketDimClient/ClientProxy.java index 26340c8..004e4ce 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDimClient/ClientProxy.java +++ b/src/main/java/StevenDimDoors/mod_pocketDimClient/ClientProxy.java @@ -1,8 +1,15 @@ package StevenDimDoors.mod_pocketDimClient; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.World; import StevenDimDoors.mod_pocketDim.CommonProxy; +import StevenDimDoors.mod_pocketDim.blocks.BaseDimDoor; +import StevenDimDoors.mod_pocketDim.core.DimLink; +import StevenDimDoors.mod_pocketDim.core.PocketManager; import StevenDimDoors.mod_pocketDim.ticking.MobMonolith; import StevenDimDoors.mod_pocketDim.tileentities.TileEntityDimDoor; +import StevenDimDoors.mod_pocketDim.tileentities.TileEntityRift; import StevenDimDoors.mod_pocketDim.tileentities.TileEntityTransTrapdoor; +import StevenDimDoors.mod_pocketDim.watcher.ClientLinkData; import cpw.mods.fml.client.registry.ClientRegistry; import cpw.mods.fml.client.registry.RenderingRegistry; @@ -17,16 +24,27 @@ public class ClientProxy extends CommonProxy ClientRegistry.bindTileEntitySpecialRenderer(TileEntityDimDoor.class, new RenderDimDoor()); ClientRegistry.bindTileEntitySpecialRenderer(TileEntityTransTrapdoor.class, new RenderTransTrapdoor()); //This code activates the new rift rendering, as well as a bit of code in TileEntityRift - //ClientRegistry.bindTileEntitySpecialRenderer(TileEntityRift.class, new RenderRift()); - + ClientRegistry.bindTileEntitySpecialRenderer(TileEntityRift.class, new RenderRift()); + //MinecraftForgeClient.preloadTexture(RIFT2_PNG); RenderingRegistry.registerEntityRenderingHandler(MobMonolith.class, new RenderMobObelisk(.5F)); + RenderingRegistry.registerBlockHandler(new PrivatePocketRender(RenderingRegistry.getNextAvailableRenderId())); + } @Override - public void loadTextures() + public void updateDoorTE(BaseDimDoor door, World world, int x, int y, int z) { - + TileEntity tile = world.getBlockTileEntity(x, y, z); + if (tile instanceof TileEntityDimDoor) + { + DimLink link = PocketManager.getLink(x, y, z, world); + int metadata = world.getBlockMetadata(x, y, z); + TileEntityDimDoor dimTile = (TileEntityDimDoor) tile; + dimTile.openOrClosed = door.isDoorOnRift(world, x, y, z)&&door.isUpperDoorBlock(metadata); + dimTile.orientation = door.getFullMetadata(world, x, y, z) & 7; + dimTile.lockStatus = door.getLockStatus(world, x, y, z); + } } @Override 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 cece273..0000000 --- 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/ClosingRiftFX.java b/src/main/java/StevenDimDoors/mod_pocketDimClient/ClosingRiftFX.java index 2ea3239..a36d77c 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDimClient/ClosingRiftFX.java +++ b/src/main/java/StevenDimDoors/mod_pocketDimClient/ClosingRiftFX.java @@ -100,7 +100,7 @@ public class ClosingRiftFX extends EntityFX float var15 = (float)(this.prevPosZ + (this.posZ - this.prevPosZ) * par2 - interpPosZ); float var16 = 0.8F; - if (PocketManager.getDimensionData(worldObj).isPocketDimension()) + if (PocketManager.createDimensionData(worldObj).isPocketDimension()) { var16 = 0.4F; } diff --git a/src/main/java/StevenDimDoors/mod_pocketDimClient/GoggleRiftFX.java b/src/main/java/StevenDimDoors/mod_pocketDimClient/GoggleRiftFX.java index 069d58f..9845af8 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDimClient/GoggleRiftFX.java +++ b/src/main/java/StevenDimDoors/mod_pocketDimClient/GoggleRiftFX.java @@ -54,7 +54,7 @@ public class GoggleRiftFX extends EntityFireworkSparkFX float var15 = (float)(this.prevPosZ + (this.posZ - this.prevPosZ) * par2 - interpPosZ); float var16 = .0F; - if (PocketManager.getDimensionData(worldObj).isPocketDimension()) + if (PocketManager.createDimensionData(worldObj).isPocketDimension()) { var16 = .7F; } diff --git a/src/main/java/StevenDimDoors/mod_pocketDimClient/PrivatePocketRender.java b/src/main/java/StevenDimDoors/mod_pocketDimClient/PrivatePocketRender.java new file mode 100644 index 0000000..08458ea --- /dev/null +++ b/src/main/java/StevenDimDoors/mod_pocketDimClient/PrivatePocketRender.java @@ -0,0 +1,160 @@ +package StevenDimDoors.mod_pocketDimClient; + +import org.lwjgl.opengl.GL11; +import net.minecraft.block.Block; +import net.minecraft.block.BlockGrass; +import net.minecraft.client.renderer.RenderBlocks; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.util.Icon; +import net.minecraft.world.IBlockAccess; +import cpw.mods.fml.client.registry.ISimpleBlockRenderingHandler; + +public class PrivatePocketRender implements ISimpleBlockRenderingHandler +{ + public static int renderID; + + public PrivatePocketRender(int renderID) + { + PrivatePocketRender.renderID = renderID; + } + + @Override + public void renderInventoryBlock(Block block, int metadata, int modelID, RenderBlocks renderer) + { + Tessellator tessellator = Tessellator.instance; + + float f2; + float f3; + int k; + block.setBlockBoundsForItemRender(); + renderer.setRenderBoundsFromBlock(block); + GL11.glRotatef(90.0F, 0.0F, 1.0F, 0.0F); + GL11.glTranslatef(-0.5F, -0.5F, -0.5F); + tessellator.startDrawingQuads(); + tessellator.setNormal(0.0F, -1.0F, 0.0F); + renderer.renderFaceYNeg(block, 0.0D, 0.0D, 0.0D, renderer.getBlockIconFromSideAndMetadata(block, 0, metadata)); + tessellator.draw(); + + if (renderer.useInventoryTint) + { + k = block.getRenderColor(metadata); + f2 = (float)(k >> 16 & 255) / 255.0F; + f3 = (float)(k >> 8 & 255) / 255.0F; + float f7 = (float)(k & 255) / 255.0F; + //GL11.glColor4f(f2 * par3, f3 * par3, f7 * par3, 1.0F); + } + + tessellator.startDrawingQuads(); + tessellator.setNormal(0.0F, 1.0F, 0.0F); + renderer.renderFaceYPos(block, 0.0D, 0.0D, 0.0D, renderer.getBlockIconFromSideAndMetadata(block, 1, metadata)); + tessellator.draw(); + + if (renderer.useInventoryTint) + { + // GL11.glColor4f(par3, par3, par3, 1.0F); + } + + tessellator.startDrawingQuads(); + tessellator.setNormal(0.0F, 0.0F, -1.0F); + renderer.renderFaceZNeg(block, 0.0D, 0.0D, 0.0D, renderer.getBlockIconFromSideAndMetadata(block, 2, metadata)); + tessellator.draw(); + tessellator.startDrawingQuads(); + tessellator.setNormal(0.0F, 0.0F, 1.0F); + renderer.renderFaceZPos(block, 0.0D, 0.0D, 0.0D, renderer.getBlockIconFromSideAndMetadata(block, 3, metadata)); + tessellator.draw(); + tessellator.startDrawingQuads(); + tessellator.setNormal(-1.0F, 0.0F, 0.0F); + renderer.renderFaceXNeg(block, 0.0D, 0.0D, 0.0D, renderer.getBlockIconFromSideAndMetadata(block, 4, metadata)); + tessellator.draw(); + tessellator.startDrawingQuads(); + tessellator.setNormal(1.0F, 0.0F, 0.0F); + renderer.renderFaceXPos(block, 0.0D, 0.0D, 0.0D, renderer.getBlockIconFromSideAndMetadata(block, 5, metadata)); + tessellator.draw(); + GL11.glTranslatef(0.5F, 0.5F, 0.5F); } + + @Override + public boolean renderWorldBlock(IBlockAccess world, int x, int y, int z, Block block, int modelId, RenderBlocks renderer) + { + + Tessellator tessellator = Tessellator.instance; + boolean flag = false; + + Icon icon = renderer.getBlockIcon(block, world, x, y, z, 2); + + + + tessellator.setColorOpaque_F(1F, 1F, 1F); + + if (renderer.renderAllFaces || block.shouldSideBeRendered(world, x, y - 1, z, 0)) + { + renderer.renderFaceYNeg(block, (double)x, (double)y, (double)z, icon); + flag = true; + } + tessellator.setColorOpaque_F(1F, 1F, 1F); + + if (renderer.renderAllFaces || block.shouldSideBeRendered(world, x, y + 1, z, 1)) + { + renderer.renderFaceYPos(block, (double)x, (double)y, (double)z, icon); + flag = true; + } + + + tessellator.setColorOpaque_F(1F, 1F, 1F); + + if (renderer.renderAllFaces || block.shouldSideBeRendered(world, x, y, z - 1, 2)) + { + renderer.renderFaceZNeg(block, (double)x, (double)y, (double)z, icon); + + + flag = true; + } + tessellator.setColorOpaque_F(1F, 1F, 1F); + + if (renderer.renderAllFaces || block.shouldSideBeRendered(world, x, y, z + 1, 3)) + { + renderer.renderFaceZPos(block, (double)x, (double)y, (double)z, icon); + + + + flag = true; + } + tessellator.setColorOpaque_F(1F, 1F, 1F); + + if (renderer.renderAllFaces || block.shouldSideBeRendered(world, x - 1, y, z, 4)) + { + renderer.renderFaceXNeg(block, (double)x, (double)y, (double)z, icon); + + + + flag = true; + } + tessellator.setColorOpaque_F(1F, 1F, 1F); + + if (renderer.renderAllFaces || block.shouldSideBeRendered(world, x + 1, y, z, 5)) + { + renderer.renderFaceXPos(block, (double)x, (double)y, (double)z, icon); + + + + flag = true; + } + + return flag; + } + + + @Override + public boolean shouldRender3DInInventory() + { + // TODO Auto-generated method stub + return true; + } + + @Override + public int getRenderId() + { + // TODO Auto-generated method stub + return renderID; + } + +} diff --git a/src/main/java/StevenDimDoors/mod_pocketDimClient/RenderDimDoor.java b/src/main/java/StevenDimDoors/mod_pocketDimClient/RenderDimDoor.java index 88358d1..cbd3e21 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDimClient/RenderDimDoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDimClient/RenderDimDoor.java @@ -1,18 +1,43 @@ package StevenDimDoors.mod_pocketDimClient; +import static org.lwjgl.opengl.GL11.GL_LIGHTING; +import static org.lwjgl.opengl.GL11.GL_ONE_MINUS_DST_COLOR; +import static org.lwjgl.opengl.GL11.GL_TEXTURE_2D; +import static org.lwjgl.opengl.GL11.GL_ZERO; +import static org.lwjgl.opengl.GL11.glBlendFunc; import java.nio.FloatBuffer; +import java.util.Iterator; import java.util.Random; - -import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.GLAllocation; -import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer; -import net.minecraft.tileentity.TileEntity; -import net.minecraft.util.ResourceLocation; - import org.lwjgl.opengl.GL11; -import StevenDimDoors.mod_pocketDim.DDProperties; +import net.minecraft.block.material.MapColor; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.ActiveRenderInfo; +import net.minecraft.client.renderer.GLAllocation; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.entity.RenderItem; +import net.minecraft.client.renderer.entity.RenderManager; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.renderer.texture.TextureCompass; +import net.minecraft.client.renderer.texture.TextureManager; +import net.minecraft.client.renderer.texture.TextureMap; +import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer; +import net.minecraft.entity.item.EntityItem; +import net.minecraft.entity.item.EntityItemFrame; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.Direction; +import net.minecraft.util.MathHelper; +import net.minecraft.util.ResourceLocation; +import net.minecraft.world.storage.MapCoord; +import net.minecraft.world.storage.MapData; + +import static org.lwjgl.opengl.GL11.*; + import StevenDimDoors.mod_pocketDim.mod_pocketDim; +import StevenDimDoors.mod_pocketDim.config.DDProperties; import StevenDimDoors.mod_pocketDim.core.DimLink; import StevenDimDoors.mod_pocketDim.core.NewDimData; import StevenDimDoors.mod_pocketDim.core.PocketManager; @@ -24,8 +49,12 @@ import cpw.mods.fml.relauncher.SideOnly; public class RenderDimDoor extends TileEntitySpecialRenderer { private FloatBuffer buffer = GLAllocation.createDirectFloatBuffer(16); - private ResourceLocation riftPath= new ResourceLocation(mod_pocketDim.modid + ":textures/other/RIFT.png"); private ResourceLocation warpPath= new ResourceLocation(mod_pocketDim.modid + ":textures/other/WARP.png"); + private ResourceLocation keyPath= new ResourceLocation(mod_pocketDim.modid + ":textures/other/Keyhole.png"); + private ResourceLocation KeyholeLight= new ResourceLocation(mod_pocketDim.modid + ":textures/other/KeyholeLight.png"); + private ResourceLocation keyOutline= new ResourceLocation(mod_pocketDim.modid + ":textures/other/keyOutline.png"); + private ResourceLocation keyOutlineLight= new ResourceLocation(mod_pocketDim.modid + ":textures/other/keyOutlineLight.png"); + private static final int NETHER_DIMENSION_ID = -1; private static DDProperties properties = null; @@ -42,28 +71,15 @@ public class RenderDimDoor extends TileEntitySpecialRenderer public void renderDimDoorTileEntity(TileEntityDimDoor tile, double x, double y, double z) { - try - { - mod_pocketDim.dimensionalDoor.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 rand = new Random(31100L); float var13 = 0.75F; for (int count = 0; count < 16; ++count) { + + GL11.glPushMatrix(); float var15 = 16 - count; float var16 = 0.2625F; @@ -71,7 +87,7 @@ public class RenderDimDoor extends TileEntitySpecialRenderer if (count == 0) { - this.bindTexture(riftPath); + this.bindTexture(warpPath); // move files into assets/modid and change to new ResourceLocation(modid:/RIFT.png) var17 = 0.1F; var15 = 25.0F; @@ -88,92 +104,80 @@ public class RenderDimDoor extends TileEntitySpecialRenderer GL11.glBlendFunc(GL11.GL_ONE, GL11.GL_ONE); var16 = .5F; } - /** - * float startY = (float)(+(y + (double)var13)); float ratioY = - * startY + ActiveRenderInfo.objectY; float ratioY2 = startY + var15 - * + ActiveRenderInfo.objectY; float yConverted = ratioY / ratioY2; - * - * float startZ = (float)(+(z + (double)var13)); float ratioZ = - * startZ + ActiveRenderInfo.objectZ; float ratioZ2 = startZ + var15 - * + ActiveRenderInfo.objectZ; float zConverted = ratioZ / ratioZ2; - * - * float startX = (float)(+(x + (double)var13)); float ratioX = - * startX + ActiveRenderInfo.objectX; float ratioX2 = startX + var15 - * + ActiveRenderInfo.objectX; float xConverted = ratioX / ratioX2; - * - * yConverted += (float)(y + (double)var13); xConverted += (float)(x - * + (double)var13); zConverted += (float)(z + (double)var13); - **/ - - GL11.glTranslatef( - Minecraft.getSystemTime() % 200000L / 200000.0F, - 0, 0.0F); - GL11.glTranslatef(0, - Minecraft.getSystemTime() % 200000L / 200000.0F, - 0.0F); - GL11.glTranslatef(0, 0, - Minecraft.getSystemTime() % 200000L / 200000.0F); - - GL11.glTexGeni(GL11.GL_S, GL11.GL_TEXTURE_GEN_MODE, - GL11.GL_OBJECT_LINEAR); - GL11.glTexGeni(GL11.GL_T, GL11.GL_TEXTURE_GEN_MODE, - GL11.GL_OBJECT_LINEAR); - GL11.glTexGeni(GL11.GL_R, GL11.GL_TEXTURE_GEN_MODE, - GL11.GL_OBJECT_LINEAR); - GL11.glTexGeni(GL11.GL_Q, GL11.GL_TEXTURE_GEN_MODE, - GL11.GL_OBJECT_LINEAR); - switch ((tile.orientation % 4) + 4) - { - case 4: - GL11.glTexGen(GL11.GL_S, GL11.GL_OBJECT_PLANE, - this.getFloatBuffer(0.0F, 1.0F, 0.0F, 0.0F)); - GL11.glTexGen(GL11.GL_T, GL11.GL_OBJECT_PLANE, - this.getFloatBuffer(0.0F, 0.0F, 1.0F, 0.0F)); - GL11.glTexGen(GL11.GL_R, GL11.GL_OBJECT_PLANE, - this.getFloatBuffer(0.0F, 0.0F, 0.0F, 1.0F)); - GL11.glTexGen(GL11.GL_Q, GL11.GL_OBJECT_PLANE, - this.getFloatBuffer(1.0F, 0.0F, 0.0F, 0.15F)); - - break; - case 5: - - GL11.glTexGen(GL11.GL_S, GL11.GL_OBJECT_PLANE, - this.getFloatBuffer(0.0F, 1.0F, 0.0F, 0.0F)); - GL11.glTexGen(GL11.GL_T, GL11.GL_OBJECT_PLANE, - this.getFloatBuffer(1.0F, 0.0F, 0.0F, 0.0F)); - GL11.glTexGen(GL11.GL_R, GL11.GL_OBJECT_PLANE, - this.getFloatBuffer(0.0F, 0.0F, 0.0F, 1.0F)); - GL11.glTexGen(GL11.GL_Q, GL11.GL_OBJECT_PLANE, - this.getFloatBuffer(0.0F, 0.0F, 1.0F, 0.15F)); - break; - case 6: - GL11.glTexGen(GL11.GL_S, GL11.GL_OBJECT_PLANE, - this.getFloatBuffer(0.0F, 1.0F, 0.0F, 0.0F)); - GL11.glTexGen(GL11.GL_T, GL11.GL_OBJECT_PLANE, - this.getFloatBuffer(0.0F, 0.0F, 1.0F, 0.0F)); - GL11.glTexGen(GL11.GL_R, GL11.GL_OBJECT_PLANE, - this.getFloatBuffer(0.0F, 0.0F, 0.0F, 1.0F)); - GL11.glTexGen(GL11.GL_Q, GL11.GL_OBJECT_PLANE, - this.getFloatBuffer(1.0F, 0.0F, 0.0F, -0.15F)); - - break; - case 7: - GL11.glTexGen(GL11.GL_S, GL11.GL_OBJECT_PLANE, - this.getFloatBuffer(0.0F, 1.0F, 0.0F, 0.0F)); - GL11.glTexGen(GL11.GL_T, GL11.GL_OBJECT_PLANE, - this.getFloatBuffer(1.0F, 0.0F, 0.0F, 0.0F)); - GL11.glTexGen(GL11.GL_R, GL11.GL_OBJECT_PLANE, - this.getFloatBuffer(0.0F, 0.0F, 0.0F, 1.0F)); - GL11.glTexGen(GL11.GL_Q, GL11.GL_OBJECT_PLANE, - this.getFloatBuffer(0.0F, 0.0F, 1.0F, -0.15F)); - break; - - } - - GL11.glEnable(GL11.GL_TEXTURE_GEN_S); - GL11.glEnable(GL11.GL_TEXTURE_GEN_T); - GL11.glEnable(GL11.GL_TEXTURE_GEN_R); - GL11.glEnable(GL11.GL_TEXTURE_GEN_Q); + + + + GL11.glTranslatef( + Minecraft.getSystemTime() % 200000L / 200000.0F, + 0, 0.0F); + GL11.glTranslatef(0, + Minecraft.getSystemTime() % 200000L / 200000.0F, + 0.0F); + GL11.glTranslatef(0, 0, + Minecraft.getSystemTime() % 200000L / 200000.0F); + + GL11.glTexGeni(GL11.GL_S, GL11.GL_TEXTURE_GEN_MODE, + GL11.GL_OBJECT_LINEAR); + GL11.glTexGeni(GL11.GL_T, GL11.GL_TEXTURE_GEN_MODE, + GL11.GL_OBJECT_LINEAR); + GL11.glTexGeni(GL11.GL_R, GL11.GL_TEXTURE_GEN_MODE, + GL11.GL_OBJECT_LINEAR); + GL11.glTexGeni(GL11.GL_Q, GL11.GL_TEXTURE_GEN_MODE, + GL11.GL_OBJECT_LINEAR); + switch ((tile.orientation % 4) + 4) + { + case 4: + GL11.glTexGen(GL11.GL_S, GL11.GL_OBJECT_PLANE, + this.getFloatBuffer(0.0F, 1.0F, 0.0F, 0.0F)); + GL11.glTexGen(GL11.GL_T, GL11.GL_OBJECT_PLANE, + this.getFloatBuffer(0.0F, 0.0F, 1.0F, 0.0F)); + GL11.glTexGen(GL11.GL_R, GL11.GL_OBJECT_PLANE, + this.getFloatBuffer(0.0F, 0.0F, 0.0F, 1.0F)); + GL11.glTexGen(GL11.GL_Q, GL11.GL_OBJECT_PLANE, + this.getFloatBuffer(1.0F, 0.0F, 0.0F, 0.15F)); + + break; + case 5: + + GL11.glTexGen(GL11.GL_S, GL11.GL_OBJECT_PLANE, + this.getFloatBuffer(0.0F, 1.0F, 0.0F, 0.0F)); + GL11.glTexGen(GL11.GL_T, GL11.GL_OBJECT_PLANE, + this.getFloatBuffer(1.0F, 0.0F, 0.0F, 0.0F)); + GL11.glTexGen(GL11.GL_R, GL11.GL_OBJECT_PLANE, + this.getFloatBuffer(0.0F, 0.0F, 0.0F, 1.0F)); + GL11.glTexGen(GL11.GL_Q, GL11.GL_OBJECT_PLANE, + this.getFloatBuffer(0.0F, 0.0F, 1.0F, 0.15F)); + break; + case 6: + GL11.glTexGen(GL11.GL_S, GL11.GL_OBJECT_PLANE, + this.getFloatBuffer(0.0F, 1.0F, 0.0F, 0.0F)); + GL11.glTexGen(GL11.GL_T, GL11.GL_OBJECT_PLANE, + this.getFloatBuffer(0.0F, 0.0F, 1.0F, 0.0F)); + GL11.glTexGen(GL11.GL_R, GL11.GL_OBJECT_PLANE, + this.getFloatBuffer(0.0F, 0.0F, 0.0F, 1.0F)); + GL11.glTexGen(GL11.GL_Q, GL11.GL_OBJECT_PLANE, + this.getFloatBuffer(1.0F, 0.0F, 0.0F, -0.15F)); + + break; + case 7: + GL11.glTexGen(GL11.GL_S, GL11.GL_OBJECT_PLANE, + this.getFloatBuffer(0.0F, 1.0F, 0.0F, 0.0F)); + GL11.glTexGen(GL11.GL_T, GL11.GL_OBJECT_PLANE, + this.getFloatBuffer(1.0F, 0.0F, 0.0F, 0.0F)); + GL11.glTexGen(GL11.GL_R, GL11.GL_OBJECT_PLANE, + this.getFloatBuffer(0.0F, 0.0F, 0.0F, 1.0F)); + GL11.glTexGen(GL11.GL_Q, GL11.GL_OBJECT_PLANE, + this.getFloatBuffer(0.0F, 0.0F, 1.0F, -0.15F)); + break; + + } + + GL11.glEnable(GL11.GL_TEXTURE_GEN_S); + GL11.glEnable(GL11.GL_TEXTURE_GEN_T); + GL11.glEnable(GL11.GL_TEXTURE_GEN_R); + GL11.glEnable(GL11.GL_TEXTURE_GEN_Q); + + GL11.glPopMatrix(); GL11.glMatrixMode(GL11.GL_TEXTURE); GL11.glPushMatrix(); @@ -189,34 +193,8 @@ public class RenderDimDoor extends TileEntitySpecialRenderer GL11.glBegin(GL11.GL_QUADS); - // Set the portal's color depending on whether it's in the Nether - float var21, var22, var23; - NewDimData dimension = PocketManager.getDimensionData(tile.worldObj); - if (dimension.root().id() == NETHER_DIMENSION_ID) - { - var21 = rand.nextFloat() * 0.5F + 0.4F; - var22 = rand.nextFloat() * 0.05F; - var23 = rand.nextFloat() * 0.05F; - if (count == 0) - { - var21 = 1.0F; - } - } - else - { - var21 = rand.nextFloat() * 0.5F + 0.1F; - var22 = rand.nextFloat() * 0.4F + 0.4F; - var23 = rand.nextFloat() * 0.6F + 0.5F; - if (count == 0) - { - var23 = 1.0F; - var22 = 1.0F; - } - } - - GL11.glColor4d(var21 * var17, var22 * var17, var23 * var17, 1.0F); - if (tile.openOrClosed) - { + float[] color = tile.getRenderColor(rand); + GL11.glColor4f(color[0] * var17, color[1] * var17, color[2] * var17, color[3]); switch (tile.orientation) { @@ -230,8 +208,8 @@ public class RenderDimDoor extends TileEntitySpecialRenderer case 1: GL11.glVertex3d(x, y + 1, z + .01); GL11.glVertex3d(x + 1, y + 1, z + .01); - GL11.glVertex3d(x + 1, y - 1, z + .01); - GL11.glVertex3d(x, y - 1, z + .01); + GL11.glVertex3d(x + 1, y -1, z + .01); + GL11.glVertex3d(x, y -1, z + .01); break; case 2: GL11.glVertex3d(x + .99, y + 1, z); @@ -240,13 +218,13 @@ public class RenderDimDoor extends TileEntitySpecialRenderer GL11.glVertex3d(x + .99, y - 1, z); break; case 3: - GL11.glVertex3d(x, y - 1, z + .99); - GL11.glVertex3d(x + 1, y - 1, z + .99); + GL11.glVertex3d(x, y -1, z + .99); + GL11.glVertex3d(x + 1, y -1, z + .99); GL11.glVertex3d(x + 1, y + 1, z + .99); GL11.glVertex3d(x, y + 1, z + .99); break; case 4: - GL11.glVertex3d(x + .15F, y - 1, z); + GL11.glVertex3d(x + .15F, y - 1 , z); GL11.glVertex3d(x + .15, y - 1, z + 1.0D); GL11.glVertex3d(x + .15, y + 1, z + 1.0D); GL11.glVertex3d(x + .15, y + 1, z); @@ -270,7 +248,7 @@ public class RenderDimDoor extends TileEntitySpecialRenderer GL11.glVertex3d(x, y + 1, z + .85); break; } - } + GL11.glEnd(); @@ -293,13 +271,110 @@ public class RenderDimDoor extends TileEntitySpecialRenderer buffer.flip(); return buffer; } + + private void renderKeyHole(TileEntityDimDoor tile, double x, + double y, double z, int i) + { + if(tile.orientation>3) + { + return; + } + int rotation = (tile.orientation+3)%4; + + GL11.glPushMatrix(); + GL11.glTranslated(x,y,z); + x= ActiveRenderInfo.objectX; + y = ActiveRenderInfo.objectY; + z = ActiveRenderInfo.objectZ; + + GL11.glRotatef(180.0F - 90*rotation, 0.0F, 1.0F, 0.0F); + //GL11.glRotatef((float)(-90 * rotation), 0.0F, 0.0F, 1.0F); + + GL11.glTranslatef(0.007F, .25F, 0F); + + switch (rotation) + { + case 0: + GL11.glTranslatef(-0.5F, 0, -0.03F); + break; + case 1: + GL11.glTranslatef(-.5F, 0F, .97F); + break; + case 2: + GL11.glTranslatef(.5F, 0F, .97F); + break; + case 3: + GL11.glTranslatef(0.5F, 0F, -0.03F); + } + + GL11.glDisable(GL_LIGHTING); + Tessellator tessellator = Tessellator.instance; + GL11.glEnable(GL11.GL_BLEND); + if(i==1) + { + bindTexture(KeyholeLight); + GL11.glColor4d(1, 1, 1, .7); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_DST_COLOR); + + } + else + { + bindTexture(keyPath); + glBlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA); + + } + GL11.glRotatef(180.0F, 0.0F, 1.0F, 0.0F); + GL11.glRotatef(180.0F, 0.0F, 0.0F, 1.0F); + GL11.glScalef(0.00860625F, 0.00730625F, 0.0086625F); + GL11.glTranslatef(-65.0F, -107.0F, -3.0F); + GL11.glNormal3f(0.0F, 0.0F, -1.0F); + tessellator.startDrawingQuads(); + byte b0 = 7; + tessellator.addVertexWithUV((double)(0 - b0), (double)(128 + b0), 0.0D, 0.0D, 1.0D); + tessellator.addVertexWithUV((double)(128 + b0), (double)(128 + b0), 0.0D, 1.0D, 1.0D); + tessellator.addVertexWithUV((double)(128 + b0), (double)(0 - b0), 0.0D, 1.0D, 0.0D); + tessellator.addVertexWithUV((double)(0 - b0), (double)(0 - b0), 0.0D, 0.0D, 0.0D); + tessellator.draw(); + GL11.glTranslatef(0.0F, 0.0F, -1.0F); + GL11.glDisable(GL11.GL_BLEND); + + + GL11.glPopMatrix(); + } + + @Override public void renderTileEntityAt(TileEntity par1TileEntity, double par2, double par4, double par6, float par8) { if (properties.DoorRenderingEnabled) { - renderDimDoorTileEntity((TileEntityDimDoor) par1TileEntity, par2, par4, par6); + TileEntityDimDoor tile = (TileEntityDimDoor) par1TileEntity; + try + { + mod_pocketDim.dimensionalDoor.updateAttachedTile(tile.worldObj, + tile.xCoord, tile.yCoord, tile.zCoord); + } + catch (Exception e) + { + e.printStackTrace(); + } + + if (tile.openOrClosed) + { + + renderDimDoorTileEntity((TileEntityDimDoor) par1TileEntity, par2, par4, par6); + if(tile.lockStatus>=1) + { + for(int i = 0; i<1+tile.lockStatus; i++ ) + { + this.renderKeyHole(tile, par2, par4, par6, i); + + } + } + + } + } } -} +} \ No newline at end of file diff --git a/src/main/java/StevenDimDoors/mod_pocketDimClient/RenderMobObelisk.java b/src/main/java/StevenDimDoors/mod_pocketDimClient/RenderMobObelisk.java index b21e084..dc35abd 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDimClient/RenderMobObelisk.java +++ b/src/main/java/StevenDimDoors/mod_pocketDimClient/RenderMobObelisk.java @@ -1,22 +1,19 @@ package StevenDimDoors.mod_pocketDimClient; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.OpenGlHelper; +import net.minecraft.client.renderer.entity.RenderLiving; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLiving; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.client.event.RenderLivingEvent; +import net.minecraftforge.common.MinecraftForge; + import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL12; import StevenDimDoors.mod_pocketDim.mod_pocketDim; import StevenDimDoors.mod_pocketDim.ticking.MobMonolith; -import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.OpenGlHelper; -import net.minecraft.client.renderer.Tessellator; -import net.minecraft.client.renderer.entity.RenderLiving; -import net.minecraft.entity.Entity; -import net.minecraft.entity.EntityHanging; -import net.minecraft.entity.EntityLiving; -import net.minecraft.entity.EntityLivingBase; -import net.minecraft.util.MathHelper; -import net.minecraft.util.ResourceLocation; -import net.minecraftforge.client.event.RenderLivingEvent; -import net.minecraftforge.common.MinecraftForge; import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; @@ -31,15 +28,15 @@ public class RenderMobObelisk extends RenderLiving this.obeliskModel = (ModelMobObelisk)this.mainModel; } + @Override public void doRenderLiving(EntityLiving entity, double x, double y, double z, float par8, float par9) { final float minScaling = 0; final float maxScaling = 0.1f; - final int maxAggroLevel = 500; MobMonolith monolith = ((MobMonolith) entity); // Use linear interpolation to scale how much jitter we want for our given aggro level - float aggroScaling = minScaling + monolith.aggro * (maxScaling - minScaling) / maxAggroLevel; + float aggroScaling = minScaling + (maxScaling - minScaling) * monolith.getAggroProgress(); // Calculate jitter - include entity ID to give Monoliths individual jitters float time = ((Minecraft.getSystemTime() + 0xF1234568 * monolith.entityId) % 200000) / 50.0F; @@ -67,21 +64,25 @@ public class RenderMobObelisk extends RenderLiving try { - float interpolatedYaw = this.interpolateRotation(par1EntityLivingBase.prevRenderYawOffset, par1EntityLivingBase.renderYawOffset, par9); - float interpolatedYawHead = this.interpolateRotation(par1EntityLivingBase.prevRotationYawHead, par1EntityLivingBase.rotationYawHead, par9); + float interpolatedYaw = interpolateRotation(par1EntityLivingBase.prevRenderYawOffset, par1EntityLivingBase.renderYawOffset, par9); + float interpolatedYawHead = interpolateRotation(par1EntityLivingBase.prevRotationYawHead, par1EntityLivingBase.rotationYawHead, par9); float rotation; float pitch = par1EntityLivingBase.prevRotationPitch + (par1EntityLivingBase.rotationPitch - par1EntityLivingBase.prevRotationPitch) * par9; this.renderLivingAt(par1EntityLivingBase, x, y, z); rotation = this.handleRotationFloat(par1EntityLivingBase, par9); this.rotateCorpse(par1EntityLivingBase, rotation, interpolatedYaw, par9); + float f6 = 0.0625F; GL11.glEnable(GL12.GL_RESCALE_NORMAL); + GL11.glScalef(-1.0F, -1.0F, 1.0F); this.preRenderCallback(par1EntityLivingBase, par9); - GL11.glTranslatef(0.0F, -24.0F * f6 - 0.0078125F, 0.0F); + GL11.glRotatef(((MobMonolith)par1EntityLivingBase).pitchLevel , 1.0F, 0.0F, 0.0F); + GL11.glTranslatef(0.0F, 24.0F * f6 - 0.0078125F, 0.0F); - this.renderModel(par1EntityLivingBase, 0, 0, rotation, interpolatedYawHead - interpolatedYaw, pitch, f6); + + this.renderModel(par1EntityLivingBase, 0, 0, rotation, interpolatedYaw, pitch, f6); OpenGlHelper.setActiveTexture(OpenGlHelper.lightmapTexUnit); GL11.glDisable(GL11.GL_TEXTURE_2D); @@ -105,29 +106,25 @@ public class RenderMobObelisk extends RenderLiving GL11.glPopMatrix(); MinecraftForge.EVENT_BUS.post(new RenderLivingEvent.Post(par1EntityLivingBase, this)); } - - - private float interpolateRotation(float par1, float par2, float par3) + + private static float interpolateRotation(float par1, float par2, float par3) { - float f3; - - for (f3 = par2 - par1; f3 < -180.0F; f3 += 360.0F) + float f3 = par2 - par1; + while (f3 < -180.0f) { - ; + f3 += 360.0F; } - while (f3 >= 180.0F) { f3 -= 360.0F; } - return par1 + par3 * f3; } + @Override protected ResourceLocation getEntityTexture(Entity entity) { - byte b0 = entity.getDataWatcher().getWatchableObjectByte(16); - - return new ResourceLocation(mod_pocketDim.modid+":textures/mobs/Monolith"+b0+".png"); + MobMonolith monolith = (MobMonolith) entity; + return new ResourceLocation(mod_pocketDim.modid + ":textures/mobs/Monolith" + monolith.getTextureState() + ".png"); } } \ No newline at end of file diff --git a/src/main/java/StevenDimDoors/mod_pocketDimClient/RenderRift.java b/src/main/java/StevenDimDoors/mod_pocketDimClient/RenderRift.java index 07c1cf9..762bca4 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDimClient/RenderRift.java +++ b/src/main/java/StevenDimDoors/mod_pocketDimClient/RenderRift.java @@ -1,218 +1,168 @@ package StevenDimDoors.mod_pocketDimClient; -import static org.lwjgl.opengl.GL11.GL_BLEND; -import static org.lwjgl.opengl.GL11.GL_LIGHTING; -import static org.lwjgl.opengl.GL11.GL_ONE_MINUS_DST_COLOR; -import static org.lwjgl.opengl.GL11.GL_TEXTURE_2D; -import static org.lwjgl.opengl.GL11.GL_ZERO; -import static org.lwjgl.opengl.GL11.glBlendFunc; - +import static org.lwjgl.opengl.GL11.*; +import java.awt.Point; import java.util.HashMap; - +import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer; import net.minecraft.tileentity.TileEntity; - import org.lwjgl.opengl.GL11; - import StevenDimDoors.mod_pocketDim.tileentities.TileEntityRift; +import StevenDimDoors.mod_pocketDim.util.l_systems.LSystem; +import StevenDimDoors.mod_pocketDim.util.l_systems.LSystem.PolygonStorage; import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; @SideOnly(Side.CLIENT) public class RenderRift extends TileEntitySpecialRenderer { - + @Override - public void renderTileEntityAt(TileEntity te, double xWorld, double yWorld, - double zWorld, float f) + public void renderTileEntityAt(TileEntity te, double xWorld, double yWorld, double zWorld, float f) { - yWorld = yWorld+.75; + // prepare fb for drawing GL11.glPushMatrix(); - + + // make the rift render on both sides, disable texture mapping and + // lighting GL11.glDisable(GL11.GL_CULL_FACE); - GL11.glDisable(GL_TEXTURE_2D); - GL11.glDisable(GL_LIGHTING); + GL11.glDisable(GL_TEXTURE_2D); + GL11.glDisable(GL_LIGHTING); + GL11.glEnable(GL_BLEND); + /** + * GL11.glLogicOp(GL11.GL_INVERT); + * GL11.glEnable(GL11.GL_COLOR_LOGIC_OP); + */ + TileEntityRift rift = (TileEntityRift) te; + // draws the verticies corresponding to the passed it + this.drawCrack(rift.riftRotation, rift.getCurve(), rift.growth/15, xWorld, yWorld, zWorld); - //GL11.glLogicOp(GL11.GL_INVERT); - // GL11.glEnable(GL11.GL_COLOR_LOGIC_OP); - - GL11.glColor4f(.2F, .2F, .2F, 1F); - - GL11.glEnable(GL_BLEND); - glBlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ZERO); - - /** - * just draws the verticies - */ - this.drawCrack(TileEntityRift.class.cast(te).renderingCenters, xWorld, yWorld, zWorld); - this.drawCrackRotated(TileEntityRift.class.cast(te).renderingCenters, xWorld, yWorld, zWorld); - - + GL11.glDisable(GL_BLEND); + // reenable all the stuff we disabled GL11.glEnable(GL11.GL_CULL_FACE); GL11.glEnable(GL11.GL_LIGHTING); - GL11.glEnable(GL_TEXTURE_2D); + GL11.glEnable(GL_TEXTURE_2D); - GL11.glDisable(GL11.GL_COLOR_LOGIC_OP); GL11.glPopMatrix(); - } - - public void drawCrack(HashMap quads,double xWorld,double yWorld,double zWorld) + + /** + * method that draws the fractal and applies animations/effects + * + * f + * + * @param riftRotation + * @param poly + * @param size + * @param xWorld + * @param yWorld + * @param zWorld + */ + public void drawCrack(int riftRotation, PolygonStorage poly, double size, double xWorld, double yWorld, double zWorld) { - GL11.glBegin(GL11.GL_QUAD_STRIP); + // calculate the proper size for the rift render + double scale = size / (poly.maxX - poly.minX); - drawVertex(xWorld+.5, yWorld-Math.log(Math.pow(quads.size(),2)+1)/14, zWorld+.5); - drawVertex(xWorld+.5, yWorld+Math.log(Math.pow(quads.size(),2)+1)/14, zWorld+.5); - for(int i = 0;;i++) - { - if(!quads.containsKey(i)) - { - break; - } - double[] coords = quads.get(i); - double width=Math.log(Math.pow(quads.size(),2-Math.log(i+1))+1)/14; - if(coords[3]==0) - { - - if(quads.containsKey(i+1)) - { - - drawVertex(xWorld+coords[0]+.5, yWorld+coords[1]-width/2 , zWorld+coords[2]); - drawVertex(xWorld+coords[0]+.5 , yWorld+coords[1]+width/2 , zWorld+coords[2]); - - - - } - else - { - drawVertex(xWorld+coords[0]+.5, yWorld+coords[1]-width/200 , zWorld+coords[2]); - drawVertex(xWorld+coords[0]+.5 , yWorld+coords[1]+width/200 , zWorld+coords[2]); - } - } - else - { - - - - if(quads.containsKey(i+1)) - { - drawVertex(xWorld+coords[0], yWorld+coords[1]-width/2 , zWorld+coords[2]+.5); - drawVertex(xWorld+coords[0], yWorld+coords[1]+width/2 , zWorld+coords[2]+.5); - - - } - else - { - drawVertex(xWorld+coords[0], yWorld+coords[1]+width/200 , zWorld+coords[2]+.5); - drawVertex(xWorld+coords[0], yWorld+coords[1]-width/200, zWorld+coords[2]+.5); - } + // calculate the midpoint of the fractal bounding box + double offsetX = ((poly.maxX + poly.minX)) / 2; + double offsetY = ((poly.maxY + poly.minY)) / 2; + double offsetZ = 0; - - } - - } + // changes how far the triangles move + float motionMagnitude = 3.0F; - - GL11.glEnd(); - - - } - - public void drawCrackRotated(HashMap quads,double xWorld,double yWorld,double zWorld) - { - GL11.glBegin(GL11.GL_QUAD_STRIP); + // changes how quickly the triangles move + float motionSpeed = 2000.0F; - drawVertex(xWorld+.5, yWorld+Math.log(Math.pow(quads.size(),2)+1)/14, zWorld+.5); - drawVertex(xWorld+.5, yWorld-Math.log(Math.pow(quads.size(),2)+1)/14, zWorld+.5); - for(int i = 0;;i++) - { - if(!quads.containsKey(i)) - { - break; - } - double[] coords = quads.get(i); - double width=Math.log(Math.pow(quads.size(),2-Math.log(i+1))+1)/14; - if(coords[3]==0) - { - - - if(quads.containsKey(i+1)) - { - drawVertex(xWorld+coords[0]+.5, yWorld-(coords[1]-width/2) , zWorld-coords[2]+1); - drawVertex(xWorld+coords[0]+.5 , yWorld-(coords[1]+width/2) , zWorld-coords[2]+1); - - } - else - { - - drawVertex(xWorld+coords[0]+.5, yWorld-(coords[1]-width/200) , zWorld-coords[2]+1); - drawVertex(xWorld+coords[0]+.5 , yWorld-(coords[1]+width/200) , zWorld-coords[2]+1); - } + // number of individual jitter waveforms to generate + // changes how "together" the overall motions are + int jCount = 5; - } - else - { - - - if(quads.containsKey(i+1)) - { - - drawVertex(xWorld-coords[0]+1, yWorld-(coords[1]-width/2) , zWorld+coords[2]+.5); - drawVertex(xWorld-coords[0]+1, yWorld-(coords[1]+width/2) , zWorld+coords[2]+.5); - - } - else - { - drawVertex(xWorld-coords[0]+1, yWorld-(coords[1]+width/200) , zWorld+coords[2]+.5); - drawVertex(xWorld-coords[0]+1, yWorld-(coords[1]-width/200), zWorld+coords[2]+.5); - } - - } - } + // Calculate jitter like for monoliths + float time = (float) (((Minecraft.getSystemTime() + 0xF1234568 * this.hashCode()) % 2000000) / motionSpeed); + double[] jitters = new double[jCount]; - GL11.glEnd(); - } - - public void testDraw(HashMap quads,double xWorld,double yWorld,double zWorld) - { - GL11.glBegin(GL11.GL_QUADS); - for(int i = 0;;i++) - { - - if(!quads.containsKey(i)) - { - break; - } - double[] coords = quads.get(i); - drawVertex(xWorld-coords[0], yWorld , zWorld+.1); - drawVertex(xWorld-coords[0], yWorld+.1 , zWorld+.1); - drawVertex(xWorld-coords[0], yWorld +.1, zWorld); - drawVertex(xWorld-coords[0], yWorld , zWorld); - - - } - GL11.glEnd(); - - } - public void drawVertex(double x, double y, double z) - { - GL11.glVertex3f((float)x,(float)y,(float)z); - } - public double[] rotateCoords(int rotation, double[] coords) - { - double[] rotatedCoords = new double[4]; - if(rotation == 180) + // generate a series of waveforms + for (int i = 0; i < jCount - 1; i += 1) { + jitters[i] = Math.sin((1F + i / 10F) * time) * Math.cos(1F - (i / 10F) * time) / motionMagnitude; + jitters[i + 1] = Math.cos((1F + i / 10F) * time) * Math.sin(1F - (i / 10F) * time) / motionMagnitude; - - rotatedCoords[0]=-coords[0]; - rotatedCoords[1]=-coords[1]; - - rotatedCoords[2]=-coords[2]; - rotatedCoords[3]=-coords[3]; - //return rotatedCoords; } - return coords; - + + // determines which jitter waveform we select. Modulo so the same point + // gets the same jitter waveform over multiple frames + int jIndex = 0; + // set the color for the render + GL11.glColor4f(.1F, .1F, .1F, 1F); + + // set the blending mode + GL11.glEnable(GL_BLEND); + glBlendFunc(GL_ONE_MINUS_SRC_COLOR, GL_ONE); + GL11.glBegin(GL11.GL_TRIANGLES); + for (Point p : poly.points) + { + jIndex = Math.abs(((p.x + p.y) * (p.x + p.y + 1) / 2) + p.y); + // jIndex++; + // calculate the rotation for the fractal, apply offset, and apply + // jitter + double x = (((p.x + jitters[(jIndex + 1) % jCount]) - offsetX) * Math.cos(Math.toRadians(riftRotation)) - (jitters[(jIndex + 2) % jCount]) + * Math.sin(Math.toRadians(riftRotation))); + double y = p.y + (jitters[jIndex % jCount]) - offsetY; + double z = (((p.x + jitters[(jIndex + 2) % jCount]) - offsetX) * Math.sin(Math.toRadians(riftRotation)) + (jitters[(jIndex + 2) % jCount]) + * Math.cos(Math.toRadians(riftRotation))); + + // apply scaling + x *= scale; + y *= scale; + z *= scale; + + // apply transform to center the offset origin into the middle of a + // block + x += .5; + y += .5; + z += .5; + + // draw the vertex and apply the world (screenspace) relative + // coordinates + GL11.glVertex3d(xWorld + x, yWorld + y, zWorld + z); + } + GL11.glEnd(); + + GL11.glColor4f(.3F, .3F, .3F, .2F); + + glBlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ZERO); + + // draw the next set of triangles to form a background and change their + // color slightly over time + GL11.glBegin(GL11.GL_TRIANGLES); + for (Point p : poly.points) + { + jIndex++; + + double x = (((p.x) - offsetX) * Math.cos(Math.toRadians(riftRotation)) - 0 * Math.sin(Math.toRadians(riftRotation))); + double y = p.y - offsetY; + double z = (((p.x) - offsetX) * Math.sin(Math.toRadians(riftRotation)) + 0 * Math.cos(Math.toRadians(riftRotation))); + + x *= scale; + y *= scale; + z *= scale; + + x += .5; + y += .5; + z += .5; + + if (jIndex % 3 == 0) + { + // GL11.glColor4d(1-jitters[(jIndex + 5) % jCount] / 11,1- + // jitters[(jIndex + 4) % jCount] / 8, 1-jitters[(jIndex+3) % + // jCount] / 8, 1); + } + GL11.glVertex3d(xWorld + x, yWorld + y, zWorld + z); + } + + // stop drawing triangles + GL11.glEnd(); + } } \ 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 dc65e57..98f8e88 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; @@ -11,9 +12,9 @@ import net.minecraft.util.ResourceLocation; import org.lwjgl.opengl.GL11; -import StevenDimDoors.mod_pocketDim.DDProperties; import StevenDimDoors.mod_pocketDim.mod_pocketDim; import StevenDimDoors.mod_pocketDim.blocks.TransTrapdoor; +import StevenDimDoors.mod_pocketDim.config.DDProperties; import StevenDimDoors.mod_pocketDim.tileentities.TileEntityTransTrapdoor; import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; @@ -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) { diff --git a/src/main/java/StevenDimDoors/mod_pocketDimClient/RiftFX.java b/src/main/java/StevenDimDoors/mod_pocketDimClient/RiftFX.java index 7f4dc94..f564180 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDimClient/RiftFX.java +++ b/src/main/java/StevenDimDoors/mod_pocketDimClient/RiftFX.java @@ -111,7 +111,7 @@ public class RiftFX extends EntityFX float f13 = (float)(this.prevPosZ + (this.posZ - this.prevPosZ) * par2 - interpPosZ); float f14 = 0F; - if (PocketManager.getDimensionData(worldObj).isPocketDimension()) + if (PocketManager.createDimensionData(worldObj).isPocketDimension()) { f14 = 0.7F; } diff --git a/src/main/java/StevenDimDoors/mod_pocketDimClient/TESyncHandler.java b/src/main/java/StevenDimDoors/mod_pocketDimClient/TESyncHandler.java new file mode 100644 index 0000000..5e7f465 --- /dev/null +++ b/src/main/java/StevenDimDoors/mod_pocketDimClient/TESyncHandler.java @@ -0,0 +1,25 @@ +package StevenDimDoors.mod_pocketDimClient; + +public class TESyncHandler +{ + public void onServerChanges() + { + + } + + public void onClientChanges() + { + + } + + public void onClientData() + { + + } + + public void onServerData() + { + + } + +} diff --git a/src/main/java/org/poly2tri/Poly2Tri.java b/src/main/java/org/poly2tri/Poly2Tri.java new file mode 100644 index 0000000..ec9f422 --- /dev/null +++ b/src/main/java/org/poly2tri/Poly2Tri.java @@ -0,0 +1,124 @@ +/* Poly2Tri + * Copyright (c) 2009-2010, Poly2Tri Contributors + * http://code.google.com/p/poly2tri/ + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of Poly2Tri nor the names of its contributors may be + * used to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.poly2tri; + +import org.poly2tri.geometry.polygon.Polygon; +import org.poly2tri.geometry.polygon.PolygonSet; +import org.poly2tri.triangulation.Triangulatable; +import org.poly2tri.triangulation.TriangulationAlgorithm; +import org.poly2tri.triangulation.TriangulationContext; +import org.poly2tri.triangulation.TriangulationMode; +import org.poly2tri.triangulation.TriangulationProcess; +import org.poly2tri.triangulation.delaunay.sweep.DTSweep; +import org.poly2tri.triangulation.delaunay.sweep.DTSweepContext; +import org.poly2tri.triangulation.sets.ConstrainedPointSet; +import org.poly2tri.triangulation.sets.PointSet; +import org.poly2tri.triangulation.util.PolygonGenerator; + +public class Poly2Tri +{ + + private static final TriangulationAlgorithm _defaultAlgorithm = TriangulationAlgorithm.DTSweep; + + public static void triangulate( PolygonSet ps ) + { + TriangulationContext tcx = createContext( _defaultAlgorithm ); + for( Polygon p : ps.getPolygons() ) + { + tcx.prepareTriangulation( p ); + triangulate( tcx ); + tcx.clear(); + } + } + + public static void triangulate( Polygon p ) + { + triangulate( _defaultAlgorithm, p ); + } + + public static void triangulate( ConstrainedPointSet cps ) + { + triangulate( _defaultAlgorithm, cps ); + } + + public static void triangulate( PointSet ps ) + { + triangulate( _defaultAlgorithm, ps ); + } + + public static TriangulationContext createContext( TriangulationAlgorithm algorithm ) + { + switch( algorithm ) + { + case DTSweep: + default: + return new DTSweepContext(); + } + } + + public static void triangulate( TriangulationAlgorithm algorithm, + Triangulatable t ) + { + TriangulationContext tcx; + +// long time = System.nanoTime(); + tcx = createContext( algorithm ); + tcx.prepareTriangulation( t ); + triangulate( tcx ); +// logger.info( "Triangulation of {} points [{}ms]", tcx.getPoints().size(), ( System.nanoTime() - time ) / 1e6 ); + } + + public static void triangulate( TriangulationContext tcx ) + { + switch( tcx.algorithm() ) + { + case DTSweep: + default: + DTSweep.triangulate( (DTSweepContext)tcx ); + } + } + + /** + * Will do a warmup run to let the JVM optimize the triangulation code + */ + public static void warmup() + { + /* + * After a method is run 10000 times, the Hotspot compiler will compile + * it into native code. Periodically, the Hotspot compiler may recompile + * the method. After an unspecified amount of time, then the compilation + * system should become quiet. + */ + Polygon poly = PolygonGenerator.RandomCircleSweep2( 50, 50000 ); + TriangulationProcess process = new TriangulationProcess(); + process.triangulate( poly ); + } +} diff --git a/src/main/java/org/poly2tri/geometry/polygon/Polygon.java b/src/main/java/org/poly2tri/geometry/polygon/Polygon.java new file mode 100644 index 0000000..e972033 --- /dev/null +++ b/src/main/java/org/poly2tri/geometry/polygon/Polygon.java @@ -0,0 +1,269 @@ +package org.poly2tri.geometry.polygon; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.poly2tri.triangulation.Triangulatable; +import org.poly2tri.triangulation.TriangulationContext; +import org.poly2tri.triangulation.TriangulationMode; +import org.poly2tri.triangulation.TriangulationPoint; +import org.poly2tri.triangulation.delaunay.DelaunayTriangle; + +public class Polygon implements Triangulatable +{ + + protected ArrayList _points = new ArrayList(); + protected ArrayList _steinerPoints; + protected ArrayList _holes; + + protected List m_triangles; + + protected PolygonPoint _last; + + /** + * To create a polygon we need atleast 3 separate points + * + * @param p1 + * @param p2 + * @param p3 + */ + public Polygon( PolygonPoint p1, PolygonPoint p2, PolygonPoint p3 ) + { + p1._next = p2; + p2._next = p3; + p3._next = p1; + p1._previous = p3; + p2._previous = p1; + p3._previous = p2; + _points.add( p1 ); + _points.add( p2 ); + _points.add( p3 ); + } + + /** + * Requires atleast 3 points + * @param points - ordered list of points forming the polygon. + * No duplicates are allowed + */ + public Polygon( List points ) + { + // Lets do one sanity check that first and last point hasn't got same position + // Its something that often happen when importing polygon data from other formats + if( points.get(0).equals( points.get(points.size()-1) ) ) + { + points.remove( points.size()-1 ); + } + _points.addAll( points ); + } + + /** + * Requires atleast 3 points + * + * @param points + */ + public Polygon( PolygonPoint[] points ) + { + this( Arrays.asList( points ) ); + } + + public TriangulationMode getTriangulationMode() + { + return TriangulationMode.POLYGON; + } + + public int pointCount() + { + int count = _points.size(); + if( _steinerPoints != null ) + { + count += _steinerPoints.size(); + } + return count; + } + + public void addSteinerPoint( TriangulationPoint point ) + { + if( _steinerPoints == null ) + { + _steinerPoints = new ArrayList(); + } + _steinerPoints.add( point ); + } + + public void addSteinerPoints( List points ) + { + if( _steinerPoints == null ) + { + _steinerPoints = new ArrayList(); + } + _steinerPoints.addAll( points ); + } + + public void clearSteinerPoints() + { + if( _steinerPoints != null ) + { + _steinerPoints.clear(); + } + } + + /** + * Assumes: that given polygon is fully inside the current polygon + * @param poly - a subtraction polygon + */ + public void addHole( Polygon poly ) + { + if( _holes == null ) + { + _holes = new ArrayList(); + } + _holes.add( poly ); + // XXX: tests could be made here to be sure it is fully inside +// addSubtraction( poly.getPoints() ); + } + + /** + * Will insert a point in the polygon after given point + * + * @param a + * @param b + * @param p + */ + public void insertPointAfter( PolygonPoint a, PolygonPoint newPoint ) + { + // Validate that + int index = _points.indexOf( a ); + if( index != -1 ) + { + newPoint.setNext( a.getNext() ); + newPoint.setPrevious( a ); + a.getNext().setPrevious( newPoint ); + a.setNext( newPoint ); + _points.add( index+1, newPoint ); + } + else + { + throw new RuntimeException( "Tried to insert a point into a Polygon after a point not belonging to the Polygon" ); + } + } + + public void addPoints( List list ) + { + PolygonPoint first; + for( PolygonPoint p : list ) + { + p.setPrevious( _last ); + if( _last != null ) + { + p.setNext( _last.getNext() ); + _last.setNext( p ); + } + _last = p; + _points.add( p ); + } + first = (PolygonPoint)_points.get(0); + _last.setNext( first ); + first.setPrevious( _last ); + } + + /** + * Will add a point after the last point added + * + * @param p + */ + public void addPoint(PolygonPoint p ) + { + p.setPrevious( _last ); + p.setNext( _last.getNext() ); + _last.setNext( p ); + _points.add( p ); + } + + public void removePoint( PolygonPoint p ) + { + PolygonPoint next, prev; + + next = p.getNext(); + prev = p.getPrevious(); + prev.setNext( next ); + next.setPrevious( prev ); + _points.remove( p ); + } + + public PolygonPoint getPoint() + { + return _last; + } + + public List getPoints() + { + return _points; + } + + public List getTriangles() + { + return m_triangles; + } + + public void addTriangle( DelaunayTriangle t ) + { + m_triangles.add( t ); + } + + public void addTriangles( List list ) + { + m_triangles.addAll( list ); + } + + public void clearTriangulation() + { + if( m_triangles != null ) + { + m_triangles.clear(); + } + } + + /** + * Creates constraints and populates the context with points + */ + public void prepareTriangulation( TriangulationContext tcx ) + { + if( m_triangles == null ) + { + m_triangles = new ArrayList( _points.size() ); + } + else + { + m_triangles.clear(); + } + + // Outer constraints + for( int i = 0; i < _points.size()-1 ; i++ ) + { + tcx.newConstraint( _points.get( i ), _points.get( i+1 ) ); + } + tcx.newConstraint( _points.get( 0 ), _points.get( _points.size()-1 ) ); + tcx.addPoints( _points ); + + // Hole constraints + if( _holes != null ) + { + for( Polygon p : _holes ) + { + for( int i = 0; i < p._points.size()-1 ; i++ ) + { + tcx.newConstraint( p._points.get( i ), p._points.get( i+1 ) ); + } + tcx.newConstraint( p._points.get( 0 ), p._points.get( p._points.size()-1 ) ); + tcx.addPoints( p._points ); + } + } + + if( _steinerPoints != null ) + { + tcx.addPoints( _steinerPoints ); + } + } + +} diff --git a/src/main/java/org/poly2tri/geometry/polygon/PolygonPoint.java b/src/main/java/org/poly2tri/geometry/polygon/PolygonPoint.java new file mode 100644 index 0000000..a0e3cf1 --- /dev/null +++ b/src/main/java/org/poly2tri/geometry/polygon/PolygonPoint.java @@ -0,0 +1,39 @@ +package org.poly2tri.geometry.polygon; + +import org.poly2tri.triangulation.point.TPoint; + +public class PolygonPoint extends TPoint +{ + protected PolygonPoint _next; + protected PolygonPoint _previous; + + public PolygonPoint( double x, double y ) + { + super( x, y ); + } + + public PolygonPoint( double x, double y, double z ) + { + super( x, y, z ); + } + + public void setPrevious( PolygonPoint p ) + { + _previous = p; + } + + public void setNext( PolygonPoint p ) + { + _next = p; + } + + public PolygonPoint getNext() + { + return _next; + } + + public PolygonPoint getPrevious() + { + return _previous; + } +} diff --git a/src/main/java/org/poly2tri/geometry/polygon/PolygonSet.java b/src/main/java/org/poly2tri/geometry/polygon/PolygonSet.java new file mode 100644 index 0000000..d7e33bb --- /dev/null +++ b/src/main/java/org/poly2tri/geometry/polygon/PolygonSet.java @@ -0,0 +1,58 @@ +/* Poly2Tri + * Copyright (c) 2009-2010, Poly2Tri Contributors + * http://code.google.com/p/poly2tri/ + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of Poly2Tri nor the names of its contributors may be + * used to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.poly2tri.geometry.polygon; + +import java.util.ArrayList; +import java.util.List; + +public class PolygonSet +{ + protected ArrayList _polygons = new ArrayList(); + + public PolygonSet() + { + } + + public PolygonSet( Polygon poly ) + { + _polygons.add( poly ); + } + + public void add( Polygon p ) + { + _polygons.add( p ); + } + + public List getPolygons() + { + return _polygons; + } +} diff --git a/src/main/java/org/poly2tri/geometry/polygon/PolygonUtil.java b/src/main/java/org/poly2tri/geometry/polygon/PolygonUtil.java new file mode 100644 index 0000000..3ca71de --- /dev/null +++ b/src/main/java/org/poly2tri/geometry/polygon/PolygonUtil.java @@ -0,0 +1,15 @@ +package org.poly2tri.geometry.polygon; + +public class PolygonUtil +{ + /** + * TODO + * @param polygon + */ + public static void validate( Polygon polygon ) + { + // TODO: implement + // 1. Check for duplicate points + // 2. Check for intersecting sides + } +} diff --git a/src/main/java/org/poly2tri/geometry/primitives/Edge.java b/src/main/java/org/poly2tri/geometry/primitives/Edge.java new file mode 100644 index 0000000..49b00b6 --- /dev/null +++ b/src/main/java/org/poly2tri/geometry/primitives/Edge.java @@ -0,0 +1,17 @@ +package org.poly2tri.geometry.primitives; + +public abstract class Edge +{ + protected A p; + protected A q; + + public A getP() + { + return p; + } + + public A getQ() + { + return q; + } +} diff --git a/src/main/java/org/poly2tri/geometry/primitives/Point.java b/src/main/java/org/poly2tri/geometry/primitives/Point.java new file mode 100644 index 0000000..680c141 --- /dev/null +++ b/src/main/java/org/poly2tri/geometry/primitives/Point.java @@ -0,0 +1,31 @@ +package org.poly2tri.geometry.primitives; + +public abstract class Point +{ + public abstract double getX(); + public abstract double getY(); + public abstract double getZ(); + + public abstract float getXf(); + public abstract float getYf(); + public abstract float getZf(); + + public abstract void set( double x, double y, double z ); + + protected static int calculateHashCode( double x, double y, double z) + { + int result = 17; + + final long a = Double.doubleToLongBits(x); + result += 31 * result + (int) (a ^ (a >>> 32)); + + final long b = Double.doubleToLongBits(y); + result += 31 * result + (int) (b ^ (b >>> 32)); + + final long c = Double.doubleToLongBits(z); + result += 31 * result + (int) (c ^ (c >>> 32)); + + return result; + + } +} diff --git a/src/main/java/org/poly2tri/transform/coordinate/AnyToXYTransform.java b/src/main/java/org/poly2tri/transform/coordinate/AnyToXYTransform.java new file mode 100644 index 0000000..97026a5 --- /dev/null +++ b/src/main/java/org/poly2tri/transform/coordinate/AnyToXYTransform.java @@ -0,0 +1,71 @@ +package org.poly2tri.transform.coordinate; + +/** + * A transform that aligns given source normal with the XY plane normal [0,0,1] + * + * @author thahlen@gmail.com + */ + +public class AnyToXYTransform extends Matrix3Transform +{ + /** + * Assumes source normal is normalized + */ + public AnyToXYTransform( double nx, double ny, double nz ) + { + setSourceNormal( nx, ny, nz ); + } + + /** + * Assumes source normal is normalized + * + * @param nx + * @param ny + * @param nz + */ + public void setSourceNormal( double nx, double ny, double nz ) + { + double h,f,c,vx,vy,hvx; + + vx = -ny; + vy = nx; + c = nz; + + h = (1-c)/(1-c*c); + hvx = h*vx; + f = (c < 0) ? -c : c; + + if( f < 1.0 - 1.0E-4 ) + { + m00=c + hvx*vx; + m01=hvx*vy; + m02=-vy; + m10=hvx*vy; + m11=c + h*vy*vy; + m12=vx; + m20=vy; + m21=-vx; + m22=c; + } + else + { + // if "from" and "to" vectors are nearly parallel + m00=1; + m01=0; + m02=0; + m10=0; + m11=1; + m12=0; + m20=0; + m21=0; + if( c > 0 ) + { + m22=1; + } + else + { + m22=-1; + } + } + } +} diff --git a/src/main/java/org/poly2tri/transform/coordinate/CoordinateTransform.java b/src/main/java/org/poly2tri/transform/coordinate/CoordinateTransform.java new file mode 100644 index 0000000..f00cb1c --- /dev/null +++ b/src/main/java/org/poly2tri/transform/coordinate/CoordinateTransform.java @@ -0,0 +1,12 @@ +package org.poly2tri.transform.coordinate; + +import java.util.List; + +import org.poly2tri.geometry.primitives.Point; + +public abstract interface CoordinateTransform +{ + public abstract void transform( Point p, Point store ); + public abstract void transform( Point p ); + public abstract void transform( List list ); +} diff --git a/src/main/java/org/poly2tri/transform/coordinate/Matrix3Transform.java b/src/main/java/org/poly2tri/transform/coordinate/Matrix3Transform.java new file mode 100644 index 0000000..f8422bc --- /dev/null +++ b/src/main/java/org/poly2tri/transform/coordinate/Matrix3Transform.java @@ -0,0 +1,38 @@ +package org.poly2tri.transform.coordinate; + +import java.util.List; + +import org.poly2tri.geometry.primitives.Point; + +public abstract class Matrix3Transform implements CoordinateTransform +{ + protected double m00,m01,m02,m10,m11,m12,m20,m21,m22; + + public void transform( Point p, Point store ) + { + final double px = p.getX(); + final double py = p.getY(); + final double pz = p.getZ(); + store.set(m00 * px + m01 * py + m02 * pz, + m10 * px + m11 * py + m12 * pz, + m20 * px + m21 * py + m22 * pz ); + } + + public void transform( Point p ) + { + final double px = p.getX(); + final double py = p.getY(); + final double pz = p.getZ(); + p.set(m00 * px + m01 * py + m02 * pz, + m10 * px + m11 * py + m12 * pz, + m20 * px + m21 * py + m22 * pz ); + } + + public void transform( List list ) + { + for( Point p : list ) + { + transform( p ); + } + } +} diff --git a/src/main/java/org/poly2tri/transform/coordinate/NoTransform.java b/src/main/java/org/poly2tri/transform/coordinate/NoTransform.java new file mode 100644 index 0000000..2f43cbc --- /dev/null +++ b/src/main/java/org/poly2tri/transform/coordinate/NoTransform.java @@ -0,0 +1,21 @@ +package org.poly2tri.transform.coordinate; + +import java.util.List; + +import org.poly2tri.geometry.primitives.Point; + +public class NoTransform implements CoordinateTransform +{ + public void transform( Point p, Point store ) + { + store.set( p.getX(), p.getY(), p.getZ() ); + } + + public void transform( Point p ) + { + } + + public void transform( List list ) + { + } +} diff --git a/src/main/java/org/poly2tri/transform/coordinate/XYToAnyTransform.java b/src/main/java/org/poly2tri/transform/coordinate/XYToAnyTransform.java new file mode 100644 index 0000000..6c0a30f --- /dev/null +++ b/src/main/java/org/poly2tri/transform/coordinate/XYToAnyTransform.java @@ -0,0 +1,74 @@ +package org.poly2tri.transform.coordinate; + +/** + * A transform that aligns the XY plane normal [0,0,1] with any given target normal + * + * http://www.cs.brown.edu/~jfh/papers/Moller-EBA-1999/paper.pdf + * + * @author thahlen@gmail.com + * + */ +public class XYToAnyTransform extends Matrix3Transform +{ + /** + * Assumes target normal is normalized + */ + public XYToAnyTransform( double nx, double ny, double nz ) + { + setTargetNormal( nx, ny, nz ); + } + + /** + * Assumes target normal is normalized + * + * @param nx + * @param ny + * @param nz + */ + public void setTargetNormal( double nx, double ny, double nz ) + { + double h,f,c,vx,vy,hvx; + + vx = ny; + vy = -nx; + c = nz; + + h = (1-c)/(1-c*c); + hvx = h*vx; + f = (c < 0) ? -c : c; + + if( f < 1.0 - 1.0E-4 ) + { + m00=c + hvx*vx; + m01=hvx*vy; + m02=-vy; + m10=hvx*vy; + m11=c + h*vy*vy; + m12=vx; + m20=vy; + m21=-vx; + m22=c; + } + else + { + // if "from" and "to" vectors are nearly parallel + m00=1; + m01=0; + m02=0; + m10=0; + m11=1; + m12=0; + m20=0; + m21=0; + if( c > 0 ) + { + m22=1; + } + else + { + m22=-1; + } + } + + } +} diff --git a/src/main/java/org/poly2tri/triangulation/Triangulatable.java b/src/main/java/org/poly2tri/triangulation/Triangulatable.java new file mode 100644 index 0000000..dddc620 --- /dev/null +++ b/src/main/java/org/poly2tri/triangulation/Triangulatable.java @@ -0,0 +1,22 @@ +package org.poly2tri.triangulation; + +import java.util.List; + +import org.poly2tri.triangulation.delaunay.DelaunayTriangle; + +public interface Triangulatable +{ + /** + * Preparations needed before triangulation start should be handled here + * @param tcx + */ + public void prepareTriangulation( TriangulationContext tcx ); + + public List getTriangles(); + public List getPoints(); + public void addTriangle( DelaunayTriangle t ); + public void addTriangles( List list ); + public void clearTriangulation(); + + public TriangulationMode getTriangulationMode(); +} diff --git a/src/main/java/org/poly2tri/triangulation/TriangulationAlgorithm.java b/src/main/java/org/poly2tri/triangulation/TriangulationAlgorithm.java new file mode 100644 index 0000000..497aada --- /dev/null +++ b/src/main/java/org/poly2tri/triangulation/TriangulationAlgorithm.java @@ -0,0 +1,36 @@ +/* Poly2Tri + * Copyright (c) 2009-2010, Poly2Tri Contributors + * http://code.google.com/p/poly2tri/ + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of Poly2Tri nor the names of its contributors may be + * used to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.poly2tri.triangulation; + +public enum TriangulationAlgorithm +{ + DTSweep +} diff --git a/src/main/java/org/poly2tri/triangulation/TriangulationConstraint.java b/src/main/java/org/poly2tri/triangulation/TriangulationConstraint.java new file mode 100644 index 0000000..0e3f0d2 --- /dev/null +++ b/src/main/java/org/poly2tri/triangulation/TriangulationConstraint.java @@ -0,0 +1,55 @@ +/* Poly2Tri + * Copyright (c) 2009-2010, Poly2Tri Contributors + * http://code.google.com/p/poly2tri/ + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of Poly2Tri nor the names of its contributors may be + * used to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.poly2tri.triangulation; + +/** + * Forces a triangle edge between two points p and q + * when triangulating. For example used to enforce + * Polygon Edges during a polygon triangulation. + * + * @author Thomas Åhlén, thahlen@gmail.com + */ +public class TriangulationConstraint +{ + protected TriangulationPoint p; + protected TriangulationPoint q; + + public TriangulationPoint getP() + { + return p; + } + + public TriangulationPoint getQ() + { + return q; + } + +} diff --git a/src/main/java/org/poly2tri/triangulation/TriangulationContext.java b/src/main/java/org/poly2tri/triangulation/TriangulationContext.java new file mode 100644 index 0000000..71b26bc --- /dev/null +++ b/src/main/java/org/poly2tri/triangulation/TriangulationContext.java @@ -0,0 +1,171 @@ +/* Poly2Tri + * Copyright (c) 2009-2010, Poly2Tri Contributors + * http://code.google.com/p/poly2tri/ + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of Poly2Tri nor the names of its contributors may be + * used to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.poly2tri.triangulation; + +import java.util.ArrayList; +import java.util.List; + +import org.poly2tri.triangulation.delaunay.DelaunayTriangle; + +public abstract class TriangulationContext +{ + protected A _debug; + protected boolean _debugEnabled = false; + + protected ArrayList _triList = new ArrayList(); + + protected ArrayList _points = new ArrayList(200); + protected TriangulationMode _triangulationMode; + protected Triangulatable _triUnit; + + private boolean _terminated = false; + private boolean _waitUntilNotified; + + private int _stepTime = -1; + private int _stepCount = 0; + public int getStepCount() { return _stepCount; } + + public void done() + { + _stepCount++; + } + + public abstract TriangulationAlgorithm algorithm(); + + public void prepareTriangulation( Triangulatable t ) + { + _triUnit = t; + _triangulationMode = t.getTriangulationMode(); + t.prepareTriangulation( this ); + } + + public abstract TriangulationConstraint newConstraint( TriangulationPoint a, TriangulationPoint b ); + + public void addToList( DelaunayTriangle triangle ) + { + _triList.add( triangle ); + } + + public List getTriangles() + { + return _triList; + } + + public Triangulatable getTriangulatable() + { + return _triUnit; + } + + public List getPoints() + { + return _points; + } + + public synchronized void update(String message) + { + if( _debugEnabled ) + { + try + { + synchronized( this ) + { + _stepCount++; + if( _stepTime > 0 ) + { + wait( (int)_stepTime ); + /** Can we resume execution or are we expected to wait? */ + if( _waitUntilNotified ) + { + wait(); + } + } + else + { + wait(); + } + // We have been notified + _waitUntilNotified = false; + } + } + catch( InterruptedException e ) + { + update("Triangulation was interrupted"); + } + } + if( _terminated ) + { + throw new RuntimeException( "Triangulation process terminated before completion"); + } + } + + public void clear() + { + _points.clear(); + _terminated = false; + if( _debug != null ) + { + _debug.clear(); + } + _stepCount=0; + } + + public TriangulationMode getTriangulationMode() + { + return _triangulationMode; + } + + public synchronized void waitUntilNotified(boolean b) + { + _waitUntilNotified = b; + } + + public void terminateTriangulation() + { + _terminated=true; + } + + public boolean isDebugEnabled() + { + return _debugEnabled; + } + + public abstract void isDebugEnabled( boolean b ); + + public A getDebugContext() + { + return _debug; + } + + public void addPoints( List points ) + { + _points.addAll( points ); + } +} diff --git a/src/main/java/org/poly2tri/triangulation/TriangulationDebugContext.java b/src/main/java/org/poly2tri/triangulation/TriangulationDebugContext.java new file mode 100644 index 0000000..a6eca87 --- /dev/null +++ b/src/main/java/org/poly2tri/triangulation/TriangulationDebugContext.java @@ -0,0 +1,13 @@ +package org.poly2tri.triangulation; + +public abstract class TriangulationDebugContext +{ + protected TriangulationContext _tcx; + + public TriangulationDebugContext( TriangulationContext tcx ) + { + _tcx = tcx; + } + + public abstract void clear(); +} diff --git a/src/main/java/org/poly2tri/triangulation/TriangulationMode.java b/src/main/java/org/poly2tri/triangulation/TriangulationMode.java new file mode 100644 index 0000000..946862d --- /dev/null +++ b/src/main/java/org/poly2tri/triangulation/TriangulationMode.java @@ -0,0 +1,6 @@ +package org.poly2tri.triangulation; + +public enum TriangulationMode +{ + UNCONSTRAINED,CONSTRAINED,POLYGON; +} diff --git a/src/main/java/org/poly2tri/triangulation/TriangulationPoint.java b/src/main/java/org/poly2tri/triangulation/TriangulationPoint.java new file mode 100644 index 0000000..37686a5 --- /dev/null +++ b/src/main/java/org/poly2tri/triangulation/TriangulationPoint.java @@ -0,0 +1,112 @@ +/* Poly2Tri + * Copyright (c) 2009-2010, Poly2Tri Contributors + * http://code.google.com/p/poly2tri/ + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of Poly2Tri nor the names of its contributors may be + * used to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.poly2tri.triangulation; + +import java.util.ArrayList; + +import org.poly2tri.geometry.primitives.Point; +import org.poly2tri.triangulation.delaunay.sweep.DTSweepConstraint; + + +public abstract class TriangulationPoint extends Point +{ + // List of edges this point constitutes an upper ending point (CDT) + private ArrayList edges; + + @Override + public String toString() + { + return "[" + getX() + "," + getY() + "]"; + } + + public abstract double getX(); + public abstract double getY(); + public abstract double getZ(); + + public abstract float getXf(); + public abstract float getYf(); + public abstract float getZf(); + + public abstract void set( double x, double y, double z ); + + public ArrayList getEdges() + { + return edges; + } + + public void addEdge( DTSweepConstraint e ) + { + if( edges == null ) + { + edges = new ArrayList(); + } + edges.add( e ); + } + + public boolean hasEdges() + { + return edges != null; + } + + /** + * @param p - edge destination point + * @return the edge from this point to given point + */ + public DTSweepConstraint getEdge( TriangulationPoint p ) + { + for( DTSweepConstraint c : edges ) + { + if( c.p == p ) + { + return c; + } + } + return null; + } + + public boolean equals(Object obj) + { + if( obj instanceof TriangulationPoint ) + { + TriangulationPoint p = (TriangulationPoint)obj; + return getX() == p.getX() && getY() == p.getY(); + } + return super.equals( obj ); + } + + public int hashCode() + { + long bits = java.lang.Double.doubleToLongBits(getX()); + bits ^= java.lang.Double.doubleToLongBits(getY()) * 31; + return (((int) bits) ^ ((int) (bits >> 32))); + } + +} diff --git a/src/main/java/org/poly2tri/triangulation/TriangulationProcess.java b/src/main/java/org/poly2tri/triangulation/TriangulationProcess.java new file mode 100644 index 0000000..35baf1f --- /dev/null +++ b/src/main/java/org/poly2tri/triangulation/TriangulationProcess.java @@ -0,0 +1,341 @@ +/* Poly2Tri + * Copyright (c) 2009-2010, Poly2Tri Contributors + * http://code.google.com/p/poly2tri/ + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of Poly2Tri nor the names of its contributors may be + * used to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.poly2tri.triangulation; + +import java.lang.Thread.State; +import java.util.ArrayList; +import java.util.List; + +import org.poly2tri.Poly2Tri; +import org.poly2tri.geometry.polygon.Polygon; +import org.poly2tri.geometry.polygon.PolygonSet; +import org.poly2tri.triangulation.sets.ConstrainedPointSet; +import org.poly2tri.triangulation.sets.PointSet; + + +/** + * + * @author Thomas Åhlén, thahlen@gmail.com + * + */ +public class TriangulationProcess implements Runnable +{ + + private final TriangulationAlgorithm _algorithm; + + private TriangulationContext _tcx; + private Thread _thread; + private boolean _isTerminated = false; + private int _pointCount = 0; + private long _timestamp = 0; + private double _triangulationTime = 0; + + private boolean _awaitingTermination; + private boolean _restart = false; + + private ArrayList _triangulations = new ArrayList(); + + private ArrayList _listeners = new ArrayList(); + + public void addListener( TriangulationProcessListener listener ) + { + _listeners.add( listener ); + } + + public void removeListener( TriangulationProcessListener listener ) + { + _listeners.remove( listener ); + } + + public void clearListeners() + { + _listeners.clear(); + } + + /** + * Notify all listeners of this new event + * @param event + */ + private void sendEvent( TriangulationProcessEvent event ) + { + for( TriangulationProcessListener l : _listeners ) + { + l.triangulationEvent( event, _tcx.getTriangulatable() ); + } + } + + public int getStepCount() + { + return _tcx.getStepCount(); + } + + public long getTimestamp() + { + return _timestamp; + } + + public double getTriangulationTime() + { + return _triangulationTime; + } + + /** + * Uses SweepLine algorithm by default + * @param algorithm + */ + public TriangulationProcess() + { + this( TriangulationAlgorithm.DTSweep ); + } + + public TriangulationProcess( TriangulationAlgorithm algorithm ) + { + _algorithm = algorithm; + _tcx = Poly2Tri.createContext( algorithm ); + } + + /** + * This retriangulates same set as previous triangulation + * useful if you want to do consecutive triangulations with + * same data. Like when you when you want to do performance + * tests. + */ +// public void triangulate() +// { +// start(); +// } + + /** + * Triangulate a PointSet with eventual constraints + * + * @param cps + */ + public void triangulate( PointSet ps ) + { + _triangulations.clear(); + _triangulations.add( ps ); + start(); + } + + /** + * Triangulate a PointSet with eventual constraints + * + * @param cps + */ + public void triangulate( ConstrainedPointSet cps ) + { + _triangulations.clear(); + _triangulations.add( cps ); + start(); + } + + /** + * Triangulate a PolygonSet + * + * @param ps + */ + public void triangulate( PolygonSet ps ) + { + _triangulations.clear(); + _triangulations.addAll( ps.getPolygons() ); + start(); + } + + /** + * Triangulate a Polygon + * + * @param ps + */ + public void triangulate( Polygon polygon ) + { + _triangulations.clear(); + _triangulations.add( polygon ); + start(); + } + + /** + * Triangulate a List of Triangulatables + * + * @param ps + */ + public void triangulate( List list ) + { + _triangulations.clear(); + _triangulations.addAll( list ); + start(); + } + + private void start() + { + if( _thread == null || _thread.getState() == State.TERMINATED ) + { + _isTerminated = false; + _thread = new Thread( this, _algorithm.name() + "." + _tcx.getTriangulationMode() ); + _thread.start(); + sendEvent( TriangulationProcessEvent.Started ); + } + else + { + // Triangulation already running. Terminate it so we can start a new + shutdown(); + _restart = true; + } + } + + public boolean isWaiting() + { + if( _thread != null && _thread.getState() == State.WAITING ) + { + return true; + } + return false; + } + + public void run() + { + _pointCount=0; + try + { + long time = System.nanoTime(); + for( Triangulatable t : _triangulations ) + { + _tcx.clear(); + _tcx.prepareTriangulation( t ); + _pointCount += _tcx._points.size(); + Poly2Tri.triangulate( _tcx ); + } + _triangulationTime = ( System.nanoTime() - time ) / 1e6; + sendEvent( TriangulationProcessEvent.Done ); + } + catch( RuntimeException e ) + { + if( _awaitingTermination ) + { + _awaitingTermination = false; + sendEvent( TriangulationProcessEvent.Aborted ); + } + else + { + e.printStackTrace(); + sendEvent( TriangulationProcessEvent.Failed ); + } + } + catch( Exception e ) + { + e.printStackTrace(); + sendEvent( TriangulationProcessEvent.Failed ); + } + finally + { + _timestamp = System.currentTimeMillis(); + _isTerminated = true; + _thread = null; + } + + // Autostart a new triangulation? + if( _restart ) + { + _restart = false; + start(); + } + } + + public void resume() + { + if( _thread != null ) + { + // Only force a resume when process is waiting for a notification + if( _thread.getState() == State.WAITING ) + { + synchronized( _tcx ) + { + _tcx.notify(); + } + } + else if( _thread.getState() == State.TIMED_WAITING ) + { + _tcx.waitUntilNotified( false ); + } + } + } + + public void shutdown() + { + _awaitingTermination = true; + _tcx.terminateTriangulation(); + resume(); + } + + public TriangulationContext getContext() + { + return _tcx; + } + + public boolean isDone() + { + return _isTerminated; + } + + public void requestRead() + { + _tcx.waitUntilNotified( true ); + } + + public boolean isReadable() + { + if( _thread == null ) + { + return true; + } + else + { + synchronized( _thread ) + { + if( _thread.getState() == State.WAITING ) + { + return true; + } + else if( _thread.getState() == State.TIMED_WAITING ) + { + // Make sure that it stays readable + _tcx.waitUntilNotified( true ); + return true; + } + return false; + } + } + } + + public int getPointCount() + { + return _pointCount; + } +} diff --git a/src/main/java/org/poly2tri/triangulation/TriangulationProcessEvent.java b/src/main/java/org/poly2tri/triangulation/TriangulationProcessEvent.java new file mode 100644 index 0000000..dce9e04 --- /dev/null +++ b/src/main/java/org/poly2tri/triangulation/TriangulationProcessEvent.java @@ -0,0 +1,36 @@ +/* Poly2Tri + * Copyright (c) 2009-2010, Poly2Tri Contributors + * http://code.google.com/p/poly2tri/ + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of Poly2Tri nor the names of its contributors may be + * used to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.poly2tri.triangulation; + +public enum TriangulationProcessEvent +{ + Started,Waiting,Failed,Aborted,Done +} diff --git a/src/main/java/org/poly2tri/triangulation/TriangulationProcessListener.java b/src/main/java/org/poly2tri/triangulation/TriangulationProcessListener.java new file mode 100644 index 0000000..922e3c9 --- /dev/null +++ b/src/main/java/org/poly2tri/triangulation/TriangulationProcessListener.java @@ -0,0 +1,36 @@ +/* Poly2Tri + * Copyright (c) 2009-2010, Poly2Tri Contributors + * http://code.google.com/p/poly2tri/ + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of Poly2Tri nor the names of its contributors may be + * used to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.poly2tri.triangulation; + +public interface TriangulationProcessListener +{ + public void triangulationEvent( TriangulationProcessEvent e, Triangulatable unit ); +} diff --git a/src/main/java/org/poly2tri/triangulation/TriangulationUtil.java b/src/main/java/org/poly2tri/triangulation/TriangulationUtil.java new file mode 100644 index 0000000..9da0328 --- /dev/null +++ b/src/main/java/org/poly2tri/triangulation/TriangulationUtil.java @@ -0,0 +1,213 @@ +/* Poly2Tri + * Copyright (c) 2009-2010, Poly2Tri Contributors + * http://code.google.com/p/poly2tri/ + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of Poly2Tri nor the names of its contributors may be + * used to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */package org.poly2tri.triangulation; + + +/** + * @author Thomas Åhlén, thahlen@gmail.com + */ +public class TriangulationUtil +{ + public final static double EPSILON = 1e-12; + + // Returns triangle circumcircle point and radius +// public static Tuple2 circumCircle( TPoint a, TPoint b, TPoint c ) +// { +// double A = det( a, b, c ); +// double C = detC( a, b, c ); +// +// double sa = a.getX() * a.getX() + a.getY() * a.getY(); +// double sb = b.getX() * b.getX() + b.getY() * b.getY(); +// double sc = c.getX() * c.getX() + c.getY() * c.getY(); +// +// TPoint bx1 = new TPoint( sa, a.getY() ); +// TPoint bx2 = new TPoint( sb, b.getY() ); +// TPoint bx3 = new TPoint( sc, c.getY() ); +// double bx = det( bx1, bx2, bx3 ); +// +// TPoint by1 = new TPoint( sa, a.getX() ); +// TPoint by2 = new TPoint( sb, b.getX() ); +// TPoint by3 = new TPoint( sc, c.getX() ); +// double by = det( by1, by2, by3 ); +// +// double x = bx / ( 2 * A ); +// double y = by / ( 2 * A ); +// +// TPoint center = new TPoint( x, y ); +// double radius = Math.sqrt( bx * bx + by * by - 4 * A * C ) / ( 2 * Math.abs( A ) ); +// +// return new Tuple2( center, radius ); +// } + + /** + * Requirement:
+ * 1. a,b and c form a triangle.
+ * 2. a and d is know to be on opposite side of bc
+ *
+     *                a
+     *                +
+     *               / \
+     *              /   \
+     *            b/     \c
+     *            +-------+ 
+     *           /    B    \  
+     *          /           \ 
+     * 
+ * Fact: d has to be in area B to have a chance to be inside the circle formed by + * a,b and c
+ * d is outside B if orient2d(a,b,d) or orient2d(c,a,d) is CW
+ * This preknowledge gives us a way to optimize the incircle test + * @param a - triangle point, opposite d + * @param b - triangle point + * @param c - triangle point + * @param d - point opposite a + * @return true if d is inside circle, false if on circle edge + */ + public static boolean smartIncircle( final TriangulationPoint pa, + final TriangulationPoint pb, + final TriangulationPoint pc, + final TriangulationPoint pd ) + { + final double pdx = pd.getX(); + final double pdy = pd.getY(); + final double adx = pa.getX() - pdx; + final double ady = pa.getY() - pdy; + final double bdx = pb.getX() - pdx; + final double bdy = pb.getY() - pdy; + + final double adxbdy = adx * bdy; + final double bdxady = bdx * ady; + final double oabd = adxbdy - bdxady; +// oabd = orient2d(pa,pb,pd); + if( oabd <= 0 ) + { + return false; + } + + final double cdx = pc.getX() - pdx; + final double cdy = pc.getY() - pdy; + + final double cdxady = cdx * ady; + final double adxcdy = adx * cdy; + final double ocad = cdxady - adxcdy; +// ocad = orient2d(pc,pa,pd); + if( ocad <= 0 ) + { + return false; + } + + final double bdxcdy = bdx * cdy; + final double cdxbdy = cdx * bdy; + + final double alift = adx * adx + ady * ady; + final double blift = bdx * bdx + bdy * bdy; + final double clift = cdx * cdx + cdy * cdy; + + final double det = alift * ( bdxcdy - cdxbdy ) + blift * ocad + clift * oabd; + + return det > 0; + } + + /** + * @see smartIncircle + * @param pa + * @param pb + * @param pc + * @param pd + * @return + */ + public static boolean inScanArea( final TriangulationPoint pa, + final TriangulationPoint pb, + final TriangulationPoint pc, + final TriangulationPoint pd ) + { + final double pdx = pd.getX(); + final double pdy = pd.getY(); + final double adx = pa.getX() - pdx; + final double ady = pa.getY() - pdy; + final double bdx = pb.getX() - pdx; + final double bdy = pb.getY() - pdy; + + final double adxbdy = adx * bdy; + final double bdxady = bdx * ady; + final double oabd = adxbdy - bdxady; +// oabd = orient2d(pa,pb,pd); + if( oabd <= 0 ) + { + return false; + } + + final double cdx = pc.getX() - pdx; + final double cdy = pc.getY() - pdy; + + final double cdxady = cdx * ady; + final double adxcdy = adx * cdy; + final double ocad = cdxady - adxcdy; +// ocad = orient2d(pc,pa,pd); + if( ocad <= 0 ) + { + return false; + } + return true; + } + + /** + * Forumla to calculate signed area
+ * Positive if CCW
+ * Negative if CW
+ * 0 if collinear
+ *
+     * A[P1,P2,P3]  =  (x1*y2 - y1*x2) + (x2*y3 - y2*x3) + (x3*y1 - y3*x1)
+     *              =  (x1-x3)*(y2-y3) - (y1-y3)*(x2-x3)
+     * 
+ */ + public static Orientation orient2d( TriangulationPoint pa, + TriangulationPoint pb, + TriangulationPoint pc ) + { + double detleft = ( pa.getX() - pc.getX() ) * ( pb.getY() - pc.getY() ); + double detright = ( pa.getY() - pc.getY() ) * ( pb.getX() - pc.getX() ); + double val = detleft - detright; + if( val > -EPSILON && val < EPSILON ) + { + return Orientation.Collinear; + } + else if( val > 0 ) + { + return Orientation.CCW; + } + return Orientation.CW; + } + + public enum Orientation + { + CW,CCW,Collinear; + } +} diff --git a/src/main/java/org/poly2tri/triangulation/delaunay/DelaunayTriangle.java b/src/main/java/org/poly2tri/triangulation/delaunay/DelaunayTriangle.java new file mode 100644 index 0000000..c93fcb0 --- /dev/null +++ b/src/main/java/org/poly2tri/triangulation/delaunay/DelaunayTriangle.java @@ -0,0 +1,685 @@ +/* Poly2Tri + * Copyright (c) 2009-2010, Poly2Tri Contributors + * http://code.google.com/p/poly2tri/ + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of Poly2Tri nor the names of its contributors may be + * used to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.poly2tri.triangulation.delaunay; + +import java.util.ArrayList; + +import org.poly2tri.triangulation.TriangulationPoint; +import org.poly2tri.triangulation.delaunay.sweep.DTSweepConstraint; +import org.poly2tri.triangulation.point.TPoint; + + +public class DelaunayTriangle +{ + + /** Neighbor pointers */ + public final DelaunayTriangle[] neighbors = new DelaunayTriangle[3]; + /** Flags to determine if an edge is a Constrained edge */ + public final boolean[] cEdge = new boolean[] { false, false, false }; + /** Flags to determine if an edge is a Delauney edge */ + public final boolean[] dEdge = new boolean[] { false, false, false }; + /** Has this triangle been marked as an interior triangle? */ + protected boolean interior = false; + + public final TriangulationPoint[] points = new TriangulationPoint[3]; + + public DelaunayTriangle( TriangulationPoint p1, TriangulationPoint p2, TriangulationPoint p3 ) + { + points[0] = p1; + points[1] = p2; + points[2] = p3; + } + + public int index( TriangulationPoint p ) + { + if( p == points[0] ) + { + return 0; + } + else if( p == points[1] ) + { + return 1; + } + else if( p == points[2] ) + { + return 2; + } + throw new RuntimeException("Calling index with a point that doesn't exist in triangle"); + } + + public int indexCW( TriangulationPoint p ) + { + int index = index(p); + switch( index ) + { + case 0: return 2; + case 1: return 0; + default: return 1; + } + } + + public int indexCCW( TriangulationPoint p ) + { + int index = index(p); + switch( index ) + { + case 0: return 1; + case 1: return 2; + default: return 0; + } + } + + public boolean contains( TriangulationPoint p ) + { + return ( p == points[0] || p == points[1] || p == points[2] ); + } + + public boolean contains( DTSweepConstraint e ) + { + return ( contains( e.p ) && contains( e.q ) ); + } + + public boolean contains( TriangulationPoint p, TriangulationPoint q ) + { + return ( contains( p ) && contains( q ) ); + } + + // Update neighbor pointers + private void markNeighbor( TriangulationPoint p1, + TriangulationPoint p2, + DelaunayTriangle t ) + { + if( ( p1 == points[2] && p2 == points[1] ) || ( p1 == points[1] && p2 == points[2] ) ) + { + neighbors[0] = t; + } + else if( ( p1 == points[0] && p2 == points[2] ) || ( p1 == points[2] && p2 == points[0] ) ) + { + neighbors[1] = t; + } + else if( ( p1 == points[0] && p2 == points[1] ) || ( p1 == points[1] && p2 == points[0] ) ) + { + neighbors[2] = t; + } + else + { + // throw new Exception("Neighbor error, please report!"); + } + } + + /* Exhaustive search to update neighbor pointers */ + public void markNeighbor( DelaunayTriangle t ) + { + if( t.contains( points[1], points[2] ) ) + { + neighbors[0] = t; + t.markNeighbor( points[1], points[2], this ); + } + else if( t.contains( points[0], points[2] ) ) + { + neighbors[1] = t; + t.markNeighbor( points[0], points[2], this ); + } + else if( t.contains( points[0], points[1] ) ) + { + neighbors[2] = t; + t.markNeighbor( points[0], points[1], this ); + } + else + { + } + } + + public void clearNeighbors() + { + neighbors[0] = neighbors[1] = neighbors[2] = null; + } + + public void clearNeighbor( DelaunayTriangle triangle ) + { + if( neighbors[0] == triangle ) + { + neighbors[0] = null; + } + else if( neighbors[1] == triangle ) + { + neighbors[1] = null; + } + else + { + neighbors[2] = null; + } + } + + /** + * Clears all references to all other triangles and points + */ + public void clear() + { + DelaunayTriangle t; + for( int i=0; i<3; i++ ) + { + t = neighbors[i]; + if( t != null ) + { + t.clearNeighbor( this ); + } + } + clearNeighbors(); + points[0]=points[1]=points[2]=null; + } + /** + * @param t - opposite triangle + * @param p - the point in t that isn't shared between the triangles + * @return + */ + public TriangulationPoint oppositePoint( DelaunayTriangle t, TriangulationPoint p ) + { + assert t != this : "self-pointer error"; + return pointCW( t.pointCW(p) ); + } + + // The neighbor clockwise to given point + public DelaunayTriangle neighborCW( TriangulationPoint point ) + { + if( point == points[0] ) + { + return neighbors[1]; + } + else if( point == points[1] ) + { + return neighbors[2]; + } + return neighbors[0]; + } + + // The neighbor counter-clockwise to given point + public DelaunayTriangle neighborCCW( TriangulationPoint point ) + { + if( point == points[0] ) + { + return neighbors[2]; + } + else if( point == points[1] ) + { + return neighbors[0]; + } + return neighbors[1]; + } + + // The neighbor across to given point + public DelaunayTriangle neighborAcross( TriangulationPoint opoint ) + { + if( opoint == points[0] ) + { + return neighbors[0]; + } + else if( opoint == points[1] ) + { + return neighbors[1]; + } + return neighbors[2]; + } + + // The point counter-clockwise to given point + public TriangulationPoint pointCCW( TriangulationPoint point ) + { + if( point == points[0] ) + { + return points[1]; + } + else if( point == points[1] ) + { + return points[2]; + } + else if( point == points[2] ) + { + return points[0]; + } + throw new RuntimeException("[FIXME] point location error"); + } + + // The point counter-clockwise to given point + public TriangulationPoint pointCW( TriangulationPoint point ) + { + if( point == points[0] ) + { + return points[2]; + } + else if( point == points[1] ) + { + return points[0]; + } + else if( point == points[2] ) + { + return points[1]; + } + throw new RuntimeException("[FIXME] point location error"); + } + + // Legalize triangle by rotating clockwise around oPoint + public void legalize( TriangulationPoint oPoint, TriangulationPoint nPoint ) + { + if( oPoint == points[0] ) + { + points[1] = points[0]; + points[0] = points[2]; + points[2] = nPoint; + } + else if( oPoint == points[1] ) + { + points[2] = points[1]; + points[1] = points[0]; + points[0] = nPoint; + } + else if( oPoint == points[2] ) + { + points[0] = points[2]; + points[2] = points[1]; + points[1] = nPoint; + } + else + { + throw new RuntimeException("legalization bug"); + } + } + + public void printDebug() + { + System.out.println( points[0] + "," + points[1] + "," + points[2] ); + } + + // Finalize edge marking + public void markNeighborEdges() + { + for( int i = 0; i < 3; i++ ) + { + if( cEdge[i] ) + { + switch( i ) + { + case 0: + if( neighbors[0] != null ) + neighbors[0].markConstrainedEdge( points[1], points[2] ); + break; + case 1: + if( neighbors[1] != null ) + neighbors[1].markConstrainedEdge( points[0], points[2] ); + break; + case 2: + if( neighbors[2] != null ) + neighbors[2].markConstrainedEdge( points[0], points[1] ); + break; + } + } + } + } + + public void markEdge( DelaunayTriangle triangle ) + { + for( int i = 0; i < 3; i++ ) + { + if( cEdge[i] ) + { + switch( i ) + { + case 0: + triangle.markConstrainedEdge( points[1], points[2] ); + break; + case 1: + triangle.markConstrainedEdge( points[0], points[2] ); + break; + case 2: + triangle.markConstrainedEdge( points[0], points[1] ); + break; + } + } + } + } + + public void markEdge( ArrayList tList ) + { + + for( DelaunayTriangle t : tList ) + { + for( int i = 0; i < 3; i++ ) + { + if( t.cEdge[i] ) + { + switch( i ) + { + case 0: + markConstrainedEdge( t.points[1], t.points[2] ); + break; + case 1: + markConstrainedEdge( t.points[0], t.points[2] ); + break; + case 2: + markConstrainedEdge( t.points[0], t.points[1] ); + break; + } + } + } + } + } + + public void markConstrainedEdge( int index ) + { + cEdge[index] = true; + } + + public void markConstrainedEdge( DTSweepConstraint edge ) + { + markConstrainedEdge( edge.p, edge.q ); + if( ( edge.q == points[0] && edge.p == points[1] ) + || ( edge.q == points[1] && edge.p == points[0] ) ) + { + cEdge[2] = true; + } + else if( ( edge.q == points[0] && edge.p == points[2] ) + || ( edge.q == points[2] && edge.p == points[0] ) ) + { + cEdge[1] = true; + } + else if( ( edge.q == points[1] && edge.p == points[2] ) + || ( edge.q == points[2] && edge.p == points[1] ) ) + { + cEdge[0] = true; + } + } + + // Mark edge as constrained + public void markConstrainedEdge( TriangulationPoint p, TriangulationPoint q ) + { + if( ( q == points[0] && p == points[1] ) || ( q == points[1] && p == points[0] ) ) + { + cEdge[2] = true; + } + else if( ( q == points[0] && p == points[2] ) || ( q == points[2] && p == points[0] ) ) + { + cEdge[1] = true; + } + else if( ( q == points[1] && p == points[2] ) || ( q == points[2] && p == points[1] ) ) + { + cEdge[0] = true; + } + } + + public double area() + { + double a = (points[0].getX() - points[2].getX())*(points[1].getY() - points[0].getY()); + double b = (points[0].getX() - points[1].getX())*(points[2].getY() - points[0].getY()); + + return 0.5*Math.abs( a - b ); + } + + public TPoint centroid() + { + double cx = ( points[0].getX() + points[1].getX() + points[2].getX() ) / 3d; + double cy = ( points[0].getY() + points[1].getY() + points[2].getY() ) / 3d; + return new TPoint( cx, cy ); + } + + /** + * Get the neighbor that share this edge + * + * @param constrainedEdge + * @return index of the shared edge or -1 if edge isn't shared + */ + public int edgeIndex( TriangulationPoint p1, TriangulationPoint p2 ) + { + if( points[0] == p1 ) + { + if( points[1] == p2 ) + { + return 2; + } + else if( points[2] == p2 ) + { + return 1; + } + } + else if( points[1] == p1 ) + { + if( points[2] == p2 ) + { + return 0; + } + else if( points[0] == p2 ) + { + return 2; + } + } + else if( points[2] == p1 ) + { + if( points[0] == p2 ) + { + return 1; + } + else if( points[1] == p2 ) + { + return 0; + } + } + return -1; + } + + public boolean getConstrainedEdgeCCW( TriangulationPoint p ) + { + if( p == points[0] ) + { + return cEdge[2]; + } + else if( p == points[1] ) + { + return cEdge[0]; + } + return cEdge[1]; + } + + public boolean getConstrainedEdgeCW( TriangulationPoint p ) + { + if( p == points[0] ) + { + return cEdge[1]; + } + else if( p == points[1] ) + { + return cEdge[2]; + } + return cEdge[0]; + } + + public boolean getConstrainedEdgeAcross( TriangulationPoint p ) + { + if( p == points[0] ) + { + return cEdge[0]; + } + else if( p == points[1] ) + { + return cEdge[1]; + } + return cEdge[2]; + } + + public void setConstrainedEdgeCCW( TriangulationPoint p, boolean ce ) + { + if( p == points[0] ) + { + cEdge[2] = ce; + } + else if( p == points[1] ) + { + cEdge[0] = ce; + } + else + { + cEdge[1] = ce; + } + } + + public void setConstrainedEdgeCW( TriangulationPoint p, boolean ce ) + { + if( p == points[0] ) + { + cEdge[1] = ce; + } + else if( p == points[1] ) + { + cEdge[2] = ce; + } + else + { + cEdge[0] = ce; + } + } + + public void setConstrainedEdgeAcross( TriangulationPoint p, boolean ce ) + { + if( p == points[0] ) + { + cEdge[0] = ce; + } + else if( p == points[1] ) + { + cEdge[1] = ce; + } + else + { + cEdge[2] = ce; + } + } + + public boolean getDelunayEdgeCCW( TriangulationPoint p ) + { + if( p == points[0] ) + { + return dEdge[2]; + } + else if( p == points[1] ) + { + return dEdge[0]; + } + return dEdge[1]; + } + + public boolean getDelunayEdgeCW( TriangulationPoint p ) + { + if( p == points[0] ) + { + return dEdge[1]; + } + else if( p == points[1] ) + { + return dEdge[2]; + } + return dEdge[0]; + } + + public boolean getDelunayEdgeAcross( TriangulationPoint p ) + { + if( p == points[0] ) + { + return dEdge[0]; + } + else if( p == points[1] ) + { + return dEdge[1]; + } + return dEdge[2]; + } + + public void setDelunayEdgeCCW( TriangulationPoint p, boolean e ) + { + if( p == points[0] ) + { + dEdge[2] = e; + } + else if( p == points[1] ) + { + dEdge[0] = e; + } + else + { + dEdge[1] = e; + } + } + + public void setDelunayEdgeCW( TriangulationPoint p, boolean e ) + { + if( p == points[0] ) + { + dEdge[1] = e; + } + else if( p == points[1] ) + { + dEdge[2] = e; + } + else + { + dEdge[0] = e; + } + } + + public void setDelunayEdgeAcross( TriangulationPoint p, boolean e ) + { + if( p == points[0] ) + { + dEdge[0] = e; + } + else if( p == points[1] ) + { + dEdge[1] = e; + } + else + { + dEdge[2] = e; + } + } + + public void clearDelunayEdges() + { + dEdge[0] = false; + dEdge[1] = false; + dEdge[2] = false; + } + + public boolean isInterior() + { + return interior; + } + + public void isInterior( boolean b ) + { + interior = b; + } +} diff --git a/src/main/java/org/poly2tri/triangulation/delaunay/sweep/AdvancingFront.java b/src/main/java/org/poly2tri/triangulation/delaunay/sweep/AdvancingFront.java new file mode 100644 index 0000000..e7994f3 --- /dev/null +++ b/src/main/java/org/poly2tri/triangulation/delaunay/sweep/AdvancingFront.java @@ -0,0 +1,179 @@ +/* Poly2Tri + * Copyright (c) 2009-2010, Poly2Tri Contributors + * http://code.google.com/p/poly2tri/ + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of Poly2Tri nor the names of its contributors may be + * used to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.poly2tri.triangulation.delaunay.sweep; + +import org.poly2tri.triangulation.TriangulationPoint; + + +/** + * @author Thomas Åhlen (thahlen@gmail.com) + */ +public class AdvancingFront +{ + public AdvancingFrontNode head; + public AdvancingFrontNode tail; + protected AdvancingFrontNode search; + + public AdvancingFront( AdvancingFrontNode head, AdvancingFrontNode tail ) + { + this.head = head; + this.tail = tail; + this.search = head; + addNode( head ); + addNode( tail ); + } + + public void addNode( AdvancingFrontNode node ) + { +// _searchTree.put( node.key, node ); + } + + public void removeNode( AdvancingFrontNode node ) + { +// _searchTree.delete( node.key ); + } + + public String toString() + { + StringBuilder sb = new StringBuilder(); + AdvancingFrontNode node = head; + while( node != tail ) + { + sb.append( node.point.getX() ).append( "->" ); + node = node.next; + } + sb.append( tail.point.getX() ); + return sb.toString(); + } + + private final AdvancingFrontNode findSearchNode( double x ) + { + // TODO: implement BST index + return search; + } + + /** + * We use a balancing tree to locate a node smaller or equal to + * given key value + * + * @param x + * @return + */ + public AdvancingFrontNode locateNode( TriangulationPoint point ) + { + return locateNode( point.getX() ); + } + + private AdvancingFrontNode locateNode( double x ) + { + AdvancingFrontNode node = findSearchNode(x); + if( x < node.value ) + { + while( (node = node.prev) != null ) + { + if( x >= node.value ) + { + search = node; + return node; + } + } + } + else + { + while( (node = node.next) != null ) + { + if( x < node.value ) + { + search = node.prev; + return node.prev; + } + } + } + return null; + } + + /** + * This implementation will use simple node traversal algorithm to find + * a point on the front + * + * @param point + * @return + */ + public AdvancingFrontNode locatePoint( final TriangulationPoint point ) + { + final double px = point.getX(); + AdvancingFrontNode node = findSearchNode(px); + final double nx = node.point.getX(); + + if( px == nx ) + { + if( point != node.point ) + { + // We might have two nodes with same x value for a short time + if( point == node.prev.point ) + { + node = node.prev; + } + else if( point == node.next.point ) + { + node = node.next; + } + else + { + throw new RuntimeException( "Failed to find Node for given afront point"); +// node = null; + } + } + } + else if( px < nx ) + { + while( (node = node.prev) != null ) + { + if( point == node.point ) + { + break; + } + } + } + else + { + while( (node = node.next) != null ) + { + if( point == node.point ) + { + break; + } + } + } + search = node; + return node; + } +} \ No newline at end of file diff --git a/src/main/java/org/poly2tri/triangulation/delaunay/sweep/AdvancingFrontIndex.java b/src/main/java/org/poly2tri/triangulation/delaunay/sweep/AdvancingFrontIndex.java new file mode 100644 index 0000000..8305416 --- /dev/null +++ b/src/main/java/org/poly2tri/triangulation/delaunay/sweep/AdvancingFrontIndex.java @@ -0,0 +1,43 @@ +package org.poly2tri.triangulation.delaunay.sweep; + +public class AdvancingFrontIndex
+{ + double _min,_max; + IndexNode _root; + + public AdvancingFrontIndex( double min, double max, int depth ) + { + if( depth > 5 ) depth = 5; + _root = createIndex( depth ); + } + + private IndexNode createIndex( int n ) + { + IndexNode node = null; + if( n > 0 ) + { + node = new IndexNode(); + node.bigger = createIndex( n-1 ); + node.smaller = createIndex( n-1 ); + } + return node; + } + + public A fetchAndRemoveIndex( A key ) + { + return null; + } + + public A fetchAndInsertIndex( A key ) + { + return null; + } + + class IndexNode + { + A value; + IndexNode smaller; + IndexNode bigger; + double range; + } +} diff --git a/src/main/java/org/poly2tri/triangulation/delaunay/sweep/AdvancingFrontNode.java b/src/main/java/org/poly2tri/triangulation/delaunay/sweep/AdvancingFrontNode.java new file mode 100644 index 0000000..d986925 --- /dev/null +++ b/src/main/java/org/poly2tri/triangulation/delaunay/sweep/AdvancingFrontNode.java @@ -0,0 +1,84 @@ +/* Poly2Tri + * Copyright (c) 2009-2010, Poly2Tri Contributors + * http://code.google.com/p/poly2tri/ + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of Poly2Tri nor the names of its contributors may be + * used to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.poly2tri.triangulation.delaunay.sweep; + +import org.poly2tri.triangulation.TriangulationPoint; +import org.poly2tri.triangulation.delaunay.DelaunayTriangle; + + + +public class AdvancingFrontNode +{ + protected AdvancingFrontNode next = null; + protected AdvancingFrontNode prev = null; + + protected final Double key; // XXX: BST + protected final double value; + protected final TriangulationPoint point; + protected DelaunayTriangle triangle; + + public AdvancingFrontNode( TriangulationPoint point ) + { + this.point = point; + value = point.getX(); + key = Double.valueOf( value ); // XXX: BST + } + + public AdvancingFrontNode getNext() + { + return next; + } + + public AdvancingFrontNode getPrevious() + { + return prev; + } + + public TriangulationPoint getPoint() + { + return point; + } + + public DelaunayTriangle getTriangle() + { + return triangle; + } + + public boolean hasNext() + { + return next != null; + } + + public boolean hasPrevious() + { + return prev != null; + } +} diff --git a/src/main/java/org/poly2tri/triangulation/delaunay/sweep/DTSweep.java b/src/main/java/org/poly2tri/triangulation/delaunay/sweep/DTSweep.java new file mode 100644 index 0000000..bd9fd35 --- /dev/null +++ b/src/main/java/org/poly2tri/triangulation/delaunay/sweep/DTSweep.java @@ -0,0 +1,1290 @@ +/* Poly2Tri + * Copyright (c) 2009-2010, Poly2Tri Contributors + * http://code.google.com/p/poly2tri/ + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of Poly2Tri nor the names of its contributors may be + * used to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.poly2tri.triangulation.delaunay.sweep; + +import static org.poly2tri.triangulation.TriangulationUtil.EPSILON; +import static org.poly2tri.triangulation.TriangulationUtil.inScanArea; +import static org.poly2tri.triangulation.TriangulationUtil.orient2d; +import static org.poly2tri.triangulation.TriangulationUtil.smartIncircle; +import java.util.List; +import org.poly2tri.triangulation.TriangulationMode; +import org.poly2tri.triangulation.TriangulationPoint; +import org.poly2tri.triangulation.TriangulationUtil.Orientation; +import org.poly2tri.triangulation.delaunay.DelaunayTriangle; + +/** + * Sweep-line, Constrained Delauney Triangulation (CDT) See: Domiter, V. and + * Zalik, B.(2008)'Sweep-line algorithm for constrained Delaunay triangulation', + * International Journal of Geographical Information Science + * + * "FlipScan" Constrained Edge Algorithm invented by author of this code. + * + * Author: Thomas Åhlén, thahlen@gmail.com + */ + +public class DTSweep +{ + + private final static double PI_div2 = Math.PI/2; + private final static double PI_3div4 = 3*Math.PI/4; + + public DTSweep() + {} + + /** Triangulate simple polygon with holes **/ + public static void triangulate( DTSweepContext tcx ) + { + tcx.createAdvancingFront(); + + sweep( tcx ); + + if( tcx.getTriangulationMode() == TriangulationMode.POLYGON ) + { + finalizationPolygon( tcx ); + } + else + { + finalizationConvexHull( tcx ); + } + + tcx.done(); + } + + /** + * Start sweeping the Y-sorted point set from bottom to top + * + * @param tcx + */ + private static void sweep( DTSweepContext tcx ) + { + List points; + TriangulationPoint point; + AdvancingFrontNode node; + + points = tcx.getPoints(); + + for( int i=1; i + */ + private static void turnAdvancingFrontConvex( DTSweepContext tcx, + AdvancingFrontNode b, + AdvancingFrontNode c ) + { + AdvancingFrontNode first = b; + while( c != tcx.aFront.tail ) + { + if( tcx.isDebugEnabled() ) { tcx.getDebugContext().setActiveNode( c ); } + + if( orient2d( b.point, c.point, c.next.point ) == Orientation.CCW ) + { + // [b,c,d] Concave - fill around c + fill( tcx, c ); + c = c.next; + } + else + { + // [b,c,d] Convex + if( b != first && orient2d( b.prev.point, b.point, c.point ) == Orientation.CCW ) + { + // [a,b,c] Concave - fill around b + fill( tcx, b ); + b = b.prev; + } + else + { + // [a,b,c] Convex - nothing to fill + b = c; + c = c.next; + } + } + } + } + + private static void finalizationPolygon( DTSweepContext tcx ) + { + // Get an Internal triangle to start with + DelaunayTriangle t = tcx.aFront.head.next.triangle; + TriangulationPoint p = tcx.aFront.head.next.point; + while( !t.getConstrainedEdgeCW( p ) ) + { + t = t.neighborCCW( p ); + } + + // Collect interior triangles constrained by edges + tcx.meshClean( t ); + } + + /** + * Find closes node to the left of the new point and + * create a new triangle. If needed new holes and basins + * will be filled to. + * + * @param tcx + * @param point + * @return + */ + private static AdvancingFrontNode pointEvent( DTSweepContext tcx, + TriangulationPoint point ) + { + AdvancingFrontNode node,newNode; + + node = tcx.locateNode( point ); + if( tcx.isDebugEnabled() ) { tcx.getDebugContext().setActiveNode( node ); } + newNode = newFrontTriangle( tcx, point, node ); + + // Only need to check +epsilon since point never have smaller + // x value than node due to how we fetch nodes from the front + if( point.getX() <= node.point.getX() + EPSILON ) + { + fill( tcx, node ); + } + tcx.addNode( newNode ); + + fillAdvancingFront( tcx, newNode ); + return newNode; + } + + /** + * Creates a new front triangle and legalize it + * + * @param tcx + * @param point + * @param node + * @return + */ + private static AdvancingFrontNode newFrontTriangle( DTSweepContext tcx, + TriangulationPoint point, + AdvancingFrontNode node ) + { + AdvancingFrontNode newNode; + DelaunayTriangle triangle; + + triangle = new DelaunayTriangle( point, node.point, node.next.point ); + triangle.markNeighbor( node.triangle ); + tcx.addToList( triangle ); + + newNode = new AdvancingFrontNode( point ); + newNode.next = node.next; + newNode.prev = node; + node.next.prev = newNode; + node.next = newNode; + + tcx.addNode( newNode ); // XXX: BST + + if( tcx.isDebugEnabled() ) { tcx.getDebugContext().setActiveNode( newNode ); } + + if( !legalize( tcx, triangle ) ) + { + tcx.mapTriangleToNodes( triangle ); + } + + return newNode; + } + + /** + * + * + * @param tcx + * @param edge + * @param node + */ + private static void edgeEvent( DTSweepContext tcx, + DTSweepConstraint edge, + AdvancingFrontNode node ) + { + try + { + tcx.edgeEvent.constrainedEdge = edge; + tcx.edgeEvent.right = edge.p.getX() > edge.q.getX(); + + if( tcx.isDebugEnabled() ) { tcx.getDebugContext().setPrimaryTriangle( node.triangle ); } + + if( isEdgeSideOfTriangle( node.triangle, edge.p, edge.q ) ) + { + return; + } + + // For now we will do all needed filling + // TODO: integrate with flip process might give some better performance + // but for now this avoid the issue with cases that needs both flips and fills + fillEdgeEvent( tcx, edge, node ); + + edgeEvent( tcx, edge.p, edge.q , node.triangle, edge.q ); + } + catch( PointOnEdgeException e ) + { + } + } + + private static void fillEdgeEvent( DTSweepContext tcx, DTSweepConstraint edge, AdvancingFrontNode node ) + { + if( tcx.edgeEvent.right ) + { + fillRightAboveEdgeEvent( tcx, edge, node ); + } + else + { + fillLeftAboveEdgeEvent( tcx, edge, node ); + } + } + + private static void fillRightConcaveEdgeEvent( DTSweepContext tcx, DTSweepConstraint edge, AdvancingFrontNode node ) + { + fill( tcx, node.next ); + if( node.next.point != edge.p ) + { + // Next above or below edge? + if( orient2d( edge.q, node.next.point, edge.p ) == Orientation.CCW ) + { + // Below + if( orient2d( node.point, node.next.point, node.next.next.point ) == Orientation.CCW ) + { + // Next is concave + fillRightConcaveEdgeEvent( tcx, edge, node ); + } + else + { + // Next is convex + } + } + } + } + + private static void fillRightConvexEdgeEvent( DTSweepContext tcx, DTSweepConstraint edge, AdvancingFrontNode node ) + { + // Next concave or convex? + if( orient2d( node.next.point, node.next.next.point, node.next.next.next.point ) == Orientation.CCW ) + { + // Concave + fillRightConcaveEdgeEvent( tcx, edge, node.next ); + } + else + { + // Convex + // Next above or below edge? + if( orient2d( edge.q, node.next.next.point, edge.p ) == Orientation.CCW ) + { + // Below + fillRightConvexEdgeEvent( tcx, edge, node.next ); + } + else + { + // Above + } + } + } + + private static void fillRightBelowEdgeEvent( DTSweepContext tcx, DTSweepConstraint edge, AdvancingFrontNode node ) + { + if( tcx.isDebugEnabled() ) { tcx.getDebugContext().setActiveNode( node ); } + if( node.point.getX() < edge.p.getX() ) // needed? + { + if( orient2d( node.point, node.next.point, node.next.next.point ) == Orientation.CCW ) + { + // Concave + fillRightConcaveEdgeEvent( tcx, edge, node ); + } + else + { + // Convex + fillRightConvexEdgeEvent( tcx, edge, node ); + // Retry this one + fillRightBelowEdgeEvent( tcx, edge, node ); + } + + } + } + + private static void fillRightAboveEdgeEvent( DTSweepContext tcx, DTSweepConstraint edge, AdvancingFrontNode node ) + { + while( node.next.point.getX() < edge.p.getX() ) + { + if( tcx.isDebugEnabled() ) { tcx.getDebugContext().setActiveNode( node ); } + // Check if next node is below the edge + Orientation o1 = orient2d( edge.q, node.next.point, edge.p ); + if( o1 == Orientation.CCW ) + { + fillRightBelowEdgeEvent( tcx, edge, node ); + } + else + { + node = node.next; + } + } + } + + private static void fillLeftConvexEdgeEvent( DTSweepContext tcx, DTSweepConstraint edge, AdvancingFrontNode node ) + { + // Next concave or convex? + if( orient2d( node.prev.point, node.prev.prev.point, node.prev.prev.prev.point ) == Orientation.CW ) + { + // Concave + fillLeftConcaveEdgeEvent( tcx, edge, node.prev ); + } + else + { + // Convex + // Next above or below edge? + if( orient2d( edge.q, node.prev.prev.point, edge.p ) == Orientation.CW ) + { + // Below + fillLeftConvexEdgeEvent( tcx, edge, node.prev ); + } + else + { + // Above + } + } + } + + private static void fillLeftConcaveEdgeEvent( DTSweepContext tcx, DTSweepConstraint edge, AdvancingFrontNode node ) + { + fill( tcx, node.prev ); + if( node.prev.point != edge.p ) + { + // Next above or below edge? + if( orient2d( edge.q, node.prev.point, edge.p ) == Orientation.CW ) + { + // Below + if( orient2d( node.point, node.prev.point, node.prev.prev.point ) == Orientation.CW ) + { + // Next is concave + fillLeftConcaveEdgeEvent( tcx, edge, node ); + } + else + { + // Next is convex + } + } + } + } + + private static void fillLeftBelowEdgeEvent( DTSweepContext tcx, DTSweepConstraint edge, AdvancingFrontNode node ) + { + if( tcx.isDebugEnabled() ) { tcx.getDebugContext().setActiveNode( node ); } + if( node.point.getX() > edge.p.getX() ) + { + if( orient2d( node.point, node.prev.point, node.prev.prev.point ) == Orientation.CW ) + { + // Concave + fillLeftConcaveEdgeEvent( tcx, edge, node ); + } + else + { + // Convex + fillLeftConvexEdgeEvent( tcx, edge, node ); + // Retry this one + fillLeftBelowEdgeEvent( tcx, edge, node ); + } + + } + } + + private static void fillLeftAboveEdgeEvent( DTSweepContext tcx, DTSweepConstraint edge, AdvancingFrontNode node ) + { + while( node.prev.point.getX() > edge.p.getX() ) + { + if( tcx.isDebugEnabled() ) { tcx.getDebugContext().setActiveNode( node ); } + // Check if next node is below the edge + Orientation o1 = orient2d( edge.q, node.prev.point, edge.p ); + if( o1 == Orientation.CW ) + { + fillLeftBelowEdgeEvent( tcx, edge, node ); + } + else + { + node = node.prev; + } + } + } + + private static boolean isEdgeSideOfTriangle( DelaunayTriangle triangle, + TriangulationPoint ep, + TriangulationPoint eq ) + { + int index; + index = triangle.edgeIndex( ep, eq ); + if( index != -1 ) + { + triangle.markConstrainedEdge( index ); + triangle = triangle.neighbors[ index ]; + if( triangle != null ) + { + triangle.markConstrainedEdge( ep, eq ); + } + return true; + } + return false; + } + + private static void edgeEvent( DTSweepContext tcx, + TriangulationPoint ep, + TriangulationPoint eq, + DelaunayTriangle triangle, + TriangulationPoint point ) + { + TriangulationPoint p1,p2; + + if( tcx.isDebugEnabled() ) { tcx.getDebugContext().setPrimaryTriangle( triangle ); } + + if( isEdgeSideOfTriangle( triangle, ep, eq ) ) + { + return; + } + + p1 = triangle.pointCCW( point ); + Orientation o1 = orient2d( eq, p1, ep ); + if( o1 == Orientation.Collinear ) + { + if( triangle.contains( eq, p1 ) ) + { + triangle.markConstrainedEdge( eq, p1 ); + // We are modifying the constraint maybe it would be better to + // not change the given constraint and just keep a variable for the new constraint + tcx.edgeEvent.constrainedEdge.q = p1; + triangle = triangle.neighborAcross( point ); + edgeEvent( tcx, ep, p1, triangle, p1 ); + } + else + { + throw new PointOnEdgeException( "EdgeEvent - Point on constrained edge not supported yet" ); + } + return; + } + + p2 = triangle.pointCW( point ); + Orientation o2 = orient2d( eq, p2, ep ); + if( o2 == Orientation.Collinear ) + { + if( triangle.contains( eq, p2 ) ) + { + triangle.markConstrainedEdge( eq, p2 ); + // We are modifying the constraint maybe it would be better to + // not change the given constraint and just keep a variable for the new constraint + tcx.edgeEvent.constrainedEdge.q = p2; + triangle = triangle.neighborAcross( point ); + edgeEvent( tcx, ep, p2, triangle, p2 ); + } + else + { + throw new PointOnEdgeException( "EdgeEvent - Point on constrained edge not supported yet" ); + } + return; + } + + if( o1 == o2 ) + { + // Need to decide if we are rotating CW or CCW to get to a triangle + // that will cross edge + if( o1 == Orientation.CW ) + { + triangle = triangle.neighborCCW( point ); + } + else + { + triangle = triangle.neighborCW( point ); + } + edgeEvent( tcx, ep, eq, triangle, point ); + } + else + { + // This triangle crosses constraint so lets flippin start! + flipEdgeEvent( tcx, ep, eq, triangle, point ); + } + } + + private static void flipEdgeEvent( DTSweepContext tcx, + TriangulationPoint ep, + TriangulationPoint eq, + DelaunayTriangle t, + TriangulationPoint p ) + { + TriangulationPoint op, newP; + DelaunayTriangle ot; + boolean inScanArea; + + ot = t.neighborAcross( p ); + op = ot.oppositePoint( t, p ); + + if( ot == null ) + { + // If we want to integrate the fillEdgeEvent do it here + // With current implementation we should never get here + throw new RuntimeException( "[BUG:FIXME] FLIP failed due to missing triangle"); + } + + if( t.getConstrainedEdgeAcross(p) ) + { + throw new RuntimeException( "Intersecting Constraints" ); + } + + if( tcx.isDebugEnabled() ) + { + tcx.getDebugContext().setPrimaryTriangle( t ); + tcx.getDebugContext().setSecondaryTriangle( ot ); + } // TODO: remove + + inScanArea = inScanArea( p, + t.pointCCW( p ), + t.pointCW( p ), + op ); + if( inScanArea ) + { + // Lets rotate shared edge one vertex CW + rotateTrianglePair( t, p, ot, op ); + tcx.mapTriangleToNodes( t ); + tcx.mapTriangleToNodes( ot ); + + if( p == eq && op == ep ) + { + if( eq == tcx.edgeEvent.constrainedEdge.q + && ep == tcx.edgeEvent.constrainedEdge.p) + { + if( tcx.isDebugEnabled() ) { System.out.println("[FLIP] - constrained edge done" ); } // TODO: remove + t.markConstrainedEdge( ep, eq ); + ot.markConstrainedEdge( ep, eq ); + legalize( tcx, t ); + legalize( tcx, ot ); + } + else + { + if( tcx.isDebugEnabled() ) { System.out.println("[FLIP] - subedge done" ); } // TODO: remove + // XXX: I think one of the triangles should be legalized here? + } + } + else + { + if( tcx.isDebugEnabled() ) { System.out.println("[FLIP] - flipping and continuing with triangle still crossing edge" ); } // TODO: remove + Orientation o = orient2d( eq, op, ep ); + t = nextFlipTriangle( tcx, o, t, ot, p, op ); + flipEdgeEvent( tcx, ep, eq, t, p ); + } + } + else + { + newP = nextFlipPoint( ep, eq, ot, op ); + flipScanEdgeEvent( tcx, ep, eq, t, ot, newP ); + edgeEvent( tcx, ep, eq, t, p ); + } + } + + /** + * When we need to traverse from one triangle to the next we need + * the point in current triangle that is the opposite point to the next + * triangle. + * + * @param ep + * @param eq + * @param ot + * @param op + * @return + */ + private static TriangulationPoint nextFlipPoint( TriangulationPoint ep, + TriangulationPoint eq, + DelaunayTriangle ot, + TriangulationPoint op ) + { + Orientation o2d = orient2d( eq, op, ep ); + if( o2d == Orientation.CW ) + { + // Right + return ot.pointCCW( op ); + } + else if( o2d == Orientation.CCW ) + { + // Left + return ot.pointCW( op ); + } + else + { + // TODO: implement support for point on constraint edge + throw new PointOnEdgeException("Point on constrained edge not supported yet"); + } + } + + /** + * After a flip we have two triangles and know that only one will still be + * intersecting the edge. So decide which to contiune with and legalize the other + * + * @param tcx + * @param o - should be the result of an orient2d( eq, op, ep ) + * @param t - triangle 1 + * @param ot - triangle 2 + * @param p - a point shared by both triangles + * @param op - another point shared by both triangles + * @return returns the triangle still intersecting the edge + */ + private static DelaunayTriangle nextFlipTriangle( DTSweepContext tcx, + Orientation o, + DelaunayTriangle t, + DelaunayTriangle ot, + TriangulationPoint p, + TriangulationPoint op) + { + int edgeIndex; + if( o == Orientation.CCW ) + { + // ot is not crossing edge after flip + edgeIndex = ot.edgeIndex( p, op ); + ot.dEdge[edgeIndex] = true; + legalize( tcx, ot ); + ot.clearDelunayEdges(); + return t; + } + // t is not crossing edge after flip + edgeIndex = t.edgeIndex( p, op ); + t.dEdge[edgeIndex] = true; + legalize( tcx, t ); + t.clearDelunayEdges(); + return ot; + } + + /** + * Scan part of the FlipScan algorithm
+ * When a triangle pair isn't flippable we will scan for the next + * point that is inside the flip triangle scan area. When found + * we generate a new flipEdgeEvent + * + * @param tcx + * @param ep - last point on the edge we are traversing + * @param eq - first point on the edge we are traversing + * @param flipTriangle - the current triangle sharing the point eq with edge + * @param t + * @param p + */ + private static void flipScanEdgeEvent( DTSweepContext tcx, + TriangulationPoint ep, + TriangulationPoint eq, + DelaunayTriangle flipTriangle, + DelaunayTriangle t, + TriangulationPoint p ) + { + DelaunayTriangle ot; + TriangulationPoint op,newP; + boolean inScanArea; + + ot = t.neighborAcross( p ); + op = ot.oppositePoint( t, p ); + + if( ot == null ) + { + // If we want to integrate the fillEdgeEvent do it here + // With current implementation we should never get here + throw new RuntimeException( "[BUG:FIXME] FLIP failed due to missing triangle"); + } + + if( tcx.isDebugEnabled() ) + { + System.out.println("[FLIP:SCAN] - scan next point" ); // TODO: remove + tcx.getDebugContext().setPrimaryTriangle( t ); + tcx.getDebugContext().setSecondaryTriangle( ot ); + } + + inScanArea = inScanArea( eq, + flipTriangle.pointCCW( eq ), + flipTriangle.pointCW( eq ), + op ); + if( inScanArea ) + { + // flip with new edge op->eq + flipEdgeEvent( tcx, eq, op, ot, op ); + // TODO: Actually I just figured out that it should be possible to + // improve this by getting the next ot and op before the the above + // flip and continue the flipScanEdgeEvent here + // set new ot and op here and loop back to inScanArea test + // also need to set a new flipTriangle first + // Turns out at first glance that this is somewhat complicated + // so it will have to wait. + } + else + { + newP = nextFlipPoint( ep, eq, ot, op ); + flipScanEdgeEvent( tcx, ep, eq, flipTriangle, ot, newP ); + } + } + + /** + * Fills holes in the Advancing Front + * + * + * @param tcx + * @param n + */ + private static void fillAdvancingFront( DTSweepContext tcx, AdvancingFrontNode n ) + { + AdvancingFrontNode node; + double angle; + + // Fill right holes + node = n.next; + while( node.hasNext() ) + { + if( isLargeHole(node) ) + { + break; + } + fill( tcx, node ); + node = node.next; + } + + // Fill left holes + node = n.prev; + while( node.hasPrevious() ) + { + if( isLargeHole(node) ) + { + break; + } + fill( tcx, node ); + node = node.prev; + } + + // Fill right basins + if( n.hasNext() && n.next.hasNext() ) + { + angle = basinAngle( n ); + if( angle < PI_3div4 ) + { + fillBasin( tcx, n ); + } + } + } + + /** + * @param node + * @return true if hole angle exceeds 90 degrees + */ + private static boolean isLargeHole(AdvancingFrontNode node) + { + double angle = angle(node.point, node.next.point, node.prev.point); + //XXX: don't see angle being in range [-pi/2,0] due to how advancing front works +// return (angle > PI_div2) || (angle < -PI_div2); + return (angle > PI_div2) || (angle < 0); + + // ISSUE 48: http://code.google.com/p/poly2tri/issues/detail?id=48 + // TODO: Adding this fix suggested in issues 48 caused some + // triangulations to fail so commented it out for now. + // + // Also haven't been able to produce a triangulation that gives the + // problem described in issue 48. + +// AdvancingFrontNode nextNode = node.next; +// AdvancingFrontNode prevNode = node.prev; +// if( !AngleExceeds90Degrees(node.point, +// nextNode.point, +// prevNode.point)) +// { +// return false; +// } +// +// // Check additional points on front. +// AdvancingFrontNode next2Node = nextNode.next; +// // "..Plus.." because only want angles on same side as point being added. +// if( (next2Node != null) +// && !AngleExceedsPlus90DegreesOrIsNegative(node.point, +// next2Node.point, +// prevNode.point)) +// { +// return false; +// } +// +// AdvancingFrontNode prev2Node = prevNode.prev; +// // "..Plus.." because only want angles on same side as point being added. +// if( (prev2Node != null) +// && !AngleExceedsPlus90DegreesOrIsNegative(node.point, +// nextNode.point, +// prev2Node.point)) +// { +// return false; +// } +// return true; + } + +// private static boolean AngleExceeds90Degrees +// ( +// TriangulationPoint origin, +// TriangulationPoint pa, +// TriangulationPoint pb +// ) +// { +// double angle = angle(origin, pa, pb); +// return (angle > PI_div2) || (angle < -PI_div2); +// } +// +// +// private static boolean AngleExceedsPlus90DegreesOrIsNegative +// ( +// TriangulationPoint origin, +// TriangulationPoint pa, +// TriangulationPoint pb +// ) +// { +// double angle = angle(origin, pa, pb); +// return (angle > PI_div2) || (angle < 0); +// } + + /** + * Fills a basin that has formed on the Advancing Front to the right + * of given node.
+ * First we decide a left,bottom and right node that forms the + * boundaries of the basin. Then we do a reqursive fill. + * + * @param tcx + * @param node - starting node, this or next node will be left node + */ + private static void fillBasin( DTSweepContext tcx, AdvancingFrontNode node ) + { + if( orient2d( node.point, node.next.point, node.next.next.point ) == Orientation.CCW ) + { + tcx.basin.leftNode = node; + } + else + { + tcx.basin.leftNode = node.next; + } + + // Find the bottom and right node + tcx.basin.bottomNode = tcx.basin.leftNode; + while( tcx.basin.bottomNode.hasNext() + && tcx.basin.bottomNode.point.getY() >= tcx.basin.bottomNode.next.point.getY() ) + { + tcx.basin.bottomNode = tcx.basin.bottomNode.next; + } + if( tcx.basin.bottomNode == tcx.basin.leftNode ) + { + // No valid basin + return; + } + + tcx.basin.rightNode = tcx.basin.bottomNode; + while( tcx.basin.rightNode.hasNext() + && tcx.basin.rightNode.point.getY() < tcx.basin.rightNode.next.point.getY() ) + { + tcx.basin.rightNode = tcx.basin.rightNode.next; + } + if( tcx.basin.rightNode == tcx.basin.bottomNode ) + { + // No valid basins + return; + } + + tcx.basin.width = tcx.basin.rightNode.getPoint().getX() - tcx.basin.leftNode.getPoint().getX(); + tcx.basin.leftHighest = tcx.basin.leftNode.getPoint().getY() > tcx.basin.rightNode.getPoint().getY(); + + fillBasinReq( tcx, tcx.basin.bottomNode ); + } + + /** + * Recursive algorithm to fill a Basin with triangles + * + * @param tcx + * @param node - bottomNode + * @param cnt - counter used to alternate on even and odd numbers + */ + private static void fillBasinReq( DTSweepContext tcx, AdvancingFrontNode node ) + { + // if shallow stop filling + if( isShallow( tcx, node) ) + { + return; + } + + fill( tcx, node ); + if( node.prev == tcx.basin.leftNode && node.next == tcx.basin.rightNode ) + { + return; + } + else if( node.prev == tcx.basin.leftNode ) + { + Orientation o = orient2d( node.point, node.next.point, node.next.next.point ); + if( o == Orientation.CW ) + { + return; + } + node = node.next; + } + else if( node.next == tcx.basin.rightNode ) + { + Orientation o = orient2d( node.point, node.prev.point, node.prev.prev.point ); + if( o == Orientation.CCW ) + { + return; + } + node = node.prev; + } + else + { + // Continue with the neighbor node with lowest Y value + if( node.prev.point.getY() < node.next.point.getY() ) + { + node = node.prev; + } + else + { + node = node.next; + } + } + fillBasinReq( tcx, node ); + } + + private static boolean isShallow( DTSweepContext tcx, AdvancingFrontNode node ) + { + double height; + + if( tcx.basin.leftHighest ) + { + height = tcx.basin.leftNode.getPoint().getY() - node.getPoint().getY(); + } + else + { + height = tcx.basin.rightNode.getPoint().getY() - node.getPoint().getY(); + } + if( tcx.basin.width > height ) + { + return true; + } + return false; + } + + /** + * + * @param node - middle node + * @return the angle between p-a and p-b in range [-pi,pi] + */ + private static double angle( TriangulationPoint p, + TriangulationPoint a, + TriangulationPoint b ) + { + // XXX: do we really need a signed angle for holeAngle? + // could possible save some cycles here + /* Complex plane + * ab = cosA +i*sinA + * ab = (ax + ay*i)(bx + by*i) = (ax*bx + ay*by) + i(ax*by-ay*bx) + * atan2(y,x) computes the principal value of the argument function + * applied to the complex number x+iy + * Where x = ax*bx + ay*by + * y = ax*by - ay*bx + */ + final double px = p.getX(); + final double py = p.getY(); + final double ax = a.getX() - px; + final double ay = a.getY() - py; + final double bx = b.getX() - px; + final double by = b.getY() - py; + return Math.atan2( ax*by - ay*bx, ax*bx + ay*by ); + } + + /** + * The basin angle is decided against the horizontal line [1,0] + */ + private static double basinAngle( AdvancingFrontNode node ) + { + double ax = node.point.getX() - node.next.next.point.getX(); + double ay = node.point.getY() - node.next.next.point.getY(); + return Math.atan2( ay, ax ); + } + + /** + * Adds a triangle to the advancing front to fill a hole. + * @param tcx + * @param node - middle node, that is the bottom of the hole + */ + private static void fill( DTSweepContext tcx, AdvancingFrontNode node ) + { + DelaunayTriangle triangle = new DelaunayTriangle( node.prev.point, + node.point, + node.next.point ); + // TODO: should copy the cEdge value from neighbor triangles + // for now cEdge values are copied during the legalize + triangle.markNeighbor( node.prev.triangle ); + triangle.markNeighbor( node.triangle ); + tcx.addToList( triangle ); + + // Update the advancing front + node.prev.next = node.next; + node.next.prev = node.prev; + tcx.removeNode( node ); + + // If it was legalized the triangle has already been mapped + if( !legalize( tcx, triangle ) ) + { + tcx.mapTriangleToNodes( triangle ); + } + } + + /** + * Returns true if triangle was legalized + */ + private static boolean legalize( DTSweepContext tcx, + DelaunayTriangle t ) + { + int oi; + boolean inside; + TriangulationPoint p,op; + DelaunayTriangle ot; + // To legalize a triangle we start by finding if any of the three edges + // violate the Delaunay condition + for( int i=0; i<3; i++ ) + { + // TODO: fix so that cEdge is always valid when creating new triangles then we can check it here + // instead of below with ot + if( t.dEdge[i] ) + { + continue; + } + ot = t.neighbors[i]; + if( ot != null ) + { + p = t.points[i]; + op = ot.oppositePoint( t, p ); + oi = ot.index( op ); + // If this is a Constrained Edge or a Delaunay Edge(only during recursive legalization) + // then we should not try to legalize + if( ot.cEdge[oi] || ot.dEdge[oi] ) + { + t.cEdge[i] = ot.cEdge[oi]; // XXX: have no good way of setting this property when creating new triangles so lets set it here + continue; + } + inside = smartIncircle( p, + t.pointCCW( p ), + t.pointCW( p ), + op ); + if( inside ) + { + boolean notLegalized; + + // Lets mark this shared edge as Delaunay + t.dEdge[i] = true; + ot.dEdge[oi] = true; + + // Lets rotate shared edge one vertex CW to legalize it + rotateTrianglePair( t, p, ot, op ); + + // We now got one valid Delaunay Edge shared by two triangles + // This gives us 4 new edges to check for Delaunay + + // Make sure that triangle to node mapping is done only one time for a specific triangle + notLegalized = !legalize( tcx, t ); + if( notLegalized ) + { + tcx.mapTriangleToNodes( t ); + } + notLegalized = !legalize( tcx, ot ); + if( notLegalized ) + { + tcx.mapTriangleToNodes( ot ); + } + + // Reset the Delaunay edges, since they only are valid Delaunay edges + // until we add a new triangle or point. + // XXX: need to think about this. Can these edges be tried after we + // return to previous recursive level? + t.dEdge[i] = false; + ot.dEdge[oi] = false; + + // If triangle have been legalized no need to check the other edges since + // the recursive legalization will handles those so we can end here. + return true; + } + } + } + return false; + } + + /** + * Rotates a triangle pair one vertex CW + *
+     *       n2                    n2
+     *  P +-----+             P +-----+
+     *    | t  /|               |\  t |  
+     *    |   / |               | \   |
+     *  n1|  /  |n3           n1|  \  |n3
+     *    | /   |    after CW   |   \ |
+     *    |/ oT |               | oT \|
+     *    +-----+ oP            +-----+
+     *       n4                    n4
+     * 
+ */ + private static void rotateTrianglePair( DelaunayTriangle t, + TriangulationPoint p, + DelaunayTriangle ot, + TriangulationPoint op ) + { + DelaunayTriangle n1,n2,n3,n4; + n1 = t.neighborCCW( p ); + n2 = t.neighborCW( p ); + n3 = ot.neighborCCW( op ); + n4 = ot.neighborCW( op ); + + boolean ce1,ce2,ce3,ce4; + ce1 = t.getConstrainedEdgeCCW(p); + ce2 = t.getConstrainedEdgeCW(p); + ce3 = ot.getConstrainedEdgeCCW(op); + ce4 = ot.getConstrainedEdgeCW(op); + + boolean de1,de2,de3,de4; + de1 = t.getDelunayEdgeCCW(p); + de2 = t.getDelunayEdgeCW(p); + de3 = ot.getDelunayEdgeCCW(op); + de4 = ot.getDelunayEdgeCW(op); + + t.legalize( p, op ); + ot.legalize( op, p ); + + // Remap dEdge + ot.setDelunayEdgeCCW( p, de1 ); + t.setDelunayEdgeCW( p, de2 ); + t.setDelunayEdgeCCW( op, de3 ); + ot.setDelunayEdgeCW( op, de4 ); + + // Remap cEdge + ot.setConstrainedEdgeCCW( p, ce1 ); + t.setConstrainedEdgeCW( p, ce2 ); + t.setConstrainedEdgeCCW( op, ce3 ); + ot.setConstrainedEdgeCW( op, ce4 ); + + // Remap neighbors + // XXX: might optimize the markNeighbor by keeping track of + // what side should be assigned to what neighbor after the + // rotation. Now mark neighbor does lots of testing to find + // the right side. + t.clearNeighbors(); + ot.clearNeighbors(); + if( n1 != null ) ot.markNeighbor( n1 ); + if( n2 != null ) t.markNeighbor( n2 ); + if( n3 != null ) t.markNeighbor( n3 ); + if( n4 != null ) ot.markNeighbor( n4 ); + t.markNeighbor( ot ); + } +} diff --git a/src/main/java/org/poly2tri/triangulation/delaunay/sweep/DTSweepConstraint.java b/src/main/java/org/poly2tri/triangulation/delaunay/sweep/DTSweepConstraint.java new file mode 100644 index 0000000..636cbd9 --- /dev/null +++ b/src/main/java/org/poly2tri/triangulation/delaunay/sweep/DTSweepConstraint.java @@ -0,0 +1,103 @@ +/* Poly2Tri + * Copyright (c) 2009-2010, Poly2Tri Contributors + * http://code.google.com/p/poly2tri/ + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of Poly2Tri nor the names of its contributors may be + * used to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.poly2tri.triangulation.delaunay.sweep; + +import java.util.logging.Logger; +import org.poly2tri.triangulation.TriangulationConstraint; +import org.poly2tri.triangulation.TriangulationPoint; + +/** + * + * @author Thomas Åhlén, thahlen@gmail.com + * + */ +public class DTSweepConstraint extends TriangulationConstraint +{ + + public TriangulationPoint p; + public TriangulationPoint q; + + /** + * Give two points in any order. Will always be ordered so + * that q.y > p.y and q.x > p.x if same y value + * + * @param p1 + * @param p2 + */ + public DTSweepConstraint( TriangulationPoint p1, TriangulationPoint p2 ) +// throws DuplicatePointException + { + p = p1; + q = p2; + if( p1.getY() > p2.getY() ) + { + q = p1; + p = p2; + } + else if( p1.getY() == p2.getY() ) + { + if( p1.getX() > p2.getX() ) + { + q = p1; + p = p2; + } + else if( p1.getX() == p2.getX() ) + { +// throw new DuplicatePointException( p1 + "=" + p2 ); +// return; + } + } + q.addEdge(this); + } + +// public TPoint intersect( TPoint a, TPoint b ) +// { +// double pqx,pqy,bax,bay,t; +// +// pqx = p.getX()-q.getX(); +// pqy = p.getY()-q.getY(); +// t = pqy*(a.getX()-q.getX()) - pqx*(a.getY()-q.getY() ); +// t /= pqx*(b.getY()-a.getY()) - pqy*(b.getX()-a.getX()); +// bax = t*(b.getX()-a.getX()) + a.getX(); +// bay = t*(b.getY()-a.getY()) + a.getY(); +// return new TPoint( bax, bay ); +// } + + public TriangulationPoint getP() + { + return p; + } + + public TriangulationPoint getQ() + { + return q; + } +} diff --git a/src/main/java/org/poly2tri/triangulation/delaunay/sweep/DTSweepContext.java b/src/main/java/org/poly2tri/triangulation/delaunay/sweep/DTSweepContext.java new file mode 100644 index 0000000..4605479 --- /dev/null +++ b/src/main/java/org/poly2tri/triangulation/delaunay/sweep/DTSweepContext.java @@ -0,0 +1,280 @@ +/* Poly2Tri + * Copyright (c) 2009-2010, Poly2Tri Contributors + * http://code.google.com/p/poly2tri/ + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of Poly2Tri nor the names of its contributors may be + * used to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.poly2tri.triangulation.delaunay.sweep; + +import java.util.ArrayDeque; +import java.util.Collections; +import org.poly2tri.triangulation.Triangulatable; +import org.poly2tri.triangulation.TriangulationAlgorithm; +import org.poly2tri.triangulation.TriangulationConstraint; +import org.poly2tri.triangulation.TriangulationContext; +import org.poly2tri.triangulation.TriangulationPoint; +import org.poly2tri.triangulation.delaunay.DelaunayTriangle; +import org.poly2tri.triangulation.point.TPoint; + +/** + * + * @author Thomas Åhlén, thahlen@gmail.com + * + */ +public class DTSweepContext extends TriangulationContext +{ + + // Inital triangle factor, seed triangle will extend 30% of + // PointSet width to both left and right. + private final float ALPHA = 0.3f; + + /** Advancing front **/ + protected AdvancingFront aFront; + /** head point used with advancing front */ + private TriangulationPoint _head; + /** tail point used with advancing front */ + private TriangulationPoint _tail; + protected Basin basin = new Basin(); + protected EdgeEvent edgeEvent = new EdgeEvent(); + + private DTSweepPointComparator _comparator = new DTSweepPointComparator(); + + public DTSweepContext() + { + clear(); + } + + public void isDebugEnabled( boolean b ) + { + if( b ) + { + if( _debug == null ) + { + _debug = new DTSweepDebugContext(this); + } + } + _debugEnabled = b; + } + + public void removeFromList( DelaunayTriangle triangle ) + { + _triList.remove( triangle ); + // TODO: remove all neighbor pointers to this triangle +// for( int i=0; i<3; i++ ) +// { +// if( triangle.neighbors[i] != null ) +// { +// triangle.neighbors[i].clearNeighbor( triangle ); +// } +// } +// triangle.clearNeighbors(); + } + + protected void meshClean(DelaunayTriangle triangle) + { + DelaunayTriangle t1,t2; + if( triangle != null ) + { + ArrayDeque deque = new ArrayDeque(); + deque.addFirst(triangle); + triangle.isInterior(true); + + while( !deque.isEmpty() ) + { + t1 = deque.removeFirst(); + _triUnit.addTriangle( t1 ); + for( int i=0; i<3; ++i ) + { + if( !t1.cEdge[i] ) + { + t2 = t1.neighbors[i]; + if( t2 != null && !t2.isInterior() ) + { + t2.isInterior(true); + deque.addLast(t2); + } + } + } + } + } + } + + public void clear() + { + super.clear(); + _triList.clear(); + } + + public AdvancingFront getAdvancingFront() + { + return aFront; + } + + public void setHead( TriangulationPoint p1 ) { _head = p1; } + public TriangulationPoint getHead() { return _head; } + + public void setTail( TriangulationPoint p1 ) { _tail = p1; } + public TriangulationPoint getTail() { return _tail; } + + public void addNode( AdvancingFrontNode node ) + { +// System.out.println( "add:" + node.key + ":" + System.identityHashCode(node.key)); +// m_nodeTree.put( node.getKey(), node ); + aFront.addNode( node ); + } + + public void removeNode( AdvancingFrontNode node ) + { +// System.out.println( "remove:" + node.key + ":" + System.identityHashCode(node.key)); +// m_nodeTree.delete( node.getKey() ); + aFront.removeNode( node ); + } + + public AdvancingFrontNode locateNode( TriangulationPoint point ) + { + return aFront.locateNode( point ); + } + + public void createAdvancingFront() + { + AdvancingFrontNode head,tail,middle; + // Initial triangle + DelaunayTriangle iTriangle = new DelaunayTriangle( _points.get(0), + getTail(), + getHead() ); + addToList( iTriangle ); + + head = new AdvancingFrontNode( iTriangle.points[1] ); + head.triangle = iTriangle; + middle = new AdvancingFrontNode( iTriangle.points[0] ); + middle.triangle = iTriangle; + tail = new AdvancingFrontNode( iTriangle.points[2] ); + + aFront = new AdvancingFront( head, tail ); + aFront.addNode( middle ); + + // TODO: I think it would be more intuitive if head is middles next and not previous + // so swap head and tail + aFront.head.next = middle; + middle.next = aFront.tail; + middle.prev = aFront.head; + aFront.tail.prev = middle; + } + + class Basin + { + AdvancingFrontNode leftNode; + AdvancingFrontNode bottomNode; + AdvancingFrontNode rightNode; + public double width; + public boolean leftHighest; + } + + class EdgeEvent + { + DTSweepConstraint constrainedEdge; + public boolean right; + } + + /** + * Try to map a node to all sides of this triangle that don't have + * a neighbor. + * + * @param t + */ + public void mapTriangleToNodes( DelaunayTriangle t ) + { + AdvancingFrontNode n; + for( int i=0; i<3; i++ ) + { + if( t.neighbors[i] == null ) + { + n = aFront.locatePoint( t.pointCW( t.points[i] ) ); + if( n != null ) + { + n.triangle = t; + } + } + } + } + + @Override + public void prepareTriangulation( Triangulatable t ) + { + super.prepareTriangulation( t ); + + double xmax, xmin; + double ymax, ymin; + + xmax = xmin = _points.get(0).getX(); + ymax = ymin = _points.get(0).getY(); + // Calculate bounds. Should be combined with the sorting + for( TriangulationPoint p : _points ) + { + if( p.getX() > xmax ) + xmax = p.getX(); + if( p.getX() < xmin ) + xmin = p.getX(); + if( p.getY() > ymax ) + ymax = p.getY(); + if( p.getY() < ymin ) + ymin = p.getY(); + } + + double deltaX = ALPHA * ( xmax - xmin ); + double deltaY = ALPHA * ( ymax - ymin ); + TPoint p1 = new TPoint( xmax + deltaX, ymin - deltaY ); + TPoint p2 = new TPoint( xmin - deltaX, ymin - deltaY ); + + setHead( p1 ); + setTail( p2 ); + +// long time = System.nanoTime(); + // Sort the points along y-axis + Collections.sort( _points, _comparator ); +// logger.info( "Triangulation setup [{}ms]", ( System.nanoTime() - time ) / 1e6 ); + } + + + public void finalizeTriangulation() + { + _triUnit.addTriangles( _triList ); + _triList.clear(); + } + + @Override + public TriangulationConstraint newConstraint( TriangulationPoint a, TriangulationPoint b ) + { + return new DTSweepConstraint( a, b ); + } + + @Override + public TriangulationAlgorithm algorithm() + { + return TriangulationAlgorithm.DTSweep; + } +} diff --git a/src/main/java/org/poly2tri/triangulation/delaunay/sweep/DTSweepDebugContext.java b/src/main/java/org/poly2tri/triangulation/delaunay/sweep/DTSweepDebugContext.java new file mode 100644 index 0000000..103815f --- /dev/null +++ b/src/main/java/org/poly2tri/triangulation/delaunay/sweep/DTSweepDebugContext.java @@ -0,0 +1,105 @@ +package org.poly2tri.triangulation.delaunay.sweep; + +import org.poly2tri.triangulation.TriangulationContext; +import org.poly2tri.triangulation.TriangulationDebugContext; +import org.poly2tri.triangulation.TriangulationPoint; +import org.poly2tri.triangulation.delaunay.DelaunayTriangle; + +public class DTSweepDebugContext extends TriangulationDebugContext +{ + /* + * Fields used for visual representation of current triangulation + */ + protected DelaunayTriangle _primaryTriangle; + protected DelaunayTriangle _secondaryTriangle; + protected TriangulationPoint _activePoint; + protected AdvancingFrontNode _activeNode; + protected DTSweepConstraint _activeConstraint; + + public DTSweepDebugContext( DTSweepContext tcx ) + { + super( tcx ); + } + + public boolean isDebugContext() + { + return true; + } + + // private Tuple2 m_circumCircle = new Tuple2( new TPoint(), new Double(0) ); +// public Tuple2 getCircumCircle() { return m_circumCircle; } + public DelaunayTriangle getPrimaryTriangle() + { + return _primaryTriangle; + } + + public DelaunayTriangle getSecondaryTriangle() + { + return _secondaryTriangle; + } + + public AdvancingFrontNode getActiveNode() + { + return _activeNode; + } + + public DTSweepConstraint getActiveConstraint() + { + return _activeConstraint; + } + + public TriangulationPoint getActivePoint() + { + return _activePoint; + } + + public void setPrimaryTriangle( DelaunayTriangle triangle ) + { + _primaryTriangle = triangle; + _tcx.update("setPrimaryTriangle"); + } + + public void setSecondaryTriangle( DelaunayTriangle triangle ) + { + _secondaryTriangle = triangle; + _tcx.update("setSecondaryTriangle"); + } + + public void setActivePoint( TriangulationPoint point ) + { + _activePoint = point; + } + + public void setActiveConstraint( DTSweepConstraint e ) + { + _activeConstraint = e; + _tcx.update("setWorkingSegment"); + } + + public void setActiveNode( AdvancingFrontNode node ) + { + _activeNode = node; + _tcx.update("setWorkingNode"); + } + + @Override + public void clear() + { + _primaryTriangle = null; + _secondaryTriangle = null; + _activePoint = null; + _activeNode = null; + _activeConstraint = null; + } + +// public void setWorkingCircumCircle( TPoint point, TPoint point2, TPoint point3 ) +// { +// double dx,dy; +// +// CircleXY.circumCenter( point, point2, point3, m_circumCircle.a ); +// dx = m_circumCircle.a.getX()-point.getX(); +// dy = m_circumCircle.a.getY()-point.getY(); +// m_circumCircle.b = Double.valueOf( Math.sqrt( dx*dx + dy*dy ) ); +// +// } +} diff --git a/src/main/java/org/poly2tri/triangulation/delaunay/sweep/DTSweepPointComparator.java b/src/main/java/org/poly2tri/triangulation/delaunay/sweep/DTSweepPointComparator.java new file mode 100644 index 0000000..65e1754 --- /dev/null +++ b/src/main/java/org/poly2tri/triangulation/delaunay/sweep/DTSweepPointComparator.java @@ -0,0 +1,35 @@ +package org.poly2tri.triangulation.delaunay.sweep; + +import java.util.Comparator; + +import org.poly2tri.triangulation.TriangulationPoint; + +public class DTSweepPointComparator implements Comparator +{ + public int compare( TriangulationPoint p1, TriangulationPoint p2 ) + { + if(p1.getY() < p2.getY() ) + { + return -1; + } + else if( p1.getY() > p2.getY()) + { + return 1; + } + else + { + if(p1.getX() < p2.getX()) + { + return -1; + } + else if( p1.getX() > p2.getX() ) + { + return 1; + } + else + { + return 0; + } + } + } +} diff --git a/src/main/java/org/poly2tri/triangulation/delaunay/sweep/PointOnEdgeException.java b/src/main/java/org/poly2tri/triangulation/delaunay/sweep/PointOnEdgeException.java new file mode 100644 index 0000000..dfc4467 --- /dev/null +++ b/src/main/java/org/poly2tri/triangulation/delaunay/sweep/PointOnEdgeException.java @@ -0,0 +1,15 @@ +package org.poly2tri.triangulation.delaunay.sweep; + +public class PointOnEdgeException extends RuntimeException +{ + + /** + * + */ + private static final long serialVersionUID = 1L; + + public PointOnEdgeException( String msg ) + { + super(msg); + } +} diff --git a/src/main/java/org/poly2tri/triangulation/point/FloatBufferPoint.java b/src/main/java/org/poly2tri/triangulation/point/FloatBufferPoint.java new file mode 100644 index 0000000..ad815fc --- /dev/null +++ b/src/main/java/org/poly2tri/triangulation/point/FloatBufferPoint.java @@ -0,0 +1,94 @@ +/* Poly2Tri + * Copyright (c) 2009-2010, Poly2Tri Contributors + * http://code.google.com/p/poly2tri/ + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of Poly2Tri nor the names of its contributors may be + * used to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.poly2tri.triangulation.point; + +import java.nio.FloatBuffer; + +import org.poly2tri.triangulation.TriangulationPoint; + + +public class FloatBufferPoint extends TriangulationPoint +{ + private final FloatBuffer _fb; + private final int _ix,_iy,_iz; + + public FloatBufferPoint( FloatBuffer fb, int index ) + { + _fb = fb; + _ix = index; + _iy = index+1; + _iz = index+2; + } + + public final double getX() + { + return _fb.get( _ix ); + } + public final double getY() + { + return _fb.get( _iy ); + } + public final double getZ() + { + return _fb.get( _iz ); + } + + public final float getXf() + { + return _fb.get( _ix ); + } + public final float getYf() + { + return _fb.get( _iy ); + } + public final float getZf() + { + return _fb.get( _iz ); + } + + @Override + public void set( double x, double y, double z ) + { + _fb.put( _ix, (float)x ); + _fb.put( _iy, (float)y ); + _fb.put( _iz, (float)z ); + } + + public static TriangulationPoint[] toPoints( FloatBuffer fb ) + { + FloatBufferPoint[] points = new FloatBufferPoint[fb.limit()/3]; + for( int i=0,j=0; i + * A constraint defines an edge between two points in the set, these edges can not + * be crossed. They will be enforced triangle edges after a triangulation. + *

+ * + * + * @author Thomas Åhlén, thahlen@gmail.com + */ +public class ConstrainedPointSet extends PointSet +{ + int[] _index; + List _constrainedPointList = null; + + public ConstrainedPointSet( List points, int[] index ) + { + super( points ); + _index = index; + } + + /** + * + * @param points - A list of all points in PointSet + * @param constraints - Pairs of two points defining a constraint, all points must be part of given PointSet! + */ + public ConstrainedPointSet( List points, List constraints ) + { + super( points ); + _constrainedPointList = new ArrayList(); + _constrainedPointList.addAll(constraints); + } + + @Override + public TriangulationMode getTriangulationMode() + { + return TriangulationMode.CONSTRAINED; + } + + public int[] getEdgeIndex() + { + return _index; + } + + @SuppressWarnings("unchecked") + @Override + public void prepareTriangulation( TriangulationContext tcx ) + { + super.prepareTriangulation( tcx ); + if( _constrainedPointList != null ) + { + TriangulationPoint p1,p2; + Iterator iterator = _constrainedPointList.iterator(); + while(iterator.hasNext()) + { + p1 = (TriangulationPoint)iterator.next(); + p2 = (TriangulationPoint)iterator.next(); + tcx.newConstraint(p1,p2); + } + } + else + { + for( int i = 0; i < _index.length; i+=2 ) + { + // XXX: must change!! + tcx.newConstraint( _points.get( _index[i] ), _points.get( _index[i+1] ) ); + } + } + } + + /** + * TODO: TO BE IMPLEMENTED! + * Peforms a validation on given input
+ * 1. Check's if there any constraint edges are crossing or collinear
+ * 2. + * @return + */ + public boolean isValid() + { + return true; + } +} diff --git a/src/main/java/org/poly2tri/triangulation/sets/PointSet.java b/src/main/java/org/poly2tri/triangulation/sets/PointSet.java new file mode 100644 index 0000000..d4ff5b6 --- /dev/null +++ b/src/main/java/org/poly2tri/triangulation/sets/PointSet.java @@ -0,0 +1,95 @@ +/* Poly2Tri + * Copyright (c) 2009-2010, Poly2Tri Contributors + * http://code.google.com/p/poly2tri/ + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of Poly2Tri nor the names of its contributors may be + * used to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.poly2tri.triangulation.sets; + +import java.util.ArrayList; +import java.util.List; + +import org.poly2tri.triangulation.Triangulatable; +import org.poly2tri.triangulation.TriangulationContext; +import org.poly2tri.triangulation.TriangulationMode; +import org.poly2tri.triangulation.TriangulationPoint; +import org.poly2tri.triangulation.delaunay.DelaunayTriangle; + +public class PointSet implements Triangulatable +{ + List _points; + List _triangles; + + public PointSet( List points ) + { + _points = new ArrayList(); + _points.addAll( points ); + } + + public TriangulationMode getTriangulationMode() + { + return TriangulationMode.UNCONSTRAINED; + } + + public List getPoints() + { + return _points; + } + + public List getTriangles() + { + return _triangles; + } + + public void addTriangle( DelaunayTriangle t ) + { + _triangles.add( t ); + } + + public void addTriangles( List list ) + { + _triangles.addAll( list ); + } + + public void clearTriangulation() + { + _triangles.clear(); + } + + public void prepareTriangulation( TriangulationContext tcx ) + { + if( _triangles == null ) + { + _triangles = new ArrayList( _points.size() ); + } + else + { + _triangles.clear(); + } + tcx.addPoints( _points ); + } +} diff --git a/src/main/java/org/poly2tri/triangulation/util/PointGenerator.java b/src/main/java/org/poly2tri/triangulation/util/PointGenerator.java new file mode 100644 index 0000000..baf2c17 --- /dev/null +++ b/src/main/java/org/poly2tri/triangulation/util/PointGenerator.java @@ -0,0 +1,38 @@ +package org.poly2tri.triangulation.util; + +import java.util.ArrayList; +import java.util.List; + +import org.poly2tri.triangulation.TriangulationPoint; +import org.poly2tri.triangulation.point.TPoint; + +public class PointGenerator +{ + public static List uniformDistribution( int n, double scale ) + { + ArrayList points = new ArrayList(); + for( int i=0; i uniformGrid( int n, double scale ) + { + double x=0; + double size = scale/n; + double halfScale = 0.5*scale; + + ArrayList points = new ArrayList(); + for( int i=0; i scale/2 ? scale/2 : radius; + radius = radius < scale/10 ? scale/10 : radius; + } while( radius < scale/10 || radius > scale/2 ); + point = new PolygonPoint( radius*Math.cos( (PI_2*i)/vertexCount ), + radius*Math.sin( (PI_2*i)/vertexCount ) ); + points[i] = point; + } + return new Polygon( points ); + } + + public static Polygon RandomCircleSweep2( double scale, int vertexCount ) + { + PolygonPoint point; + PolygonPoint[] points; + double radius = scale/4; + + points = new PolygonPoint[vertexCount]; + for(int i=0; i scale/2 ? scale/2 : radius; + radius = radius < scale/10 ? scale/10 : radius; + } while( radius < scale/10 || radius > scale/2 ); + point = new PolygonPoint( radius*Math.cos( (PI_2*i)/vertexCount ), + radius*Math.sin( (PI_2*i)/vertexCount ) ); + points[i] = point; + } + return new Polygon( points ); + } +} diff --git a/src/main/java/org/poly2tri/triangulation/util/QuadTreeRefinement.java b/src/main/java/org/poly2tri/triangulation/util/QuadTreeRefinement.java new file mode 100644 index 0000000..f3ab2ed --- /dev/null +++ b/src/main/java/org/poly2tri/triangulation/util/QuadTreeRefinement.java @@ -0,0 +1,17 @@ +package org.poly2tri.triangulation.util; + +import org.poly2tri.geometry.polygon.Polygon; + +/** + * Use a QuadTree traversal to add steiner points + * inside the polygon that needs refinement + * + * @author thahlen@gmail.com + */ +public class QuadTreeRefinement +{ + public static final void refine( Polygon p, int depth ) + { + + } +} diff --git a/src/main/java/org/poly2tri/triangulation/util/Tuple2.java b/src/main/java/org/poly2tri/triangulation/util/Tuple2.java new file mode 100644 index 0000000..4c5fa7d --- /dev/null +++ b/src/main/java/org/poly2tri/triangulation/util/Tuple2.java @@ -0,0 +1,43 @@ +/* Poly2Tri + * Copyright (c) 2009-2010, Poly2Tri Contributors + * http://code.google.com/p/poly2tri/ + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of Poly2Tri nor the names of its contributors may be + * used to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.poly2tri.triangulation.util; + +public class Tuple2 +{ + public A a; + public B b; + + public Tuple2(A a,B b) + { + this.a = a; + this.b = b; + } +} diff --git a/src/main/java/org/poly2tri/triangulation/util/Tuple3.java b/src/main/java/org/poly2tri/triangulation/util/Tuple3.java new file mode 100644 index 0000000..b81d8a5 --- /dev/null +++ b/src/main/java/org/poly2tri/triangulation/util/Tuple3.java @@ -0,0 +1,45 @@ +/* Poly2Tri + * Copyright (c) 2009-2010, Poly2Tri Contributors + * http://code.google.com/p/poly2tri/ + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of Poly2Tri nor the names of its contributors may be + * used to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.poly2tri.triangulation.util; + +public class Tuple3 +{ + public A a; + public B b; + public C c; + + public Tuple3(A a,B b,C c) + { + this.a = a; + this.b = b; + this.c = c; + } +} diff --git a/src/main/resources/assets/dimdoors/RIFT.png b/src/main/resources/assets/dimdoors/RIFT.png deleted file mode 100644 index ae24e83..0000000 Binary files a/src/main/resources/assets/dimdoors/RIFT.png and /dev/null differ diff --git a/src/main/resources/assets/dimdoors/WARP.png b/src/main/resources/assets/dimdoors/WARP.png deleted file mode 100644 index fd8efb2..0000000 Binary files a/src/main/resources/assets/dimdoors/WARP.png and /dev/null differ diff --git a/src/main/resources/assets/dimdoors/sound/doorLockRemoved.mp3 b/src/main/resources/assets/dimdoors/sound/doorLockRemoved.mp3 new file mode 100644 index 0000000..d7f1ec2 Binary files /dev/null and b/src/main/resources/assets/dimdoors/sound/doorLockRemoved.mp3 differ diff --git a/src/main/resources/assets/dimdoors/sound/doorLockRemoved.ogg b/src/main/resources/assets/dimdoors/sound/doorLockRemoved.ogg new file mode 100644 index 0000000..dbdbca6 Binary files /dev/null and b/src/main/resources/assets/dimdoors/sound/doorLockRemoved.ogg differ diff --git a/src/main/resources/assets/dimdoors/sound/doorLocked.mp3 b/src/main/resources/assets/dimdoors/sound/doorLocked.mp3 new file mode 100644 index 0000000..79bbc6a Binary files /dev/null and b/src/main/resources/assets/dimdoors/sound/doorLocked.mp3 differ diff --git a/src/main/resources/assets/dimdoors/sound/doorLocked.ogg b/src/main/resources/assets/dimdoors/sound/doorLocked.ogg new file mode 100644 index 0000000..19c104c Binary files /dev/null and b/src/main/resources/assets/dimdoors/sound/doorLocked.ogg differ diff --git a/src/main/resources/assets/dimdoors/sound/keyLock.mp3 b/src/main/resources/assets/dimdoors/sound/keyLock.mp3 new file mode 100644 index 0000000..ae52ae9 Binary files /dev/null and b/src/main/resources/assets/dimdoors/sound/keyLock.mp3 differ diff --git a/src/main/resources/assets/dimdoors/sound/keyLock.ogg b/src/main/resources/assets/dimdoors/sound/keyLock.ogg new file mode 100644 index 0000000..c63ede2 Binary files /dev/null and b/src/main/resources/assets/dimdoors/sound/keyLock.ogg differ diff --git a/src/main/resources/assets/dimdoors/sound/keyUnlock.mp3 b/src/main/resources/assets/dimdoors/sound/keyUnlock.mp3 new file mode 100644 index 0000000..7845146 Binary files /dev/null and b/src/main/resources/assets/dimdoors/sound/keyUnlock.mp3 differ diff --git a/src/main/resources/assets/dimdoors/sound/keyUnlock.ogg b/src/main/resources/assets/dimdoors/sound/keyUnlock.ogg new file mode 100644 index 0000000..910bee5 Binary files /dev/null and b/src/main/resources/assets/dimdoors/sound/keyUnlock.ogg differ diff --git a/src/main/resources/assets/dimdoors/sound/monkLarge.ogg b/src/main/resources/assets/dimdoors/sound/monkLarge.ogg deleted file mode 100644 index 73e69b4..0000000 Binary files a/src/main/resources/assets/dimdoors/sound/monkLarge.ogg and /dev/null differ diff --git a/src/main/resources/assets/dimdoors/text/Dim_Data_Schema_v1-0-0.json b/src/main/resources/assets/dimdoors/text/Dim_Data_Schema_v1-0-0.json new file mode 100644 index 0000000..c08afe0 --- /dev/null +++ b/src/main/resources/assets/dimdoors/text/Dim_Data_Schema_v1-0-0.json @@ -0,0 +1,245 @@ +{ + "type":"object", + "$schema": "http://json-schema.org/draft-04/schema", + + "description": "A serialized Dim Data object", + "properties":{ + "ChildIDs": { + "type":"array", + "items": { + "type": "number" + } + }, + "Depth": { + "type":"number" + }, + "ID": { + "type":"number" + }, + "DimensionType": { + "type":"number" + }, + "IsFilled": { + "type":"boolean" + }, + "DungeonData": { + "type": "object", + + "properties": { + "Weight": { + "type": "number" + }, + "IsOpen": { + "type": "boolean" + }, + "IsInternal": { + "type": "boolean" + }, + "SchematicPath": { + "type": "string" + }, + "SchematicName": { + "type": "string" + }, + "DungeonTypeName": { + "type": "string" + }, + "DungeonPackName": { + "type": "string" + } + }, + "required": [ + "Weight", + "IsOpen", + "IsInternal", + "SchematicPath", + "SchematicName", + "DungeonTypeName", + "DungeonPackName" + ] + }, + "Links": { + "type":"array", + "items": { + "type": "object", + "properties": { + "children": { + "type":"array", + "items":{ + "type": "object", + "properties":{ + "x": { + "type": "integer" + }, + "y": { + "type": "integer" + }, + "z": { + "type": "integer" + } + }, + "required": [ + "x", + "y", + "z" + ] + } + }, + "orientation": { + "type": "number" + }, + "source": { + "type": "object", + "properties": { + "x": { + "type": "integer" + }, + "y": { + "type": "integer" + }, + "z": { + "type": "integer" + }, + "dimension": { + "type": "integer" + } + }, + "required": [ + "x", + "y", + "z", + "dimension" + ] + }, + "parent": { + "type": "object", + "properties": { + "x": { + "type": "integer" + }, + "y": { + "type": "integer" + }, + "z": { + "type": "integer" + } + }, + "required": [ + "x", + "y", + "z" + ] + }, + "tail": { + "type": "object", + "properties": { + "linkType" : { + "type": "number" + }, + "destination":{ + "type": "object", + "properties": { + "x": { + "type": "integer" + }, + "y": { + "type": "integer" + }, + "z": { + "type": "integer" + }, + "dimension": { + "type": "integer" + } + }, + "required": [ + "x", + "y", + "z", + "dimension" + ] + } + }, + "required": [ + "linkType" + ] + }, + "lock":{ + "type": "object", + "properties": { + "lockState": { + "type": "boolean" + }, + "lockKey": { + "type": "number" + } + }, + "required": [ + "lockState", + "lockKey" + ] + + } + }, + "required": [ + "children", + "orientation", + "source", + "parent", + "tail" + ] + } + }, + "Orientation": { + "type":"number" + }, + "Origin": { + "type":"object", + "properties":{ + "x": { + "type":"number" + }, + "y": { + "type":"number" + }, + "z": { + "type":"number" + } + }, + "required": [ + "x", + "y", + "z" + ] + }, + "PackDepth": { + "type":"number" + }, + "ParentID": { + "type":"number" + }, + "RootID": { + "type":"number" + }, + "SAVE_DATA_VERSION_ID_INSTANCE": { + "type":"number" + }, + "Tails": { + "type":"array" + } + }, + "required": ["Tails", + "SAVE_DATA_VERSION_ID_INSTANCE", + "RootID", + "ParentID", + "PackDepth", + "Origin", + "Orientation", + "Links", + "IsFilled", + "ID", + "DimensionType", + "Depth", + "ChildIDs" + ] +} diff --git a/src/main/resources/assets/dimdoors/text/Dim_Data_Schema_v982405775.json b/src/main/resources/assets/dimdoors/text/Dim_Data_Schema_v982405775.json new file mode 100644 index 0000000..2fa616d --- /dev/null +++ b/src/main/resources/assets/dimdoors/text/Dim_Data_Schema_v982405775.json @@ -0,0 +1,245 @@ +{ + "type":"object", + "$schema": "http://json-schema.org/draft-04/schema", + + "description": "A serialized Dim Data object", + "properties":{ + "ChildIDs": { + "type":"array", + "items": { + "type": "number" + } + }, + "Depth": { + "type":"number" + }, + "ID": { + "type":"number" + }, + "IsDungeon": { + "type":"boolean" + }, + "IsFilled": { + "type":"boolean" + }, + "DungeonData": { + "type": "object", + + "properties": { + "Weight": { + "type": "number" + }, + "IsOpen": { + "type": "boolean" + }, + "IsInternal": { + "type": "boolean" + }, + "SchematicPath": { + "type": "string" + }, + "SchematicName": { + "type": "string" + }, + "DungeonTypeName": { + "type": "string" + }, + "DungeonPackName": { + "type": "string" + } + }, + "required": [ + "Weight", + "IsOpen", + "IsInternal", + "SchematicPath", + "SchematicName", + "DungeonTypeName", + "DungeonPackName" + ] + }, + "Links": { + "type":"array", + "items": { + "type": "object", + "properties": { + "children": { + "type":"array", + "items":{ + "type": "object", + "properties":{ + "x": { + "type": "integer" + }, + "y": { + "type": "integer" + }, + "z": { + "type": "integer" + } + }, + "required": [ + "x", + "y", + "z" + ] + } + }, + "orientation": { + "type": "number" + }, + "source": { + "type": "object", + "properties": { + "x": { + "type": "integer" + }, + "y": { + "type": "integer" + }, + "z": { + "type": "integer" + }, + "dimension": { + "type": "integer" + } + }, + "required": [ + "x", + "y", + "z", + "dimension" + ] + }, + "parent": { + "type": "object", + "properties": { + "x": { + "type": "integer" + }, + "y": { + "type": "integer" + }, + "z": { + "type": "integer" + } + }, + "required": [ + "x", + "y", + "z" + ] + }, + "tail": { + "type": "object", + "properties": { + "linkType" : { + "type": "number" + }, + "destination":{ + "type": "object", + "properties": { + "x": { + "type": "integer" + }, + "y": { + "type": "integer" + }, + "z": { + "type": "integer" + }, + "dimension": { + "type": "integer" + } + }, + "required": [ + "x", + "y", + "z", + "dimension" + ] + } + }, + "required": [ + "linkType" + ] + }, + "lock":{ + "type": "object", + "properties": { + "lockState": { + "type": "boolean" + }, + "lockKey": { + "type": "number" + } + }, + "required": [ + "lockState", + "lockKey" + ] + + } + }, + "required": [ + "children", + "orientation", + "source", + "parent", + "tail" + ] + } + }, + "Orientation": { + "type":"number" + }, + "Origin": { + "type":"object", + "properties":{ + "x": { + "type":"number" + }, + "y": { + "type":"number" + }, + "z": { + "type":"number" + } + }, + "required": [ + "x", + "y", + "z" + ] + }, + "PackDepth": { + "type":"number" + }, + "ParentID": { + "type":"number" + }, + "RootID": { + "type":"number" + }, + "SAVE_DATA_VERSION_ID_INSTANCE": { + "type":"number" + }, + "Tails": { + "type":"array" + } + }, + "required": ["Tails", + "SAVE_DATA_VERSION_ID_INSTANCE", + "RootID", + "ParentID", + "PackDepth", + "Origin", + "Orientation", + "Links", + "IsFilled", + "ID", + "IsDungeon", + "Depth", + "ChildIDs" + ] +} diff --git a/src/main/resources/assets/dimdoors/text/How_to_add_dungeons.txt b/src/main/resources/assets/dimdoors/text/How_to_add_dungeons.txt index c361d91..254245c 100644 --- a/src/main/resources/assets/dimdoors/text/How_to_add_dungeons.txt +++ b/src/main/resources/assets/dimdoors/text/How_to_add_dungeons.txt @@ -1,51 +1,70 @@ -Adding dungeons is pretty simple, but you have to know the various flags and stuff I use to read them in and build them. Ill walk you through the process here, and provide all the flags and a breif description of what they mean here. +This guide explains the simple details involved in creating your own dungeons. -To get started, run Minecraft with DimDoors installed and use the "/dd-create" command. +[CREATING YOUR BUILDING AREA] -This will generate an empty pocket dim for you to build with that is in the proper orientation (north). If you do not use this command, you WILL run into issues later. +To get started, run Minecraft with Dimensional Doors installed and use the command "/dd-create". This will create an empty pocket dimension for you to build in. It used to be necessary to use this command to ensure that the resulting room was oriented properly for exporting. That's no longer the case; you can now create pockets in any way and they'll also work fine. -So on to the building- You can ONLY use vanilla blocks in the dungeons. Everything that is not vanilla MC will be turned into fabric of reality when I gen them, or it will crash horribly. The only exceptions to this are DimDoors doors, which will be treated like mundane, vanilla doors of the same material. +[CHOOSING YOUR BUILDING MATERIALS] -The first step is to make your entrance door. This is where the player will appear when they teleport in for the first time. It is marked by a vanilla wooden door. It will be replaced by a wooden warp door on generation, and by default is set as the door you entered from. +You can ONLY build a dungeon using regular Minecraft blocks and some Dimensional Doors blocks. Everything that is not a regular Minecrat block or part of the acceptable Dimensional Doors blocks will be turned into Fabric of Reality during both exporting and importing of the dungeon. This is a safety precaution against potentially serious crashes. The permitted blocks from Dimensional Doors are: -As you build your dungeon, there are a few restrictions. Any chests you place will get filled with random loot, and not what you place in them. Any dispensers will get a few stacks of arrows. Other than that, any vanilla mechanics should work fine, except rails. I'm working on that now, as well as saving inventories. +Fabric of Reality, Ancient Fabric, Eternal Fabric, Warp Doors, Dimensional Doors, and Transient Doors -Any iron doors you place will become iron dim doors, and link to more dungeon pockets, so use these to make your dungeon lead farther into a dungeon chain. +Transient doors are only intended for use with Rift Gateway designs and may not be assigned a destination if loaded in a dungeon. Also note that rifts are not in the permitted list and will be filtered out. Entities (e.g. mobs, minecarts, items frames, and dropped items) will not be imported or exported either. -If you want your dungeon to link back the Overworld, place a wooden door on top of a Sandstone block. This will mark it as an exit door, and it will generate as a wooden Dim door leading to the Overworld (or whatever dim this chain started in). The sandstone block will become whatever is under it. +Previously, builders would have to use regular Minecraft doors and those would be converted into Warp Doors and Dimensional Doors when a design was imported. That behavior was changed to that players could use regular doors within their designs. All dimensional doors will be reset upon importing so creating paths within a single room is currently not possible. -Once you have finished creating your dungeon, you need to use the command "/dd-export " +[BUILDING YOUR DUNGEON] -To name it, use the following format: +The first step is to place the entrance door. That is where the player will appear when they teleport in for the first time. It is designated using a Warp Door. Any dungeon without an entrance door will fail to load. -___ +You can place Dimensinoal Doors to connect your room to other rooms. You only have to place the doors where you want them. The doors will be linked to other rooms automatically whenever a player steps through. -DungeonType: The dungeon types are "Hub", "SimpleHall", "ComplexHall", "Trap', "Maze", "Exit", and "DeadEnd'. +You can also place Warp Doors to act as exits to the Overworld and other dimensions. Their destinations will be assigned automatically whenever a player steps through. Note that there is an extra step involved for this. Any exit doors must have a block of regular sandstone underneath to make the proper entrance clear. If you forget to place the sandstone block, then the mod may select one of your exit doors as the entrance. The mod will also automatically replace the sandstone block with the block underneath it. - Hub: Dungeons that have 4 or more iron doors in them should be labeled as hubs, so they don't generate one after another. +Any empty chests or trapped chests will be loaded with loot automatically when the dungeon is imported. Chests or trapped chests with contents already will not be affected. Be sure not to leave loot inside your chests if you import and re-export any of your designs; this is a common mistake. - SimpleHall: Dungeons that contain a single iron door or two, but no more than that, and don't contain traps. These are the halls that separate rooms and should generally be tagged as 'closed'. +It used to be that empty dispensers would be filled automatically with a stack of arrows. That was needed before when loaded inventories could not be exported. Now that feature has been removed for added flexibility - in case someone needs to have empty dispensers in their designs. - ComplexHall: These dungeons are more like rooms and can be open. They can have piston puzzles or locks, and up to three iron doors. In addition, they can contain wooden doors to link to the surface. +Finally, End Portal Frame blocks act as special markers. When the dungeon is imported, the blocks are removed and Monoliths are spawned in their place. This is used to manually set up Monolith positions to ensure that certain areas of a dungeon are protected. It's not usually necessary to use those markers because have ways of assigning them random positions in a dungeon (explained below). - Trap: These dungeons are primarily traps and often contain only a single iron door. The traps should never instantly kill the player, and it should be possible to beat them. They can contain either a reward/chest, or simply allow progress. Piston traps are very fun for these. +[EXPORTING YOUR DUNGEON] - Maze: These dungeons can contain up to 3 iron doors. They can be simple labyrinths or full of changing walls, etc. They should not, however, be primarily trying to kill the player, though they can have possibly lethal elements. In the worst case, think of it as half trap and half hub. +Once you have finished creating your dungeon, you need to export it as a schematic file with the command "/dd-export [SpawnWeight]" - Exit: The main purpose of these dungeons is to link back to Overworld with a wooden door. They should never contain iron doors. +The mod searches a 101 x 101 x 101 block cube (centered on the player's position) for blocks and chooses the smallest area that contains all of the blocks it finds. That area is then exported. Be careful about leaving garbage outside of the pocket in which you were building since it will be detected and exported along with everything else. - DeadEnd: Dungeons that have no other doors except the entrance. Usually contain some sort of treasure. +The following section explains each parameter for the command. + +DungeonType: The dungeon types for the default Ruins are "Hub", "SimpleHall", "ComplexHall", "Trap", "Exit", and "DeadEnd". + + Hub: Dungeons that have 4 or more iron doors in them should be labeled as hubs, so they don't generate one after another. + + SimpleHall: Dungeons that contain one or two Dimensional Doors, but no more than that, and don't contain traps. These are the halls that separate rooms and are generally "closed" rooms. + + ComplexHall: These dungeons are more like rooms than hallways and can be open. They can have piston puzzles or locks, and up to three Dimensional Doors. In addition, they can contain wooden doors to link to the surface. + + Trap: These dungeons are primarily traps and often contain only a single iron door. The traps should never instantly kill the player, and it should be possible to beat them. They can contain either a reward/chest, or simply allow progress. Piston traps are very fun for these. + + Exit: The main purpose of these dungeons is to link back to Overworld with a wooden door. They should never contain iron doors. + + DeadEnd: Dungeons that have no other doors except the entrance. Usually contain some sort of treasure. + +Note that there used to be a Maze type as well. That type was changed for internal use. Dungeon types are specific to each dungeon pack and other type names may apply for other packs. IsOpen: Indicates whether the dungeon is an open-air structure or a closed structure that should be surrounded by Monoliths. Monoliths prevent players from breaking out of closed structures to avoid puzzles or traps. The only valid values are "open" or "closed". SpawnWeight: An optional integer that determines how frequently you want the dungeon to appear relative to others of the same type. The default weight is 100. Higher values cause a dungeon to generate more often, while lower values cause it to be less common. The minimum weight is 0 and the maximum weight is 10,000. +-------------------------- -Examples: - Hub_RuinsWithDoors_Open_100 - SimpleHall_WindingHallway_Closed_50 - Trap_CleverTrap_Closed +You can also use the command "/dd-export override" to force the mod to export your surroundings as a schematic without following the naming restrictions above. This is useful for exporting a dungeon with a dungeon type that isn't part of Ruins. + +Examples names: + Hub_RuinsWithDoors_Open_100 + SimpleHall_WindingHallway_Closed_50 + Trap_CleverTrap_Closed Although you can deviate from the format above, the current dungeon generation system requires that format to work properly. It will not select schematics that do not follow those naming rules. -Congratulations! You have added your own dungeon. You can use the command "/dd-rift " to generate it, or use "/dd-rift list" to list all available dungeons. Finally, "/dd-rift random" will select a dungeon at random. \ No newline at end of file +Congratulations! You have added your own dungeon. You can use the command "/dd-rift " to generate it, or use "/dd-list" to list all available dungeons. diff --git a/src/main/resources/assets/dimdoors/textures/blocks/tile.Corium_flowing.png b/src/main/resources/assets/dimdoors/textures/blocks/tile.Corium_flowing.png deleted file mode 100644 index af07f91..0000000 Binary files a/src/main/resources/assets/dimdoors/textures/blocks/tile.Corium_flowing.png and /dev/null differ diff --git a/src/main/resources/assets/dimdoors/textures/blocks/tile.Corium_flowing.png.mcmeta b/src/main/resources/assets/dimdoors/textures/blocks/tile.Corium_flowing.png.mcmeta deleted file mode 100644 index b374392..0000000 --- a/src/main/resources/assets/dimdoors/textures/blocks/tile.Corium_flowing.png.mcmeta +++ /dev/null @@ -1,27 +0,0 @@ -{ - "animation": - { - "frametime": 3, - "frames": - [ - -0, -1, -2, -3, -4, -5, -6, -7, -8, -9, -10, -11, -12, -13, -14, -15 - - ] - } -} \ No newline at end of file diff --git a/src/main/resources/assets/dimdoors/textures/blocks/tile.Corium_still.png b/src/main/resources/assets/dimdoors/textures/blocks/tile.Corium_still.png deleted file mode 100644 index 78bb29d..0000000 Binary files a/src/main/resources/assets/dimdoors/textures/blocks/tile.Corium_still.png and /dev/null differ diff --git a/src/main/resources/assets/dimdoors/textures/blocks/tile.Corium_still.png.mcmeta b/src/main/resources/assets/dimdoors/textures/blocks/tile.Corium_still.png.mcmeta deleted file mode 100644 index 2b28937..0000000 --- a/src/main/resources/assets/dimdoors/textures/blocks/tile.Corium_still.png.mcmeta +++ /dev/null @@ -1,51 +0,0 @@ -{ - "animation": - { - "frametime": 3, - "frames": - [ - -0, -1, -2, -3, -4, -5, -6, -7, -8, -9, -10, -11, -12, -13, -14, -15, -16, -17, -18, -19, -18, -17, -16, -15, -14, -13, -12, -11, -10, -9, -8, -7, -6, -5, -4, -3, -2, -1 - - ] - } -} - - diff --git a/src/main/resources/assets/dimdoors/textures/blocks/tile.transientDoor_top.png b/src/main/resources/assets/dimdoors/textures/blocks/tile.blockDimWallPersonal.png similarity index 97% rename from src/main/resources/assets/dimdoors/textures/blocks/tile.transientDoor_top.png rename to src/main/resources/assets/dimdoors/textures/blocks/tile.blockDimWallPersonal.png index 8ceb7c9..0e9e7a4 100644 Binary files a/src/main/resources/assets/dimdoors/textures/blocks/tile.transientDoor_top.png and b/src/main/resources/assets/dimdoors/textures/blocks/tile.blockDimWallPersonal.png differ diff --git a/src/main/resources/assets/dimdoors/textures/blocks/tile.chaosDoor_bottom.png b/src/main/resources/assets/dimdoors/textures/blocks/tile.chaosDoor_lower.png similarity index 100% rename from src/main/resources/assets/dimdoors/textures/blocks/tile.chaosDoor_bottom.png rename to src/main/resources/assets/dimdoors/textures/blocks/tile.chaosDoor_lower.png diff --git a/src/main/resources/assets/dimdoors/textures/blocks/tile.chaosDoor_top.png b/src/main/resources/assets/dimdoors/textures/blocks/tile.chaosDoor_upper.png similarity index 100% rename from src/main/resources/assets/dimdoors/textures/blocks/tile.chaosDoor_top.png rename to src/main/resources/assets/dimdoors/textures/blocks/tile.chaosDoor_upper.png diff --git a/src/main/resources/assets/dimdoors/textures/blocks/tile.dimDoorGold_bottom.png b/src/main/resources/assets/dimdoors/textures/blocks/tile.dimDoorGold_lower.png similarity index 100% rename from src/main/resources/assets/dimdoors/textures/blocks/tile.dimDoorGold_bottom.png rename to src/main/resources/assets/dimdoors/textures/blocks/tile.dimDoorGold_lower.png diff --git a/src/main/resources/assets/dimdoors/textures/blocks/tile.dimDoorGold_top.png b/src/main/resources/assets/dimdoors/textures/blocks/tile.dimDoorGold_upper.png similarity index 100% rename from src/main/resources/assets/dimdoors/textures/blocks/tile.dimDoorGold_top.png rename to src/main/resources/assets/dimdoors/textures/blocks/tile.dimDoorGold_upper.png diff --git a/src/main/resources/assets/dimdoors/textures/blocks/tile.dimDoorPersonal_lower.png b/src/main/resources/assets/dimdoors/textures/blocks/tile.dimDoorPersonal_lower.png new file mode 100644 index 0000000..a1c590c Binary files /dev/null and b/src/main/resources/assets/dimdoors/textures/blocks/tile.dimDoorPersonal_lower.png differ diff --git a/src/main/resources/assets/dimdoors/textures/blocks/tile.dimDoorPersonal_upper.png b/src/main/resources/assets/dimdoors/textures/blocks/tile.dimDoorPersonal_upper.png new file mode 100644 index 0000000..e4c3d91 Binary files /dev/null and b/src/main/resources/assets/dimdoors/textures/blocks/tile.dimDoorPersonal_upper.png differ diff --git a/src/main/resources/assets/dimdoors/textures/blocks/tile.dimDoorWarp_bottom.png b/src/main/resources/assets/dimdoors/textures/blocks/tile.dimDoorWarp_lower.png similarity index 100% rename from src/main/resources/assets/dimdoors/textures/blocks/tile.dimDoorWarp_bottom.png rename to src/main/resources/assets/dimdoors/textures/blocks/tile.dimDoorWarp_lower.png diff --git a/src/main/resources/assets/dimdoors/textures/blocks/tile.dimDoorWarp_top.png b/src/main/resources/assets/dimdoors/textures/blocks/tile.dimDoorWarp_upper.png similarity index 100% rename from src/main/resources/assets/dimdoors/textures/blocks/tile.dimDoorWarp_top.png rename to src/main/resources/assets/dimdoors/textures/blocks/tile.dimDoorWarp_upper.png diff --git a/src/main/resources/assets/dimdoors/textures/blocks/tile.dimDoor_bottom.png b/src/main/resources/assets/dimdoors/textures/blocks/tile.dimDoor_bottom.png deleted file mode 100644 index 825356d..0000000 Binary files a/src/main/resources/assets/dimdoors/textures/blocks/tile.dimDoor_bottom.png and /dev/null differ diff --git a/src/main/resources/assets/dimdoors/textures/blocks/tile.dimDoorLink_bottom.png b/src/main/resources/assets/dimdoors/textures/blocks/tile.dimDoor_lower.png similarity index 100% rename from src/main/resources/assets/dimdoors/textures/blocks/tile.dimDoorLink_bottom.png rename to src/main/resources/assets/dimdoors/textures/blocks/tile.dimDoor_lower.png diff --git a/src/main/resources/assets/dimdoors/textures/blocks/tile.dimDoor_top.png b/src/main/resources/assets/dimdoors/textures/blocks/tile.dimDoor_top.png deleted file mode 100644 index 4ec9868..0000000 Binary files a/src/main/resources/assets/dimdoors/textures/blocks/tile.dimDoor_top.png and /dev/null differ diff --git a/src/main/resources/assets/dimdoors/textures/blocks/tile.dimDoorLink_top.png b/src/main/resources/assets/dimdoors/textures/blocks/tile.dimDoor_upper.png similarity index 100% rename from src/main/resources/assets/dimdoors/textures/blocks/tile.dimDoorLink_top.png rename to src/main/resources/assets/dimdoors/textures/blocks/tile.dimDoor_upper.png diff --git a/src/main/resources/assets/dimdoors/textures/blocks/tile.dimDoorexitlink_bottom.png b/src/main/resources/assets/dimdoors/textures/blocks/tile.dimDoorexitlink_bottom.png deleted file mode 100644 index 73605a0..0000000 Binary files a/src/main/resources/assets/dimdoors/textures/blocks/tile.dimDoorexitlink_bottom.png and /dev/null differ diff --git a/src/main/resources/assets/dimdoors/textures/blocks/tile.dimDoorexitlink_top.png b/src/main/resources/assets/dimdoors/textures/blocks/tile.dimDoorexitlink_top.png deleted file mode 100644 index 9df8356..0000000 Binary files a/src/main/resources/assets/dimdoors/textures/blocks/tile.dimDoorexitlink_top.png and /dev/null differ diff --git a/src/main/resources/assets/dimdoors/textures/blocks/tile.doorGold_bottom.png b/src/main/resources/assets/dimdoors/textures/blocks/tile.doorGold_lower.png similarity index 100% rename from src/main/resources/assets/dimdoors/textures/blocks/tile.doorGold_bottom.png rename to src/main/resources/assets/dimdoors/textures/blocks/tile.doorGold_lower.png diff --git a/src/main/resources/assets/dimdoors/textures/blocks/tile.doorGold_top.png b/src/main/resources/assets/dimdoors/textures/blocks/tile.doorGold_upper.png similarity index 100% rename from src/main/resources/assets/dimdoors/textures/blocks/tile.doorGold_top.png rename to src/main/resources/assets/dimdoors/textures/blocks/tile.doorGold_upper.png diff --git a/src/main/resources/assets/dimdoors/textures/blocks/tile.doorQuartz_lower.png b/src/main/resources/assets/dimdoors/textures/blocks/tile.doorQuartz_lower.png new file mode 100644 index 0000000..a1c590c Binary files /dev/null and b/src/main/resources/assets/dimdoors/textures/blocks/tile.doorQuartz_lower.png differ diff --git a/src/main/resources/assets/dimdoors/textures/blocks/tile.doorQuartz_upper.png b/src/main/resources/assets/dimdoors/textures/blocks/tile.doorQuartz_upper.png new file mode 100644 index 0000000..e4c3d91 Binary files /dev/null and b/src/main/resources/assets/dimdoors/textures/blocks/tile.doorQuartz_upper.png differ diff --git a/src/main/resources/assets/dimdoors/textures/blocks/tile.transientDoor - Copy.png b/src/main/resources/assets/dimdoors/textures/blocks/tile.transientDoor_lower.png similarity index 100% rename from src/main/resources/assets/dimdoors/textures/blocks/tile.transientDoor - Copy.png rename to src/main/resources/assets/dimdoors/textures/blocks/tile.transientDoor_lower.png diff --git a/src/main/resources/assets/dimdoors/textures/blocks/tile.transientDoor_bottom.png b/src/main/resources/assets/dimdoors/textures/blocks/tile.transientDoor_upper.png similarity index 100% rename from src/main/resources/assets/dimdoors/textures/blocks/tile.transientDoor_bottom.png rename to src/main/resources/assets/dimdoors/textures/blocks/tile.transientDoor_upper.png diff --git a/src/main/resources/assets/dimdoors/textures/items/itemChaosDoor.png b/src/main/resources/assets/dimdoors/textures/items/itemChaosDoor.png index 142ed36..4196ace 100644 Binary files a/src/main/resources/assets/dimdoors/textures/items/itemChaosDoor.png and b/src/main/resources/assets/dimdoors/textures/items/itemChaosDoor.png differ diff --git a/src/main/resources/assets/dimdoors/textures/items/itemDDKey.png b/src/main/resources/assets/dimdoors/textures/items/itemDDKey.png new file mode 100644 index 0000000..e2f0a74 Binary files /dev/null and b/src/main/resources/assets/dimdoors/textures/items/itemDDKey.png differ diff --git a/src/main/resources/assets/dimdoors/textures/items/itemQuartzDimDoor.png b/src/main/resources/assets/dimdoors/textures/items/itemQuartzDimDoor.png new file mode 100644 index 0000000..ca9f2e4 Binary files /dev/null and b/src/main/resources/assets/dimdoors/textures/items/itemQuartzDimDoor.png differ diff --git a/src/main/resources/assets/dimdoors/textures/items/itemQuartzDoor.png b/src/main/resources/assets/dimdoors/textures/items/itemQuartzDoor.png new file mode 100644 index 0000000..33fc4ef Binary files /dev/null and b/src/main/resources/assets/dimdoors/textures/items/itemQuartzDoor.png differ diff --git a/src/main/resources/assets/dimdoors/textures/other/keyOutline.png b/src/main/resources/assets/dimdoors/textures/other/keyOutline.png new file mode 100644 index 0000000..7cc2713 Binary files /dev/null and b/src/main/resources/assets/dimdoors/textures/other/keyOutline.png differ diff --git a/src/main/resources/assets/dimdoors/textures/other/keyOutlineLight.png b/src/main/resources/assets/dimdoors/textures/other/keyOutlineLight.png new file mode 100644 index 0000000..382c1d0 Binary files /dev/null and b/src/main/resources/assets/dimdoors/textures/other/keyOutlineLight.png differ diff --git a/src/main/resources/assets/dimdoors/textures/other/keyhole.png b/src/main/resources/assets/dimdoors/textures/other/keyhole.png new file mode 100644 index 0000000..7bb3ea3 Binary files /dev/null and b/src/main/resources/assets/dimdoors/textures/other/keyhole.png differ diff --git a/src/main/resources/assets/dimdoors/textures/other/keyholeLight.png b/src/main/resources/assets/dimdoors/textures/other/keyholeLight.png new file mode 100644 index 0000000..e6fcfc6 Binary files /dev/null and b/src/main/resources/assets/dimdoors/textures/other/keyholeLight.png differ diff --git a/src/main/resources/mcmod.info b/src/main/resources/mcmod.info index edad775..7a43be9 100644 --- a/src/main/resources/mcmod.info +++ b/src/main/resources/mcmod.info @@ -6,10 +6,10 @@ "modid": "dimdoors", "name": "Dimensional Doors", "description": "Bend and twist reality itself, creating pocket dimensions, rifts, and much more", -"version": "1.6.4R2.2.2RC1", +"version": "$version", "credits": "Created by StevenRS11, Coded by StevenRS11 and SenseiKiwi, Logo and Testing by Jaitsu", "logoFile": "/dimdoors_logo.png", -"mcversion": "", +"mcversion": "$mcversion", "url": "http://www.minecraftforum.net/topic/1650007-147smpssplan-dimensional-doors-v110-physics-what-physics-updated-with-fancy-opengl/", "updateUrl": "", "authors": [ "StevenRS11", "SenseiKiwi" ], diff --git a/src/main/resources/schematics/balgor.txt b/src/main/resources/schematics/balgor.txt deleted file mode 100644 index b9d8157..0000000 --- a/src/main/resources/schematics/balgor.txt +++ /dev/null @@ -1,6 +0,0 @@ -/schematics/balgor/ComplexHall_GardenBalgor1_open_39.schematic -/schematics/balgor/ComplexHall_OpenHallBalgor1_Closed_68.schematic -/schematics/balgor/ComplexHall_SilverEggHallBalgor1_closed_25.schematic -/schematics/balgor/Maze_OmniMazeBalgor1_open_30.schematic -/schematics/balgor/Trap_ArrowTrapBalgor1_closed_20.schematic -/schematics/balgor/Trap_ZombieHallBalgor1_closed_25.schematic diff --git a/src/main/resources/schematics/balgor/ComplexHall_GardenBalgor1_open_39.schematic b/src/main/resources/schematics/balgor/ComplexHall_GardenBalgor1_open_39.schematic deleted file mode 100644 index fd5f926..0000000 Binary files a/src/main/resources/schematics/balgor/ComplexHall_GardenBalgor1_open_39.schematic and /dev/null differ diff --git a/src/main/resources/schematics/balgor/ComplexHall_OpenHallBalgor1_Closed_68.schematic b/src/main/resources/schematics/balgor/ComplexHall_OpenHallBalgor1_Closed_68.schematic deleted file mode 100644 index 19be9c4..0000000 Binary files a/src/main/resources/schematics/balgor/ComplexHall_OpenHallBalgor1_Closed_68.schematic and /dev/null differ diff --git a/src/main/resources/schematics/balgor/ComplexHall_SilverEggHallBalgor1_closed_25.schematic b/src/main/resources/schematics/balgor/ComplexHall_SilverEggHallBalgor1_closed_25.schematic deleted file mode 100644 index 270f035..0000000 Binary files a/src/main/resources/schematics/balgor/ComplexHall_SilverEggHallBalgor1_closed_25.schematic and /dev/null differ diff --git a/src/main/resources/schematics/balgor/Maze_OmniMazeBalgor1_open_30.schematic b/src/main/resources/schematics/balgor/Maze_OmniMazeBalgor1_open_30.schematic deleted file mode 100644 index bffcbcf..0000000 Binary files a/src/main/resources/schematics/balgor/Maze_OmniMazeBalgor1_open_30.schematic and /dev/null differ diff --git a/src/main/resources/schematics/balgor/Trap_ArrowTrapBalgor1_closed_20.schematic b/src/main/resources/schematics/balgor/Trap_ArrowTrapBalgor1_closed_20.schematic deleted file mode 100644 index 8ef105c..0000000 Binary files a/src/main/resources/schematics/balgor/Trap_ArrowTrapBalgor1_closed_20.schematic and /dev/null differ diff --git a/src/main/resources/schematics/balgor/Trap_ZombieHallBalgor1_closed_25.schematic b/src/main/resources/schematics/balgor/Trap_ZombieHallBalgor1_closed_25.schematic deleted file mode 100644 index b968f0d..0000000 Binary files a/src/main/resources/schematics/balgor/Trap_ZombieHallBalgor1_closed_25.schematic and /dev/null differ diff --git a/src/main/resources/schematics/balgor/rules.txt b/src/main/resources/schematics/balgor/rules.txt deleted file mode 100644 index bb4d683..0000000 --- a/src/main/resources/schematics/balgor/rules.txt +++ /dev/null @@ -1,23 +0,0 @@ -Version 1 -Types: -Trap -ComplexHall -Maze - -Settings: -AllowDuplicatesInChain = false -AllowPackChangeOut = false -DistortDoorCoordinates = true - -## Prevent this pack from being selected for transitioning in once we've transitioned out -AllowPackChangeIn = true - -Rules: - -? ? ? -> - -? ? -> Maze#20 ComplexHall#40 Trap#40 - -? -> ComplexHall#40 Trap#60 - -->ComplexHall#100 \ No newline at end of file diff --git a/src/main/resources/schematics/ruins.txt b/src/main/resources/schematics/ruins.txt index 2641e62..5e43921 100644 --- a/src/main/resources/schematics/ruins.txt +++ b/src/main/resources/schematics/ruins.txt @@ -1,4 +1,7 @@ +/schematics/ruins/ComplexHall_Balgor0-CrumbledHall_Closed_75.schematic /schematics/ruins/complexHall_buggyTopEntry1_open_100.schematic +/schematics/ruins/ComplexHall_Cere-PuzzleWall_Open_75.schematic +/schematics/ruins/ComplexHall_Cere-TransferTunnel_Closed_100.schematic /schematics/ruins/complexHall_exitRuinsWithHiddenDoor_open_100.schematic /schematics/ruins/complexHall_hallwayHiddenTreasure_closed_100.schematic /schematics/ruins/complexHall_largeBrokenHall_closed_100.schematic @@ -14,7 +17,9 @@ /schematics/ruins/complexHall_smallRotundaWithExit_closed_100.schematic /schematics/ruins/complexHall_tntPuzzleTrap_closed_50.schematic /schematics/ruins/deadEnd_azersDungeonO_closed_100.schematic +/schematics/ruins/DeadEnd_Balgor0-ArrowHall_Closed_75.schematic /schematics/ruins/deadEnd_brokenPillarsO_open_100.schematic +/schematics/ruins/DeadEnd_Cere-FloatingAltar_Open_75.schematic /schematics/ruins/deadEnd_diamondTowerTemple1_open_100.schematic /schematics/ruins/deadEnd_fallingTrapO_open_100.schematic /schematics/ruins/deadEnd_hiddenStaircaseO_open_100.schematic @@ -30,10 +35,14 @@ /schematics/ruins/deadEnd_tntTrapO_open_100.schematic /schematics/ruins/exit_exitCube_open_100.schematic /schematics/ruins/exit_lockingExitHall_closed_100.schematic +/schematics/ruins/Exit_SK-HotSuspense_Open_75.schematic /schematics/ruins/Exit_SK-LockingExitTrap_Closed_50.schematic /schematics/ruins/exit_smallExitPrison_open_100.schematic +/schematics/ruins/Exit_XombyCraft-RopeBridge_Open_100.schematic /schematics/ruins/hub_4WayBasicHall_closed_200.schematic /schematics/ruins/hub_4WayHallExit_closed_200.schematic +/schematics/ruins/Hub_Balgor0-OmniMaze_Open_50.schematic +/schematics/ruins/Hub_Cere-GreatHall_Open_40.schematic /schematics/ruins/hub_doorTotemRuins_open_100.schematic /schematics/ruins/hub_fortRuins_open_100.schematic /schematics/ruins/hub_hallwayTrapRooms1_closed_100.schematic @@ -59,12 +68,14 @@ /schematics/ruins/SimpleHall_SK-SpiralHallway_Open_100.schematic /schematics/ruins/SimpleHall_SK-UTurnLeft_Open_50.schematic /schematics/ruins/SimpleHall_SK-UTurnRight_Open_50.schematic +/schematics/ruins/SimpleHall_SK-WatchedForkLeft_Closed_80.schematic +/schematics/ruins/SimpleHall_SK-WatchedForkRight_Closed_80.schematic /schematics/ruins/simpleHall_smallSimpleLeft_closed_100.schematic /schematics/ruins/simpleHall_smallSimpleRight_closed_100.schematic /schematics/ruins/trap_fakeTNTTrap_closed_100.schematic /schematics/ruins/trap_hallwayPitFallTrap_closed_200.schematic /schematics/ruins/trap_lavaPyramid_open_100.schematic -/schematics/ruins/trap_pistonFallRuins_open_100.schematic +/schematics/ruins/trap_pistonFallRuins_open_75.schematic /schematics/ruins/trap_pistonFloorHall_closed_150.schematic /schematics/ruins/trap_pistonFloorPlatform2_closed_100.schematic /schematics/ruins/trap_pistonFloorPlatform_closed_100.schematic @@ -72,6 +83,7 @@ /schematics/ruins/trap_pistonSmasherHall_closed_100.schematic /schematics/ruins/Trap_SK-FakeTNTTrap-B_Closed_50.schematic /schematics/ruins/Trap_SK-NicolesTower_Open_50.schematic +/schematics/ruins/Trap_SK-RaceTheLight_Closed_50.schematic /schematics/ruins/Trap_SK-RestlessCorridor_Open_40.schematic /schematics/ruins/Trap_SK-SimpleLeftTrap_Closed_50.schematic /schematics/ruins/Trap_SK-SimpleRightTrap_Closed_50.schematic @@ -79,6 +91,3 @@ /schematics/ruins/Trap_SK-TrappedStairsUp_Closed_50.schematic /schematics/ruins/Trap_SK-UTrapRight_Open_50.schematic /schematics/ruins/trap_wallFallcomboPistonHall_closed_200.schematic -/schematics/ruins/DeadEnd_Floating-Altar_Open_100.schematic -/schematics/ruins/complexHall_exitRuinsWithHiddenDoor_open_100 -.schematic diff --git a/src/main/resources/schematics/ruins/ComplexHall_Balgor0-CrumbledHall_Closed_75.schematic b/src/main/resources/schematics/ruins/ComplexHall_Balgor0-CrumbledHall_Closed_75.schematic new file mode 100644 index 0000000..7f924f6 Binary files /dev/null and b/src/main/resources/schematics/ruins/ComplexHall_Balgor0-CrumbledHall_Closed_75.schematic differ diff --git a/src/main/resources/schematics/ruins/ComplexHall_Cere-JumpPass_Open_75.schematic b/src/main/resources/schematics/ruins/ComplexHall_Cere-JumpPass_Open_75.schematic new file mode 100644 index 0000000..9c242b6 Binary files /dev/null and b/src/main/resources/schematics/ruins/ComplexHall_Cere-JumpPass_Open_75.schematic differ diff --git a/src/main/resources/schematics/ruins/ComplexHall_CerePuzzleWall_Open_100.schematic b/src/main/resources/schematics/ruins/ComplexHall_Cere-PuzzleWall_Open_75.schematic similarity index 100% rename from src/main/resources/schematics/ruins/ComplexHall_CerePuzzleWall_Open_100.schematic rename to src/main/resources/schematics/ruins/ComplexHall_Cere-PuzzleWall_Open_75.schematic diff --git a/src/main/resources/schematics/ruins/ComplexHall_Cere-TransferTunnel_Closed_100.schematic b/src/main/resources/schematics/ruins/ComplexHall_Cere-TransferTunnel_Closed_100.schematic new file mode 100644 index 0000000..786a010 Binary files /dev/null and b/src/main/resources/schematics/ruins/ComplexHall_Cere-TransferTunnel_Closed_100.schematic differ diff --git a/src/main/resources/schematics/ruins/DeadEnd_Balgor0-ArrowHall_Closed_75.schematic b/src/main/resources/schematics/ruins/DeadEnd_Balgor0-ArrowHall_Closed_75.schematic new file mode 100644 index 0000000..12855b2 Binary files /dev/null and b/src/main/resources/schematics/ruins/DeadEnd_Balgor0-ArrowHall_Closed_75.schematic differ diff --git a/src/main/resources/schematics/ruins/DeadEnd_Cere-FloatingAltar_Open_75.schematic b/src/main/resources/schematics/ruins/DeadEnd_Cere-FloatingAltar_Open_75.schematic new file mode 100644 index 0000000..3e9d654 Binary files /dev/null and b/src/main/resources/schematics/ruins/DeadEnd_Cere-FloatingAltar_Open_75.schematic differ diff --git a/src/main/resources/schematics/ruins/DeadEnd_Floating-Altar_Open_100.schematic b/src/main/resources/schematics/ruins/DeadEnd_Floating-Altar_Open_100.schematic deleted file mode 100644 index fa5b3c0..0000000 Binary files a/src/main/resources/schematics/ruins/DeadEnd_Floating-Altar_Open_100.schematic and /dev/null differ diff --git a/src/main/resources/schematics/ruins/Exit_SK-HotSuspense_Open_75.schematic b/src/main/resources/schematics/ruins/Exit_SK-HotSuspense_Open_75.schematic new file mode 100644 index 0000000..b658c79 Binary files /dev/null and b/src/main/resources/schematics/ruins/Exit_SK-HotSuspense_Open_75.schematic differ diff --git a/src/main/resources/schematics/ruins/Exit_XombyCraft-RopeBridge_Open_100.schematic b/src/main/resources/schematics/ruins/Exit_XombyCraft-RopeBridge_Open_100.schematic new file mode 100644 index 0000000..d427889 Binary files /dev/null and b/src/main/resources/schematics/ruins/Exit_XombyCraft-RopeBridge_Open_100.schematic differ diff --git a/src/main/resources/schematics/ruins/Hub_Balgor0-OmniMaze_Open_50.schematic b/src/main/resources/schematics/ruins/Hub_Balgor0-OmniMaze_Open_50.schematic new file mode 100644 index 0000000..077e4e7 Binary files /dev/null and b/src/main/resources/schematics/ruins/Hub_Balgor0-OmniMaze_Open_50.schematic differ diff --git a/src/main/resources/schematics/ruins/Hub_Cere-GreatHall_Open_40.schematic b/src/main/resources/schematics/ruins/Hub_Cere-GreatHall_Open_40.schematic new file mode 100644 index 0000000..e639e58 Binary files /dev/null and b/src/main/resources/schematics/ruins/Hub_Cere-GreatHall_Open_40.schematic differ diff --git a/src/main/resources/schematics/ruins/Hub_SK-FractalCage_Open_40.schematic b/src/main/resources/schematics/ruins/Hub_SK-FractalCage_Open_40.schematic index 5a0c61c..d66f82a 100644 Binary files a/src/main/resources/schematics/ruins/Hub_SK-FractalCage_Open_40.schematic and b/src/main/resources/schematics/ruins/Hub_SK-FractalCage_Open_40.schematic differ diff --git a/src/main/resources/schematics/ruins/Hub_SK-RandomSnow_Open_75.schematic b/src/main/resources/schematics/ruins/Hub_SK-RandomSnow_Open_75.schematic index 18503e1..5a4a0ce 100644 Binary files a/src/main/resources/schematics/ruins/Hub_SK-RandomSnow_Open_75.schematic and b/src/main/resources/schematics/ruins/Hub_SK-RandomSnow_Open_75.schematic differ diff --git a/src/main/resources/schematics/ruins/Hub_SK-RandomSwamp_Open_75.schematic b/src/main/resources/schematics/ruins/Hub_SK-RandomSwamp_Open_75.schematic index 5f3b18d..b3a086e 100644 Binary files a/src/main/resources/schematics/ruins/Hub_SK-RandomSwamp_Open_75.schematic and b/src/main/resources/schematics/ruins/Hub_SK-RandomSwamp_Open_75.schematic differ diff --git a/src/main/resources/schematics/ruins/SimpleHall_SK-WatchedForkLeft_Closed_80.schematic b/src/main/resources/schematics/ruins/SimpleHall_SK-WatchedForkLeft_Closed_80.schematic new file mode 100644 index 0000000..4601cc0 Binary files /dev/null and b/src/main/resources/schematics/ruins/SimpleHall_SK-WatchedForkLeft_Closed_80.schematic differ diff --git a/src/main/resources/schematics/ruins/SimpleHall_SK-WatchedForkRight_Closed_80.schematic b/src/main/resources/schematics/ruins/SimpleHall_SK-WatchedForkRight_Closed_80.schematic new file mode 100644 index 0000000..d5be666 Binary files /dev/null and b/src/main/resources/schematics/ruins/SimpleHall_SK-WatchedForkRight_Closed_80.schematic differ diff --git a/src/main/resources/schematics/ruins/Trap_SK-RaceTheLight_Closed_50.schematic b/src/main/resources/schematics/ruins/Trap_SK-RaceTheLight_Closed_50.schematic new file mode 100644 index 0000000..8206a43 Binary files /dev/null and b/src/main/resources/schematics/ruins/Trap_SK-RaceTheLight_Closed_50.schematic differ diff --git a/src/main/resources/schematics/ruins/rules.txt b/src/main/resources/schematics/ruins/rules.txt index a14fe17..0618858 100644 --- a/src/main/resources/schematics/ruins/rules.txt +++ b/src/main/resources/schematics/ruins/rules.txt @@ -16,6 +16,8 @@ DistortDoorCoordinates = true ## Prevent this pack from being selected for transitioning in once we've transitioned out AllowPackChangeIn = false +DuplicateSearchLevels = 1 + Rules: Exit -> DeadEnd Exit diff --git a/src/main/resources/schematics/ruins/trap_pistonFallRuins_open_100.schematic b/src/main/resources/schematics/ruins/trap_pistonFallRuins_open_100.schematic deleted file mode 100644 index ca2d664..0000000 Binary files a/src/main/resources/schematics/ruins/trap_pistonFallRuins_open_100.schematic and /dev/null differ diff --git a/src/main/resources/schematics/ruins/trap_pistonFallRuins_open_75.schematic b/src/main/resources/schematics/ruins/trap_pistonFallRuins_open_75.schematic new file mode 100644 index 0000000..0ed8a39 Binary files /dev/null and b/src/main/resources/schematics/ruins/trap_pistonFallRuins_open_75.schematic differ