From a8e37da4bc3c3a605d13ee43dbe54e488b12a9ab Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Thu, 6 Mar 2014 18:27:03 -0400 Subject: [PATCH 001/187] Minor Change Just sprucing up some config stuff... --- .../mod_pocketDim/DDProperties.java | 17 +++++++++++++---- .../mod_pocketDim/ticking/MobMonolith.java | 2 +- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/DDProperties.java b/src/main/java/StevenDimDoors/mod_pocketDim/DDProperties.java index 622d107..a7aed13 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/DDProperties.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/DDProperties.java @@ -96,6 +96,7 @@ public class DDProperties public final boolean LimboReturnsInventoryEnabled; public final boolean DoorRenderingEnabled; public final boolean TNFREAKINGT_Enabled; + public final boolean MonolithTeleportationEnabled; /** @@ -118,10 +119,11 @@ public class DDProperties //Names of categories private final String CATEGORY_CRAFTING = "crafting"; private final String CATEGORY_ENTITY = "entity"; + private final String CATEGORY_SPECIAL = "special"; 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) { @@ -228,13 +230,20 @@ public class DDProperties 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!"); } + + // SPECIAL CONFIG SETTINGS + // I'm adding this category because one of our users convinced me, personally, to please allow this. + // These settings are checked _after_ we save the config file, so Forge won't generate them automatically. + // Whoever wants to use them must intentionally write them into the config file. + + MonolithTeleportationEnabled = config.get(CATEGORY_SPECIAL, "Enable Monolith Teleportation", true).getBoolean(true); } public static DDProperties initialize(File configFile) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/ticking/MobMonolith.java b/src/main/java/StevenDimDoors/mod_pocketDim/ticking/MobMonolith.java index de4103e..9119d08 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/ticking/MobMonolith.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/ticking/MobMonolith.java @@ -193,7 +193,7 @@ public class MobMonolith extends EntityFlying implements IMob this.soundTime=200; } } - else if (!this.worldObj.isRemote && !entityPlayer.capabilities.isCreativeMode) + else if (!this.worldObj.isRemote && properties.MonolithTeleportationEnabled && !entityPlayer.capabilities.isCreativeMode) { 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); From 62bd3bd19e106b2abc4db0adf4dcdd5d26e4e299 Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Thu, 6 Mar 2014 21:32:38 -0400 Subject: [PATCH 002/187] Changes to Commands Made some minor changes to the way that we register commands with Minecraft. Also changed the way that we generate onCommandUsage() strings so that the style of our outputs is consistent with that of Minecraft and Forge commands. It seems the way the messages were generated changed for MC 1.6. Finally, removed compareTo() from DDCommandBase since it was completely unnecessary (CommandBase already does the same) and casting objects to CommandBase was causing errors with some Chicken Bones commands that directly implemented ICommand. --- .../commands/CommandCreateDungeonRift.java | 8 ----- .../commands/CommandCreatePocket.java | 5 --- .../commands/CommandDeleteAllLinks.java | 5 --- .../commands/CommandDeleteRifts.java | 5 --- .../commands/CommandExportDungeon.java | 7 ----- .../commands/CommandResetDungeons.java | 5 --- .../commands/CommandTeleportPlayer.java | 10 ++---- .../mod_pocketDim/commands/DDCommandBase.java | 31 ++++++++++--------- .../mod_pocketDim/mod_pocketDim.java | 14 ++++----- 9 files changed, 26 insertions(+), 64 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandCreateDungeonRift.java b/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandCreateDungeonRift.java index 791b4bb..23e0b64 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandCreateDungeonRift.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandCreateDungeonRift.java @@ -32,14 +32,6 @@ 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) { diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandCreatePocket.java b/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandCreatePocket.java index 1081a18..b2843a6 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandCreatePocket.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandCreatePocket.java @@ -21,11 +21,6 @@ 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) { diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandDeleteAllLinks.java b/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandDeleteAllLinks.java index 2923716..317b101 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandDeleteAllLinks.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandDeleteAllLinks.java @@ -28,11 +28,6 @@ public class CommandDeleteAllLinks extends DDCommandBase return instance; } - @Override - public String getCommandUsage(ICommandSender sender) { - return "Usage: /dd-deletelinks "; - } - @Override protected DDCommandResult processCommand(EntityPlayer sender, String[] command) { diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandDeleteRifts.java b/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandDeleteRifts.java index 7f6be30..328576c 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandDeleteRifts.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandDeleteRifts.java @@ -28,11 +28,6 @@ public class CommandDeleteRifts extends DDCommandBase return instance; } - @Override - public String getCommandUsage(ICommandSender sender) { - return "Usage: /dd-??? "; - } - @Override protected DDCommandResult processCommand(EntityPlayer sender, String[] command) { diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandExportDungeon.java b/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandExportDungeon.java index 7e7df1d..86008cd 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandExportDungeon.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandExportDungeon.java @@ -26,13 +26,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) { diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandResetDungeons.java b/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandResetDungeons.java index 0f51851..f9ed088 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandResetDungeons.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandResetDungeons.java @@ -28,11 +28,6 @@ public class CommandResetDungeons extends DDCommandBase return instance; } - @Override - public String getCommandUsage(ICommandSender sender) { - return "/dd-resetdungeons"; - } - @Override protected DDCommandResult processCommand(EntityPlayer sender, String[] command) { diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandTeleportPlayer.java b/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandTeleportPlayer.java index 206df94..1b29999 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandTeleportPlayer.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandTeleportPlayer.java @@ -23,17 +23,11 @@ public class CommandTeleportPlayer extends DDCommandBase 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. */ diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/commands/DDCommandBase.java b/src/main/java/StevenDimDoors/mod_pocketDim/commands/DDCommandBase.java index 87c08ed..ea8061f 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/commands/DDCommandBase.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/commands/DDCommandBase.java @@ -39,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(); } /* @@ -66,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()); } } @@ -78,12 +88,5 @@ public abstract class DDCommandBase extends CommandBase ChatMessageComponent cmp = new ChatMessageComponent(); cmp.addText(message); player.sendChatToPlayer(cmp); - } - - @Override - public int compareTo(Object par1Obj) - { - return this.getCommandName().compareTo(((CommandBase)par1Obj).getCommandName()); - } } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java b/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java index c52aa5f..c44eaee 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java @@ -307,16 +307,16 @@ public class mod_pocketDim //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); + event.registerServerCommand( CommandResetDungeons.instance() ); + event.registerServerCommand( CommandCreateDungeonRift.instance() ); + event.registerServerCommand( CommandDeleteAllLinks.instance() ); //CommandDeleteDimensionData.instance().register(event); - CommandDeleteRifts.instance().register(event); - CommandExportDungeon.instance().register(event); + event.registerServerCommand( CommandDeleteRifts.instance() ); + event.registerServerCommand( CommandExportDungeon.instance() ); //CommandPrintDimensionData.instance().register(event); //CommandPruneDimensions.instance().register(event); - CommandCreatePocket.instance().register(event); - CommandTeleportPlayer.instance().register(event); + event.registerServerCommand( CommandCreatePocket.instance() ); + event.registerServerCommand( CommandTeleportPlayer.instance() ); // Initialize a new DeathTracker String deathTrackerFile = DimensionManager.getCurrentSaveRootDirectory() + "/DimensionalDoors/data/deaths.txt"; From b2dfb35a72e5b099c81d743241cb6896a18f139f Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Fri, 7 Mar 2014 01:17:14 -0400 Subject: [PATCH 003/187] Rotation Fixes and Schematic Changes Fixed rotations for hopper and droppers. Hoppers were failing because powered hoppers have different metadata. Droppers were just missing from the list of oriented blocks. Fixed the wooden buttons on Cerevisiae's altar room and added her puzzle room once hoppers were working reliably. --- .../mod_pocketDim/schematic/BlockRotator.java | 38 ++++++++++++++++-- ...omplexHall_Cere-PuzzleWall_Open.schematic} | Bin ...dEnd_Cere-FloatingAltar_Open_100.schematic | Bin 0 -> 1612 bytes 3 files changed, 34 insertions(+), 4 deletions(-) rename src/main/resources/schematics/ruins/{ComplexHall_CerePuzzleWall_Open_100.schematic => ComplexHall_Cere-PuzzleWall_Open.schematic} (100%) create mode 100644 src/main/resources/schematics/ruins/DeadEnd_Cere-FloatingAltar_Open_100.schematic diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/schematic/BlockRotator.java b/src/main/java/StevenDimDoors/mod_pocketDim/schematic/BlockRotator.java index bbf1251..af0050e 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; @@ -241,7 +242,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 +259,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 +382,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 +412,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/resources/schematics/ruins/ComplexHall_CerePuzzleWall_Open_100.schematic b/src/main/resources/schematics/ruins/ComplexHall_Cere-PuzzleWall_Open.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.schematic diff --git a/src/main/resources/schematics/ruins/DeadEnd_Cere-FloatingAltar_Open_100.schematic b/src/main/resources/schematics/ruins/DeadEnd_Cere-FloatingAltar_Open_100.schematic new file mode 100644 index 0000000000000000000000000000000000000000..3e9d65485337b42cc4cbef17feca6ec5f52dfbd4 GIT binary patch literal 1612 zcmV-S2DAAeiwFP!000000PUR1Zrer_hDVYmO3n=}y6qwcx-wCq=tAf+jguCrixy~s ztYSd22#bg%5f%$3-KP7zN;X7arH@nUW^+d5FN-2MWAgt5n52K6xt=*34k;ar-XE7^ zXEN~JOG_M`4g7%+m!Ab8gb)q1k@%G24)IxL%O^;DjKoJsgtUP66crbWknG7aPjWCF z-31_okYccO7l7mnnvJ)2sDxCEuI>U5g|4#Q0^DM@u-pTNz37u}nr;d2co946sTDIz zRSpded7`_>BY5dOV1fp`S_>sQUG4lEIdwx))uz!g9EwKEa4Ug5>ZNq^x?b5=ehUIF ze;37ZA*q(=bcXtOdtHEiu@d&~PfMDkbwKb}n?|<0Z{D4Ry;v%p70I2DwT1FR%Wx|K zrRk-5J>&>qG&(K-B|6=9Rwc~@o61&Vj;D7Vi2PLkp4k(Gi& zoRHld_qvVLu>uzY;cYaWW@i7c1EkqHYQs0N;av?}3xZF{;gcdAO-KkKgb+dqA%qY@ z2qAIn(jz^ar^%dXYS-|HoIwvC*#5VCucf!M!yf-8_^PvW;d=g^#{H?n=W!_ z2rD|})qB^EcE5DzXMatvoZ0l{c;HUY-RZmNzmI30GyU!6<@IdtjG`nOe@AxTMB5M1 z_9)uE7mHVOH5Q_MTZpFUoIBGie=KZE^j?fcKVHu+-_3>i?!SXOM}CpotBDv$hkL_lhSUT2@s>sgFFl6)ed&DH`Jo(Bi`~M-VdJK54o+p1p$=H5E}V~EIJ`}XvyLM4;BK&i{pnu zp#ND1z0U*!DJ&Hgg$#&&ytooV2qAc$cVRv&7mneKRfQ# z*cV?lMf;6A^2g$9OLR8h{J8wAyM#i76l)`fVY(WIK&5D+2>X*Pfy1E>)bN7h4iPq= z4iOEN{x9jK;al-Gqc{}9B9djEJMv`gTarDzVbiR6QY=oy9*<%lN*IeFNH_d8`ed_Y zo`>XFpV+4(ycx#nf;4HkAW2?JiSkN{c2@G1c)PEPacxUQ;^}ZLhHEjdZVbcoaNBe( zM%qf<%Q8LB>{Y=ngxePOih%vONjpWNxK`8J&P*8I^kCa|iZZnA$ibpNiQ0PXCaL!A z$WBNai7V}SvTCoi=jmdaW%dH$dcqc3CY{>0IZ<%(M)R+RJSRwd167nPn!<(xFY};u zi{T)rOB*T$WOWEbWh-l|V%dqRt!%e=4YEBwNxx>lJ{g|GY?btpCCC$%7S|KCP+k-? z+_bYty_AkwYdT^d8jJS#P=)E@*<052@9Y!55}nRW{~oRqpP*5nIPND2dwXOnB{@;t zM$(j~*|NMBu(ZRE|E&0!*b1P9@}j8WrW?6*a?{K8Qo9*hRuDKT?8CsAIrf$4bbDrH zC+_CXMA=H(MBT|Ht0kY}2e$0`pN27Y(KN_1kAlH^q82IuvxC_|R5ili53cvcF>@vu zW9MycrqmKO$@PEO!!i%@t>;dR?{`uF4{N=zXzF|&gqO1O3SQ`9)VbelOs4g|<-6Z$ zfiXnMn)c?}j@Q@=%-1lnpygXa9vmSE3SqzBzero}iv|(0)bPE73lQEGRq3Z%qY!^! zp^Ou&xQ0PU-k`u}+>D0vzQaXA2qAN1-$PrRC;JCJJJ1rzEf1W9l6SehDl8VIe?#l_=YIZSufp9%>3ke2BlFI); K4w_fa`Tzh)O%OK# literal 0 HcmV?d00001 From 6f3d03b660acecfae6a0383ec2623a85ca01d0c8 Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Fri, 7 Mar 2014 02:21:33 -0400 Subject: [PATCH 004/187] Changed Monolith Config Changed the Monolith teleportation setting so that it's always written to the config file instead of being secret. Steven agreed to this. o_o --- .../StevenDimDoors/mod_pocketDim/DDProperties.java | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/DDProperties.java b/src/main/java/StevenDimDoors/mod_pocketDim/DDProperties.java index a7aed13..0c61faf 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/DDProperties.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/DDProperties.java @@ -119,7 +119,6 @@ public class DDProperties //Names of categories private final String CATEGORY_CRAFTING = "crafting"; private final String CATEGORY_ENTITY = "entity"; - private final String CATEGORY_SPECIAL = "special"; private final String CATEGORY_DIMENSION = "dimension"; private final String CATEGORY_PROVIDER = "provider"; private final String CATEGORY_BIOME = "biome"; @@ -209,6 +208,9 @@ public class DDProperties WorldRiftGenerationEnabled = config.get(Configuration.CATEGORY_GENERAL, "Enable Rift World Generation", true, "Sets whether dungeon rifts generate in dimensions other than Limbo").getBoolean(true); + 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 " + "spawn in a given Limbo chunk. The default chance is 28.").getInt(); @@ -237,13 +239,6 @@ public class DDProperties { throw new IllegalStateException("World generation blocks MUST have block IDs less than 256. Fix your configuration!"); } - - // SPECIAL CONFIG SETTINGS - // I'm adding this category because one of our users convinced me, personally, to please allow this. - // These settings are checked _after_ we save the config file, so Forge won't generate them automatically. - // Whoever wants to use them must intentionally write them into the config file. - - MonolithTeleportationEnabled = config.get(CATEGORY_SPECIAL, "Enable Monolith Teleportation", true).getBoolean(true); } public static DDProperties initialize(File configFile) From 60c2cc4710823ed0e0bab0c78d4379d7931026c4 Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Fri, 7 Mar 2014 15:15:22 -0400 Subject: [PATCH 005/187] Dropped Support for Structure Gen Flag Dropped support for Minecraft's structure generation flag because several other mods ignore it and supporting it can give the appearance that DD isn't working properly. We already have settings for disabling gateways in our config file. --- .../world/gateways/GatewayGenerator.java | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) 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..a95ee24 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/world/gateways/GatewayGenerator.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/world/gateways/GatewayGenerator.java @@ -113,10 +113,9 @@ 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()) + // 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) { valid = false; x = y = z = 0; //Stop the compiler from freaking out @@ -177,9 +176,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(); - } } From baa55555476a3c1692f91c3bbc86853fea47fca8 Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Fri, 7 Mar 2014 17:41:12 -0400 Subject: [PATCH 006/187] Fixing Build Issue with DDCommandBase I copied two functions from CommandBase into DDCommandBase because their absence is breaking our builds on Technic and Dryware Jenkins. I have no idea why that's happening. My copy of MC's source code has those functions in CommandBase and my code compiles without a problem. --- .../mod_pocketDim/commands/DDCommandBase.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/commands/DDCommandBase.java b/src/main/java/StevenDimDoors/mod_pocketDim/commands/DDCommandBase.java index ea8061f..b62cc86 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/commands/DDCommandBase.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/commands/DDCommandBase.java @@ -1,6 +1,7 @@ package StevenDimDoors.mod_pocketDim.commands; import net.minecraft.command.CommandBase; +import net.minecraft.command.ICommand; import net.minecraft.command.ICommandSender; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.util.ChatMessageComponent; @@ -89,4 +90,19 @@ public abstract class DDCommandBase extends CommandBase cmp.addText(message); player.sendChatToPlayer(cmp); } + + /* + * 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 + */ + public int compareTo(ICommand par1ICommand) + { + return this.getCommandName().compareTo(par1ICommand.getCommandName()); + } + + public int compareTo(Object par1Obj) + { + return this.compareTo((ICommand)par1Obj); + } } From 89baf624ebcc2242491c0cf50cdeb19b7a033fca Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Fri, 7 Mar 2014 18:35:20 -0400 Subject: [PATCH 007/187] Minor Improvements to Biomes Shifted the duplicate code from our biome classes into a single parent class. Also added checks so that Minecraft crashes if a biome ID conflict occurs. This is to put an end to the recent streak of posts on our MCF thread about people experiencing issues because DD and BoP have conflicts out of the box. --- .../mod_pocketDim/mod_pocketDim.java | 11 +++++- .../mod_pocketDim/world/BiomeGenLimbo.java | 34 ++----------------- .../mod_pocketDim/world/BiomeGenPocket.java | 22 ++---------- .../mod_pocketDim/world/DDBiomeGenBase.java | 34 +++++++++++++++++++ 4 files changed, 50 insertions(+), 51 deletions(-) create mode 100644 src/main/java/StevenDimDoors/mod_pocketDim/world/DDBiomeGenBase.java diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java b/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java index c44eaee..a4e6844 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java @@ -61,6 +61,7 @@ import StevenDimDoors.mod_pocketDim.tileentities.TileEntityRift; import StevenDimDoors.mod_pocketDim.tileentities.TileEntityTransTrapdoor; import StevenDimDoors.mod_pocketDim.world.BiomeGenLimbo; import StevenDimDoors.mod_pocketDim.world.BiomeGenPocket; +import StevenDimDoors.mod_pocketDim.world.DDBiomeGenBase; import StevenDimDoors.mod_pocketDim.world.LimboProvider; import StevenDimDoors.mod_pocketDim.world.PocketProvider; import StevenDimDoors.mod_pocketDim.world.gateways.GatewayGenerator; @@ -207,6 +208,11 @@ public class mod_pocketDim itemStabilizedLinkSignature = (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)); @@ -282,7 +288,10 @@ public class mod_pocketDim @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()); } 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/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!"); + } + } + } +} From b68de9eabd9c1fa021505168a62cf459f567640a Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Fri, 7 Mar 2014 20:16:28 -0400 Subject: [PATCH 008/187] Improved Door Code and Removed Hack Improved some of our door code by giving some of our variables real names. Also found a hack in BaseDimDoor.isDropped() and a strange comment that said "I have no idea, but sometimes this is returned as the blockID instead of metadata." I finally figured out that due to some random mistake introduced in another function, idDropped() sometimes received a block ID instead of metadata, which is what that comment referred to. I fixed the cause and removed the hack. --- .../mod_pocketDim/blocks/BaseDimDoor.java | 86 +++++++------------ .../mod_pocketDim/blocks/BlockDoorGold.java | 2 +- .../blocks/BlockGoldDimDoor.java | 2 +- .../mod_pocketDim/blocks/TransientDoor.java | 14 ++- 4 files changed, 40 insertions(+), 64 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BaseDimDoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BaseDimDoor.java index 3233c6e..824e2c6 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BaseDimDoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BaseDimDoor.java @@ -10,6 +10,7 @@ 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.Item; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.Icon; import net.minecraft.util.MathHelper; @@ -27,13 +28,13 @@ 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; public BaseDimDoor(int blockID, Material material, DDProperties properties) { super(blockID, material); - + this.properties = properties; } @@ -229,60 +230,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.setBlock(x, y, z, 0); } - - /** - 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.setBlock(x, y, z, 0); + if (!world.isRemote) + { + this.dropBlockAsItem(world, x, y, z, metadata, 0); + } } - - if (par5 > 0 && par5 != this.blockID) + else { - 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); + } } } } @@ -297,15 +276,12 @@ public abstract class BaseDimDoor extends BlockDoor implements IDimDoor, ITileEn return this.getDrops(); } - @Override - public int idDropped(int par1, Random par2Random, int par3) + /** + * Returns the ID of the items to drop on destruction. + */ + 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(); } /** @@ -375,9 +351,11 @@ public abstract class BaseDimDoor extends BlockDoor implements IDimDoor, ITileEn } @Override - public int getDrops() + public abstract int getDrops(); + + protected static boolean isUpperDoorBlock(int metadata) { - return this.blockID; + return (metadata & 8) != 0; } protected static boolean isDoorOpen(int metadata) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockDoorGold.java b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockDoorGold.java index 5b20779..41b45c0 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockDoorGold.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockDoorGold.java @@ -45,7 +45,7 @@ public class BlockDoorGold extends BlockDoor @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) + if (par1IBlockAccess.getBlockId(par2, par3 - 1, par4) == this.blockID) { return this.blockIcon; } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockGoldDimDoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockGoldDimDoor.java index 7cd4e0c..b4ffd21 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockGoldDimDoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockGoldDimDoor.java @@ -32,8 +32,8 @@ public class BlockGoldDimDoor extends BaseDimDoor dimension.createLink(x, y, z, LinkTypes.POCKET,world.getBlockMetadata(x, y - 1, z)); } } - } + @Override public int getDrops() { diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/TransientDoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/TransientDoor.java index 0c00501..bac5c5d 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/TransientDoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/TransientDoor.java @@ -1,5 +1,11 @@ package StevenDimDoors.mod_pocketDim.blocks; +import net.minecraft.block.material.Material; +import net.minecraft.entity.Entity; +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.DDProperties; import StevenDimDoors.mod_pocketDim.core.DDTeleporter; import StevenDimDoors.mod_pocketDim.core.DimLink; @@ -7,14 +13,6 @@ 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.util.AxisAlignedBB; -import net.minecraft.world.World; - public class TransientDoor extends BaseDimDoor { public TransientDoor(int blockID, Material material, DDProperties properties) From db91dfce5ab0c8c642eb12bfa94791e016da81e3 Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Fri, 7 Mar 2014 20:17:30 -0400 Subject: [PATCH 009/187] Minor Change Minor spacing change @.@ --- .../java/StevenDimDoors/mod_pocketDim/blocks/BaseDimDoor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BaseDimDoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BaseDimDoor.java index 824e2c6..6fe1d08 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BaseDimDoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BaseDimDoor.java @@ -45,7 +45,7 @@ public abstract class BaseDimDoor extends BlockDoor implements IDimDoor, ITileEn this.blockIconBottom = par1IconRegister.registerIcon(mod_pocketDim.modid + ":" + this.getUnlocalizedName()+"_bottom"); } - /** + /** * From the specified side and block metadata retrieves the blocks texture. Args: side, metadata */ @Override From ee72f3248ec132acda0b9f8d30b0f796c545778a Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Fri, 7 Mar 2014 21:38:15 -0400 Subject: [PATCH 010/187] Removed Corium Assets Removed leftover assets for Corium --- .../textures/blocks/tile.Corium_flowing.png | Bin 9931 -> 0 bytes .../blocks/tile.Corium_flowing.png.mcmeta | 27 ---------- .../textures/blocks/tile.Corium_still.png | Bin 10420 -> 0 bytes .../blocks/tile.Corium_still.png.mcmeta | 51 ------------------ 4 files changed, 78 deletions(-) delete mode 100644 src/main/resources/assets/dimdoors/textures/blocks/tile.Corium_flowing.png delete mode 100644 src/main/resources/assets/dimdoors/textures/blocks/tile.Corium_flowing.png.mcmeta delete mode 100644 src/main/resources/assets/dimdoors/textures/blocks/tile.Corium_still.png delete mode 100644 src/main/resources/assets/dimdoors/textures/blocks/tile.Corium_still.png.mcmeta 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 af07f91d2c25b15584f13e9173988cc5d3017a4c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9931 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 VzBT7zh!cl^j)virFR&LO{|D{T2crN0 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 - - ] - } -} - - From 576ac0aae2899a11f0a77388819c25b5194122e9 Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Fri, 7 Mar 2014 22:03:20 -0400 Subject: [PATCH 011/187] Fixed Double Door Textures Fixed the way textures are applied so that doors from our mod can appear as double doors. Renamed door textures to be consistent with Minecraft door textures. Got rid of a few obsolete textures. Unfortunately, something broke with door blocks updating. I need to fix that in the next commit. --- .../mod_pocketDim/blocks/BaseDimDoor.java | 128 +++++++++++++----- .../mod_pocketDim/blocks/BlockDimWall.java | 2 +- .../mod_pocketDim/blocks/BlockDoorGold.java | 113 ++++++++++++---- ...or_bottom.png => tile.chaosDoor_lower.png} | Bin ...sDoor_top.png => tile.chaosDoor_upper.png} | Bin ..._bottom.png => tile.dimDoorGold_lower.png} | Bin ...old_top.png => tile.dimDoorGold_upper.png} | Bin ..._bottom.png => tile.dimDoorWarp_lower.png} | Bin ...arp_top.png => tile.dimDoorWarp_upper.png} | Bin .../textures/blocks/tile.dimDoor_bottom.png | Bin 625 -> 0 bytes ...Link_bottom.png => tile.dimDoor_lower.png} | Bin .../textures/blocks/tile.dimDoor_top.png | Bin 540 -> 0 bytes ...oorLink_top.png => tile.dimDoor_upper.png} | Bin .../blocks/tile.dimDoorexitlink_bottom.png | Bin 778 -> 0 bytes .../blocks/tile.dimDoorexitlink_top.png | Bin 698 -> 0 bytes ...old_bottom.png => tile.doorGold_lower.png} | Bin ...orGold_top.png => tile.doorGold_upper.png} | Bin ... Copy.png => tile.transientDoor_lower.png} | Bin .../blocks/tile.transientDoor_top.png | Bin 2805 -> 0 bytes ...ottom.png => tile.transientDoor_upper.png} | Bin 20 files changed, 186 insertions(+), 57 deletions(-) rename src/main/resources/assets/dimdoors/textures/blocks/{tile.chaosDoor_bottom.png => tile.chaosDoor_lower.png} (100%) rename src/main/resources/assets/dimdoors/textures/blocks/{tile.chaosDoor_top.png => tile.chaosDoor_upper.png} (100%) rename src/main/resources/assets/dimdoors/textures/blocks/{tile.dimDoorGold_bottom.png => tile.dimDoorGold_lower.png} (100%) rename src/main/resources/assets/dimdoors/textures/blocks/{tile.dimDoorGold_top.png => tile.dimDoorGold_upper.png} (100%) rename src/main/resources/assets/dimdoors/textures/blocks/{tile.dimDoorWarp_bottom.png => tile.dimDoorWarp_lower.png} (100%) rename src/main/resources/assets/dimdoors/textures/blocks/{tile.dimDoorWarp_top.png => tile.dimDoorWarp_upper.png} (100%) delete mode 100644 src/main/resources/assets/dimdoors/textures/blocks/tile.dimDoor_bottom.png rename src/main/resources/assets/dimdoors/textures/blocks/{tile.dimDoorLink_bottom.png => tile.dimDoor_lower.png} (100%) delete mode 100644 src/main/resources/assets/dimdoors/textures/blocks/tile.dimDoor_top.png rename src/main/resources/assets/dimdoors/textures/blocks/{tile.dimDoorLink_top.png => tile.dimDoor_upper.png} (100%) delete mode 100644 src/main/resources/assets/dimdoors/textures/blocks/tile.dimDoorexitlink_bottom.png delete mode 100644 src/main/resources/assets/dimdoors/textures/blocks/tile.dimDoorexitlink_top.png rename src/main/resources/assets/dimdoors/textures/blocks/{tile.doorGold_bottom.png => tile.doorGold_lower.png} (100%) rename src/main/resources/assets/dimdoors/textures/blocks/{tile.doorGold_top.png => tile.doorGold_upper.png} (100%) rename src/main/resources/assets/dimdoors/textures/blocks/{tile.transientDoor - Copy.png => tile.transientDoor_lower.png} (100%) delete mode 100644 src/main/resources/assets/dimdoors/textures/blocks/tile.transientDoor_top.png rename src/main/resources/assets/dimdoors/textures/blocks/{tile.transientDoor_bottom.png => tile.transientDoor_upper.png} (100%) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BaseDimDoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BaseDimDoor.java index 6fe1d08..22e7649 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BaseDimDoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BaseDimDoor.java @@ -6,6 +6,7 @@ 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; @@ -28,8 +29,12 @@ import cpw.mods.fml.relauncher.SideOnly; public abstract class BaseDimDoor extends BlockDoor implements IDimDoor, ITileEntityProvider { - private Icon blockIconBottom; - protected final DDProperties properties; + protected final DDProperties properties; + + @SideOnly(Side.CLIENT) + private Icon[] upperTextures; + @SideOnly(Side.CLIENT) + private Icon[] lowerTextures; public BaseDimDoor(int blockID, Material material, DDProperties properties) { @@ -39,10 +44,15 @@ public abstract class BaseDimDoor extends BlockDoor implements IDimDoor, ITileEn } @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); } /** @@ -50,9 +60,9 @@ public abstract class BaseDimDoor extends BlockDoor implements IDimDoor, ITileEn */ @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 @@ -64,22 +74,24 @@ 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; + final int MAGIC_CONSTANT = 1003; + + int metadata = this.getFullMetadata(world, x, y, z); + int lowMeta = metadata & 7; + lowMeta ^= 4; - if ((var10 & 8) == 0) + if (isUpperDoorBlock(metadata)) { - world.setBlockMetadataWithNotify(x, y, z, var11,2); - world.markBlockRangeForRenderUpdate(x, y, z, x, y, z); + 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; } @@ -91,23 +103,73 @@ 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]; + else + return this.lowerTextures[reversed ? 1 : 0]; + } + else + { + 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. @@ -353,12 +415,12 @@ public abstract class BaseDimDoor extends BlockDoor implements IDimDoor, ITileEn @Override public abstract int getDrops(); - protected static boolean isUpperDoorBlock(int metadata) + public static boolean isUpperDoorBlock(int metadata) { return (metadata & 8) != 0; } - protected static boolean isDoorOpen(int metadata) + public static boolean isDoorOpen(int metadata) { return (metadata & 4) != 0; } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockDimWall.java b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockDimWall.java index 8d90548..82e451a 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockDimWall.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockDimWall.java @@ -27,7 +27,7 @@ public class BlockDimWall extends Block public BlockDimWall(int blockID, int j, Material par2Material) { - super(blockID, Material.ground); + super(blockID, par2Material); this.setCreativeTab(mod_pocketDim.dimDoorsCreativeTab); } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockDoorGold.java b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockDoorGold.java index 41b45c0..54972e4 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockDoorGold.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockDoorGold.java @@ -8,6 +8,7 @@ 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; @@ -15,19 +16,27 @@ import net.minecraft.world.IBlockAccess; public class BlockDoorGold extends BlockDoor { - private Icon blockIconBottom; + @SideOnly(Side.CLIENT) + private Icon[] upperTextures; + @SideOnly(Side.CLIENT) + private Icon[] lowerTextures; public BlockDoorGold(int par1, Material par2Material) { super(par1, par2Material); } - + @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); + } @Override public int idDropped(int par1, Random par2Random, int par3) @@ -35,23 +44,81 @@ public class BlockDoorGold extends BlockDoor return (par1 & 8) != 0 ? 0 : mod_pocketDim.itemGoldenDoor.itemID; } - @Override - public Icon getIcon(int par1, int par2) - { - return this.blockIcon; - } - + /** + * From the specified side and block metadata retrieves the blocks texture. Args: side, metadata + */ @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; - } - } + public Icon getIcon(int side, int metadata) + { + return this.upperTextures[0]; + } + + /** + * 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 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 (BaseDimDoor.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 (BaseDimDoor.isUpperDoorBlock(fullMetadata)) + return this.upperTextures[reversed ? 1 : 0]; + else + return this.lowerTextures[reversed ? 1 : 0]; + } + else + { + return this.lowerTextures[0]; + } + } } 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.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 825356d73f76b5ecd54adeddfb122a1d07f69f71..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 625 zcmV-%0*?KOP)+cY>BBb#}qLvmdN-VJ!tuB;WLn|7JlxU-iXj1;vk!R%Xhts)t?wm7c z=B*nY9aS!u)7jaX%H^`&-rn^2`Kflht>52YeSCb_{r&x2kB^VKySp>MSzB9^J3l`+ zGRc>h7kzzwsoU-9=jX=+xOX}o6RB3Ky1&2I)zy`bj*hglvLbhJabW_tx3{WPD%P>l zXc+PP``aS9=jUe?i$&%0c^w}gE166x9*@gmC7aFa^z_tRVDt6$)wuM0(3hJZ67@8NLRx=&0@C=dw9O-)S+kl=xF!1D64 zHa0fQE@yJMM1;DTnHdca56ewYPit~=(gf&ECjbc-o&eyTJ3=`2`~Cj{s1dOTm@g8E z7`(Ih2B<|~aBxs=Y-~(JLqnzpND|30qnG#20|Ntw{{DXT_4VlwKb)v~HJ7e_00000 LNkvXXu0mjfJ8LHB 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 4ec98689a80f9d286c486edbceef39cb960a66ae..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 540 zcmV+%0^|LOP)`76rkabIv(p#()9zPjy!<9KYfyrc20#d1z9KPQV0bVh7 zyB&(j3}i*#U(Reci*mUvm3Yr&GU8)Z-kIZYIH3G~zZiLbf9m}V1_P8zr4M_dP!KT6 zR(ieuuevsHv)N!c9Ddl_?KTMF@pzyN27}OHleB@y;}O&8^j`qC+x=`JH5ZFTv|25! zRx2D12i$HqoX=lMr8Qb0J$dc7_nKA%svP$cMdI{6OROzr?RvKkXenKlCRpW4}M e?hU_0GWY?mCFU(i_V%>^0000AI+mzZMX^1AF_W1*=gD_3n#qqd zcW3uPpr8+FeF?)DtG$=cCR+t5jvaa(hu z8qmUHc>!6k;zY@>MSW91XUBy5#s~cFF5sc*!mpMKy_AVR-#482*_^{&Z5mhQ8B~M+ z5tNCb=vO}~(4#9EahzQ<;TE zP{0`}Y9|aRdM9xb)pHAFzXqax1hP)v&Ix?8uldKbqzV0$g%dFECq6ZWXF*RgqrGLs zewYaJHhlN0u)!?!s)G=-E8{qh5P@Vtf7ixSe`r$L>q>NzMwEOiw71PTjTuS7EDuq1 zkbOH6|*}BVJ*+WZFtO}|>qUtAU7LQzvxqIp5nmc)a!7tzJ3Fi6NPT&aG$BdeYqYgdQp@+CTbd;W z8rlN|3SI$4%7fL)nrTp&aUy4x6{!WbtyS8KI&EypFCfhJpj((h`l}KmS!nD!(9BGs zl^x)i{u?ad_MRP`oP)kwIO!>YsWz@17OTwgPA>o_qRMlek){4@avWv^FGsUHAVLo3nkDq!j|2 zCjRZ{#VC8$k1Fdgi~ThCL_BmApIz8`6+ zU9+ypR(u#YBGjvcV6j;KoZhJkJXeRHM$DS^gB3Twa>msLL6&6{DJbSOXaX-cy{JXC z3HFzroJn->F@)o_5h$_^YTAMAnLb?9e7M>f#dRZytLk^p3)D#(zb)i}DVugAt`<|it&WtTG z$Y(0Ak+Sj4yEN9xc}#2XU!e5H1a<1}Ur947H;E{#fcbxO#*V$YKAbMOa8`8llUagu zdS_RYBnhG@LZ{Oq>oMHLx=dh6$q1Wp%>C}_q g90)ibAxI2<1IWB9LE=;As{jB107*qoM6N<$g8N!WrvLx| 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.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_top.png b/src/main/resources/assets/dimdoors/textures/blocks/tile.transientDoor_top.png deleted file mode 100644 index 8ceb7c901facccf03b31f193eeb89a08ce80af09..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2805 zcmVKLZ*U+IBfRsybQWXdwQbLP>6pAqfylh#{fb6;Z(vMMVS~$e@S=j*ftg6;Uhf59&ghTmgWD0l;*T zI709Y^p6lP1rIRMx#05C~cW=H_Aw*bJ-5DT&Z2n+x)QHX^p z00esgV8|mQcmRZ%02D^@S3L16t`O%c004NIvOKvYIYoh62rY33S640`D9%Y2D-rV&neh&#Q1i z007~1e$oCcFS8neI|hJl{-P!B1ZZ9hpmq0)X0i`JwE&>$+E?>%_LC6RbVIkUx0b+_+BaR3cnT7Zv!AJxW zizFb)h!jyGOOZ85F;a?DAXP{m@;!0_IfqH8(HlgRxt7s3}k3K`kFu>>-2Q$QMFfPW!La{h336o>X zu_CMttHv6zR;&ZNiS=X8v3CR#fknUxHUxJ0uoBa_M6WNWeqIg~6QE69c9o#eyhGvpiOA@W-aonk<7r1(?fC{oI5N*U!4 zfg=2N-7=cNnjjOr{yriy6mMFgG#l znCF=fnQv8CDz++o6_Lscl}eQ+l^ZHARH>?_s@|##Rr6KLRFA1%Q+=*RRWnoLsR`7U zt5vFIcfW3@?wFpwUVxrVZ>QdQz32KIeJ}k~{cZZE^+ya? z2D1z#2HOnI7(B%_ac?{wFUQ;QQA1tBKtrWrm0_3Rgps+?Jfqb{jYbcQX~taRB;#$y zZN{S}1|}gUOHJxc?wV3fxuz+mJ4`!F$IZ;mqRrNsHJd##*D~ju=bP7?-?v~|cv>vB zsJ6IeNwVZxrdjT`yl#bBIa#GxRa#xMMy;K#CDyyGyQdMSxlWT#tDe?p!?5wT$+oGt z8L;Kp2HUQ-ZMJ=3XJQv;x5ci*?vuTfeY$;({XGW_huIFR9a(?@3)XSs8O^N5RyOM=TTmp(3=8^+zpz2r)C z^>JO{deZfso3oq3?Wo(Y?l$ge?uXo;%ru`Vo>?<<(8I_>;8Eq#KMS9gFl*neeosSB zfoHYnBQIkwkyowPu(zdms`p{<7e4kra-ZWq<2*OsGTvEV%s0Td$hXT+!*8Bnh2KMe zBmZRodjHV?r+_5^X9J0WL4jKW`}lf%A-|44I@@LTvf1rHjG(ze6+w@Jt%Bvjts!X0 z?2xS?_ve_-kiKB_KiJlZ$9G`c^=E@oNG)mWWaNo-3TIW8)$Hg0Ub-~8?KhvJ>$ z3*&nim@mj(aCxE5!t{lw7O5^0EIO7zOo&c6l<+|iDySBWCGrz@C5{St!X3hAA}`T4 z(TLbXTq+(;@<=L8dXnssyft|w#WSTW<++3>sgS%(4NTpeI-VAqb|7ssJvzNHgOZVu zaYCvgO_R1~>SyL=cFU|~g|hy|Zi}}s9+d~lYqOB71z9Z$wnC=pR9Yz4DhIM>Wmjgu z&56o6maCpC&F##y%G;1PobR9i?GnNg;gYtchD%p19a!eQtZF&3JaKv33gZ<8D~47E ztUS1iwkmDaPpj=$m#%)jCVEY4fnLGNg2A-`YwHVD3gv};>)hAvT~AmqS>Lr``i7kw zJ{5_It`yrBmlc25DBO7E8;5VoznR>Ww5hAaxn$2~(q`%A-YuS64wkBy=9dm`4cXeX z4c}I@?e+FW+b@^RDBHV(wnMq2zdX3SWv9u`%{xC-q*U}&`cyXV(%rRT*Z6MH?i+i& z_B8C(+grT%{XWUQ+f@NoP1R=AW&26{v-dx)iK^-Nmiuj8txj!m?Z*Ss1N{dh4z}01 z)YTo*JycSU)+_5r4#yw9{+;i4Ee$peRgIj+;v;ZGdF1K$3E%e~4LaI(jC-u%2h$&R z9cLXcYC@Xwnns&bn)_Q~Te?roKGD|d-g^8;+aC{{G(1^(O7m37Y1-+6)01cN&y1aw zoqc{T`P^XJqPBbIW6s}d4{z_f5Om?vMgNQEJG?v2T=KYd^0M3I6IZxbny)%vZR&LD zJpPl@Psh8QyPB@KTx+@RdcC!KX7}kEo;S|j^u2lU7XQ}Oo;f|;z4Ll+_r>@1-xl3| zawq-H%e&ckC+@AhPrP6BKT#_XdT7&;F71j}Joy zkC~6lh7E@6o;W@^IpRNZ{ptLtL(gQ-CY~4mqW;US7Zxvm_|@yz&e53Bp_lTPlfP|z zrTyx_>lv@x#=^!PzR7qqF<$gm`|ZJZ+;<)Cqu&ot2z=0000WV@Og>004R=004l4008;_004mL004C`008P>0026e000+nl3&F} z0000WNkl Date: Fri, 7 Mar 2014 22:21:34 -0400 Subject: [PATCH 012/187] Fixed Door Bug Fixed the bug referenced in the previous commit that caused doors to break instantly. --- .../StevenDimDoors/mod_pocketDim/blocks/BaseDimDoor.java | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BaseDimDoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BaseDimDoor.java index 22e7649..ee37ab0 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BaseDimDoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BaseDimDoor.java @@ -82,7 +82,7 @@ public abstract class BaseDimDoor extends BlockDoor implements IDimDoor, ITileEn if (isUpperDoorBlock(metadata)) { - world.setBlockMetadataWithNotify(x, y - 1, z, lowMeta,2); + world.setBlockMetadataWithNotify(x, y - 1, z, lowMeta, 2); world.markBlockRangeForRenderUpdate(x, y - 1, z, x, y, z); } else @@ -295,7 +295,7 @@ public abstract class BaseDimDoor extends BlockDoor implements IDimDoor, ITileEn public void onNeighborBlockChange(World world, int x, int y, int z, int neighborID) { int metadata = world.getBlockMetadata(x, y, z); - if (!isUpperDoorBlock(metadata)) + if (isUpperDoorBlock(metadata)) { if (world.getBlockId(x, y - 1, z) != this.blockID) { @@ -403,7 +403,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) @@ -412,9 +411,6 @@ public abstract class BaseDimDoor extends BlockDoor implements IDimDoor, ITileEn } } - @Override - public abstract int getDrops(); - public static boolean isUpperDoorBlock(int metadata) { return (metadata & 8) != 0; From b393c763a9cdf16dc763c4054478748b5489bc8f Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Sun, 9 Mar 2014 10:07:35 -0400 Subject: [PATCH 013/187] Minor Change Minor change to configuration explanation --- src/main/java/StevenDimDoors/mod_pocketDim/DDProperties.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/DDProperties.java b/src/main/java/StevenDimDoors/mod_pocketDim/DDProperties.java index 0c61faf..f0494ce 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/DDProperties.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/DDProperties.java @@ -157,7 +157,7 @@ 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, From 946ac37a27ab0026b1147a863a9f866435d1420f Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Tue, 11 Mar 2014 01:31:10 -0400 Subject: [PATCH 014/187] Changes to Schematics Added SK-RaceTheLight to our schematics. Changed the weights on Cere-FloatingAltar and Cere-PuzzleWall to 75 (previously 100). Fixed what appears to be a mistake pasted into ruins.txt and also updated it for the latest dungeons. --- src/main/resources/schematics/ruins.txt | 6 +++--- ...omplexHall_Cere-PuzzleWall_Open_75.schematic} | Bin ...DeadEnd_Cere-FloatingAltar_Open_75.schematic} | Bin .../Trap_SK-RaceTheLight_Closed_50.schematic | Bin 0 -> 1604 bytes 4 files changed, 3 insertions(+), 3 deletions(-) rename src/main/resources/schematics/ruins/{ComplexHall_Cere-PuzzleWall_Open.schematic => ComplexHall_Cere-PuzzleWall_Open_75.schematic} (100%) rename src/main/resources/schematics/ruins/{DeadEnd_Cere-FloatingAltar_Open_100.schematic => DeadEnd_Cere-FloatingAltar_Open_75.schematic} (100%) create mode 100644 src/main/resources/schematics/ruins/Trap_SK-RaceTheLight_Closed_50.schematic diff --git a/src/main/resources/schematics/ruins.txt b/src/main/resources/schematics/ruins.txt index 2641e62..f922cbb 100644 --- a/src/main/resources/schematics/ruins.txt +++ b/src/main/resources/schematics/ruins.txt @@ -1,4 +1,5 @@ /schematics/ruins/complexHall_buggyTopEntry1_open_100.schematic +/schematics/ruins/ComplexHall_Cere-PuzzleWall_Open_75.schematic /schematics/ruins/complexHall_exitRuinsWithHiddenDoor_open_100.schematic /schematics/ruins/complexHall_hallwayHiddenTreasure_closed_100.schematic /schematics/ruins/complexHall_largeBrokenHall_closed_100.schematic @@ -15,6 +16,7 @@ /schematics/ruins/complexHall_tntPuzzleTrap_closed_50.schematic /schematics/ruins/deadEnd_azersDungeonO_closed_100.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 @@ -72,6 +74,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 +82,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_Cere-PuzzleWall_Open.schematic b/src/main/resources/schematics/ruins/ComplexHall_Cere-PuzzleWall_Open_75.schematic similarity index 100% rename from src/main/resources/schematics/ruins/ComplexHall_Cere-PuzzleWall_Open.schematic rename to src/main/resources/schematics/ruins/ComplexHall_Cere-PuzzleWall_Open_75.schematic diff --git a/src/main/resources/schematics/ruins/DeadEnd_Cere-FloatingAltar_Open_100.schematic b/src/main/resources/schematics/ruins/DeadEnd_Cere-FloatingAltar_Open_75.schematic similarity index 100% rename from src/main/resources/schematics/ruins/DeadEnd_Cere-FloatingAltar_Open_100.schematic rename to src/main/resources/schematics/ruins/DeadEnd_Cere-FloatingAltar_Open_75.schematic 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 0000000000000000000000000000000000000000..44df526533179a4e94cce055107c1164381976a7 GIT binary patch literal 1604 zcmV-K2D|wmiwFP!000000PUU6Zrer>#)pz<{j;q&X#@09G-n3B63C@Z<)A67A_W|v zCkG%b)*>R4fo-60n&l? z#ns5Zv3%#M35_$$w*Y?ffkYyasw_RwuJ?hIh4i`(++(YE1H=V&VGvCb0^&1dK%-o# zZtZ#pN~3xs5W7(ikGZDTYgvQ#9Ow*yxPk?`Iv_qHy0&ux@ArH_cv`l?xYKQC8|mEJ zb1mGc1INJm>-hk!;2w*3hOTR>W+aI4jM~bKoy(8ri{{SBMfS0Op zW4DJMaUAs8Nw}DCbe#Q+o|+lO3p*_CI=kM9@{4O>uO3}a1S%q+f!5oD8HH4f7Vg=p z$1V!C5kH6Jn^8zrHSFlhQU>t9lL^+s2tX@Bz>QYvW+-!4r7C-E-*BM#U$^0_J{;)6 z6#$JrnSr&^1Wz2Ls%Y3ZrM;yr?F144bvKW+m;c&c+wg3IB<{7K;+WUh0Q+rN;UcPh zcXzsyDSg;wrF7jcx}c{S+XIy<|Fyjc!oIW6Hjt{$$V2F9Lt!TsL+FW9%rlBaB9TZW z5{X12kw_#Gi9{li)T#}w7q0L4jy;RM7HvWMH_NxDjy0Zv{(L+cS#3Cc?TqdCWu4$v zKej>t)wgfrnwm3&gO}c9Vo&Sv;PupUXMft$zUPgH-a9vVNxcr*U*Wjm@x$Wz`{1zy zqMaH@r><}(9qDu^-01-6bfm1)v2dr_qEjc~_`JB&_iiTE)bhQc!Qrc0e{$zmE!!sa}NF)-8 zL?V$&tfnwgS+OI%TdFx(c_Im#^Nw=>Fxd+bzrn0*Uv8eP21Eo*RzWjWtK7lr?#Azf zY$w~R1ITu=T_umy)fog5fK)=&;NYe0 zT#tNsTm$_NXXuaMyCxjO|F)o%|D)wSBLV~jK*@x^LFRP?sthRY2rz;l0>J!Ma!~QK ze+k8c@L+%WY<$iO7$pGFz=FE(~+a3Q9W$&Uqk+)Dtd1D5x( zjz<=0-^H~Zc-qUf6G(uaroF<~b_25=15n8LlniWbJ6+oq0*SOs0H7H~N_%Cm?MlHZ z0#5Hv1uOP{#DD4EQ1NJ5D1PI83Vy2x$%2Roy9sUD5_v~$6vj6~h C<|bwU literal 0 HcmV?d00001 From 836eb8a7e09798763d8de63b69f506f22354c260 Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Tue, 11 Mar 2014 05:38:40 -0400 Subject: [PATCH 015/187] Added Support for Cluster and Gateway Filters Added a per-save config file called DimDoorsWorld.cfg. Its corresponding class is DDWorldProperties. This class supports whitelisting and blacklisting dimensions for Rift Cluster and Rift Gateway generation. Note that our ban against generating gateways in the Nether and The End still applies regardless of those settings. The new config file is loaded before the server starts initializing terrain. Also moved DDProperties to another package alongside DDWorldProperties - that required updating references in most of the mod's files. --- .../experimental/SphereDecayOperation.java | 2 +- .../mod_pocketDim/CraftingManager.java | 1 + .../StevenDimDoors/mod_pocketDim/DDLoot.java | 1 + .../StevenDimDoors/mod_pocketDim/DimData.java | 2 + .../mod_pocketDim/EventHookContainer.java | 1 + .../mod_pocketDim/blocks/BaseDimDoor.java | 2 +- .../blocks/BlockDimWallPerm.java | 2 +- .../mod_pocketDim/blocks/BlockDoorGold.java | 2 +- .../blocks/BlockGoldDimDoor.java | 2 +- .../mod_pocketDim/blocks/BlockRift.java | 2 +- .../mod_pocketDim/blocks/DimensionalDoor.java | 2 +- .../mod_pocketDim/blocks/TransientDoor.java | 2 +- .../mod_pocketDim/blocks/UnstableDoor.java | 2 +- .../mod_pocketDim/blocks/WarpDoor.java | 2 +- .../commands/CommandExportDungeon.java | 2 +- .../{ => config}/DDProperties.java | 6 +- .../config/DDWorldProperties.java | 68 ++++++++++++++ .../mod_pocketDim/config/DimensionFilter.java | 93 +++++++++++++++++++ .../mod_pocketDim/core/DDTeleporter.java | 2 +- .../mod_pocketDim/core/NewDimData.java | 2 +- .../mod_pocketDim/core/PocketManager.java | 2 +- .../dungeon/DungeonSchematic.java | 2 +- .../dungeon/FillContainersOperation.java | 2 +- .../mod_pocketDim/helpers/DungeonHelper.java | 2 +- .../mod_pocketDim/items/BaseItemDoor.java | 2 +- .../mod_pocketDim/items/ItemRiftBlade.java | 2 +- .../mod_pocketDim/mod_pocketDim.java | 30 ++++-- .../ticking/CustomLimboPopulator.java | 2 +- .../mod_pocketDim/ticking/LimboDecay.java | 2 +- .../mod_pocketDim/ticking/MobMonolith.java | 2 +- .../tileentities/TileEntityRift.java | 2 +- .../mod_pocketDim/world/CustomCaveGen.java | 2 +- .../mod_pocketDim/world/LimboGenerator.java | 2 +- .../mod_pocketDim/world/LimboProvider.java | 2 +- .../mod_pocketDim/world/PocketBuilder.java | 2 +- .../mod_pocketDim/world/PocketProvider.java | 2 +- .../fortresses/DDNetherFortressGenerator.java | 2 +- .../DDStructureNetherBridgeStart.java | 2 +- .../world/gateways/BaseGateway.java | 2 +- .../world/gateways/GatewayGenerator.java | 27 +++--- .../world/gateways/GatewayLimbo.java | 2 +- .../gateways/GatewaySandstonePillars.java | 2 +- .../world/gateways/GatewayTwoPillars.java | 2 +- .../mod_pocketDimClient/RenderDimDoor.java | 2 +- .../RenderTransTrapdoor.java | 2 +- 45 files changed, 240 insertions(+), 61 deletions(-) rename src/main/java/StevenDimDoors/mod_pocketDim/{ => config}/DDProperties.java (97%) create mode 100644 src/main/java/StevenDimDoors/mod_pocketDim/config/DDWorldProperties.java create mode 100644 src/main/java/StevenDimDoors/mod_pocketDim/config/DimensionFilter.java 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/CraftingManager.java b/src/main/java/StevenDimDoors/mod_pocketDim/CraftingManager.java index 9109f16..086054a 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/CraftingManager.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/CraftingManager.java @@ -1,5 +1,6 @@ package StevenDimDoors.mod_pocketDim; +import StevenDimDoors.mod_pocketDim.config.DDProperties; import net.minecraft.block.Block; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/DDLoot.java b/src/main/java/StevenDimDoors/mod_pocketDim/DDLoot.java index 74dc5e9..599786f 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/DDLoot.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/DDLoot.java @@ -12,6 +12,7 @@ import net.minecraft.util.MathHelper; import net.minecraft.util.WeightedRandom; import net.minecraft.util.WeightedRandomChestContent; import net.minecraftforge.common.ChestGenHooks; +import StevenDimDoors.mod_pocketDim.config.DDProperties; import StevenDimDoors.mod_pocketDim.util.WeightedContainer; /* diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/DimData.java b/src/main/java/StevenDimDoors/mod_pocketDim/DimData.java index 7648161..cd57285 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/DimData.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/DimData.java @@ -8,6 +8,8 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; +import StevenDimDoors.mod_pocketDim.config.DDProperties; + import net.minecraft.util.MathHelper; import net.minecraft.world.World; @Deprecated diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java b/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java index 8f6c4a3..d3b09f4 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java @@ -19,6 +19,7 @@ import net.minecraftforge.event.entity.living.LivingFallEvent; import net.minecraftforge.event.entity.player.PlayerInteractEvent; import net.minecraftforge.event.terraingen.InitMapGenEvent; import net.minecraftforge.event.world.WorldEvent; +import StevenDimDoors.mod_pocketDim.config.DDProperties; import StevenDimDoors.mod_pocketDim.core.DDTeleporter; import StevenDimDoors.mod_pocketDim.core.PocketManager; import StevenDimDoors.mod_pocketDim.items.BaseItemDoor; diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BaseDimDoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BaseDimDoor.java index ee37ab0..9c56e91 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BaseDimDoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BaseDimDoor.java @@ -17,8 +17,8 @@ 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; diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockDimWallPerm.java b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockDimWallPerm.java index 5047d9e..42a2d1e 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; diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockDoorGold.java b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockDoorGold.java index 54972e4..1e8f91e 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockDoorGold.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockDoorGold.java @@ -4,8 +4,8 @@ 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 StevenDimDoors.mod_pocketDim.config.DDProperties; import net.minecraft.block.BlockDoor; import net.minecraft.block.material.Material; import net.minecraft.client.renderer.IconFlipped; diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockGoldDimDoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockGoldDimDoor.java index b4ffd21..5a788db 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockGoldDimDoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockGoldDimDoor.java @@ -1,7 +1,7 @@ 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.NewDimData; diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockRift.java b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockRift.java index 5f6f896..4e307cd 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockRift.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockRift.java @@ -20,9 +20,9 @@ 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; diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/DimensionalDoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/DimensionalDoor.java index f8869ea..42d25f6 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/DimensionalDoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/DimensionalDoor.java @@ -3,7 +3,7 @@ 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.config.DDProperties; import StevenDimDoors.mod_pocketDim.core.DimLink; import StevenDimDoors.mod_pocketDim.core.LinkTypes; import StevenDimDoors.mod_pocketDim.core.NewDimData; diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/TransientDoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/TransientDoor.java index bac5c5d..fb0a187 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/TransientDoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/TransientDoor.java @@ -6,7 +6,7 @@ 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.DDProperties; +import StevenDimDoors.mod_pocketDim.config.DDProperties; import StevenDimDoors.mod_pocketDim.core.DDTeleporter; import StevenDimDoors.mod_pocketDim.core.DimLink; import StevenDimDoors.mod_pocketDim.core.LinkTypes; diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/UnstableDoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/UnstableDoor.java index cf2b699..e59a94c 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/UnstableDoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/UnstableDoor.java @@ -3,7 +3,7 @@ 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.config.DDProperties; import StevenDimDoors.mod_pocketDim.core.LinkTypes; import StevenDimDoors.mod_pocketDim.core.NewDimData; import StevenDimDoors.mod_pocketDim.core.PocketManager; diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/WarpDoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/WarpDoor.java index 7decebf..6f7d881 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/WarpDoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/WarpDoor.java @@ -3,7 +3,7 @@ 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.config.DDProperties; import StevenDimDoors.mod_pocketDim.core.DimLink; import StevenDimDoors.mod_pocketDim.core.LinkTypes; import StevenDimDoors.mod_pocketDim.core.NewDimData; diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandExportDungeon.java b/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandExportDungeon.java index 86008cd..4c0ad4d 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandExportDungeon.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandExportDungeon.java @@ -4,7 +4,7 @@ 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 diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/DDProperties.java b/src/main/java/StevenDimDoors/mod_pocketDim/config/DDProperties.java similarity index 97% rename from src/main/java/StevenDimDoors/mod_pocketDim/DDProperties.java rename to src/main/java/StevenDimDoors/mod_pocketDim/config/DDProperties.java index f0494ce..18378df 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/DDProperties.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/config/DDProperties.java @@ -1,4 +1,4 @@ -package StevenDimDoors.mod_pocketDim; +package StevenDimDoors.mod_pocketDim.config; import java.io.File; @@ -87,7 +87,6 @@ public class DDProperties * Other Flags */ - public final boolean WorldRiftGenerationEnabled; public final boolean RiftSpreadEnabled; public final boolean RiftGriefingEnabled; public final boolean RiftsSpawnEndermenEnabled; @@ -204,9 +203,6 @@ public class DDProperties 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); MonolithTeleportationEnabled = config.get(Configuration.CATEGORY_GENERAL, "Enable Monolith Teleportation", true, "Sets whether Monoliths can teleport players").getBoolean(true); 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..f669ded --- /dev/null +++ b/src/main/java/StevenDimDoors/mod_pocketDim/config/DDWorldProperties.java @@ -0,0 +1,68 @@ +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; + + //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"); + + 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/DDTeleporter.java b/src/main/java/StevenDimDoors/mod_pocketDim/core/DDTeleporter.java index e4e9c7a..8905140 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/core/DDTeleporter.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/core/DDTeleporter.java @@ -22,10 +22,10 @@ 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.config.DDProperties; import StevenDimDoors.mod_pocketDim.helpers.yCoordHelper; import StevenDimDoors.mod_pocketDim.items.BaseItemDoor; import StevenDimDoors.mod_pocketDim.items.ItemDimensionalDoor; diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/core/NewDimData.java b/src/main/java/StevenDimDoors/mod_pocketDim/core/NewDimData.java index 46158a8..6eb201b 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/core/NewDimData.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/core/NewDimData.java @@ -8,8 +8,8 @@ import java.util.TreeMap; import StevenDimDoors.mod_pocketDim.watcher.ClientLinkData; 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.util.Point4D; diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/core/PocketManager.java b/src/main/java/StevenDimDoors/mod_pocketDim/core/PocketManager.java index 29fbf75..842c6c8 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/core/PocketManager.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/core/PocketManager.java @@ -15,9 +15,9 @@ import cpw.mods.fml.relauncher.SideOnly; 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; diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/dungeon/DungeonSchematic.java b/src/main/java/StevenDimDoors/mod_pocketDim/dungeon/DungeonSchematic.java index 8395d9b..38848ad 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/dungeon/DungeonSchematic.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/dungeon/DungeonSchematic.java @@ -16,9 +16,9 @@ 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.NewDimData; diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/dungeon/FillContainersOperation.java b/src/main/java/StevenDimDoors/mod_pocketDim/dungeon/FillContainersOperation.java index 62bec13..5a91f31 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 diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/helpers/DungeonHelper.java b/src/main/java/StevenDimDoors/mod_pocketDim/helpers/DungeonHelper.java index 3f8e7a3..56de06a 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/helpers/DungeonHelper.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/helpers/DungeonHelper.java @@ -19,8 +19,8 @@ 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.NewDimData; diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/items/BaseItemDoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/items/BaseItemDoor.java index 8651270..e97ad6a 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/items/BaseItemDoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/items/BaseItemDoor.java @@ -11,8 +11,8 @@ import net.minecraft.item.ItemStack; import net.minecraft.util.MathHelper; import net.minecraft.util.MovingObjectPosition; 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.PocketManager; import StevenDimDoors.mod_pocketDim.tileentities.TileEntityDimDoor; diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemRiftBlade.java b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemRiftBlade.java index ceee388..a49735a 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; diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java b/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java index a4e6844..b433abb 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java @@ -15,7 +15,6 @@ 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; @@ -34,6 +33,8 @@ import StevenDimDoors.mod_pocketDim.commands.CommandDeleteRifts; import StevenDimDoors.mod_pocketDim.commands.CommandExportDungeon; 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; @@ -74,8 +75,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; @@ -134,6 +136,7 @@ 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 GatewayGenerator gatewayGenerator; @@ -296,25 +299,36 @@ public class mod_pocketDim } @EventHandler - public void onServerStopping(FMLServerStoppingEvent event) + public void onServerStopped(FMLServerStoppedEvent event) { try { PocketManager.unload(); deathTracker.writeToFile(); deathTracker = null; + worldProperties = null; } catch (Exception e) { e.printStackTrace(); } } + + @EventHandler + public void onServerAboutToStart(FMLServerAboutToStartEvent event) + { + final String saveRootDirectory = DimensionManager.getCurrentSaveRootDirectory().getAbsolutePath(); + + // Load the config file that's specific to this world + worldProperties = new DDWorldProperties(new File(saveRootDirectory + "/DimensionalDoors/DimDoorsWorld.cfg")); + + // Initialize a new DeathTracker + deathTracker = new DeathTracker(saveRootDirectory + "/DimensionalDoors/data/deaths.txt"); + } @EventHandler public void onServerStarting(FMLServerStartingEvent event) { - //TODO- load dims with forced chunks on server startup here - // Register commands with the server event.registerServerCommand( CommandResetDungeons.instance() ); event.registerServerCommand( CommandCreateDungeonRift.instance() ); @@ -327,9 +341,6 @@ public class mod_pocketDim event.registerServerCommand( CommandCreatePocket.instance() ); event.registerServerCommand( CommandTeleportPlayer.instance() ); - // Initialize a new DeathTracker - String deathTrackerFile = DimensionManager.getCurrentSaveRootDirectory() + "/DimensionalDoors/data/deaths.txt"; - deathTracker = new DeathTracker(deathTrackerFile); try { @@ -337,7 +348,8 @@ public class mod_pocketDim } 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()); } } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/ticking/CustomLimboPopulator.java b/src/main/java/StevenDimDoors/mod_pocketDim/ticking/CustomLimboPopulator.java index 908e2e9..465e57b 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/ticking/CustomLimboPopulator.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/ticking/CustomLimboPopulator.java @@ -9,8 +9,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; diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/ticking/LimboDecay.java b/src/main/java/StevenDimDoors/mod_pocketDim/ticking/LimboDecay.java index c325109..e5c9420 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/ticking/LimboDecay.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/ticking/LimboDecay.java @@ -7,7 +7,7 @@ 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 diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/ticking/MobMonolith.java b/src/main/java/StevenDimDoors/mod_pocketDim/ticking/MobMonolith.java index 9119d08..ae1f7cc 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/ticking/MobMonolith.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/ticking/MobMonolith.java @@ -18,8 +18,8 @@ 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; diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityRift.java b/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityRift.java index 6432062..d597e9f 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityRift.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityRift.java @@ -25,9 +25,9 @@ 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; 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/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..3be9520 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/world/LimboProvider.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/world/LimboProvider.java @@ -12,8 +12,8 @@ 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 cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/world/PocketBuilder.java b/src/main/java/StevenDimDoors/mod_pocketDim/world/PocketBuilder.java index 8a30d34..c384ec4 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/world/PocketBuilder.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/world/PocketBuilder.java @@ -9,9 +9,9 @@ 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.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.NewDimData; diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/world/PocketProvider.java b/src/main/java/StevenDimDoors/mod_pocketDim/world/PocketProvider.java index 33f8c70..08924d8 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/world/PocketProvider.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/world/PocketProvider.java @@ -9,8 +9,8 @@ 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.PocketManager; import StevenDimDoors.mod_pocketDim.ticking.CustomLimboPopulator; import cpw.mods.fml.relauncher.Side; 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..644a5c1 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; 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..bc7cc06 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 { 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..92572b7 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/world/gateways/BaseGateway.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/world/gateways/BaseGateway.java @@ -6,9 +6,9 @@ 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.config.DDProperties; import StevenDimDoors.mod_pocketDim.core.DimLink; import StevenDimDoors.mod_pocketDim.core.LinkTypes; import StevenDimDoors.mod_pocketDim.core.NewDimData; 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 a95ee24..9936150 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/world/gateways/GatewayGenerator.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/world/gateways/GatewayGenerator.java @@ -8,8 +8,8 @@ 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.NewDimData; @@ -58,15 +58,17 @@ 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 or The End. + int dimensionID = world.provider.dimensionId; + if (world.isRemote + || (world.provider instanceof PocketProvider) + || (dimensionID == END_DIMENSION_ID) + || (dimensionID == NETHER_DIMENSION_ID)) { 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; @@ -113,9 +117,10 @@ public class GatewayGenerator implements IWorldGenerator while (random.nextInt(MAX_CLUSTER_GROWTH_CHANCE) < CLUSTER_GROWTH_CHANCE); } - // Randomly decide whether to place a Rift Gateway here. + // 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 (random.nextInt(MAX_GATEWAY_GENERATION_CHANCE) < properties.GatewayGenerationChance) + 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 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..6dbf10b 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/world/gateways/GatewayLimbo.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/world/gateways/GatewayLimbo.java @@ -1,8 +1,8 @@ package StevenDimDoors.mod_pocketDim.world.gateways; 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.dungeon.pack.DungeonPack; import StevenDimDoors.mod_pocketDim.helpers.DungeonHelper; import StevenDimDoors.mod_pocketDim.items.BaseItemDoor; 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..cab1e12 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/world/gateways/GatewaySandstonePillars.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/world/gateways/GatewaySandstonePillars.java @@ -3,8 +3,8 @@ package StevenDimDoors.mod_pocketDim.world.gateways; import java.util.ArrayList; import java.util.Random; -import StevenDimDoors.mod_pocketDim.DDProperties; import StevenDimDoors.mod_pocketDim.mod_pocketDim; +import StevenDimDoors.mod_pocketDim.config.DDProperties; import StevenDimDoors.mod_pocketDim.dungeon.pack.DungeonPack; import StevenDimDoors.mod_pocketDim.helpers.DungeonHelper; import net.minecraft.block.Block; 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..9e1ea33 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/world/gateways/GatewayTwoPillars.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/world/gateways/GatewayTwoPillars.java @@ -2,8 +2,8 @@ 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.config.DDProperties; import StevenDimDoors.mod_pocketDim.dungeon.pack.DungeonPack; import StevenDimDoors.mod_pocketDim.helpers.DungeonHelper; import StevenDimDoors.mod_pocketDim.world.LimboProvider; diff --git a/src/main/java/StevenDimDoors/mod_pocketDimClient/RenderDimDoor.java b/src/main/java/StevenDimDoors/mod_pocketDimClient/RenderDimDoor.java index 88358d1..6639974 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDimClient/RenderDimDoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDimClient/RenderDimDoor.java @@ -11,8 +11,8 @@ 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.config.DDProperties; import StevenDimDoors.mod_pocketDim.core.DimLink; import StevenDimDoors.mod_pocketDim.core.NewDimData; import StevenDimDoors.mod_pocketDim.core.PocketManager; diff --git a/src/main/java/StevenDimDoors/mod_pocketDimClient/RenderTransTrapdoor.java b/src/main/java/StevenDimDoors/mod_pocketDimClient/RenderTransTrapdoor.java index dc65e57..0f3ea97 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDimClient/RenderTransTrapdoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDimClient/RenderTransTrapdoor.java @@ -11,9 +11,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; From 73cb5ccb6c38fbc428ae2d9e3b1610d4a6d26b88 Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Wed, 12 Mar 2014 05:08:49 -0400 Subject: [PATCH 016/187] Fixed Rifts Spreading through Walls Fixed the issue of rifts spreading through walls. We tried using raytracing but rifts would always "leak" out of unbreakable enclosures. With this latest change, rifts spread with the same logic that determines which blocks are reachable to them. --- .../mod_pocketDim/blocks/BlockRift.java | 84 +++++++++++++++---- .../mod_pocketDim/core/NewDimData.java | 1 - .../tileentities/TileEntityRift.java | 51 ++--------- 3 files changed, 73 insertions(+), 63 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockRift.java b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockRift.java index 4e307cd..cc15c9f 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; @@ -27,6 +26,7 @@ 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,7 +38,7 @@ 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; @@ -164,11 +164,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) + { + spawnWorldThread(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 +195,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,18 +210,16 @@ 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) { if (blockID != 0 && (random.nextInt(MAX_WORLD_THREAD_CHANCE) < WORLD_THREAD_CHANCE) @@ -236,11 +257,40 @@ public class BlockRift extends Block implements ITileEntityProvider if (!this.isBlockImmune(world, x, y, z) && world.getChunkProvider().chunkExists(x >> 4, z >> 4)) { int blockID = world.getBlockId(x, y, z); - world.setBlock(x, y, z, properties.RiftBlockID); - this.spawnWorldThread(blockID, world, x, y, z, random); + if (world.setBlock(x, y, z, properties.RiftBlockID)) + spawnWorldThread(blockID, world, x, y, z, random); } } + public boolean spreadRift(NewDimData dimension, DimLink parent, World world, Random random) + { + 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()) + { + // 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); + spawnWorldThread(blockID, world, x, y, z, random); + return true; + } + } + return false; + } + /** * Lets pistons push through rifts, destroying them */ diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/core/NewDimData.java b/src/main/java/StevenDimDoors/mod_pocketDim/core/NewDimData.java index 6eb201b..ba977d5 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/core/NewDimData.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/core/NewDimData.java @@ -15,7 +15,6 @@ import StevenDimDoors.mod_pocketDim.dungeon.pack.DungeonPack; import StevenDimDoors.mod_pocketDim.util.Point4D; import StevenDimDoors.mod_pocketDim.watcher.IUpdateWatcher; -@SuppressWarnings("deprecation") public abstract class NewDimData { private static class InnerDimLink extends DimLink diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityRift.java b/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityRift.java index d597e9f..dd6f08e 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityRift.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityRift.java @@ -35,8 +35,6 @@ import StevenDimDoors.mod_pocketDim.util.Point4D; public class TileEntityRift extends TileEntity { - 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 ENDERMAN_SPAWNING_CHANCE = 1; private static final int MAX_ENDERMAN_SPAWNING_CHANCE = 32; @@ -100,7 +98,7 @@ public class TileEntityRift extends TileEntity //This code should execute once every 10 seconds if (updateTimer > 200) { - this.spawnEndermen(); + //this.spawnEndermen(); this.grow(mod_pocketDim.properties); updateTimer = 0; } @@ -334,53 +332,16 @@ public class TileEntityRift extends TileEntity 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, 5, 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; - } - } - } - } + + hasGrownRifts = mod_pocketDim.blockRift.spreadRift(dimension, link, worldObj, random); } @Override From 5db2b35850d28ab32f6aca31fdc5cf9426020616 Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Wed, 12 Mar 2014 05:12:46 -0400 Subject: [PATCH 017/187] Minor Fix I forgot to uncomment the line for rifts spawning Endermen. --- .../mod_pocketDim/tileentities/TileEntityRift.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityRift.java b/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityRift.java index dd6f08e..a0031f3 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityRift.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityRift.java @@ -98,7 +98,7 @@ public class TileEntityRift extends TileEntity //This code should execute once every 10 seconds if (updateTimer > 200) { - //this.spawnEndermen(); + this.spawnEndermen(); this.grow(mod_pocketDim.properties); updateTimer = 0; } From 8d28dc15171748e3f646c3b643ce9905e68f076c Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Wed, 12 Mar 2014 06:06:45 -0400 Subject: [PATCH 018/187] Fixed Uncontrolled Rift Spread Switched rifts over to using link.childCount() to track spread instead of the hasGrownRifts flag in the tile entity. The flag had the flaw that if the rift was replaced by a block, the flag would reset and the rift could spread again. I think I remember this being intended as punishment for messing with rifts but it's a problem when combined with World Thread farming. --- .../tileentities/TileEntityRift.java | 21 ++++++++----------- 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityRift.java b/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityRift.java index a0031f3..4b7a600 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityRift.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityRift.java @@ -35,11 +35,14 @@ import StevenDimDoors.mod_pocketDim.util.Point4D; public class TileEntityRift extends TileEntity { - private static final int MAX_ANCESTOR_LINKS = 3; + 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 Random random = new Random(); @@ -51,7 +54,6 @@ public class TileEntityRift extends TileEntity public int zOffset = 0; public boolean shouldClose = false; private boolean hasUpdated = false; - private boolean hasGrownRifts = false; public DimLink nearestRiftData; public int spawnedEndermenID = 0; @@ -107,8 +109,6 @@ public class TileEntityRift extends TileEntity this.calculateOldParticleOffset(); //this also calculates the distance for the particle stuff. } updateTimer++; - - } @Override @@ -169,10 +169,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); } @@ -318,7 +318,7 @@ public class TileEntityRift extends TileEntity public void grow(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; @@ -327,7 +327,7 @@ public class TileEntityRift extends TileEntity NewDimData dimension = PocketManager.getDimensionData(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; } @@ -340,8 +340,7 @@ public class TileEntityRift extends TileEntity { return; } - - hasGrownRifts = mod_pocketDim.blockRift.spreadRift(dimension, link, worldObj, random); + mod_pocketDim.blockRift.spreadRift(dimension, link, worldObj, random); } @Override @@ -354,7 +353,6 @@ public class TileEntityRift extends TileEntity 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"); @@ -367,7 +365,6 @@ public class TileEntityRift extends TileEntity nbt.setInteger("age", this.age); nbt.setInteger("count", this.updateTimer); nbt.setInteger("count2", this.riftCloseTimer); - nbt.setBoolean("grownRifts",this.hasGrownRifts); nbt.setInteger("xOffset", this.xOffset); nbt.setInteger("yOffset", this.yOffset); nbt.setInteger("zOffset", this.zOffset); From 3a91d9a6ec8980ae33c4f47347d76b6b8ffbd9d9 Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Wed, 12 Mar 2014 07:05:23 -0400 Subject: [PATCH 019/187] Minor Adjustments to Rift Spread Made a small correction to the condition on max ancestors. Also thoroughly tested this code to ensure that it really does limit rift spread. Currently, 2 initial rifts will cause 4 more rifts to be created eventually. --- .../mod_pocketDim/tileentities/TileEntityRift.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityRift.java b/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityRift.java index 4b7a600..135235e 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityRift.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityRift.java @@ -35,6 +35,7 @@ import StevenDimDoors.mod_pocketDim.util.Point4D; public class TileEntityRift extends TileEntity { + 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; @@ -327,7 +328,7 @@ public class TileEntityRift extends TileEntity NewDimData dimension = PocketManager.getDimensionData(worldObj); DimLink link = dimension.getLink(xCoord, yCoord, zCoord); - if (link.childCount() >= MAX_CHILD_LINKS || countAncestorLinks(link) > MAX_ANCESTOR_LINKS) + if (link.childCount() >= MAX_CHILD_LINKS || countAncestorLinks(link) >= MAX_ANCESTOR_LINKS) { return; } @@ -335,7 +336,7 @@ public class TileEntityRift extends TileEntity // 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(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; From f1eff42a33048e64fd3a02b6b530b3a8d561ae2b Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Wed, 12 Mar 2014 10:27:32 -0400 Subject: [PATCH 020/187] Improvements to Crafting Recipes Added a configuration option for adjusting the number of World Threads needed to create one Stable Fabric. A few users have asked for this to be available. The default setting is our usual 8 thread for each fabric. Also overhauled our recipes to remove blank item slots, allowing them to be crafted on any line of the grid, as long as all the items are aligned properly. --- .../mod_pocketDim/CraftingManager.java | 133 +++++++++--------- .../mod_pocketDim/config/DDProperties.java | 5 + 2 files changed, 68 insertions(+), 70 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/CraftingManager.java b/src/main/java/StevenDimDoors/mod_pocketDim/CraftingManager.java index 086054a..24e58df 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/CraftingManager.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/CraftingManager.java @@ -9,89 +9,82 @@ import static StevenDimDoors.mod_pocketDim.mod_pocketDim.*; public class CraftingManager { - + private 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(itemStableFabric, 1), + Item.enderPearl, mod_pocketDim.itemWorldThread); + break; + case 2: + GameRegistry.addRecipe(new ItemStack(itemStableFabric, 1), + "yxy", 'x', Item.enderPearl, 'y', mod_pocketDim.itemWorldThread); + break; + case 3: + GameRegistry.addRecipe(new ItemStack(itemStableFabric, 1), + " y ", "yxy", " y ", 'x', Item.enderPearl, 'y', mod_pocketDim.itemWorldThread); + break; + default: + GameRegistry.addRecipe(new ItemStack(itemStableFabric, 1), + "yyy", "yxy", "yyy", 'x', Item.enderPearl, 'y', mod_pocketDim.itemWorldThread); + break; + } } + if (properties.CraftingDimensionalDoorAllowed) + { + GameRegistry.addRecipe(new ItemStack(itemDimensionalDoor, 1), + "yxy", 'x', mod_pocketDim.itemStableFabric, 'y', Item.doorIron); + } + if (properties.CraftingUnstableDoorAllowed) + { + GameRegistry.addRecipe(new ItemStack(itemUnstableDoor, 1), + "yxy", 'x', Item.eyeOfEnder, 'y', mod_pocketDim.itemDimensionalDoor); + } + if (properties.CraftingWarpDoorAllowed) + { + GameRegistry.addRecipe(new ItemStack(itemWarpDoor, 1), + "yxy", 'x', mod_pocketDim.itemStableFabric, 'y', Item.doorWood); + } + if (properties.CraftingTransTrapdoorAllowed) + { + GameRegistry.addRecipe(new ItemStack(transTrapdoor, 1), + "y", "x", "y", 'x', mod_pocketDim.itemStableFabric, 'y', Block.trapdoor); + } + if (properties.CraftingRiftSignatureAllowed) + { + GameRegistry.addRecipe(new ItemStack(itemRiftSignature, 1), + " y ", "yxy", " y ", 'x', mod_pocketDim.itemStableFabric, 'y', Item.ingotIron); + } + if (properties.CraftingRiftRemoverAllowed) + { + GameRegistry.addRecipe(new ItemStack(itemRiftRemover, 1), + "yyy", "yxy", "yyy", 'x', mod_pocketDim.itemStableFabric, 'y', Item.ingotGold); + } + if (properties.CraftingRiftBladeAllowed) + { + GameRegistry.addRecipe(new ItemStack(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.itemStabilizedLinkSignature,1), + " y ", "yxy", " y ", 'x', mod_pocketDim.itemRiftSignature, 'y', mod_pocketDim.itemStableFabric); } 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.itemGoldenDoor, 'y', mod_pocketDim.itemStableFabric); } 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); } } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/config/DDProperties.java b/src/main/java/StevenDimDoors/mod_pocketDim/config/DDProperties.java index 18378df..67b1b11 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/config/DDProperties.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/config/DDProperties.java @@ -108,6 +108,7 @@ public class DDProperties public final int FortressGatewayGenerationChance; public final int MonolithSpawningChance; public final int LimboReturnRange; + public final int WorldThreadRequirementLevel; public final String CustomSchematicDirectory; @@ -144,6 +145,10 @@ public class DDProperties 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); + 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); WorldThreadLootEnabled = config.get(CATEGORY_LOOT, "Enable World Thread Loot", true).getBoolean(true); From f40e1e0a91a399de3e421926194a7924a38006a5 Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Thu, 13 Mar 2014 05:43:26 -0400 Subject: [PATCH 021/187] Change to Dungeon Exits Chances Changed dungeon exits so that they have a minimum 15% chance of exiting to the Overworld if a dungeon's root dimension isn't the Overworld. Also made a minor change to the existing special case for the Nether - the minimum 20% chance only applies if the root dimension isn't the Nether. --- .../StevenDimDoors/mod_pocketDim/core/DDTeleporter.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/core/DDTeleporter.java b/src/main/java/StevenDimDoors/mod_pocketDim/core/DDTeleporter.java index 8905140..bdb7fd7 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/core/DDTeleporter.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/core/DDTeleporter.java @@ -40,9 +40,12 @@ 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; @@ -633,7 +636,11 @@ public class DDTeleporter 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(OVERWORLD_DIMENSION_ID), link, properties); + } + if (current.root().id() != NETHER_DIMENSION_ID && random.nextInt(MAX_NETHER_EXIT_CHANCE) < NETHER_EXIT_CHANCE) { return generateSafeExit(PocketManager.getDimensionData(NETHER_DIMENSION_ID), link, properties); } From 01fe9cc87eb9ca8844fd493b876fd62cbea3f72b Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Thu, 13 Mar 2014 05:47:04 -0400 Subject: [PATCH 022/187] Added Config Setting for Limbo Escape Added a configuration option for toggling whether players can teleport out of Limbo by walking over Eternal Fabric. This became viable after Rift Gateways began generating in Limbo again. Keybounce has expressed an interest in using option to deal with the issue of players returning home since his Overworld won't have gateways. --- .../mod_pocketDim/blocks/BlockDimWallPerm.java | 3 ++- .../mod_pocketDim/config/DDWorldProperties.java | 11 +++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockDimWallPerm.java b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockDimWallPerm.java index 42a2d1e..d3dac45 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockDimWallPerm.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockDimWallPerm.java @@ -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/config/DDWorldProperties.java b/src/main/java/StevenDimDoors/mod_pocketDim/config/DDWorldProperties.java index f669ded..db2a498 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/config/DDWorldProperties.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/config/DDWorldProperties.java @@ -13,6 +13,12 @@ public class DDWorldProperties public final DimensionFilter RiftClusterDimensions; public final DimensionFilter RiftGatewayDimensions; + /** + * General Flags + */ + public final boolean LimboEscapeEnabled; + + //Names of categories private static final String CATEGORY_WORLD_GENERATION = "world generation"; @@ -33,6 +39,11 @@ public class DDWorldProperties 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); + config.save(); } From 941cecb372b153fab6a21ecf0f86423beeffdaa1 Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Thu, 13 Mar 2014 05:58:02 -0400 Subject: [PATCH 023/187] Tweaks to Loot Set loot chests to generate 6 stacks of items instead of 5 stacks. Increased the maximum amount of World Thread per stack from 8 to 12 threads. Increased the chance of encountering a grave chest to 1 in 6 instead of 1 in 7. --- src/main/java/StevenDimDoors/mod_pocketDim/DDLoot.java | 6 +++--- .../mod_pocketDim/dungeon/FillContainersOperation.java | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/DDLoot.java b/src/main/java/StevenDimDoors/mod_pocketDim/DDLoot.java index 599786f..50f4fb6 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/DDLoot.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/DDLoot.java @@ -20,7 +20,7 @@ import StevenDimDoors.mod_pocketDim.util.WeightedContainer; */ public class DDLoot { - private static final String[] SPECIAL_SKULL_OWNERS = new String[] { "stevenrs11", "kamikazekiwi3", "Jaitsu", "XCompWiz", "skyboy026", "Wylker" }; + private static final String[] SPECIAL_SKULL_OWNERS = new String[] { "stevenrs11", "kamikazekiwi3", "fbt", "Jaitsu", "XCompWiz", "skyboy026", "Wylker" }; private static final double MIN_ITEM_DAMAGE = 0.3; private static final double MAX_ITEM_DAMAGE = 0.9; @@ -31,7 +31,7 @@ public class DDLoot { public static final String DIMENSIONAL_DUNGEON_CHEST = "dimensionalDungeonChest"; public static ChestGenHooks DungeonChestInfo = null; - private static final int CHEST_SIZE = 5; + private static final int CHEST_SIZE = 6; private DDLoot() { } @@ -56,7 +56,7 @@ public class DDLoot { addContent(true, items, Item.appleGold.itemID, 10); addContent(properties.FabricOfRealityLootEnabled, items, mod_pocketDim.blockDimWall.blockID, 20, 16, 64); - addContent(properties.WorldThreadLootEnabled, items, mod_pocketDim.itemWorldThread.itemID, 80, 2, 8); + addContent(properties.WorldThreadLootEnabled, items, mod_pocketDim.itemWorldThread.itemID, 80, 2, 12); // Add all the items to our dungeon chest addItemsToContainer(DungeonChestInfo, items); diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/dungeon/FillContainersOperation.java b/src/main/java/StevenDimDoors/mod_pocketDim/dungeon/FillContainersOperation.java index 5a91f31..f124225 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/dungeon/FillContainersOperation.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/dungeon/FillContainersOperation.java @@ -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) { From 7a043dfa65cb6e3efdedc4d7c4b7c5ab347e9be6 Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Fri, 14 Mar 2014 06:41:42 -0400 Subject: [PATCH 024/187] Added Crash on Provider ID Conflict Added a check so that Dimensional Doors crashes if another registers our provider IDs. This will show people that something needs fixing instead of us risking strange bugs. --- .../java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java b/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java index b433abb..1069181 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java @@ -232,8 +232,11 @@ 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!"); + DimensionManager.registerDimension(properties.LimboDimensionID, properties.LimboProviderID); LanguageRegistry.addName(goldenDoor, "Golden Door"); From cc46d90ed4d48d3e8d08517d077722a2ad24d1eb Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Fri, 14 Mar 2014 07:07:35 -0400 Subject: [PATCH 025/187] Updated Rift Blade Code Removed duplicate code from ItemRiftBlade. It was code that duplicated the functionality of ItemSword since ItemRiftBlade didn't extend ItemSword originally. Also updated the tooltip text to remove mentions of the old door-rotating ability. That's not provided anymore since doors are easily broken and replaced now. Extended teleport range slightly. --- .../mod_pocketDim/items/ItemRiftBlade.java | 46 ++----------------- 1 file changed, 3 insertions(+), 43 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemRiftBlade.java b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemRiftBlade.java index a49735a..d846251 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemRiftBlade.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemRiftBlade.java @@ -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."); } } From 7e8fe10c7db17d9c5e718511b8b8038cf37235d3 Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Fri, 14 Mar 2014 08:35:44 -0400 Subject: [PATCH 026/187] Split dd-rift into Separate Commands Split dd-rift into dd-rift, dd-random, and dd-list --- .../commands/CommandCreateDungeonRift.java | 73 ++++------- .../commands/CommandCreateRandomRift.java | 117 ++++++++++++++++++ .../commands/CommandListDungeons.java | 74 +++++++++++ .../mod_pocketDim/helpers/DungeonHelper.java | 10 +- .../mod_pocketDim/mod_pocketDim.java | 4 + 5 files changed, 225 insertions(+), 53 deletions(-) create mode 100644 src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandCreateRandomRift.java create mode 100644 src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandListDungeons.java diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandCreateDungeonRift.java b/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandCreateDungeonRift.java index 23e0b64..d5ba8dd 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandCreateDungeonRift.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandCreateDungeonRift.java @@ -21,7 +21,7 @@ public class CommandCreateDungeonRift extends DDCommandBase private CommandCreateDungeonRift() { - super("dd-rift", ""); + super("dd-rift", ""); } public static CommandCreateDungeonRift instance() @@ -41,7 +41,7 @@ public class CommandCreateDungeonRift extends DDCommandBase if (sender.worldObj.isRemote) { return DDCommandResult.SUCCESS; - } + } if (command.length == 0) { return DDCommandResult.TOO_FEW_ARGUMENTS; @@ -50,61 +50,38 @@ 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()); + } + //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 { - 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("random")) - { - - 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."); - } - 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."); - } - } + //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/CommandCreateRandomRift.java b/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandCreateRandomRift.java new file mode 100644 index 0000000..013921b --- /dev/null +++ b/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandCreateRandomRift.java @@ -0,0 +1,117 @@ +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.LinkTypes; +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 (sender.worldObj.isRemote) + { + return DDCommandResult.SUCCESS; + } + 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, 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."); + } + 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) + { + //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."); + } + } + 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; + } + else + { + return matches.get( random.nextInt(matches.size()) ); + } + } +} \ No newline at end of file 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..043d0fd --- /dev/null +++ b/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandListDungeons.java @@ -0,0 +1,74 @@ +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 (sender.worldObj.isRemote) + { + return DDCommandResult.SUCCESS; + } + 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/helpers/DungeonHelper.java b/src/main/java/StevenDimDoors/mod_pocketDim/helpers/DungeonHelper.java index 56de06a..545168d 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/helpers/DungeonHelper.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/helpers/DungeonHelper.java @@ -577,11 +577,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) ); diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java b/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java index 1069181..a5f2e8a 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java @@ -28,9 +28,11 @@ 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.CommandCreateRandomRift; import StevenDimDoors.mod_pocketDim.commands.CommandDeleteAllLinks; 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; @@ -335,6 +337,8 @@ public class mod_pocketDim // Register commands with the server event.registerServerCommand( CommandResetDungeons.instance() ); event.registerServerCommand( CommandCreateDungeonRift.instance() ); + event.registerServerCommand( CommandListDungeons.instance() ); + event.registerServerCommand( CommandCreateRandomRift.instance() ); event.registerServerCommand( CommandDeleteAllLinks.instance() ); //CommandDeleteDimensionData.instance().register(event); event.registerServerCommand( CommandDeleteRifts.instance() ); From d1a2476a4e503d931f187760cced5db7b280ad6a Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Fri, 14 Mar 2014 17:22:55 -0400 Subject: [PATCH 027/187] Quick Fix for Limbo Music Crash The following small change deals with a strange background-music-related crash. Wasn't this issue fixed for Jaitsu and Aether II? I'm not sure what's the cause but I've added a check to prevent the NPE. Please deal with this most robustly in the future. --- .../mod_pocketDim/EventHookContainer.java | 35 +++++++++++-------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java b/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java index d3b09f4..02f3aea 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java @@ -218,24 +218,29 @@ public class EventHookContainer public void playMusicForDim(World world) { - if(world.isRemote) + 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"); - } + // 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) + { + 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 From 4f2f86535b3e43ebf7f13c0817d7e9c864e06e29 Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Sat, 15 Mar 2014 03:54:41 -0400 Subject: [PATCH 028/187] Minor Changes Cleaned up the code for placing Vanilla doors on rifts in EventHookContainer. Unfortunately, there's a section that I don't understand and that I feel has a bug. Remember that comments are very helpful. --- .../mod_pocketDim/EventHookContainer.java | 39 ++++++++++--------- .../mod_pocketDim/mod_pocketDim.java | 4 +- 2 files changed, 22 insertions(+), 21 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java b/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java index 02f3aea..bfe6cf8 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java @@ -81,42 +81,43 @@ public class EventHookContainer @ForgeSubscribe public void onPlayerEvent(PlayerInteractEvent event) { - //Handle placement of vanilla doors on rifts - if(!event.entity.worldObj.isRemote) + // Handle placing Vanilla doors on rifts + if (!event.entity.worldObj.isRemote) { World world = event.entity.worldObj; - ItemStack item = event.entityPlayer.inventory.getCurrentItem(); - if(item!=null) + ItemStack stack = event.entityPlayer.inventory.getCurrentItem(); + if (stack != null) { - if(item.getItem() instanceof ItemDoor&&!(item.getItem() instanceof BaseItemDoor)) + Item item = stack.getItem(); + if (item instanceof ItemDoor && !(item instanceof BaseItemDoor)) { Block doorToPlace = null; - if(item.itemID == Item.doorIron.itemID) + if (stack.itemID == Item.doorIron.itemID) { - doorToPlace =mod_pocketDim.dimensionalDoor; + doorToPlace = mod_pocketDim.dimensionalDoor; } - else if(item.itemID == Item.doorWood.itemID) + else if (stack.itemID == Item.doorWood.itemID) { - doorToPlace =mod_pocketDim.warpDoor; + doorToPlace = mod_pocketDim.warpDoor; } - else if(item.itemID == mod_pocketDim.itemGoldenDoor.itemID) + else if (stack.itemID == mod_pocketDim.itemGoldenDoor.itemID) { - doorToPlace =mod_pocketDim.goldenDimensionalDoor; + doorToPlace = mod_pocketDim.goldenDimensionalDoor; } - if(((BaseItemDoor) mod_pocketDim.itemDimensionalDoor).tryPlacingDoor(doorToPlace, world, event.entityPlayer,item)) + + // SenseiKiwi: Why do we have a condition like this? And the event isn't cancelled if we take the else portion. + // Comments would have been very helpful. + if (mod_pocketDim.itemDimensionalDoor.tryPlacingDoor(doorToPlace, world, event.entityPlayer, stack)) { - if(!event.entityPlayer.capabilities.isCreativeMode) + if (!event.entityPlayer.capabilities.isCreativeMode) { - item.stackSize--; - } - if(!event.entity.worldObj.isRemote) - { - event.setCanceled(true); + stack.stackSize--; } + event.setCanceled(true); } else { - BaseItemDoor.tryItemUse(doorToPlace, item, event.entityPlayer, world, event.x, event.y, event.z, event.face, true, true); + BaseItemDoor.tryItemUse(doorToPlace, stack, event.entityPlayer, world, event.x, event.y, event.z, event.face, true, true); } } } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java b/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java index a5f2e8a..09bb6d6 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java @@ -124,7 +124,7 @@ 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; @@ -203,7 +203,7 @@ public class mod_pocketDim 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"); + itemDimensionalDoor = (ItemDimensionalDoor) (new ItemDimensionalDoor(properties.DimensionalDoorItemID, Material.iron)).setUnlocalizedName("itemDimDoor"); itemWarpDoor = (new ItemWarpDoor(properties.WarpDoorItemID, Material.wood)).setUnlocalizedName("itemDimDoorWarp"); itemRiftSignature = (new ItemRiftSignature(properties.RiftSignatureItemID)).setUnlocalizedName("itemLinkSignature"); itemRiftRemover = (new itemRiftRemover(properties.RiftRemoverItemID, Material.wood)).setUnlocalizedName("itemRiftRemover"); From 84eee1b15528b7c6d2f16fe2b55058f80506f054 Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Sun, 16 Mar 2014 04:13:20 -0400 Subject: [PATCH 029/187] Added More Dungeons Added Cere-JumpPass, Cere-TransferTunnel, Cere-GreatHall, SK-WatchedForkLeft, and SK-WatchedForkRight. Made a minor change to SK-RaceTheLight. --- src/main/resources/schematics/ruins.txt | 4 ++++ ...omplexHall_Cere-JumpPass_Open_75.schematic | Bin 0 -> 675 bytes ...l_Cere-TransferTunnel_Closed_100.schematic | Bin 0 -> 2163 bytes .../Hub_Cere-GreatHall_Open_40.schematic | Bin 0 -> 8088 bytes ...all_SK-WatchedForkLeft_Closed_80.schematic | Bin 0 -> 2022 bytes ...ll_SK-WatchedForkRight_Closed_80.schematic | Bin 0 -> 2066 bytes .../Trap_SK-RaceTheLight_Closed_50.schematic | Bin 1604 -> 1565 bytes 7 files changed, 4 insertions(+) create mode 100644 src/main/resources/schematics/ruins/ComplexHall_Cere-JumpPass_Open_75.schematic create mode 100644 src/main/resources/schematics/ruins/ComplexHall_Cere-TransferTunnel_Closed_100.schematic create mode 100644 src/main/resources/schematics/ruins/Hub_Cere-GreatHall_Open_40.schematic create mode 100644 src/main/resources/schematics/ruins/SimpleHall_SK-WatchedForkLeft_Closed_80.schematic create mode 100644 src/main/resources/schematics/ruins/SimpleHall_SK-WatchedForkRight_Closed_80.schematic diff --git a/src/main/resources/schematics/ruins.txt b/src/main/resources/schematics/ruins.txt index f922cbb..fb199f5 100644 --- a/src/main/resources/schematics/ruins.txt +++ b/src/main/resources/schematics/ruins.txt @@ -1,5 +1,6 @@ /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 @@ -36,6 +37,7 @@ /schematics/ruins/exit_smallExitPrison_open_100.schematic /schematics/ruins/hub_4WayBasicHall_closed_200.schematic /schematics/ruins/hub_4WayHallExit_closed_200.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 @@ -61,6 +63,8 @@ /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 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 0000000000000000000000000000000000000000..9c242b6300ed23dde961216341d744a80a24921e GIT binary patch literal 675 zcmV;U0$lwciwFP!000000PR`bZqqOnJ}IPW_9HX|f``a8_oJNvX=q3wah)_)V=Z;6 z#Hbsukhhss?UqO3QE*4oriqmhfHnjm> z{Q(691qB5K1%>^DzBNeg(KJd*yHd8C!mc3gO3&}13#NJ_wMvJhS7afd+UUUP+mGU8 z&PwAlXMfnf>2B`inQf?0OnVlq7d7D z1p2u@^K27NeqbLZVMi>gKY$)~;cU&{j_`C81fd3}o*jKcgdq2ujYD>rj)M>*LT!oz z!cu!07%b%C22;@BHI7EV$OHvs=-HTDVsg#clVFC(RXFs62)S$v?Kew2W#cUybvE9> zf3HnVKwBo>umb8|D4HhKTRPH*9*XEH<6S1hsBBx4ubq~$-S47yA`|7cgH?vH$~a~( ztNtY-6Y9Zx1I%;R{pbhd>xhN?-QguU6c}9_sD-EHc6XR{B|J|$FrUv8FY^tl`t$5D z<2)S-4*9ot0ru+ujPS&xFzA8)6T9pq;H?4uoI>!cL9v6Ny~cAjkCB^%di->t1760 zQq0PZwVfq`pzoG2cmu0==Mp%g1Dar&M=9FPyX&%1)VoPq5< z}V-&4^RcUQ4q^D=)BEeH=pN02*6!X}p}W&6Iw9fuR;m&r&SCn|4ulIZAkbC78CIH|Uh1SPUkZy&ba!UKxN}s|XnJ-4x>>1B=s`%c{0?`ymfE6jLMSWlB6w~Od z&iYuys+IH~p^3;A3A4s}fHSt@eUb6Zd?R%0MZEWulW4T-;tju1$G-mF^ObG^xREYH z2c#?SnQ*VS{m}i#te>ZsQa|pYDf@IX4W}C=3-bBX*AiMmS7(FE1T4C-i^eW@$55MP z3-K|g{EXhlC}hZo8sDUR=lI0@dO;%AZiK}MX|3n6wgyN=4GCzyeX+ixp#u1H%Z(Re zb-Z5i-JP|@m7avLv58HSeAwXa33TsTLo>VE0mC%%rn#@MxG~YjM$D3_fBL|1wx*Fj z2YQ6$odqwsgwC{j%-8rHzt0Puj;5CXL5zPx5oDd>C*&nQ_v}k&U?W4^!cwv zb2b~hd$5jg-l{U{Vy#T1Gk4M>N#)vy{bkhD?zFWT`&Ul6 z7ask7I$>^h>UpwL>uMFe&7Sn;5_wb->ZITk$uX({gpI+W*Sw^zGECWZVp7RgUWgv- z-9AyfL@ko2y;U>hp7`UN8y~oQDgH*$r-D^@isYSi^JeUX&+LTd@&rZYekLMUjj#R& zpKYGkXx`EI_cL|TpSvc%&3{n_D#K|=1PtXkDyX$ESi5ug8ttO90i(hzy2au|MaZsq zqUNZ@qbJ9vE?sgR^9pYN!S4O+;;B*SkDveLW>nZr^%a0=A-D~?=m5+YP{`I#%vuJQ z%{F$ESS1T6WAn(88B}h|HKc!Ti{kr@u*KJI;;#HFLOcAvw1-?hcxYv@Jt|w=7WGmA z28yQl${-on#BGqdW^9^K6i zI-O(_zw-&I%V?ZEs5mn+rwPD>A9U|RM73%FFLNpAc#-ctdI)s}DQu5F@@V z=0K{KL~t`$P|{g4p}&Py-!)+3zwvXr3Ak)($0RLVA`FBuXJjXj+CXXRVFDYQhep=i zb^_~1C_Sgi#Xx!sELv^qr#YTno&DGWJ!>!dsR`i;>Jz#ZR!#5oZ^i4d9;Bs8S@eez z5xvX_z-)BXOO|yYov!Eb9^)>Jro4%(EkWNo%zDp+aZm^zP2FAi2cLW$OpJ+;IAc;5tpOKYqLfOQT)ekH)< z>U&-pNyZJX<6`k2Xf=9QIxFeJmrrUor%)3o)P%sMZF^yPzlsC4ExdFBg>e&u<4Q z2DgYr;eP%{5ZBDd4rU+-e)oUJ|5{@D>((mo{<^IieFlKKK%r3aw;+%X007fKp!p$w QrCZuMvD*)9BDQJ$0(1W=vH$=8 literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..e639e589fbdb90122736f608ac7b7c37f8a85431 GIT binary patch literal 8088 zcmZ8`2{@Er`+wP&YO+))CQ(wNBzqnuOQcCiDN9tSm{JmHMkz~TL_(z@WoKj!G08HP zgzTijU<$*G!EDd+^M2p|`~Ls`-*a8(I?uW9bKlqb+~=IP+103u=wBHRYdi-O%eB=eo>zYS;%Q|cx7WkbhuDxzoJO5|YqNpNLQ?Whx^Ie`p zn^#$P$+pWKewOm2E&G(UeF{AU8x@XhzC4;>lXhf)8FNZ$O1Ebz!$*KWZe|^vGBxQH zzo*C8L6r1Bm{GwL}rj@MBwyfcmC-SVb=wsTB4XjqVyw|cQUGz=y6>lY^=J10GP)g;JE=6-j0 z*`@cxS}E^PFC!;7>@rR3+77)8B$NKtaea@ljs^+*WV4j^+xOXG?S;SJt>zZ5$MY=Y zW#|uBmY#r0Wc((cJ7OKy1P4U2-|U(3P`Cej?e1l}g9O8FSDi%8;U3(MWzfmo;QmYL zT@e|ulfzJR2`s68#Fxjn@(weN+;mr!D@}IVrgZnAh;a>_^G9dY$*&+XGO%YT;M9g2 zF|OPm$4>}B@!|!Qr@ODu-|Sm`viD{=Wp~=J?>3Z1kA^~nOkmq%CA_Y25clo|bf@hu zi?wxTD6?63_5I8-G_fW^Gh+E`!u{jcnxWrGB>%{pV|PuEUE9R9wnjTvcOSYM+m-Ok zj(e;}W~u&goIL(y=z>6p+L)`+H@uwEDx(Ix!G0IF%r@y=#dpl6?A;_SWS^Jcb}y|s_4c2GK&Ce9)RU>h`7SnvHwy6+2e+_pS#dT$?We#t=w8xud>P#W_$bI{^!E~dPT~#lp zX;R$2TH~!{ctMF+6IZU_(cW(~dfC>sozyTj)aiLCsRIms)md+Ek^Evm(LwC>i{T4> z#0_^QLF3;oS^d*n9qu(WdmcJ?9{*OSam=!8`lemXevab%8?T8X%V$82gxB zq%X%way&ka?(6aSU<#@Oo=zhHq3aVRloisftk;(`-yR!a=uQR?{`zT7P0O_=MZp~I zWkej@|GDSp6X?gODv>6mM0_-ihz346talyJLv%0f zKRSfzx*nNjcfKXi7w>~NJ_2u`UHpX{xGeLQV{rB>_E!DbN6>Zu%7n(sAllp(o0KP3 z?_f){ke|CQDKoi;{C?yuXOFkab}DxRJ9xghpF{kCO> zZiYYYN8e@Hr;O~u#;LZE4Ox&>>hrpKbCq;o!L1=@R}F>pX|!gWjtTqpAF92bO-{Sl zwoUJQuUpTe^l#3b`T@h`2gL>l^9)<;BDSu#uwd|Z8nYyhd_7)Kwpe)KX0Nt!?(dk_ z8*@faxxJnOM|q2#r4LM+m>0D!wtp2L`ONJxa*JHNEE)SHa5@O}xMFdg$2vmAv0{JT zWi|Kx^o^mJ*Ro0qG8>B=l~YDwr5wzYjJ@a&P}rfnSg$12cFNBh%M?4OZTGi?a2INi zrQ#)u4@7chuy4Z<9W_A&BaKesyEPttvCT%8lIG#NEjyruW}f5&ikT3Zg#?Aud59^s{yc2WkEqnKuF(e6mc$iYf0C>Qf?b z(bOsuT%_Uz)UY+Q=bX7#lZH?(X^-9cZQslLQEbl;)q`%P@}e&E zXsK)V^h742<3FOO-OcPEt5ERkjE9le&6rVC2tAdbQ>pRI%02SHx|#@Yz>d1PR+fHH zQ_K@!-!D;OP{KcV?6|_vP|E$PNx}VUe`aE^Lhe2(_yhq2ipDL2YznHwdMWtf>ne0R z>_`oNeB-e^(HltnecJ5VSCNx%_9UE48^bc{Vs^Z!LR6n+&+ilQ0UHL;QT(~xmjSyJ z{eF?xr2zNTw#zjZ%5FNm&|X8Mt+;_*eKn?nUj`G;4$H57#w{`fz;;VfMcm(B3q(sQ zWpcilZq+!=JlCT;{uS?fAte$_?F=-sp&!Ug8;u=VVt}z$B>Yf+6?v zw}{9fDz~oOt^1U_)h@+b(@Jjk-$=X6tI!%c7jJ>qb2rYN9{m9Qae#=n&pb{LRhVSL z@k-}JOcQbQ20>=fl_Au(D*et9;z$bFYUvnwZV*wRu1H1!QchsngMicrHIgcxoT`vA?7-k_Xf9e z_`M|Cr^qAQp%!i`MT=O@bzMQbjG!Jp9OvUpN_EV^-rUgevNue8*dD=8DclLqr%-I1>staUJYuX%rP= z_|%4%bx6{Wz~bABS2ul8%2(e+EPWR8?SZYELCJ~+Ti;LeV1U9hq#C=-7JqP@i}j{i zpN2Nh4pJoqio5QC6P|0+8kPV@K&S~qeqGu;4^4AukxaHG6 zpuudguwj-nr!M_O))Mct;OmTB=~iO+cojw0*3reRczp^nf1QT5!rEE1=P5*HlEfh* zU0i}8?i~Mo=aFvm08W;rRts6T#>WuLkT4#1v8qG>u)NI`1!Y&qy?q97=89PhK)PL7 z7A)K@s#Evs6%cFDqYKq-=~W&;&mpVZT^W-q6*%9Yo~u6f6}D!Gl(7o$XS`Jl{aM_Z z{!IM?duU{fCXXk7)b2ebi2f9no1EH?o+qaY!CCdR6aA=@9}6Nw49A84h;?eTX@xdy zH0)VGADw6V{o-GJ(1!=oWq^H+oT7+Ev_j80El1p@mq*utA|8&g4OAz3NgwE$6P?Zq z5T5dAp^UIzD0{skU-}`|btmB2+b9Ub9wm317b~pF%@V%_@X4)?J5Rr-)cSOA)d;)yP##q25#`_2N&as<)Z}Xb|6yMW_ ztLG=qo%00747{8Whg8wci(#Ne(LE2J^a?;W&Aqhg>oD;7IXM9-Bi!MdQB;I~-i3L>{Xh z7o-;6GfX#z3sulJ)R=XFf4PS`Ja(SG&gqWNJHpSqZQ$b8MZW_EK~IOpUJCN!nk@52 zLg3av8~LfUz})_w10S}QIk42mQ=q`{fRY`9NM-*H^09YBcATu+#*?V~8H1+~wXmV8 z4$G9y0$004^oREc;$|8-X%wb)GNBKz2dwW#SXEXrR7^BaVrKVhM8@w-v>c+W@)q6O z>Z#-GHAa3ZmJE4xqWWeVt(D=)xV2m_A=d*gmcoxX6iiCL??F*t`J9PuqHG?{jeB?J zX;<6HM5oNIL)aRS0ME7@S~yI=AUF~J`Ui`X z{i}M)1{1OR%-QG5`E2k;Z5Crmx7aq3(5J*EcW`@bF|ScS&rD|l>n7a3L$G%xasYkN zvYk!ZD@da=GjXGYo|8N*m^W~S75)L!({r3wOWFLh{MHj%p!U+Z2pBI zkzjB#aWTlp70*Anvs~Q{SN>_k%AHtjgr^~(GneFi<44NE1`*3xU zqcgbYf}p3PYnv?h9k|m~(M_@@5%) zo__2Mq3GHu9?7U7y)htDVL_e}>4{Q76H(MQtlIx8kEAlVy*ISTicNAaq?&DdP854i zbj~fJq7fqGctBR^M5Z{veaI3t^Q63Su1{PrMLYmPQJR8qmjaM zSo2lgx~4y`&CXh@178qHrl*%jk}yToLmmHgTT`-=J3vGC|MZ9j!70*J9GE(_SnSK| z}3t;x28m>7l1O}+T5@eeBc z?i3#D%2W)O71Zb4xaD8ak~)$MkA{TZbL9~d$ZF=dsuOs(qn3h8;l2M@h_B_-_m2k- zllT3%`ESLpZ6R7~&a|dT5%;#N;lmjRZrB9~@l1q7QeyM)Q{jgQ^pWwcqqU|JhK0xchtLJWV1)|i5IWaLz{}+pD2Ox2YEzhpNTKZll1ITzNK;iC0}XW%JMK4Pqz;Q#&cLgH$*$06 zi1^{Y-+OKm&yhyxNoP;6T+$5^$KL?2>Uoo~I{I-Galc*A7*!peElDS3iiF!sFSgf+ z8Y3Go&*mR8^5-{=PHj&rv!k)<+KMh5J<4-d{85==?;QGgKiyY6QELI8rDiAjrI0 zR4d0nSsVmJ$`K$ltQ72ql@(S{?VQ=JFL*Tp_Ir_(NhobLKnL4FvjY>#Ohv zaN#Mf5qB2v42Ixa`e@b>yqEZ?U9Zvxdwmx#TmN_7(zH>%)T7qk73VH8dc$f_gzfw=Jz%=flT% zCNbzNcv1dL@X*yhc+}e84U~}m#=Y~PT6(62TUICAglhN`{TGXLwh*k+TI4UN0NI!> z09XD94O&lHPe>yhc(TChQJCJ~QJrQasbjwb&<|qKW&+mm9DD5@hwjX}1Hg`Bw%I~{ zjx1X5_+1{@*(*2Zl>izNPMN>H25FRa=v>r#q zhC;yTW?;QJ*bCdY5QbNC2CQh6#hSa#uf8~cvoX_(P8?ZWim?SHVf`Imo?DTHP8eaN#QT| zhB(cqwkwyFXwZ&AKs^T@!_^}a)q90zJ!NZ*`@;Cv(wUte5fx-jGeG6+PiUb98#Ttc zTY$b?2)K3eJY^m1UFJ#&L#vQSk4r;cwcog`faFOw=<#?lB`q2)Y*q*eAA_J(Ix}L` z#UI(Ongv%yLkfxokP*w=Z$p9-R)oDWyA~+ROgNo}LjM|Oe8<=nqHzaB zRedC3|Ggf&e?;@kj3dURbM* zc$>S!6O=`%6yVn%y@@P58=h*-L*%>w{ViG0U#<=n5sZ)W4=?A;6MJ!M!7(2O#04eP z5do!-*t-_3GCtss?10S}L?6J*cffx zbKX^!w>(}&A6GctyBU7L+>Lu%2|Xp6L)@STxh$-6WGa=9Vl){v5ts!}SBKUtPyf}R zJuAN$`cBN;Wz3PKP6{md$h>lNn2Z??~Y;XkbVsrcu$KkFYlN4J)dOPmY z&C~_FJD57NXoTB9B{oa~lTaF;dwWX@K?a?DnG0M7|4wjeU2;okYc~Fu4|uv~H_nvL z{p(F9c0+`yn2T!rW6-sTeXFmqP4N8Brm&o4J(#Rx(XeJv2!w0XAV-8Iz9$bsRVY-STuZOvD$wcTz2U zl8?9rYV1nbp^A4|0s6VD^Rqw@a)&EmAg(z7wTlYTm8eBa^at3HgHLIXuM6IbCqqCy z-sH=h+jh%jJ2|#;F87cTVvH4iQ!IP|GZX|G96~o}HetS{tU04m?pvEX2vEQd=LT%D zp_|!~mAMR_FCcUgG`4&CzUAJo&_zh+AZ&b)N4FpOo$$Sqk-LYee@=B0_3gh0C#%qr zBGU`8K}=H88U7s*l}Idi(NLYEuH)=)(3k^C!SsH-I`!kMfXX%<1w^SHmUccke9#jA zFds{TfEQ3x-cJx(#s7w-W(h5X2SvaE?rpR z%se2&Q($lNQ@1diX8fLwEd~mTfboGOrku(+ugX{vvF1`*N#(#W*>yXh@67V<%^ert zE5)1XvVps*@HjI!p4*?{=U6gVkVEOfoFMFzIW`$4X!qtMTD+O}lTa8NO|X9k_#V;6 z{n~=R3HpwvO#qH${O7g&5P3c44j~zEH(QtTg&!>5%`T&e!Y0e6QM6qMS`%mtj!P;e z-Tsl z!uBljaFd?U?NlQ-rDw!<0IJd8i6QO^OA?v$1W$nXW%(Qi>L_sMQXf(xSwqtm#B}IX z5+$y#%27PkMv&roJO>WgK`qB!_N~$_XXx6#;=%M+6cK4xxwf%DJUUIL~Y0C^OpH)ZKNVV z23Tq*hQf(l2ktkWHF^>)tb9aj1g`NB~^lUwT73U4W< z-vGwKuob{2ucthx>QYddKs%)hMn-eny0$yDH>Gq#F;ULca!Pu_Ijro`wp& zaDwh*va9fENwhT2Y7}!B3ibwM>UQD^%K!{Mr8Dn2P*uAZ9g9YNM4DF1Li67u>Nxp& zrZo2-p79OPzy*OW9n``Rs=w5yx>g-@o_`Ds9UE_Cu2|b*8~X9$VR|@IPo6W_q(+bx zto=50ze2vx68}jp_fP;%_uxym*l|D;IMH8#BPn9xkfIRfvz zYlcooHt8Xys$mmEQIAQA->3(d-bD8QRI}1UEaMh@sMDnb|0U`kKT`f3I6`xE6X8GH g{l7FGj9})(qyHDPU(=#RJs{wy|G+i9ZlQJm1NW6;ApigX literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..4601cc00dfbd11c7029c8be51093928a91235c28 GIT binary patch literal 2022 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 Jr~5Ymz(1dc5vc$G literal 1604 zcmV-K2D|wmiwFP!000000PUU6Zrer>#)pz<{j;q&X#@09G-n3B63C@Z<)A67A_W|v zCkG%b)*>R4fo-60n&l? z#ns5Zv3%#M35_$$w*Y?ffkYyasw_RwuJ?hIh4i`(++(YE1H=V&VGvCb0^&1dK%-o# zZtZ#pN~3xs5W7(ikGZDTYgvQ#9Ow*yxPk?`Iv_qHy0&ux@ArH_cv`l?xYKQC8|mEJ zb1mGc1INJm>-hk!;2w*3hOTR>W+aI4jM~bKoy(8ri{{SBMfS0Op zW4DJMaUAs8Nw}DCbe#Q+o|+lO3p*_CI=kM9@{4O>uO3}a1S%q+f!5oD8HH4f7Vg=p z$1V!C5kH6Jn^8zrHSFlhQU>t9lL^+s2tX@Bz>QYvW+-!4r7C-E-*BM#U$^0_J{;)6 z6#$JrnSr&^1Wz2Ls%Y3ZrM;yr?F144bvKW+m;c&c+wg3IB<{7K;+WUh0Q+rN;UcPh zcXzsyDSg;wrF7jcx}c{S+XIy<|Fyjc!oIW6Hjt{$$V2F9Lt!TsL+FW9%rlBaB9TZW z5{X12kw_#Gi9{li)T#}w7q0L4jy;RM7HvWMH_NxDjy0Zv{(L+cS#3Cc?TqdCWu4$v zKej>t)wgfrnwm3&gO}c9Vo&Sv;PupUXMft$zUPgH-a9vVNxcr*U*Wjm@x$Wz`{1zy zqMaH@r><}(9qDu^-01-6bfm1)v2dr_qEjc~_`JB&_iiTE)bhQc!Qrc0e{$zmE!!sa}NF)-8 zL?V$&tfnwgS+OI%TdFx(c_Im#^Nw=>Fxd+bzrn0*Uv8eP21Eo*RzWjWtK7lr?#Azf zY$w~R1ITu=T_umy)fog5fK)=&;NYe0 zT#tNsTm$_NXXuaMyCxjO|F)o%|D)wSBLV~jK*@x^LFRP?sthRY2rz;l0>J!Ma!~QK ze+k8c@L+%WY<$iO7$pGFz=FE(~+a3Q9W$&Uqk+)Dtd1D5x( zjz<=0-^H~Zc-qUf6G(uaroF<~b_25=15n8LlniWbJ6+oq0*SOs0H7H~N_%Cm?MlHZ z0#5Hv1uOP{#DD4EQ1NJ5D1PI83Vy2x$%2Roy9sUD5_v~$6vj6~h C<|bwU From cfd48e796a2c247acf312f21fb62a865687d62e5 Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Sun, 16 Mar 2014 10:01:35 -0400 Subject: [PATCH 030/187] Added Settings and Minor Preemptive Fix Added a setting to DDProperties for controlling the max distance that players can be moved randomly when they're sent to Limbo. We previously had a setting for the same except for leaving Limbo. Cleaned up some of the related code a little. Added another setting for the chance of rifts dropping World Thread on block destruction. Also fixed a potential NPE in EventHookContainer that could arise theoretically arise if a non-Vanilla door was attached to a rift. --- .../mod_pocketDim/EventHookContainer.java | 28 ++++++++++--------- .../mod_pocketDim/blocks/BlockRift.java | 14 +++++----- .../mod_pocketDim/config/DDProperties.java | 11 +++++++- .../mod_pocketDim/ticking/MobMonolith.java | 3 +- .../mod_pocketDim/world/LimboProvider.java | 25 +++++++---------- 5 files changed, 43 insertions(+), 38 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java b/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java index bfe6cf8..b03e35f 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java @@ -89,7 +89,7 @@ public class EventHookContainer if (stack != null) { Item item = stack.getItem(); - if (item instanceof ItemDoor && !(item instanceof BaseItemDoor)) + if (item instanceof ItemDoor) { Block doorToPlace = null; if (stack.itemID == Item.doorIron.itemID) @@ -105,19 +105,22 @@ public class EventHookContainer doorToPlace = mod_pocketDim.goldenDimensionalDoor; } - // SenseiKiwi: Why do we have a condition like this? And the event isn't cancelled if we take the else portion. - // Comments would have been very helpful. - if (mod_pocketDim.itemDimensionalDoor.tryPlacingDoor(doorToPlace, world, event.entityPlayer, stack)) + if (doorToPlace != null) { - if (!event.entityPlayer.capabilities.isCreativeMode) + // SenseiKiwi: Why do we have a condition like this? And the event isn't cancelled if we take the else portion. + // Comments would have been very helpful. + if (mod_pocketDim.itemDimensionalDoor.tryPlacingDoor(doorToPlace, world, event.entityPlayer, stack)) { - stack.stackSize--; + if (!event.entityPlayer.capabilities.isCreativeMode) + { + stack.stackSize--; + } + event.setCanceled(true); + } + else + { + BaseItemDoor.tryItemUse(doorToPlace, stack, event.entityPlayer, world, event.x, event.y, event.z, event.face, true, true); } - event.setCanceled(true); - } - else - { - BaseItemDoor.tryItemUse(doorToPlace, stack, event.entityPlayer, world, event.x, event.y, event.z, event.face, true, true); } } } @@ -198,8 +201,7 @@ public class EventHookContainer 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); + Point4D destination = LimboProvider.getLimboSkySpawn(player, properties); DDTeleporter.teleportEntity(player, destination, false); } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockRift.java b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockRift.java index cc15c9f..ada00b6 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockRift.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockRift.java @@ -43,8 +43,8 @@ public class BlockRift extends Block implements ITileEntityProvider 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; @@ -173,7 +173,7 @@ public class BlockRift extends Block implements ITileEntityProvider { if (random.nextInt(MAX_BLOCK_DESTRUCTION_CHANCE) < BLOCK_DESTRUCTION_CHANCE) { - spawnWorldThread(world.getBlockId(target.getX(), target.getY(), target.getZ()), world, x, y, z, random); + dropWorldThread(world.getBlockId(target.getX(), target.getY(), target.getZ()), world, x, y, z, random); world.destroyBlock(target.getX(), target.getY(), target.getZ(), false); } } @@ -220,9 +220,9 @@ public class BlockRift extends Block implements ITileEntityProvider return targets; } - private void spawnWorldThread(int blockID, World world, int x, int y, int z, Random random) + private 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)) @@ -258,7 +258,7 @@ public class BlockRift extends Block implements ITileEntityProvider { int blockID = world.getBlockId(x, y, z); if (world.setBlock(x, y, z, properties.RiftBlockID)) - spawnWorldThread(blockID, world, x, y, z, random); + dropWorldThread(blockID, world, x, y, z, random); } } @@ -284,7 +284,7 @@ public class BlockRift extends Block implements ITileEntityProvider if (world.setBlock(x, y, z, properties.RiftBlockID)) { dimension.createChildLink(x, y, z, parent); - spawnWorldThread(blockID, world, x, y, z, random); + dropWorldThread(blockID, world, x, y, z, random); return true; } } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/config/DDProperties.java b/src/main/java/StevenDimDoors/mod_pocketDim/config/DDProperties.java index 67b1b11..3aaa69a 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/config/DDProperties.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/config/DDProperties.java @@ -3,6 +3,7 @@ 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; @@ -107,6 +108,8 @@ 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; @@ -166,8 +169,10 @@ public class DDProperties "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); @@ -227,6 +232,10 @@ 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(); diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/ticking/MobMonolith.java b/src/main/java/StevenDimDoors/mod_pocketDim/ticking/MobMonolith.java index ae1f7cc..36df4dc 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/ticking/MobMonolith.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/ticking/MobMonolith.java @@ -195,8 +195,7 @@ public class MobMonolith extends EntityFlying implements IMob } else if (!this.worldObj.isRemote && properties.MonolithTeleportationEnabled && !entityPlayer.capabilities.isCreativeMode) { - 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); + Point4D destination = LimboProvider.getLimboSkySpawn(entityPlayer, properties); DDTeleporter.teleportEntity(entityPlayer, destination, false); this.aggro = 0; diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/world/LimboProvider.java b/src/main/java/StevenDimDoors/mod_pocketDim/world/LimboProvider.java index 3be9520..76ae6cb 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; @@ -15,6 +17,7 @@ import StevenDimDoors.mod_pocketDim.CloudRenderBlank; 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; @@ -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 From 188ec6d68b61194d762a8aaa56ac931b6064696b Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Sun, 16 Mar 2014 10:08:37 -0400 Subject: [PATCH 031/187] Minor Change Minor name change --- .../java/StevenDimDoors/mod_pocketDim/EventHookContainer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java b/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java index b03e35f..f52fa18 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java @@ -40,7 +40,7 @@ public class EventHookContainer } @ForgeSubscribe(priority = EventPriority.LOW) - public void onMapGen(InitMapGenEvent event) + public void onInitMapGen(InitMapGenEvent event) { // Replace the Nether fortress generator with our own only if any gateways would ever generate. // This allows admins to disable our fortress overriding without disabling all gateways. From 1e5e8dcf2b440a8a561174025c97304f70f48004 Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Sun, 16 Mar 2014 22:44:13 -0400 Subject: [PATCH 032/187] Added Subtree Searches for Dungeon Packs Added a new setting to dungeon pack configs called "DuplicateSearchLevels", which allows us to configure how many levels up of the dungeon tree should be checked to avoid duplicating rooms used in that subtree. In other words, it lets us avoid repeating rooms used in neighboring branches of the dungeon. The setting has been added but it's not fully supported yet - some additional code is needed in DungeonHelper and it's not trivial to implement. I took a break because doing it wrong could break dungeon selection. --- .../dungeon/pack/DungeonPack.java | 34 ++++++++++++++++--- .../dungeon/pack/DungeonPackConfig.java | 12 +++++++ .../dungeon/pack/DungeonPackConfigReader.java | 15 ++++++++ .../mod_pocketDim/helpers/DungeonHelper.java | 9 ++++- src/main/resources/schematics/ruins/rules.txt | 2 ++ 5 files changed, 67 insertions(+), 5 deletions(-) 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..44ea2d1 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; @@ -136,15 +137,30 @@ public class DungeonPack int maxSearchLength = config.allowDuplicatesInChain() ? maxRuleLength : MAX_HISTORY_LENGTH; ArrayList history = DungeonHelper.getDungeonChainHistory(dimension, this, maxSearchLength); - return getNextDungeon(history, random); + + ArrayList subtreeHistory; + /*if (config.getDuplicateSearchLevels() > 0) + { + subtreeHistory = DungeonHelper.getFlatDungeonTree( + DungeonHelper.getAncestor(dimension, config.getDuplicateSearchLevels()), + MAX_SUBTREE_LIST_SIZE); + } + else + { + 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 +179,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 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/helpers/DungeonHelper.java b/src/main/java/StevenDimDoors/mod_pocketDim/helpers/DungeonHelper.java index 545168d..419ffcd 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/helpers/DungeonHelper.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/helpers/DungeonHelper.java @@ -615,7 +615,7 @@ public class DungeonHelper { throw new IllegalArgumentException("dimension cannot be null."); } - if(dimension.parent()==null) + if (dimension.parent() == null) { return new ArrayList(); } @@ -664,4 +664,11 @@ public class DungeonHelper } return dungeons; } + + public static NewDimData getAncestor(NewDimData dimension, int levels) + { + // Find the ancestor of a dimension located a specified number of levels up. + // If such an ancestor does not exist, return the root dimension. + return null; + } } \ No newline at end of file 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 From 151f1a93a51bd81ae2656420ac14acb6c887e87b Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Sun, 16 Mar 2014 22:55:26 -0400 Subject: [PATCH 033/187] Fixed Tooltip for ItemStabilizedRiftSignature Fixed the tooltip for the Stabilized Rift Signature - it was a copy of the Rift Signature's tooltip. --- .../mod_pocketDim/items/ItemStabilizedRiftSignature.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemStabilizedRiftSignature.java b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemStabilizedRiftSignature.java index c17da83..4d1cf84 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemStabilizedRiftSignature.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemStabilizedRiftSignature.java @@ -119,8 +119,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."); } } } From 3966f420db9a25979c75e0b6b79fd262a0039cad Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Mon, 17 Mar 2014 02:37:57 -0400 Subject: [PATCH 034/187] Improvements to Dungeon Selection Changed the code for dungeon selection in various classes so that rather than allocating and passing around the dimension where the dungeon will be generated, we instead pass around the parent dimension. This simplifies our code and moves us toward avoiding stray dims when dungeon selection fails and to solving the dungeon pre-generation problem with gateways. --- .../dungeon/pack/DungeonPack.java | 6 +- .../mod_pocketDim/helpers/DungeonHelper.java | 61 +++++++++++-------- .../mod_pocketDim/world/PocketBuilder.java | 35 ++++------- 3 files changed, 52 insertions(+), 50 deletions(-) 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 44ea2d1..6c426d2 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/dungeon/pack/DungeonPack.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/dungeon/pack/DungeonPack.java @@ -123,7 +123,7 @@ public class DungeonPack } } - public DungeonData getNextDungeon(NewDimData dimension, Random random) + public DungeonData getNextDungeon(NewDimData parent, Random random) { if (allDungeons.isEmpty()) { @@ -136,13 +136,13 @@ 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); + ArrayList history = DungeonHelper.getDungeonChainHistory(parent, this, maxSearchLength); ArrayList subtreeHistory; /*if (config.getDuplicateSearchLevels() > 0) { subtreeHistory = DungeonHelper.getFlatDungeonTree( - DungeonHelper.getAncestor(dimension, config.getDuplicateSearchLevels()), + DungeonHelper.getAncestor(parent, config.getDuplicateSearchLevels()), MAX_SUBTREE_LIST_SIZE); } else diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/helpers/DungeonHelper.java b/src/main/java/StevenDimDoors/mod_pocketDim/helpers/DungeonHelper.java index 419ffcd..e2d601b 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/helpers/DungeonHelper.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/helpers/DungeonHelper.java @@ -231,10 +231,13 @@ 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. + DungeonPack pack; - DungeonData dungeon = data.dungeon(); + DungeonData dungeon = dimension.dungeon(); if (dungeon != null) { pack = dungeon.dungeonType().Owner; @@ -247,7 +250,7 @@ public class DungeonHelper } else { - if (data.id() == NETHER_DIMENSION_ID) + if (dimension.id() == NETHER_DIMENSION_ID) { pack = NetherPack; } @@ -500,9 +503,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 +515,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) { @@ -609,34 +612,42 @@ 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 same pack as the root will be included. + * @param root - the pocket dimension that serves as the root for the dungeon tree + * @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, int maxSize) { - NewDimData root = dimension; ArrayList dungeons = new ArrayList(); Queue pendingDimensions = new LinkedList(); diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/world/PocketBuilder.java b/src/main/java/StevenDimDoors/mod_pocketDim/world/PocketBuilder.java index c384ec4..877837f 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/world/PocketBuilder.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/world/PocketBuilder.java @@ -186,7 +186,6 @@ public class PocketBuilder schematic = loadAndValidateDungeon(dungeon, properties); return PocketBuilder.buildDungeonPocket(dungeon, dimension, link, schematic, world, properties); - } @@ -206,10 +205,18 @@ 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); //Load a world @@ -220,17 +227,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 +248,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) { From f4b619635ef56f774bf7bbb99219a3c856b1258d Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Mon, 17 Mar 2014 03:04:06 -0400 Subject: [PATCH 035/187] Rearranged dd-rift Workflow Changed dd-rift and dd-random so that rifts are only placed after a dungeon is generated successfully. We also delete the link if generation fails to clean up after ourselves. Also changed PocketBuilder.generateSelectedDungeonPocket() so that its checks are stricter and we validate dungeons before allocating a dimension. This resolves one of our old issues: "Rearrange workflow in dd-rift to prevent rifts from being created if no dungeon gets loaded and to prevent dimension registration if the dimension cannot be populated" --- .../commands/CommandCreateDungeonRift.java | 19 +++++++++++---- .../commands/CommandCreateRandomRift.java | 19 +++++++++++---- .../mod_pocketDim/world/PocketBuilder.java | 24 ++++++++----------- .../world/gateways/BaseGateway.java | 12 ++++++++-- 4 files changed, 48 insertions(+), 26 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandCreateDungeonRift.java b/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandCreateDungeonRift.java index d5ba8dd..b1512e3 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandCreateDungeonRift.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandCreateDungeonRift.java @@ -63,15 +63,24 @@ public class CommandCreateDungeonRift extends DDCommandBase { result = findDungeonByPartialName(command[0], dungeonHelper.getUntaggedDungeons()); } - //Check if we found any matches + + // 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() + ")."); + 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 { diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandCreateRandomRift.java b/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandCreateRandomRift.java index 013921b..97cc1a5 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandCreateRandomRift.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandCreateRandomRift.java @@ -69,15 +69,24 @@ public class CommandCreateRandomRift extends DDCommandBase { result = getRandomDungeonByPartialName(command[0], dungeonHelper.getUntaggedDungeons()); } - //Check if we found any matches + + // 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() + ")."); + 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 { diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/world/PocketBuilder.java b/src/main/java/StevenDimDoors/mod_pocketDim/world/PocketBuilder.java index 877837f..860bf4c 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/world/PocketBuilder.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/world/PocketBuilder.java @@ -145,7 +145,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,13 +155,20 @@ 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); + + // Register a new dimension NewDimData parent = PocketManager.getDimensionData(link.source().getDimension()); NewDimData dimension = PocketManager.registerPocket(parent, true); @@ -174,17 +181,6 @@ 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); } 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 92572b7..b19e8df 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/world/gateways/BaseGateway.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/world/gateways/BaseGateway.java @@ -73,7 +73,15 @@ public abstract class BaseGateway 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)); + DungeonData dungeon = this.getStartingDungeon(PocketManager.getDimensionData(world), world.rand); + if (dungeon != null) + { + PocketBuilder.generateSelectedDungeonPocket(link, mod_pocketDim.properties, dungeon); + } + else + { + System.err.println("Warning: Dimensional Doors was unable to assign a dungeon to a Rift Gateway."); + } return true; } @@ -107,7 +115,7 @@ public abstract class BaseGateway */ public DungeonData getStartingDungeon(NewDimData dimension, Random random) { - return getStartingPack().getNextDungeon(dimension,random); + return getStartingPack().getNextDungeon(dimension, random); } /** From a92b07d976757052bcf3dac18dac8cf6348d480d Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Mon, 17 Mar 2014 06:34:02 -0400 Subject: [PATCH 036/187] Overhauled Gateway Code * Split off schematic-related functionality into BaseSchematicGateway. * Moved the default implementations of many methods to the base classes because having a bunch of duplicate stubs all over the place was a waste. * Removed methods that were redundant or weren't being used for anything. * Added support for importing schematics while ignoring air blocks through IBlockSetter - now our gateways are copied in without air by default. * Fixed bugs that would have prevented the sandstone gateway from generating. * Removed the code in generate() that would cause dungeon pre-generation. We should solve this by attaching data to links instead and it's not a feature that we're even using right now (everything uses the default pack). * Fully documented our functions - it's so beautiful... --- .../dungeon/DungeonSchematic.java | 4 +- .../schematic/ChunkBlockSetter.java | 9 +- .../mod_pocketDim/schematic/Schematic.java | 6 +- .../schematic/WorldBlockSetter.java | 15 +- .../world/gateways/BaseGateway.java | 193 ++++-------------- .../world/gateways/BaseSchematicGateway.java | 66 ++++++ .../world/gateways/GatewayGenerator.java | 21 +- .../world/gateways/GatewayLimbo.java | 46 +---- .../gateways/GatewaySandstonePillars.java | 48 +---- .../world/gateways/GatewayTwoPillars.java | 43 +--- 10 files changed, 158 insertions(+), 293 deletions(-) create mode 100644 src/main/java/StevenDimDoors/mod_pocketDim/world/gateways/BaseSchematicGateway.java diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/dungeon/DungeonSchematic.java b/src/main/java/StevenDimDoors/mod_pocketDim/dungeon/DungeonSchematic.java index 38848ad..23bd064 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/dungeon/DungeonSchematic.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/dungeon/DungeonSchematic.java @@ -184,11 +184,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)); } } 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/world/gateways/BaseGateway.java b/src/main/java/StevenDimDoors/mod_pocketDim/world/gateways/BaseGateway.java index b19e8df..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,144 +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.Point3D; -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.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); - DungeonData dungeon = this.getStartingDungeon(PocketManager.getDimensionData(world), world.rand); - if (dungeon != null) - { - PocketBuilder.generateSelectedDungeonPocket(link, mod_pocketDim.properties, dungeon); - } - else - { - System.err.println("Warning: Dimensional Doors was unable to assign a dungeon to a Rift Gateway."); - } - - 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; } @@ -149,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..6eaa0da --- /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.LinkTypes; +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, LinkTypes.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 9936150..d2d9c0f 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/world/gateways/GatewayGenerator.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/world/gateways/GatewayGenerator.java @@ -25,7 +25,7 @@ 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; @@ -50,7 +50,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)); } @@ -135,26 +134,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); } } } 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 6dbf10b..c202fcd 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/world/gateways/GatewayLimbo.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/world/gateways/GatewayLimbo.java @@ -3,67 +3,37 @@ package StevenDimDoors.mod_pocketDim.world.gateways; import net.minecraft.world.World; import StevenDimDoors.mod_pocketDim.mod_pocketDim; import StevenDimDoors.mod_pocketDim.config.DDProperties; -import StevenDimDoors.mod_pocketDim.dungeon.pack.DungeonPack; -import StevenDimDoors.mod_pocketDim.helpers.DungeonHelper; import StevenDimDoors.mod_pocketDim.items.BaseItemDoor; 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. + // 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 columns around the door + // Build the columns around the door 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); - - - } - - @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 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 cab1e12..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.mod_pocketDim; import StevenDimDoors.mod_pocketDim.config.DDProperties; -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 9e1ea33..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.mod_pocketDim; -import StevenDimDoors.mod_pocketDim.config.DDProperties; -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); - } - } From f8982a871d84f37b2b4bfdb66e1f504e11b39490 Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Mon, 17 Mar 2014 08:57:31 -0400 Subject: [PATCH 037/187] Minor Change Removed a misleading comment from the rules.txt for Balgor --- src/main/resources/schematics/balgor/rules.txt | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/main/resources/schematics/balgor/rules.txt b/src/main/resources/schematics/balgor/rules.txt index bb4d683..57c87e7 100644 --- a/src/main/resources/schematics/balgor/rules.txt +++ b/src/main/resources/schematics/balgor/rules.txt @@ -8,8 +8,6 @@ Settings: AllowDuplicatesInChain = false AllowPackChangeOut = false DistortDoorCoordinates = true - -## Prevent this pack from being selected for transitioning in once we've transitioned out AllowPackChangeIn = true Rules: @@ -20,4 +18,4 @@ Rules: ? -> ComplexHall#40 Trap#60 -->ComplexHall#100 \ No newline at end of file +-> ComplexHall#100 \ No newline at end of file From b1b1035b5f9d0cf67e71c26c70410a308d9ee649 Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Mon, 17 Mar 2014 19:03:32 -0400 Subject: [PATCH 038/187] Integrated Balgor Pack and Fixed Bugs * Set up the necessary code in DungeonHelper so that Balgor is registered along with the other bundled packs. * Improved the code for registering bundled packs to reduce the number of paths we need to hardcode and to crash DD if a pack fails to load. A crash would be inevitable no matter what since bundled packs are integral to DD. * Corrected an invalid generation rule for Balgor. It's set to select random dungeons infinitely for now. I'll add an exit room later and change the rule to force an exit. Balgor is still unusable until its schematics get proper doors. * Fixed PocketBuilder to actually check the results of validating schematics before we try to build them. This was causing cryptic error messages when flawed schematics were loaded (e.g. rooms without proper doors) and could have caused serious problems during dungeon regeneration. Don't ignore validation! --- .../mod_pocketDim/helpers/DungeonHelper.java | 51 ++++++++++--------- .../mod_pocketDim/world/PocketBuilder.java | 11 +++- .../resources/schematics/balgor/rules.txt | 2 +- 3 files changed, 37 insertions(+), 27 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/helpers/DungeonHelper.java b/src/main/java/StevenDimDoors/mod_pocketDim/helpers/DungeonHelper.java index e2d601b..487e4f4 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; @@ -32,7 +32,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; @@ -48,10 +47,7 @@ public class DungeonHelper 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 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 +154,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 +183,7 @@ public class DungeonHelper if (config == null) { System.err.println("Could not load config file: " + configPath); - return; + return null; } //Register the pack @@ -208,6 +204,7 @@ public class DungeonHelper { registerDungeon(schematicPath, pack, isInternal, verbose); } + return pack; } public List getRegisteredDungeons() @@ -235,6 +232,7 @@ public class DungeonHelper { // 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 = dimension.dungeon(); @@ -436,32 +434,31 @@ 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); + registerBundledPack("Balgor", 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) { @@ -473,15 +470,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) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/world/PocketBuilder.java b/src/main/java/StevenDimDoors/mod_pocketDim/world/PocketBuilder.java index 860bf4c..f26939b 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/world/PocketBuilder.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/world/PocketBuilder.java @@ -104,8 +104,13 @@ public class PocketBuilder return false; } + DungeonSchematic schematic = loadAndValidateDungeon(dimension.dungeon(), properties); + if (schematic == null) + { + return false; + } Point3D destination = new Point3D(incomingLink.destination()); - loadAndValidateDungeon(dimension.dungeon(), properties).copyToWorld(world, destination, originLink.orientation(), incomingLink, random, properties, false); + schematic.copyToWorld(world, destination, originLink.orientation(), incomingLink, random, properties, false); dimension.setFilled(true); return true; } @@ -167,6 +172,10 @@ public class PocketBuilder // 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()); diff --git a/src/main/resources/schematics/balgor/rules.txt b/src/main/resources/schematics/balgor/rules.txt index 57c87e7..2e02f45 100644 --- a/src/main/resources/schematics/balgor/rules.txt +++ b/src/main/resources/schematics/balgor/rules.txt @@ -12,7 +12,7 @@ AllowPackChangeIn = true Rules: -? ? ? -> +? ? ? -> ? ? ? -> Maze#20 ComplexHall#40 Trap#40 From c980c797e8028a3398eed830d8ef08f4b9e6240a Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Tue, 18 Mar 2014 04:56:07 -0400 Subject: [PATCH 039/187] Fixed Limbo Gateways and Minor Change * Fixed Limbo gateways. I accidentally broke them while overhauling gateways in general. * Changed references to BaseItemDoor.placeDoorBlock() to use ItemDoor.placeDoorBlock() instead. We should refer to the original class that implements the function. --- .../mod_pocketDim/core/DDTeleporter.java | 7 ++----- .../world/fortresses/ComponentNetherGateway.java | 4 ++-- .../mod_pocketDim/world/gateways/GatewayLimbo.java | 12 ++++++------ 3 files changed, 10 insertions(+), 13 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/core/DDTeleporter.java b/src/main/java/StevenDimDoors/mod_pocketDim/core/DDTeleporter.java index bdb7fd7..7c7bb6c 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/core/DDTeleporter.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/core/DDTeleporter.java @@ -9,8 +9,8 @@ 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,14 +20,11 @@ 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.Point3D; import StevenDimDoors.mod_pocketDim.mod_pocketDim; import StevenDimDoors.mod_pocketDim.blocks.BaseDimDoor; 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; @@ -605,7 +602,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()); 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..8b05b39 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/world/fortresses/ComponentNetherGateway.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/world/fortresses/ComponentNetherGateway.java @@ -4,6 +4,7 @@ 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; @@ -13,7 +14,6 @@ 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.items.BaseItemDoor; public class ComponentNetherGateway extends StructureComponent { @@ -159,7 +159,7 @@ public class ComponentNetherGateway extends StructureComponent { link = dimension.createLink(x, y + 1, z, LinkTypes.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/gateways/GatewayLimbo.java b/src/main/java/StevenDimDoors/mod_pocketDim/world/gateways/GatewayLimbo.java index c202fcd..27448b3 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/world/gateways/GatewayLimbo.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/world/gateways/GatewayLimbo.java @@ -1,9 +1,9 @@ package StevenDimDoors.mod_pocketDim.world.gateways; +import net.minecraft.item.ItemDoor; import net.minecraft.world.World; import StevenDimDoors.mod_pocketDim.mod_pocketDim; import StevenDimDoors.mod_pocketDim.config.DDProperties; -import StevenDimDoors.mod_pocketDim.items.BaseItemDoor; import StevenDimDoors.mod_pocketDim.world.LimboProvider; public class GatewayLimbo extends BaseGateway @@ -19,16 +19,16 @@ public class GatewayLimbo extends BaseGateway 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); + 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 + 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); + ItemDoor.placeDoorBlock(world, x, y + 1, z, 0, mod_pocketDim.transientDoor); return true; } From 300228ea2466e25aad1ee6fb1722ba75d70a56c4 Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Tue, 18 Mar 2014 05:01:09 -0400 Subject: [PATCH 040/187] Fixed Limbo Gateways (again) Forgot to add the line for creating the dungeon link. Done and tested. --- .../mod_pocketDim/world/gateways/GatewayLimbo.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) 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 27448b3..cb50437 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/world/gateways/GatewayLimbo.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/world/gateways/GatewayLimbo.java @@ -4,6 +4,8 @@ import net.minecraft.item.ItemDoor; import net.minecraft.world.World; import StevenDimDoors.mod_pocketDim.mod_pocketDim; import StevenDimDoors.mod_pocketDim.config.DDProperties; +import StevenDimDoors.mod_pocketDim.core.LinkTypes; +import StevenDimDoors.mod_pocketDim.core.PocketManager; import StevenDimDoors.mod_pocketDim.world.LimboProvider; public class GatewayLimbo extends BaseGateway @@ -27,7 +29,8 @@ public class GatewayLimbo extends BaseGateway 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); - + + PocketManager.getDimensionData(world).createLink(x, y + 2, z, LinkTypes.DUNGEON, 0); ItemDoor.placeDoorBlock(world, x, y + 1, z, 0, mod_pocketDim.transientDoor); return true; } From 3d8a9aaf274412d148672e21b4130d79db46f34a Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Tue, 18 Mar 2014 20:30:09 -0400 Subject: [PATCH 041/187] Removed Balgor Pack After finally getting the dungeons to load, I've determined that only half of the rooms should be included. The three remaining rooms should definitely stay. That's not much for a pack so I'm going to make some modifications to the schematics and include them as part of Ruins. --- .../mod_pocketDim/helpers/DungeonHelper.java | 1 - src/main/resources/schematics/balgor.txt | 6 ----- ...omplexHall_GardenBalgor1_open_39.schematic | Bin 2502 -> 0 bytes ...exHall_OpenHallBalgor1_Closed_68.schematic | Bin 2144 -> 0 bytes ...l_SilverEggHallBalgor1_closed_25.schematic | Bin 1933 -> 0 bytes .../Maze_OmniMazeBalgor1_open_30.schematic | Bin 8652 -> 0 bytes .../Trap_ArrowTrapBalgor1_closed_20.schematic | Bin 3264 -> 0 bytes ...Trap_ZombieHallBalgor1_closed_25.schematic | Bin 1956 -> 0 bytes .../resources/schematics/balgor/rules.txt | 21 ------------------ 9 files changed, 28 deletions(-) delete mode 100644 src/main/resources/schematics/balgor.txt delete mode 100644 src/main/resources/schematics/balgor/ComplexHall_GardenBalgor1_open_39.schematic delete mode 100644 src/main/resources/schematics/balgor/ComplexHall_OpenHallBalgor1_Closed_68.schematic delete mode 100644 src/main/resources/schematics/balgor/ComplexHall_SilverEggHallBalgor1_closed_25.schematic delete mode 100644 src/main/resources/schematics/balgor/Maze_OmniMazeBalgor1_open_30.schematic delete mode 100644 src/main/resources/schematics/balgor/Trap_ArrowTrapBalgor1_closed_20.schematic delete mode 100644 src/main/resources/schematics/balgor/Trap_ZombieHallBalgor1_closed_25.schematic delete mode 100644 src/main/resources/schematics/balgor/rules.txt diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/helpers/DungeonHelper.java b/src/main/java/StevenDimDoors/mod_pocketDim/helpers/DungeonHelper.java index 487e4f4..a4cc980 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/helpers/DungeonHelper.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/helpers/DungeonHelper.java @@ -436,7 +436,6 @@ public class DungeonHelper //Open the list of dungeons packaged with our mod and register their schematics RuinsPack = registerBundledPack("Ruins", reader); NetherPack = registerBundledPack("Nether", reader); - registerBundledPack("Balgor", reader); System.out.println("Finished registering bundled dungeon packs"); } 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 fd5f92694462905c708a15a3aa9d72b8577650fa..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2502 zcmds2Z#WZr8=fJgQPR>M?GRCn%9j5|VyPy=)P(+M%^01OPRuqrM{kKzZMCh$O6!GfrC}y5sGz2dLgB`VO-}I$P5$L->e_C%yJThuSME;E?ZlZW|EX=@9F00hW@kJ&%~AcvK+CMpS58`&AU ztOEZCOup1S(eg4+Q*f9S7S?kL_zu=^=?J{}KH7fo9WzqOd-o*+*Y_C`Hw3G9S@JbZ&ca50Tg)!5iuiX+r zN*9UjW{pS)p~{wl7ho`_`_;vRM)LqT#iD1u3a(Z?v(z188*g#Me5T&c+*h@cb8Hx0 z9)>Naf^*5ut10I{0Gnpd@0ogYbawV)L>sQiL5ic-Z-htUEkyZjgP;Dz%S}XbNR}w| zEh78&2bc*C$uSV*v1ZFI^zRsj(-)rt=2`*(2TX|oz#rTD4FQ2*{S^OuWZ7RIT{+qP zc4lhoh4cJ$^mFoUo_jiNL<$-FG$Q5Hjg%2Tw@rQB+7)h}0;3+%V%Fs}{FdcOZBZPY z=g(K~X~Hy~o$k^yJ>@RsVuWt)yyci$AxxN8O?;fn!Oz3jIcob9gM%-H)hkD&v6JZm zwr@WmB1aJ+cgRHnds#w#vf!NSryUu3#+ixpX71Ez$E5C6il(n>lVZq%bfn#YlGr*D z^r<5?pzh#f+$+Z|O&-rXOB2&T8(gMk6#kkh^Ry+ozN61ub9A%nnaL$#rmUs|X3KWv4XV^D>H*c4jJ^Bqf2ts8{O z#EJtIJ-|e7Prg4KNWL1^8~PT}U59B-s@ck?Cc)^bjS`W43ia1oZTsf~dqSU4D{EJE zR%RmVvk7o|QVsQ(nOGev&FC8F+MBtToiw|GK3;N&P}8NvQ+b(8c|=otblHrx=H>aA zd#H=+11Pi{|N1WMrvmYHF8F2_Hnc`J)>TL&CqEUtW>hEB@U$Rm#Q^Ds9r5&^i zaeDp+9~lXdDINqvrSYRj?VhCTm|U#)FZGd7@+6kGp$?~w^IL(cVlZ3!&?WKnkx%G3gAaKDn1_>@&0MLXn-xeD5^@PceuDYv5no zI;I#kJ|7bYCG41cWWf z4;9@GeZt<1?fC-sbmR1mhTGA#_oI8h{MA?9f&IEd7N2!%_<=4(Qfu84%h_Y4#K#{vowqVl~T{!(I|>u zuH^+s<>TF0F8sl?_J6htZTRPZlxp|(kCnV5bABD}2A6wqR%(1u5KWGQcP_%U%`8`u zi$1xh+rytoxGa$Nz93WLd@Phl*g0#XSdQsIPihXgMl{0&yn B$aDYz 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 19be9c4f09f7384b7892572a22f82eb86f70721a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2144 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 ID#T*dUr6=E8vp!D(E=<^Ar| z)KpE~s#`NtHGjT!{+!xpJ?lJc?X~x_sA5s!{?ks3CX(q|oRKAxlr)7-dmO)~)QKoH zQ2eAlPN67F!6tW+Uc;g18jnvrX)hRJgv3)03L6c-aA+KE&|CNaTFc8it*XNtmf0SY zasPZ>ev%USa(Sc^__RH7#9{KY;CYA05n}Uv&}BDiBzJVx(B;qFVq|=E+7q{=ncFpn zEs#BbGGUTIVcv0aT-xOrcny>&3wDMNm5bD5oM19?+>Dz}@JB$%1Jr8xV*1&V%;wMv z&NxtjKU+d=hyYhh#b2Kn?&s~rMopvm3ck6?4XdjSMs|7zVo$0Pp?W(DI`{p z^C+||KAakbUHcW_Ee;77yy4yV^6+q^6t8E5@phdh1oW-X+M>kQxb>WB`80O(VDkwp zk5Booc07rlRL?4F_%ez5Wa=8aDN28b~DtSCo_A}in1NFjX11-#xhT3fo5x z@4y1L>zfLSwfqlz=B5COcv^whVp{KvRXOys0mnXzrMvh55vYF#4UT)^E+MokKui;= z;i0l3tb;SE7f^XrkvBcF*Yd|$2LrI;|9J!pjxQ?W^f>$|L9BhGYyP8sdgaa~%Lr9# zpQ2s0{-s8;%(|}@xXmJEEfH`hl@lM{%5M@F#A{_tLg`PQlGxZZmlY-;SZt&6)Q3D~ z?qbo>Y5p$0Hs`R9Bc@{He(|x+_b0_feN0$wfUD;kS(>1Y?3PfAt_%E0=cgYW_l#6e z$^IGyeLEGmp{gH-9yFwRhxZ1eJ|8N^06-gB(_G)8I;X^|&S6MUsc&c$V+x=8p~<$i zKZvI?k=o{FnB#M>`;AA1b3a_}EhWwo+~Hl(e;pOZ9Ht76_x-FYE)rtZiL)56X+@cu zmTKS_b8s=Lh(R0F*ci5Rd0s#MJ-G4@WW%$n9j&g593=gJm{g44fT&8?68Co z5lo=^2}M!viom$GXv;wV54##AXMQW>rb0u4zwM)Yv>&%yiv7woEhk%IOS^kedo#r_ z=rDu~eqtFHQ$-qTH!~XLpmqO3`m}-6%5#5+o7IuZKNA|-%EJ(Qq%?USmXsrCP%eb` z)^C{|=kHTc;N$gB6Zavp!o_ifbP!@`@0qo+dOh)Mt+8Ly&QO+0Uw;^dA5{DHo)xP1 z*Vrt*NFq?{=P`{ZL9*N8H)4;1Be+MbRNHlVv=;Djijh2&0^cAM**o`Ps#+BLEW;aN z!Th&bc=G$wS$ZmY`@5SCjt8Z6c0~CD` zOWv(mTI?nvxAm|L?a78T>+Y|2mDAt7*=P@skL^+%r~(PQ2Lu zBITIeS-+xPYq4t*4Np|H@wyU}wM;8y|Jq-Kb?({Rqf99|S|sZ+05dk9@#4U2(L$B8 zj5BRSm}~(!l6b>jx1thRR?4s-sVxakJrjO!CLMdR89F{oDDuaA9436Ul@AkNR7$%a zr2nkQ{Qa(L@>^AP^IW||aovUpkGDT4$gqsd39(JmsWHgl}n_XtXSRDzi|V!>4fhYes(H z&Ysm1Mwc|z&=CRNWspQh-D zMfvFNiDxRphYZ<_7eM|#f-(-NW1vVwERyGBMd?M&qJnCZt=RnVb~bRUfB3tTgQ4Nw z18xn`xv-UWn;+X~Z?AeJxizZb)|nlw*bl157~jEl6kC~gzAVXYaTGo5P#HW84gEBr z?$k1%qpMh4T&a06HCCm{j?b~2>@C=nY3=mjd~!$ZY!z%yWIZ485XB;z09-6-?w_Kb zoxu07^h{Pc21{8ZJ~;1Em%tWjgh$%+Xp z$+(eIs)nnkI**tJ>#10Q6FH?amXdeJh_sCvVdT4pn5&>_gqOTh&srPsXvJ#2Y%bOj$g%}MP*t(FamRtX^3Ckwk6hM6Y8YJGt_}{SU8F+3Z3GXY{~S}Csy+as zB~O=qy1vhq7E8SN9VJj&g(xboJna@?^vyJ5J6~VE-tH(-c5B0;d}}UIWM3AcFY?K_ z#hgM$Cvzfar3k*y(J7|FDf`kJHn7=eV1VJBUTNaK{=K znQ_sQ-R~It8=XAIp_W34tLXDgT-f|9-?Gph9WQtFaaVw%x6Gf8hDA$Zn4T_rcFb`GnH%pG1&U~A(AR%JHBEk)7PNl@BRS(XMPnAK} z%vs)Y)a6-}xitE9ATsf26g|$LT4~0D8QtvE8vj*h{bLIFrv4%aQ^!Wij!b!$yXL?y ziZ}3&+z&)vOL4tz=w7s$9flS2&wH{jR#qw{c)DA|%9K!eA1x>qVR4Wuu68 z0RPJhc24|P5c(T8@tNkzTI#ch4p$bVHY4TF1)J#|p_o25W*MtF$ZRr_s_QNSOy*P0 zR!yXbaNpROt$&Y+{F zNqu=avUJiL1}&jz{)6H;lX7k*i0wCmfLKg{ZQNEtNn&v~*SHDd^2rxzvTYj6Op(rd zg=BO0nC~-R&WnnR4fIZSXs6OGA+9-*;(>i>k}m3CCH7R#1ME&*dVUOf zKA7_DEiXsH#NmVO1)5{cnUUL^_ z54SCoM&^UvwGNsMSBXo)%-Y#;SF)XQBBL8x%f@nKt#vG{$3>5l`h43;(k=xN8kduvRrKH4d$}meCwv&r=Azo+ed2eHJmTPn%k|3&A;FrOp;R$$8gge zNwy+0uzVmZwP6<25nRM4WEz0tRl%^jD^(5l1+ zB53b#GrdfvZ`U`LXMR?5@T&`A)`+p^jE|HI=S7ECqX^~fT+h=>Lo6g)()3a9v+6w0 zo_66QRo+T?u}@ARsk3^A@KH7Im)-~6IGtGTn8D48s1^SB=+_1lUDRoyO_|-F-}--Jt%aRSdHZZIt_l1Ek_dhwh#w? zAo5qk#(1Y;lA*9*5m>wa*XSp_cOuDtDShe*PK$USWkuc?u91UpQr@gA+`oNjW8Q$n z8!clX=l`It88+kp02>+qbMuBaTICRNxvx4UW_=v8tLrc2!q|8fZMr~U$ zzY$gp?5E>KBZHgxZE9oF#q{mai!YalwIQV(p<0+0B}6s8(_;?X6zipqhWL zq?cnsERtX7FEcWh2`%G7Ye9Zj29Xylrs5gbq(25N12<+q##ByK#J+yk5H6ys&!Up_ zxnLEEXGLphrm5B-xS<@kdY&$FBMw|SG>iK*>hZifdW9ccegU8)rb zfCRQ1|J?B&Nw}w)^%L9ZQ?y4t}5Vxn2{Qi{4F5{}BRGcLR_Jv`eBA!bS_A32)J6&U>OAh77(RmJwx+N4k zdDBcL0}Z>$nrj`LCa;ahD(ss|GcbhF`q%euXTRvege311@=k=kHlxnrq(1;Cdc29b znIR!3wQI$_9cOR5$njN+RnuTW(V||SXF6@c%3Gq0E$J;1G%83Zrbj_SkM1I2vlLS7 z*a(WhaaTZpboGM2QDswjCI(XW&eaaxubMbAjpRl5&%Y_Cn%t|%ox4C4!hy#*z!`0U zQC`Ysq4Vt z8_fO^fw3n;=Gj|n)K=juNI*e#p--I$v;FjQyaa$mzA}_8j-yzt;=|fbg);k-66N?| z`nZkVK=cOr@%Pzt0g-1dC0daFLY*O3-=d|}TcA5)a+`9kTJM2l^|@kZ5Tib<7R6|c zR%*svsLXCHyQ@+`KiO(v72GhRvN1bfa2xw6@g+8?y6W!ucD zJ}j#)9RKcE7H9(^YHqT>_nZIyeKhSG{Ck{PII(#Sf-{!u0d`p)O9ZaH7{?BD!aGut z>BJ93>%gPu$~hB`nsTxP&E}42|06$EVlSCV4?#W-Ooe?N7N%9oGbVraHg_xOk=k(% zvuu-TuHD(y_iM4e!O{+~qx*hvX=fewiCJOQ+-ZhS_N00(c=eO}f`6ibp`M>~JU``> zskb2eI7EB&e?7&?M^$VvS5m(@ozM)^ZdAy3yLlrf@*pzAojG>5QS_tlSw#jnxWpmX zDGb6|<6H4{MZ9?gPC`dY@3i+Yo0LlHN(Ac=R{EstYY_)eLEGnJvrKZ64YWI-5W2!| zTKcYuC_MH%pfa8Ag>bJ6MR1>;U>D`lgrTV|+!)x`LsM&f#?Ic|qgr21f}^;;*_H7* z?Yqwe_~eRW5$U3Et6p8v)wGe#6rgY5rzW=+rKrv*mg|^j>`q!Hue$;c6gC)B3duhP zk*GVQtMyN8oaB$-u8WOXx|gu^0kZ_#OKm`mL+5f2a6yvEz|_I_{rqM=^3;jmqgWcO z=oK`JYR^kh>=@(EDbvVJgMf8$^V8Y~Uo^p{B4%&?EdWv}Um;-mnxs)hzM5-~@oG&> z4u1;PkaaJUO$QAckYwfjjUO|qI~yBWDCIqtij!t8b_^3xD>*$BRFN|m#Q?-ky_p+F zE(1G`FW90bo>rmP08LQa@3rxuzX>)n9nHz)cQ}f%;zJHdb?0z0#d&8C><5N`x0uuH zYwqbQ5p(DzTe^}JD_gtLeAr&>O_F&(@f|DC=~o^89Q}kDx|7rHol)C`7GiDA7&fE_ zs6Y0|CXmrl*RfZxXdZ`pOPjDZB_!)|En&9WgD*B47e1)|Ni|Ky679b19i8nIhcoE_ zvCJ7Bty7AO7s#O8nz>ry`FwwxO^Mxae>fm05ADhJgKm0y18yAFBo zl<2&npHK3JXKs6WWPqVPSBq)-8oO1gCB*ydP}|Yi#JTIQs~Uu2O2(gt6Kj<@%;tl= z=uykKU$v=|w>el4k~2@nzOcj$b;L%vDy|AHo;-3~|I!oBjS2$BEjbRi5*V%^BGzzV^hwv`D}Uz%WPtL7Ht+ThLP{J0PNg)NSXqY zG8qZ?(xICnw`P&;%^8fubNfPjkD?3|IVwYWH`T0Jr#UGdu!C-x^|jY?vJnXknO3wo z`pV@~oZ%<}g`t(5ay>)1~m=<&8-<>;|Ec=oyBj4I&C z`(;=w$gCpWrI0QXy1nYRDiJu&_jvN5o3XCj@R`vxi{W72J{b&ZlR z>lq^V>wPJj2MIaUZJu74J9~!O<15g~{*cceK22yu z!0h)WKDp6X^q$RfI5a#%Z>LuJo_o!PnJf1xT#L}{xdplExl$jA0P!^wyZP@{vD~rK zW}XIjy20exXw_I4AGmm{8~jsfS!{U*y9eps9*Sme8p=)9AJh3M?nmFb&s)Zv>ld1n zU(00S*r6P4bOdpAvH9l|6}!fHif$~o4n@H!P>%JWXvLdo{@>YU*rnp*UBTb0{p*~? zI!L<+=Jw9bNSFV`{(K?yL&#Q%0bbm8UTqzth6_xY?PF!18$EYK)hP9-zmU*vyzR0nyO;1B$J3D|79>3VtXp{A1m-F8JsS_08#w#$fcZhE0UVMy0V@0Zv> zIejjlJVMEP^82Zg+A)?UfXg=}s9mO$cpk30Uq`-s{%UL0@(dIHp! zRDkyxRN3by_*+EBDB4BB#U8aFM|IJ{Y@a=-EtNH(+^?JWzkEtwUxxDeki^M-> zH|3ACTuq^Q3K3O$rP9XSF8R$=Z96e!9qD)ZA)?XJ=pIC`bQ(?+Un%F)zoOSt*Wby57@ZY*P7z*nYZhhh zx^Ii9`T=?$v>XA)OGp5+#mO1Z>Aj~_ppq> zyV~o5m(xmLF9v`ekoehKJ(4nV%os6eNPLP66~-aT3Y|mzqLqg(4v-{!5+v0Cl_*+6 zE<@c9eiG-rGe+awSy*mEnJIsjU!>}2PEMT2MRMi8%lRdorIT`~Q-cd(Jw+Ajz~r8| zY<#&>2PKCpem8v3TxO<#4Byn>NaFPS)DY>qH?0{buyh0mD{?#~OAo$k3|qT}YSkQ4 zxfx5VZ_tvvsd}_WXX;@+`o{+7292L}0PgFLe4C+p0>2;L7Q=`r~W$X3aC)y&~ z;%^KU#zDbQuB3U=4tv4>e+Cg(>3uok&UkzK;TW{v1DNJQK;4&u>*L(QU?qXk{w7dn z#t5q;Gs5}1LM=j+i)K8$-Ty}IZsCn{_%;{7cZ!8|i;S2!N^pd2Ts@TG3A5~K85Mpd ztn%5EYfmB5g7XJMWRmZyX3hr<8_rBqWo7bYJTYQcGDHnB^pe93f-T>FmB+PLeg$qT z@*O|ei!A$th+IQB(C+?7O$M@=LNJj_uAM~8_L215DKiw6k~4$e$j>&4`?>76wFSP+l%T_tk` zK=|ofm?HA5tqXBm3tJQO+i>Jiw88#L^WxZp3Wc+Hq}?broAQHimhHqC)_eY zdH>HY0`paU-@c7G4;RMwkH$qUo8RSham0nR+B$r}{p$`Y5Zijmi)qOq^7axmA$Q#P zD`FUcxKy~khu9eml1I99fqddztINoEA!Q)lJ)pKh{GQQR&Y`w_0(zv*{2k7!s*F?j zCe!)oc&%@)90<@Kctf#c3N(F3iSydBxT?U91^GeP+cjvRvYZ4AB+B8V2y&-JeW}s^ zqhojJ0VF4ZQ9v|lW?SiC{PnRLZ>3;9?yBh055guaMwAScJ0O1&pe?Z?k)!mdh#`gM zW6qhaB$_8XAOOLj?M6pjF8rmfqXxYIW3c-D)1-7MDa!VieD%5b3pLBrWX5Z*pYQC~ zqDxzQZ-ePxgOy4EB)_^{@bOrB#aSqQfDhc;I6Ggx?R7lE^#}}m$(n*s!85y@WaSwD zeF>V>$NhV2x+8bS4%>`5?-R+pVPL@D!ti8zz@x=ct{wsIzMebh`IQ-(rz2C@ zyC10Hq>me~0;ZZT`RZ&CTq)rx1b~)7Qa- zx#o2UL3*#-bNc2V;rwUS6XAU?hi(tLHb^-5RYw2ime>6%{MxUdk5ym$`yYRF560Jv k>t9jY-~J=9ul^zHX#Y#Ne@%KtCC}oK_SDm{c?fX-0cN}hI{*Lx 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 8ef105cd58a62dbabb521651ca927dd869d54d98..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3264 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 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 b968f0d972057bb273fbf4ba01ff6e2ab058cc9d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1956 zcmd5)YfzJC7XF}CE^cHOB)AdfQn?5QM-o6m0tA91m;@1U`7nq|;0uzZRW5Q7tdv+v z6<2hXL>iLRfP{!G0YorXs9O+_L@ucbBt;Ss1ffBJa0weNo$2(~&g`E(Ki>1sd!Bip z=RD`w6`KOT#Z>ta&1(N%WHBVcYT(>CGJp@1x+Ze75Tl~I3N6lk5p z>iTMQaOdJANR_AF#Is0a%jv8=J^U^B`JMe?XesGJ{6~Q64}{gmrSNI_4dEx31|Y9g zxf;7=07q2cO`*?++%D=%2YLM|u}%PRWht7zru=_R_In5#^~FZsFtq3XUAz+W&tBCc z@A1;{RV{d#9Uo76OVkwKXzP4@w3!835Ht%nq`!2(y#$gb+GgdC(wk;$R{5*h_NoE( z!cu0wcuK*ORY4 zG2D_Fn6%xZ=znXHFZwnun~+1?{Q5e|k}mpojJJ8xqB5#Vx4f(R8s+akqOA)qKdP6J z)o8!B2cH}Dn9z@vc&I-+OkjV*&d=1n>9>`&w7hfBClS_1qm}&_#!pli|nPQ zJd7s?i=iP6r7?e`An2Duc5G%f`AA4{n81eZT|zuF)>6j2>gaH+aw?Ao<$Sx>REMB$ zyJMS$LQ8{&dDQ1m&2*!!J*7T}55LTiPSD{@QuqL*$BIMUulNL8ZQYco1}$flwEE>N zl$R6D2DWsTC%bxnz5%~h*NamQ{E(xF?qvV=MdULirBT5c@UC>Co&+O(>UF9#Pb9?! zGZ)iC2%jk0jqHHNnMH}{JC&7X<<4~<#m9=MDN}>Yo5fGH+>f>#A{L-S6jEUI7J)H?S$FLeC0uWkpkC- zi5CUd8?SX4U90I~-P!S3GxYOM#qg>adpg6}*ELr(@rSOY#{K5%Zb^tqVM)xxe+AI_ z{2!;d$L)5372xMBe`mg`n2}b?v}4_U*Y1hd^m)qf zJqY4|_vBuQ4Km`t7cZ5#4P0xo&{;|(88U;+;6B4q&<7-hlHM%u+bkAu?ihJsyNcPz zUI8S2vuwRiH{t>S=gIos^9)186owA-I2?|qH~UPk2N=SekxC>I&o8^SA@Rzxku!9h zs9@LfuV+)G*}hZm<@}?YU@+=_VN!oe=`j>Fu2kmyZAvwjs=ae0T=?BT=3_cr3R>qY zhL+vmoxRSQhfDJiCG3Ows_G#9=++jyO{b<)!0Cc-F4D7V?)#hZZ1c z>2?-X%aywkyD|?gY!f|!oj$tY+kH|gk<5iE1kOiNVm@HkzsELtk#Rr$tPbloFPsjF z8?-mKgBjem9_pv;_HK%-!w%<2;67DXTV;8qo9>t4q^`6xX58MEX{yHS-oxlTnu3{2 z$&Yi(zUYpt3pRkUgmx@%W=HOdvH`90RES^1%h{|y)Jj<{(=P&ya{Rlwr%|2Up^bHv z2QRgc8pms(XToHaB4moX@=dOHP2)Lv;y_xEg4-KZ2l+}z*Hv9gzi}`2gP_DMkD+8A zqSCL9_!@%y$CcL~cs=3afI2m+e1PcIDEW11W25KjPPgKG&XKk!D3rd%9M&`H;(b!- zlM@JGZx&6;w|kSG(?A(YQ`U|bP{GXazsHAH;yq;i+qtNEAy})J%IIoNC^SrfOdl|Z zAV^$)nIK4{~%0;rO ? - -? ? -> Maze#20 ComplexHall#40 Trap#40 - -? -> ComplexHall#40 Trap#60 - --> ComplexHall#100 \ No newline at end of file From ddcb0ff42e0eb472b9b36ff3f50d1479c271014b Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Wed, 19 Mar 2014 00:27:26 -0400 Subject: [PATCH 042/187] Added Dungeons to Ruins * Added three of Balgor0's dungeons to the Ruins pack * Made aesthetic and functional improvements to the dungeons --- src/main/resources/schematics/ruins.txt | 3 +++ ...Hall_Balgor0-CrumbledHall_Closed_75.schematic | Bin 0 -> 2513 bytes ...DeadEnd_Balgor0-ArrowHall_Closed_75.schematic | Bin 0 -> 2421 bytes .../ruins/Hub_Balgor0-OmniMaze_Open_50.schematic | Bin 0 -> 7039 bytes 4 files changed, 3 insertions(+) create mode 100644 src/main/resources/schematics/ruins/ComplexHall_Balgor0-CrumbledHall_Closed_75.schematic create mode 100644 src/main/resources/schematics/ruins/DeadEnd_Balgor0-ArrowHall_Closed_75.schematic create mode 100644 src/main/resources/schematics/ruins/Hub_Balgor0-OmniMaze_Open_50.schematic diff --git a/src/main/resources/schematics/ruins.txt b/src/main/resources/schematics/ruins.txt index fb199f5..5920286 100644 --- a/src/main/resources/schematics/ruins.txt +++ b/src/main/resources/schematics/ruins.txt @@ -1,3 +1,4 @@ +/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 @@ -16,6 +17,7 @@ /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 @@ -37,6 +39,7 @@ /schematics/ruins/exit_smallExitPrison_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 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 0000000000000000000000000000000000000000..7f924f633f517004c1bb97e4698989d2b7cd0dcf GIT binary patch literal 2513 zcmd^8X;c!37BV=lR1;zFwm3Z~_jq|X@#Gt|n;5=w_s zGYv5X(UhgsY+_t66?chBBP7ugMMNCm^5dQJ&inWNyz{;v_q*qwd%t_mJ@>ODY*zaR zB#$PGMrjtEbZpBvV3UJX<5HVzg4*3|?QXN^Gk9?mNfdp$zI6NtO^cdCC9JJWt#1;Q z-bLWfB1{MTVb7+Kw0r)0!WGMLof*7P;nXxFRXiEm(nUJ$lEoaM*(}Npt zPZ4&<3`|xH*QuUc46R(YzlwIkqs*CSG(uX3&`Lf!v<|dGKfrYl9JW6L=U+TTk z7ikXOdaK9jx0oSD)tpmKD0Vhw8!z!*USWJ{?0InP!M4_9{=J_-t|079c&Rx{>!gD) z;`gQmtK6f&x6 zFjePQQda9$7qRqVRnxGln4YP;Rm)h*P%f%IpstaU6J@E3ucn8^$YC*IM%FVUJ7kBm zZts00r@b)jfeq!^P7UStxE}DHB{re^+mkojCz?ZjBXR=_(T=+lS3h1|NlCS4<#%-P z8H~v>x7KCJiR(|Z{D3I67%xS)`vYG)laZ3xLiq$_7!~mlUIOGAKF1xp)HR#4@CZ^N zbIg(VZs*f*JN3ng{qz2Bh`?zpv#1In0cvw32N$YnhF{s;VwAMsQSo6d>Ha6b8>wIG z-kqOwVHPIOX83+SRWWt0V*@aqFqH~bbdxG&4mrVo&Ha72cR`UpgsVRGU@-S!2m*2M z;y!vXJOP1vRy{%M52U<(5A~7l_9uvph$(5a@#=1a^wyyCK@=fG#S?>T`|D`JU;D?* zXl-$|=8b*z3^Z|@+ceX>QCKa~D@gz4F0*1e7Cj++91&-I=2~y-lcv~O)Yq*6*=59R z%Wd0~4o3jUPlf^7%IEzB9NX?9grM_tzBrp2t&C82J5brsczQ!HHI(8=O1}-U4!mpZ zII!oWubGI#XO&Dtt5t#7wxhuU?h&x`B54b5xKfi9AGBVgaqeUGt(SoEBqZ%>&|Vxc z8yV&1Bl&VJZ-We&Klp$KyKQP%q8b0>@kbySGrKOwv_Z3h@_Ab$dA-knR6`%VAmAQ| zOVv#hy8tFzof!M!Y6D_>Dalv#y<{GM?9PQJfMeX(>aUa|Z!=KPhzkPe38e%2zOj4& z_i)Z!HLt!F%cN({nbqb2DTtH4+^6hHu$45!*s(`y8)+rA@oh>his32Fh7c+WuH)f+ zJfHN;QJC6W_tY31fbn4NAYS^J<4r=EMkQ2EU7tMGRvJZfr|Zk2V_)k4EHRmwG-e6W zDsz)g##J6*z^k7`)`D!t(U$2SWYOqCx%uH4k*9XB>8S+#cVj!Hys7`a1>1En(OoaT z!H#Mirm0M_Z>Hq^E!;Ly+wLJ$nlHvq>&fk@m5)3Hp_83xJ$Wgu_Nm55-yUJj4Exf&4uuRl@yDB}o|V$< zS%oKu4q3&sn(yq=WPLQxl<2+;v67CeyCrVLHRN%Y${jalvd+EwWQu_K6iq$47A}ZG zYIt-SXAfTg#t*NFj>>Nz;v{4o7&DOT-c&3tV?nP)x^DU}V`5)z%1o~6dv8D9XQfCJ z@bBQR2pH~yjJ^o4%BpLy-0N_tsj=^Bz`O&{{%G|Y^p}oDmz$gDNBbGYrklbB2E*_6h+4XO{?pD0q NEw((Lpz;Q&{RuUh!;k;~ literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..12855b2ec04aea0fa529522bb3c43363e3acecb2 GIT binary patch literal 2421 zcmdT^`8OMg8clU{OPBYkoDoz})rc_m>d>kdrFI&U5}hF_iD;+Mu|%2HB&BJ(kxUcY zgo-t2LliaXC=VfuG&GjjDwd#@pwf~z@67x#f53Y`y!*@doqNtb_k8EO=jv1T0RF@R zb0l`i4NN{Gc>*!IH1KBXZYKKOhbeonr+ix05<5N-=}W_Xs*aaSi0;biO!4`owEF+J zg|zt(?JPO(``{w3t+7y?v=aa*aW?QrQ`O9BhG$(SZBg04LPKwmP8JxCJS)i52bujhft{o@M|fb)g0hY@ea2&!s*+xT~$ zR2WMgZ-svFj+t(HKdC|LN#$H;U){HG3~P8q&ac!3ou)1W)B)A`OHv(seBbCubn7eo8N)) z-QP&E-Yj*Ll<__rTCCww^nd9)>M!T01A6v)6?zvzzL?Ciovr6N(9t^whc>4T006%O zuF1M<_XA|_z2s0Eb&Sdo<FtIE9CzC2=fYffMJPPIu<5yn(s zB&y8;j>2PDWHHSxU!7WMF!41vu}{r62Z<;jO}ID*dRwPl68D^0f$4PZN%hqY-;_;D z1gbTWM7ZfoIV75z5Kl$&609#LD<0;-nr0^&<-w~{LWK)2?UR{x`t2F=mZSarjNb1R zMEBpnP2%fybZmaWu6zgHk6*%WioRc~%TuI2wFutAS8eH6nV>K*A6{-s>?=@{a$w?E z9Vq@Of+u<_pHb9%6q{&mTnV{aoNwDZyBb=YvilmFa;W^Gw!;mjxV3d)b?Wm&dqciT z^7_CIKvo6eBx?Kp*=Q7sfbDBu%Nl$76-U+AVHRJKh=575KlnBzmJTQaL!dQl2GKCF ze_o~81#6}z>P<9fSuhx-6nI8=NWGvJ1-@tNkIHlCukAQRrvxIJdOcsT;%HJ%b1Dsf zX53E*Mo1SQ{cK^J*wvY96NYHCjI>p8B+rX%TD?juh=ovKpC5W*ai~#_&;3oRyL{#s zhbMh@y9;nVp}_5-=6mKv~Zh3rAVGuQGMAhY!EM>OKjtzOeW!uD_2 zQ6R1(z$c5hh+63GgjD8qI1wULWtu$D#Nplu1m+>@5qW&hZ}cPN@V(p1S+bLP$W8^1 z{>39V2Ce=PQexKX1q6NY>1+(woRltJZ1op4AcQHb zDPO5(#<_`MQ*rSxr8k&yq`AO^85#+m?S}S8Ly4e6me1VY9gJTWP#LD>4+7$F&N+;^=@Gt{A-s$A91k>$G{_=54;?<4zTj+-byfk42o93BvAz?A> zYGUFEMs0lep|D13wintOlTzLVlqe3!k)M%ilD@-m7_ZW&-o=H}-u2 z#`K=;NnCi0;fZ(KmxnJ0Sj+LM_pxmeg^UNIa|5tFoPmb0uc?`G%*)~o?U|}aYNska zG)=_K1UUB*BC2-_7Q2E>kH*wnWKvzA;LO|fnpH?-9LlPiqSYHYP&n0>5t}IkHIi54Xu>rachY8 z;NFdLjBU|lL?j3qn2j#O?|NK6?mj7yHMi>-XZw9_7Oo#Jj0^l#dmVm~M?~3+3H?st z28Z1Lra~GZVTY{-*&CtBpM3Q{qGkfwSu!cM&CV`68VL>MCe?aoljyxQj}Sr^4D044 zXv+~!XD0>j{ntrkGT99yQDcz)f0t%fBnS)!5AN)5H?smBIB-A+qIMZ_d;UO7@82jj Xz)x=q7G9U8sdj?AH8|wQYJh(OVP~YJ literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..077e4e70db5c441e349e4ec4145a524d1ae73b9e GIT binary patch literal 7039 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 literal 0 HcmV?d00001 From 484a44a0639b101e3962c3877dd7627f05cf6e57 Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Wed, 19 Mar 2014 07:04:46 -0400 Subject: [PATCH 043/187] Minor Change to LimboProvider Changed the condition on LimboProvider.canRespawnHere() so that players can respawn in Limbo even if LimboEnabled is false. LimboEnabled only controls whether players are sent to Limbo when they die in a pocket. It does not prevent players from ending up in Limbo because of Monoliths. If Hardcore Limbo is enabled, it stands to reason that people should be respawning in Limbo anyway. --- .../java/StevenDimDoors/mod_pocketDim/world/LimboProvider.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/world/LimboProvider.java b/src/main/java/StevenDimDoors/mod_pocketDim/world/LimboProvider.java index 76ae6cb..9e22053 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/world/LimboProvider.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/world/LimboProvider.java @@ -62,7 +62,7 @@ public class LimboProvider extends WorldProvider @Override public boolean canRespawnHere() { - return properties.HardcoreLimboEnabled && properties.LimboEnabled; + return properties.HardcoreLimboEnabled; } @Override From ac8874f96a446a0af9f553ccde289422f35c248b Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Wed, 19 Mar 2014 07:43:05 -0400 Subject: [PATCH 044/187] Fixed Crash with ChickenChunks Fixed a nasty crash to desktop. It happens when ChickenChunks is installed and a new world is generated with HardcoreLimboEnabled = true. It appears that ChickenChunks forces a chunk to generate in Limbo if LimboProvider.canRespawnHere() = true, which is the case if hardcore Limbo is enabled. Our Monolith and gateway generation code runs as a tick handler instead of through standard world gen calls. I believe Limbo is unloaded immediately after the chunks are generated because no players are around. That would cause DimensionManager to return null for Limbo because it's not loaded, which would crash our code. We probably dealt with this for Monoliths by adding a check. Now it happened again because we didn't take precautions while calling the gateway generation method. I've added code to forcefully load Limbo if it's not loaded. --- .../ticking/CustomLimboPopulator.java | 37 +++++++++++-------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/ticking/CustomLimboPopulator.java b/src/main/java/StevenDimDoors/mod_pocketDim/ticking/CustomLimboPopulator.java index 465e57b..2f4522a 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/ticking/CustomLimboPopulator.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/ticking/CustomLimboPopulator.java @@ -37,24 +37,36 @@ public class CustomLimboPopulator implements IRegularTickReceiver { @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.instance.gatewayGenerator.generate(limboWorld.rand, location.ChunkX, location.ChunkZ, + limboWorld, limboWorld.getChunkProvider(), limboWorld.getChunkProvider()); } else { @@ -145,15 +157,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); From 4fecf092a3bf30c077bb06727f5db98da313855b Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Wed, 19 Mar 2014 07:46:21 -0400 Subject: [PATCH 045/187] Changed Default Provider and Biome IDs XombyCraft has been kind enough to research which provider and biome IDs are used by major mods. He found some ranges of free IDs and suggested changing our defaults to sidestep conflicts with Biomes o' Plenty. --- .../StevenDimDoors/mod_pocketDim/config/DDProperties.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/config/DDProperties.java b/src/main/java/StevenDimDoors/mod_pocketDim/config/DDProperties.java index 3aaa69a..e41a467 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/config/DDProperties.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/config/DDProperties.java @@ -211,8 +211,8 @@ 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(); + PocketProviderID = config.get(CATEGORY_PROVIDER, "Pocket Provider ID", 124).getInt(); + LimboProviderID = config.get(CATEGORY_PROVIDER, "Limbo Provider ID", 113).getInt(); MonolithTeleportationEnabled = config.get(Configuration.CATEGORY_GENERAL, "Enable Monolith Teleportation", true, "Sets whether Monoliths can teleport players").getBoolean(true); @@ -237,8 +237,8 @@ public class DDProperties "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(); From 5c44ddefe9298ca8998bb753b34a4cec9f28eea2 Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Wed, 19 Mar 2014 11:53:33 -0400 Subject: [PATCH 046/187] Added Hidden Chests to Snow and Swamp Hubs Added hidden chests as is the tradition for biome-themed pockets. --- .../ruins/Hub_SK-RandomSnow_Open_75.schematic | Bin 2784 -> 2824 bytes .../Hub_SK-RandomSwamp_Open_75.schematic | Bin 2846 -> 2951 bytes 2 files changed, 0 insertions(+), 0 deletions(-) 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 18503e1650f8b766b229aa6f24f873d3e253a1d9..5a4a0cef22fb00fe9d9abdab788e446cbeab0356 100644 GIT binary patch literal 2824 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 literal 2784 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 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 5f3b18da3de552ed61cb57d9764080035eebb7fc..b3a086e0c80def1f1a197be52120464e8fbd6137 100644 GIT binary patch literal 2951 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 L0#_*7Un%_;@j5W! literal 2846 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 B2J`>` From 8ebaa0f4934d094b867258fe04e6820edba9ebb5 Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Wed, 19 Mar 2014 13:15:30 -0400 Subject: [PATCH 047/187] Completed Subtree Searches for Dungeon Packs Completed the implementation of searching through dungeon subtrees to avoid duplicates in "nearby" rooms --- .../dungeon/pack/DungeonPack.java | 19 +++--- .../mod_pocketDim/helpers/DungeonHelper.java | 59 +++++++++++++------ 2 files changed, 52 insertions(+), 26 deletions(-) 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 6c426d2..4a37e85 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/dungeon/pack/DungeonPack.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/dungeon/pack/DungeonPack.java @@ -138,17 +138,22 @@ public class DungeonPack int maxSearchLength = config.allowDuplicatesInChain() ? maxRuleLength : MAX_HISTORY_LENGTH; ArrayList history = DungeonHelper.getDungeonChainHistory(parent, this, maxSearchLength); - ArrayList subtreeHistory; - /*if (config.getDuplicateSearchLevels() > 0) + ArrayList subtreeHistory = null; + if (config.getDuplicateSearchLevels() > 0) { - subtreeHistory = DungeonHelper.getFlatDungeonTree( - DungeonHelper.getAncestor(parent, config.getDuplicateSearchLevels()), - MAX_SUBTREE_LIST_SIZE); + // 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); + } } - else + if (subtreeHistory == null) { subtreeHistory = new ArrayList(); - }*/ + } subtreeHistory = new ArrayList(); return getNextDungeon(history, subtreeHistory, random); diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/helpers/DungeonHelper.java b/src/main/java/StevenDimDoors/mod_pocketDim/helpers/DungeonHelper.java index a4cc980..2c9775e 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/helpers/DungeonHelper.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/helpers/DungeonHelper.java @@ -641,45 +641,66 @@ public class DungeonHelper } /** - * Performs a breadth-first listing of all dungeons rooted at a specified dimension. Only dungeons from the same pack as the root will be included. + * 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, int maxSize) + public static ArrayList listDungeonsInTree(NewDimData root, DungeonPack pack, int maxSize) { + 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; } - public static NewDimData getAncestor(NewDimData dimension, int levels) + /** + * 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. - // If such an ancestor does not exist, return the root dimension. - return null; + 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 From 7258ffa7dc1328ff2b093e47f65d99699c36cc6a Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Wed, 19 Mar 2014 23:08:25 -0400 Subject: [PATCH 048/187] Updated pistonFallRuins Updated the dungeon pistonFallRuins so that it causes less extreme lag by slowing down and spacing out the timing for the piston traps. Also reinforced the dungeon against tampering and added lava inside each piston drop. --- src/main/resources/schematics/ruins.txt | 2 +- .../trap_pistonFallRuins_open_100.schematic | Bin 3963 -> 0 bytes .../ruins/trap_pistonFallRuins_open_75.schematic | Bin 0 -> 4178 bytes 3 files changed, 1 insertion(+), 1 deletion(-) delete mode 100644 src/main/resources/schematics/ruins/trap_pistonFallRuins_open_100.schematic create mode 100644 src/main/resources/schematics/ruins/trap_pistonFallRuins_open_75.schematic diff --git a/src/main/resources/schematics/ruins.txt b/src/main/resources/schematics/ruins.txt index 5920286..7bd11e7 100644 --- a/src/main/resources/schematics/ruins.txt +++ b/src/main/resources/schematics/ruins.txt @@ -73,7 +73,7 @@ /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 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 ca2d664aa35f68cc300de3c90f7cbbd0b9ce0a22..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3963 zcmbVOc{mhY+gF|zFS3OYlbvjZF%OFDhEPgm&6<5lVZ=;jE5&58WUOI~r5R!Dh9YFk zGM3DQ$2OUmVeDfWpWdhI`>ywUzdyd~J=b-vbD#UV&wYO9cc0&N4&dc!mcJV{XCPUm zfhWNSf?wNN;p-C*odA9KDk7!FVr9w3y>p56t+RW;=ZVvm$MECF+gh&E_JmU!!C^L) z-#pBfUQDjizTGGPTmk4r?{Dt~<>@N+hr=QdsrbvShhD#T`}d)9 zVF)G5!ZOF>w??0X`1cj~snXGFi|7|SUp_BEQz-+Yd6GQ|&p#h1sn{K|TZl)2BAh#< z6v!T^)Uu+7Cg~Y>=V~VIGi)NwzDH+sA3K*K`<{}-b;D!^aqA^K0uhNS!yh!<;@n(% zYp*&U(#7)V?8RJRmLCgc(fN&t0UJe{*meP0M~QjW4_E)V{#EYfnjQDC61vfzn>gxr z^K&_X#Bg(B-m_NoEfdB!qX^i3-+{ygK!sAd3?H|U@P!R4OWJ_nA9Z_^GDKtYZD}9T zQZotB?nKS9RF;x>GBa{ME2>!^IWP;4egn_ouE;WZ04co?L~n#hWn{dAnBVDpXeNL6 za#t!Ziw!*+*d6gM?9t||(fGp;JG~jUwleCXA^SppT87OxMD%etc)$w=59?)m65xYO zIe?SlMi+aeF?FLc&vVzNDb-cJ+o#mb?Fd1lc05W7ee9Bjv&&T&<7Z6}f^JJ@xY;ga zDctl7IFYoPQg2}t1ryPMQbY>qJGTfNROA^R*ul?*>K_%+2I;S#bD5f}&N>@0R(YlX z3+*NmuvGYK?ygz8%+!m)pDP_F<`$``N zb;bEi*4y92C<%v)9~@KbIe+d^7oUS1GH+mTNNuVOQyZkU`(;ASsN58gVi_*uU>5xD z4FCNK|M?hAFI=0u;8#UL^@+(h8fLVNsdm!=-%nT@udPRiNDrbSav=6pP(tFEY;u^O zGOjr2@Xy7*9z7!w_dw&0^%oe#+-|Mgv;Wf=tOVJo3fR%yU8v(WOC9d|y6m;BJS0 zUP9ECGY5$piJuE!a}}h058^P%+gNqKl?VJ3laJs25j|v8c|Z9xY7JVpE^yUL0NSph zESa}@yxqoG0jP59p_JG(OTCmNO|@NaU*p|I`X>!j$e#))(8q!5F2;M_wQ}eEZeA34 zCM$nt_!!IE^WW-OSpL#`LKXX`jGkydm5us$LH)lx!8fse1l_|m>U!M(pjC(13iZV@ zx0s}^Ln!ocp&YU{m$8Z7wk3Dy>cALZaB&Rg)|`qiY|jH~hb#xcb}4Wd=K73_OA=$Z zmGdnZ`MLWz%JPMs@6*uPa2{U!#zA4?1&opWn&725UD+gw2`LWUdz~FuLm%AbMc%{#aWObP$M^X? zzQXp<4EOJ`hR77dE(%d=tWOb#;=rc8GR(YU?4V#D#W?A-n~#O>7XL(KM}*2SL1baOd^kI?63RYoRVppsbhMuw+5pU zd{vvit^TN*S+P@a$+0})zw=|XpxGj#-NllsXR=59vwGM7m^oPnii+XX%?%ug*RAZz zM$J@g0s1Bji0swHm7YytDqaS+zAp57!}nTo;T4a2Dv3n5^DN zNtkmTG5&m2-sy%&sBxf&|BhSwato3MFJAScp zE1wl8Sqf>_?G4|l)R^Fe*$-%%^BvS8D>nX;u*DhVtpZZRKC3b6iG#BHYzN6*JVG!O5qtGPq}4%b(#Y4FaS>i^&x9@a)6U?E zYOxW4ngNK_*7qfv`1P@L{sE=J{wGKRJLXQn$&qYl?=)YveDa2VxlPtFAX?BKMdUaN z9P}Oay4FvLyHl#c>T9Wjv#$}l5gPfLa6z3C&^|}*R059@v=Wx^owersPc_mW+?_g)YbV!^0yDUC;dho)@0VKCMAN z-v_B|gKW42Hr+Zhn6pSHjOkpB9Q3|zxQ2R8=iK87Y!tyqqQ%!{{12;6YEDh~JBm8b z^kMa{AzXH?ciFOMP9a@Dt4?ON5Zl_DKydWv*ahqCdn>o?`shUH+v)b7GC#e7X53?& zIZy{EiZ{b*c-bZzO*3@x2uFF0exWTw5oIXdZJnsl?e|_1D}|;fmmu~J+O&~;7@DCD zvH_!y4LhW59ropnIMTMd_KIjOcXjU_QvGdH1eU(748X%GQ_W!^)Un~t*c`{sa4vy5 zCq8wa?E&&Eo6BbkeEz*El%&HliAX3lenWS9OakiNnl&@#?f$to0~Dq>$3?{s5l^qc z#U>46w+K-mVpo|Cj9`jnK^`_s#&BtzcQ~)Eerm%k(Hx8^DoNciL!i#uA_x&Cj$lhZ z(JHq#)jjjld79eX_pdVz?_lj+VX!buD8*!W86Qmo7Ly9@?gxa1Gl~g@%?+)z=p#Cz z(`DNp0DpC!Af2t2O$&7Qjzg1f8|c4b@r0T4(ko1LvISK2_P{!emQa-=GVSyuev$cn z5xrE*Hndw4yYWK_3&JBjvKtuz9h2sE~}srO#`nUXp3uC;-?m*C8;PPhF^v21yMvCCORlnwHAUrFcE;Z%wk(%6WTWA5ZJ~dO`<>-)ot9;8yh>-v91_?xh!^392cNXIn{C6~C> z>Mbe#BI|s#w!`jY)JA;kG_7(bFZp($6@+3ka%X$Izv3-X##^;T6|~)CHHZ}#hF8#n z0>kRw`7L@YLh*hy+ZMLmS1US|)62O&j=w~c_1ES>4=AVjbK0xL1_{P$;gG4RRR&i@ zL+l4A0zSsh=K8lH{)Suqh!E?2V5YAMdHGZ6Cb%k$xk9&3^Z(FE zUL-+k%)B|SOy#AvY!K5|WA2+P3sBO<4vZeJ7vjD*G17fCuD{?s>vuwS=a7JKFS=~0UbCX zMz{6=XnczBT+&;IpF>x(M~ZP_UtuAI4bvfVO_rgdhw%qYk0MYMV>8Qs&Y{kzi}+5P z!EHg?{%MJw>`E+VqYmCpN|M>iTimmDGJlmmxthjqRClKI(c>$RUFVvOL|Sw}kJ@d2 zbWY9i%6cLf?sFp3?6-<~;#Dq!YGz()i`UGYvY33_HR|8wO5FDzil6S!ZHe0s*jekB ztDfnV4pzzpv1#n{4R22*y4(se377mLAyibV4SDA^2`D$};>ga5Iw_0h6oEq34S-b{ zQfuit@|y(%r*<_lf0j1R)P+ilKqFlFla#MTU8h`3=#z?EA6*w{1^Xe-UmRAX<6`~i z8szOycLf8{UcY5hO~HerREO)l*V0Mo1#;N)^sgeac*&>k^zb~Q&u)El z`V_l6=AL^02eflrNnx7bi*>Q+;b&b}w$C8OuYVFlL_8d~vR5Zocv_WtlJ0@^XYBNc;<+rJ?@?2GeAp@8nBevb2;1P-nwbpWjEU9t(3hF{@tm!J$}Zw~y?>)kD9x(923X>6=gf$J3LXM1S?) mSqHre|Id^xPuQ#@R1CCBPyVk@cx~rC0Fi0LH)e30<-Y(jsM1IP 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 0000000000000000000000000000000000000000..0ed8a39edfe1ba3b38e109c5a8562eed2d7e5874 GIT binary patch literal 4178 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 Date: Thu, 20 Mar 2014 05:31:02 -0400 Subject: [PATCH 049/187] Updated SK-FractalCage * Added a small treasure room that opens when the puzzle is solved and made the exits in the corners slightly more apparent by placing redstone lamps. * Tweaked the redstone a little to correct for a brief signal cutoff. * Tried to add fireworks that would shoot out when the puzzle was solved, but it was too hard to secure them against theft while also getting consistent explosions. --- .../Hub_SK-FractalCage_Open_40.schematic | Bin 9345 -> 10698 bytes 1 file changed, 0 insertions(+), 0 deletions(-) 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 5a0c61c472be8c29f84cdfa64290125ed17a07e8..db1ceaf0a1b71058248e55bb41fe66f71741a77c 100644 GIT binary patch literal 10698 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 SH^#T$XWrb1jDb>Gs{aK_?&-q- From bf2f5da67237e4accc5395ef07f57f54a0569079 Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Sat, 22 Mar 2014 08:00:21 -0400 Subject: [PATCH 050/187] More Dungeons * Added two exit dungeons: SK-HotSuspense and XombyCraft-RopeBridge * Removed a duplicate copy of Cere-FloatingAltar that slipped by --- src/main/resources/schematics/ruins.txt | 2 ++ .../DeadEnd_Floating-Altar_Open_100.schematic | Bin 1647 -> 0 bytes .../ruins/Exit_SK-HotSuspense_Open_75.schematic | Bin 0 -> 1777 bytes ...Exit_XombyCraft-RopeBridge_Open_100.schematic | Bin 0 -> 2137 bytes 4 files changed, 2 insertions(+) delete mode 100644 src/main/resources/schematics/ruins/DeadEnd_Floating-Altar_Open_100.schematic create mode 100644 src/main/resources/schematics/ruins/Exit_SK-HotSuspense_Open_75.schematic create mode 100644 src/main/resources/schematics/ruins/Exit_XombyCraft-RopeBridge_Open_100.schematic diff --git a/src/main/resources/schematics/ruins.txt b/src/main/resources/schematics/ruins.txt index 7bd11e7..5e43921 100644 --- a/src/main/resources/schematics/ruins.txt +++ b/src/main/resources/schematics/ruins.txt @@ -35,8 +35,10 @@ /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 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 fa5b3c02be7b1bef59ab37db1643d211990b08cf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1647 zcmV-#29Wt5iwFP!000000PUPjkJ?5U#|M_hkbP6DUVF%1*Q!+IfO<@`Nh@`$R%)f3 zb|qM>U}XVoq1vR^=H9Q8i%y!{v~%`_Bvj0001FE-o%oFUpZ^c5-@lezD?sJ9Ys8V87_r?EnA(tjTe? zWF_Ur##ZbC02)M(+m>;pZ23s8&Y7h3C1sr;bG1cjpEumg&3`hx`Os>o0=0ejgafM% zP(ti=!X;OSG7l-3%^V&rSz)kVCp35~BQ6<*qFq`x+*8)cO^t|S9g?;VJ|yg}*LSn} z9=h03kt&HojHHre?Q*ZlYBCiAb_^@Tf6s=XS%V~4lBI0f^q!X{*K{$OUlh6GAILQ~Qv_X}`?b}tT;1RdofZa!_ zR+E{0bQr!h`fz|Ly6K$O?Z9Dzk28KVI9@>-qe##m*+f#ZT63W{rOz+K=proy;F?YqlIN?fJ|oUm^V)_*x3|M)P!f4^Yt`~Pa{QXO%gLb9b%;gcaPO(@XH z?E;X-k;aa}efpFw&B)|hxm^I#4eY)p{Qgg`PJiIh1AIIvx$(dWpcPg;s32)2tn%ON9z?UIwu#zLtP8J1`b%=$WQL?O-q000000001N5l8k6u_L|M zl|OVREp?<%CsRr(XUp+dUN=w+@;Eb?d{ITR(3iZGml~<}^-3vcllz-fw|$PuHtYUu z+3zMx_D!1|zqQB92{R4WjlcPE|G91tftI*g2+~5ape;C7fSB?&dt1p43|3EjXzFa{CQT%Pq52-Q8Y`&=eu*|MEfbe(uM$R)){V4+cvbU6dJ~HyZIX%vttSn| zv38aGD0V6SlG&ea?%$BsG2Oi@)&N=b?C|4U!+hZe?{7p|mfh-vU2W=6g!t+j5hTA{MUa5Ba zDcLJG{Ha`$){ZjgFR<_1%}D+J$XTnC*>wlmow$IMbat1QxpHD{}ayTa;2k`*zb>mshnWfEif#w`Rxx<`Z z-nps9$&3ySqk|6$>}`s!0_t__&M3I=`U5Xz1<8+Kw+ggvUllM?4vjrY(al24NVz#G zzIU6J=8J^_LY~~h#BZ;`NCAz3@~E4e*=($Jxt#*7JK&zlD{`2Bz%OULPkwB}a~}YE z4I!VogS+566Dm`qH~}eYQ=4KpW9?nO*1N`yA=q`JV=?Um0Pxf}@1tn>?_yAL6!IAW z0000000000000000000$Pt<>oj&f(0^0xL6rQZN(4wMmOnx^8= t41Ng7Q>#d$9R)E#>#m;iFBMm%t*UOM_9gWjL!PXM{{biFAL-8e001=BEK&df 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 0000000000000000000000000000000000000000..b658c79f1e1d744615f817049f76aabfe952ef21 GIT binary patch literal 1777 zcmb2|=3sz;w|5WvNr#IxJWS@{Nx9@Y+xNbL^nMqvz}+5Ky;fe?%DLEpYol(#)FtaL zJa^pV^R2Sis^MeBy0_Ikigy-E{I8D=Jdu9?V?oW7ORn=yKD=F?e)RamEj80mzWZ2U zCGxXO*98e|yOsHysiPw!*ShwaiQvVuk^}qHm2S1&_y$oEt8u<~?xh_wFB*Pb$>r+e zvTDof^7ySM%TxWgelQlZ6TB$A{`xmo0l|y2l>YPmZ@B+ZSWt59{r9h@9Q*p)R#x~e zM3a(!%~iEF#UX5)^~@pQ^7w!{(BwYce?-h$LRy|4Z)GKel-B=0wY?;6A%E`+n8fXu8$M z$jt56@4kF9_{+b)bJudFc8jOMIjJL#3*P<&Tcub$yZ>LkMHYX*Y+O0>@7|I;-&|%Goz`b$ zt2TIj=}`Qi+qS3Qt*`ypy?wn!bkfx8700K=Z4Z%)NS(POr!w@)j5P_9ErqA2T7~_N z`g`HzoK(H&nzf(2(zic<_Wr2%ioI*1&3>v(ewsbozU<}AXWuthRZoBQ>(Kd_Z57UU zH|G>ybLKyLB(*y`Ug}fm`_@qBxS!Y7SLo~9mpfXW_-Io*-%qV=Stq8;N6o)i{cYtc zvwh;P+RyEqU+x@NseeZ9^*-@;a{K?Bjk@x+RX;NIME3K08-8^f+%V#n{S+o%XSOo$ zQ`kG{H<_CsD8?Uj3GZpu*QvQ7ruRo@^#)||H~)WasHwi4B7FGzH9PM4=F>I1t5>|e z&24;2>dfrJF5=wwyvYyqlOBG4W|UgUzqJ;qbY@><9cTY>sJuLOZFCd9t#+CxKKk{V zgL^D}N;ZB-e7pHWW%0~SJKAsU+iS3xM#6^@bd8_hiLT=`xN%sLTYg(_Pb>dzFE^L% zZ%_Qocm4SEb%Oj#S!f7Wa_`{rK#t-sDj)o1eU z-Wo1F*V#6=Mqes8es>jsbKY8e zZbpOnb|Fl8dG}^BI*+lkKO}GDwQt#Iqi7(p#`ughx4oG4&Y#(;n-KzxAa?bde=C<}H_uE1 zYUZ5rl(W$^eK*jn*Uz&xFFxpSu&>VUlEK~0n(KXkdL`TrwU zUv7QadeFx>U*`|YnNKYTW&w+~GaR3f9r8b*m#18`ro^7f?j{>>ThoD@YG}k-Jm6aBKIr+c0 LV)=|$u1pL77vx*Y literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..d42788997736c26751cd01860494ede305edbab0 GIT binary patch literal 2137 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 literal 0 HcmV?d00001 From da579bc23d37afa36c301de014511229e7f94dc8 Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Sun, 23 Mar 2014 11:38:28 -0400 Subject: [PATCH 051/187] Stopped Filling Empty Dispensers Changed FillContainersOperation so that empty dispensers are not filled with a stack of arrows on import. Just in case someone needs to use empty dispensers in their design. As far as I can remember, this won't affect any of our dungeons - arrow traps are rare. The only dungeon that I can remember is one by Balgor and it was exported with all of its dispensers loaded. --- .../mod_pocketDim/dungeon/FillContainersOperation.java | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/dungeon/FillContainersOperation.java b/src/main/java/StevenDimDoors/mod_pocketDim/dungeon/FillContainersOperation.java index f124225..e44a58b 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/dungeon/FillContainersOperation.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/dungeon/FillContainersOperation.java @@ -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; } From e5adb43f77de6b13bbab40f5a1a7f0f6438bfc96 Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Sun, 23 Mar 2014 11:39:03 -0400 Subject: [PATCH 052/187] Updated How to Add Dungeons Updated our dungeon creation guide. It was badly outdated by now. --- .../dimdoors/text/How_to_add_dungeons.txt | 67 ++++++++++++------- 1 file changed, 43 insertions(+), 24 deletions(-) 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. From d6b07db3d6213bf9b6f7139c4cc42389230854cf Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Sun, 23 Mar 2014 17:18:47 -0400 Subject: [PATCH 053/187] Fixed Conflict with Witchery Mod * Changed DDTeleporter to stop us from generating exits to Witchery's Spirit World - this would cause people to lose their items upon leaving the dimension. * Changed GatewayGenerator to stop us from generating gateways or rift clusters in the Spirit World --- .../mod_pocketDim/core/DDTeleporter.java | 18 +++++++++++++++--- .../world/gateways/GatewayGenerator.java | 7 +++++-- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/core/DDTeleporter.java b/src/main/java/StevenDimDoors/mod_pocketDim/core/DDTeleporter.java index 7c7bb6c..0c95b06 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/core/DDTeleporter.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/core/DDTeleporter.java @@ -46,6 +46,7 @@ public class DDTeleporter 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; @@ -644,9 +645,7 @@ public class DDTeleporter 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); } @@ -657,6 +656,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 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 d2d9c0f..dfd855a 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/world/gateways/GatewayGenerator.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/world/gateways/GatewayGenerator.java @@ -32,6 +32,7 @@ public class GatewayGenerator implements IWorldGenerator 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; @@ -58,12 +59,14 @@ public class GatewayGenerator implements IWorldGenerator public void generate(Random random, int chunkX, int chunkZ, World world, IChunkProvider chunkGenerator, IChunkProvider chunkProvider) { // 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 or The End. + // 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)) + || (dimensionID == NETHER_DIMENSION_ID) + || (world.provider.getDimensionName().hashCode() == SPIRIT_WORLD_NAME.hashCode())) { return; } From 42f0656b1befcfe0d19fecfd4c874778dbbd2546 Mon Sep 17 00:00:00 2001 From: StevenRS11 Date: Mon, 24 Mar 2014 20:58:36 -0400 Subject: [PATCH 054/187] Changes Made saving a bit more robust, now we only delete ones that where not modified. Also overhauled door placement, its all handled by the eventHandler now. --- .../mod_pocketDim/EventHookContainer.java | 359 +++++++++--------- .../mod_pocketDim/items/BaseItemDoor.java | 163 +++++++- .../items/ItemDimensionalDoor.java | 20 +- .../mod_pocketDim/items/ItemGoldDimDoor.java | 24 +- .../mod_pocketDim/items/ItemUnstableDoor.java | 20 +- .../mod_pocketDim/items/ItemWarpDoor.java | 20 +- .../mod_pocketDim/saving/DDSaveHandler.java | 50 ++- 7 files changed, 362 insertions(+), 294 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java b/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java index f52fa18..67519a1 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java @@ -19,6 +19,7 @@ import net.minecraftforge.event.entity.living.LivingFallEvent; import net.minecraftforge.event.entity.player.PlayerInteractEvent; import net.minecraftforge.event.terraingen.InitMapGenEvent; import net.minecraftforge.event.world.WorldEvent; +import StevenDimDoors.mod_pocketDim.blocks.BaseDimDoor; import StevenDimDoors.mod_pocketDim.config.DDProperties; import StevenDimDoors.mod_pocketDim.core.DDTeleporter; import StevenDimDoors.mod_pocketDim.core.PocketManager; @@ -32,218 +33,202 @@ import cpw.mods.fml.relauncher.SideOnly; public class EventHookContainer { - private final DDProperties properties; - + private final DDProperties properties; + public EventHookContainer(DDProperties properties) { this.properties = properties; } - + @ForgeSubscribe(priority = EventPriority.LOW) public void onInitMapGen(InitMapGenEvent event) { - // Replace the Nether fortress generator with our own only if any gateways would ever generate. - // This allows admins to disable our fortress overriding without disabling all gateways. + // Replace the Nether fortress generator with our own only if any + // gateways would ever generate. + // This allows admins to disable our fortress overriding without + // disabling all gateways. /* - if (properties.FortressGatewayGenerationChance > 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 + ":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 placing Vanilla doors on rifts - if (!event.entity.worldObj.isRemote) + // Handle all door placement here + + World world = event.entity.worldObj; + ItemStack stack = event.entityPlayer.inventory.getCurrentItem(); + if (stack != null) { - World world = event.entity.worldObj; - ItemStack stack = event.entityPlayer.inventory.getCurrentItem(); - if (stack != null) + if (stack.getItem() instanceof ItemDoor) { - Item item = stack.getItem(); - if (item instanceof ItemDoor) + if(mod_pocketDim.itemDimensionalDoor.tryToPlaceDoor(stack, event.entityPlayer, world, event.x, event.y, event.z, event.face)) { - Block doorToPlace = null; - if (stack.itemID == Item.doorIron.itemID) - { - doorToPlace = mod_pocketDim.dimensionalDoor; - } - else if (stack.itemID == Item.doorWood.itemID) - { - doorToPlace = mod_pocketDim.warpDoor; - } - else if (stack.itemID == mod_pocketDim.itemGoldenDoor.itemID) - { - doorToPlace = mod_pocketDim.goldenDimensionalDoor; - } - - if (doorToPlace != null) - { - // SenseiKiwi: Why do we have a condition like this? And the event isn't cancelled if we take the else portion. - // Comments would have been very helpful. - if (mod_pocketDim.itemDimensionalDoor.tryPlacingDoor(doorToPlace, world, event.entityPlayer, stack)) - { - if (!event.entityPlayer.capabilities.isCreativeMode) - { - stack.stackSize--; - } - event.setCanceled(true); - } - else - { - BaseItemDoor.tryItemUse(doorToPlace, stack, event.entityPlayer, world, event.x, event.y, event.z, event.face, true, true); - } - } + //cancel the event so we dont 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 (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(); + @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()); 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(); - - 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; + @ForgeSubscribe + public void onWorldSave(WorldEvent.Save event) + { + if (event.world.provider.dimensionId == 0) + { + PocketManager.save(); - // 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) - { - sndManager.sndSystem.backgroundMusic("LimboMusic", soundPoolEntry.getSoundUrl(), soundPoolEntry.getSoundName(), false); - sndManager.sndSystem.play("LimboMusic"); - } - } - else if (!(world.provider instanceof LimboProvider)) - { - sndManager.sndSystem.stop("LimboMusic"); - } - } - } - } + 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; + + // 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) + { + 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/items/BaseItemDoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/items/BaseItemDoor.java index e97ad6a..d29f322 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/items/BaseItemDoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/items/BaseItemDoor.java @@ -1,25 +1,31 @@ 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.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 + private static HashMap vanillaDoorMapping = new HashMap(); private static DDProperties properties = null; public BaseItemDoor(int itemID, Material material) @@ -29,6 +35,10 @@ public abstract class BaseItemDoor extends ItemDoor this.setCreativeTab(mod_pocketDim.dimDoorsCreativeTab); if (properties == null) properties = DDProperties.instance(); + + vanillaDoorMapping.put((ItemDoor) mod_pocketDim.itemGoldenDoor, (BaseItemDoor) mod_pocketDim.itemGoldenDimensionalDoor); + vanillaDoorMapping.put((ItemDoor) Item.doorIron, (BaseItemDoor) mod_pocketDim.itemDimensionalDoor); + vanillaDoorMapping.put((ItemDoor) Item.doorWood, (BaseItemDoor) mod_pocketDim.itemWarpDoor); } @Override @@ -41,12 +51,86 @@ 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 getDoortoItemMapping(); + + /** + * 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 + // TODO Auto-generated method stub + return false; + } + + public static BaseDimDoor getDoorToPlace(Item item) + { + if (!(item instanceof BaseItemDoor)) + { + item = BaseItemDoor.vanillaDoorMapping.get(item); + } + return ((BaseItemDoor) item).getDoortoItemMapping(); + } + + /** + * Tries to place a door block, called in EventHookContainer + * + * @param doorBlock + * @param stack + * @param player + * @param world + * @param x + * @param y + * @param z + * @param side + * @param requireLink + * @param reduceStack + * @return + */ + public static boolean tryToPlaceDoor(ItemStack stack, EntityPlayer player, World world, int x, int y, int z, int side) + { + if (world.isRemote) + { + return false; + } + if (!(stack.getItem() instanceof ItemDoor)) + { + throw new IllegalArgumentException("The itemstack must correspond to some type of door"); + } + if (BaseItemDoor.placeDoorOnBlock(getDoorToPlace(stack.getItem()), stack, player, world, x, y, z, side)) + { + return true; + } + return BaseItemDoor.placeDoorOnRift(getDoorToPlace(stack.getItem()), 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 +142,13 @@ 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) { 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 +158,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 +186,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 +215,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/ItemDimensionalDoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemDimensionalDoor.java index 6804e28..a85f5e4 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemDimensionalDoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemDimensionalDoor.java @@ -7,6 +7,7 @@ import net.minecraft.entity.player.EntityPlayer; 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 { @@ -26,23 +27,8 @@ public class ItemDimensionalDoor extends BaseItemDoor } @Override - public ItemStack onItemRightClick(ItemStack stack, World world, EntityPlayer player) + protected BaseDimDoor getDoortoItemMapping() { - 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..fceb2f3 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemGoldDimDoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemGoldDimDoor.java @@ -7,6 +7,7 @@ import net.minecraft.entity.player.EntityPlayer; 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 { @@ -16,7 +17,6 @@ public class ItemGoldDimDoor extends BaseItemDoor // TODO Auto-generated constructor stub } - @SuppressWarnings({ "rawtypes", "unchecked" }) @Override public void addInformation(ItemStack par1ItemStack, EntityPlayer par2EntityPlayer, List par3List, boolean par4) @@ -27,26 +27,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 getDoortoItemMapping() { - 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/ItemUnstableDoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemUnstableDoor.java index a7d63ec..809fc86 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemUnstableDoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemUnstableDoor.java @@ -7,6 +7,7 @@ import net.minecraft.entity.player.EntityPlayer; 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 { @@ -23,23 +24,8 @@ public class ItemUnstableDoor extends BaseItemDoor } @Override - public ItemStack onItemRightClick(ItemStack stack, World world, EntityPlayer player) + protected BaseDimDoor getDoortoItemMapping() { - 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..ac3f66a 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemWarpDoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemWarpDoor.java @@ -7,6 +7,7 @@ import net.minecraft.entity.player.EntityPlayer; 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 { @@ -26,23 +27,8 @@ public class ItemWarpDoor extends BaseItemDoor } @Override - public ItemStack onItemRightClick(ItemStack stack, World world, EntityPlayer player) + protected BaseDimDoor getDoortoItemMapping() { - 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/saving/DDSaveHandler.java b/src/main/java/StevenDimDoors/mod_pocketDim/saving/DDSaveHandler.java index fb39f5b..8cef1fd 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/saving/DDSaveHandler.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/saving/DDSaveHandler.java @@ -7,6 +7,7 @@ import java.io.IOException; import java.util.ArrayList; import java.util.Deque; import java.util.HashMap; +import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; import java.util.List; @@ -243,43 +244,58 @@ public class DDSaveHandler // 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. + + //I still dont think that this is the best way to do this, but atleast it is better than + //risking deleting everything. I delete files afterwards that I did not modify. - String basePath = DimensionManager.getCurrentSaveRootDirectory() + "/DimensionalDoors/data/"; - File basePathFile = new File(basePath); - Files.createParentDirs(basePathFile); - basePathFile.mkdir(); - + //get the save directory path + File saveDirectory = new File(DimensionManager.getCurrentSaveRootDirectory() + "/DimensionalDoors/data/"); + + //create the save directory + Files.createParentDirs(saveDirectory); + saveDirectory.mkdir(); + + //create and write the blackList BlacklistProcessor blacklistReader = new BlacklistProcessor(); - writeBlacklist(blacklist, blacklistReader,basePath); + writeBlacklist(blacklist, blacklistReader,saveDirectory); FileFilter dataFileFilter = new FileFilters.RegexFileFilter("dim_-?\\d+\\.txt"); - //TODO Deal with temp files correctly - File[] dataFiles = basePathFile.listFiles(dataFileFilter); + //Take the list of all dimData files already saved in the save Directory, and map them according to ID. + File[] dataFiles = saveDirectory.listFiles(dataFileFilter); + HashMap unsavedDimData = new HashMap(); for (File dataFile : dataFiles) { - dataFile.delete(); + unsavedDimData.put(Integer.parseInt(dataFile.getName().split("[.]")[0].substring(4)), dataFile); } - - basePathFile = null; - basePath += "dim_"; - boolean succeeded = true; + + //write the dimension save data, and remove the ones we save from the mapping DimDataProcessor writer = new DimDataProcessor(); for (IPackable dimension : dimensions) { - succeeded &= writeDimension(dimension, writer, basePath); + succeeded &= writeDimension(dimension, writer, saveDirectory.getAbsolutePath()+"/dim_"); + unsavedDimData.remove(Integer.parseInt(dimension.name())); + } + + //once we have finished saving, delete the files from the save directory that where not saved + if(succeeded) + { + for (File dataFile : unsavedDimData.values()) + { + dataFile.delete(); + } } return succeeded; } - private static boolean writeBlacklist(List blacklist, BlacklistProcessor writer, String basePath) + private static boolean writeBlacklist(List blacklist, BlacklistProcessor writer, File saveDirectory) { try { - File tempFile = new File(basePath + "blacklist.tmp"); - File saveFile = new File(basePath + "blacklist.txt"); + File tempFile = new File(saveDirectory.getAbsolutePath() + "blacklist.tmp"); + File saveFile = new File(saveDirectory.getAbsolutePath() + "blacklist.txt"); writer.writeToFile(tempFile, blacklist); saveFile.delete(); tempFile.renameTo(saveFile); From 76e9fce9d4d2fd1aba09c822a6215ec3f3888902 Mon Sep 17 00:00:00 2001 From: StevenRS11 Date: Mon, 24 Mar 2014 21:09:21 -0400 Subject: [PATCH 055/187] Fixed all doors being placed as dim doors --- .../java/StevenDimDoors/mod_pocketDim/items/BaseItemDoor.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/items/BaseItemDoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/items/BaseItemDoor.java index d29f322..5f7ca97 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/items/BaseItemDoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/items/BaseItemDoor.java @@ -143,7 +143,8 @@ 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) && stack.stackSize > 0) + && (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); From 9914666639e930c606efe08d71c5a09d4870903b Mon Sep 17 00:00:00 2001 From: StevenRS11 Date: Mon, 24 Mar 2014 20:58:36 -0400 Subject: [PATCH 056/187] Changes Made saving a bit more robust, now we only delete ones that where not modified. Also overhauled door placement, its all handled by the eventHandler now. --- .../mod_pocketDim/EventHookContainer.java | 359 +++++++++--------- .../mod_pocketDim/items/BaseItemDoor.java | 163 +++++++- .../items/ItemDimensionalDoor.java | 20 +- .../mod_pocketDim/items/ItemGoldDimDoor.java | 24 +- .../mod_pocketDim/items/ItemUnstableDoor.java | 20 +- .../mod_pocketDim/items/ItemWarpDoor.java | 20 +- .../mod_pocketDim/saving/DDSaveHandler.java | 50 ++- 7 files changed, 362 insertions(+), 294 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java b/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java index f52fa18..67519a1 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java @@ -19,6 +19,7 @@ import net.minecraftforge.event.entity.living.LivingFallEvent; import net.minecraftforge.event.entity.player.PlayerInteractEvent; import net.minecraftforge.event.terraingen.InitMapGenEvent; import net.minecraftforge.event.world.WorldEvent; +import StevenDimDoors.mod_pocketDim.blocks.BaseDimDoor; import StevenDimDoors.mod_pocketDim.config.DDProperties; import StevenDimDoors.mod_pocketDim.core.DDTeleporter; import StevenDimDoors.mod_pocketDim.core.PocketManager; @@ -32,218 +33,202 @@ import cpw.mods.fml.relauncher.SideOnly; public class EventHookContainer { - private final DDProperties properties; - + private final DDProperties properties; + public EventHookContainer(DDProperties properties) { this.properties = properties; } - + @ForgeSubscribe(priority = EventPriority.LOW) public void onInitMapGen(InitMapGenEvent event) { - // Replace the Nether fortress generator with our own only if any gateways would ever generate. - // This allows admins to disable our fortress overriding without disabling all gateways. + // Replace the Nether fortress generator with our own only if any + // gateways would ever generate. + // This allows admins to disable our fortress overriding without + // disabling all gateways. /* - if (properties.FortressGatewayGenerationChance > 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 + ":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 placing Vanilla doors on rifts - if (!event.entity.worldObj.isRemote) + // Handle all door placement here + + World world = event.entity.worldObj; + ItemStack stack = event.entityPlayer.inventory.getCurrentItem(); + if (stack != null) { - World world = event.entity.worldObj; - ItemStack stack = event.entityPlayer.inventory.getCurrentItem(); - if (stack != null) + if (stack.getItem() instanceof ItemDoor) { - Item item = stack.getItem(); - if (item instanceof ItemDoor) + if(mod_pocketDim.itemDimensionalDoor.tryToPlaceDoor(stack, event.entityPlayer, world, event.x, event.y, event.z, event.face)) { - Block doorToPlace = null; - if (stack.itemID == Item.doorIron.itemID) - { - doorToPlace = mod_pocketDim.dimensionalDoor; - } - else if (stack.itemID == Item.doorWood.itemID) - { - doorToPlace = mod_pocketDim.warpDoor; - } - else if (stack.itemID == mod_pocketDim.itemGoldenDoor.itemID) - { - doorToPlace = mod_pocketDim.goldenDimensionalDoor; - } - - if (doorToPlace != null) - { - // SenseiKiwi: Why do we have a condition like this? And the event isn't cancelled if we take the else portion. - // Comments would have been very helpful. - if (mod_pocketDim.itemDimensionalDoor.tryPlacingDoor(doorToPlace, world, event.entityPlayer, stack)) - { - if (!event.entityPlayer.capabilities.isCreativeMode) - { - stack.stackSize--; - } - event.setCanceled(true); - } - else - { - BaseItemDoor.tryItemUse(doorToPlace, stack, event.entityPlayer, world, event.x, event.y, event.z, event.face, true, true); - } - } + //cancel the event so we dont 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 (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(); + @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()); 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(); - - 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; + @ForgeSubscribe + public void onWorldSave(WorldEvent.Save event) + { + if (event.world.provider.dimensionId == 0) + { + PocketManager.save(); - // 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) - { - sndManager.sndSystem.backgroundMusic("LimboMusic", soundPoolEntry.getSoundUrl(), soundPoolEntry.getSoundName(), false); - sndManager.sndSystem.play("LimboMusic"); - } - } - else if (!(world.provider instanceof LimboProvider)) - { - sndManager.sndSystem.stop("LimboMusic"); - } - } - } - } + 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; + + // 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) + { + 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/items/BaseItemDoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/items/BaseItemDoor.java index e97ad6a..d29f322 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/items/BaseItemDoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/items/BaseItemDoor.java @@ -1,25 +1,31 @@ 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.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 + private static HashMap vanillaDoorMapping = new HashMap(); private static DDProperties properties = null; public BaseItemDoor(int itemID, Material material) @@ -29,6 +35,10 @@ public abstract class BaseItemDoor extends ItemDoor this.setCreativeTab(mod_pocketDim.dimDoorsCreativeTab); if (properties == null) properties = DDProperties.instance(); + + vanillaDoorMapping.put((ItemDoor) mod_pocketDim.itemGoldenDoor, (BaseItemDoor) mod_pocketDim.itemGoldenDimensionalDoor); + vanillaDoorMapping.put((ItemDoor) Item.doorIron, (BaseItemDoor) mod_pocketDim.itemDimensionalDoor); + vanillaDoorMapping.put((ItemDoor) Item.doorWood, (BaseItemDoor) mod_pocketDim.itemWarpDoor); } @Override @@ -41,12 +51,86 @@ 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 getDoortoItemMapping(); + + /** + * 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 + // TODO Auto-generated method stub + return false; + } + + public static BaseDimDoor getDoorToPlace(Item item) + { + if (!(item instanceof BaseItemDoor)) + { + item = BaseItemDoor.vanillaDoorMapping.get(item); + } + return ((BaseItemDoor) item).getDoortoItemMapping(); + } + + /** + * Tries to place a door block, called in EventHookContainer + * + * @param doorBlock + * @param stack + * @param player + * @param world + * @param x + * @param y + * @param z + * @param side + * @param requireLink + * @param reduceStack + * @return + */ + public static boolean tryToPlaceDoor(ItemStack stack, EntityPlayer player, World world, int x, int y, int z, int side) + { + if (world.isRemote) + { + return false; + } + if (!(stack.getItem() instanceof ItemDoor)) + { + throw new IllegalArgumentException("The itemstack must correspond to some type of door"); + } + if (BaseItemDoor.placeDoorOnBlock(getDoorToPlace(stack.getItem()), stack, player, world, x, y, z, side)) + { + return true; + } + return BaseItemDoor.placeDoorOnRift(getDoorToPlace(stack.getItem()), 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 +142,13 @@ 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) { 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 +158,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 +186,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 +215,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/ItemDimensionalDoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemDimensionalDoor.java index 6804e28..a85f5e4 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemDimensionalDoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemDimensionalDoor.java @@ -7,6 +7,7 @@ import net.minecraft.entity.player.EntityPlayer; 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 { @@ -26,23 +27,8 @@ public class ItemDimensionalDoor extends BaseItemDoor } @Override - public ItemStack onItemRightClick(ItemStack stack, World world, EntityPlayer player) + protected BaseDimDoor getDoortoItemMapping() { - 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..fceb2f3 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemGoldDimDoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemGoldDimDoor.java @@ -7,6 +7,7 @@ import net.minecraft.entity.player.EntityPlayer; 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 { @@ -16,7 +17,6 @@ public class ItemGoldDimDoor extends BaseItemDoor // TODO Auto-generated constructor stub } - @SuppressWarnings({ "rawtypes", "unchecked" }) @Override public void addInformation(ItemStack par1ItemStack, EntityPlayer par2EntityPlayer, List par3List, boolean par4) @@ -27,26 +27,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 getDoortoItemMapping() { - 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/ItemUnstableDoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemUnstableDoor.java index a7d63ec..809fc86 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemUnstableDoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemUnstableDoor.java @@ -7,6 +7,7 @@ import net.minecraft.entity.player.EntityPlayer; 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 { @@ -23,23 +24,8 @@ public class ItemUnstableDoor extends BaseItemDoor } @Override - public ItemStack onItemRightClick(ItemStack stack, World world, EntityPlayer player) + protected BaseDimDoor getDoortoItemMapping() { - 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..ac3f66a 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemWarpDoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemWarpDoor.java @@ -7,6 +7,7 @@ import net.minecraft.entity.player.EntityPlayer; 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 { @@ -26,23 +27,8 @@ public class ItemWarpDoor extends BaseItemDoor } @Override - public ItemStack onItemRightClick(ItemStack stack, World world, EntityPlayer player) + protected BaseDimDoor getDoortoItemMapping() { - 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/saving/DDSaveHandler.java b/src/main/java/StevenDimDoors/mod_pocketDim/saving/DDSaveHandler.java index fb39f5b..8cef1fd 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/saving/DDSaveHandler.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/saving/DDSaveHandler.java @@ -7,6 +7,7 @@ import java.io.IOException; import java.util.ArrayList; import java.util.Deque; import java.util.HashMap; +import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; import java.util.List; @@ -243,43 +244,58 @@ public class DDSaveHandler // 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. + + //I still dont think that this is the best way to do this, but atleast it is better than + //risking deleting everything. I delete files afterwards that I did not modify. - String basePath = DimensionManager.getCurrentSaveRootDirectory() + "/DimensionalDoors/data/"; - File basePathFile = new File(basePath); - Files.createParentDirs(basePathFile); - basePathFile.mkdir(); - + //get the save directory path + File saveDirectory = new File(DimensionManager.getCurrentSaveRootDirectory() + "/DimensionalDoors/data/"); + + //create the save directory + Files.createParentDirs(saveDirectory); + saveDirectory.mkdir(); + + //create and write the blackList BlacklistProcessor blacklistReader = new BlacklistProcessor(); - writeBlacklist(blacklist, blacklistReader,basePath); + writeBlacklist(blacklist, blacklistReader,saveDirectory); FileFilter dataFileFilter = new FileFilters.RegexFileFilter("dim_-?\\d+\\.txt"); - //TODO Deal with temp files correctly - File[] dataFiles = basePathFile.listFiles(dataFileFilter); + //Take the list of all dimData files already saved in the save Directory, and map them according to ID. + File[] dataFiles = saveDirectory.listFiles(dataFileFilter); + HashMap unsavedDimData = new HashMap(); for (File dataFile : dataFiles) { - dataFile.delete(); + unsavedDimData.put(Integer.parseInt(dataFile.getName().split("[.]")[0].substring(4)), dataFile); } - - basePathFile = null; - basePath += "dim_"; - boolean succeeded = true; + + //write the dimension save data, and remove the ones we save from the mapping DimDataProcessor writer = new DimDataProcessor(); for (IPackable dimension : dimensions) { - succeeded &= writeDimension(dimension, writer, basePath); + succeeded &= writeDimension(dimension, writer, saveDirectory.getAbsolutePath()+"/dim_"); + unsavedDimData.remove(Integer.parseInt(dimension.name())); + } + + //once we have finished saving, delete the files from the save directory that where not saved + if(succeeded) + { + for (File dataFile : unsavedDimData.values()) + { + dataFile.delete(); + } } return succeeded; } - private static boolean writeBlacklist(List blacklist, BlacklistProcessor writer, String basePath) + private static boolean writeBlacklist(List blacklist, BlacklistProcessor writer, File saveDirectory) { try { - File tempFile = new File(basePath + "blacklist.tmp"); - File saveFile = new File(basePath + "blacklist.txt"); + File tempFile = new File(saveDirectory.getAbsolutePath() + "blacklist.tmp"); + File saveFile = new File(saveDirectory.getAbsolutePath() + "blacklist.txt"); writer.writeToFile(tempFile, blacklist); saveFile.delete(); tempFile.renameTo(saveFile); From 3a292d7eac89fa9c1403b06fe22ef09d8000be5e Mon Sep 17 00:00:00 2001 From: StevenRS11 Date: Mon, 24 Mar 2014 21:09:21 -0400 Subject: [PATCH 057/187] Fixed all doors being placed as dim doors --- .../java/StevenDimDoors/mod_pocketDim/items/BaseItemDoor.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/items/BaseItemDoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/items/BaseItemDoor.java index d29f322..5f7ca97 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/items/BaseItemDoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/items/BaseItemDoor.java @@ -143,7 +143,8 @@ 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) && stack.stackSize > 0) + && (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); From f682ba6a2b1ca1ed25e232fe92276d8ec16fc9a4 Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Wed, 26 Mar 2014 02:12:53 -0400 Subject: [PATCH 058/187] Fixes for Saving Process * Switched to deleting dimension data when a dimension is removed instead of trying to figure out which dimensions were removed later * Fixed a bug with blacklist paths * Rearranged saving code slightly to avoid the potential performance impact of repeated calls to getAbsolutePath() --- .../mod_pocketDim/core/PocketManager.java | 14 ++++-- .../mod_pocketDim/saving/DDSaveHandler.java | 49 +++++-------------- 2 files changed, 23 insertions(+), 40 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/core/PocketManager.java b/src/main/java/StevenDimDoors/mod_pocketDim/core/PocketManager.java index 842c6c8..4d8a07a 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/core/PocketManager.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/core/PocketManager.java @@ -304,6 +304,7 @@ 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. @@ -314,7 +315,7 @@ public class PocketManager { if (deleteFolder) { - deleteDimensionFolder(target); + deleteDimensionFiles(target); } dimensionIDBlackList.add(dimension.id); deleteDimensionData(dimension.id); @@ -322,20 +323,25 @@ public class PocketManager } return false; } - private static boolean deleteDimensionFolder(NewDimData target) + + private static boolean deleteDimensionFiles(NewDimData target) { InnerDimData dimension = (InnerDimData) target; if (dimension.isPocketDimension() && DimensionManager.getWorld(dimension.id()) == null) { - File saveDirectory = new File(DimensionManager.getCurrentSaveRootDirectory() + "/DimensionalDoors/pocketDimID" + dimension.id()); + 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(); return true; } return false; } + private static boolean deleteDimensionData(int dimensionID) { - if(dimensionData.containsKey(dimensionID)&& DimensionManager.getWorld(dimensionID) == null) + if (dimensionData.containsKey(dimensionID) && DimensionManager.getWorld(dimensionID) == null) { NewDimData target = PocketManager.getDimensionData(dimensionID); InnerDimData dimension = (InnerDimData) target; diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/saving/DDSaveHandler.java b/src/main/java/StevenDimDoors/mod_pocketDim/saving/DDSaveHandler.java index 8cef1fd..b995edd 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/saving/DDSaveHandler.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/saving/DDSaveHandler.java @@ -244,58 +244,35 @@ public class DDSaveHandler // 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. - - //I still dont think that this is the best way to do this, but atleast it is better than - //risking deleting everything. I delete files afterwards that I did not modify. - //get the save directory path + // Get the save directory path File saveDirectory = new File(DimensionManager.getCurrentSaveRootDirectory() + "/DimensionalDoors/data/"); + String savePath = saveDirectory.getAbsolutePath(); - //create the save directory + // Create the save directory Files.createParentDirs(saveDirectory); saveDirectory.mkdir(); - //create and write the blackList - BlacklistProcessor blacklistReader = new BlacklistProcessor(); - writeBlacklist(blacklist, blacklistReader,saveDirectory); - - FileFilter dataFileFilter = new FileFilters.RegexFileFilter("dim_-?\\d+\\.txt"); - - //Take the list of all dimData files already saved in the save Directory, and map them according to ID. - File[] dataFiles = saveDirectory.listFiles(dataFileFilter); - HashMap unsavedDimData = new HashMap(); - for (File dataFile : dataFiles) - { - unsavedDimData.put(Integer.parseInt(dataFile.getName().split("[.]")[0].substring(4)), dataFile); - } + // Create and write the blackList + writeBlacklist(blacklist, savePath); + // Write the dimension save data, and remove the ones we save from the mapping boolean succeeded = true; - - //write the dimension save data, and remove the ones we save from the mapping DimDataProcessor writer = new DimDataProcessor(); for (IPackable dimension : dimensions) { - succeeded &= writeDimension(dimension, writer, saveDirectory.getAbsolutePath()+"/dim_"); - unsavedDimData.remove(Integer.parseInt(dimension.name())); - } - - //once we have finished saving, delete the files from the save directory that where not saved - if(succeeded) - { - for (File dataFile : unsavedDimData.values()) - { - dataFile.delete(); - } + succeeded &= writeDimension(dimension, writer, savePath + "/dim_"); } return succeeded; } - private static boolean writeBlacklist(List blacklist, BlacklistProcessor writer, File saveDirectory) + private static boolean writeBlacklist(List blacklist, String savePath) { try { - File tempFile = new File(saveDirectory.getAbsolutePath() + "blacklist.tmp"); - File saveFile = new File(saveDirectory.getAbsolutePath() + "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); @@ -306,9 +283,9 @@ 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) { try From 35c5943faf5fa4c8b7e751fd4e4565894dbbc15d Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Wed, 26 Mar 2014 03:13:07 -0400 Subject: [PATCH 059/187] Changes to EventHookContainer * Fixed comments messed up by auto-formatting * Minor formatting changes * Combined two conditions in the door-placement code into an equivalent condition --- .../mod_pocketDim/EventHookContainer.java | 53 ++++++++----------- 1 file changed, 22 insertions(+), 31 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java b/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java index 67519a1..72d1704 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java @@ -33,7 +33,7 @@ import cpw.mods.fml.relauncher.SideOnly; public class EventHookContainer { - private final DDProperties properties; + private final DDProperties properties; public EventHookContainer(DDProperties properties) { @@ -44,9 +44,8 @@ public class EventHookContainer public void onInitMapGen(InitMapGenEvent event) { // Replace the Nether fortress generator with our own only if any - // gateways would ever generate. - // This allows admins to disable our fortress overriding without - // disabling all gateways. + // gateways would ever generate. This allows admins to disable our + // fortress overriding without disabling all gateways. /* * if (properties.FortressGatewayGenerationChance > 0 && * properties.WorldRiftGenerationEnabled && event.type == @@ -88,15 +87,13 @@ public class EventHookContainer World world = event.entity.worldObj; ItemStack stack = event.entityPlayer.inventory.getCurrentItem(); - if (stack != null) + if (stack != null && stack.getItem() instanceof ItemDoor) { - if (stack.getItem() instanceof ItemDoor) + if (mod_pocketDim.itemDimensionalDoor.tryToPlaceDoor(stack, event.entityPlayer, world, + event.x, event.y, event.z, event.face)) { - if(mod_pocketDim.itemDimensionalDoor.tryToPlaceDoor(stack, event.entityPlayer, world, event.x, event.y, event.z, event.face)) - { - //cancel the event so we dont get two doors from vanilla doors - event.setCanceled(true); - } + // Cancel the event so that we don't get two doors + event.setCanceled(true); } } } @@ -105,11 +102,9 @@ public class EventHookContainer 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. + // 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(); @@ -131,16 +126,14 @@ public class EventHookContainer 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. + // 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) + if (properties.LimboEnabled && properties.LimboReturnsInventoryEnabled && + entity instanceof EntityPlayer && entity.worldObj.provider instanceof PocketProvider) { EntityPlayer player = (EntityPlayer) entity; mod_pocketDim.deathTracker.addUsername(player.username); @@ -155,11 +148,10 @@ public class EventHookContainer 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. + // 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; @@ -209,9 +201,8 @@ public class EventHookContainer 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... + // 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) From 248ac1ecf4939585fbbaa062e6eaeae29e6b86bd Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Wed, 26 Mar 2014 03:32:17 -0400 Subject: [PATCH 060/187] Minor Change Minor mix-up with saving a change to a comment --- .../java/StevenDimDoors/mod_pocketDim/EventHookContainer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java b/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java index 72d1704..f241c24 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java @@ -92,7 +92,7 @@ public class EventHookContainer if (mod_pocketDim.itemDimensionalDoor.tryToPlaceDoor(stack, event.entityPlayer, world, event.x, event.y, event.z, event.face)) { - // Cancel the event so that we don't get two doors + // Cancel the event so that we don't get two doors from vanilla doors event.setCanceled(true); } } From 19bc9eec99f543aababcfab8ca1bf500d8910621 Mon Sep 17 00:00:00 2001 From: StevenRS11 Date: Wed, 26 Mar 2014 23:19:56 -0400 Subject: [PATCH 061/187] I HATE YOU GITHUB --- .../mod_pocketDim/EventHookContainer.java | 53 ++++++++----------- .../mod_pocketDim/core/PocketManager.java | 14 +++-- .../mod_pocketDim/saving/DDSaveHandler.java | 49 +++++------------ 3 files changed, 45 insertions(+), 71 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java b/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java index 67519a1..f241c24 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java @@ -33,7 +33,7 @@ import cpw.mods.fml.relauncher.SideOnly; public class EventHookContainer { - private final DDProperties properties; + private final DDProperties properties; public EventHookContainer(DDProperties properties) { @@ -44,9 +44,8 @@ public class EventHookContainer public void onInitMapGen(InitMapGenEvent event) { // Replace the Nether fortress generator with our own only if any - // gateways would ever generate. - // This allows admins to disable our fortress overriding without - // disabling all gateways. + // gateways would ever generate. This allows admins to disable our + // fortress overriding without disabling all gateways. /* * if (properties.FortressGatewayGenerationChance > 0 && * properties.WorldRiftGenerationEnabled && event.type == @@ -88,15 +87,13 @@ public class EventHookContainer World world = event.entity.worldObj; ItemStack stack = event.entityPlayer.inventory.getCurrentItem(); - if (stack != null) + if (stack != null && stack.getItem() instanceof ItemDoor) { - if (stack.getItem() instanceof ItemDoor) + if (mod_pocketDim.itemDimensionalDoor.tryToPlaceDoor(stack, event.entityPlayer, world, + event.x, event.y, event.z, event.face)) { - if(mod_pocketDim.itemDimensionalDoor.tryToPlaceDoor(stack, event.entityPlayer, world, event.x, event.y, event.z, event.face)) - { - //cancel the event so we dont get two doors from vanilla doors - event.setCanceled(true); - } + // Cancel the event so that we don't get two doors from vanilla doors + event.setCanceled(true); } } } @@ -105,11 +102,9 @@ public class EventHookContainer 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. + // 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(); @@ -131,16 +126,14 @@ public class EventHookContainer 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. + // 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) + if (properties.LimboEnabled && properties.LimboReturnsInventoryEnabled && + entity instanceof EntityPlayer && entity.worldObj.provider instanceof PocketProvider) { EntityPlayer player = (EntityPlayer) entity; mod_pocketDim.deathTracker.addUsername(player.username); @@ -155,11 +148,10 @@ public class EventHookContainer 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. + // 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; @@ -209,9 +201,8 @@ public class EventHookContainer 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... + // 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) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/core/PocketManager.java b/src/main/java/StevenDimDoors/mod_pocketDim/core/PocketManager.java index 842c6c8..4d8a07a 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/core/PocketManager.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/core/PocketManager.java @@ -304,6 +304,7 @@ 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. @@ -314,7 +315,7 @@ public class PocketManager { if (deleteFolder) { - deleteDimensionFolder(target); + deleteDimensionFiles(target); } dimensionIDBlackList.add(dimension.id); deleteDimensionData(dimension.id); @@ -322,20 +323,25 @@ public class PocketManager } return false; } - private static boolean deleteDimensionFolder(NewDimData target) + + private static boolean deleteDimensionFiles(NewDimData target) { InnerDimData dimension = (InnerDimData) target; if (dimension.isPocketDimension() && DimensionManager.getWorld(dimension.id()) == null) { - File saveDirectory = new File(DimensionManager.getCurrentSaveRootDirectory() + "/DimensionalDoors/pocketDimID" + dimension.id()); + 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(); return true; } return false; } + private static boolean deleteDimensionData(int dimensionID) { - if(dimensionData.containsKey(dimensionID)&& DimensionManager.getWorld(dimensionID) == null) + if (dimensionData.containsKey(dimensionID) && DimensionManager.getWorld(dimensionID) == null) { NewDimData target = PocketManager.getDimensionData(dimensionID); InnerDimData dimension = (InnerDimData) target; diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/saving/DDSaveHandler.java b/src/main/java/StevenDimDoors/mod_pocketDim/saving/DDSaveHandler.java index 8cef1fd..b995edd 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/saving/DDSaveHandler.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/saving/DDSaveHandler.java @@ -244,58 +244,35 @@ public class DDSaveHandler // 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. - - //I still dont think that this is the best way to do this, but atleast it is better than - //risking deleting everything. I delete files afterwards that I did not modify. - //get the save directory path + // Get the save directory path File saveDirectory = new File(DimensionManager.getCurrentSaveRootDirectory() + "/DimensionalDoors/data/"); + String savePath = saveDirectory.getAbsolutePath(); - //create the save directory + // Create the save directory Files.createParentDirs(saveDirectory); saveDirectory.mkdir(); - //create and write the blackList - BlacklistProcessor blacklistReader = new BlacklistProcessor(); - writeBlacklist(blacklist, blacklistReader,saveDirectory); - - FileFilter dataFileFilter = new FileFilters.RegexFileFilter("dim_-?\\d+\\.txt"); - - //Take the list of all dimData files already saved in the save Directory, and map them according to ID. - File[] dataFiles = saveDirectory.listFiles(dataFileFilter); - HashMap unsavedDimData = new HashMap(); - for (File dataFile : dataFiles) - { - unsavedDimData.put(Integer.parseInt(dataFile.getName().split("[.]")[0].substring(4)), dataFile); - } + // Create and write the blackList + writeBlacklist(blacklist, savePath); + // Write the dimension save data, and remove the ones we save from the mapping boolean succeeded = true; - - //write the dimension save data, and remove the ones we save from the mapping DimDataProcessor writer = new DimDataProcessor(); for (IPackable dimension : dimensions) { - succeeded &= writeDimension(dimension, writer, saveDirectory.getAbsolutePath()+"/dim_"); - unsavedDimData.remove(Integer.parseInt(dimension.name())); - } - - //once we have finished saving, delete the files from the save directory that where not saved - if(succeeded) - { - for (File dataFile : unsavedDimData.values()) - { - dataFile.delete(); - } + succeeded &= writeDimension(dimension, writer, savePath + "/dim_"); } return succeeded; } - private static boolean writeBlacklist(List blacklist, BlacklistProcessor writer, File saveDirectory) + private static boolean writeBlacklist(List blacklist, String savePath) { try { - File tempFile = new File(saveDirectory.getAbsolutePath() + "blacklist.tmp"); - File saveFile = new File(saveDirectory.getAbsolutePath() + "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); @@ -306,9 +283,9 @@ 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) { try From 41b77c639cd03b163107b253c33634f263db7c50 Mon Sep 17 00:00:00 2001 From: StevenRS11 Date: Fri, 28 Mar 2014 00:39:27 -0400 Subject: [PATCH 062/187] Fixed Door on rifts --- .../mod_pocketDim/items/BaseItemDoor.java | 17 ++++++++++++----- .../items/ItemDimensionalDoor.java | 9 +++++---- .../mod_pocketDim/items/ItemGoldDimDoor.java | 9 +++++---- .../mod_pocketDim/items/ItemUnstableDoor.java | 5 +++-- .../mod_pocketDim/items/ItemWarpDoor.java | 5 +++-- .../mod_pocketDim/mod_pocketDim.java | 9 +++++---- 6 files changed, 33 insertions(+), 21 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/items/BaseItemDoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/items/BaseItemDoor.java index 5f7ca97..319a258 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/items/BaseItemDoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/items/BaseItemDoor.java @@ -28,17 +28,24 @@ public abstract class BaseItemDoor extends ItemDoor private static HashMap vanillaDoorMapping = 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 door) { super(itemID, material); this.setMaxStackSize(64); this.setCreativeTab(mod_pocketDim.dimDoorsCreativeTab); if (properties == null) properties = DDProperties.instance(); - - vanillaDoorMapping.put((ItemDoor) mod_pocketDim.itemGoldenDoor, (BaseItemDoor) mod_pocketDim.itemGoldenDimensionalDoor); - vanillaDoorMapping.put((ItemDoor) Item.doorIron, (BaseItemDoor) mod_pocketDim.itemDimensionalDoor); - vanillaDoorMapping.put((ItemDoor) Item.doorWood, (BaseItemDoor) mod_pocketDim.itemWarpDoor); + + if(door!=null) + { + vanillaDoorMapping.put(door, this); + } } @Override diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemDimensionalDoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemDimensionalDoor.java index a85f5e4..d6bb9ce 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemDimensionalDoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemDimensionalDoor.java @@ -4,6 +4,7 @@ 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; @@ -11,10 +12,10 @@ 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 diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemGoldDimDoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemGoldDimDoor.java index fceb2f3..9dde8f5 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemGoldDimDoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemGoldDimDoor.java @@ -4,6 +4,7 @@ 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; @@ -12,10 +13,10 @@ 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 diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemUnstableDoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemUnstableDoor.java index 809fc86..c859443 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemUnstableDoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemUnstableDoor.java @@ -4,6 +4,7 @@ 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; @@ -11,9 +12,9 @@ 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" }) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemWarpDoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemWarpDoor.java index ac3f66a..35c5737 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemWarpDoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemWarpDoor.java @@ -4,6 +4,7 @@ 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; @@ -11,9 +12,9 @@ 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" }) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java b/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java index 09bb6d6..7d6a800 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java @@ -9,6 +9,7 @@ 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; @@ -201,14 +202,14 @@ public class mod_pocketDim 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 = (ItemDimensionalDoor) (new ItemDimensionalDoor(properties.DimensionalDoorItemID, Material.iron)).setUnlocalizedName("itemDimDoor"); - itemWarpDoor = (new ItemWarpDoor(properties.WarpDoorItemID, Material.wood)).setUnlocalizedName("itemDimDoorWarp"); + 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"); itemWorldThread = (new ItemWorldThread(properties.WorldThreadItemID)).setUnlocalizedName("itemWorldThread"); From cc2def03fde1a9d1c492bc6138891fae7bfcafaa Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Fri, 28 Mar 2014 02:07:20 -0400 Subject: [PATCH 063/187] Added Dirty Flag Added a flag to NewDimData so that we can avoid writing dimensions to disk if they haven't been modified. They're still rewritten when the server shuts down. --- .../mod_pocketDim/EventHookContainer.java | 2 +- .../mod_pocketDim/core/NewDimData.java | 46 ++++++++++++++----- .../mod_pocketDim/core/PocketManager.java | 6 +-- .../mod_pocketDim/saving/DDSaveHandler.java | 21 +++++++-- .../mod_pocketDim/saving/IPackable.java | 2 + 5 files changed, 57 insertions(+), 20 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java b/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java index f241c24..aa04337 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java @@ -185,7 +185,7 @@ public class EventHookContainer { if (event.world.provider.dimensionId == 0) { - PocketManager.save(); + PocketManager.save(true); if (mod_pocketDim.deathTracker != null && mod_pocketDim.deathTracker.isModified()) { diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/core/NewDimData.java b/src/main/java/StevenDimDoors/mod_pocketDim/core/NewDimData.java index ba977d5..22b783f 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/core/NewDimData.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/core/NewDimData.java @@ -19,7 +19,7 @@ public abstract class NewDimData { private static class InnerDimLink extends DimLink { - public InnerDimLink(Point4D source, DimLink parent,int orientation) + public InnerDimLink(Point4D source, DimLink parent, int orientation) { super(new ClientLinkData(source, orientation), parent); } @@ -130,6 +130,7 @@ public abstract class NewDimData 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, @@ -157,6 +158,7 @@ public abstract class NewDimData this.origin = null; this.dungeon = null; this.linkWatcher = linkWatcher; + this.modified = true; //Register with parent if (parent != null) @@ -165,6 +167,7 @@ public abstract class NewDimData this.root = parent.root; this.depth = parent.depth + 1; parent.children.add(this); + parent.modified = true; } else { @@ -288,27 +291,30 @@ 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, int linkType, int orientation) { - return createLink(new Point4D(x, y, z, id), linkType,orientation); + return createLink(new Point4D(x, y, z, id), linkType, orientation); } - public DimLink createLink(Point4D source, int linkType,int orientation) + public DimLink createLink(Point4D source, int linkType, int orientation) { //Return an existing link if there is one to avoid creating multiple links starting at the same point. InnerDimLink link = linkMapping.get(source); if (link == null) { - link = new InnerDimLink(source, linkType,orientation); + link = new InnerDimLink(source, linkType, orientation); linkMapping.put(source, link); linkList.add(link); } else { - link.overwrite(linkType,orientation); + link.overwrite(linkType, orientation); } + modified = true; + //Link created! - if(linkType!=LinkTypes.CLIENT_SIDE) + if (linkType != LinkTypes.CLIENT_SIDE) { linkWatcher.onCreated(link.link); } @@ -348,6 +354,7 @@ public abstract class NewDimData linkWatcher.onCreated(link.link); } } + modified = true; return link; } @@ -364,6 +371,7 @@ public abstract class NewDimData //Raise deletion event linkWatcher.onDeleted(target.link); target.clear(); + modified = true; } return (target != null); } @@ -418,6 +426,7 @@ public abstract class NewDimData public void setFilled(boolean isFilled) { this.isFilled = isFilled; + this.modified = true; } public int id() @@ -499,16 +508,19 @@ public abstract class NewDimData 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; + this.depth = 1; + this.parent = this.root; this.root.children.add(this); + this.root.modified = true; + this.modified = true; } public static int calculatePackDepth(NewDimData parent, DungeonData current) @@ -557,12 +569,14 @@ public abstract class NewDimData setDestination(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) { InnerDimLink link = (InnerDimLink) incoming; link.setDestination(x, y, z, this); + this.modified = true; } public DimLink getRandomLink() @@ -581,8 +595,18 @@ public abstract class NewDimData } } + public boolean isModified() + { + return modified; + } + + public void clearModified() + { + this.modified = false; + } + 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 4d8a07a..da38f61 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/core/PocketManager.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/core/PocketManager.java @@ -446,7 +446,7 @@ public class PocketManager } } - public static void save() + public static void save(boolean checkModified) { if (!isLoaded) { @@ -466,7 +466,7 @@ public class PocketManager try { - DDSaveHandler.saveAll(dimensionData.values(), dimensionIDBlackList); + DDSaveHandler.saveAll(dimensionData.values(), dimensionIDBlackList, checkModified); } catch (Exception e) { @@ -627,7 +627,7 @@ public class PocketManager throw new IllegalStateException("Pocket dimensions have already been unloaded!"); } - save(); + save(false); unregisterPockets(); dimensionData = null; rootDimensions = null; diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/saving/DDSaveHandler.java b/src/main/java/StevenDimDoors/mod_pocketDim/saving/DDSaveHandler.java index b995edd..fed91f8 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/saving/DDSaveHandler.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/saving/DDSaveHandler.java @@ -64,14 +64,14 @@ public class DDSaveHandler // 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); - packedDims.put(packedDim.ID,packedDim); + packedDims.put(packedDim.ID, packedDim); } List linksToUnpack = new ArrayList(); @@ -80,7 +80,7 @@ public class DDSaveHandler { linksToUnpack.addAll(packedDim.Links); } - return unpackDimData(packedDims)&&unpackLinkData(linksToUnpack); + return unpackDimData(packedDims) && unpackLinkData(linksToUnpack); } /** @@ -239,7 +239,8 @@ 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, @@ -261,7 +262,17 @@ public class DDSaveHandler DimDataProcessor writer = new DimDataProcessor(); for (IPackable dimension : dimensions) { - succeeded &= writeDimension(dimension, writer, savePath + "/dim_"); + if (!checkModified || dimension.isModified()) + { + if (writeDimension(dimension, writer, savePath + "/dim_")) + { + dimension.clearModified(); + } + else + { + succeeded = false; + } + } } return succeeded; } 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(); } From 0491b55f405988d300d2cf280b9a6e67fe33703d Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Fri, 28 Mar 2014 02:31:29 -0400 Subject: [PATCH 064/187] Minor Change Minor changes to comments --- .../mod_pocketDim/saving/DDSaveHandler.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/saving/DDSaveHandler.java b/src/main/java/StevenDimDoors/mod_pocketDim/saving/DDSaveHandler.java index fed91f8..f240358 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/saving/DDSaveHandler.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/saving/DDSaveHandler.java @@ -242,26 +242,25 @@ public class DDSaveHandler 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. - // Get the save directory path File saveDirectory = new File(DimensionManager.getCurrentSaveRootDirectory() + "/DimensionalDoors/data/"); String savePath = saveDirectory.getAbsolutePath(); // Create the save directory + // Don't catch exceptions here. If we can't create this folder, + // then the mod should crash to let the user know early on. Files.createParentDirs(saveDirectory); saveDirectory.mkdir(); // Create and write the blackList writeBlacklist(blacklist, savePath); - // Write the dimension save data, and remove the ones we save from the mapping + // Write the dimension save data boolean succeeded = true; DimDataProcessor writer = new DimDataProcessor(); for (IPackable dimension : dimensions) { + // Check if the dimension should be saved if (!checkModified || dimension.isModified()) { if (writeDimension(dimension, writer, savePath + "/dim_")) From 582db26cdc37f09e8e491d05383bd8d2ac7beb3f Mon Sep 17 00:00:00 2001 From: StevenRS11 Date: Thu, 3 Apr 2014 14:06:48 -0400 Subject: [PATCH 065/187] Fixed a crash in rift sig placement --- .../StevenDimDoors/mod_pocketDim/items/ItemRiftSignature.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemRiftSignature.java b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemRiftSignature.java index 6f5c5b8..a20bc46 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemRiftSignature.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemRiftSignature.java @@ -142,6 +142,10 @@ public class ItemRiftSignature extends Item { y=y-2;//get the block the player actually clicked on Block block = Block.blocksList[world.getBlockId(x, y, z)]; + if(block==null) + { + return y+2; + } if(block.isBlockReplaceable(world, x, y, z)) { return y+1;//move block placement down (-2+1) one so its directly over things like snow From 41fbcfe0ff3dc6e9be336d2bab2ec04b23856b11 Mon Sep 17 00:00:00 2001 From: StevenRS11 Date: Thu, 3 Apr 2014 14:09:36 -0400 Subject: [PATCH 066/187] Savedata backs up on write now --- .../mod_pocketDim/saving/DDSaveHandler.java | 40 ++++++++++++++----- 1 file changed, 30 insertions(+), 10 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/saving/DDSaveHandler.java b/src/main/java/StevenDimDoors/mod_pocketDim/saving/DDSaveHandler.java index b995edd..eed33b2 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/saving/DDSaveHandler.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/saving/DDSaveHandler.java @@ -11,6 +11,7 @@ import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; import java.util.List; +import org.apache.commons.io.FileUtils; import net.minecraftforge.common.DimensionManager; import StevenDimDoors.mod_pocketDim.Point3D; @@ -71,6 +72,10 @@ public class DDSaveHandler 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); } @@ -241,17 +246,24 @@ public class DDSaveHandler public static boolean saveAll(Iterable> dimensions, List blacklist) throws IOException { + long startTime = System.nanoTime(); + // 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. // Get the save directory path File saveDirectory = new File(DimensionManager.getCurrentSaveRootDirectory() + "/DimensionalDoors/data/"); + File backupDir = new File(saveDirectory+"/backup"); String savePath = saveDirectory.getAbsolutePath(); - - // Create the save directory - Files.createParentDirs(saveDirectory); - saveDirectory.mkdir(); + + + if(!saveDirectory.exists()) + { + // Create the save directory + Files.createParentDirs(saveDirectory); + saveDirectory.mkdir(); + } // Create and write the blackList writeBlacklist(blacklist, savePath); @@ -261,8 +273,11 @@ public class DDSaveHandler DimDataProcessor writer = new DimDataProcessor(); for (IPackable dimension : dimensions) { - succeeded &= writeDimension(dimension, writer, savePath + "/dim_"); + succeeded &= writeDimension(dimension, writer, savePath + "/dim_",backupDir); } + + startTime = System.nanoTime()-startTime; + System.out.println("Saving took "+startTime/1000000000D+" seconds"); return succeeded; } @@ -286,15 +301,20 @@ public class DDSaveHandler } } - private static boolean writeDimension(IPackable dimension, DimDataProcessor writer, String basePath) + private static boolean writeDimension(IPackable dimension, DimDataProcessor writer, String basePath, File backupDir) { try { - File tempFile = new File(basePath + (dimension.name() + ".tmp")); File saveFile = new File(basePath + (dimension.name() + ".txt")); - writer.writeToFile(tempFile, dimension.pack()); - saveFile.delete(); - tempFile.renameTo(saveFile); + + //If the savefile already exists, back it up. + if(saveFile.exists()) + { + FileUtils.copyFileToDirectory(saveFile, backupDir); + saveFile.delete(); + } + + writer.writeToFile(saveFile, dimension.pack()); return true; } catch (Exception e) From aa7ee3c8fe161ff036ba114f2fb2f6495fd1e631 Mon Sep 17 00:00:00 2001 From: StevenRS11 Date: Thu, 3 Apr 2014 14:10:00 -0400 Subject: [PATCH 067/187] added logger --- .../StevenDimDoors/mod_pocketDim/util/Logger.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 src/main/java/StevenDimDoors/mod_pocketDim/util/Logger.java diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/util/Logger.java b/src/main/java/StevenDimDoors/mod_pocketDim/util/Logger.java new file mode 100644 index 0000000..c544f05 --- /dev/null +++ b/src/main/java/StevenDimDoors/mod_pocketDim/util/Logger.java @@ -0,0 +1,12 @@ +package StevenDimDoors.mod_pocketDim.util; + +public class Logger +{ + private static Logger instance; + + public Logger() + { + instance = this; + } + +} From d98b6279de3bb28cad88a237dcc3cfc7d7dbc346 Mon Sep 17 00:00:00 2001 From: StevenRS11 Date: Thu, 3 Apr 2014 15:55:35 -0400 Subject: [PATCH 068/187] quick fix --- .../StevenDimDoors/mod_pocketDim/saving/DDSaveHandler.java | 2 +- .../java/StevenDimDoors/mod_pocketDim/util/DDLogger.java | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/saving/DDSaveHandler.java b/src/main/java/StevenDimDoors/mod_pocketDim/saving/DDSaveHandler.java index d8278be..2ae2a9a 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/saving/DDSaveHandler.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/saving/DDSaveHandler.java @@ -46,7 +46,7 @@ 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.logger().startTimer("Loading data"); + DDLogger.startTimer("Loading data"); String basePath = DimensionManager.getCurrentSaveRootDirectory() + "/DimensionalDoors/data/"; File dataDirectory = new File(basePath); diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/util/DDLogger.java b/src/main/java/StevenDimDoors/mod_pocketDim/util/DDLogger.java index 6a92967..1b28510 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/util/DDLogger.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/util/DDLogger.java @@ -15,7 +15,7 @@ public class DDLogger this.log.append("Logger started.\n"); } - private static DDLogger logger() + public static DDLogger logger() { if( instance == null) { @@ -35,10 +35,9 @@ public class DDLogger { this.description=description; } - private DDTimer start() + private void start() { this.startTime=System.nanoTime(); - return this; } private void stop(long endTime) { From 56e522a61abdc49a2f7a6407de2b45bd6ccb432b Mon Sep 17 00:00:00 2001 From: StevenRS11 Date: Thu, 3 Apr 2014 20:15:34 -0400 Subject: [PATCH 069/187] logging changes --- src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java | 2 ++ .../java/StevenDimDoors/mod_pocketDim/saving/DDSaveHandler.java | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java b/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java index 529a032..54f22a9 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java @@ -315,6 +315,8 @@ public class mod_pocketDim { PocketManager.unload(); deathTracker.writeToFile(); + System.out.println(DDLogger.logger().printLog()); + DDLogger.logger().clearLog(); deathTracker = null; worldProperties = null; this.currrentSaveRootDirectory=null; diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/saving/DDSaveHandler.java b/src/main/java/StevenDimDoors/mod_pocketDim/saving/DDSaveHandler.java index 2ae2a9a..ef6e377 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/saving/DDSaveHandler.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/saving/DDSaveHandler.java @@ -293,7 +293,6 @@ public class DDSaveHandler } DDLogger.stopTimer("Saving data"); - System.out.println(DDLogger.logger().printLog()); return succeeded; } From 18460348af1974335bea90f1f318f40e6c6c96c8 Mon Sep 17 00:00:00 2001 From: StevenRS11 Date: Fri, 11 Apr 2014 19:27:26 -0400 Subject: [PATCH 070/187] stopped logging --- src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java | 2 -- .../java/StevenDimDoors/mod_pocketDim/saving/DDSaveHandler.java | 2 -- 2 files changed, 4 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java b/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java index 54f22a9..529a032 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java @@ -315,8 +315,6 @@ public class mod_pocketDim { PocketManager.unload(); deathTracker.writeToFile(); - System.out.println(DDLogger.logger().printLog()); - DDLogger.logger().clearLog(); deathTracker = null; worldProperties = null; this.currrentSaveRootDirectory=null; diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/saving/DDSaveHandler.java b/src/main/java/StevenDimDoors/mod_pocketDim/saving/DDSaveHandler.java index ef6e377..a40e293 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/saving/DDSaveHandler.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/saving/DDSaveHandler.java @@ -252,7 +252,6 @@ public class DDSaveHandler public static boolean saveAll(Iterable> dimensions, List blacklist, boolean checkModified) throws IOException { - DDLogger.startTimer("Saving data"); // 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. @@ -292,7 +291,6 @@ public class DDSaveHandler } } - DDLogger.stopTimer("Saving data"); return succeeded; } From d192dae945632b777414fc52638c6f17515f295e Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Fri, 11 Apr 2014 20:33:06 -0400 Subject: [PATCH 071/187] Improvements to Saving * Changed saving code to create backups by moving existing files rather than creating copies and deleting the originals. * Removed final call to PocketManager.save() in PocketManager.unload(). Since we no longer check if the caller is the client or server and unload() must be called from both, this prevents clients from trying to save pocket data locally. A final save() call wasn't needed anyway. --- .../mod_pocketDim/core/PocketManager.java | 3 +-- .../mod_pocketDim/saving/DDSaveHandler.java | 26 +++++++------------ 2 files changed, 10 insertions(+), 19 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/core/PocketManager.java b/src/main/java/StevenDimDoors/mod_pocketDim/core/PocketManager.java index 2bf9f59..4eae666 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/core/PocketManager.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/core/PocketManager.java @@ -621,8 +621,7 @@ public class PocketManager { throw new IllegalStateException("Pocket dimensions have already been unloaded!"); } - - save(false); + unregisterPockets(); dimensionData = null; rootDimensions = null; diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/saving/DDSaveHandler.java b/src/main/java/StevenDimDoors/mod_pocketDim/saving/DDSaveHandler.java index a40e293..a2022c4 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/saving/DDSaveHandler.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/saving/DDSaveHandler.java @@ -2,16 +2,11 @@ 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.HashSet; -import java.util.Iterator; import java.util.LinkedList; import java.util.List; -import org.apache.commons.io.FileUtils; import net.minecraftforge.common.DimensionManager; import StevenDimDoors.mod_pocketDim.Point3D; @@ -21,10 +16,7 @@ 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.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; @@ -258,8 +250,10 @@ public class DDSaveHandler // Get the save directory path File saveDirectory = new File(mod_pocketDim.instance.getCurrentSavePath() + "/DimensionalDoors/data/"); - File backupDir = new File(saveDirectory+"/backup"); + File backupDirectory = new File(saveDirectory + "/backup"); String savePath = saveDirectory.getAbsolutePath(); + String baseSavePath = savePath + "/dim_"; + String baseBackupPath = backupDirectory.getAbsolutePath() + "/dim_"; if(!saveDirectory.exists()) { @@ -276,11 +270,10 @@ public class DDSaveHandler DimDataProcessor writer = new DimDataProcessor(); for (IPackable dimension : dimensions) { - // Check if the dimension should be saved if (!checkModified || dimension.isModified()) { - if (writeDimension(dimension, writer, savePath + "/dim_",backupDir)) + if (writeDimension(dimension, writer, baseSavePath, baseBackupPath)) { dimension.clearModified(); } @@ -314,17 +307,16 @@ public class DDSaveHandler } } - private static boolean writeDimension(IPackable dimension, DimDataProcessor writer, String basePath, File backupDir) + private static boolean writeDimension(IPackable dimension, DimDataProcessor writer, String basePath, String backupPath) { try { - File saveFile = new File(basePath + (dimension.name() + ".txt")); + File saveFile = new File(basePath + dimension.name() + ".txt"); - //If the savefile already exists, back it up. - if(saveFile.exists()) + // If the save file already exists, back it up. + if (saveFile.exists()) { - FileUtils.copyFileToDirectory(saveFile, backupDir); - saveFile.delete(); + Files.move(saveFile, new File(backupPath + dimension.name() + ".txt")); } writer.writeToFile(saveFile, dimension.pack()); From a2ef6ef90509ab124042d87ef08112c96a3f30e6 Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Fri, 11 Apr 2014 20:34:11 -0400 Subject: [PATCH 072/187] Minor Change Changed DDLogger.logger() to private to guarantee that the logger isn't being used anywhere in DD, since that could impact performance on servers. --- src/main/java/StevenDimDoors/mod_pocketDim/util/DDLogger.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/util/DDLogger.java b/src/main/java/StevenDimDoors/mod_pocketDim/util/DDLogger.java index 1b28510..18ebda0 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/util/DDLogger.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/util/DDLogger.java @@ -15,7 +15,8 @@ public class DDLogger this.log.append("Logger started.\n"); } - public static DDLogger logger() + // SenseiKiwi: I changed this to private to guarantee that the logger isn't being used anywhere. + private static DDLogger logger() { if( instance == null) { From 4dca0eb82b23b985f995b3d618682003f4b8bce3 Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Fri, 11 Apr 2014 21:32:36 -0400 Subject: [PATCH 073/187] Updated Version Update our version numbers --- build.gradle | 2 +- src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java | 2 +- src/main/resources/mcmod.info | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/build.gradle b/build.gradle index 487f821..2cbcf59 100644 --- a/build.gradle +++ b/build.gradle @@ -15,7 +15,7 @@ apply plugin: 'forge' -version = "2.2.2RC1-" + System.getenv("BUILD_NUMBER") +version = "2.2.3-" + System.getenv("BUILD_NUMBER") group= "com.stevenrs11.dimdoors" // http://maven.apache.org/guides/mini/guide-naming-conventions.html archivesBaseName = "DimensionalDoors" diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java b/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java index 529a032..7b37e1d 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java @@ -99,7 +99,7 @@ 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 = "1.6.4-R2.2.3"; public static final String modid = "dimdoors"; //need to clean up diff --git a/src/main/resources/mcmod.info b/src/main/resources/mcmod.info index edad775..4687d32 100644 --- a/src/main/resources/mcmod.info +++ b/src/main/resources/mcmod.info @@ -6,7 +6,7 @@ "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": "1.6.4-R2.2.3", "credits": "Created by StevenRS11, Coded by StevenRS11 and SenseiKiwi, Logo and Testing by Jaitsu", "logoFile": "/dimdoors_logo.png", "mcversion": "", From ffe45c729e7c90d699f58ecdef8bc241ee3b091c Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Sun, 13 Apr 2014 16:57:11 -0400 Subject: [PATCH 074/187] Fixed Bugs * Fixed bug with backup directory creation * Fixed two doorways in SK-FractalCage that were supposed to open but had been replaced with Eternal Fabric --- .../mod_pocketDim/saving/DDSaveHandler.java | 9 +++++++-- .../Hub_SK-FractalCage_Open_40.schematic | Bin 10698 -> 10545 bytes 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/saving/DDSaveHandler.java b/src/main/java/StevenDimDoors/mod_pocketDim/saving/DDSaveHandler.java index a2022c4..28929dc 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/saving/DDSaveHandler.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/saving/DDSaveHandler.java @@ -250,17 +250,22 @@ public class DDSaveHandler // Get the save directory path File saveDirectory = new File(mod_pocketDim.instance.getCurrentSavePath() + "/DimensionalDoors/data/"); - File backupDirectory = new File(saveDirectory + "/backup"); String savePath = saveDirectory.getAbsolutePath(); String baseSavePath = savePath + "/dim_"; + File backupDirectory = new File(savePath + "/backup"); String baseBackupPath = backupDirectory.getAbsolutePath() + "/dim_"; - if(!saveDirectory.exists()) + if (!saveDirectory.exists()) { // 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); 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 db1ceaf0a1b71058248e55bb41fe66f71741a77c..d66f82afae8fb11d004c309d96ba871cadb0e5ba 100644 GIT binary patch literal 10545 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 E0M~+x0{{R3 literal 10698 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 Date: Sun, 13 Apr 2014 23:52:51 -0400 Subject: [PATCH 075/187] fixed monoliths everything was terrible --- .../mod_pocketDim/ticking/MobMonolith.java | 253 +++++++----------- .../mod_pocketDimClient/RenderMobObelisk.java | 15 +- 2 files changed, 103 insertions(+), 165 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/ticking/MobMonolith.java b/src/main/java/StevenDimDoors/mod_pocketDim/ticking/MobMonolith.java index 36df4dc..d06ffac 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/ticking/MobMonolith.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/ticking/MobMonolith.java @@ -27,10 +27,16 @@ import StevenDimDoors.mod_pocketDim.world.PocketProvider; public class MobMonolith extends EntityFlying implements IMob { - public int aggro = 0; + public static final int MAX_AGGRO_RANGE = 35; + public static final int MAX_SOUND_COOLDOWN = 200; + public static final float MAX_AGGRO = 100; + public static final int TEXTURE_STATES = 18; + public float pitchLevel; + + public float aggro = 0; private float soundTime = 0; private byte textureState = 0; - private float scaleFactor = 0; + private int aggroMax; private static DDProperties properties = null; @@ -38,9 +44,8 @@ public class MobMonolith extends EntityFlying implements IMob public MobMonolith(World par1World) { super(par1World); - this.setSize(3F, 9.0F); + this.setSize(3F, 3F); this.noClip=true; - this.scaleFactor = (float) ((rand.nextDouble()/2)+1); this.aggroMax = rand.nextInt(245)+200; if (properties == null) properties = DDProperties.instance(); @@ -55,6 +60,14 @@ public class MobMonolith extends EntityFlying implements IMob @Override public boolean attackEntityFrom(DamageSource par1DamageSource, float par2) { + if (par1DamageSource == DamageSource.inWall) + { + this.posY = posY + 1; + } + else + { + this.aggro = this.aggroMax; + } return false; } @Override @@ -82,17 +95,12 @@ public class MobMonolith extends EntityFlying implements IMob this.getAttributeMap().getAttributeInstance(SharedMonsterAttributes.maxHealth).setAttribute(10); } + @Override public boolean canBePushed() { return false; } - @Override - public float getRenderSizeModifier() - { - return this.scaleFactor; - } - public void setEntityPosition(Entity entity, double x, double y, double z) { entity.lastTickPosX = entity.prevPosX = entity.posX = x; @@ -108,33 +116,6 @@ public class MobMonolith extends EntityFlying implements IMob this.dataWatcher.addObject(16, Byte.valueOf((byte)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() { @@ -150,168 +131,131 @@ public class MobMonolith extends EntityFlying implements IMob } super.onEntityUpdate(); - if(this.isClipping()) - { - this.moveEntity(0, .1, 0); - } - EntityPlayer entityPlayer = this.worldObj.getClosestPlayerToEntity(this, 35); + EntityPlayer entityPlayer = this.worldObj.getClosestPlayerToEntity(this,MAX_AGGRO_RANGE); + + //need to always manage aggro level, even if player is out of range. + this.setAggroLevel(entityPlayer); + //these things only matter if the player is in range. if (entityPlayer != null) { - if(this.soundTime<=0) - { - this.playSound(mod_pocketDim.modid+":monk", 1F, 1F); - this.soundTime=100; - } - this.faceEntity(entityPlayer, 1, 1); - - if (shouldAttackPlayer(entityPlayer)) + this.playSounds(entityPlayer); + //teleport the player if the conditions are met + if (aggro >= MAX_AGGRO && !this.worldObj.isRemote && properties.MonolithTeleportationEnabled && !entityPlayer.capabilities.isCreativeMode) { - if (aggro<470) - { - 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; - } - } - else if (!this.worldObj.isRemote && properties.MonolithTeleportationEnabled && !entityPlayer.capabilities.isCreativeMode) - { - Point4D destination = LimboProvider.getLimboSkySpawn(entityPlayer, properties); - 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(entityPlayer, properties); + DDTeleporter.teleportEntity(entityPlayer, destination, false); + this.aggro = 0; + entityPlayer.worldObj.playSoundAtEntity(entityPlayer,mod_pocketDim.modid+":crack",13, 1); } - else if(this.worldObj.provider instanceof PocketProvider) - { - if(aggro 0) + { + this.aggro = this.aggro -(this.aggro/25); + } + if(player != null) + { + //monoliths increase aggro slightly if the player is near, but slowly and to a cap. + float distance = this.getDistanceToEntity(player); + aggro+= 1.5-(distance/this.MAX_AGGRO_RANGE); + + //rapidly increase aggro if the monolith has line of sight to the player. + if(player.canEntityBeSeen(this)) + { + //prevent monoliths from teleporting the player in limbo + if(this.worldObj.provider instanceof LimboProvider) { - if(rand.nextInt(3)==0) - { - aggro++; - } + aggro+=1.5; } else { - if(aggro>0) - { - aggro--; - } + this.spawnParticles(player); + aggro+=3; } } } - else + + //convert the aggro counter to one of the texture states, and set it. + this.textureState = (byte) ((this.TEXTURE_STATES/this.MAX_AGGRO)*this.aggro); + if(this.textureState>TEXTURE_STATES) { - if(aggro>0) - { - aggro--; - - if(rand.nextBoolean()) - { - aggro--; - } - } + textureState = TEXTURE_STATES; } - 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) + + /** + * Plays sounds at different levels of aggro, using soundTime to prevent too many sounds at once. + * @param entityPlayer + */ + private void playSounds(EntityPlayer entityPlayer) { - return par1EntityPlayer.canEntityBeSeen(this); + float aggroPercent = (aggro/MAX_AGGRO); + if(this.soundTime<=0) + { + this.playSound(mod_pocketDim.modid+":monk", 1F, 1F); + this.soundTime=100; + } + if ((aggroPercent>.80)&&this.soundTime<100) + { + this.worldObj.playSoundEffect(entityPlayer.posX, entityPlayer.posY, entityPlayer.posZ,mod_pocketDim.modid+":tearing",2, 1F); + this.soundTime=200; + } + if ((aggroPercent>.95)&&this.soundTime<200) + { + this.worldObj.playSoundEffect(entityPlayer.posX, entityPlayer.posY, entityPlayer.posZ,mod_pocketDim.modid+":tearing",5, 1F); + this.soundTime=250; + } + this.soundTime--; } - - public boolean attackEntityFrom(DamageSource par1DamageSource, int par2) + + private void spawnParticles(EntityPlayer player) { - if (par1DamageSource == DamageSource.inWall) + for (int i = 1; i < (10*(aggro/MAX_AGGRO)); ++i) { - this.posY = posY + 1; + 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); } - else - { - this.aggro = this.aggroMax; - } - return false; } - + @Override public void faceEntity(Entity par1Entity, float par2, float par3) { double d0 = par1Entity.posX - this.posX; double d1 = par1Entity.posZ - this.posZ; - double d2; - - if (par1Entity instanceof EntityLiving) - { - EntityLiving entityliving = (EntityLiving)par1Entity; - d2 = entityliving.posY + entityliving.getEyeHeight() - (this.posY + this.getEyeHeight()); - } - else - { - d2 = (par1Entity.boundingBox.minY + par1Entity.boundingBox.maxY) - (this.posY + this.getEyeHeight()); - } - + double d2 = (par1Entity.posY + par1Entity.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.rotationYaw = f2; - + this.pitchLevel = (float)-((Math.atan(d2/d3) )* 180.0D / Math.PI); + this.rotationYaw = f2; this.rotationYawHead=f2; this.renderYawOffset=this.rotationYaw; } - @Override - public float getRotationYawHead() - { - return 0.0F; - } + @Override public void writeEntityToNBT(NBTTagCompound par1NBTTagCompound) { super.writeEntityToNBT(par1NBTTagCompound); par1NBTTagCompound.setFloat("soundTime", this.soundTime); - par1NBTTagCompound.setInteger("aggro", this.aggro); + par1NBTTagCompound.setFloat("aggro", this.aggro); par1NBTTagCompound.setInteger("aggroMax", this.aggroMax); par1NBTTagCompound.setByte("textureState", this.textureState); - par1NBTTagCompound.setFloat("scaleFactor", this.scaleFactor); } @Override @@ -319,10 +263,11 @@ public class MobMonolith extends EntityFlying implements IMob { super.readEntityFromNBT(par1NBTTagCompound); this.soundTime = par1NBTTagCompound.getFloat("soundTime"); - this.aggro = par1NBTTagCompound.getInteger("aggro"); + + //make them load with half aggro so they dont instantly teleport players + this.aggro = par1NBTTagCompound.getFloat("aggro")/2; this.aggroMax = par1NBTTagCompound.getInteger("aggroMax"); this.textureState = par1NBTTagCompound.getByte("textureState"); - this.scaleFactor = par1NBTTagCompound.getFloat("scaleFactor"); } @Override diff --git a/src/main/java/StevenDimDoors/mod_pocketDimClient/RenderMobObelisk.java b/src/main/java/StevenDimDoors/mod_pocketDimClient/RenderMobObelisk.java index b21e084..48dbfa9 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDimClient/RenderMobObelisk.java +++ b/src/main/java/StevenDimDoors/mod_pocketDimClient/RenderMobObelisk.java @@ -63,25 +63,18 @@ public class RenderMobObelisk extends RenderLiving GL11.glDisable(GL11.GL_DEPTH_TEST); GL11.glDepthMask(false); GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); - this.mainModel.onGround = this.renderSwingProgress(par1EntityLivingBase, par9); try { float interpolatedYaw = this.interpolateRotation(par1EntityLivingBase.prevRenderYawOffset, par1EntityLivingBase.renderYawOffset, par9); - float interpolatedYawHead = this.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; + this.rotateCorpse(par1EntityLivingBase, 0, 0, par9); 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); - - this.renderModel(par1EntityLivingBase, 0, 0, rotation, interpolatedYawHead - interpolatedYaw, pitch, f6); + GL11.glRotatef(interpolatedYaw , 0.0F, 1.0F, 0.0F); + GL11.glRotatef(((MobMonolith)par1EntityLivingBase).pitchLevel , 1.0F, 0.0F, 0.0F); + this.renderModel(par1EntityLivingBase, 0, 0, 0,0, 0, 0); OpenGlHelper.setActiveTexture(OpenGlHelper.lightmapTexUnit); GL11.glDisable(GL11.GL_TEXTURE_2D); From be7cd9d1864008b76e7bfd9ddb18a6a8cc17a8ef Mon Sep 17 00:00:00 2001 From: StevenRS11 Date: Tue, 15 Apr 2014 04:30:31 -0400 Subject: [PATCH 076/187] More eye tweaks --- .../mod_pocketDim/ticking/MobMonolith.java | 16 +++++++++++----- .../mod_pocketDimClient/RenderMobObelisk.java | 16 +++++++++++++--- 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/ticking/MobMonolith.java b/src/main/java/StevenDimDoors/mod_pocketDim/ticking/MobMonolith.java index d06ffac..6d18cb6 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/ticking/MobMonolith.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/ticking/MobMonolith.java @@ -100,6 +100,12 @@ public class MobMonolith extends EntityFlying implements IMob { return false; } + + @Override + public float getEyeHeight() + { + return this.height +2F; + } public void setEntityPosition(Entity entity, double x, double y, double z) { @@ -206,14 +212,14 @@ public class MobMonolith extends EntityFlying implements IMob this.playSound(mod_pocketDim.modid+":monk", 1F, 1F); this.soundTime=100; } - if ((aggroPercent>.80)&&this.soundTime<100) + if ((aggroPercent>.70)&&this.soundTime<100) { - this.worldObj.playSoundEffect(entityPlayer.posX, entityPlayer.posY, entityPlayer.posZ,mod_pocketDim.modid+":tearing",2, 1F); - this.soundTime=200; + 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>.95)&&this.soundTime<200) + if ((aggroPercent>.90)&&this.soundTime<200) { - this.worldObj.playSoundEffect(entityPlayer.posX, entityPlayer.posY, entityPlayer.posZ,mod_pocketDim.modid+":tearing",5, 1F); + this.worldObj.playSoundEffect(entityPlayer.posX, entityPlayer.posY, entityPlayer.posZ,mod_pocketDim.modid+":tearing",7, 1F); this.soundTime=250; } this.soundTime--; diff --git a/src/main/java/StevenDimDoors/mod_pocketDimClient/RenderMobObelisk.java b/src/main/java/StevenDimDoors/mod_pocketDimClient/RenderMobObelisk.java index 48dbfa9..8cb4f97 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDimClient/RenderMobObelisk.java +++ b/src/main/java/StevenDimDoors/mod_pocketDimClient/RenderMobObelisk.java @@ -63,18 +63,28 @@ public class RenderMobObelisk extends RenderLiving GL11.glDisable(GL11.GL_DEPTH_TEST); GL11.glDepthMask(false); GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); + this.mainModel.onGround = this.renderSwingProgress(par1EntityLivingBase, par9); try { float interpolatedYaw = this.interpolateRotation(par1EntityLivingBase.prevRenderYawOffset, par1EntityLivingBase.renderYawOffset, par9); + float interpolatedYawHead = this.interpolateRotation(par1EntityLivingBase.prevRotationYawHead, par1EntityLivingBase.rotationYawHead, par9); + float rotation; + float pitch = par1EntityLivingBase.prevRotationPitch + (par1EntityLivingBase.rotationPitch - par1EntityLivingBase.prevRotationPitch) * par9; this.renderLivingAt(par1EntityLivingBase, x, y, z); - this.rotateCorpse(par1EntityLivingBase, 0, 0, par9); + + 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.glRotatef(interpolatedYaw , 0.0F, 1.0F, 0.0F); GL11.glRotatef(((MobMonolith)par1EntityLivingBase).pitchLevel , 1.0F, 0.0F, 0.0F); - this.renderModel(par1EntityLivingBase, 0, 0, 0,0, 0, 0); + + GL11.glTranslatef(0.0F, -24.0F * f6 - 0.0078125F, 0.0F); + + this.renderModel(par1EntityLivingBase, 0, 0, rotation, interpolatedYawHead - interpolatedYaw, pitch, f6); OpenGlHelper.setActiveTexture(OpenGlHelper.lightmapTexUnit); GL11.glDisable(GL11.GL_TEXTURE_2D); From 3664e707cf2c2b0b8f9234a50cb85a9b86f85217 Mon Sep 17 00:00:00 2001 From: StevenRS11 Date: Tue, 15 Apr 2014 07:27:08 -0400 Subject: [PATCH 077/187] Fixed minor issues Doors render right now No longer placing doors on left clicks --- .../mod_pocketDim/EventHookContainer.java | 6 +- .../mod_pocketDim/blocks/BaseDimDoor.java | 25 ++++++-- .../mod_pocketDimClient/RenderDimDoor.java | 63 ++++++++++--------- 3 files changed, 60 insertions(+), 34 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java b/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java index aa04337..9f7fd0c 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java @@ -17,6 +17,7 @@ import net.minecraftforge.event.ForgeSubscribe; import net.minecraftforge.event.entity.living.LivingDeathEvent; import net.minecraftforge.event.entity.living.LivingFallEvent; import net.minecraftforge.event.entity.player.PlayerInteractEvent; +import net.minecraftforge.event.entity.player.PlayerInteractEvent.Action; import net.minecraftforge.event.terraingen.InitMapGenEvent; import net.minecraftforge.event.world.WorldEvent; import StevenDimDoors.mod_pocketDim.blocks.BaseDimDoor; @@ -84,7 +85,10 @@ public class EventHookContainer public void onPlayerEvent(PlayerInteractEvent event) { // Handle all door placement here - + if(event.action == Action.LEFT_CLICK_BLOCK) + { + return; + } World world = event.entity.worldObj; ItemStack stack = event.entityPlayer.inventory.getCurrentItem(); if (stack != null && stack.getItem() instanceof ItemDoor) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BaseDimDoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BaseDimDoor.java index 9c56e91..1b85af9 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BaseDimDoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BaseDimDoor.java @@ -179,11 +179,30 @@ public abstract class BaseDimDoor extends BlockDoor implements IDimDoor, ITileEn if (tile instanceof TileEntityDimDoor) { TileEntityDimDoor dimTile = (TileEntityDimDoor) tile; - dimTile.openOrClosed = PocketManager.getLink(x, y, z, world.provider.dimensionId) != null; + dimTile.openOrClosed = this.isDoorOnRift(world, x, y, z); dimTile.orientation = this.getFullMetadata(world, x, y, z) & 7; } return this; } + + public boolean isDoorOnRift(World world, int x, int y, int z) + { + if(this.isUpperDoorBlock( world.getBlockMetadata(x, y, z))) + { + if(PocketManager.getLink(x, y, z, world.provider.dimensionId) != null||PocketManager.getLink(x, y-1, z, world.provider.dimensionId) != null) + { + return true; + } + } + else + { + if(PocketManager.getLink(x, y, z, world.provider.dimensionId) != null||PocketManager.getLink(x, y+1, z, world.provider.dimensionId) != null) + { + return true; + } + } + return false; + } /** * Is this block (a) opaque and (b) a full 1m cube? This determines whether or not to render the shared face of two @@ -192,9 +211,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 diff --git a/src/main/java/StevenDimDoors/mod_pocketDimClient/RenderDimDoor.java b/src/main/java/StevenDimDoors/mod_pocketDimClient/RenderDimDoor.java index 6639974..23e72bb 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDimClient/RenderDimDoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDimClient/RenderDimDoor.java @@ -42,15 +42,7 @@ 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; @@ -215,62 +207,61 @@ public class RenderDimDoor extends TileEntitySpecialRenderer } GL11.glColor4d(var21 * var17, var22 * var17, var23 * var17, 1.0F); - if (tile.openOrClosed) - { + switch (tile.orientation) { case 0: - GL11.glVertex3d(x + .01F, y - 1, z); - GL11.glVertex3d(x + .01, y - 1, z + 1.0D); + GL11.glVertex3d(x + .01F, y, z); + GL11.glVertex3d(x + .01, y , z + 1.0D); GL11.glVertex3d(x + .01, y + 1, z + 1.0D); GL11.glVertex3d(x + .01, y + 1, z); break; 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 , z + .01); + GL11.glVertex3d(x, y , z + .01); break; case 2: GL11.glVertex3d(x + .99, y + 1, z); GL11.glVertex3d(x + .99, y + 1, z + 1.0D); - GL11.glVertex3d(x + .99, y - 1, z + 1.0D); - GL11.glVertex3d(x + .99, y - 1, z); + GL11.glVertex3d(x + .99, y , z + 1.0D); + GL11.glVertex3d(x + .99, y , z); break; case 3: - GL11.glVertex3d(x, y - 1, z + .99); - GL11.glVertex3d(x + 1, y - 1, z + .99); + GL11.glVertex3d(x, y , z + .99); + GL11.glVertex3d(x + 1, y , 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 + .15, y - 1, z + 1.0D); + GL11.glVertex3d(x + .15F, y , z); + GL11.glVertex3d(x + .15, y , z + 1.0D); GL11.glVertex3d(x + .15, y + 1, z + 1.0D); GL11.glVertex3d(x + .15, y + 1, z); break; case 5: GL11.glVertex3d(x, y + 1, z + .15); GL11.glVertex3d(x + 1, y + 1, z + .15); - GL11.glVertex3d(x + 1, y - 1, z + .15); - GL11.glVertex3d(x, y - 1, z + .15); + GL11.glVertex3d(x + 1, y , z + .15); + GL11.glVertex3d(x, y , z + .15); break; case 6: GL11.glVertex3d(x + .85, y + 1, z); GL11.glVertex3d(x + .85, y + 1, z + 1.0D); - GL11.glVertex3d(x + .85, y - 1, z + 1.0D); - GL11.glVertex3d(x + .85, y - 1, z); + GL11.glVertex3d(x + .85, y , z + 1.0D); + GL11.glVertex3d(x + .85, y , z); break; case 7: - GL11.glVertex3d(x, y - 1, z + .85); - GL11.glVertex3d(x + 1, y - 1, z + .85); + GL11.glVertex3d(x, y , z + .85); + GL11.glVertex3d(x + 1, y , z + .85); GL11.glVertex3d(x + 1, y + 1, z + .85); GL11.glVertex3d(x, y + 1, z + .85); break; } - } + GL11.glEnd(); @@ -299,7 +290,21 @@ public class RenderDimDoor extends TileEntitySpecialRenderer { 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); + } } } } From 871d2ff1c218ba2622101a304645ccf759354454 Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Sat, 19 Apr 2014 04:28:12 -0400 Subject: [PATCH 078/187] Fixed Golden Door Item ID Mishandling Keybounce noticed that he was having a persistent item ID conflict with DD's Golden Doors - the normal doors not the dimensional variant. I discovered that we have been assigning them the same ID as the Golden Door block ever since they were first introduced 7 months ago. It didn't break immediately since Forge adds +256 to item IDs. --- src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java b/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java index 7b37e1d..8e1ee94 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java @@ -206,7 +206,7 @@ public class mod_pocketDim 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")); - itemGoldenDoor = (new ItemGoldDoor(properties.GoldenDoorID, Material.wood)).setUnlocalizedName("itemGoldDoor"); + 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"); From b15a8af299061bdf3a5c2f29bdd25783fc16247f Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Wed, 30 Apr 2014 04:40:33 -0400 Subject: [PATCH 079/187] Minor Change Minor change to a line in CustomLimboPopulator. We should access static fields through their classes, not instances. --- .../mod_pocketDim/ticking/CustomLimboPopulator.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/ticking/CustomLimboPopulator.java b/src/main/java/StevenDimDoors/mod_pocketDim/ticking/CustomLimboPopulator.java index 2f4522a..ddc018c 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; @@ -65,7 +64,7 @@ public class CustomLimboPopulator implements IRegularTickReceiver { limboWorld = PocketManager.loadDimension(properties.LimboDimensionID); } placeMonolithsInLimbo(limboWorld, location.ChunkX, location.ChunkZ); - mod_pocketDim.instance.gatewayGenerator.generate(limboWorld.rand, location.ChunkX, location.ChunkZ, + mod_pocketDim.gatewayGenerator.generate(limboWorld.rand, location.ChunkX, location.ChunkZ, limboWorld, limboWorld.getChunkProvider(), limboWorld.getChunkProvider()); } else From 9003d924ea164f7d82105439a9347e8404131753 Mon Sep 17 00:00:00 2001 From: StevenRS11 Date: Mon, 5 May 2014 19:10:58 -0400 Subject: [PATCH 080/187] Fixed Door Render --- .../mod_pocketDim/blocks/BaseDimDoor.java | 3 +- .../mod_pocketDimClient/RenderDimDoor.java | 34 +++++++++---------- 2 files changed, 19 insertions(+), 18 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BaseDimDoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BaseDimDoor.java index 1b85af9..3b94723 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BaseDimDoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BaseDimDoor.java @@ -178,8 +178,9 @@ public abstract class BaseDimDoor extends BlockDoor implements IDimDoor, ITileEn TileEntity tile = world.getBlockTileEntity(x, y, z); if (tile instanceof TileEntityDimDoor) { + int metadata = world.getBlockMetadata(x, y, z); TileEntityDimDoor dimTile = (TileEntityDimDoor) tile; - dimTile.openOrClosed = this.isDoorOnRift(world, x, y, z); + dimTile.openOrClosed = this.isDoorOnRift(world, x, y, z)&&this.isUpperDoorBlock(metadata); dimTile.orientation = this.getFullMetadata(world, x, y, z) & 7; } return this; diff --git a/src/main/java/StevenDimDoors/mod_pocketDimClient/RenderDimDoor.java b/src/main/java/StevenDimDoors/mod_pocketDimClient/RenderDimDoor.java index 23e72bb..aad9ef5 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDimClient/RenderDimDoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDimClient/RenderDimDoor.java @@ -213,50 +213,50 @@ public class RenderDimDoor extends TileEntitySpecialRenderer { case 0: - GL11.glVertex3d(x + .01F, y, z); - GL11.glVertex3d(x + .01, y , z + 1.0D); + GL11.glVertex3d(x + .01F, y - 1, z); + GL11.glVertex3d(x + .01, y - 1, z + 1.0D); GL11.glVertex3d(x + .01, y + 1, z + 1.0D); GL11.glVertex3d(x + .01, y + 1, z); break; case 1: GL11.glVertex3d(x, y + 1, z + .01); GL11.glVertex3d(x + 1, y + 1, z + .01); - GL11.glVertex3d(x + 1, y , z + .01); - GL11.glVertex3d(x, y , 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); GL11.glVertex3d(x + .99, y + 1, z + 1.0D); - GL11.glVertex3d(x + .99, y , z + 1.0D); - GL11.glVertex3d(x + .99, y , z); + GL11.glVertex3d(x + .99, y - 1, z + 1.0D); + GL11.glVertex3d(x + .99, y - 1, z); break; case 3: - GL11.glVertex3d(x, y , z + .99); - GL11.glVertex3d(x + 1, y , 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 , z); - GL11.glVertex3d(x + .15, y , z + 1.0D); + 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); break; case 5: GL11.glVertex3d(x, y + 1, z + .15); GL11.glVertex3d(x + 1, y + 1, z + .15); - GL11.glVertex3d(x + 1, y , z + .15); - GL11.glVertex3d(x, y , z + .15); + GL11.glVertex3d(x + 1, y - 1, z + .15); + GL11.glVertex3d(x, y - 1, z + .15); break; case 6: GL11.glVertex3d(x + .85, y + 1, z); GL11.glVertex3d(x + .85, y + 1, z + 1.0D); - GL11.glVertex3d(x + .85, y , z + 1.0D); - GL11.glVertex3d(x + .85, y , z); + GL11.glVertex3d(x + .85, y - 1, z + 1.0D); + GL11.glVertex3d(x + .85, y - 1, z); break; case 7: - GL11.glVertex3d(x, y , z + .85); - GL11.glVertex3d(x + 1, y , z + .85); + GL11.glVertex3d(x, y - 1, z + .85); + GL11.glVertex3d(x + 1, y - 1, z + .85); GL11.glVertex3d(x + 1, y + 1, z + .85); GL11.glVertex3d(x, y + 1, z + .85); break; @@ -307,4 +307,4 @@ public class RenderDimDoor extends TileEntitySpecialRenderer } } } -} +} \ No newline at end of file From 7cabf75128db91f50ab782d5f25f37066e6124b0 Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Mon, 5 May 2014 19:55:16 -0400 Subject: [PATCH 081/187] Overhauled Monoliths Removed lots of obsolete and unused code from Monoliths. The code is subdivided more clearly now. The aggro level is sent over a data watcher instead of sending the texture state. --- .../mod_pocketDim/ticking/MobMonolith.java | 246 +++++++++--------- .../mod_pocketDimClient/RenderMobObelisk.java | 49 ++-- 2 files changed, 147 insertions(+), 148 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/ticking/MobMonolith.java b/src/main/java/StevenDimDoors/mod_pocketDim/ticking/MobMonolith.java index 6d18cb6..b384d1f 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/ticking/MobMonolith.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/ticking/MobMonolith.java @@ -2,22 +2,16 @@ 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.mod_pocketDim; import StevenDimDoors.mod_pocketDim.config.DDProperties; import StevenDimDoors.mod_pocketDim.core.DDTeleporter; @@ -27,26 +21,27 @@ import StevenDimDoors.mod_pocketDim.world.PocketProvider; public class MobMonolith extends EntityFlying implements IMob { - public static final int MAX_AGGRO_RANGE = 35; - public static final int MAX_SOUND_COOLDOWN = 200; - public static final float MAX_AGGRO = 100; - public static final int TEXTURE_STATES = 18; + public static final byte MAX_AGGRO = 100; + 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; - - public float aggro = 0; - private float soundTime = 0; - private byte textureState = 0; - - private int aggroMax; + private byte aggro = 0; + private int soundTime = 0; private static DDProperties properties = null; public MobMonolith(World par1World) { super(par1World); - this.setSize(3F, 3F); - this.noClip=true; - this.aggroMax = rand.nextInt(245)+200; + this.setSize(WIDTH, HEIGHT); + this.noClip = true; if (properties == null) properties = DDProperties.instance(); } @@ -66,10 +61,17 @@ public class MobMonolith extends EntityFlying implements IMob } else { - this.aggro = this.aggroMax; + this.aggro = MAX_AGGRO; } return false; } + + @Override + public boolean canBreatheUnderwater() + { + return true; + } + @Override public AxisAlignedBB getBoundingBox() { @@ -104,22 +106,15 @@ public class MobMonolith extends EntityFlying implements IMob @Override public float getEyeHeight() { - return this.height +2F; - } - - 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 byte for the aggro level + this.dataWatcher.addObject(AGGRO_WATCHER_INDEX, Byte.valueOf((byte) 0)); } @Override @@ -131,103 +126,124 @@ 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(); - - EntityPlayer entityPlayer = this.worldObj.getClosestPlayerToEntity(this,MAX_AGGRO_RANGE); - //need to always manage aggro level, even if player is out of range. - this.setAggroLevel(entityPlayer); + super.onEntityUpdate(); + + // 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) ? this.canEntityBeSeen(player) : false; + this.updateAggroLevel(player, visibility); - //these things only matter if the player is in range. - if (entityPlayer != null) + // Change orientation and face a player if one is in range + if (player != null) { - this.faceEntity(entityPlayer, 1, 1); - this.playSounds(entityPlayer); - //teleport the player if the conditions are met - if (aggro >= MAX_AGGRO && !this.worldObj.isRemote && properties.MonolithTeleportationEnabled && !entityPlayer.capabilities.isCreativeMode) + this.facePlayer(player); + this.playSounds(player); + + if (visibility) { - Point4D destination = LimboProvider.getLimboSkySpawn(entityPlayer, properties); - DDTeleporter.teleportEntity(entityPlayer, destination, false); - this.aggro = 0; - entityPlayer.worldObj.playSoundAtEntity(entityPlayer,mod_pocketDim.modid+":crack",13, 1); + this.spawnParticles(player); + + // Teleport the target player if various conditions are met + if (aggro >= MAX_AGGRO && !this.worldObj.isRemote && + properties.MonolithTeleportationEnabled && !player.capabilities.isCreativeMode) + { + this.aggro = 0; + Point4D destination = LimboProvider.getLimboSkySpawn(player, properties); + DDTeleporter.teleportEntity(player, destination, false); + player.worldObj.playSoundAtEntity(player, mod_pocketDim.modid + ":crack", 13, 1); + } } } } - private void setAggroLevel(EntityPlayer player) + private void updateAggroLevel(EntityPlayer player, boolean visibility) { - //aggro constantly decreases at a rate that varies with the current amount of aggro. - if(aggro > 0) + // 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) { - this.aggro = this.aggro -(this.aggro/25); - } - if(player != null) - { - //monoliths increase aggro slightly if the player is near, but slowly and to a cap. - float distance = this.getDistanceToEntity(player); - aggro+= 1.5-(distance/this.MAX_AGGRO_RANGE); - - //rapidly increase aggro if the monolith has line of sight to the player. - if(player.canEntityBeSeen(this)) - { - //prevent monoliths from teleporting the player in limbo - if(this.worldObj.provider instanceof LimboProvider) + // Server side... + if (player != null) + { + // Rapidly increase the aggro level if this Monolith can see the player + if (visibility) { - aggro+=1.5; + if (this.worldObj.provider instanceof LimboProvider) + { + // Don't spawn particles in Limbo since we won't teleport the player + aggro += 1; + } + else + { + // Aggro increases faster outside of Limbo + aggro += 2; + } } else { - this.spawnParticles(player); - aggro+=3; + // Aggro increases slightly if the player is nearby, but this increase is capped + aggro += 2 - (this.getDistanceToEntity(player) / MAX_AGGRO_RANGE); } } + else + { + // Decrease aggro over time + aggro *= 0.98; + } + // Clamp the aggro level + aggro = (byte) MathHelper.clamp_int(aggro, 0, MAX_AGGRO_RANGE); + this.dataWatcher.updateObject(AGGRO_WATCHER_INDEX, Byte.valueOf(aggro)); } - - //convert the aggro counter to one of the texture states, and set it. - this.textureState = (byte) ((this.TEXTURE_STATES/this.MAX_AGGRO)*this.aggro); - if(this.textureState>TEXTURE_STATES) + else { - textureState = TEXTURE_STATES; - } - if (!this.worldObj.isRemote) - { - this.dataWatcher.updateObject(16, Byte.valueOf(this.textureState)); + // Client side... + aggro = this.dataWatcher.getWatchableObjectByte(AGGRO_WATCHER_INDEX); } } + public int getTextureState() + { + // 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 = (aggro/MAX_AGGRO); - if(this.soundTime<=0) + float aggroPercent = this.getAggroProgress(); + if (this.soundTime <= 0) { - this.playSound(mod_pocketDim.modid+":monk", 1F, 1F); - this.soundTime=100; + this.playSound(mod_pocketDim.modid + ":monk", 1F, 1F); + this.soundTime = 100; } - if ((aggroPercent>.70)&&this.soundTime<100) + if ((aggroPercent > 0.70) && this.soundTime < 100) { - 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); + 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>.90)&&this.soundTime<200) + if ((aggroPercent > 0.90) && this.soundTime < 200) { - this.worldObj.playSoundEffect(entityPlayer.posX, entityPlayer.posY, entityPlayer.posZ,mod_pocketDim.modid+":tearing",7, 1F); - this.soundTime=250; + 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) { - for (int i = 1; i < (10*(aggro/MAX_AGGRO)); ++i) + 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, @@ -237,43 +253,38 @@ public class MobMonolith extends EntityFlying implements IMob } } - @Override - public void faceEntity(Entity par1Entity, float par2, float par3) + public float getAggroProgress() { - double d0 = par1Entity.posX - this.posX; - double d1 = par1Entity.posZ - this.posZ; - double d2 = (par1Entity.posY + par1Entity.getEyeHeight()) - (this.posY +this.getEyeHeight()); + 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; - this.pitchLevel = (float)-((Math.atan(d2/d3) )* 180.0D / Math.PI); - + this.pitchLevel = (float) -((Math.atan(d2/d3) )* 180.0D / Math.PI); this.rotationYaw = f2; - this.rotationYawHead=f2; - this.renderYawOffset=this.rotationYaw; - } - - - - @Override - public void writeEntityToNBT(NBTTagCompound par1NBTTagCompound) - { - super.writeEntityToNBT(par1NBTTagCompound); - par1NBTTagCompound.setFloat("soundTime", this.soundTime); - par1NBTTagCompound.setFloat("aggro", this.aggro); - par1NBTTagCompound.setInteger("aggroMax", this.aggroMax); - par1NBTTagCompound.setByte("textureState", this.textureState); + this.rotationYawHead = f2; + this.renderYawOffset = this.rotationYaw; } @Override - public void readEntityFromNBT(NBTTagCompound par1NBTTagCompound) + public void writeEntityToNBT(NBTTagCompound rootTag) { - super.readEntityFromNBT(par1NBTTagCompound); - this.soundTime = par1NBTTagCompound.getFloat("soundTime"); + super.writeEntityToNBT(rootTag); + rootTag.setInteger("Aggro", this.aggro); + } + + @Override + public void readEntityFromNBT(NBTTagCompound rootTag) + { + super.readEntityFromNBT(rootTag); - //make them load with half aggro so they dont instantly teleport players - this.aggro = par1NBTTagCompound.getFloat("aggro")/2; - this.aggroMax = par1NBTTagCompound.getInteger("aggroMax"); - this.textureState = par1NBTTagCompound.getByte("textureState"); + // Load Monoliths with half aggro so they don't teleport players instantly + this.aggro = (byte) (rootTag.getInteger("Aggro") / 2); } @Override @@ -282,7 +293,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) { @@ -290,7 +301,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)) @@ -302,9 +313,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_pocketDimClient/RenderMobObelisk.java b/src/main/java/StevenDimDoors/mod_pocketDimClient/RenderMobObelisk.java index 8cb4f97..d033509 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,8 +64,8 @@ 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); @@ -108,29 +105,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 From 928adab4cfced202d4e49dff0ab98ced9bc76e05 Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Mon, 5 May 2014 19:56:21 -0400 Subject: [PATCH 082/187] Minor Change in RiftRegenerator Removed an unnecessary cast in RiftRegenerator --- .../StevenDimDoors/mod_pocketDim/ticking/RiftRegenerator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/ticking/RiftRegenerator.java b/src/main/java/StevenDimDoors/mod_pocketDim/ticking/RiftRegenerator.java index a50907b..192669c 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/ticking/RiftRegenerator.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/ticking/RiftRegenerator.java @@ -33,7 +33,7 @@ public class RiftRegenerator implements IRegularTickReceiver { { // 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()); + List loadedWorlds = Arrays.asList(DimensionManager.getIDs()); for (Integer dimensionID : loadedWorlds) { NewDimData dimension = PocketManager.getDimensionData(dimensionID); From f427e66f6e4dd40f6f58d84582239800e2639edd Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Mon, 5 May 2014 22:37:14 -0400 Subject: [PATCH 083/187] More Changes to Monoliths * Fixed issue with Monoliths detecting players through walls * Changed aggro values from bytes to shorts * Fixed aggro updates so that aggro levels can decrease * Fixed upper bound on aggro clamping * Added client/server-side checks to a few functions to save on performing pointless checks, such as making calculations for spawning particles on the server --- .../mod_pocketDim/ticking/MobMonolith.java | 72 +++++++++++-------- 1 file changed, 41 insertions(+), 31 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/ticking/MobMonolith.java b/src/main/java/StevenDimDoors/mod_pocketDim/ticking/MobMonolith.java index b384d1f..ea65492 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/ticking/MobMonolith.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/ticking/MobMonolith.java @@ -21,7 +21,8 @@ import StevenDimDoors.mod_pocketDim.world.PocketProvider; public class MobMonolith extends EntityFlying implements IMob { - public static final byte MAX_AGGRO = 100; + private static final short MAX_AGGRO = 200; + private static final short MAX_AGGRO_CAP = 60; private static final int MAX_TEXTURE_STATE = 18; private static final int MAX_SOUND_COOLDOWN = 200; private static final int MAX_AGGRO_RANGE = 35; @@ -32,16 +33,18 @@ public class MobMonolith extends EntityFlying implements IMob private static final float EYE_HEIGHT = HEIGHT / 2; public float pitchLevel; - private byte aggro = 0; + 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); + super(world); this.setSize(WIDTH, HEIGHT); this.noClip = true; + this.aggroCap = (short) this.rand.nextInt(MAX_AGGRO_CAP + 1); if (properties == null) properties = DDProperties.instance(); } @@ -113,8 +116,8 @@ public class MobMonolith extends EntityFlying implements IMob protected void entityInit() { super.entityInit(); - // Add a byte for the aggro level - this.dataWatcher.addObject(AGGRO_WATCHER_INDEX, Byte.valueOf((byte) 0)); + // Add a short for the aggro level + this.dataWatcher.addObject(AGGRO_WATCHER_INDEX, Short.valueOf((short) 0)); } @Override @@ -138,18 +141,26 @@ public class MobMonolith extends EntityFlying implements IMob // 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) ? this.canEntityBeSeen(player) : false; + 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.facePlayer(player); - this.playSounds(player); + if (!this.worldObj.isRemote) + { + // Play sounds on the server side + this.playSounds(player); + } if (visibility) { - this.spawnParticles(player); + // Only spawn particles on the client side and outside Limbo + if (this.worldObj.isRemote && !(this.worldObj.provider instanceof LimboProvider)) + { + this.spawnParticles(player); + } // Teleport the target player if various conditions are met if (aggro >= MAX_AGGRO && !this.worldObj.isRemote && @@ -171,41 +182,40 @@ public class MobMonolith extends EntityFlying implements IMob if (!this.worldObj.isRemote) { // Server side... - if (player != null) + // Rapidly increase the aggro level if this Monolith can see the player + if (visibility) { - // Rapidly increase the aggro level if this Monolith can see the player - if (visibility) + if (this.worldObj.provider instanceof LimboProvider) { - if (this.worldObj.provider instanceof LimboProvider) - { - // Don't spawn particles in Limbo since we won't teleport the player - aggro += 1; - } - else - { - // Aggro increases faster outside of Limbo - aggro += 2; - } + aggro++; } else { - // Aggro increases slightly if the player is nearby, but this increase is capped - aggro += 2 - (this.getDistanceToEntity(player) / MAX_AGGRO_RANGE); + // Aggro increases faster outside of Limbo + aggro += 4; } } else { - // Decrease aggro over time - aggro *= 0.98; + if (aggro >= aggroCap) + { + // Decrease aggro over time + aggro--; + } + else if (player != null) + { + // Increase aggro if a player is within range and aggro < aggroCap + aggro++; + } } // Clamp the aggro level - aggro = (byte) MathHelper.clamp_int(aggro, 0, MAX_AGGRO_RANGE); - this.dataWatcher.updateObject(AGGRO_WATCHER_INDEX, Byte.valueOf(aggro)); + aggro = (short) MathHelper.clamp_int(aggro, 0, MAX_AGGRO); + this.dataWatcher.updateObject(AGGRO_WATCHER_INDEX, Short.valueOf(aggro)); } else { // Client side... - aggro = this.dataWatcher.getWatchableObjectByte(AGGRO_WATCHER_INDEX); + aggro = this.dataWatcher.getWatchableObjectShort(AGGRO_WATCHER_INDEX); } } @@ -284,7 +294,7 @@ public class MobMonolith extends EntityFlying implements IMob super.readEntityFromNBT(rootTag); // Load Monoliths with half aggro so they don't teleport players instantly - this.aggro = (byte) (rootTag.getInteger("Aggro") / 2); + this.aggro = (short) (rootTag.getInteger("Aggro") / 2); } @Override From aab818d9481e62f58d0369da3edb875f2f30ea83 Mon Sep 17 00:00:00 2001 From: StevenRS11 Date: Tue, 6 May 2014 02:23:03 -0400 Subject: [PATCH 084/187] codemunching --- .../mod_pocketDim/ticking/MobMonolith.java | 51 ++++++++----------- .../mod_pocketDimClient/RenderMobObelisk.java | 5 +- 2 files changed, 24 insertions(+), 32 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/ticking/MobMonolith.java b/src/main/java/StevenDimDoors/mod_pocketDim/ticking/MobMonolith.java index ea65492..8e047b1 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/ticking/MobMonolith.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/ticking/MobMonolith.java @@ -22,7 +22,6 @@ import StevenDimDoors.mod_pocketDim.world.PocketProvider; public class MobMonolith extends EntityFlying implements IMob { private static final short MAX_AGGRO = 200; - private static final short MAX_AGGRO_CAP = 60; private static final int MAX_TEXTURE_STATE = 18; private static final int MAX_SOUND_COOLDOWN = 200; private static final int MAX_AGGRO_RANGE = 35; @@ -35,7 +34,6 @@ public class MobMonolith extends EntityFlying implements IMob public float pitchLevel; private short aggro = 0; private int soundTime = 0; - private final short aggroCap; private static DDProperties properties = null; @@ -44,7 +42,6 @@ public class MobMonolith extends EntityFlying implements IMob super(world); this.setSize(WIDTH, HEIGHT); this.noClip = true; - this.aggroCap = (short) this.rand.nextInt(MAX_AGGRO_CAP + 1); if (properties == null) properties = DDProperties.instance(); } @@ -58,11 +55,7 @@ public class MobMonolith extends EntityFlying implements IMob @Override public boolean attackEntityFrom(DamageSource par1DamageSource, float par2) { - if (par1DamageSource == DamageSource.inWall) - { - this.posY = posY + 1; - } - else + if (!(par1DamageSource == DamageSource.inWall)) { this.aggro = MAX_AGGRO; } @@ -181,31 +174,29 @@ public class MobMonolith extends EntityFlying implements IMob // 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) + //Server side.. + //aggro constantly decreases at a rate that varies with the current amount of aggro. + if(aggro > 0) { - if (this.worldObj.provider instanceof LimboProvider) - { - aggro++; - } - else - { - // Aggro increases faster outside of Limbo - aggro += 4; - } + this.aggro -= (short)(this.aggro/(this.MAX_AGGRO/4)); } - else + if(player != null) { - if (aggro >= aggroCap) - { - // Decrease aggro over time - aggro--; - } - else if (player != null) - { - // Increase aggro if a player is within range and aggro < aggroCap - aggro++; + //monoliths increase aggro slightly if the player is near, but slowly and to a cap. + aggro+= 1.5-(this.getDistanceToEntity(player)/this.MAX_AGGRO_RANGE); + + //rapidly increase aggro if the monolith has line of sight to the player. + if(visibility) + { + //reduce the rate at which aggro increases in limbo + if(this.worldObj.provider instanceof LimboProvider) + { + aggro+=1.5; + } + else + { + aggro+=3; + } } } // Clamp the aggro level diff --git a/src/main/java/StevenDimDoors/mod_pocketDimClient/RenderMobObelisk.java b/src/main/java/StevenDimDoors/mod_pocketDimClient/RenderMobObelisk.java index d033509..dc35abd 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDimClient/RenderMobObelisk.java +++ b/src/main/java/StevenDimDoors/mod_pocketDimClient/RenderMobObelisk.java @@ -75,13 +75,14 @@ public class RenderMobObelisk extends RenderLiving float f6 = 0.0625F; GL11.glEnable(GL12.GL_RESCALE_NORMAL); + GL11.glScalef(-1.0F, -1.0F, 1.0F); this.preRenderCallback(par1EntityLivingBase, par9); GL11.glRotatef(((MobMonolith)par1EntityLivingBase).pitchLevel , 1.0F, 0.0F, 0.0F); + GL11.glTranslatef(0.0F, 24.0F * f6 - 0.0078125F, 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); From 79edf1004b4de0f786d28d623cb9dcc2a999b57c Mon Sep 17 00:00:00 2001 From: StevenRS11 Date: Tue, 6 May 2014 03:08:46 -0400 Subject: [PATCH 085/187] tweak --- .../mod_pocketDim/ticking/MobMonolith.java | 49 ++++++++++--------- 1 file changed, 27 insertions(+), 22 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/ticking/MobMonolith.java b/src/main/java/StevenDimDoors/mod_pocketDim/ticking/MobMonolith.java index 8e047b1..4428f63 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/ticking/MobMonolith.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/ticking/MobMonolith.java @@ -22,6 +22,7 @@ import StevenDimDoors.mod_pocketDim.world.PocketProvider; public class MobMonolith extends EntityFlying implements IMob { private static final short MAX_AGGRO = 200; + private static final short MAX_AGGRO_CAP = 100; private static final int MAX_TEXTURE_STATE = 18; private static final int MAX_SOUND_COOLDOWN = 200; private static final int MAX_AGGRO_RANGE = 35; @@ -34,6 +35,7 @@ public class MobMonolith extends EntityFlying implements IMob public float pitchLevel; private short aggro = 0; private int soundTime = 0; + private final short aggroCap; private static DDProperties properties = null; @@ -42,6 +44,7 @@ public class MobMonolith extends EntityFlying implements IMob super(world); this.setSize(WIDTH, HEIGHT); this.noClip = true; + this.aggroCap = (short) (this.rand.nextInt(MAX_AGGRO_CAP + 1)+20); if (properties == null) properties = DDProperties.instance(); } @@ -55,7 +58,7 @@ public class MobMonolith extends EntityFlying implements IMob @Override public boolean attackEntityFrom(DamageSource par1DamageSource, float par2) { - if (!(par1DamageSource == DamageSource.inWall)) + if (par1DamageSource != DamageSource.inWall) { this.aggro = MAX_AGGRO; } @@ -90,7 +93,7 @@ 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 @@ -174,29 +177,31 @@ public class MobMonolith extends EntityFlying implements IMob // If we're working on the client side, retrieve aggro level from dataWatcher if (!this.worldObj.isRemote) { - //Server side.. - //aggro constantly decreases at a rate that varies with the current amount of aggro. - if(aggro > 0) + // Server side... + // Rapidly increase the aggro level if this Monolith can see the player + if (visibility) { - this.aggro -= (short)(this.aggro/(this.MAX_AGGRO/4)); + if (this.worldObj.provider instanceof LimboProvider) + { + aggro++; + } + else + { + // Aggro increases faster outside of Limbo + aggro += 4; + } } - if(player != null) + else { - //monoliths increase aggro slightly if the player is near, but slowly and to a cap. - aggro+= 1.5-(this.getDistanceToEntity(player)/this.MAX_AGGRO_RANGE); - - //rapidly increase aggro if the monolith has line of sight to the player. - if(visibility) - { - //reduce the rate at which aggro increases in limbo - if(this.worldObj.provider instanceof LimboProvider) - { - aggro+=1.5; - } - else - { - aggro+=3; - } + 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++; } } // Clamp the aggro level From f4efa7dca22a7f4aade05335839433db0cbaf889 Mon Sep 17 00:00:00 2001 From: StevenRS11 Date: Tue, 6 May 2014 02:23:03 -0400 Subject: [PATCH 086/187] codemunching --- .../mod_pocketDim/ticking/MobMonolith.java | 51 ++++++++----------- .../mod_pocketDimClient/RenderMobObelisk.java | 5 +- 2 files changed, 24 insertions(+), 32 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/ticking/MobMonolith.java b/src/main/java/StevenDimDoors/mod_pocketDim/ticking/MobMonolith.java index ea65492..8e047b1 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/ticking/MobMonolith.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/ticking/MobMonolith.java @@ -22,7 +22,6 @@ import StevenDimDoors.mod_pocketDim.world.PocketProvider; public class MobMonolith extends EntityFlying implements IMob { private static final short MAX_AGGRO = 200; - private static final short MAX_AGGRO_CAP = 60; private static final int MAX_TEXTURE_STATE = 18; private static final int MAX_SOUND_COOLDOWN = 200; private static final int MAX_AGGRO_RANGE = 35; @@ -35,7 +34,6 @@ public class MobMonolith extends EntityFlying implements IMob public float pitchLevel; private short aggro = 0; private int soundTime = 0; - private final short aggroCap; private static DDProperties properties = null; @@ -44,7 +42,6 @@ public class MobMonolith extends EntityFlying implements IMob super(world); this.setSize(WIDTH, HEIGHT); this.noClip = true; - this.aggroCap = (short) this.rand.nextInt(MAX_AGGRO_CAP + 1); if (properties == null) properties = DDProperties.instance(); } @@ -58,11 +55,7 @@ public class MobMonolith extends EntityFlying implements IMob @Override public boolean attackEntityFrom(DamageSource par1DamageSource, float par2) { - if (par1DamageSource == DamageSource.inWall) - { - this.posY = posY + 1; - } - else + if (!(par1DamageSource == DamageSource.inWall)) { this.aggro = MAX_AGGRO; } @@ -181,31 +174,29 @@ public class MobMonolith extends EntityFlying implements IMob // 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) + //Server side.. + //aggro constantly decreases at a rate that varies with the current amount of aggro. + if(aggro > 0) { - if (this.worldObj.provider instanceof LimboProvider) - { - aggro++; - } - else - { - // Aggro increases faster outside of Limbo - aggro += 4; - } + this.aggro -= (short)(this.aggro/(this.MAX_AGGRO/4)); } - else + if(player != null) { - if (aggro >= aggroCap) - { - // Decrease aggro over time - aggro--; - } - else if (player != null) - { - // Increase aggro if a player is within range and aggro < aggroCap - aggro++; + //monoliths increase aggro slightly if the player is near, but slowly and to a cap. + aggro+= 1.5-(this.getDistanceToEntity(player)/this.MAX_AGGRO_RANGE); + + //rapidly increase aggro if the monolith has line of sight to the player. + if(visibility) + { + //reduce the rate at which aggro increases in limbo + if(this.worldObj.provider instanceof LimboProvider) + { + aggro+=1.5; + } + else + { + aggro+=3; + } } } // Clamp the aggro level diff --git a/src/main/java/StevenDimDoors/mod_pocketDimClient/RenderMobObelisk.java b/src/main/java/StevenDimDoors/mod_pocketDimClient/RenderMobObelisk.java index d033509..dc35abd 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDimClient/RenderMobObelisk.java +++ b/src/main/java/StevenDimDoors/mod_pocketDimClient/RenderMobObelisk.java @@ -75,13 +75,14 @@ public class RenderMobObelisk extends RenderLiving float f6 = 0.0625F; GL11.glEnable(GL12.GL_RESCALE_NORMAL); + GL11.glScalef(-1.0F, -1.0F, 1.0F); this.preRenderCallback(par1EntityLivingBase, par9); GL11.glRotatef(((MobMonolith)par1EntityLivingBase).pitchLevel , 1.0F, 0.0F, 0.0F); + GL11.glTranslatef(0.0F, 24.0F * f6 - 0.0078125F, 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); From 03ab75b80ca703dcffd0eedfbac14cf33f9a8889 Mon Sep 17 00:00:00 2001 From: StevenRS11 Date: Tue, 6 May 2014 03:08:46 -0400 Subject: [PATCH 087/187] tweak --- .../mod_pocketDim/ticking/MobMonolith.java | 49 ++++++++++--------- 1 file changed, 27 insertions(+), 22 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/ticking/MobMonolith.java b/src/main/java/StevenDimDoors/mod_pocketDim/ticking/MobMonolith.java index 8e047b1..4428f63 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/ticking/MobMonolith.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/ticking/MobMonolith.java @@ -22,6 +22,7 @@ import StevenDimDoors.mod_pocketDim.world.PocketProvider; public class MobMonolith extends EntityFlying implements IMob { private static final short MAX_AGGRO = 200; + private static final short MAX_AGGRO_CAP = 100; private static final int MAX_TEXTURE_STATE = 18; private static final int MAX_SOUND_COOLDOWN = 200; private static final int MAX_AGGRO_RANGE = 35; @@ -34,6 +35,7 @@ public class MobMonolith extends EntityFlying implements IMob public float pitchLevel; private short aggro = 0; private int soundTime = 0; + private final short aggroCap; private static DDProperties properties = null; @@ -42,6 +44,7 @@ public class MobMonolith extends EntityFlying implements IMob super(world); this.setSize(WIDTH, HEIGHT); this.noClip = true; + this.aggroCap = (short) (this.rand.nextInt(MAX_AGGRO_CAP + 1)+20); if (properties == null) properties = DDProperties.instance(); } @@ -55,7 +58,7 @@ public class MobMonolith extends EntityFlying implements IMob @Override public boolean attackEntityFrom(DamageSource par1DamageSource, float par2) { - if (!(par1DamageSource == DamageSource.inWall)) + if (par1DamageSource != DamageSource.inWall) { this.aggro = MAX_AGGRO; } @@ -90,7 +93,7 @@ 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 @@ -174,29 +177,31 @@ public class MobMonolith extends EntityFlying implements IMob // If we're working on the client side, retrieve aggro level from dataWatcher if (!this.worldObj.isRemote) { - //Server side.. - //aggro constantly decreases at a rate that varies with the current amount of aggro. - if(aggro > 0) + // Server side... + // Rapidly increase the aggro level if this Monolith can see the player + if (visibility) { - this.aggro -= (short)(this.aggro/(this.MAX_AGGRO/4)); + if (this.worldObj.provider instanceof LimboProvider) + { + aggro++; + } + else + { + // Aggro increases faster outside of Limbo + aggro += 4; + } } - if(player != null) + else { - //monoliths increase aggro slightly if the player is near, but slowly and to a cap. - aggro+= 1.5-(this.getDistanceToEntity(player)/this.MAX_AGGRO_RANGE); - - //rapidly increase aggro if the monolith has line of sight to the player. - if(visibility) - { - //reduce the rate at which aggro increases in limbo - if(this.worldObj.provider instanceof LimboProvider) - { - aggro+=1.5; - } - else - { - aggro+=3; - } + 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++; } } // Clamp the aggro level From 3a2c87cce9872060fc39c58651fba08bbbbd7b70 Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Tue, 6 May 2014 03:32:06 -0400 Subject: [PATCH 088/187] Tweaked Monolith Aggro Rate * Decreased aggro rate to 3 to compensate for Monoliths pre-aggroing up to aggroCap * Clarified aggroCap selection --- .../StevenDimDoors/mod_pocketDim/ticking/MobMonolith.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/ticking/MobMonolith.java b/src/main/java/StevenDimDoors/mod_pocketDim/ticking/MobMonolith.java index 4428f63..e19aa65 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/ticking/MobMonolith.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/ticking/MobMonolith.java @@ -22,7 +22,8 @@ import StevenDimDoors.mod_pocketDim.world.PocketProvider; public class MobMonolith extends EntityFlying implements IMob { private static final short MAX_AGGRO = 200; - private static final short MAX_AGGRO_CAP = 100; + private static final short MAX_AGGRO_CAP = 80; + private static final short MIN_AGGRO_CAP = 20; private static final int MAX_TEXTURE_STATE = 18; private static final int MAX_SOUND_COOLDOWN = 200; private static final int MAX_AGGRO_RANGE = 35; @@ -44,7 +45,7 @@ public class MobMonolith extends EntityFlying implements IMob super(world); this.setSize(WIDTH, HEIGHT); this.noClip = true; - this.aggroCap = (short) (this.rand.nextInt(MAX_AGGRO_CAP + 1)+20); + this.aggroCap = (short) MathHelper.getRandomIntegerInRange(this.rand, MIN_AGGRO_CAP, MAX_AGGRO_CAP); if (properties == null) properties = DDProperties.instance(); } @@ -188,7 +189,7 @@ public class MobMonolith extends EntityFlying implements IMob else { // Aggro increases faster outside of Limbo - aggro += 4; + aggro += 3; } } else From d020dd384bdb05aa3c716ac43d22bcd740df9105 Mon Sep 17 00:00:00 2001 From: StevenRS11 Date: Thu, 15 May 2014 05:53:28 -0400 Subject: [PATCH 089/187] toString ftw --- .../mod_pocketDim/dungeon/pack/DungeonPack.java | 5 +++++ .../mod_pocketDim/dungeon/pack/DungeonType.java | 5 +++++ 2 files changed, 10 insertions(+) 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 4a37e85..732f5df 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/dungeon/pack/DungeonPack.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/dungeon/pack/DungeonPack.java @@ -298,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/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; + } } From 8d1028ccb5077d2935e2cc0cd5721a5a4ab7f394 Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Thu, 15 May 2014 06:45:26 -0400 Subject: [PATCH 090/187] Changes to CraftingManager * Fixed a mistake in the crafting recipe for Golden Dim Doors * Removed static import of fields from mod_pocketDim. There were already qualified references to those fields in some areas. We should be consistent. --- .../mod_pocketDim/CraftingManager.java | 25 +++++++++---------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/CraftingManager.java b/src/main/java/StevenDimDoors/mod_pocketDim/CraftingManager.java index 24e58df..508a041 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/CraftingManager.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/CraftingManager.java @@ -5,7 +5,6 @@ import net.minecraft.block.Block; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import cpw.mods.fml.common.registry.GameRegistry; -import static StevenDimDoors.mod_pocketDim.mod_pocketDim.*; public class CraftingManager { @@ -18,19 +17,19 @@ public class CraftingManager switch (properties.WorldThreadRequirementLevel) { case 1: - GameRegistry.addShapelessRecipe(new ItemStack(itemStableFabric, 1), + GameRegistry.addShapelessRecipe(new ItemStack(mod_pocketDim.itemStableFabric, 1), Item.enderPearl, mod_pocketDim.itemWorldThread); break; case 2: - GameRegistry.addRecipe(new ItemStack(itemStableFabric, 1), + GameRegistry.addRecipe(new ItemStack(mod_pocketDim.itemStableFabric, 1), "yxy", 'x', Item.enderPearl, 'y', mod_pocketDim.itemWorldThread); break; case 3: - GameRegistry.addRecipe(new ItemStack(itemStableFabric, 1), + GameRegistry.addRecipe(new ItemStack(mod_pocketDim.itemStableFabric, 1), " y ", "yxy", " y ", 'x', Item.enderPearl, 'y', mod_pocketDim.itemWorldThread); break; default: - GameRegistry.addRecipe(new ItemStack(itemStableFabric, 1), + GameRegistry.addRecipe(new ItemStack(mod_pocketDim.itemStableFabric, 1), "yyy", "yxy", "yyy", 'x', Item.enderPearl, 'y', mod_pocketDim.itemWorldThread); break; } @@ -38,37 +37,37 @@ public class CraftingManager if (properties.CraftingDimensionalDoorAllowed) { - GameRegistry.addRecipe(new ItemStack(itemDimensionalDoor, 1), + GameRegistry.addRecipe(new ItemStack(mod_pocketDim.itemDimensionalDoor, 1), "yxy", 'x', mod_pocketDim.itemStableFabric, 'y', Item.doorIron); } if (properties.CraftingUnstableDoorAllowed) { - GameRegistry.addRecipe(new ItemStack(itemUnstableDoor, 1), + GameRegistry.addRecipe(new ItemStack(mod_pocketDim.itemUnstableDoor, 1), "yxy", 'x', Item.eyeOfEnder, 'y', mod_pocketDim.itemDimensionalDoor); } if (properties.CraftingWarpDoorAllowed) { - GameRegistry.addRecipe(new ItemStack(itemWarpDoor, 1), + GameRegistry.addRecipe(new ItemStack(mod_pocketDim.itemWarpDoor, 1), "yxy", 'x', mod_pocketDim.itemStableFabric, 'y', Item.doorWood); } if (properties.CraftingTransTrapdoorAllowed) { - GameRegistry.addRecipe(new ItemStack(transTrapdoor, 1), + GameRegistry.addRecipe(new ItemStack(mod_pocketDim.transTrapdoor, 1), "y", "x", "y", 'x', mod_pocketDim.itemStableFabric, 'y', Block.trapdoor); } if (properties.CraftingRiftSignatureAllowed) { - GameRegistry.addRecipe(new ItemStack(itemRiftSignature, 1), + GameRegistry.addRecipe(new ItemStack(mod_pocketDim.itemRiftSignature, 1), " y ", "yxy", " y ", 'x', mod_pocketDim.itemStableFabric, 'y', Item.ingotIron); } if (properties.CraftingRiftRemoverAllowed) { - GameRegistry.addRecipe(new ItemStack(itemRiftRemover, 1), + GameRegistry.addRecipe(new ItemStack(mod_pocketDim.itemRiftRemover, 1), "yyy", "yxy", "yyy", 'x', mod_pocketDim.itemStableFabric, 'y', Item.ingotGold); } if (properties.CraftingRiftBladeAllowed) { - GameRegistry.addRecipe(new ItemStack(itemRiftBlade, 1), + GameRegistry.addRecipe(new ItemStack(mod_pocketDim.itemRiftBlade, 1), "x", "x", "y", 'x', mod_pocketDim.itemStableFabric, 'y', Item.blazeRod); } if (properties.CraftingStabilizedRiftSignatureAllowed) @@ -79,7 +78,7 @@ public class CraftingManager if (properties.CraftingGoldenDimensionalDoorAllowed) { GameRegistry.addRecipe(new ItemStack(mod_pocketDim.itemGoldenDimensionalDoor,1), - "yxy", 'x', mod_pocketDim.itemGoldenDoor, 'y', mod_pocketDim.itemStableFabric); + "yxy", 'x', mod_pocketDim.itemStableFabric, 'y', mod_pocketDim.itemGoldenDoor); } if (properties.CraftingGoldenDoorAllowed) { From ac9b3d73e8e3a48ee2c9a7572e6d12a826dce61c Mon Sep 17 00:00:00 2001 From: StevenRS11 Date: Fri, 16 May 2014 21:42:59 -0400 Subject: [PATCH 091/187] Various Fixed bug in converting old saves Started color work --- .../mod_pocketDim/core/PocketManager.java | 3 +- .../mod_pocketDim/mod_pocketDim.java | 3 ++ .../mod_pocketDim/saving/OldSaveImporter.java | 53 +++++++++++++++---- .../tileentities/DDTileEntityBase.java | 13 +++++ .../tileentities/TileEntityDimDoor.java | 29 +++++++--- .../tileentities/TileEntityRift.java | 18 ++++--- .../tileentities/TileEntityTransTrapdoor.java | 38 ++++++------- .../mod_pocketDimClient/RenderDimDoor.java | 29 +--------- 8 files changed, 110 insertions(+), 76 deletions(-) create mode 100644 src/main/java/StevenDimDoors/mod_pocketDim/tileentities/DDTileEntityBase.java diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/core/PocketManager.java b/src/main/java/StevenDimDoors/mod_pocketDim/core/PocketManager.java index 4eae666..1882bba 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/core/PocketManager.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/core/PocketManager.java @@ -424,7 +424,8 @@ public class PocketManager { 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!"); } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java b/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java index 8e1ee94..239b137 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java @@ -101,6 +101,9 @@ public class mod_pocketDim { public static final String version = "1.6.4-R2.2.3"; 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") diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/saving/OldSaveImporter.java b/src/main/java/StevenDimDoors/mod_pocketDim/saving/OldSaveImporter.java index 42b8d01..bc1a8c9 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/saving/OldSaveImporter.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/saving/OldSaveImporter.java @@ -39,10 +39,39 @@ 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()) { @@ -55,19 +84,21 @@ public class OldSaveImporter newPackedLinkData.add(newPackedLink); allPackedLinks.add(newPackedLink); - } - - 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); + PackedDimData dim; + if(data.isPocket) + { + 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); + } + else + { + dim = new PackedDimData(data.dimID, data.depth, data.depth, data.dimID, data.dimID, 0, data.dungeonGenerator!=null, 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/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..115aa64 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityDimDoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityDimDoor.java @@ -1,8 +1,10 @@ package StevenDimDoors.mod_pocketDim.tileentities; +import java.util.Random; import StevenDimDoors.mod_pocketDim.ServerPacketHandler; import StevenDimDoors.mod_pocketDim.mod_pocketDim; import StevenDimDoors.mod_pocketDim.blocks.IDimDoor; +import StevenDimDoors.mod_pocketDim.core.NewDimData; import StevenDimDoors.mod_pocketDim.core.PocketManager; import net.minecraft.block.Block; import net.minecraft.nbt.NBTTagCompound; @@ -11,7 +13,7 @@ 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; @@ -22,13 +24,9 @@ public class TileEntityDimDoor extends TileEntity @Override public boolean canUpdate() { - return true; + return false; } - @Override - public void updateEntity() - { - } @Override public Packet getDescriptionPacket() { @@ -83,5 +81,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/TileEntityRift.java b/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityRift.java index 135235e..d6e781b 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityRift.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityRift.java @@ -33,7 +33,7 @@ import StevenDimDoors.mod_pocketDim.core.NewDimData; import StevenDimDoors.mod_pocketDim.core.PocketManager; import StevenDimDoors.mod_pocketDim.util.Point4D; -public class TileEntityRift extends TileEntity +public class TileEntityRift extends DDTileEntityBase { private static final int RIFT_INTERACTION_RANGE = 5; private static final int MAX_ANCESTOR_LINKS = 2; @@ -44,7 +44,9 @@ public class TileEntityRift extends TileEntity 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 float[] POCKET_RENDER_COLOR= {1,1,1,.7F}; + private static final float[] DEFAULT_RENDER_COLOR= {1,1,1,1}; + private static Random random = new Random(); private int age = 0; @@ -112,11 +114,7 @@ public class TileEntityRift extends TileEntity updateTimer++; } - @Override - public boolean canUpdate() - { - return true; - } + private void clearBlocksOnRift() { @@ -387,4 +385,10 @@ public class TileEntityRift extends TileEntity { readFromNBT(pkt.data); } + + @Override + public float[] getRenderColor(Random rand) + { + return null; + } } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityTransTrapdoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityTransTrapdoor.java index 125a225..d26b46f 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityTransTrapdoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityTransTrapdoor.java @@ -1,44 +1,36 @@ package StevenDimDoors.mod_pocketDim.tileentities; +import java.util.Random; +import StevenDimDoors.mod_pocketDim.mod_pocketDim; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.tileentity.TileEntity; -public class TileEntityTransTrapdoor extends TileEntity +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_pocketDimClient/RenderDimDoor.java b/src/main/java/StevenDimDoors/mod_pocketDimClient/RenderDimDoor.java index aad9ef5..6e5abea 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDimClient/RenderDimDoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDimClient/RenderDimDoor.java @@ -181,33 +181,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); - + float[] color = tile.getRenderColor(rand); + GL11.glColor4f(color[0] * var17, color[1] * var17, color[2] * var17, color[3]); switch (tile.orientation) { From 8f9dfea947a0803846ba520b7c6813152a8f9f8a Mon Sep 17 00:00:00 2001 From: StevenRS11 Date: Tue, 20 May 2014 03:17:32 -0400 Subject: [PATCH 092/187] added locking doors and cleaned up --- .../mod_pocketDim/blocks/BaseDimDoor.java | 92 ++++++++-- .../mod_pocketDim/blocks/BlockDoorGold.java | 100 +---------- .../mod_pocketDim/blocks/IDimDoor.java | 3 + .../mod_pocketDim/blocks/TransTrapdoor.java | 7 +- .../commands/CommandResetDungeons.java | 4 +- .../mod_pocketDim/config/DDProperties.java | 4 + .../mod_pocketDim/core/DDTeleporter.java | 10 +- .../mod_pocketDim/core/DimLink.java | 59 ++++-- .../mod_pocketDim/core/LinkTail.java | 1 - .../mod_pocketDim/core/NewDimData.java | 168 +++++++++++++----- .../mod_pocketDim/core/PocketManager.java | 97 +--------- .../mod_pocketDim/items/ItemDDKey.java | 73 ++++++++ .../items/ItemDDLockCreator.java | 111 ++++++++++++ .../mod_pocketDim/mod_pocketDim.java | 8 + .../mod_pocketDim/saving/DDSaveHandler.java | 4 +- .../saving/DimDataProcessor.java | 12 +- .../mod_pocketDim/saving/OldSaveImporter.java | 2 +- .../mod_pocketDim/saving/PackedLinkData.java | 4 +- .../tileentities/TileEntityDimDoor.java | 3 +- .../tileentities/TileEntityRift.java | 3 +- .../mod_pocketDim/watcher/ClientLinkData.java | 9 +- .../mod_pocketDim/world/ILockable.java | 6 + .../mod_pocketDim/world/PocketBuilder.java | 4 +- 23 files changed, 507 insertions(+), 277 deletions(-) create mode 100644 src/main/java/StevenDimDoors/mod_pocketDim/items/ItemDDKey.java create mode 100644 src/main/java/StevenDimDoors/mod_pocketDim/items/ItemDDLockCreator.java create mode 100644 src/main/java/StevenDimDoors/mod_pocketDim/world/ILockable.java diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BaseDimDoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BaseDimDoor.java index 3b94723..582f3da 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BaseDimDoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BaseDimDoor.java @@ -1,7 +1,6 @@ package StevenDimDoors.mod_pocketDim.blocks; import java.util.Random; - import net.minecraft.block.Block; import net.minecraft.block.BlockDoor; import net.minecraft.block.ITileEntityProvider; @@ -11,7 +10,7 @@ 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.Item; +import net.minecraft.item.ItemStack; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.Icon; import net.minecraft.util.MathHelper; @@ -22,7 +21,8 @@ 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.items.ItemDDLockCreator; import StevenDimDoors.mod_pocketDim.tileentities.TileEntityDimDoor; import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; @@ -74,6 +74,12 @@ 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) { + + if(!checkCanOpen(world, x, y, z, player)) + { + return false; + } + final int MAGIC_CONSTANT = 1003; int metadata = this.getFullMetadata(world, x, y, z); @@ -92,6 +98,7 @@ public abstract class BaseDimDoor extends BlockDoor implements IDimDoor, ITileEn } world.playAuxSFXAtEntity(player, MAGIC_CONSTANT, x, y, z, 0); + return true; } @@ -188,21 +195,33 @@ public abstract class BaseDimDoor extends BlockDoor implements IDimDoor, ITileEn public boolean isDoorOnRift(World world, int x, int y, int z) { - if(this.isUpperDoorBlock( world.getBlockMetadata(x, y, 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) { - if(PocketManager.getLink(x, y, z, world.provider.dimensionId) != null||PocketManager.getLink(x, y-1, z, world.provider.dimensionId) != null) + return link; + } + + if(isUpperDoorBlock( world.getBlockMetadata(x, y, z))) + { + link = PocketManager.getLink(x, y-1, z, world.provider.dimensionId); + if(link!=null) { - return true; + return link; } } else { - if(PocketManager.getLink(x, y, z, world.provider.dimensionId) != null||PocketManager.getLink(x, y+1, z, world.provider.dimensionId) != null) + link = PocketManager.getLink(x, y+1, z, world.provider.dimensionId); + if(link != null) { - return true; + return link; } } - return false; + return null; } /** @@ -312,6 +331,10 @@ public abstract class BaseDimDoor extends BlockDoor implements IDimDoor, ITileEn @Override public void onNeighborBlockChange(World world, int x, int y, int z, int neighborID) { + if(this.hasLock(world, x, y, z)) + { + return; + } int metadata = world.getBlockMetadata(x, y, z); if (isUpperDoorBlock(metadata)) { @@ -429,16 +452,63 @@ public abstract class BaseDimDoor extends BlockDoor implements IDimDoor, ITileEn } } - public static boolean isUpperDoorBlock(int metadata) + public boolean isUpperDoorBlock(int metadata) { return (metadata & 8) != 0; } - public static boolean isDoorOpen(int metadata) + public boolean isDoorOpen(int metadata) { return (metadata & 4) != 0; } + + public boolean hasLock(World world, int x, int y, int z) + { + DimLink link = getLink(world, x, y, z); + if(link!=null&&link.isLocked()) + { + return true; + } + return false; + } + + 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) + { + if(!hasLock(world, x, y, z)) + { + return true; + } + + if(player == null) + { + return false; + } + DimLink link = getLink(world, x, y, z); + ItemStack itemStack; + + for(ItemStack item : player.inventory.mainInventory) + { + if(item != null) + { + if(item.getItem() instanceof ItemDDKey) + { + if(ItemDDKey.getBoundLink(item)==link) + { + return true; + } + } + } + } + return false; + } + + protected static boolean isEntityFacingDoor(int metadata, EntityLivingBase entity) { // Although any entity has the proper fields for this check, diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockDoorGold.java b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockDoorGold.java index 1e8f91e..2657969 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockDoorGold.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockDoorGold.java @@ -16,109 +16,25 @@ import net.minecraft.world.IBlockAccess; public class BlockDoorGold extends BlockDoor { - @SideOnly(Side.CLIENT) - private Icon[] upperTextures; - @SideOnly(Side.CLIENT) - private Icon[] lowerTextures; - public BlockDoorGold(int par1, Material par2Material) { super(par1, par2Material); } - @Override - @SideOnly(Side.CLIENT) - public void registerIcons(IconRegister iconRegister) - { - 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); - } + @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; } - - /** - * From the specified side and block metadata retrieves the blocks texture. Args: side, metadata - */ - @Override - @SideOnly(Side.CLIENT) - public Icon getIcon(int side, int metadata) - { - return this.upperTextures[0]; - } + - /** - * 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 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 (BaseDimDoor.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 (BaseDimDoor.isUpperDoorBlock(fullMetadata)) - return this.upperTextures[reversed ? 1 : 0]; - else - return this.lowerTextures[reversed ? 1 : 0]; - } - else - { - return this.lowerTextures[0]; - } - } + } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/IDimDoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/IDimDoor.java index b3884dc..9701b15 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/IDimDoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/IDimDoor.java @@ -13,4 +13,7 @@ public interface IDimDoor public int getDrops(); public TileEntity initDoorTE(World world, int x, int y, int z); + + public boolean isDoorOnRift(World world, int x, int y, int z); + } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/TransTrapdoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/TransTrapdoor.java index d1b7fd4..30d74ef 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/TransTrapdoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/TransTrapdoor.java @@ -18,7 +18,6 @@ import StevenDimDoors.mod_pocketDim.core.NewDimData; import StevenDimDoors.mod_pocketDim.core.PocketManager; import StevenDimDoors.mod_pocketDim.tileentities.TileEntityTransTrapdoor; -@SuppressWarnings("deprecation") public class TransTrapdoor extends BlockTrapDoor implements IDimDoor, ITileEntityProvider { @@ -126,4 +125,10 @@ 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; + } } \ 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 f9ed088..0e1d5e2 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandResetDungeons.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandResetDungeons.java @@ -62,11 +62,11 @@ public class CommandResetDungeons extends DDCommandBase { if(link.linkType()==LinkTypes.REVERSE) { - data.createLink(link.source(), LinkTypes.DUNGEON_EXIT, link.orientation()); + data.createLink(link.source(), LinkTypes.DUNGEON_EXIT, link.orientation(), false); } if(link.linkType()==LinkTypes.DUNGEON) { - data.createLink(link.source(), LinkTypes.DUNGEON, link.orientation()); + data.createLink(link.source(), LinkTypes.DUNGEON, link.orientation(), false); } } } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/config/DDProperties.java b/src/main/java/StevenDimDoors/mod_pocketDim/config/DDProperties.java index e41a467..f86c514 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/config/DDProperties.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/config/DDProperties.java @@ -46,6 +46,8 @@ public class DDProperties public final int UnstableDoorItemID; public final int WarpDoorItemID; public final int WorldThreadItemID; + public final int DDKeyItemID; + public final int DDLockCreatorItemID; /** @@ -204,6 +206,8 @@ 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(); + DDLockCreatorItemID = config.getItem("Rift Interlock Item ID", 5682).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(); diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/core/DDTeleporter.java b/src/main/java/StevenDimDoors/mod_pocketDim/core/DDTeleporter.java index 0c95b06..b85f31c 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/core/DDTeleporter.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/core/DDTeleporter.java @@ -485,7 +485,7 @@ public class DDTeleporter { if(PocketManager.isBlackListed(link.destination().getDimension())) { - link=PocketManager.getDimensionData(link.source().getDimension()).createLink(link.link.point,LinkTypes.SAFE_EXIT,link.link.orientation); + link=PocketManager.getDimensionData(link.source().getDimension()).createLink(link.point,LinkTypes.SAFE_EXIT,link.orientation, false); } else { @@ -561,7 +561,7 @@ 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(); @@ -585,7 +585,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)) @@ -617,7 +617,7 @@ 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); } @@ -628,7 +628,7 @@ 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); diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/core/DimLink.java b/src/main/java/StevenDimDoors/mod_pocketDim/core/DimLink.java index 8ee3d9a..ccbd2b3 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/core/DimLink.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/core/DimLink.java @@ -8,27 +8,31 @@ import StevenDimDoors.mod_pocketDim.watcher.ClientLinkData; public abstract class DimLink { - protected ClientLinkData link; + protected Point4D point; + protected int orientation; + protected boolean isLocked; protected DimLink parent; protected LinkTail tail; protected List children; - protected DimLink(ClientLinkData link, DimLink parent) + protected DimLink(Point4D point, int orientation, boolean locked, 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.parent = parent; - this.link = link; + this.point = point; this.tail = parent.tail; + this.orientation = orientation; + this.isLocked = locked; this.children = new LinkedList(); parent.children.add(this); } - protected DimLink(ClientLinkData link, int linkType) + protected DimLink(Point4D point, int orientation, boolean locked, int linkType) { if ((linkType < LinkTypes.ENUM_MIN || linkType > LinkTypes.ENUM_MAX) && linkType != LinkTypes.CLIENT_SIDE) { @@ -36,24 +40,41 @@ public abstract class DimLink } this.parent = null; - this.link = link; + this.point = point; + this.orientation = orientation; + this.isLocked = locked; 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(0, null); + } + public int orientation() { - return link.orientation; - } - - public ClientLinkData link() - { - return link; + return orientation; } public Point4D destination() @@ -93,9 +114,19 @@ public abstract class DimLink { return tail.getLinkType(); } + + public boolean isLocked() + { + return isLocked; + } + + public void setLocked(boolean bol) + { + isLocked = bol; + } public String toString() { - return link.point + " -> " + (hasDestination() ? destination() : ""); + return point + " -> " + (hasDestination() ? destination() : ""); } } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/core/LinkTail.java b/src/main/java/StevenDimDoors/mod_pocketDim/core/LinkTail.java index 887f97e..5513600 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/core/LinkTail.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/core/LinkTail.java @@ -28,5 +28,4 @@ class LinkTail public void setLinkType(int linkType) { this.linkType = linkType; } - } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/core/NewDimData.java b/src/main/java/StevenDimDoors/mod_pocketDim/core/NewDimData.java index 22b783f..03b89b0 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/core/NewDimData.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/core/NewDimData.java @@ -12,21 +12,26 @@ 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.IUpdateWatcher; -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, boolean isLocked) { - super(new ClientLinkData(source, orientation), parent); + super(source, orientation, isLocked, parent); } - public InnerDimLink(Point4D source, int linkType, int orientation) + public InnerDimLink(Point4D source, int linkType, int orientation, boolean isLocked) { - super(new ClientLinkData(source, orientation), linkType); + super(source, orientation, isLocked, linkType); } public void setDestination(int x, int y, int z, NewDimData dimension) @@ -34,26 +39,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) @@ -65,7 +50,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."); @@ -88,7 +73,7 @@ public abstract class NewDimData parent = nextParent; tail = nextParent.tail; nextParent.children.add(this); - this.link.orientation=orientation; + this.orientation=orientation; return true; } @@ -111,7 +96,7 @@ public abstract class NewDimData parent = null; tail = new LinkTail(linkType, null); //Set new orientation - this.link.orientation=orientation; + this.orientation=orientation; } } @@ -294,16 +279,16 @@ public abstract class NewDimData public DimLink createLink(int x, int y, int z, int linkType, int orientation) { - return createLink(new Point4D(x, y, z, id), linkType, orientation); + return createLink(new Point4D(x, y, z, id), linkType, orientation, false); } - public DimLink createLink(Point4D source, int linkType, int orientation) + public DimLink createLink(Point4D source, int linkType, int orientation, boolean locked) { //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); } @@ -316,42 +301,41 @@ public abstract class NewDimData //Link created! if (linkType != LinkTypes.CLIENT_SIDE) { - linkWatcher.onCreated(link.link); + linkWatcher.onCreated(new ClientLinkData(link)); } return link; } public DimLink createChildLink(int x, int y, int z, DimLink parent) { - if (parent == null) - { - throw new IllegalArgumentException("parent cannot be null."); - } - - return createChildLink(new Point4D(x, y, z, id), (InnerDimLink) parent); + return createChildLink(new Point4D(x, y, z, id), (InnerDimLink) parent, false); } - private DimLink createChildLink(Point4D source, InnerDimLink parent) + public DimLink createChildLink(Point4D source, DimLink parent, boolean 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."); + } 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); + 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; @@ -369,7 +353,7 @@ public abstract class NewDimData { linkList.remove(target); //Raise deletion event - linkWatcher.onDeleted(target.link); + linkWatcher.onDeleted(new ClientLinkData(link)); target.clear(); modified = true; } @@ -605,6 +589,102 @@ public abstract class NewDimData 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; + isDungeon = false; + 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.isLocked())); + + 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, + isDungeon, isFilled,packedDungeon, originPoint, ChildIDs, Links, Tails); + // FIXME: IMPLEMENTATION PLZTHX + //I tried + } + + @Override + public String name() + { + return String.valueOf(id); + } + + public String toString() { return "DimID= " + this.id; diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/core/PocketManager.java b/src/main/java/StevenDimDoors/mod_pocketDim/core/PocketManager.java index 1882bba..d2ee19f 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/core/PocketManager.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/core/PocketManager.java @@ -41,7 +41,7 @@ import StevenDimDoors.mod_pocketDim.watcher.UpdateWatcherProxy; */ 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 @@ -59,102 +59,7 @@ public class PocketManager // This constructor is meant for client-side code only super(id, root); } - - 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; - isDungeon = false; - isFilled = false; - depth = Integer.MIN_VALUE; - packDepth = Integer.MIN_VALUE; - origin = null; - orientation = Integer.MIN_VALUE; - dungeon = null; - linkWatcher = null; - } - @Override - public String name() - { - return String.valueOf(id); - } - - @Override - 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.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); - - } - - - } - 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 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..6f64553 --- /dev/null +++ b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemDDKey.java @@ -0,0 +1,73 @@ +package StevenDimDoors.mod_pocketDim.items; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import net.minecraft.client.renderer.texture.IconRegister; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.world.World; +import StevenDimDoors.mod_pocketDim.mod_pocketDim; +import StevenDimDoors.mod_pocketDim.core.DimLink; +import StevenDimDoors.mod_pocketDim.core.PocketManager; + +public class ItemDDKey extends Item +{ + public ItemDDKey(int itemID) + { + super(itemID); + this.setCreativeTab(mod_pocketDim.dimDoorsCreativeTab); + } + + @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 true; + } + + public static void setBoundDoor(ItemStack itemStack, DimLink link) + { + NBTTagCompound tag = new NBTTagCompound(); + + int x = link.source().getX(); + int y = link.source().getY(); + int z = link.source().getZ(); + + tag.setInteger("linkX", x); + tag.setInteger("linkY", y); + tag.setInteger("linkZ", z); + tag.setInteger("linkDimID", link.source().getDimension()); + + itemStack.setTagCompound(tag); + itemStack.setItemDamage(1); + } + + public static DimLink getBoundLink(ItemStack itemStack) + { + if (itemStack.hasTagCompound()) + { + NBTTagCompound tag = itemStack.getTagCompound(); + + Integer x = tag.getInteger("linkX"); + Integer y = tag.getInteger("linkY"); + Integer z = tag.getInteger("linkZ"); + Integer dimID = tag.getInteger("linkDimID"); + + if (x != null && y != null && z != null && dimID != null) + { + return PocketManager.getLink(x, y, z, dimID); + } + } + return null; + } + + +} diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemDDLockCreator.java b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemDDLockCreator.java new file mode 100644 index 0000000..e4c3b45 --- /dev/null +++ b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemDDLockCreator.java @@ -0,0 +1,111 @@ +package StevenDimDoors.mod_pocketDim.items; + +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.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +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.DimLink; +import StevenDimDoors.mod_pocketDim.core.NewDimData; +import StevenDimDoors.mod_pocketDim.core.PocketManager; +import StevenDimDoors.mod_pocketDim.items.ItemRiftSignature.Point4DOrientation; + +public class ItemDDLockCreator extends Item +{ + public ItemDDLockCreator(int itemID) + { + super(itemID); + this.setCreativeTab(mod_pocketDim.dimDoorsCreativeTab); + } + + @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 itemStack) + { + return itemStack.hasTagCompound(); + } + + public boolean onItemUseFirst(ItemStack itemStack, EntityPlayer player, World world, int x, int y, int z, int side, float playerX, float playerY, float playerZ) + { + + int blockID = world.getBlockId(x, y, z); + if(!(Block.blocksList[blockID] instanceof IDimDoor)) + { + return false; + } + DimLink link = PocketManager.getLink(x, y, z, world); + if(link==null) + { + return false; + } + if(itemStack.hasTagCompound()) + { + if(link == getBoundLink(itemStack)) + { + link.setLocked(!link.isLocked()); + return true; + } + return false; + } + setBoundDoor(itemStack,link); + link.setLocked(true); + + return true; + } + + public static void setBoundDoor(ItemStack itemStack, DimLink link) + { + NBTTagCompound tag = new NBTTagCompound(); + + int x = link.source().getX(); + int y = link.source().getY(); + int z = link.source().getZ(); + + + tag.setInteger("linkX", x); + tag.setInteger("linkY", y); + tag.setInteger("linkZ", z); + tag.setInteger("linkDimID", link.source().getDimension()); + + itemStack.setTagCompound(tag); + itemStack.setItemDamage(1); + } + + public DimLink getBoundLink(ItemStack itemStack) + { + if (itemStack.hasTagCompound()) + { + NBTTagCompound tag = itemStack.getTagCompound(); + + Integer x = tag.getInteger("linkX"); + Integer y = tag.getInteger("linkY"); + Integer z = tag.getInteger("linkZ"); + Integer dimID = tag.getInteger("linkDimID"); + + if (x != null && y != null && z != null && dimID != null) + { + return PocketManager.getLink(x, y, z, dimID); + } + } + return null; + } + + public String getItemStackDisplayName(ItemStack par1ItemStack) + { + return StatCollector.translateToLocal(this.getUnlocalizedName(par1ItemStack) + ".name"); + } + +} diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java b/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java index 239b137..ce74df8 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java @@ -42,6 +42,8 @@ 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.ItemDDLockCreator; import StevenDimDoors.mod_pocketDim.items.ItemDimensionalDoor; import StevenDimDoors.mod_pocketDim.items.ItemGoldDimDoor; import StevenDimDoors.mod_pocketDim.items.ItemGoldDoor; @@ -136,6 +138,8 @@ public class mod_pocketDim public static Item itemStableFabric; public static Item itemUnstableDoor; public static Item itemStabilizedLinkSignature; + public static Item itemDDKey; + public static Item itemDDLockCreator; public static BiomeGenBase limboBiome; public static BiomeGenBase pocketBiome; @@ -209,6 +213,8 @@ public class mod_pocketDim 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")); + itemDDKey = (new ItemDDKey(properties.DDKeyItemID)).setUnlocalizedName("itemDDKey"); + itemDDLockCreator = (new ItemDDLockCreator(properties.DDLockCreatorItemID)).setUnlocalizedName("itemDDLockCreator"); 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"); @@ -272,6 +278,8 @@ public class mod_pocketDim LanguageRegistry.addName(itemDimensionalDoor, "Dimensional Door"); LanguageRegistry.addName(itemRiftBlade, "Rift Blade"); LanguageRegistry.addName(itemWorldThread, "World Thread"); + LanguageRegistry.addName(itemDDKey, "Unbound Rift Key"); + LanguageRegistry.addName(itemDDLockCreator, "Unbound Rift Interlock"); /** * Add names for multiblock inventory item diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/saving/DDSaveHandler.java b/src/main/java/StevenDimDoors/mod_pocketDim/saving/DDSaveHandler.java index 28929dc..77e1a4c 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/saving/DDSaveHandler.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/saving/DDSaveHandler.java @@ -197,7 +197,7 @@ public class DDSaveHandler linkType = LinkTypes.NORMAL; } - DimLink link = data.createLink(packedLink.source, linkType, packedLink.orientation); + DimLink link = data.createLink(packedLink.source, linkType, packedLink.orientation, packedLink.locked); Point4D destination = packedLink.tail.destination; if(destination!=null) { @@ -216,7 +216,7 @@ public class DDSaveHandler NewDimData data = PocketManager.getDimensionData(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.locked); } unpackedLinks.add(packedLink); } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/saving/DimDataProcessor.java b/src/main/java/StevenDimDoors/mod_pocketDim/saving/DimDataProcessor.java index 7b3dd39..3164868 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/saving/DimDataProcessor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/saving/DimDataProcessor.java @@ -202,6 +202,8 @@ public class DimDataProcessor extends BaseConfigurationProcessor private PackedLinkData createLinkDataFromJson(JsonReader reader) throws IOException { + boolean locked = false; + Point4D source; Point3D parent; PackedLinkTail tail; @@ -230,9 +232,16 @@ public class DimDataProcessor extends BaseConfigurationProcessor children.add(this.createPointFromJson(reader)); } reader.endArray(); + + if(reader.peek()== JsonToken.NAME) + { + reader.nextName(); + locked = reader.nextBoolean(); + + } reader.endObject(); - return new PackedLinkData(source, parent, tail, orientation, children); + return new PackedLinkData(source, parent, tail, orientation, children, locked); } private PackedDungeonData createDungeonDataFromJson(JsonReader reader) throws IOException { @@ -293,6 +302,7 @@ public class DimDataProcessor extends BaseConfigurationProcessor } linkType = reader.nextInt(); + reader.endObject(); return new PackedLinkTail(destination, linkType); diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/saving/OldSaveImporter.java b/src/main/java/StevenDimDoors/mod_pocketDim/saving/OldSaveImporter.java index bc1a8c9..6ddcb9f 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/saving/OldSaveImporter.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/saving/OldSaveImporter.java @@ -80,7 +80,7 @@ public class OldSaveImporter PackedLinkTail tail = new PackedLinkTail(destintion, link.linkOrientation); 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, false); newPackedLinkData.add(newPackedLink); allPackedLinks.add(newPackedLink); diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/saving/PackedLinkData.java b/src/main/java/StevenDimDoors/mod_pocketDim/saving/PackedLinkData.java index a98b448..0cd62d6 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/saving/PackedLinkData.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/saving/PackedLinkData.java @@ -12,13 +12,15 @@ public class PackedLinkData public final PackedLinkTail tail; public final int orientation; public final List children; + public final boolean locked; - public PackedLinkData(Point4D source, Point3D parent, PackedLinkTail tail, int orientation, List children) + public PackedLinkData(Point4D source, Point3D parent, PackedLinkTail tail, int orientation, List children, boolean locked) { this.source=source; this.parent=parent; this.tail=tail; this.orientation=orientation; this.children=children; + this.locked = locked; } } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityDimDoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityDimDoor.java index 115aa64..638c1a8 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityDimDoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityDimDoor.java @@ -6,6 +6,7 @@ import StevenDimDoors.mod_pocketDim.mod_pocketDim; import StevenDimDoors.mod_pocketDim.blocks.IDimDoor; import StevenDimDoors.mod_pocketDim.core.NewDimData; import StevenDimDoors.mod_pocketDim.core.PocketManager; +import StevenDimDoors.mod_pocketDim.watcher.ClientLinkData; import net.minecraft.block.Block; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.network.packet.Packet; @@ -32,7 +33,7 @@ public class TileEntityDimDoor extends DDTileEntityBase { 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; } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityRift.java b/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityRift.java index d6e781b..a644d6c 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityRift.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityRift.java @@ -32,6 +32,7 @@ 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.watcher.ClientLinkData; public class TileEntityRift extends DDTileEntityBase { @@ -375,7 +376,7 @@ public class TileEntityRift extends DDTileEntityBase { 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; } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/watcher/ClientLinkData.java b/src/main/java/StevenDimDoors/mod_pocketDim/watcher/ClientLinkData.java index 5670542..daa7aa9 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/watcher/ClientLinkData.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/watcher/ClientLinkData.java @@ -11,30 +11,35 @@ public class ClientLinkData { public Point4D point; public int orientation; + public boolean isLocked; public ClientLinkData(DimLink link) { this.point= link.source(); this.orientation=link.orientation(); + this.isLocked = link.isLocked(); } - public ClientLinkData(Point4D point, int orientation) + public ClientLinkData(Point4D point, int orientation, boolean isLocked) { this.point = point; this.orientation=orientation; + this.isLocked = isLocked; } public void write(DataOutputStream output) throws IOException { Point4D.write(point, output); output.writeInt(orientation); + output.writeBoolean(isLocked); } public static ClientLinkData read(DataInputStream input) throws IOException { Point4D point = Point4D.read(input); int orientation = input.readInt(); - return new ClientLinkData(point, orientation); + boolean isLocked = input.readBoolean(); + return new ClientLinkData(point, orientation, isLocked); } } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/world/ILockable.java b/src/main/java/StevenDimDoors/mod_pocketDim/world/ILockable.java new file mode 100644 index 0000000..6265a04 --- /dev/null +++ b/src/main/java/StevenDimDoors/mod_pocketDim/world/ILockable.java @@ -0,0 +1,6 @@ +package StevenDimDoors.mod_pocketDim.world; + +public interface ILockable +{ + +} diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/world/PocketBuilder.java b/src/main/java/StevenDimDoors/mod_pocketDim/world/PocketBuilder.java index f26939b..4d2d3a1 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/world/PocketBuilder.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/world/PocketBuilder.java @@ -66,7 +66,7 @@ public class PocketBuilder if(originLink==null) { int orientation = linkIn.orientation(); - originLink=dimension.createLink(oldLinkPos, LinkTypes.SAFE_EXIT, (orientation+2)%4); + originLink=dimension.createLink(oldLinkPos, LinkTypes.SAFE_EXIT, (orientation+2)%4, false); return false; } //The link that originally created the dungeon on the way in @@ -75,7 +75,7 @@ public class PocketBuilder { int orientation = linkIn.orientation(); dimension.deleteLink(originLink); - dimension.createLink(oldLinkPos, LinkTypes.SAFE_EXIT, (orientation+2)%4); + dimension.createLink(oldLinkPos, LinkTypes.SAFE_EXIT, (orientation+2)%4, false); return false; } NewDimData parent = PocketManager.getDimensionData(incomingLink.source().getDimension()); From ef860e295e493dfc6e3528f57b32035111f7544e Mon Sep 17 00:00:00 2001 From: StevenRS11 Date: Tue, 20 May 2014 19:13:26 -0400 Subject: [PATCH 093/187] more stuffs Lock render is still wip, as are most things. That said, I can render monolith eyes anywhere now. --- .../mod_pocketDim/CraftingManager.java | 59 +++- .../mod_pocketDim/blocks/BaseDimDoor.java | 12 +- .../mod_pocketDim/config/DDProperties.java | 7 +- .../mod_pocketDim/items/ItemDDKey.java | 196 ++++++++++-- .../items/ItemDDLockCreator.java | 111 ------- .../mod_pocketDim/mod_pocketDim.java | 7 +- .../mod_pocketDim/world/ILockable.java | 6 - .../mod_pocketDimClient/RenderDimDoor.java | 297 ++++++++++++------ .../mod_pocketDimClient/RenderRift.java | 2 +- src/main/resources/assets/dimdoors/RIFT.png | Bin 353570 -> 0 bytes src/main/resources/assets/dimdoors/WARP.png | Bin 482376 -> 0 bytes .../dimdoors/textures/other/keyOutline.png | Bin 0 -> 2340 bytes .../textures/other/keyOutlineLight.png | Bin 0 -> 3256 bytes .../dimdoors/textures/other/keyhole.png | Bin 0 -> 16866 bytes .../dimdoors/textures/other/keyholeLight.png | Bin 0 -> 16286 bytes 15 files changed, 439 insertions(+), 258 deletions(-) delete mode 100644 src/main/java/StevenDimDoors/mod_pocketDim/items/ItemDDLockCreator.java delete mode 100644 src/main/java/StevenDimDoors/mod_pocketDim/world/ILockable.java delete mode 100644 src/main/resources/assets/dimdoors/RIFT.png delete mode 100644 src/main/resources/assets/dimdoors/WARP.png create mode 100644 src/main/resources/assets/dimdoors/textures/other/keyOutline.png create mode 100644 src/main/resources/assets/dimdoors/textures/other/keyOutlineLight.png create mode 100644 src/main/resources/assets/dimdoors/textures/other/keyhole.png create mode 100644 src/main/resources/assets/dimdoors/textures/other/keyholeLight.png diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/CraftingManager.java b/src/main/java/StevenDimDoors/mod_pocketDim/CraftingManager.java index 24e58df..063fa44 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/CraftingManager.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/CraftingManager.java @@ -1,15 +1,21 @@ package StevenDimDoors.mod_pocketDim; import StevenDimDoors.mod_pocketDim.config.DDProperties; +import StevenDimDoors.mod_pocketDim.core.DimLink; +import StevenDimDoors.mod_pocketDim.items.ItemDDKey; import net.minecraft.block.Block; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.IInventory; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +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 { - private CraftingManager() { } + CraftingManager() { } public static void registerRecipes(DDProperties properties) { @@ -86,6 +92,55 @@ public class CraftingManager GameRegistry.addRecipe(new ItemStack(mod_pocketDim.itemGoldenDoor, 1), "yy", "yy", "yy", 'y', Item.ingotGold); } + if (properties.CraftingDDKeysAllowed) + { + GameRegistry.addRecipe(new ItemStack(mod_pocketDim.itemDDKey, 1), + " x ", " x ", "yzy", 'y', Item.ingotGold, 'x', Item.ingotIron, 'z', mod_pocketDim.itemStableFabric); + 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 && neighborID != this.blockID) { this.onNeighborBlockChange(world, x, y - 1, z, neighborID); @@ -358,7 +353,7 @@ public abstract class BaseDimDoor extends BlockDoor implements IDimDoor, ITileEn this.dropBlockAsItem(world, x, y, z, metadata, 0); } } - else + else if(!this.hasLock(world, x, y, z)) { boolean powered = world.isBlockIndirectlyGettingPowered(x, y, z) || world.isBlockIndirectlyGettingPowered(x, y + 1, z); if ((powered || neighborID > 0 && Block.blocksList[neighborID].canProvidePower()) && neighborID != this.blockID) @@ -490,7 +485,6 @@ public abstract class BaseDimDoor extends BlockDoor implements IDimDoor, ITileEn return false; } DimLink link = getLink(world, x, y, z); - ItemStack itemStack; for(ItemStack item : player.inventory.mainInventory) { @@ -498,7 +492,7 @@ public abstract class BaseDimDoor extends BlockDoor implements IDimDoor, ITileEn { if(item.getItem() instanceof ItemDDKey) { - if(ItemDDKey.getBoundLink(item)==link) + if(((ItemDDKey) item.getItem()).canKeyOpen(link, item)) { return true; } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/config/DDProperties.java b/src/main/java/StevenDimDoors/mod_pocketDim/config/DDProperties.java index f86c514..8cf94ae 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/config/DDProperties.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/config/DDProperties.java @@ -47,7 +47,6 @@ public class DDProperties public final int WarpDoorItemID; public final int WorldThreadItemID; public final int DDKeyItemID; - public final int DDLockCreatorItemID; /** @@ -77,6 +76,8 @@ public class DDProperties public final boolean CraftingStableFabricAllowed; public final boolean CraftingGoldenDimensionalDoorAllowed; public final boolean CraftingGoldenDoorAllowed; + public final boolean CraftingDDKeysAllowed; + /** * Loot Flags @@ -149,7 +150,8 @@ 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); + 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(); @@ -207,7 +209,6 @@ public class DDProperties 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(); - DDLockCreatorItemID = config.getItem("Rift Interlock Item ID", 5682).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(); diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemDDKey.java b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemDDKey.java index 6f64553..7a74d6a 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemDDKey.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemDDKey.java @@ -1,14 +1,22 @@ 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.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.StatCollector; import net.minecraft.world.World; import StevenDimDoors.mod_pocketDim.mod_pocketDim; +import StevenDimDoors.mod_pocketDim.blocks.IDimDoor; import StevenDimDoors.mod_pocketDim.core.DimLink; import StevenDimDoors.mod_pocketDim.core.PocketManager; @@ -18,8 +26,17 @@ public class ItemDDKey extends Item { super(itemID); this.setCreativeTab(mod_pocketDim.dimDoorsCreativeTab); + this.setMaxStackSize(1); + } + public void addInformation(ItemStack par1ItemStack, EntityPlayer par2EntityPlayer, List par3List, boolean par4) + { + boolean check = (this.isBound(par1ItemStack) ? par3List.add("Bound") : par3List.add("Unbound")); + return; + } + + @Override public void registerIcons(IconRegister par1IconRegister) { @@ -30,44 +47,185 @@ public class ItemDDKey extends Item @SideOnly(Side.CLIENT) public boolean hasEffect(ItemStack par1ItemStack) { - return true; + return !this.isBound(par1ItemStack); } - public static void setBoundDoor(ItemStack itemStack, DimLink link) + 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; + } + 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; + } + //make sure we are not trying to mess with a door thats already locked by someone else + if(!this.canKeyOpen(link, itemStack)&&link.isLocked()) + { + return false; + } + + //see if we can bind this key to this door and lock it + if(setBoundDoor(itemStack, link)) + { + link.setLocked(true); + return false; + } + + //lastly, just see if we can toggle the door's lock state if its locked. + if(this.canKeyOpen(link, itemStack)) + { + link.setLocked(!link.isLocked()); + return false; + } + + return false; + } + + + public boolean setBoundDoor(ItemStack itemStack, DimLink link) + { + //dont bind to a door if we already are bound, or if we dont have permission to lock that door + if(this.isBound(itemStack)|| (!this.canKeyOpen(link, itemStack)&&link.isLocked())) + { + return false; + } + + //dont bind if the door has a lock already on it, but we can still open it. That would waste the key. + if(link.isLocked()) + { + return false; + } + + //init tags + if(!itemStack.hasTagCompound()) + { + this.initNBTTags(itemStack); + } + + //consume this keys ability to create a lock + itemStack.getTagCompound().setBoolean("HasLockedDoor", true); + + //create the tag that binds this door to this key NBTTagCompound tag = new NBTTagCompound(); int x = link.source().getX(); int y = link.source().getY(); int z = link.source().getZ(); - tag.setInteger("linkX", x); - tag.setInteger("linkY", y); - tag.setInteger("linkZ", z); - tag.setInteger("linkDimID", link.source().getDimension()); + tag.setInteger("x", x); + tag.setInteger("y", y); + tag.setInteger("z", z); + tag.setInteger("dim", link.source().getDimension()); - itemStack.setTagCompound(tag); - itemStack.setItemDamage(1); + //add this door's tag to this keys keyring + NBTTagList keyRing = itemStack.getTagCompound().getTagList("DDKeys"); + keyRing.appendTag(tag); + itemStack.getTagCompound().setTag("DDKeys", keyRing); + + return true; + } + + /** + * copies all the tags from the first key onto the second key + * @param givingKey + * @param receivingKey + */ + public void addDoorToKey(ItemStack givingKey, ItemStack receivingKey) + { + //cant copy tags from a key with no tags + if(!givingKey.hasTagCompound()) + { + return; + } + + //initialize the receiving key + if(!receivingKey.hasTagCompound()) + { + this.initNBTTags(receivingKey); + } + + //get the tags + NBTTagCompound recevingTags = receivingKey.getTagCompound(); + NBTTagCompound sendingTags = (NBTTagCompound) givingKey.getTagCompound().copy(); + + //copy over the actual tags + for(int i = 0; i3) + { + 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); + + switch (rotation) + { + case 0: + GL11.glTranslatef(-0.5F, .24F, -0.03F); + break; + case 1: + GL11.glTranslatef(-.5F, .24F, .97F); + break; + case 2: + GL11.glTranslatef(.5F, .24F, .97F); + break; + case 3: + GL11.glTranslatef(0.5F, .24F, -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, .6); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_DST_COLOR); + + } + else + { + bindTexture(keyPath); + GL11.glColor4d(.0, .7, .1, 1); + + 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) { @@ -279,7 +366,13 @@ public class RenderDimDoor extends TileEntitySpecialRenderer if (tile.openOrClosed) { renderDimDoorTileEntity((TileEntityDimDoor) par1TileEntity, par2, par4, par6); + for(int i = 0; i<2; i++ ) + { + this.renderKeyHole(tile, par2, par4, par6, i); + + } } + } } } \ 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..8782e2b 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDimClient/RenderRift.java +++ b/src/main/java/StevenDimDoors/mod_pocketDimClient/RenderRift.java @@ -39,7 +39,7 @@ public class RenderRift extends TileEntitySpecialRenderer GL11.glColor4f(.2F, .2F, .2F, 1F); GL11.glEnable(GL_BLEND); - glBlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ZERO); + glBlendFunc(GL11.GL_SRC_ALPHA_SATURATE,GL_ONE_MINUS_DST_COLOR); /** * just draws the verticies diff --git a/src/main/resources/assets/dimdoors/RIFT.png b/src/main/resources/assets/dimdoors/RIFT.png deleted file mode 100644 index ae24e8345cf895b75575200ba9df599801405842..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 353570 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

>wM@bGLT9uu=8mS?KX#VYNC*7Z}t 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]v{gC%yaU-A8LRE3eb@|9zWCHO*^trv(%vz9 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 UKb1ze%K+hkTz9mjn*03yf4`NGj{pDw diff --git a/src/main/resources/assets/dimdoors/WARP.png b/src/main/resources/assets/dimdoors/WARP.png deleted file mode 100644 index fd8efb2cf443c366ed2bef07c2497db73859650b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 482376 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

DgUST)MLXOLu69o7u=wM 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�dpJ)i9Ze>4UT6p)A#gDC6LWa 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 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 0000000000000000000000000000000000000000..7cc27136e9bd03df33f2577a1b92d52282be23a2 GIT binary patch literal 2340 zcmc(h`9IYE7RTQoGqR3#>_S8;%#5N&mXUpJLS-cR8cI~QugMmZWY1DeBNHxPN`1?| zB-Lb@DGk0PDjBjSWsGG+F?a4iaDTk_hx2%y=lSKFpI)z%fp>R6h^vYN01!@&wjKaL zf))azaDnjR{eK8VEZmV01%QP7e+mM3Y08437SYke4S+aZ0La$?*x(Cv9)M^x0N?xp zFrxyX6n5)uw>t%#Fd?NZdhpyEn7=SD1cc;{M#e5GRRz1t+P&Y z&pWb>HuY=v>GG^y6B2F-F;m)@h<%n_RJVo)@3OnPyI5aL_0JsfG1EshD)j6mc-#3Z zC&P9=M&+@-7O;7=AMEjsM9yf`_MzwN@8bFEY(DmW3S`h(xG5t_hx-emAu4bMdO)5m z_J2XOKW9{a7e~?b98jo8O4RCs)CgCiVxeoL2dFFElqv~OIzxA4U?>9xk=It*dqU}w zC&NY7Sgbx9j}Dyu_Mir78EujMSE}w%q=iWVUPuy+6JcVH%0H$N<%&PhQ!civ2EuTt zmw`vlQ+xF;SLPTy@7>6~v_pA9?nfin)8|@$6zV-e3oY}TL>otowC0!Amb#o8dr?YC z?2hy|KXO=On=8g&4TCY3wM6DMSN*mcS47{D*VJWkTz1=2#DgGy9&a(w5N~%IWUi3% zLj2{^Qq4Og5)jHv4jiA*V#5+{Uh1f|zc9xv@a)rs<9%C*L(thWi)(d>?tA5f6>u20 zEla6{RG&)?qAr}+xLcQcXMl6N5ZACq&AJRf08)yqA}zk z{@NM-Qj*C>dhiRo8X&GlH&U#{6xMO3J6E~!5Hd0sT2RR!MBTsQ(bqW*$G2MjTAV&( z;Bx7AH0!+P9%1~0=!nc>0`=2RoeO{`UWN}9Qhnga)tL2sbs0j27-mmad2zl}xK`cN zfRMA2Wod5=+}11^#b~WdY*>LpthEHrp_QO^rzz#K@%sm#0R}9|Y0IyNJR*!w?=7P( z4xNROFmzi886ZJ*GFrHQ7oE>EVNxfR{BU?s3zr+LLaQHD$V1Jkcyp7kRk(%_7s-&Kmx*6BJM;%Fx{x+9&u`-Q=S6H*oOn6RqZjO{#m{(mEWqy2Zm#DlxpGMu2(KZ-Ug-Pqj zP_P9vPdTx?hI~YVF^|yMP@BWkmyWpGUyshMNaZaZMl~3+m8=MGfOW6EZfshYU3Y4% zt(Y^=yT$77P=M7p+_H4gEdIc_UsFFuIJYeNp71orm1LyiDJCiT?e)K28e@)(Nc9Y! z=!{eDy!+^~NvfKM?{O`1OP%65>B;GcnFRDO76%Wn)N2!I8dH>t@B#zh%A@l5A30Up z!_^b;a25J)J;}(?8y|~=14VH1i0f>Utea5!@QQ)PYV&%y{$MN_4$`o!vFq$O?Wr`b z{4F3}3v0h~WxDRFMXyl03Cx=|!h7ps){FyTE?A#ds~U^p2&y||JAcq&#aHQIPPN!$ zeIyPVvOdAylgE1P@aiH6o`%J8qSWH+m#+FNg6ZJd7wzktG8QyhT*~I*H`(p$ZK(?$ zmZRx_UH+-{f}>Ktw{ryuU;&EsymsWH3)xl@>C##b2U?^q^p9e#OF^b49eY`2utbO2 z3qeS}r2nD}O6LS)`DX+9Cm>045fjVB^pfB^nZ2sy3Uez-P)M8Ag^*FteFNU)tv@Nh zYbpT4A<3zuw-o-KRuMpdZHV`;n!m6-IqnD07Od9MkK?n&w`Jp1m3Pt~m=6oR+$g5s z%qWe*gD^rbOOyAdWY!wECCiG;?02L4_LT@6st=UR@@(yWY(qcmPDViON0m%6vKwikQ%1765);6) z6`P-LZ;V>(?}&iDS6Sw(&}VX!<137$vc$ERYeghH?JG8Kdu(7D5HSWL1a6Jx6d4xMrMg=G5sjIW|O{gM8O8JvO89LR%Mr*A5m?e zfz0zemP%4yz~hLDOWV{2G8K^C<*f^AZzlyA1cY@pS<6DJOX^v2JHW_FWS8!w0GAJi z$ZJL;Jaq&IiIx>Dc(e|^4W700RacayYbfsK?We01Hc%-sE?ra5*K%F%-ieuzSQGX^ zvzkt_u7BY#Dff5G>s_j=EDJ=eLf5mzX#Dz0*}K<_}wD9d3s+5 zAb8A`KzQ|_so^%p-?+roz@q#~+Sg6p?p%(GEG#ZAj&#){nN?i$yM7aY z!?!-t-SHO5RGVb#g1^Da6w{6&nBkbQdmO$+{YM=x1+zrRN8Rs{gR`)4X|kvsx}u~g zA9eU7EDA(HqaaZ*9KcE9G~PmEp0N`Jx&$2r^aZVzr(BP_vbtnb0wQcP)gFbMSQqBg zPd}D!S9PbVx@zmQ!k3cza90lZ=?{g}k6nytbjmt3L+TTsui+24x|zCpNOZ6)pRr!}{GrP8OZGYE#<3TyL%j~W>Wa#$x}W5STZf#52VLg~GgHlnRm;x~ ztDzK7=!SpYoc_5!&@fOd_u1lijZLd`Wq{?E9M-+wM->jL2`?Q3&6mW_d{-U8t+AsU+>@y30Vu=x7!Zl*TjUQ z_IAH7MXt_h!AW^L!#e|vgS+4;;K1ypGaQ(MBjI|*%n*P(CjlTw0kD0*%-;YAR0iNX z0f6(F0PqtZIdxrT&X^EhN82KJY$Xt;o4ez*R0U@=;SzCxBaZ}BrY9(9F-=J=|WYJNjU7;cXbS+r@bhE zBZ#v0n(O}=XZ!au&!SIg($xCv*GS^(UcTRt(uLiD_JtEH*1d^8<&}Xu=m)uwb1*-| zS9XdZ8T~&&@J`6iZr9#}I+cph-={1X`IaP@=F-^@<|HOX*e2mg&cN0{?Z$7(2jz#9 zZpAd@x|8b@=zPA=Bo8!l`1rB3{_{uVQxwU)o-Ts(_C--EFVa4GxKj>~F6*Qd;{1%&Csv=a);b}T3H(BuNY7HNL=y8Qo+)KU- zVE%$_>%6Fa3AhM)k&OLlDV$Q1NkEy1H$uBa9O|{7VX7`s+HZM+8`U)fVM@?c6Wv zL2nf7&`K{Ml23u&O3NW6Mk<0{^k<~@ZsjOI!LVx8=`Zvej-R(68JNYE2w<&%x@5U! z1NWbrYe^*8Z`KD|au~8CqTuSUB?ndMoj}{XP5m1v^3%fwxlb}S_NcE__TqN}ZMHuH z>XyHss$oD~`&w-{tGC8L^0QMNPCZY@pmL>&kJ5{um!vP|PPMchUE?dT>8sB?V^xaU z)ZdMW3w!T=h}VA$G7vqLN>aNUr?1dD%Atc;W32Z7#4wPJC5>d&Ww&FG*$ZqcuR&`+ zW{;hc<@ZDgG3y)-Ol${FMqQ33pAfd*svEvp(sFM>O}o1HXu&ymFrQ1Xt6)>>J0X*N zmh9p!8RQq~@2MoYF@y+aGf6dsCf!n*FBTz?>k%dildK{vuv5rlxPUU*rHcJr%8nV- zl$V1oSTlnl^q)`=e47gv-SbOo1eJm{RSXdE9a zjOwa%8e#H zkG0kFNvffE6EYw?OPIPG_pG#8qpvc2bxHw3SjHxlo|!SWxMlvPx7o_(8n`I?x&)tC zz6>tkL{>8eH@Ac}GltF(PCc;Y8s@_00wV^u*l2E1>D}xPO(AMEM+m9l;@Q(`eXt`B z<=yJ5BCYa|w@2!tY0qL^+SJwi^Nl%v%Docu%Jl0bcuaVr2D~?O^v^{>oP=v6{abf8-?eo8lcR&S(^<;2e>3 zi&~@b_3!*q-3_C9UvD$AJA(uVke)~3PO3$hJ9<}k6_#5@^Ai_976kOFWX*3h#8=NO z7l@PK4^7^fFL!KG2L{-BXzS4ZR&<$phL}h|_(YYMqTsTU1f%NZqmXL`i+uMYYeaT< zH0s4R(rBiXSosB!rNiMPYMZ6Omm?ry2_rWNYp0Bxsp9mO!}lR=(_!+gcP6M)LHg zLs*=HwAuZcBk&Bk00g~;;d zqVEQ<){R-hJ;GS4%DGO?et5@@(bvF#nJ-SIdr&i`Q{_xoc%cmyq|$xQBm`#~(kh3* za~r{z%OVW9@x^Bo%;KoVi==?$!M-P%%%*}^jn<1qDBXL`7uGY&PT;DQM$wGixCD8*tBtn)I)8s{>{l>gY8_}O%(J% z??=k0PV9uPW#(39U~OKN=d_s%NNvIRfZf!`X&?g_H7 zT`UDDXYM=}!`QnV4rJs>iirYCGhP2#G$7yhja%hm{B8u6_ch8B+VY;!1hI?((4u== zkrLLqgID5970#u=NMeQ4epu zXHA2bG?3I6osyxq%B*gQ6ALUFy2GNJrD#{b*9li-D?`mjSAo|8R^tqBt-rP3M;u> literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..262a8e5e3b43da63fd8096f69b46632220022197 GIT binary patch literal 16866 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 literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..e6fcfc636909891fe3b995a42fd8cd3df6544eb4 GIT binary patch literal 16286 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 literal 0 HcmV?d00001 From 3fcc55b5e19f6ae549689d2ab70072fe6d961cbc Mon Sep 17 00:00:00 2001 From: StevenRS11 Date: Thu, 22 May 2014 00:15:27 -0400 Subject: [PATCH 094/187] finished networking changes for locks --- .../mod_pocketDim/CommonProxy.java | 17 ++ .../mod_pocketDim/CraftingManager.java | 3 +- .../mod_pocketDim/EventHookContainer.java | 3 + .../mod_pocketDim/PacketConstants.java | 1 + .../mod_pocketDim/ServerPacketHandler.java | 13 ++ .../mod_pocketDim/blocks/BaseDimDoor.java | 52 ++--- .../mod_pocketDim/blocks/TransTrapdoor.java | 52 +++++ .../mod_pocketDim/blocks/WarpDoor.java | 1 - .../commands/CommandResetDungeons.java | 4 +- .../mod_pocketDim/core/DDLock.java | 169 ++++++++++++++++ .../mod_pocketDim/core/DDTeleporter.java | 2 +- .../mod_pocketDim/core/DimLink.java | 78 ++++++-- .../mod_pocketDim/core/NewDimData.java | 24 ++- .../mod_pocketDim/core/PocketManager.java | 40 ++-- .../mod_pocketDim/helpers/Compactor.java | 2 +- .../mod_pocketDim/items/ItemDDKey.java | 180 ++++-------------- .../mod_pocketDim/saving/DDSaveHandler.java | 6 +- .../saving/DimDataProcessor.java | 26 ++- .../mod_pocketDim/saving/OldSaveImporter.java | 2 +- .../mod_pocketDim/saving/PackedDimData.java | 2 + .../mod_pocketDim/saving/PackedLinkData.java | 7 +- .../tileentities/TileEntityDimDoor.java | 1 + .../mod_pocketDim/watcher/ClientLinkData.java | 78 ++++---- .../mod_pocketDim/watcher/IUpdateWatcher.java | 1 + .../watcher/UpdateWatcherProxy.java | 9 + .../mod_pocketDim/world/PocketBuilder.java | 81 -------- .../ClientPacketHandler.java | 3 + .../mod_pocketDimClient/ClientProxy.java | 19 +- .../mod_pocketDimClient/RenderDimDoor.java | 15 +- .../mod_pocketDimClient/TESyncHandler.java | 25 +++ .../assets/dimdoors/sound/doorLocked.mp3 | Bin 0 -> 6675 bytes .../assets/dimdoors/sound/doorLocked.ogg | Bin 0 -> 5942 bytes .../assets/dimdoors/sound/keyLock.mp3 | Bin 0 -> 3670 bytes .../assets/dimdoors/sound/keyLock.ogg | Bin 0 -> 4821 bytes .../assets/dimdoors/sound/keyUnlock.mp3 | Bin 0 -> 3043 bytes .../assets/dimdoors/sound/keyUnlock.ogg | Bin 0 -> 4086 bytes .../assets/dimdoors/sound/monkLarge.ogg | Bin 361575 -> 0 bytes .../dimdoors/textures/items/itemDDKey.png | Bin 0 -> 3262 bytes .../dimdoors/textures/other/keyhole.png | Bin 16866 -> 16819 bytes 39 files changed, 566 insertions(+), 350 deletions(-) create mode 100644 src/main/java/StevenDimDoors/mod_pocketDim/core/DDLock.java create mode 100644 src/main/java/StevenDimDoors/mod_pocketDimClient/TESyncHandler.java create mode 100644 src/main/resources/assets/dimdoors/sound/doorLocked.mp3 create mode 100644 src/main/resources/assets/dimdoors/sound/doorLocked.ogg create mode 100644 src/main/resources/assets/dimdoors/sound/keyLock.mp3 create mode 100644 src/main/resources/assets/dimdoors/sound/keyLock.ogg create mode 100644 src/main/resources/assets/dimdoors/sound/keyUnlock.mp3 create mode 100644 src/main/resources/assets/dimdoors/sound/keyUnlock.ogg delete mode 100644 src/main/resources/assets/dimdoors/sound/monkLarge.ogg create mode 100644 src/main/resources/assets/dimdoors/textures/items/itemDDKey.png diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/CommonProxy.java b/src/main/java/StevenDimDoors/mod_pocketDim/CommonProxy.java index ada7b95..952b796 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; @@ -130,6 +133,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/CraftingManager.java b/src/main/java/StevenDimDoors/mod_pocketDim/CraftingManager.java index 063fa44..07b14bb 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/CraftingManager.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/CraftingManager.java @@ -1,6 +1,7 @@ package StevenDimDoors.mod_pocketDim; import StevenDimDoors.mod_pocketDim.config.DDProperties; +import StevenDimDoors.mod_pocketDim.core.DDLock; import StevenDimDoors.mod_pocketDim.core.DimLink; import StevenDimDoors.mod_pocketDim.items.ItemDDKey; import net.minecraft.block.Block; @@ -129,7 +130,7 @@ public class CraftingManager implements ICraftingHandler } } } - keyItem.addDoorToKey(topKey, bottomKey); + DDLock.addKeys(bottomKey, DDLock.getKeys(topKey)); item.setTagCompound(bottomKey.getTagCompound()); player.inventory.addItemStackToInventory(topKey); } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java b/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java index 9f7fd0c..be2125e 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java @@ -59,6 +59,9 @@ public class EventHookContainer @ForgeSubscribe public void onSoundLoad(SoundLoadEvent event) { + 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"); 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 131cc3c..9b1d878 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BaseDimDoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BaseDimDoor.java @@ -181,14 +181,7 @@ public abstract class BaseDimDoor extends BlockDoor implements IDimDoor, ITileEn //but this works fine and is more versatile I think. public BaseDimDoor updateAttachedTile(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 = this.isDoorOnRift(world, x, y, z)&&this.isUpperDoorBlock(metadata); - dimTile.orientation = this.getFullMetadata(world, x, y, z) & 7; - } + mod_pocketDim.proxy.updateDoorTE(this, world, x, y, z); return this; } @@ -353,7 +346,7 @@ public abstract class BaseDimDoor extends BlockDoor implements IDimDoor, ITileEn this.dropBlockAsItem(world, x, y, z, metadata, 0); } } - else if(!this.hasLock(world, x, y, z)) + else if(this.getLockStatus(world, x, y, z)<=1) { boolean powered = world.isBlockIndirectlyGettingPowered(x, y, z) || world.isBlockIndirectlyGettingPowered(x, y + 1, z); if ((powered || neighborID > 0 && Block.blocksList[neighborID].canProvidePower()) && neighborID != this.blockID) @@ -457,17 +450,32 @@ public abstract class BaseDimDoor extends BlockDoor implements IDimDoor, ITileEn return (metadata & 4) != 0; } - - public boolean hasLock(World world, int x, int y, int z) + /** + * 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.isLocked()) + if(link!=null&&link.hasLock()) { - return true; + status++; + if(link.isLocked()) + { + status++; + } } - return false; + return status; } + public boolean checkCanOpen(World world, int x, int y, int z) { return this.checkCanOpen(world, x, y, z, null); @@ -475,30 +483,30 @@ public abstract class BaseDimDoor extends BlockDoor implements IDimDoor, ITileEn public boolean checkCanOpen(World world, int x, int y, int z, EntityPlayer player) { - if(!hasLock(world, x, y, z)) + DimLink link = getLink(world, x, y, z); + if(link==null||player==null) + { + return link==null; + } + if(!link.isLocked()) { return true; } - if(player == null) - { - return false; - } - DimLink link = getLink(world, x, y, z); - for(ItemStack item : player.inventory.mainInventory) { if(item != null) { if(item.getItem() instanceof ItemDDKey) { - if(((ItemDDKey) item.getItem()).canKeyOpen(link, item)) + if(link.open(item)) { return true; } } } } + player.playSound(mod_pocketDim.modid + ":doorLocked", 1F, 1F); return false; } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/TransTrapdoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/TransTrapdoor.java index 30d74ef..f4d8746 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/TransTrapdoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/TransTrapdoor.java @@ -8,6 +8,8 @@ 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; @@ -16,6 +18,7 @@ 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.items.ItemDDKey; import StevenDimDoors.mod_pocketDim.tileentities.TileEntityTransTrapdoor; public class TransTrapdoor extends BlockTrapDoor implements IDimDoor, ITileEntityProvider @@ -40,6 +43,55 @@ 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.isLocked()) + { + return true; + } + + for(ItemStack item : player.inventory.mainInventory) + { + if(item != null) + { + if(item.getItem() instanceof ItemDDKey) + { + if(link.open(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, par3, 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) { diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/WarpDoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/WarpDoor.java index 6f7d881..58cfd05 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/WarpDoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/WarpDoor.java @@ -9,7 +9,6 @@ import StevenDimDoors.mod_pocketDim.core.LinkTypes; 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) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandResetDungeons.java b/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandResetDungeons.java index 0e1d5e2..8176537 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandResetDungeons.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandResetDungeons.java @@ -62,11 +62,11 @@ public class CommandResetDungeons extends DDCommandBase { if(link.linkType()==LinkTypes.REVERSE) { - data.createLink(link.source(), LinkTypes.DUNGEON_EXIT, link.orientation(), false); + data.createLink(link.source(), LinkTypes.DUNGEON_EXIT, link.orientation(), null); } if(link.linkType()==LinkTypes.DUNGEON) { - data.createLink(link.source(), LinkTypes.DUNGEON, link.orientation(), false); + data.createLink(link.source(), LinkTypes.DUNGEON, link.orientation(), null); } } } 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..3b00196 --- /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 isLocked; + private final int lockKey; + + + public DDLock(boolean isLocked, int lockKey) + { + this.isLocked = 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 isLocked() + { + return this.isLocked; + } + + /** + * set the state of the lock. Returns false if there is no lock to set, + * otherwise returns true + * @param flag + */ + public void lock(boolean flag) + { + this.isLocked = flag; + } + + + /** + * see if we could unlock this door if it where locked. + * @param link + * @param itemStack + * @return + */ + public boolean canOpen(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 open(ItemStack itemStack) + { + return (!this.isLocked)||this.canOpen(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(isKey(key)) + { + if(key.hasTagCompound()) + { + return key.getTagCompound().getBoolean("HasCreatedLock"); + } + initNBTTags(key); + } + return false; + } + + public static boolean isKey(ItemStack key) + { + return key.getItem() instanceof ItemDDKey; + } + + + + public static DDLock createLock(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 b85f31c..c34814b 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/core/DDTeleporter.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/core/DDTeleporter.java @@ -485,7 +485,7 @@ public class DDTeleporter { if(PocketManager.isBlackListed(link.destination().getDimension())) { - link=PocketManager.getDimensionData(link.source().getDimension()).createLink(link.point,LinkTypes.SAFE_EXIT,link.orientation, false); + link=PocketManager.getDimensionData(link.source().getDimension()).createLink(link.point,LinkTypes.SAFE_EXIT,link.orientation, null); } else { diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/core/DimLink.java b/src/main/java/StevenDimDoors/mod_pocketDim/core/DimLink.java index ccbd2b3..e4c9c94 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/core/DimLink.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/core/DimLink.java @@ -2,20 +2,20 @@ package StevenDimDoors.mod_pocketDim.core; import java.util.LinkedList; import java.util.List; - +import net.minecraft.item.ItemStack; +import StevenDimDoors.mod_pocketDim.items.ItemDDKey; import StevenDimDoors.mod_pocketDim.util.Point4D; -import StevenDimDoors.mod_pocketDim.watcher.ClientLinkData; public abstract class DimLink { protected Point4D point; protected int orientation; - protected boolean isLocked; + private DDLock lock; protected DimLink parent; protected LinkTail tail; protected List children; - protected DimLink(Point4D point, int orientation, boolean locked, DimLink parent) + protected DimLink(Point4D point, int orientation, DDLock lock, DimLink parent) { if (parent.point.getDimension() != point.getDimension()) @@ -23,26 +23,25 @@ public abstract class DimLink // 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.point = point; this.tail = parent.tail; this.orientation = orientation; - this.isLocked = locked; this.children = new LinkedList(); parent.children.add(this); } - protected DimLink(Point4D point, int orientation, boolean locked, int linkType) + protected DimLink(Point4D point, int orientation, DDLock lock, int linkType) { 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.point = point; this.orientation = orientation; - this.isLocked = locked; this.tail = new LinkTail(linkType, null); this.children = new LinkedList(); } @@ -115,18 +114,63 @@ public abstract class DimLink return tail.getLinkType(); } - public boolean isLocked() - { - return isLocked; - } - public void setLocked(boolean bol) - { - isLocked = bol; - } - public String toString() { return point + " -> " + (hasDestination() ? destination() : ""); } + + /** + * Tries to open this lock. Returns true if the lock is open or if the key can open it + * @return + */ + public boolean open(ItemStack item) + { + return lock.open(item); + } + + /** + * test if there is a lock, regardless if it is locked or not. + * @return + */ + public boolean hasLock() + { + return this.lock!=null; + } + + public boolean isLocked() + { + return this.hasLock()&&this.lock.isLocked(); + } + + public DDLock getLock() + { + PocketManager.getDimensionData(this.source().getDimension()).flagModified(); + return this.lock; + } + /** + * 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.createLock(itemStack, lockKey); + PocketManager.getDimensionData(this.source().getDimension()).flagModified(); + return true; + } + } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/core/NewDimData.java b/src/main/java/StevenDimDoors/mod_pocketDim/core/NewDimData.java index 03b89b0..eef3432 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/core/NewDimData.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/core/NewDimData.java @@ -24,14 +24,14 @@ public abstract class NewDimData implements IPackable { private static class InnerDimLink extends DimLink { - public InnerDimLink(Point4D source, DimLink parent, int orientation, boolean isLocked) + public InnerDimLink(Point4D source, DimLink parent, int orientation, DDLock lock) { - super(source, orientation, isLocked, parent); + super(source, orientation, lock, parent); } - public InnerDimLink(Point4D source, int linkType, int orientation, boolean isLocked) + public InnerDimLink(Point4D source, int linkType, int orientation, DDLock lock) { - super(source, orientation, isLocked, linkType); + super(source, orientation, lock, linkType); } public void setDestination(int x, int y, int z, NewDimData dimension) @@ -99,7 +99,6 @@ public abstract class NewDimData implements IPackable this.orientation=orientation; } } - protected static Random random = new Random(); protected int id; @@ -279,10 +278,10 @@ public abstract class NewDimData implements IPackable public DimLink createLink(int x, int y, int z, int linkType, int orientation) { - return createLink(new Point4D(x, y, z, id), linkType, orientation, false); + return createLink(new Point4D(x, y, z, id), linkType, orientation, null); } - public DimLink createLink(Point4D source, int linkType, int orientation, boolean locked) + public DimLink createLink(Point4D source, int linkType, int orientation, DDLock locked) { //Return an existing link if there is one to avoid creating multiple links starting at the same point. InnerDimLink link = linkMapping.get(source); @@ -308,10 +307,10 @@ public abstract class NewDimData implements IPackable public DimLink createChildLink(int x, int y, int z, DimLink parent) { - return createChildLink(new Point4D(x, y, z, id), (InnerDimLink) parent, false); + return createChildLink(new Point4D(x, y, z, id), (InnerDimLink) parent, null); } - public DimLink createChildLink(Point4D source, DimLink parent, boolean locked) + 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. @@ -584,6 +583,11 @@ public abstract class NewDimData implements IPackable return modified; } + public void flagModified() + { + modified = true; + } + public void clearModified() { this.modified = false; @@ -651,7 +655,7 @@ public abstract class NewDimData implements IPackable 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.isLocked())); + Links.add(new PackedLinkData(link.point,parentPoint,tail,link.orientation,children,link.getLock())); PackedLinkTail tempTail = new PackedLinkTail(link.tail.getDestination(),link.tail.getLinkType()); if(Tails.contains(tempTail)) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/core/PocketManager.java b/src/main/java/StevenDimDoors/mod_pocketDim/core/PocketManager.java index d2ee19f..10d9c61 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/core/PocketManager.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/core/PocketManager.java @@ -7,32 +7,25 @@ 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.world.World; import net.minecraft.world.WorldServer; import net.minecraftforge.common.DimensionManager; -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. @@ -40,7 +33,7 @@ import StevenDimDoors.mod_pocketDim.watcher.UpdateWatcherProxy; * well as loading old dimensions on startup */ public class PocketManager -{ +{ private static class InnerDimData extends NewDimData { // This class allows us to instantiate NewDimData indirectly without exposing @@ -69,7 +62,7 @@ public class PocketManager { Point4D source = link.point; NewDimData dimension = getDimensionData(source.getDimension()); - dimension.createLink(source.getX(), source.getY(), source.getZ(), LinkTypes.CLIENT_SIDE,link.orientation); + dimension.createLink(source, LinkTypes.CLIENT_SIDE, 0, link.lock); } @Override @@ -78,7 +71,17 @@ public class PocketManager Point4D source = link.point; NewDimData dimension = getDimensionData(source.getDimension()); dimension.deleteLink(source.getX(), source.getY(), source.getZ()); - } + } + + @Override + public void update(ClientLinkData link) + { + Point4D source = link.point; + NewDimData dimension = getDimensionData(source.getDimension()); + DimLink dLink = dimension.getLink(source); + dLink.setLock(link.lock); + + } } private static class ClientDimWatcher implements IUpdateWatcher @@ -94,6 +97,12 @@ 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 @@ -633,4 +642,9 @@ public class PocketManager { return dimWatcher; } + + public static UpdateWatcherProxy getLinkWatcher() + { + return linkWatcher; + } } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/helpers/Compactor.java b/src/main/java/StevenDimDoors/mod_pocketDim/helpers/Compactor.java index 1f3d0c9..4fdaa9e 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/helpers/Compactor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/helpers/Compactor.java @@ -80,7 +80,7 @@ public class Compactor { 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(), LinkTypes.CLIENT_SIDE,0); } } } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemDDKey.java b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemDDKey.java index 7a74d6a..bfb2de8 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemDDKey.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemDDKey.java @@ -17,8 +17,10 @@ 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 { @@ -32,8 +34,14 @@ public class ItemDDKey extends Item public void addInformation(ItemStack par1ItemStack, EntityPlayer par2EntityPlayer, List par3List, boolean par4) { - boolean check = (this.isBound(par1ItemStack) ? par3List.add("Bound") : par3List.add("Unbound")); - return; + if(DDLock.hasCreatedLock(par1ItemStack)) + { + par3List.add("Bound"); + } + else + { + par3List.add("Unbound"); + } } @@ -47,7 +55,7 @@ public class ItemDDKey extends Item @SideOnly(Side.CLIENT) public boolean hasEffect(ItemStack par1ItemStack) { - return !this.isBound(par1ItemStack); + return !DDLock.hasCreatedLock(par1ItemStack); } public boolean onItemUseFirst(ItemStack itemStack, EntityPlayer player, World world, int x, int y, int z, int side, float playerX, float playerY, @@ -70,162 +78,40 @@ public class ItemDDKey extends Item { return false; } - //make sure we are not trying to mess with a door thats already locked by someone else - if(!this.canKeyOpen(link, itemStack)&&link.isLocked()) - { - return false; - } - - //see if we can bind this key to this door and lock it - if(setBoundDoor(itemStack, link)) - { - link.setLocked(true); - return false; - } - - //lastly, just see if we can toggle the door's lock state if its locked. - if(this.canKeyOpen(link, itemStack)) - { - link.setLocked(!link.isLocked()); - return false; - } - - return false; - } - - public boolean setBoundDoor(ItemStack itemStack, DimLink link) - { - //dont bind to a door if we already are bound, or if we dont have permission to lock that door - if(this.isBound(itemStack)|| (!this.canKeyOpen(link, itemStack)&&link.isLocked())) + //what to do if the door has a lock already + if(link.hasLock()) { - return false; - } - - //dont bind if the door has a lock already on it, but we can still open it. That would waste the key. - if(link.isLocked()) - { - return false; - } - - //init tags - if(!itemStack.hasTagCompound()) - { - this.initNBTTags(itemStack); - } - - //consume this keys ability to create a lock - itemStack.getTagCompound().setBoolean("HasLockedDoor", true); - - //create the tag that binds this door to this key - NBTTagCompound tag = new NBTTagCompound(); - - int x = link.source().getX(); - int y = link.source().getY(); - int z = link.source().getZ(); - - tag.setInteger("x", x); - tag.setInteger("y", y); - tag.setInteger("z", z); - tag.setInteger("dim", link.source().getDimension()); - - //add this door's tag to this keys keyring - NBTTagList keyRing = itemStack.getTagCompound().getTagList("DDKeys"); - keyRing.appendTag(tag); - itemStack.getTagCompound().setTag("DDKeys", keyRing); - - return true; - } - - /** - * copies all the tags from the first key onto the second key - * @param givingKey - * @param receivingKey - */ - public void addDoorToKey(ItemStack givingKey, ItemStack receivingKey) - { - //cant copy tags from a key with no tags - if(!givingKey.hasTagCompound()) - { - return; - } - - //initialize the receiving key - if(!receivingKey.hasTagCompound()) - { - this.initNBTTags(receivingKey); - } - - //get the tags - NBTTagCompound recevingTags = receivingKey.getTagCompound(); - NBTTagCompound sendingTags = (NBTTagCompound) givingKey.getTagCompound().copy(); - - //copy over the actual tags - for(int i = 0; i private PackedLinkData createLinkDataFromJson(JsonReader reader) throws IOException { - boolean locked = false; + DDLock lock = null; Point4D source; Point3D parent; @@ -235,13 +236,11 @@ public class DimDataProcessor extends BaseConfigurationProcessor if(reader.peek()== JsonToken.NAME) { - reader.nextName(); - locked = reader.nextBoolean(); - + lock = this.createLockFromJson(reader); } reader.endObject(); - return new PackedLinkData(source, parent, tail, orientation, children, locked); + return new PackedLinkData(source, parent, tail, orientation, children, lock); } private PackedDungeonData createDungeonDataFromJson(JsonReader reader) throws IOException { @@ -307,4 +306,21 @@ public class DimDataProcessor extends BaseConfigurationProcessor return new PackedLinkTail(destination, linkType); } + + private DDLock createLockFromJson(JsonReader reader) throws IOException + { + reader.nextName(); + + reader.beginObject(); + reader.nextName(); + + boolean locked = reader.nextBoolean(); + reader.nextName(); + + int key = reader.nextInt(); + reader.endObject(); + + return new DDLock(locked, key); + } + } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/saving/OldSaveImporter.java b/src/main/java/StevenDimDoors/mod_pocketDim/saving/OldSaveImporter.java index 6ddcb9f..13ae45a 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/saving/OldSaveImporter.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/saving/OldSaveImporter.java @@ -80,7 +80,7 @@ public class OldSaveImporter PackedLinkTail tail = new PackedLinkTail(destintion, link.linkOrientation); List children = new ArrayList(); - PackedLinkData newPackedLink = new PackedLinkData(source, new Point3D(-1,-1,-1), tail, link.linkOrientation,children, false); + PackedLinkData newPackedLink = new PackedLinkData(source, new Point3D(-1,-1,-1), tail, link.linkOrientation,children, null); newPackedLinkData.add(newPackedLink); allPackedLinks.add(newPackedLink); diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/saving/PackedDimData.java b/src/main/java/StevenDimDoors/mod_pocketDim/saving/PackedDimData.java index fb058d3..60a033d 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/saving/PackedDimData.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/saving/PackedDimData.java @@ -49,4 +49,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 0cd62d6..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,15 +13,15 @@ public class PackedLinkData public final PackedLinkTail tail; public final int orientation; public final List children; - public final boolean locked; + public final DDLock lock; - public PackedLinkData(Point4D source, Point3D parent, PackedLinkTail tail, int orientation, List children, boolean locked) + 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.locked = locked; + this.lock = lock; } } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityDimDoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityDimDoor.java index 638c1a8..e566f63 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityDimDoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityDimDoor.java @@ -19,6 +19,7 @@ public class TileEntityDimDoor extends DDTileEntityBase public boolean openOrClosed; public int orientation; public boolean hasExit; + public byte lockStatus; public boolean isDungeonChainLink; public boolean hasGennedPair=false; diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/watcher/ClientLinkData.java b/src/main/java/StevenDimDoors/mod_pocketDim/watcher/ClientLinkData.java index daa7aa9..34b7274 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/watcher/ClientLinkData.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/watcher/ClientLinkData.java @@ -3,43 +3,53 @@ 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.util.Point4D; public class ClientLinkData { - public Point4D point; - public int orientation; - public boolean isLocked; - - public ClientLinkData(DimLink link) - { - this.point= link.source(); - this.orientation=link.orientation(); - this.isLocked = link.isLocked(); - } - - public ClientLinkData(Point4D point, int orientation, boolean isLocked) - { - this.point = point; - this.orientation=orientation; - this.isLocked = isLocked; - } - - public void write(DataOutputStream output) throws IOException - { - Point4D.write(point, output); - output.writeInt(orientation); - output.writeBoolean(isLocked); - } - - public static ClientLinkData read(DataInputStream input) throws IOException - { - Point4D point = Point4D.read(input); - int orientation = input.readInt(); - boolean isLocked = input.readBoolean(); - return new ClientLinkData(point, orientation, isLocked); - } - + public Point4D point; + public DDLock lock; + + public ClientLinkData(DimLink link) + { + this.point = link.source(); + if (link.hasLock()) + { + lock = link.getLock(); + } + } + + public ClientLinkData(Point4D point, DDLock lock) + { + this.point = point; + this.lock = lock; + + } + + public void write(DataOutputStream output) throws IOException + { + Point4D.write(point, output); + + boolean hasLock = this.lock != null; + output.writeBoolean(hasLock); + + if (hasLock) + { + output.writeBoolean(lock.isLocked()); + output.writeInt(lock.getLockKey()); + } + } + + public static ClientLinkData read(DataInputStream input) throws IOException + { + Point4D point = Point4D.read(input); + DDLock lock = null; + if (input.readBoolean()) + { + lock = new DDLock(input.readBoolean(), input.readInt()); + } + return new ClientLinkData(point, 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/PocketBuilder.java b/src/main/java/StevenDimDoors/mod_pocketDim/world/PocketBuilder.java index 4d2d3a1..7b9ed43 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/world/PocketBuilder.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/world/PocketBuilder.java @@ -40,87 +40,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, false); - 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, false); - 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; - } - - DungeonSchematic schematic = loadAndValidateDungeon(dimension.dungeon(), properties); - if (schematic == null) - { - return false; - } - Point3D destination = new Point3D(incomingLink.destination()); - schematic.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 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..59bb2a8 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDimClient/ClientProxy.java +++ b/src/main/java/StevenDimDoors/mod_pocketDimClient/ClientProxy.java @@ -1,8 +1,14 @@ 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.TileEntityTransTrapdoor; +import StevenDimDoors.mod_pocketDim.watcher.ClientLinkData; import cpw.mods.fml.client.registry.ClientRegistry; import cpw.mods.fml.client.registry.RenderingRegistry; @@ -24,9 +30,18 @@ public class ClientProxy extends CommonProxy } @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/RenderDimDoor.java b/src/main/java/StevenDimDoors/mod_pocketDimClient/RenderDimDoor.java index 4e82163..195a7da 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDimClient/RenderDimDoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDimClient/RenderDimDoor.java @@ -315,15 +315,13 @@ public class RenderDimDoor extends TileEntitySpecialRenderer if(i==1) { bindTexture(KeyholeLight); - GL11.glColor4d(1, 1, 1, .6); + GL11.glColor4d(1, 1, 1, .7); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_DST_COLOR); } - else + else { bindTexture(keyPath); - GL11.glColor4d(.0, .7, .1, 1); - glBlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA); } @@ -365,12 +363,17 @@ public class RenderDimDoor extends TileEntitySpecialRenderer if (tile.openOrClosed) { + renderDimDoorTileEntity((TileEntityDimDoor) par1TileEntity, par2, par4, par6); - for(int i = 0; i<2; i++ ) + if(tile.lockStatus>=1) { - this.renderKeyHole(tile, par2, par4, par6, i); + for(int i = 0; i<1+tile.lockStatus; i++ ) + { + this.renderKeyHole(tile, par2, par4, par6, i); + } } + } } 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/resources/assets/dimdoors/sound/doorLocked.mp3 b/src/main/resources/assets/dimdoors/sound/doorLocked.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..79bbc6aa32962af7cb1dd0166cd5b1a45d897410 GIT binary patch literal 6675 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 literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..ae52ae9234c8b39f4b3039a5f0ebbdcbfb7f5beb GIT binary patch literal 3670 zcmeHIXH-+^7QKOhF-8O&VK|n_7j)NfRdx%o*-1y25*L(lpTg$W7UgtY^fBSrApFh`%tSbyafpnx< z(Fo8%9fBh>I@}*;5fH%eJHf(f;>h;)R1F-(-rNQ%Xiii+9LbLSy{0)>=s-$6G$5$>sp1HD9sEC@`d4cW94RaeM-2`Pf)-3=uozJ>41b!vgT+4^KB&n0KYx~1PAP9b17T;Mx8$T+norUp@QY3HdmbeIg1~(t)vE(CM z;Chjq$GT=JapTW;&r)RUK@dv-$OyUVsL3nK3yV?>XU)e7$~}!j^0-#G+xdRtSG4-U zX)_*1J1r#_mL3EQnOaLLA(btKP_jfkF;=L%+{-CgnxKRb{X-~CI7yX=lv9?eGiW=3 z9T*MHuU^LN1njz-qjbU1@CACwQ_1Sd4CP{}L~xBoTFfKYgy)s$%YVHGZd?*3|30es zvOgt2AxUfcy-GsazA3tcLXpiqaPyLlt-i}MQevNQnRNy{UMzro^1|eLo}To(0c%Ee z*P*q8BBiAj#@3S4#S}|?shCb${*jry+elGiSTb=Uk2rmEP6JRmNLENuK0J(Ws23R8 zOK2(V^-7Hcj!`~*_{eg9`_|=5L%qeZ^T#t+nl91%Sl;>wHzkc8QOz@7mhnf#L`h2r zw+Ok7{!PZJH1yScPBPnbBsW=?z(2mj&CAtGB!mCz+uy%xzmHXJQx-n`s8a@+fnqLp zj`mcX_VXHk3*MS4f0Dh4`iOnU?!6wE%nfJ<-@OAj)(<5%hQI#WrFPA7lrM2nOw#c7 zjh5Sl2Obu+JrUoUgJxlYO&YId-cWKaDp+?!d(mO{yT{ArWIxNV7}&*9O|sb3Zacof z&~B{{o{wPZbYO7UJ4iujZov3?q|HKZe>9s{$XlUUzkbxgf9ZU)X1Zpm zp-thM%NhlYs43~y{nj-zt*Yya$;SVW?+WFiC#8mm_C%E{*FVho}qhGxF|{zWQg2 zUcZe^SH4EXtbs_@F3w)*Vp|M>f^O#)FBHO6*pnASTsPf^TdUB%F-p-{Zu?8B(~Su| zVT|k=wXwZgp>qu`W;vFVH8qUZpgC+^&Di8tGOK+hQ}Fi?+$v@?ly{bgr$*r z4&E44WHmlF3rnx|r>WiKG&=4-I^=$v+A!Ne?^DzW;c$VT8x-eunZ`#M2Pm_eSWaVl zM@1eBQ=_iGw|~}QUfrp&bV$S=_(Er$;$$b#Cl6x_|du*TpVgJF540 z`bN&B7cDRZuh4{3hO?nOq^e3OhuCWNRIwt*52P-=A&FJ0AK_aJO6JMbDGCgkYIM7L zkSKJRdqPZsv%X@f>DWo1efou2T0U4ZKZpE5N~PmU@PP5>I)fKsT&M1ZUnA#>i>KSe zD_1Wx6f=72V&3}tVfO9VVzoAi+#B{yz=fq zEqNf(%~yJ{-e6s^!{^ke-N7s#4H=RlGI5u$W)>5ayVx6XIIe4l?dPW7EQ=;uV?r&x zUtEnd9H@x2LmTb;r0QIhqmZiDfk|VRomH#Ls}bVb{0Y9Mo$H&GIJu3zup}^KZyJ`8 z24lwo-d?+?z5cY&p2TTbGj=NEvdPxRCWJ?N@Qd~N5y{1o+Na17oh?H0<%4qYnP@rX zU=_L0+0_cQP;6_V)|q*a`^*c2A->#*voe+=6XmKX2KDYW_G<{5L4^djNvI}I-7E~iCcPrg?)i1U?HP!~4KD+W%r~Q@l;M&*K zFW-9GO6Mhht;<(^*pPaC>R#d)atGNzVGDe}HY!`xHBJI0O7kWjS`I}1q9ZVb)j=66 z!V1a(l{5Dy#&dPf@_1YkEbLl`E0{zQ7c<6SsAe(fSdeXomfUSDgJ4z+!2l3U=BOc3 z(hC5Dx9&nJRTwEQwP%~=hw8*t3<<{&Pk)Z0px2e3wLOE2VlYx+`+UwrKNzfp6|e-r zF)$*+Yl~AT^o$OODI_xljYMx=!bhe4hk7g2yOo#@T pAIns7X5c9$Mzc;7lC6cV)_z^5A3|UV0|3HDU_1c$f&0HK{{j@sFP8uS literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..c63ede2c3d084b1409eddf9fc51d7730a837480b GIT binary patch literal 4821 zcmcImc|4SB`+rawlI=LMrJ16PEklyt6l00URu95RWyaWMY%?eoDQh)vi6M$gjGAF4 z$*4vtN2V-I4xw!Ak+HNP3GY2R=X^fz@ALlqdp@7%p6j~4_qAX5J&$K-s23y+{q@Km z{6!o*rqm&&E0qvUBZku@A}JN4U&!sOU%!P?o)XP}9*L$D;P(0PM-�F8uxQWqui1 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 WU+y=JnN%vFsk_f7l!=}s$^HlF+jfrt literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..784514673100fd1018eae8767e98ab3ad586b7ae GIT binary patch literal 3043 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 literal 0 HcmV?d00001 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 73e69b47c63ff9c64211b96fa33752c53db39a09..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 361575 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�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 z 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 x@Pf=y4ET?B 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 z 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 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 0000000000000000000000000000000000000000..e2f0a749e920437b75794150f0d4a9f38d7afd49 GIT binary patch literal 3262 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/dimdoors/textures/other/keyhole.png b/src/main/resources/assets/dimdoors/textures/other/keyhole.png index 262a8e5e3b43da63fd8096f69b46632220022197..7bb3ea329e5152d3ebb8afb07324af829cdf6ec4 100644 GIT binary patch delta 15852 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 H From 3f6e32dcbfcb2b166a8cbb99eedccb3c4aed9211 Mon Sep 17 00:00:00 2001 From: StevenRS11 Date: Thu, 22 May 2014 01:03:17 -0400 Subject: [PATCH 095/187] last tweaks done --- .../mod_pocketDim/CraftingManager.java | 4 ++-- .../mod_pocketDim/blocks/BaseDimDoor.java | 7 +++++++ .../mod_pocketDim/core/DimLink.java | 10 ++++++++++ .../mod_pocketDim/items/ItemDDKey.java | 19 ++++++++++++++++--- 4 files changed, 35 insertions(+), 5 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/CraftingManager.java b/src/main/java/StevenDimDoors/mod_pocketDim/CraftingManager.java index 07b14bb..689f35b 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/CraftingManager.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/CraftingManager.java @@ -66,7 +66,7 @@ public class CraftingManager implements ICraftingHandler if (properties.CraftingRiftSignatureAllowed) { GameRegistry.addRecipe(new ItemStack(itemRiftSignature, 1), - " y ", "yxy", " y ", 'x', mod_pocketDim.itemStableFabric, 'y', Item.ingotIron); + " y ", "yxy", " y ", 'x', Item.enderPearl, 'y', Item.ingotIron); } if (properties.CraftingRiftRemoverAllowed) { @@ -96,7 +96,7 @@ public class CraftingManager implements ICraftingHandler if (properties.CraftingDDKeysAllowed) { GameRegistry.addRecipe(new ItemStack(mod_pocketDim.itemDDKey, 1), - " x ", " x ", "yzy", 'y', Item.ingotGold, 'x', Item.ingotIron, 'z', mod_pocketDim.itemStableFabric); + " z", " y ", "y ", 'y', Item.ingotGold, 'z', Item.enderPearl); GameRegistry.addRecipe(new ItemStack(mod_pocketDim.itemDDKey, 1), "z", "z", 'z', mod_pocketDim.itemDDKey); } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BaseDimDoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BaseDimDoor.java index 9b1d878..5ddc7a7 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BaseDimDoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BaseDimDoor.java @@ -10,6 +10,7 @@ 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; @@ -73,6 +74,12 @@ 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) { + + ItemStack stack = player.inventory.getCurrentItem(); + if (stack != null && stack.getItem() instanceof ItemDDKey) + { + return false; + } if(!checkCanOpen(world, x, y, z, player)) { diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/core/DimLink.java b/src/main/java/StevenDimDoors/mod_pocketDim/core/DimLink.java index e4c9c94..de26cd5 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/core/DimLink.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/core/DimLink.java @@ -128,6 +128,15 @@ public abstract class DimLink { return lock.open(item); } + + /** + * Tries to open this lock. Returns true if the lock is open or if the key can open it + * @return + */ + public boolean canOpen(ItemStack item) + { + return lock.canOpen(item); + } /** * test if there is a lock, regardless if it is locked or not. @@ -154,6 +163,7 @@ public abstract class DimLink */ public void setLock(DDLock lock) { + PocketManager.getDimensionData(this.source().getDimension()).flagModified(); this.lock = lock; } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemDDKey.java b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemDDKey.java index bfb2de8..70b838a 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemDDKey.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemDDKey.java @@ -31,6 +31,10 @@ public class ItemDDKey extends Item this.setMaxStackSize(1); } + public void onCreated(ItemStack par1ItemStack, World par2World, EntityPlayer par3EntityPlayer) + { + + } public void addInformation(ItemStack par1ItemStack, EntityPlayer par2EntityPlayer, List par3List, boolean par4) { @@ -57,7 +61,13 @@ public class ItemDDKey extends Item { return !DDLock.hasCreatedLock(par1ItemStack); } - + + + public boolean onItemUse(ItemStack par1ItemStack, EntityPlayer par2EntityPlayer, World par3World, int par4, int par5, int par6, int par7, float par8, float par9, float par10) + { + 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) { @@ -82,7 +92,7 @@ public class ItemDDKey extends Item //what to do if the door has a lock already if(link.hasLock()) { - if(link.getLock().canOpen(itemStack)) + if(link.canOpen(itemStack)) { if(link.isLocked()) { @@ -95,7 +105,10 @@ public class ItemDDKey extends Item link.getLock().lock(!link.isLocked()); PocketManager.getLinkWatcher().update(new ClientLinkData(link.source(),link.getLock())); } - + else + { + world.playSoundAtEntity(player, mod_pocketDim.modid + ":doorLocked", 1F, 1F); + } } else { From 86cfcdeee8d306563d1aa14e5ad9925a4e5da722 Mon Sep 17 00:00:00 2001 From: StevenRS11 Date: Thu, 22 May 2014 01:37:04 -0400 Subject: [PATCH 096/187] last few changes --- .../StevenDimDoors/mod_pocketDim/CraftingManager.java | 10 +++++----- .../items/ItemStabilizedRiftSignature.java | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/CraftingManager.java b/src/main/java/StevenDimDoors/mod_pocketDim/CraftingManager.java index 689f35b..54cbe3b 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/CraftingManager.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/CraftingManager.java @@ -56,12 +56,12 @@ public class CraftingManager implements ICraftingHandler if (properties.CraftingWarpDoorAllowed) { GameRegistry.addRecipe(new ItemStack(itemWarpDoor, 1), - "yxy", 'x', mod_pocketDim.itemStableFabric, 'y', Item.doorWood); + "yxy", 'x', Item.enderPearl, 'y', Item.doorWood); } if (properties.CraftingTransTrapdoorAllowed) { GameRegistry.addRecipe(new ItemStack(transTrapdoor, 1), - "y", "x", "y", 'x', mod_pocketDim.itemStableFabric, 'y', Block.trapdoor); + "y", "x", "y", 'x', Item.enderPearl, 'y', Block.trapdoor); } if (properties.CraftingRiftSignatureAllowed) { @@ -71,7 +71,7 @@ public class CraftingManager implements ICraftingHandler if (properties.CraftingRiftRemoverAllowed) { GameRegistry.addRecipe(new ItemStack(itemRiftRemover, 1), - "yyy", "yxy", "yyy", 'x', mod_pocketDim.itemStableFabric, 'y', Item.ingotGold); + "yyy", "yxy", "yyy", 'x', Item.enderPearl, 'y', Item.ingotGold); } if (properties.CraftingRiftBladeAllowed) { @@ -81,12 +81,12 @@ public class CraftingManager implements ICraftingHandler if (properties.CraftingStabilizedRiftSignatureAllowed) { GameRegistry.addRecipe(new ItemStack(mod_pocketDim.itemStabilizedLinkSignature,1), - " y ", "yxy", " y ", 'x', mod_pocketDim.itemRiftSignature, 'y', mod_pocketDim.itemStableFabric); + " y ", "yxy", " y ", 'x', mod_pocketDim.itemRiftSignature, 'y', mod_pocketDim.itemWorldThread); } if (properties.CraftingGoldenDimensionalDoorAllowed) { GameRegistry.addRecipe(new ItemStack(mod_pocketDim.itemGoldenDimensionalDoor,1), - "yxy", 'x', mod_pocketDim.itemGoldenDoor, 'y', mod_pocketDim.itemStableFabric); + "yxy", 'y', mod_pocketDim.itemGoldenDoor, 'x', mod_pocketDim.itemStableFabric); } if (properties.CraftingGoldenDoorAllowed) { diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemStabilizedRiftSignature.java b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemStabilizedRiftSignature.java index 4d1cf84..8dc5570 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemStabilizedRiftSignature.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemStabilizedRiftSignature.java @@ -55,9 +55,9 @@ public class ItemStabilizedRiftSignature extends ItemRiftSignature { // 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)) + if (!player.capabilities.isCreativeMode && !player.inventory.hasItem(Item.enderPearl.itemID)) { - mod_pocketDim.sendChat(player, "You don't have any Stable Fabric!"); + 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 @@ -88,7 +88,7 @@ public class ItemStabilizedRiftSignature extends ItemRiftSignature if (!player.capabilities.isCreativeMode) { - player.inventory.consumeInventoryItem(mod_pocketDim.itemStableFabric.itemID); + player.inventory.consumeInventoryItem(Item.enderPearl.itemID); } mod_pocketDim.sendChat(player,"Rift Created"); world.playSoundAtEntity(player,"mods.DimDoors.sfx.riftEnd", 0.6f, 1); From d8fecd07b337346055a8e5e2b9396d0d4e6cf8d5 Mon Sep 17 00:00:00 2001 From: StevenRS11 Date: Thu, 22 May 2014 01:48:21 -0400 Subject: [PATCH 097/187] render tweaks --- .../mod_pocketDimClient/RenderDimDoor.java | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDimClient/RenderDimDoor.java b/src/main/java/StevenDimDoors/mod_pocketDimClient/RenderDimDoor.java index 195a7da..cbd3e21 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDimClient/RenderDimDoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDimClient/RenderDimDoor.java @@ -287,26 +287,25 @@ public class RenderDimDoor extends TileEntitySpecialRenderer 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, .24F, -0.03F); + GL11.glTranslatef(-0.5F, 0, -0.03F); break; case 1: - GL11.glTranslatef(-.5F, .24F, .97F); + GL11.glTranslatef(-.5F, 0F, .97F); break; case 2: - GL11.glTranslatef(.5F, .24F, .97F); + GL11.glTranslatef(.5F, 0F, .97F); break; case 3: - GL11.glTranslatef(0.5F, .24F, -0.03F); + GL11.glTranslatef(0.5F, 0F, -0.03F); } GL11.glDisable(GL_LIGHTING); From 16d7bfcda6f9961a063bb28a1998407708eba478 Mon Sep 17 00:00:00 2001 From: StevenRS11 Date: Mon, 26 May 2014 19:38:01 -0400 Subject: [PATCH 098/187] personal pockets DONE --- .../mod_pocketDim/CraftingManager.java | 30 +++- .../mod_pocketDim/blocks/BlockDimWall.java | 32 +++- .../mod_pocketDim/blocks/BlockDoorGold.java | 4 - .../mod_pocketDim/blocks/BlockDoorQuartz.java | 28 ++++ .../mod_pocketDim/blocks/BlockRift.java | 1 + .../mod_pocketDim/blocks/PersonalDimDoor.java | 41 ++++++ .../mod_pocketDim/config/DDProperties.java | 17 ++- .../mod_pocketDim/core/DDTeleporter.java | 41 +++++- .../mod_pocketDim/core/LinkTypes.java | 4 +- .../mod_pocketDim/core/PocketManager.java | 50 ++++++- .../helpers/PersonalPocketHelper.java | 6 + .../mod_pocketDim/items/ItemBlockDimWall.java | 2 +- .../mod_pocketDim/items/ItemPersonalDoor.java | 35 +++++ .../mod_pocketDim/items/ItemQuartzDoor.java | 58 ++++++++ .../mod_pocketDim/mod_pocketDim.java | 20 ++- .../mod_pocketDim/saving/DDSaveHandler.java | 66 ++++++++- .../PersonalPocketMappingProcessor.java | 79 ++++++++++ .../mod_pocketDim/schematic/BlockRotator.java | 2 + .../world/PersonalPocketProvider.java | 85 +++++++++++ .../mod_pocketDim/world/PocketBuilder.java | 100 +++++++++++-- .../mod_pocketDim/world/PocketProvider.java | 4 +- .../mod_pocketDimClient/ClientProxy.java | 4 +- .../PrivatePocketRender.java | 139 ++++++++++++++++++ .../blocks/tile.blockDimWallPersonal.png | Bin 0 -> 2802 bytes .../blocks/tile.dimDoorPersonal_lower.png | Bin 0 -> 3456 bytes .../blocks/tile.dimDoorPersonal_upper.png | Bin 0 -> 3361 bytes .../textures/blocks/tile.doorQuartz_lower.png | Bin 0 -> 3456 bytes .../textures/blocks/tile.doorQuartz_upper.png | Bin 0 -> 3361 bytes .../dimdoors/textures/items/itemChaosDoor.png | Bin 217 -> 2964 bytes .../textures/items/itemQuartzDimDoor.png | Bin 0 -> 3031 bytes .../textures/items/itemQuartzDoor.png | Bin 0 -> 3031 bytes 31 files changed, 794 insertions(+), 54 deletions(-) create mode 100644 src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockDoorQuartz.java create mode 100644 src/main/java/StevenDimDoors/mod_pocketDim/blocks/PersonalDimDoor.java create mode 100644 src/main/java/StevenDimDoors/mod_pocketDim/helpers/PersonalPocketHelper.java create mode 100644 src/main/java/StevenDimDoors/mod_pocketDim/items/ItemPersonalDoor.java create mode 100644 src/main/java/StevenDimDoors/mod_pocketDim/items/ItemQuartzDoor.java create mode 100644 src/main/java/StevenDimDoors/mod_pocketDim/saving/PersonalPocketMappingProcessor.java create mode 100644 src/main/java/StevenDimDoors/mod_pocketDim/world/PersonalPocketProvider.java create mode 100644 src/main/java/StevenDimDoors/mod_pocketDimClient/PrivatePocketRender.java create mode 100644 src/main/resources/assets/dimdoors/textures/blocks/tile.blockDimWallPersonal.png create mode 100644 src/main/resources/assets/dimdoors/textures/blocks/tile.dimDoorPersonal_lower.png create mode 100644 src/main/resources/assets/dimdoors/textures/blocks/tile.dimDoorPersonal_upper.png create mode 100644 src/main/resources/assets/dimdoors/textures/blocks/tile.doorQuartz_lower.png create mode 100644 src/main/resources/assets/dimdoors/textures/blocks/tile.doorQuartz_upper.png create mode 100644 src/main/resources/assets/dimdoors/textures/items/itemQuartzDimDoor.png create mode 100644 src/main/resources/assets/dimdoors/textures/items/itemQuartzDoor.png diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/CraftingManager.java b/src/main/java/StevenDimDoors/mod_pocketDim/CraftingManager.java index 54cbe3b..34241dd 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/CraftingManager.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/CraftingManager.java @@ -1,18 +1,24 @@ package StevenDimDoors.mod_pocketDim; -import StevenDimDoors.mod_pocketDim.config.DDProperties; -import StevenDimDoors.mod_pocketDim.core.DDLock; -import StevenDimDoors.mod_pocketDim.core.DimLink; -import StevenDimDoors.mod_pocketDim.items.ItemDDKey; +import static StevenDimDoors.mod_pocketDim.mod_pocketDim.itemDimensionalDoor; +import static StevenDimDoors.mod_pocketDim.mod_pocketDim.itemRiftBlade; +import static StevenDimDoors.mod_pocketDim.mod_pocketDim.itemRiftRemover; +import static StevenDimDoors.mod_pocketDim.mod_pocketDim.itemRiftSignature; +import static StevenDimDoors.mod_pocketDim.mod_pocketDim.itemStableFabric; +import static StevenDimDoors.mod_pocketDim.mod_pocketDim.itemUnstableDoor; +import static StevenDimDoors.mod_pocketDim.mod_pocketDim.itemWarpDoor; +import static StevenDimDoors.mod_pocketDim.mod_pocketDim.transTrapdoor; import net.minecraft.block.Block; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.inventory.IInventory; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; -import net.minecraft.nbt.NBTTagCompound; +import net.minecraftforge.oredict.ShapedOreRecipe; +import StevenDimDoors.mod_pocketDim.config.DDProperties; +import StevenDimDoors.mod_pocketDim.core.DDLock; +import StevenDimDoors.mod_pocketDim.items.ItemDDKey; import cpw.mods.fml.common.ICraftingHandler; import cpw.mods.fml.common.registry.GameRegistry; -import static StevenDimDoors.mod_pocketDim.mod_pocketDim.*; public class CraftingManager implements ICraftingHandler { @@ -92,6 +98,18 @@ public class CraftingManager implements ICraftingHandler { 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) { diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockDimWall.java b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockDimWall.java index 82e451a..d33ab48 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,7 +25,7 @@ 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) { @@ -34,7 +36,7 @@ public class BlockDimWall extends Block @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 : 2; } @Override @@ -83,7 +101,7 @@ 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)); } @@ -110,7 +128,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/BlockDoorGold.java b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockDoorGold.java index 2657969..9a1845e 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockDoorGold.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockDoorGold.java @@ -33,8 +33,4 @@ public class BlockDoorGold extends BlockDoor { return (par1 & 8) != 0 ? 0 : mod_pocketDim.itemGoldenDoor.itemID; } - - - - } 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/BlockRift.java b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockRift.java index ada00b6..7749a65 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockRift.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockRift.java @@ -65,6 +65,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); 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..a93db80 --- /dev/null +++ b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/PersonalDimDoor.java @@ -0,0 +1,41 @@ +package StevenDimDoors.mod_pocketDim.blocks; + +import net.minecraft.block.material.Material; +import net.minecraft.world.World; +import StevenDimDoors.mod_pocketDim.config.DDProperties; +import StevenDimDoors.mod_pocketDim.core.DimLink; +import StevenDimDoors.mod_pocketDim.core.LinkTypes; +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, LinkTypes.PERSONAL, world.getBlockMetadata(x, y - 1, z)); + } + } + } + + @Override + public int getDrops() + { + // TODO Auto-generated method stub + return 0; + } + +} diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/config/DDProperties.java b/src/main/java/StevenDimDoors/mod_pocketDim/config/DDProperties.java index 8cf94ae..4996764 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/config/DDProperties.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/config/DDProperties.java @@ -23,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 @@ -47,7 +50,8 @@ public class DDProperties public final int WarpDoorItemID; public final int WorldThreadItemID; public final int DDKeyItemID; - + public final int ItemQuartzDoorID; + public final int ItemPersonalDimDoorID; /** * Other IDs @@ -58,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; @@ -77,7 +82,8 @@ public class DDProperties public final boolean CraftingGoldenDimensionalDoorAllowed; public final boolean CraftingGoldenDoorAllowed; public final boolean CraftingDDKeysAllowed; - + public final boolean CraftingQuartzDoorAllowed; + public final boolean CraftingPersonalDimDoorAllowed; /** * Loot Flags @@ -151,6 +157,8 @@ public class DDProperties 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 " + @@ -196,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(); @@ -209,6 +219,8 @@ public class DDProperties 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(); @@ -218,6 +230,7 @@ public class DDProperties LimboDimensionID = config.get(CATEGORY_DIMENSION, "Limbo Dimension ID", -23).getInt(); 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); diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/core/DDTeleporter.java b/src/main/java/StevenDimDoors/mod_pocketDim/core/DDTeleporter.java index c34814b..ddb2b0c 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/core/DDTeleporter.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/core/DDTeleporter.java @@ -23,6 +23,7 @@ import net.minecraftforge.common.DimensionManager; 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.ItemDimensionalDoor; @@ -251,15 +252,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 the orientation portion of its metadata return world.getBlockMetadata(door.getX(), door.getY() - 1, door.getZ()) & 3; } @@ -458,7 +458,7 @@ public class DDTeleporter return; } - if (!initializeDestination(link, DDProperties.instance(),door)) + if (!initializeDestination(link, DDProperties.instance(),entity,door)) { return; } @@ -471,7 +471,7 @@ 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); @@ -479,9 +479,9 @@ public class DDTeleporter } } - 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()!=LinkTypes.PERSONAL) { if(PocketManager.isBlackListed(link.destination().getDimension())) { @@ -500,6 +500,8 @@ public class DDTeleporter return PocketBuilder.generateNewDungeonPocket(link, properties); case LinkTypes.POCKET: return PocketBuilder.generateNewPocket(link, properties,door); + case LinkTypes.PERSONAL: + return setupPersonalLink(link, properties, entity, door); case LinkTypes.SAFE_EXIT: return generateSafeExit(link, properties); case LinkTypes.DUNGEON_EXIT: @@ -514,6 +516,29 @@ public class DDTeleporter 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()).setDestination(personalHomeLink, link.source().getX(), link.source().getY(), link.source().getZ()); + } + + dim.setDestination(link, dim.origin.getX(), dim.origin.getY(), dim.origin.getZ()); + return true; + } private static Point4D getRandomDestination() { diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/core/LinkTypes.java b/src/main/java/StevenDimDoors/mod_pocketDim/core/LinkTypes.java index f7424b5..54aef9a 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/core/LinkTypes.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/core/LinkTypes.java @@ -5,7 +5,7 @@ public class LinkTypes private LinkTypes() { } public static final int ENUM_MIN = 0; - public static final int ENUM_MAX = 7; + public static final int ENUM_MAX = 8; public static final int CLIENT_SIDE = -1337; @@ -18,4 +18,6 @@ public class LinkTypes public static final int SAFE_EXIT = 5; public static final int UNSAFE_EXIT = 6; public static final int REVERSE = 7; + public static final int PERSONAL = 8; + } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/core/PocketManager.java b/src/main/java/StevenDimDoors/mod_pocketDim/core/PocketManager.java index 10d9c61..0488fa9 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/core/PocketManager.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/core/PocketManager.java @@ -7,6 +7,7 @@ import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; +import net.minecraft.entity.player.EntityPlayer; import net.minecraft.world.World; import net.minecraft.world.WorldServer; import net.minecraftforge.common.DimensionManager; @@ -137,6 +138,9 @@ public class PocketManager //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; @@ -161,6 +165,7 @@ public class PocketManager dimensionData = new HashMap(); rootDimensions = new ArrayList(); dimensionIDBlackList = new ArrayList(); + personalPocketsMapping = new HashMap(); if(FMLCommonHandler.instance().getEffectiveSide().isClient()) { @@ -277,7 +282,14 @@ 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) { @@ -412,6 +424,21 @@ public class PocketManager return registerDimension(world.provider.dimensionId, null, false, false); } + public static NewDimData registerPersonalPocket(NewDimData parent, 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.PersonalPocketProviderID); + NewDimData data = registerDimension(dimensionID, (InnerDimData) parent, true, false); + personalPocketsMapping.put(playerName, data); + return data; + } + public static NewDimData registerPocket(NewDimData parent, boolean isDungeon) { if (parent == null) @@ -539,6 +566,7 @@ public class PocketManager unregisterPockets(); dimensionData = null; + personalPocketsMapping = null; rootDimensions = null; isLoaded = false; isConnected = false; @@ -647,4 +675,24 @@ public class PocketManager { 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/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/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/ItemPersonalDoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemPersonalDoor.java new file mode 100644 index 0000000..737837a --- /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 getDoortoItemMapping() + { + 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/mod_pocketDim.java b/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java index 08320a3..5b1a3cd 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; @@ -19,10 +18,12 @@ import net.minecraftforge.common.MinecraftForge; 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; @@ -46,6 +47,8 @@ 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; @@ -64,11 +67,11 @@ 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.DDLogger; import StevenDimDoors.mod_pocketDim.world.BiomeGenLimbo; import StevenDimDoors.mod_pocketDim.world.BiomeGenPocket; import StevenDimDoors.mod_pocketDim.world.DDBiomeGenBase; 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; @@ -113,6 +116,8 @@ public class mod_pocketDim @Instance("PocketDimensions") public static mod_pocketDim instance = new mod_pocketDim(); + public static Block quartzDoor; + public static Block personalDimDoor; public static Block transientDoor; public static Block warpDoor; public static Block goldenDoor; @@ -138,6 +143,8 @@ public class mod_pocketDim public static Item itemUnstableDoor; public static Item itemStabilizedLinkSignature; public static Item itemDDKey; + public static Item itemQuartzDoor; + public static Item itemPersonalDoor; public static BiomeGenBase limboBiome; public static BiomeGenBase pocketBiome; @@ -201,6 +208,9 @@ public class mod_pocketDim 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"); @@ -212,6 +222,8 @@ public class mod_pocketDim transTrapdoor = (TransTrapdoor) (new TransTrapdoor(properties.TransTrapdoorID, Material.wood).setHardness(1.0F) .setUnlocalizedName("dimHatch")); 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"); @@ -232,6 +244,8 @@ public class mod_pocketDim 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"); @@ -249,6 +263,8 @@ public class mod_pocketDim 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 LimboProvider from Dimensional Doors and another provider type. Fix your configuration!"); DimensionManager.registerDimension(properties.LimboDimensionID, properties.LimboProviderID); diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/saving/DDSaveHandler.java b/src/main/java/StevenDimDoors/mod_pocketDim/saving/DDSaveHandler.java index e72d07a..e721351 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/saving/DDSaveHandler.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/saving/DDSaveHandler.java @@ -7,6 +7,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedList; import java.util.List; +import java.util.Map.Entry; import net.minecraftforge.common.DimensionManager; import StevenDimDoors.mod_pocketDim.Point3D; @@ -59,6 +60,15 @@ 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(); @@ -82,7 +92,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; } /** @@ -270,6 +290,9 @@ public class DDSaveHandler // Create and write the blackList writeBlacklist(blacklist, savePath); + //create and write personal pocket mapping + writePersonalPocketMap(PocketManager.getPersonalPocketMapping(), savePath); + // Write the dimension save data boolean succeeded = true; DimDataProcessor writer = new DimDataProcessor(); @@ -312,6 +335,32 @@ public class DDSaveHandler } } + private static boolean writePersonalPocketMap(HashMap hashMap, String savePath) + { + try + { + 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 @@ -378,7 +427,6 @@ public class DDSaveHandler public static List readBlacklist(File blacklistFile, BlacklistProcessor reader) { - try { return reader.readFromFile(blacklistFile); @@ -388,6 +436,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/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 af0050e..98ae89c 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/schematic/BlockRotator.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/schematic/BlockRotator.java @@ -70,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; } 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..fe9ac66 --- /dev/null +++ b/src/main/java/StevenDimDoors/mod_pocketDim/world/PersonalPocketProvider.java @@ -0,0 +1,85 @@ +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(.89, .89, .89); + } + + 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(.89, .89, .89); + } + + @Override + public int getRespawnDimension(EntityPlayerMP player) + { + return this.dimensionId; + } + + //TODO only owning player can respawn here + @Override + public boolean canRespawnHere() + { + return true; + } + + @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 7b9ed43..1c29c90 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/world/PocketBuilder.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/world/PocketBuilder.java @@ -3,6 +3,8 @@ 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; @@ -10,6 +12,7 @@ import net.minecraft.world.chunk.storage.ExtendedBlockStorage; import net.minecraftforge.common.DimensionManager; import StevenDimDoors.experimental.MazeBuilder; 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; @@ -261,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!"); } @@ -273,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) { @@ -311,13 +312,73 @@ public class PocketBuilder { throw new IllegalArgumentException("size must be large enough to fit the specified wall thickness and some air space."); } + } + + 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.registerPersonalPocket(parent, 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 dest = LimboProvider.getLimboSkySpawn((EntityPlayer) player, properties); + 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(dest.getX(), destinationY, dest.getZ(), LinkTypes.REVERSE,(link.orientation()+2)%4); + parent.setDestination(reverseLink, source.getX(), source.getY(), source.getZ()); + + //Build the actual pocket area + buildPocket(world, dest.getX(), destinationY, dest.getZ(), orientation, size, wallThickness, properties, door); + + //Finish up destination initialization + dimension.initializePocket(dest.getX(), destinationY, dest.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) + { + validatePocketSetup(link, size, wallThickness, properties, door); + try { //Register a new dimension NewDimData parent = PocketManager.getDimensionData(link.source().getDimension()); NewDimData dimension = PocketManager.registerPocket(parent, false); + //Load a world World world = PocketManager.loadDimension(dimension.id()); @@ -385,23 +446,30 @@ 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; @@ -418,14 +486,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); } } @@ -433,8 +501,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); } } } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/world/PocketProvider.java b/src/main/java/StevenDimDoors/mod_pocketDim/world/PocketProvider.java index 08924d8..68a5217 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/world/PocketProvider.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/world/PocketProvider.java @@ -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() { diff --git a/src/main/java/StevenDimDoors/mod_pocketDimClient/ClientProxy.java b/src/main/java/StevenDimDoors/mod_pocketDimClient/ClientProxy.java index 59bb2a8..873aa8f 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDimClient/ClientProxy.java +++ b/src/main/java/StevenDimDoors/mod_pocketDimClient/ClientProxy.java @@ -24,9 +24,11 @@ public class ClientProxy extends CommonProxy 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()); - + //MinecraftForgeClient.preloadTexture(RIFT2_PNG); RenderingRegistry.registerEntityRenderingHandler(MobMonolith.class, new RenderMobObelisk(.5F)); + RenderingRegistry.registerBlockHandler(new PrivatePocketRender(RenderingRegistry.getNextAvailableRenderId())); + } @Override 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..e6d640e --- /dev/null +++ b/src/main/java/StevenDimDoors/mod_pocketDimClient/PrivatePocketRender.java @@ -0,0 +1,139 @@ +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) + { + super(); + PrivatePocketRender.renderID = renderID; + } + + @Override + public void renderInventoryBlock(Block block, int metadata, int modelID, RenderBlocks renderer) + { + + } + + @Override + public boolean renderWorldBlock(IBlockAccess world, int x, int y, int z, Block block, int modelId, RenderBlocks renderer) + { + float par5 = .5F; + float par6 = .5F; + float par7 = .5F; + Tessellator tessellator = Tessellator.instance; + boolean flag = false; + float f3 = 0.5F; + float f4 = 1.0F; + float f5 = 0.8F; + float f6 = 0.6F; + float f7 = f4 * par5; + float f8 = f4 * par6; + float f9 = f4 * par7; + float f10 = f3; + float f11 = f5; + float f12 = f6; + float f13 = f3; + float f14 = f5; + float f15 = f6; + float f16 = f3; + float f17 = f5; + float f18 = f6; + + if (block != Block.grass) + { + f10 = f3 * par5; + f11 = f5 * par5; + f12 = f6 * par5; + f13 = f3 * par6; + f14 = f5 * par6; + f15 = f6 * par6; + f16 = f3 * par7; + f17 = f5 * par7; + f18 = f6 * par7; + } + + tessellator.setColorOpaque_F(.89F, .89F, .89F); + + if (renderer.renderAllFaces || block.shouldSideBeRendered(world, x, y - 1, z, 0)) + { + renderer.renderFaceYNeg(block, (double)x, (double)y, (double)z, renderer.getBlockIcon(block, world, x, y, z, 0)); + flag = true; + } + + if (renderer.renderAllFaces || block.shouldSideBeRendered(world, x, y + 1, z, 1)) + { + renderer.renderFaceYPos(block, (double)x, (double)y, (double)z, renderer.getBlockIcon(block, world, x, y, z, 1)); + flag = true; + } + + Icon icon; + + if (renderer.renderAllFaces || block.shouldSideBeRendered(world, x, y, z - 1, 2)) + { + icon = renderer.getBlockIcon(block, world, x, y, z, 2); + renderer.renderFaceZNeg(block, (double)x, (double)y, (double)z, icon); + + + flag = true; + } + + if (renderer.renderAllFaces || block.shouldSideBeRendered(world, x, y, z + 1, 3)) + { + icon = renderer.getBlockIcon(block, world, x, y, z, 3); + renderer.renderFaceZPos(block, (double)x, (double)y, (double)z, icon); + + + + flag = true; + } + + if (renderer.renderAllFaces || block.shouldSideBeRendered(world, x - 1, y, z, 4)) + { + icon = renderer.getBlockIcon(block, world, x, y, z, 4); + renderer.renderFaceXNeg(block, (double)x, (double)y, (double)z, icon); + + + + flag = true; + } + + if (renderer.renderAllFaces || block.shouldSideBeRendered(world, x + 1, y, z, 5)) + { + icon = renderer.getBlockIcon(block, world, x, 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/resources/assets/dimdoors/textures/blocks/tile.blockDimWallPersonal.png b/src/main/resources/assets/dimdoors/textures/blocks/tile.blockDimWallPersonal.png new file mode 100644 index 0000000000000000000000000000000000000000..0e9e7a4f7813b119b1ca7df04d1292fecaefaedb GIT binary patch literal 2802 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 literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..a1c590cec45abd46571e2e6f13a365c42dc7184a GIT binary patch literal 3456 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/dimdoors/textures/items/itemChaosDoor.png b/src/main/resources/assets/dimdoors/textures/items/itemChaosDoor.png index 142ed3666236ee160af5a880009355922c3f029b..4196acebf6666e70f748c68af9c76f22870b43cb 100644 GIT binary patch delta 2958 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 Ef-6{}hyVZp delta 189 zcmV;u07Czi7uf-jB!8euL_t(|+GAj#HaL6s?0-Ud>eQ+K@fwiO)AaxHv-|%S?%531 zP_j1sf8WW>|NT2A6K4QSbK4<5u!iXuv;S9Y3I>Z4WdOxqh@a{Fzx#CffAatpum*h( zx&Ix9qy87K^#${Ne0=a5kUB5mf8iR>|0X^PU=1#bI{)i-1vdVVo#sL(FVNfof?+WD ry@1yMkR&k}rvbUSx&Mj5RLi{pf2gcHvwg;V00000NkvXXu0mjfHjH19 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 0000000000000000000000000000000000000000..33fc4ef0d20c0dcb0c3ec6ce282eeb03dfabc664 GIT binary patch literal 3031 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 Z8UV1fLkqNKRqFr%002ovPDHLkV1mT{sICA2 literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..33fc4ef0d20c0dcb0c3ec6ce282eeb03dfabc664 GIT binary patch literal 3031 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 Z8UV1fLkqNKRqFr%002ovPDHLkV1mT{sICA2 literal 0 HcmV?d00001 From 844950b39ec89fba051b1897cbf9608d865cba33 Mon Sep 17 00:00:00 2001 From: StevenRS11 Date: Mon, 26 May 2014 21:31:14 -0400 Subject: [PATCH 099/187] teaked personal pocket generation rules --- .../mod_pocketDim/EventHookContainer.java | 22 ++++++++++++++----- .../mod_pocketDim/world/PocketBuilder.java | 15 +++++++++---- 2 files changed, 27 insertions(+), 10 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java b/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java index be2125e..6b76598 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java @@ -1,14 +1,11 @@ package StevenDimDoors.mod_pocketDim; -import net.minecraft.block.Block; import net.minecraft.client.audio.SoundManager; import net.minecraft.client.audio.SoundPoolEntry; import net.minecraft.entity.Entity; 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.ChunkCoordinates; import net.minecraft.world.World; import net.minecraftforge.client.event.sound.PlayBackgroundMusicEvent; import net.minecraftforge.client.event.sound.SoundLoadEvent; @@ -20,11 +17,11 @@ import net.minecraftforge.event.entity.player.PlayerInteractEvent; import net.minecraftforge.event.entity.player.PlayerInteractEvent.Action; import net.minecraftforge.event.terraingen.InitMapGenEvent; import net.minecraftforge.event.world.WorldEvent; -import StevenDimDoors.mod_pocketDim.blocks.BaseDimDoor; import StevenDimDoors.mod_pocketDim.config.DDProperties; import StevenDimDoors.mod_pocketDim.core.DDTeleporter; +import StevenDimDoors.mod_pocketDim.core.NewDimData; import StevenDimDoors.mod_pocketDim.core.PocketManager; -import StevenDimDoors.mod_pocketDim.items.BaseItemDoor; +import StevenDimDoors.mod_pocketDim.items.ItemWarpDoor; import StevenDimDoors.mod_pocketDim.util.Point4D; import StevenDimDoors.mod_pocketDim.world.LimboProvider; import StevenDimDoors.mod_pocketDim.world.PocketProvider; @@ -78,7 +75,6 @@ public class EventHookContainer public void onSoundEffectResult(PlayBackgroundMusicEvent event) { if (FMLClientHandler.instance().getClient().thePlayer.worldObj.provider.dimensionId == mod_pocketDim.properties.LimboDimensionID) - ; { this.playMusicForDim(FMLClientHandler.instance().getClient().thePlayer.worldObj); } @@ -96,6 +92,20 @@ public class EventHookContainer ItemStack stack = event.entityPlayer.inventory.getCurrentItem(); if (stack != null && stack.getItem() instanceof ItemDoor) { + if(stack.getItem() instanceof ItemWarpDoor) + { + NewDimData data = PocketManager.getDimensionData(world); + while(data.depth()>0) + { + if(PocketManager.getPersonalPocketMapping().containsValue(data)) + { + mod_pocketDim.sendChat(event.entityPlayer,("Something prevents the Warp Door from tunneling out here")); + event.setCanceled(true); + return; + } + data = data.parent(); + } + } if (mod_pocketDim.itemDimensionalDoor.tryToPlaceDoor(stack, event.entityPlayer, world, event.x, event.y, event.z, event.face)) { diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/world/PocketBuilder.java b/src/main/java/StevenDimDoors/mod_pocketDim/world/PocketBuilder.java index 1c29c90..1577f9f 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/world/PocketBuilder.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/world/PocketBuilder.java @@ -314,6 +314,14 @@ public class PocketBuilder } } + /**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 @@ -343,20 +351,19 @@ public class PocketBuilder } //Calculate the destination point - Point4D dest = LimboProvider.getLimboSkySpawn((EntityPlayer) player, properties); 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(dest.getX(), destinationY, dest.getZ(), LinkTypes.REVERSE,(link.orientation()+2)%4); + DimLink reverseLink = dimension.createLink(source.getX(), destinationY, source.getZ(), LinkTypes.REVERSE,(link.orientation()+2)%4); parent.setDestination(reverseLink, source.getX(), source.getY(), source.getZ()); //Build the actual pocket area - buildPocket(world, dest.getX(), destinationY, dest.getZ(), orientation, size, wallThickness, properties, door); + buildPocket(world, source.getX(), destinationY, source.getZ(), orientation, size, wallThickness, properties, door); //Finish up destination initialization - dimension.initializePocket(dest.getX(), destinationY, dest.getZ(), orientation, link); + dimension.initializePocket(source.getX(), destinationY, source.getZ(), orientation, link); dimension.setFilled(true); return true; From 77241e6f908ec0da25c893202d6370151b836539 Mon Sep 17 00:00:00 2001 From: StevenRS11 Date: Mon, 26 May 2014 22:14:20 -0400 Subject: [PATCH 100/187] limbo fix --- .../mod_pocketDim/EventHookContainer.java | 24 ++++++++++++++----- .../world/PersonalPocketProvider.java | 13 ---------- 2 files changed, 18 insertions(+), 19 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java b/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java index 6b76598..7a2ed8b 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java @@ -6,6 +6,7 @@ import net.minecraft.entity.Entity; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.ItemDoor; import net.minecraft.item.ItemStack; +import net.minecraft.util.DamageSource; import net.minecraft.world.World; import net.minecraftforge.client.event.sound.PlayBackgroundMusicEvent; import net.minecraftforge.client.event.sound.SoundLoadEvent; @@ -150,13 +151,24 @@ public class EventHookContainer Entity entity = event.entity; if (properties.LimboEnabled && properties.LimboReturnsInventoryEnabled && - entity instanceof EntityPlayer && entity.worldObj.provider instanceof PocketProvider) + entity instanceof EntityPlayer) { - EntityPlayer player = (EntityPlayer) entity; - mod_pocketDim.deathTracker.addUsername(player.username); - revivePlayerInLimbo(player); - event.setCanceled(true); - return false; + 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; } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/world/PersonalPocketProvider.java b/src/main/java/StevenDimDoors/mod_pocketDim/world/PersonalPocketProvider.java index fe9ac66..8c5a434 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/world/PersonalPocketProvider.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/world/PersonalPocketProvider.java @@ -64,19 +64,6 @@ public class PersonalPocketProvider extends PocketProvider return this.worldObj.getWorldVec3Pool().getVecFromPool(.89, .89, .89); } - @Override - public int getRespawnDimension(EntityPlayerMP player) - { - return this.dimensionId; - } - - //TODO only owning player can respawn here - @Override - public boolean canRespawnHere() - { - return true; - } - @Override public int getActualHeight() { From 7da3b7fc62d6bf1b3c37a10894942a87f0119776 Mon Sep 17 00:00:00 2001 From: StevenRS11 Date: Mon, 26 May 2014 22:23:36 -0400 Subject: [PATCH 101/187] Patched a door crash bug thanks LClouds --- .../mod_pocketDim/EventHookContainer.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java b/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java index 9f7fd0c..4e47d8f 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java @@ -75,7 +75,6 @@ public class EventHookContainer public void onSoundEffectResult(PlayBackgroundMusicEvent event) { if (FMLClientHandler.instance().getClient().thePlayer.worldObj.provider.dimensionId == mod_pocketDim.properties.LimboDimensionID) - ; { this.playMusicForDim(FMLClientHandler.instance().getClient().thePlayer.worldObj); } @@ -93,11 +92,14 @@ public class EventHookContainer ItemStack stack = event.entityPlayer.inventory.getCurrentItem(); if (stack != null && stack.getItem() instanceof ItemDoor) { - if (mod_pocketDim.itemDimensionalDoor.tryToPlaceDoor(stack, event.entityPlayer, world, - event.x, event.y, event.z, event.face)) + if(BaseItemDoor.getDoorToPlace(stack.getItem())!=null) { - // Cancel the event so that we don't get two doors from vanilla doors - event.setCanceled(true); + if (mod_pocketDim.itemDimensionalDoor.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); + } } } } From e8fa928c5023e64d1f4bccab169e49b3784fa5d9 Mon Sep 17 00:00:00 2001 From: StevenRS11 Date: Thu, 29 May 2014 19:04:23 -0400 Subject: [PATCH 102/187] lock tweaks Changed how locks are modified so all modifications occur through NewDimData --- .../mod_pocketDim/core/DDLock.java | 4 +- .../mod_pocketDim/core/DimLink.java | 31 +---------- .../mod_pocketDim/core/NewDimData.java | 55 ++++++++++++++++--- .../mod_pocketDim/core/PocketManager.java | 2 +- .../mod_pocketDim/items/ItemDDKey.java | 4 +- 5 files changed, 55 insertions(+), 41 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/core/DDLock.java b/src/main/java/StevenDimDoors/mod_pocketDim/core/DDLock.java index 3b00196..4066905 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/core/DDLock.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/core/DDLock.java @@ -40,7 +40,7 @@ public class DDLock * otherwise returns true * @param flag */ - public void lock(boolean flag) + protected void lock(boolean flag) { this.isLocked = flag; } @@ -157,7 +157,7 @@ public class DDLock - public static DDLock createLock(ItemStack itemStack, int lockKey2) + protected static DDLock createLock(ItemStack itemStack, int lockKey2) { itemStack.getTagCompound().setBoolean("HasCreatedLock", true); DDLock.setKeys(itemStack, new int[]{lockKey2}); diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/core/DimLink.java b/src/main/java/StevenDimDoors/mod_pocketDim/core/DimLink.java index de26cd5..a07b46d 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/core/DimLink.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/core/DimLink.java @@ -10,7 +10,7 @@ public abstract class DimLink { protected Point4D point; protected int orientation; - private DDLock lock; + protected DDLock lock; protected DimLink parent; protected LinkTail tail; protected List children; @@ -151,36 +151,9 @@ public abstract class DimLink { return this.hasLock()&&this.lock.isLocked(); } - + public DDLock getLock() { - PocketManager.getDimensionData(this.source().getDimension()).flagModified(); return this.lock; } - /** - * only use this on the client to update errything - * @param lock - */ - public void setLock(DDLock lock) - { - PocketManager.getDimensionData(this.source().getDimension()).flagModified(); - 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.createLock(itemStack, lockKey); - PocketManager.getDimensionData(this.source().getDimension()).flagModified(); - return true; - } - } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/core/NewDimData.java b/src/main/java/StevenDimDoors/mod_pocketDim/core/NewDimData.java index eef3432..36b5f3d 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/core/NewDimData.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/core/NewDimData.java @@ -7,6 +7,7 @@ import java.util.Random; import java.util.TreeMap; import StevenDimDoors.mod_pocketDim.watcher.ClientLinkData; +import net.minecraft.item.ItemStack; import net.minecraft.world.World; import StevenDimDoors.mod_pocketDim.Point3D; import StevenDimDoors.mod_pocketDim.config.DDProperties; @@ -98,6 +99,31 @@ public abstract class NewDimData implements IPackable //Set new 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.createLock(itemStack, lockKey); + return true; + } + } protected static Random random = new Random(); @@ -561,6 +587,27 @@ public abstract class NewDimData implements IPackable link.setDestination(x, y, z, this); this.modified = true; } + + public void lock(DimLink link, boolean locked) + { + InnerDimLink innerLink = (InnerDimLink)link; + innerLink.lock.lock(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 DimLink getRandomLink() { @@ -583,11 +630,6 @@ public abstract class NewDimData implements IPackable return modified; } - public void flagModified() - { - modified = true; - } - public void clearModified() { this.modified = false; @@ -655,13 +697,12 @@ public abstract class NewDimData implements IPackable 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.getLock())); + 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); - } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/core/PocketManager.java b/src/main/java/StevenDimDoors/mod_pocketDim/core/PocketManager.java index 0488fa9..393b708 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/core/PocketManager.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/core/PocketManager.java @@ -80,7 +80,7 @@ public class PocketManager Point4D source = link.point; NewDimData dimension = getDimensionData(source.getDimension()); DimLink dLink = dimension.getLink(source); - dLink.setLock(link.lock); + dLink.lock=link.lock; } } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemDDKey.java b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemDDKey.java index 70b838a..a79162e 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemDDKey.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemDDKey.java @@ -102,7 +102,7 @@ public class ItemDDKey extends Item { world.playSoundAtEntity(player, mod_pocketDim.modid + ":keyLock", 1F, 1F); } - link.getLock().lock(!link.isLocked()); + PocketManager.getDimensionData(world).lock(link, !link.isLocked()); PocketManager.getLinkWatcher().update(new ClientLinkData(link.source(),link.getLock())); } else @@ -115,7 +115,7 @@ public class ItemDDKey extends Item if(!DDLock.hasCreatedLock(itemStack)) { world.playSoundAtEntity(player, mod_pocketDim.modid + ":keyLock", 1F, 1F); - link.createLock(itemStack, world.rand.nextInt(Integer.MAX_VALUE)); + PocketManager.getDimensionData(world).createLock(link, itemStack, world.rand.nextInt(Integer.MAX_VALUE)); PocketManager.getLinkWatcher().update(new ClientLinkData(link.source(),link.getLock())); } } From dccb12116d67eb411306b915ba795bc0228dca95 Mon Sep 17 00:00:00 2001 From: StevenRS11 Date: Sat, 31 May 2014 06:39:26 -0400 Subject: [PATCH 103/187] Naming improvements Clarified naming in DDLock and associated methods. Still not quite done. --- .../mod_pocketDim/blocks/BaseDimDoor.java | 6 +-- .../mod_pocketDim/blocks/TransTrapdoor.java | 4 +- .../mod_pocketDim/core/DDLock.java | 24 +++++----- .../mod_pocketDim/core/DimLink.java | 22 ++++++--- .../mod_pocketDim/core/NewDimData.java | 4 +- .../mod_pocketDim/items/ItemDDKey.java | 6 +-- .../mod_pocketDim/mod_pocketDim.java | 2 +- .../mod_pocketDim/watcher/ClientLinkData.java | 2 +- .../world/PersonalPocketProvider.java | 4 +- .../PrivatePocketRender.java | 47 ++++--------------- 10 files changed, 49 insertions(+), 72 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BaseDimDoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BaseDimDoor.java index 5ddc7a7..9fc2901 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BaseDimDoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BaseDimDoor.java @@ -474,7 +474,7 @@ public abstract class BaseDimDoor extends BlockDoor implements IDimDoor, ITileEn if(link!=null&&link.hasLock()) { status++; - if(link.isLocked()) + if(link.getLockState()) { status++; } @@ -495,7 +495,7 @@ public abstract class BaseDimDoor extends BlockDoor implements IDimDoor, ITileEn { return link==null; } - if(!link.isLocked()) + if(!link.getLockState()) { return true; } @@ -506,7 +506,7 @@ public abstract class BaseDimDoor extends BlockDoor implements IDimDoor, ITileEn { if(item.getItem() instanceof ItemDDKey) { - if(link.open(item)) + if(link.tryToOpen(item)) { return true; } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/TransTrapdoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/TransTrapdoor.java index f4d8746..8c51651 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/TransTrapdoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/TransTrapdoor.java @@ -55,7 +55,7 @@ public class TransTrapdoor extends BlockTrapDoor implements IDimDoor, ITileEntit { return link==null; } - if(!link.isLocked()) + if(!link.getLockState()) { return true; } @@ -66,7 +66,7 @@ public class TransTrapdoor extends BlockTrapDoor implements IDimDoor, ITileEntit { if(item.getItem() instanceof ItemDDKey) { - if(link.open(item)) + if(link.tryToOpen(item)) { return true; } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/core/DDLock.java b/src/main/java/StevenDimDoors/mod_pocketDim/core/DDLock.java index 4066905..5b54904 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/core/DDLock.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/core/DDLock.java @@ -12,13 +12,13 @@ import net.minecraft.nbt.NBTTagList; public class DDLock { - private boolean isLocked; + private boolean lockState; private final int lockKey; public DDLock(boolean isLocked, int lockKey) { - this.isLocked = isLocked; + this.lockState = isLocked; this.lockKey = lockKey; } @@ -30,9 +30,9 @@ public class DDLock * See if the lock is currently locked. False if there is no lock. * @return */ - public boolean isLocked() + public boolean getLockState() { - return this.isLocked; + return this.lockState; } /** @@ -40,9 +40,9 @@ public class DDLock * otherwise returns true * @param flag */ - protected void lock(boolean flag) + protected void setLockState(boolean flag) { - this.isLocked = flag; + this.lockState = flag; } @@ -52,7 +52,7 @@ public class DDLock * @param itemStack * @return */ - public boolean canOpen(ItemStack itemStack) + public boolean doesKeyUnlock(ItemStack itemStack) { for(int key :getKeys(itemStack)) { @@ -69,9 +69,9 @@ public class DDLock * @param item * @return */ - public boolean open(ItemStack itemStack) + public boolean tryToOpen(ItemStack itemStack) { - return (!this.isLocked)||this.canOpen(itemStack); + return (!this.lockState)||this.doesKeyUnlock(itemStack); } /** @@ -139,7 +139,7 @@ public class DDLock public static boolean hasCreatedLock(ItemStack key) { - if(isKey(key)) + if(isItemKey(key)) { if(key.hasTagCompound()) { @@ -150,14 +150,14 @@ public class DDLock return false; } - public static boolean isKey(ItemStack key) + public static boolean isItemKey(ItemStack key) { return key.getItem() instanceof ItemDDKey; } - protected static DDLock createLock(ItemStack itemStack, int lockKey2) + protected static DDLock generateLockKeyPair(ItemStack itemStack, int lockKey2) { itemStack.getTagCompound().setBoolean("HasCreatedLock", true); DDLock.setKeys(itemStack, new int[]{lockKey2}); diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/core/DimLink.java b/src/main/java/StevenDimDoors/mod_pocketDim/core/DimLink.java index a07b46d..eaf5618 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/core/DimLink.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/core/DimLink.java @@ -124,18 +124,18 @@ public abstract class DimLink * Tries to open this lock. Returns true if the lock is open or if the key can open it * @return */ - public boolean open(ItemStack item) + public boolean tryToOpen(ItemStack item) { - return lock.open(item); + return lock.tryToOpen(item); } /** - * Tries to open this lock. Returns true if the lock is open or if the key can open it + * Tests if the given key item fits this lock * @return */ - public boolean canOpen(ItemStack item) + public boolean doesKeyUnlock(ItemStack item) { - return lock.canOpen(item); + return lock.doesKeyUnlock(item); } /** @@ -147,11 +147,19 @@ public abstract class DimLink return this.lock!=null; } - public boolean isLocked() + /** + * Tests if the lock is open or not + * + */ + public boolean getLockState() { - return this.hasLock()&&this.lock.isLocked(); + return this.hasLock()&&this.lock.getLockState(); } + /** + * gets the actual lock object + * @return + */ public DDLock getLock() { return this.lock; diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/core/NewDimData.java b/src/main/java/StevenDimDoors/mod_pocketDim/core/NewDimData.java index 36b5f3d..4923a31 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/core/NewDimData.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/core/NewDimData.java @@ -120,7 +120,7 @@ public abstract class NewDimData implements IPackable { return false; } - this.lock = DDLock.createLock(itemStack, lockKey); + this.lock = DDLock.generateLockKeyPair(itemStack, lockKey); return true; } @@ -591,7 +591,7 @@ public abstract class NewDimData implements IPackable public void lock(DimLink link, boolean locked) { InnerDimLink innerLink = (InnerDimLink)link; - innerLink.lock.lock(locked); + innerLink.lock.setLockState(locked); modified = true; } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemDDKey.java b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemDDKey.java index a79162e..1721317 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemDDKey.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemDDKey.java @@ -92,9 +92,9 @@ public class ItemDDKey extends Item //what to do if the door has a lock already if(link.hasLock()) { - if(link.canOpen(itemStack)) + if(link.doesKeyUnlock(itemStack)) { - if(link.isLocked()) + if(link.getLockState()) { world.playSoundAtEntity(player, mod_pocketDim.modid + ":keyUnlock", 1F, 1F); } @@ -102,7 +102,7 @@ public class ItemDDKey extends Item { world.playSoundAtEntity(player, mod_pocketDim.modid + ":keyLock", 1F, 1F); } - PocketManager.getDimensionData(world).lock(link, !link.isLocked()); + PocketManager.getDimensionData(world).lock(link, !link.getLockState()); PocketManager.getLinkWatcher().update(new ClientLinkData(link.source(),link.getLock())); } else diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java b/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java index 5b1a3cd..d31eb66 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java @@ -212,7 +212,7 @@ public class mod_pocketDim 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"); + blockDimWall = new BlockDimWall(properties.FabricBlockID, 0, Material.iron).setLightValue(1.5F).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")); diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/watcher/ClientLinkData.java b/src/main/java/StevenDimDoors/mod_pocketDim/watcher/ClientLinkData.java index 34b7274..9694c62 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/watcher/ClientLinkData.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/watcher/ClientLinkData.java @@ -37,7 +37,7 @@ public class ClientLinkData if (hasLock) { - output.writeBoolean(lock.isLocked()); + output.writeBoolean(lock.getLockState()); output.writeInt(lock.getLockKey()); } } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/world/PersonalPocketProvider.java b/src/main/java/StevenDimDoors/mod_pocketDim/world/PersonalPocketProvider.java index 8c5a434..8f1b824 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/world/PersonalPocketProvider.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/world/PersonalPocketProvider.java @@ -31,7 +31,7 @@ public class PersonalPocketProvider extends PocketProvider public Vec3 getSkyColor(Entity cameraEntity, float partialTicks) { setCloudRenderer( new CloudRenderBlank()); - return this.worldObj.getWorldVec3Pool().getVecFromPool(.89, .89, .89); + return this.worldObj.getWorldVec3Pool().getVecFromPool(1,1,1); } public boolean isSurfaceWorld() @@ -61,7 +61,7 @@ public class PersonalPocketProvider extends PocketProvider @Override public Vec3 getFogColor(float par1, float par2) { - return this.worldObj.getWorldVec3Pool().getVecFromPool(.89, .89, .89); + return this.worldObj.getWorldVec3Pool().getVecFromPool(1,1,1); } @Override diff --git a/src/main/java/StevenDimDoors/mod_pocketDimClient/PrivatePocketRender.java b/src/main/java/StevenDimDoors/mod_pocketDimClient/PrivatePocketRender.java index e6d640e..287a4ee 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDimClient/PrivatePocketRender.java +++ b/src/main/java/StevenDimDoors/mod_pocketDimClient/PrivatePocketRender.java @@ -28,60 +28,32 @@ public class PrivatePocketRender implements ISimpleBlockRenderingHandler @Override public boolean renderWorldBlock(IBlockAccess world, int x, int y, int z, Block block, int modelId, RenderBlocks renderer) { - float par5 = .5F; - float par6 = .5F; - float par7 = .5F; + Tessellator tessellator = Tessellator.instance; boolean flag = false; - float f3 = 0.5F; - float f4 = 1.0F; - float f5 = 0.8F; - float f6 = 0.6F; - float f7 = f4 * par5; - float f8 = f4 * par6; - float f9 = f4 * par7; - float f10 = f3; - float f11 = f5; - float f12 = f6; - float f13 = f3; - float f14 = f5; - float f15 = f6; - float f16 = f3; - float f17 = f5; - float f18 = f6; - if (block != Block.grass) - { - f10 = f3 * par5; - f11 = f5 * par5; - f12 = f6 * par5; - f13 = f3 * par6; - f14 = f5 * par6; - f15 = f6 * par6; - f16 = f3 * par7; - f17 = f5 * par7; - f18 = f6 * par7; - } + Icon icon = renderer.getBlockIcon(block, world, x, y, z, 2); + - tessellator.setColorOpaque_F(.89F, .89F, .89F); + 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, renderer.getBlockIcon(block, world, x, y, z, 0)); + renderer.renderFaceYNeg(block, (double)x, (double)y, (double)z, icon); flag = true; } if (renderer.renderAllFaces || block.shouldSideBeRendered(world, x, y + 1, z, 1)) { - renderer.renderFaceYPos(block, (double)x, (double)y, (double)z, renderer.getBlockIcon(block, world, x, y, z, 1)); + renderer.renderFaceYPos(block, (double)x, (double)y, (double)z, icon); flag = true; } - Icon icon; + if (renderer.renderAllFaces || block.shouldSideBeRendered(world, x, y, z - 1, 2)) { - icon = renderer.getBlockIcon(block, world, x, y, z, 2); renderer.renderFaceZNeg(block, (double)x, (double)y, (double)z, icon); @@ -90,7 +62,6 @@ public class PrivatePocketRender implements ISimpleBlockRenderingHandler if (renderer.renderAllFaces || block.shouldSideBeRendered(world, x, y, z + 1, 3)) { - icon = renderer.getBlockIcon(block, world, x, y, z, 3); renderer.renderFaceZPos(block, (double)x, (double)y, (double)z, icon); @@ -100,7 +71,6 @@ public class PrivatePocketRender implements ISimpleBlockRenderingHandler if (renderer.renderAllFaces || block.shouldSideBeRendered(world, x - 1, y, z, 4)) { - icon = renderer.getBlockIcon(block, world, x, y, z, 4); renderer.renderFaceXNeg(block, (double)x, (double)y, (double)z, icon); @@ -110,7 +80,6 @@ public class PrivatePocketRender implements ISimpleBlockRenderingHandler if (renderer.renderAllFaces || block.shouldSideBeRendered(world, x + 1, y, z, 5)) { - icon = renderer.getBlockIcon(block, world, x, y, z, 5); renderer.renderFaceXPos(block, (double)x, (double)y, (double)z, icon); From 0d53f6c029d9dc46ef113f0b020b83404c177c44 Mon Sep 17 00:00:00 2001 From: StevenRS11 Date: Sat, 31 May 2014 06:43:28 -0400 Subject: [PATCH 104/187] Actually fix door crash --- .../java/StevenDimDoors/mod_pocketDim/items/BaseItemDoor.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/items/BaseItemDoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/items/BaseItemDoor.java index 319a258..dafcd91 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/items/BaseItemDoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/items/BaseItemDoor.java @@ -83,6 +83,10 @@ public abstract class BaseItemDoor extends ItemDoor { item = BaseItemDoor.vanillaDoorMapping.get(item); } + if(item == null) + { + return null; + } return ((BaseItemDoor) item).getDoortoItemMapping(); } From 117ed69bf7631305e96f615c57f258f290af559c Mon Sep 17 00:00:00 2001 From: StevenRS11 Date: Fri, 20 Jun 2014 13:46:36 -0400 Subject: [PATCH 105/187] added dimdata schema --- .../mod_pocketDim/helpers/DungeonHelper.java | 2 +- .../mod_pocketDim/util/JSONValidator.java | 544 ++++++++++++++++++ .../assets/dimdoors/text/Dim_Data_Schema.json | 229 ++++++++ 3 files changed, 774 insertions(+), 1 deletion(-) create mode 100644 src/main/java/StevenDimDoors/mod_pocketDim/util/JSONValidator.java create mode 100644 src/main/resources/assets/dimdoors/text/Dim_Data_Schema.json diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/helpers/DungeonHelper.java b/src/main/java/StevenDimDoors/mod_pocketDim/helpers/DungeonHelper.java index 2c9775e..1605202 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/helpers/DungeonHelper.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/helpers/DungeonHelper.java @@ -46,7 +46,7 @@ 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 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"; 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/resources/assets/dimdoors/text/Dim_Data_Schema.json b/src/main/resources/assets/dimdoors/text/Dim_Data_Schema.json new file mode 100644 index 0000000..997b6dc --- /dev/null +++ b/src/main/resources/assets/dimdoors/text/Dim_Data_Schema.json @@ -0,0 +1,229 @@ +{ + "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": "number" + } + }, + "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", + "IsDungeon", + "ID", + "Depth", + "ChildIDs" + ] +} From eeb5f9aea10b3d92e45980dd50976fe689c01571 Mon Sep 17 00:00:00 2001 From: StevenRS11 Date: Fri, 20 Jun 2014 14:04:07 -0400 Subject: [PATCH 106/187] added json validation for saves --- .../saving/DimDataProcessor.java | 311 ++-------- .../mod_pocketDim/util/JSONValidator.java | 544 ++++++++++++++++++ .../assets/dimdoors/text/Dim_Data_Schema.json | 229 ++++++++ 3 files changed, 813 insertions(+), 271 deletions(-) create mode 100644 src/main/java/StevenDimDoors/mod_pocketDim/util/JSONValidator.java create mode 100644 src/main/resources/assets/dimdoors/text/Dim_Data_Schema.json diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/saving/DimDataProcessor.java b/src/main/java/StevenDimDoors/mod_pocketDim/saving/DimDataProcessor.java index b8aae24..c30717e 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/saving/DimDataProcessor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/saving/DimDataProcessor.java @@ -1,37 +1,44 @@ package StevenDimDoors.mod_pocketDim.saving; +import java.io.File; 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 StevenDimDoors.mod_pocketDim.Point3D; +import StevenDimDoors.mod_pocketDim.util.BaseConfigurationProcessor; +import StevenDimDoors.mod_pocketDim.util.ConfigurationProcessingException; +import StevenDimDoors.mod_pocketDim.util.JSONValidator; +import StevenDimDoors.mod_pocketDim.util.Point4D; 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; import com.google.gson.stream.JsonToken; -import StevenDimDoors.mod_pocketDim.Point3D; -import StevenDimDoors.mod_pocketDim.core.DDLock; -import StevenDimDoors.mod_pocketDim.util.BaseConfigurationProcessor; -import StevenDimDoors.mod_pocketDim.util.ConfigurationProcessingException; -import StevenDimDoors.mod_pocketDim.util.Point4D; - public class DimDataProcessor extends BaseConfigurationProcessor { + private static final String JSON_SCHEMA_PATH = "/assets/dimdoors/text/Dim_Data_Schema.json"; + private static final JsonParser jsonParser = new JsonParser(); + @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"); @@ -43,284 +50,46 @@ 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(); + JsonElement ele = gson.toJsonTree(data); try { - outputStream.write(gson.toJson(data).getBytes("UTF-8")); + //ensure our json object corresponds to our schema + validateJson(ele); + outputStream.write(data.toString().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"); } } + + public PackedDimData readDimDataJson(JsonReader reader) throws IOException + { + JsonElement ele = jsonParser.parse(reader); + this.validateJson(ele); + GsonBuilder gsonBuilder = new GsonBuilder(); + return gsonBuilder.create().fromJson(ele, PackedDimData.class); + } + /** - * Nightmare method that takes a JsonReader pointed at a serialized instance of PackedDimData - * @param reader + * checks our json against the dim data schema + * @param data * @return * @throws IOException */ - public PackedDimData createDImDataFromJson(JsonReader reader) throws IOException + public boolean validateJson(JsonElement data) 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(); - - reader.beginObject(); - - reader.nextName(); - if (reader.nextLong() != PackedDimData.SAVE_DATA_VERSION_ID) - { - throw new IOException("Save data version mismatch"); - } - - 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")) - { - Dungeon = createDungeonDataFromJson(reader); - reader.nextName(); - } - - 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); + InputStream in = this.getClass().getResourceAsStream(JSON_SCHEMA_PATH); + JsonReader reader = new JsonReader(new InputStreamReader(in)); + JSONValidator.validate((JsonObject) jsonParser.parse(reader), data); + reader.close(); + in.close(); + return true; } - - private Point3D createPointFromJson(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.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) - { - list.add(reader.nextInt()); - - } - 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 - { - DDLock lock = null; - - 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(); - - if(reader.peek()== JsonToken.NAME) - { - lock = this.createLockFromJson(reader); - } - reader.endObject(); - - return new PackedLinkData(source, parent, tail, orientation, children, lock); - } - 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; - } - - 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); - } - - private DDLock createLockFromJson(JsonReader reader) throws IOException - { - reader.nextName(); - - reader.beginObject(); - reader.nextName(); - - boolean locked = reader.nextBoolean(); - reader.nextName(); - - int key = reader.nextInt(); - reader.endObject(); - - return new DDLock(locked, key); - } - } 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/resources/assets/dimdoors/text/Dim_Data_Schema.json b/src/main/resources/assets/dimdoors/text/Dim_Data_Schema.json new file mode 100644 index 0000000..997b6dc --- /dev/null +++ b/src/main/resources/assets/dimdoors/text/Dim_Data_Schema.json @@ -0,0 +1,229 @@ +{ + "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": "number" + } + }, + "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", + "IsDungeon", + "ID", + "Depth", + "ChildIDs" + ] +} From 968653e4ab65d90960cdc3fe7f1117a2965d9d61 Mon Sep 17 00:00:00 2001 From: StevenRS11 Date: Fri, 20 Jun 2014 14:13:33 -0400 Subject: [PATCH 107/187] fixed typo in DimDataProcessor and DungeonHelper --- .../StevenDimDoors/mod_pocketDim/helpers/DungeonHelper.java | 2 +- .../StevenDimDoors/mod_pocketDim/saving/DimDataProcessor.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/helpers/DungeonHelper.java b/src/main/java/StevenDimDoors/mod_pocketDim/helpers/DungeonHelper.java index 2c9775e..1605202 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/helpers/DungeonHelper.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/helpers/DungeonHelper.java @@ -46,7 +46,7 @@ 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 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"; diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/saving/DimDataProcessor.java b/src/main/java/StevenDimDoors/mod_pocketDim/saving/DimDataProcessor.java index c30717e..cf3f479 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/saving/DimDataProcessor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/saving/DimDataProcessor.java @@ -59,7 +59,7 @@ public class DimDataProcessor extends BaseConfigurationProcessor { //ensure our json object corresponds to our schema validateJson(ele); - outputStream.write(data.toString().getBytes("UTF-8")); + outputStream.write(ele.toString().getBytes("UTF-8")); outputStream.close(); } catch (Exception e) From 9e720cb4585aebad98a999807f8b2ccf973795e8 Mon Sep 17 00:00:00 2001 From: StevenRS11 Date: Wed, 25 Jun 2014 02:12:07 -0400 Subject: [PATCH 108/187] Changed linkTypes to linkType, an enum --- .../blocks/BlockGoldDimDoor.java | 4 +- .../mod_pocketDim/blocks/DimensionalDoor.java | 4 +- .../mod_pocketDim/blocks/PersonalDimDoor.java | 4 +- .../mod_pocketDim/blocks/TransTrapdoor.java | 4 +- .../mod_pocketDim/blocks/TransientDoor.java | 4 +- .../mod_pocketDim/blocks/UnstableDoor.java | 4 +- .../mod_pocketDim/blocks/WarpDoor.java | 4 +- .../commands/CommandCreateDungeonRift.java | 4 +- .../commands/CommandCreateRandomRift.java | 6 +-- .../commands/CommandResetDungeons.java | 12 +++--- .../mod_pocketDim/core/DDTeleporter.java | 31 +++++++------- .../mod_pocketDim/core/DimLink.java | 10 +++-- .../mod_pocketDim/core/LinkTail.java | 8 ++-- .../mod_pocketDim/core/LinkType.java | 42 +++++++++++++++++++ .../mod_pocketDim/core/LinkTypes.java | 23 ---------- .../mod_pocketDim/core/NewDimData.java | 14 +++---- .../mod_pocketDim/core/PocketManager.java | 2 +- .../mod_pocketDim/core/PocketType.java | 16 +++++++ .../dungeon/DungeonSchematic.java | 9 ++-- .../mod_pocketDim/helpers/Compactor.java | 5 +-- .../mod_pocketDim/helpers/DungeonHelper.java | 5 +-- .../items/ItemRiftSignature.java | 7 ++-- .../items/ItemStabilizedRiftSignature.java | 8 ++-- .../mod_pocketDim/mod_pocketDim.java | 2 +- .../mod_pocketDim/saving/DDSaveHandler.java | 11 +---- .../mod_pocketDim/world/PocketBuilder.java | 10 ++--- .../mod_pocketDim/world/PocketProvider.java | 12 ++++++ .../fortresses/ComponentNetherGateway.java | 5 +-- .../world/gateways/BaseSchematicGateway.java | 4 +- .../world/gateways/GatewayGenerator.java | 6 +-- .../world/gateways/GatewayLimbo.java | 4 +- .../PrivatePocketRender.java | 5 +++ .../assets/dimdoors/text/Dim_Data_Schema.json | 3 ++ 33 files changed, 165 insertions(+), 127 deletions(-) create mode 100644 src/main/java/StevenDimDoors/mod_pocketDim/core/LinkType.java delete mode 100644 src/main/java/StevenDimDoors/mod_pocketDim/core/LinkTypes.java create mode 100644 src/main/java/StevenDimDoors/mod_pocketDim/core/PocketType.java diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockGoldDimDoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockGoldDimDoor.java index 5a788db..0812354 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockGoldDimDoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockGoldDimDoor.java @@ -3,7 +3,7 @@ package StevenDimDoors.mod_pocketDim.blocks; 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; @@ -29,7 +29,7 @@ public class BlockGoldDimDoor extends BaseDimDoor 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)); } } } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/DimensionalDoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/DimensionalDoor.java index 42d25f6..3aceab9 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/DimensionalDoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/DimensionalDoor.java @@ -5,7 +5,7 @@ import net.minecraft.item.Item; import net.minecraft.world.World; 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; @@ -27,7 +27,7 @@ public class DimensionalDoor extends BaseDimDoor 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)); } } } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/PersonalDimDoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/PersonalDimDoor.java index a93db80..e3ae014 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/PersonalDimDoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/PersonalDimDoor.java @@ -4,7 +4,7 @@ import net.minecraft.block.material.Material; import net.minecraft.world.World; 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; @@ -26,7 +26,7 @@ public class PersonalDimDoor extends BaseDimDoor DimLink link = dimension.getLink(x, y, z); if (link == null) { - dimension.createLink(x, y, z, LinkTypes.PERSONAL, world.getBlockMetadata(x, y - 1, z)); + dimension.createLink(x, y, z, LinkType.PERSONAL, world.getBlockMetadata(x, y - 1, z)); } } } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/TransTrapdoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/TransTrapdoor.java index 8c51651..a8f774b 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/TransTrapdoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/TransTrapdoor.java @@ -15,7 +15,7 @@ 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; @@ -147,7 +147,7 @@ public class TransTrapdoor extends BlockTrapDoor implements IDimDoor, ITileEntit DimLink link = dimension.getLink(x, y, z); if (link == null && dimension.isPocketDimension()) { - dimension.createLink(x, y, z, LinkTypes.UNSAFE_EXIT,0); + dimension.createLink(x, y, z, LinkType.UNSAFE_EXIT,0); } } } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/TransientDoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/TransientDoor.java index fb0a187..b5f7576 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/TransientDoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/TransientDoor.java @@ -9,7 +9,7 @@ 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.LinkTypes; +import StevenDimDoors.mod_pocketDim.core.LinkType; import StevenDimDoors.mod_pocketDim.core.NewDimData; import StevenDimDoors.mod_pocketDim.core.PocketManager; @@ -68,7 +68,7 @@ public class TransientDoor extends BaseDimDoor 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)); } } } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/UnstableDoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/UnstableDoor.java index e59a94c..a4a7e8a 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/UnstableDoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/UnstableDoor.java @@ -4,7 +4,7 @@ import net.minecraft.block.material.Material; import net.minecraft.item.Item; import net.minecraft.world.World; import StevenDimDoors.mod_pocketDim.config.DDProperties; -import StevenDimDoors.mod_pocketDim.core.LinkTypes; +import StevenDimDoors.mod_pocketDim.core.LinkType; import StevenDimDoors.mod_pocketDim.core.NewDimData; import StevenDimDoors.mod_pocketDim.core.PocketManager; @@ -21,7 +21,7 @@ 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 diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/WarpDoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/WarpDoor.java index 58cfd05..cb21598 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/WarpDoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/WarpDoor.java @@ -5,7 +5,7 @@ import net.minecraft.item.Item; import net.minecraft.world.World; 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; @@ -25,7 +25,7 @@ public class WarpDoor extends BaseDimDoor 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)); } } } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandCreateDungeonRift.java b/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandCreateDungeonRift.java index b1512e3..c6065b8 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandCreateDungeonRift.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandCreateDungeonRift.java @@ -2,7 +2,7 @@ package StevenDimDoors.mod_pocketDim.commands; 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; @@ -68,7 +68,7 @@ public class CommandCreateDungeonRift extends DDCommandBase if (result != null) { dimension = PocketManager.getDimensionData(sender.worldObj); - link = dimension.createLink(x, y + 1, z, LinkTypes.DUNGEON, orientation); + 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 diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandCreateRandomRift.java b/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandCreateRandomRift.java index 97cc1a5..6250c14 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandCreateRandomRift.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandCreateRandomRift.java @@ -8,7 +8,7 @@ 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; @@ -58,7 +58,7 @@ public class CommandCreateRandomRift extends DDCommandBase if (command.length == 0) { dimension = PocketManager.getDimensionData(sender.worldObj); - link = dimension.createLink(x, y + 1, z, LinkTypes.DUNGEON, orientation); + 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."); } @@ -74,7 +74,7 @@ public class CommandCreateRandomRift extends DDCommandBase if (result != null) { dimension = PocketManager.getDimensionData(sender.worldObj); - link = dimension.createLink(x, y + 1, z, LinkTypes.DUNGEON, orientation); + 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 diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandResetDungeons.java b/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandResetDungeons.java index 8176537..0978338 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandResetDungeons.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandResetDungeons.java @@ -1,12 +1,10 @@ package StevenDimDoors.mod_pocketDim.commands; import java.util.ArrayList; - -import net.minecraft.command.ICommandSender; 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.LinkType; import StevenDimDoors.mod_pocketDim.core.NewDimData; import StevenDimDoors.mod_pocketDim.core.PocketManager; @@ -60,13 +58,13 @@ public class CommandResetDungeons extends DDCommandBase dungeonCount++; for(DimLink link : data.links()) { - if(link.linkType()==LinkTypes.REVERSE) + if(link.linkType()==LinkType.REVERSE) { - data.createLink(link.source(), LinkTypes.DUNGEON_EXIT, link.orientation(), null); + data.createLink(link.source(), LinkType.DUNGEON_EXIT, link.orientation(), null); } - if(link.linkType()==LinkTypes.DUNGEON) + if(link.linkType()==LinkType.DUNGEON) { - data.createLink(link.source(), LinkTypes.DUNGEON, link.orientation(), null); + data.createLink(link.source(), LinkType.DUNGEON, link.orientation(), null); } } } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/core/DDTeleporter.java b/src/main/java/StevenDimDoors/mod_pocketDim/core/DDTeleporter.java index ddb2b0c..17c6e69 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/core/DDTeleporter.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/core/DDTeleporter.java @@ -2,7 +2,6 @@ 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; @@ -462,7 +461,7 @@ public class DDTeleporter { return; } - if (link.linkType() == LinkTypes.RANDOM) + if (link.linkType() == LinkType.RANDOM) { Point4D randomDestination = getRandomDestination(); if (randomDestination != null) @@ -474,18 +473,18 @@ public class DDTeleporter 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, Entity entity, Block door) { - if (link.hasDestination()&&link.linkType()!=LinkTypes.PERSONAL) + if (link.hasDestination()&&link.linkType()!=LinkType.PERSONAL) { if(PocketManager.isBlackListed(link.destination().getDimension())) { - link=PocketManager.getDimensionData(link.source().getDimension()).createLink(link.point,LinkTypes.SAFE_EXIT,link.orientation, null); + link=PocketManager.getDimensionData(link.source().getDimension()).createLink(link.point,LinkType.SAFE_EXIT,link.orientation, null); } else { @@ -496,21 +495,21 @@ 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: + case POCKET: return PocketBuilder.generateNewPocket(link, properties,door); - case LinkTypes.PERSONAL: + case PERSONAL: return setupPersonalLink(link, properties, entity, door); - case LinkTypes.SAFE_EXIT: + 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."); @@ -557,7 +556,7 @@ public class DDTeleporter { for (DimLink link : dimension.getAllLinks()) { - if (link.linkType() != LinkTypes.RANDOM) + if (link.linkType() != LinkType.RANDOM) { matches.add(link.source()); } @@ -769,7 +768,7 @@ 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); + DimLink reverse = destinationDim.createLink(x, y + 2, z, LinkType.REVERSE,orientation); sourceDim.setDestination(reverse, source.getX(), source.getY(), source.getZ()); // Set up the warp door at the destination diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/core/DimLink.java b/src/main/java/StevenDimDoors/mod_pocketDim/core/DimLink.java index eaf5618..1232090 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/core/DimLink.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/core/DimLink.java @@ -32,12 +32,16 @@ public abstract class DimLink parent.children.add(this); } - protected DimLink(Point4D point, int orientation, DDLock lock, 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.point = point; @@ -68,7 +72,7 @@ public abstract class DimLink parent = null; point = null; - tail = new LinkTail(0, null); + tail = new LinkTail(LinkType.NORMAL, null); } public int orientation() @@ -109,7 +113,7 @@ public abstract class DimLink return parent; } - public int linkType() + public LinkType linkType() { return tail.getLinkType(); } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/core/LinkTail.java b/src/main/java/StevenDimDoors/mod_pocketDim/core/LinkTail.java index 5513600..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,11 +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 54aef9a..0000000 --- a/src/main/java/StevenDimDoors/mod_pocketDim/core/LinkTypes.java +++ /dev/null @@ -1,23 +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 = 8; - - 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; - public static final int PERSONAL = 8; - -} diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/core/NewDimData.java b/src/main/java/StevenDimDoors/mod_pocketDim/core/NewDimData.java index 4923a31..095b792 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/core/NewDimData.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/core/NewDimData.java @@ -30,7 +30,7 @@ public abstract class NewDimData implements IPackable super(source, orientation, lock, parent); } - public InnerDimLink(Point4D source, int linkType, int orientation, DDLock lock) + public InnerDimLink(Point4D source, LinkType linkType, int orientation, DDLock lock) { super(source, orientation, lock, linkType); } @@ -78,7 +78,7 @@ public abstract class NewDimData implements IPackable return true; } - public void overwrite(int linkType, int orientation) + public void overwrite(LinkType linkType, int orientation) { //Release children for (DimLink child : children) @@ -302,12 +302,12 @@ public abstract class NewDimData implements IPackable 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, null); } - public DimLink createLink(Point4D source, int linkType, int orientation, DDLock locked) + 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. InnerDimLink link = linkMapping.get(source); @@ -324,7 +324,7 @@ public abstract class NewDimData implements IPackable modified = true; //Link created! - if (linkType != LinkTypes.CLIENT_SIDE) + if (linkType != LinkType.CLIENT) { linkWatcher.onCreated(new ClientLinkData(link)); } @@ -696,10 +696,10 @@ public abstract class NewDimData implements IPackable { children.add(childLink.source().toPoint3D()); } - PackedLinkTail tail = new PackedLinkTail(link.tail.getDestination(),link.tail.getLinkType()); + PackedLinkTail tail = new PackedLinkTail(link.tail.getDestination(),link.tail.getLinkType().index); Links.add(new PackedLinkData(link.point,parentPoint,tail,link.orientation,children,link.lock)); - PackedLinkTail tempTail = new PackedLinkTail(link.tail.getDestination(),link.tail.getLinkType()); + PackedLinkTail tempTail = new PackedLinkTail(link.tail.getDestination(),link.tail.getLinkType().index); if(Tails.contains(tempTail)) { Tails.add(tempTail); diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/core/PocketManager.java b/src/main/java/StevenDimDoors/mod_pocketDim/core/PocketManager.java index 393b708..1c8cba5 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/core/PocketManager.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/core/PocketManager.java @@ -63,7 +63,7 @@ public class PocketManager { Point4D source = link.point; NewDimData dimension = getDimensionData(source.getDimension()); - dimension.createLink(source, LinkTypes.CLIENT_SIDE, 0, link.lock); + dimension.createLink(source, LinkType.CLIENT, 0, link.lock); } @Override diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/core/PocketType.java b/src/main/java/StevenDimDoors/mod_pocketDim/core/PocketType.java new file mode 100644 index 0000000..ba3da9d --- /dev/null +++ b/src/main/java/StevenDimDoors/mod_pocketDim/core/PocketType.java @@ -0,0 +1,16 @@ +package StevenDimDoors.mod_pocketDim.core; + +public enum PocketType +{ + // WARNING: Don't modify these values carelessly or you'll risk breaking existing worlds! + NORMAL(0), + DUNGEON(1), + PERSONAL(2); + + PocketType(int index) + { + this.index = index; + } + + public final int index; +} diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/dungeon/DungeonSchematic.java b/src/main/java/StevenDimDoors/mod_pocketDim/dungeon/DungeonSchematic.java index 23bd064..108b38c 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/dungeon/DungeonSchematic.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/dungeon/DungeonSchematic.java @@ -9,7 +9,6 @@ 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; @@ -20,7 +19,7 @@ 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; @@ -322,7 +321,7 @@ 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()); @@ -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/helpers/Compactor.java b/src/main/java/StevenDimDoors/mod_pocketDim/helpers/Compactor.java index 4fdaa9e..13eff90 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/helpers/Compactor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/helpers/Compactor.java @@ -6,10 +6,9 @@ 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.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; @@ -80,7 +79,7 @@ public class Compactor { ClientLinkData link = ClientLinkData.read(input); Point4D source = link.point; - dimension.createLink(source.getX(), source.getY(), source.getZ(), LinkTypes.CLIENT_SIDE,0); + dimension.createLink(source.getX(), source.getY(), source.getZ(), LinkType.CLIENT,0); } } } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/helpers/DungeonHelper.java b/src/main/java/StevenDimDoors/mod_pocketDim/helpers/DungeonHelper.java index 1605202..9c7c630 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/helpers/DungeonHelper.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/helpers/DungeonHelper.java @@ -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.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; @@ -264,7 +263,7 @@ 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); diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemRiftSignature.java b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemRiftSignature.java index a20bc46..82e5396 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; @@ -73,8 +72,8 @@ public class ItemRiftSignature extends Item //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); + DimLink link = sourceDimension.createLink(source.getX(), source.getY(), source.getZ(), LinkType.NORMAL,source.getOrientation()); + DimLink reverse = destinationDimension.createLink(x, adjustedY, z, LinkType.NORMAL,orientation); destinationDimension.setDestination(link, x, adjustedY, z); sourceDimension.setDestination(reverse, source.getX(), source.getY(), source.getZ()); diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemStabilizedRiftSignature.java b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemStabilizedRiftSignature.java index 8dc5570..72abd8c 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; @@ -67,8 +65,8 @@ public class ItemStabilizedRiftSignature extends ItemRiftSignature //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); + DimLink link = sourceDimension.createLink(source.getX(), source.getY(), source.getZ(), LinkType.NORMAL,source.getOrientation()); + DimLink reverse = destinationDimension.createLink(x, adjustedY, z, LinkType.NORMAL,orientation); destinationDimension.setDestination(link, x, adjustedY, z); sourceDimension.setDestination(reverse, source.getX(), source.getY(), source.getZ()); diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java b/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java index d31eb66..5b1a3cd 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java @@ -212,7 +212,7 @@ public class mod_pocketDim 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.5F).setHardness(0.1F).setUnlocalizedName("blockDimWall"); + 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")); diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/saving/DDSaveHandler.java b/src/main/java/StevenDimDoors/mod_pocketDim/saving/DDSaveHandler.java index e721351..a13c2cd 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/saving/DDSaveHandler.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/saving/DDSaveHandler.java @@ -8,12 +8,11 @@ import java.util.HashMap; 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.LinkType; import StevenDimDoors.mod_pocketDim.core.NewDimData; import StevenDimDoors.mod_pocketDim.core.PocketManager; import StevenDimDoors.mod_pocketDim.dungeon.DungeonData; @@ -21,7 +20,6 @@ import StevenDimDoors.mod_pocketDim.helpers.DungeonHelper; 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 @@ -210,12 +208,7 @@ public class DDSaveHandler if(packedLink.parent.equals(fakePoint)) { NewDimData data = PocketManager.getDimensionData(packedLink.source.getDimension()); - int linkType = packedLink.tail.linkType; - - if((linkType < LinkTypes.ENUM_MIN || linkType > LinkTypes.ENUM_MAX) && linkType != LinkTypes.CLIENT_SIDE) - { - linkType = LinkTypes.NORMAL; - } + LinkType linkType = LinkType.getLinkTypeFromIndex(packedLink.tail.linkType); DimLink link = data.createLink(packedLink.source, linkType, packedLink.orientation, packedLink.lock); Point4D destination = packedLink.tail.destination; diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/world/PocketBuilder.java b/src/main/java/StevenDimDoors/mod_pocketDim/world/PocketBuilder.java index 1577f9f..6f6e356 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/world/PocketBuilder.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/world/PocketBuilder.java @@ -1,7 +1,6 @@ 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; @@ -10,13 +9,12 @@ 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.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.LinkType; import StevenDimDoors.mod_pocketDim.core.NewDimData; import StevenDimDoors.mod_pocketDim.core.PocketManager; import StevenDimDoors.mod_pocketDim.dungeon.DungeonData; @@ -24,10 +22,10 @@ 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 { @@ -356,7 +354,7 @@ 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); + DimLink reverseLink = dimension.createLink(source.getX(), destinationY, source.getZ(), LinkType.REVERSE,(link.orientation()+2)%4); parent.setDestination(reverseLink, source.getX(), source.getY(), source.getZ()); //Build the actual pocket area @@ -401,7 +399,7 @@ 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); + DimLink reverseLink = dimension.createLink(source.getX(), destinationY, source.getZ(), LinkType.REVERSE,(link.orientation()+2)%4); parent.setDestination(reverseLink, source.getX(), source.getY(), source.getZ()); //Build the actual pocket area diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/world/PocketProvider.java b/src/main/java/StevenDimDoors/mod_pocketDim/world/PocketProvider.java index 68a5217..257efed 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/world/PocketProvider.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/world/PocketProvider.java @@ -81,6 +81,18 @@ public class PocketProvider extends WorldProvider return false; } + @Override + protected void generateLightBrightnessTable() + { + float modifier = 0.0F; + + for (int steps = 0; steps <= 15; ++steps) + { + float var3 = 1.0F - steps / 15.0F; + this.lightBrightnessTable[steps] = 10; + // System.out.println( this.lightBrightnessTable[steps]+"light"); + } + } @Override public String getDimensionName() { 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 8b05b39..b2176a2 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/world/fortresses/ComponentNetherGateway.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/world/fortresses/ComponentNetherGateway.java @@ -2,7 +2,6 @@ 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; @@ -11,7 +10,7 @@ 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; @@ -157,7 +156,7 @@ public class ComponentNetherGateway extends StructureComponent 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); } ItemDoor.placeDoorBlock(world, x, y, z, orientation, mod_pocketDim.transientDoor); } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/world/gateways/BaseSchematicGateway.java b/src/main/java/StevenDimDoors/mod_pocketDim/world/gateways/BaseSchematicGateway.java index 6eaa0da..486923c 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/world/gateways/BaseSchematicGateway.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/world/gateways/BaseSchematicGateway.java @@ -3,7 +3,7 @@ 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.LinkTypes; +import StevenDimDoors.mod_pocketDim.core.LinkType; import StevenDimDoors.mod_pocketDim.core.PocketManager; import StevenDimDoors.mod_pocketDim.dungeon.DungeonSchematic; import StevenDimDoors.mod_pocketDim.schematic.InvalidSchematicException; @@ -44,7 +44,7 @@ public abstract class BaseSchematicGateway extends BaseGateway this.generateRandomBits(world, x, y, z); // Generate a dungeon link in the door - PocketManager.getDimensionData(world).createLink(x, y + doorLocation.getY(), z, LinkTypes.DUNGEON, orientation); + PocketManager.getDimensionData(world).createLink(x, y + doorLocation.getY(), z, LinkType.DUNGEON, orientation); return true; } 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 dfd855a..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,7 +2,6 @@ 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; @@ -11,10 +10,9 @@ import net.minecraftforge.common.DimensionManager; 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; @@ -107,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 { 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 cb50437..ef8f9a6 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/world/gateways/GatewayLimbo.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/world/gateways/GatewayLimbo.java @@ -4,7 +4,7 @@ import net.minecraft.item.ItemDoor; import net.minecraft.world.World; import StevenDimDoors.mod_pocketDim.mod_pocketDim; import StevenDimDoors.mod_pocketDim.config.DDProperties; -import StevenDimDoors.mod_pocketDim.core.LinkTypes; +import StevenDimDoors.mod_pocketDim.core.LinkType; import StevenDimDoors.mod_pocketDim.core.PocketManager; import StevenDimDoors.mod_pocketDim.world.LimboProvider; @@ -30,7 +30,7 @@ public class GatewayLimbo extends BaseGateway world.setBlock(x, y + 1, z - 1, blockID, 0, 3); world.setBlock(x, y + 1, z + 1, blockID, 0, 3); - PocketManager.getDimensionData(world).createLink(x, y + 2, z, LinkTypes.DUNGEON, 0); + PocketManager.getDimensionData(world).createLink(x, y + 2, z, LinkType.DUNGEON, 0); ItemDoor.placeDoorBlock(world, x, y + 1, z, 0, mod_pocketDim.transientDoor); return true; } diff --git a/src/main/java/StevenDimDoors/mod_pocketDimClient/PrivatePocketRender.java b/src/main/java/StevenDimDoors/mod_pocketDimClient/PrivatePocketRender.java index 287a4ee..dde9506 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDimClient/PrivatePocketRender.java +++ b/src/main/java/StevenDimDoors/mod_pocketDimClient/PrivatePocketRender.java @@ -43,6 +43,7 @@ public class PrivatePocketRender implements ISimpleBlockRenderingHandler 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)) { @@ -51,6 +52,7 @@ public class PrivatePocketRender implements ISimpleBlockRenderingHandler } + tessellator.setColorOpaque_F(1F, 1F, 1F); if (renderer.renderAllFaces || block.shouldSideBeRendered(world, x, y, z - 1, 2)) { @@ -59,6 +61,7 @@ public class PrivatePocketRender implements ISimpleBlockRenderingHandler flag = true; } + tessellator.setColorOpaque_F(1F, 1F, 1F); if (renderer.renderAllFaces || block.shouldSideBeRendered(world, x, y, z + 1, 3)) { @@ -68,6 +71,7 @@ public class PrivatePocketRender implements ISimpleBlockRenderingHandler flag = true; } + tessellator.setColorOpaque_F(1F, 1F, 1F); if (renderer.renderAllFaces || block.shouldSideBeRendered(world, x - 1, y, z, 4)) { @@ -77,6 +81,7 @@ public class PrivatePocketRender implements ISimpleBlockRenderingHandler flag = true; } + tessellator.setColorOpaque_F(1F, 1F, 1F); if (renderer.renderAllFaces || block.shouldSideBeRendered(world, x + 1, y, z, 5)) { diff --git a/src/main/resources/assets/dimdoors/text/Dim_Data_Schema.json b/src/main/resources/assets/dimdoors/text/Dim_Data_Schema.json index 997b6dc..33d503d 100644 --- a/src/main/resources/assets/dimdoors/text/Dim_Data_Schema.json +++ b/src/main/resources/assets/dimdoors/text/Dim_Data_Schema.json @@ -19,6 +19,9 @@ "IsDungeon": { "type":"boolean" }, + "PocketType": { + "type":"number" + }, "IsFilled": { "type":"boolean" }, From 18666f58b18364f428f8f538c2812f13bb9fd881 Mon Sep 17 00:00:00 2001 From: StevenRS11 Date: Wed, 25 Jun 2014 04:37:40 -0400 Subject: [PATCH 109/187] Added versioning to save files and DimensionType --- .../commands/CommandResetDungeons.java | 5 +- .../mod_pocketDim/core/DDTeleporter.java | 2 +- .../mod_pocketDim/core/DimensionType.java | 41 ++++ .../core/IDimRegistrationCallback.java | 2 +- .../mod_pocketDim/core/NewDimData.java | 33 +-- .../mod_pocketDim/core/PocketManager.java | 45 ++-- .../mod_pocketDim/core/PocketType.java | 16 -- .../mod_pocketDim/helpers/Compactor.java | 6 +- .../mod_pocketDim/items/ItemDDKey.java | 4 +- .../mod_pocketDim/saving/DDSaveHandler.java | 9 +- .../saving/DimDataProcessor.java | 105 ++++++-- .../mod_pocketDim/saving/OldSaveImporter.java | 30 ++- .../mod_pocketDim/saving/PackedDimData.java | 9 +- .../mod_pocketDim/saving/PackedLinkTail.java | 5 +- .../mod_pocketDim/watcher/ClientDimData.java | 21 +- .../mod_pocketDim/watcher/ClientLinkData.java | 21 +- .../mod_pocketDim/world/PocketBuilder.java | 13 +- .../dimdoors/text/Dim_Data_Schema_v1-0-0.json | 229 ++++++++++++++++++ ...a.json => Dim_Data_Schema_v982405775.json} | 5 +- 19 files changed, 477 insertions(+), 124 deletions(-) create mode 100644 src/main/java/StevenDimDoors/mod_pocketDim/core/DimensionType.java delete mode 100644 src/main/java/StevenDimDoors/mod_pocketDim/core/PocketType.java create mode 100644 src/main/resources/assets/dimdoors/text/Dim_Data_Schema_v1-0-0.json rename src/main/resources/assets/dimdoors/text/{Dim_Data_Schema.json => Dim_Data_Schema_v982405775.json} (98%) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandResetDungeons.java b/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandResetDungeons.java index 0978338..3c84bdf 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandResetDungeons.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandResetDungeons.java @@ -4,6 +4,7 @@ import java.util.ArrayList; import net.minecraft.entity.player.EntityPlayer; import net.minecraftforge.common.DimensionManager; import StevenDimDoors.mod_pocketDim.core.DimLink; +import StevenDimDoors.mod_pocketDim.core.DimensionType; import StevenDimDoors.mod_pocketDim.core.LinkType; import StevenDimDoors.mod_pocketDim.core.NewDimData; import StevenDimDoors.mod_pocketDim.core.PocketManager; @@ -46,13 +47,13 @@ public class CommandResetDungeons extends DDCommandBase for (NewDimData data : PocketManager.getDimensions()) { - if(DimensionManager.getWorld(data.id())==null&&data.isDungeon()) + if(DimensionManager.getWorld(data.id())==null&&data.getDimensionType() == DimensionType.DUNGEON) { resetCount++; dungeonCount++; dimsToDelete.add(data.id()); } - else if(data.isDungeon()) + else if(data.getDimensionType() == DimensionType.DUNGEON) { dimsToFix.add(data.id()); dungeonCount++; diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/core/DDTeleporter.java b/src/main/java/StevenDimDoors/mod_pocketDim/core/DDTeleporter.java index 17c6e69..f102e96 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/core/DDTeleporter.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/core/DDTeleporter.java @@ -498,7 +498,7 @@ public class DDTeleporter case DUNGEON: return PocketBuilder.generateNewDungeonPocket(link, properties); case POCKET: - return PocketBuilder.generateNewPocket(link, properties,door); + return PocketBuilder.generateNewPocket(link, properties, door, DimensionType.POCKET); case PERSONAL: return setupPersonalLink(link, properties, entity, door); case SAFE_EXIT: 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/NewDimData.java b/src/main/java/StevenDimDoors/mod_pocketDim/core/NewDimData.java index 095b792..612117b 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/core/NewDimData.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/core/NewDimData.java @@ -130,10 +130,10 @@ public abstract class NewDimData implements IPackable 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; @@ -143,18 +143,12 @@ public abstract class NewDimData implements IPackable protected boolean modified; public IUpdateWatcher linkWatcher; - protected NewDimData(int id, NewDimData parent, boolean isPocket, boolean isDungeon, - IUpdateWatcher linkWatcher) + 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 @@ -162,7 +156,7 @@ public abstract class NewDimData implements IPackable 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; @@ -186,7 +180,7 @@ public abstract class NewDimData implements IPackable } } - 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) @@ -200,7 +194,7 @@ public abstract class NewDimData implements IPackable 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; @@ -422,11 +416,10 @@ public abstract class NewDimData implements IPackable return (root != this); } - public boolean isDungeon() + public DimensionType getDimensionType() { - return isDungeon; + return this.type; } - public boolean isFilled() { return isFilled; @@ -500,7 +493,7 @@ public abstract class NewDimData implements IPackable 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."); } @@ -655,7 +648,7 @@ public abstract class NewDimData implements IPackable linkList = null; children.clear(); children = null; - isDungeon = false; + type = null; isFilled = false; depth = Integer.MIN_VALUE; packDepth = Integer.MIN_VALUE; @@ -696,10 +689,10 @@ public abstract class NewDimData implements IPackable { children.add(childLink.source().toPoint3D()); } - PackedLinkTail tail = new PackedLinkTail(link.tail.getDestination(),link.tail.getLinkType().index); + 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().index); + PackedLinkTail tempTail = new PackedLinkTail(link.tail.getDestination(),link.tail.getLinkType()); if(Tails.contains(tempTail)) { Tails.add(tempTail); @@ -718,7 +711,7 @@ public abstract class NewDimData implements IPackable originPoint=this.origin.toPoint3D(); } return new PackedDimData(this.id, depth, this.packDepth, parentID, this.root().id(), orientation, - isDungeon, isFilled,packedDungeon, originPoint, ChildIDs, Links, Tails); + type, isFilled,packedDungeon, originPoint, ChildIDs, Links, Tails); // FIXME: IMPLEMENTATION PLZTHX //I tried } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/core/PocketManager.java b/src/main/java/StevenDimDoors/mod_pocketDim/core/PocketManager.java index 1c8cba5..4cbca5f 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/core/PocketManager.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/core/PocketManager.java @@ -42,16 +42,16 @@ public class PocketManager // 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, + 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); } } @@ -90,7 +90,7 @@ public class PocketManager @Override public void onCreated(ClientDimData data) { - registerClientDimension(data.ID, data.RootID); + registerClientDimension(data.ID, data.rootID, data.type); } @Override @@ -114,9 +114,9 @@ public class PocketManager // 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); } } @@ -177,7 +177,7 @@ public class PocketManager } //Register Limbo DDProperties properties = DDProperties.instance(); - registerDimension(properties.LimboDimensionID, null, false, false); + registerDimension(properties.LimboDimensionID, null, DimensionType.ROOT); loadInternal(); @@ -192,10 +192,15 @@ public class PocketManager { InnerDimData dimData; + DimensionType type = DimensionType.getTypeFromIndex(packedData.DimensionType); + if(type == null) + { + throw new IllegalArgumentException("Invalid dimension type"); + } //register roots if(packedData.ID==packedData.ParentID) { - dimData = new InnerDimData(packedData.ID, null, false, false, linkWatcher); + dimData = new InnerDimData(packedData.ID, null, type, linkWatcher); dimData.root=dimData; dimData.parent=dimData; dimData.depth=packedData.Depth; @@ -207,7 +212,7 @@ public class PocketManager else //register children { InnerDimData test = PocketManager.dimensionData.get(packedData.ParentID); - dimData = new InnerDimData(packedData.ID, test,true, packedData.IsDungeon, linkWatcher); + 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.getDimensionData(packedData.RootID); @@ -421,7 +426,7 @@ 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 registerPersonalPocket(NewDimData parent, String playerName) @@ -434,12 +439,12 @@ public class PocketManager DDProperties properties = DDProperties.instance(); int dimensionID = DimensionManager.getNextFreeDimId(); DimensionManager.registerDimension(dimensionID, properties.PersonalPocketProviderID); - NewDimData data = registerDimension(dimensionID, (InnerDimData) parent, true, false); + NewDimData data = registerDimension(dimensionID, (InnerDimData) parent, DimensionType.PERSONAL); personalPocketsMapping.put(playerName, data); return data; } - public static NewDimData registerPocket(NewDimData parent, boolean isDungeon) + public static NewDimData registerPocket(NewDimData parent, DimensionType type) { if (parent == null) { @@ -449,7 +454,7 @@ public class PocketManager DDProperties properties = DDProperties.instance(); int dimensionID = DimensionManager.getNextFreeDimId(); DimensionManager.registerDimension(dimensionID, properties.PocketProviderID); - return registerDimension(dimensionID, (InnerDimData) parent, true, isDungeon); + return registerDimension(dimensionID, (InnerDimData) parent, type); } /** * Registers a dimension with DD but NOT with forge. @@ -459,7 +464,7 @@ public class PocketManager * @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)) { @@ -469,7 +474,7 @@ public class PocketManager } 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()) { @@ -481,7 +486,7 @@ public class PocketManager } @SideOnly(Side.CLIENT) - private static NewDimData registerClientDimension(int dimensionID, int rootID) + private static NewDimData registerClientDimension(int dimensionID, int rootID, DimensionType type) { 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 @@ -498,7 +503,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); } } @@ -538,9 +543,11 @@ public class PocketManager return null; } 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; } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/core/PocketType.java b/src/main/java/StevenDimDoors/mod_pocketDim/core/PocketType.java deleted file mode 100644 index ba3da9d..0000000 --- a/src/main/java/StevenDimDoors/mod_pocketDim/core/PocketType.java +++ /dev/null @@ -1,16 +0,0 @@ -package StevenDimDoors.mod_pocketDim.core; - -public enum PocketType -{ - // WARNING: Don't modify these values carelessly or you'll risk breaking existing worlds! - NORMAL(0), - DUNGEON(1), - PERSONAL(2); - - PocketType(int index) - { - this.index = index; - } - - public final int index; -} diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/helpers/Compactor.java b/src/main/java/StevenDimDoors/mod_pocketDim/helpers/Compactor.java index 13eff90..a19dc9f 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/helpers/Compactor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/helpers/Compactor.java @@ -7,6 +7,7 @@ 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.LinkType; import StevenDimDoors.mod_pocketDim.core.NewDimData; @@ -67,13 +68,14 @@ 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++) { diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemDDKey.java b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemDDKey.java index 1721317..a93ec03 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemDDKey.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemDDKey.java @@ -103,7 +103,7 @@ public class ItemDDKey extends Item world.playSoundAtEntity(player, mod_pocketDim.modid + ":keyLock", 1F, 1F); } PocketManager.getDimensionData(world).lock(link, !link.getLockState()); - PocketManager.getLinkWatcher().update(new ClientLinkData(link.source(),link.getLock())); + PocketManager.getLinkWatcher().update(new ClientLinkData(link)); } else { @@ -116,7 +116,7 @@ public class ItemDDKey extends Item { 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.source(),link.getLock())); + PocketManager.getLinkWatcher().update(new ClientLinkData(link)); } } return false; diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/saving/DDSaveHandler.java b/src/main/java/StevenDimDoors/mod_pocketDim/saving/DDSaveHandler.java index a13c2cd..ae3c5af 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/saving/DDSaveHandler.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/saving/DDSaveHandler.java @@ -12,6 +12,7 @@ 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.DimensionType; import StevenDimDoors.mod_pocketDim.core.LinkType; import StevenDimDoors.mod_pocketDim.core.NewDimData; import StevenDimDoors.mod_pocketDim.core.PocketManager; @@ -157,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; @@ -175,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 @@ -189,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); } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/saving/DimDataProcessor.java b/src/main/java/StevenDimDoors/mod_pocketDim/saving/DimDataProcessor.java index cf3f479..b6880f6 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/saving/DimDataProcessor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/saving/DimDataProcessor.java @@ -1,30 +1,37 @@ package StevenDimDoors.mod_pocketDim.saving; -import java.io.File; 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 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.JSONValidator; -import StevenDimDoors.mod_pocketDim.util.Point4D; 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; -import com.google.gson.stream.JsonToken; public class DimDataProcessor extends BaseConfigurationProcessor { - private static final String JSON_SCHEMA_PATH = "/assets/dimdoors/text/Dim_Data_Schema.json"; + public final String JSON_VERSION_PROPERTY_NAME = "SAVE_DATA_VERSION_ID_INSTANCE"; + private HashMap SAVE_DATA_DEFINITIONS; private static final JsonParser jsonParser = new JsonParser(); + public static final String currentSaveVersionPath = "/assets/dimdoors/text/Dim_Data_Schema_v1-0-0.json"; + + //TODO dont load the schemas every time + public DimDataProcessor() + { + SAVE_DATA_DEFINITIONS = new HashMap(); + SAVE_DATA_DEFINITIONS.put(982405775, "/assets/dimdoors/text/Dim_Data_Schema_v982405775.json"); + SAVE_DATA_DEFINITIONS.put(PackedDimData.SAVE_DATA_VERSION_ID, currentSaveVersionPath); + + } @Override public PackedDimData readFromStream(InputStream inputStream) throws ConfigurationProcessingException @@ -58,38 +65,96 @@ public class DimDataProcessor extends BaseConfigurationProcessor try { //ensure our json object corresponds to our schema - validateJson(ele); + JSONValidator.validate(getSaveDataSchema(ele.getAsJsonObject()), ele); outputStream.write(ele.toString().getBytes("UTF-8")); outputStream.close(); } 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"); + } + } + public PackedDimData readDimDataJson(JsonReader reader) throws IOException { JsonElement ele = jsonParser.parse(reader); - this.validateJson(ele); + JsonObject schema = this.getSaveDataSchema(ele.getAsJsonObject()); + JSONValidator.validate(schema, ele); + ele = processSaveData(schema, ele.getAsJsonObject()); + GsonBuilder gsonBuilder = new GsonBuilder(); return gsonBuilder.create().fromJson(ele, PackedDimData.class); } /** - * checks our json against the dim data schema - * @param data + * Gets the schema that corresponds to a version of our save data + * @param obj * @return - * @throws IOException + * @throws IOException */ - public boolean validateJson(JsonElement data) throws IOException + public JsonObject getSaveDataSchema(JsonObject obj) { - InputStream in = this.getClass().getResourceAsStream(JSON_SCHEMA_PATH); + String schemaPath = this.SAVE_DATA_DEFINITIONS.get(obj.get(JSON_VERSION_PROPERTY_NAME).getAsInt()); + + if(schemaPath == null) + { + throw new IllegalStateException("Invalid save data version"); + } + InputStream in = this.getClass().getResourceAsStream(schemaPath); JsonReader reader = new JsonReader(new InputStreamReader(in)); - JSONValidator.validate((JsonObject) jsonParser.parse(reader), data); - reader.close(); - in.close(); - return true; + + JsonObject schema = jsonParser.parse(reader).getAsJsonObject(); + try + { + 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"); + } + return schema; + } + + /** + * 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) + { + if(save.get(JSON_VERSION_PROPERTY_NAME).getAsInt()== 982405775) + { + DimensionType type; + + //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); + save.addProperty(this.JSON_VERSION_PROPERTY_NAME, PackedDimData.SAVE_DATA_VERSION_ID); + } + + JSONValidator.validate(this.getSaveDataSchema(save), save); + return save; } } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/saving/OldSaveImporter.java b/src/main/java/StevenDimDoors/mod_pocketDim/saving/OldSaveImporter.java index 13ae45a..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 @@ -77,7 +76,7 @@ public class OldSaveImporter { 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, null); @@ -86,13 +85,30 @@ public class OldSaveImporter allPackedLinks.add(newPackedLink); } PackedDimData dim; + DimensionType type; + if(data.isPocket) { - 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.dungeonGenerator!=null) + { + type = DimensionType.DUNGEON; + } + else + { + type = DimensionType.POCKET; + } } else { - dim = new PackedDimData(data.dimID, data.depth, data.depth, data.dimID, data.dimID, 0, data.dungeonGenerator!=null, data.hasBeenFilled, null, new Point3D(0,64,0), childDims, newPackedLinkData, null); + 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); } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/saving/PackedDimData.java b/src/main/java/StevenDimDoors/mod_pocketDim/saving/PackedDimData.java index 60a033d..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; 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/watcher/ClientDimData.java b/src/main/java/StevenDimDoors/mod_pocketDim/watcher/ClientDimData.java index c0df886..666e28c 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.getDimensionType(); } 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 9694c62..434b17d 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/watcher/ClientLinkData.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/watcher/ClientLinkData.java @@ -5,33 +5,41 @@ 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 DDLock lock; - + 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, DDLock lock) + 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.write(this.type.index); boolean hasLock = this.lock != null; output.writeBoolean(hasLock); @@ -45,11 +53,12 @@ public class ClientLinkData 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, lock); + return new ClientLinkData(point, type, lock); } } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/world/PocketBuilder.java b/src/main/java/StevenDimDoors/mod_pocketDim/world/PocketBuilder.java index 6f6e356..13bda15 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/world/PocketBuilder.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/world/PocketBuilder.java @@ -14,6 +14,7 @@ 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.DimensionType; import StevenDimDoors.mod_pocketDim.core.LinkType; import StevenDimDoors.mod_pocketDim.core.NewDimData; import StevenDimDoors.mod_pocketDim.core.PocketManager; @@ -99,7 +100,7 @@ public class PocketBuilder // 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()); @@ -142,7 +143,7 @@ public class PocketBuilder DungeonSchematic schematic = pair.getSecond(); //Register a new dimension - NewDimData dimension = PocketManager.registerPocket(parent, true); + NewDimData dimension = PocketManager.registerPocket(parent, DimensionType.DUNGEON); //Load a world World world = PocketManager.loadDimension(dimension.id()); @@ -248,9 +249,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) @@ -373,7 +374,7 @@ public class PocketBuilder } } - public static boolean generateNewPocket(DimLink link, int size, int wallThickness, DDProperties properties, Block door) + public static boolean generateNewPocket(DimLink link, int size, int wallThickness, DDProperties properties, Block door, DimensionType type) { validatePocketSetup(link, size, wallThickness, properties, door); @@ -381,7 +382,7 @@ public class PocketBuilder { //Register a new dimension NewDimData parent = PocketManager.getDimensionData(link.source().getDimension()); - NewDimData dimension = PocketManager.registerPocket(parent, false); + NewDimData dimension = PocketManager.registerPocket(parent, type); //Load a world 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..cd2d416 --- /dev/null +++ b/src/main/resources/assets/dimdoors/text/Dim_Data_Schema_v1-0-0.json @@ -0,0 +1,229 @@ +{ + "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": "number" + } + }, + "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.json b/src/main/resources/assets/dimdoors/text/Dim_Data_Schema_v982405775.json similarity index 98% rename from src/main/resources/assets/dimdoors/text/Dim_Data_Schema.json rename to src/main/resources/assets/dimdoors/text/Dim_Data_Schema_v982405775.json index 33d503d..84d8cd3 100644 --- a/src/main/resources/assets/dimdoors/text/Dim_Data_Schema.json +++ b/src/main/resources/assets/dimdoors/text/Dim_Data_Schema_v982405775.json @@ -19,9 +19,6 @@ "IsDungeon": { "type":"boolean" }, - "PocketType": { - "type":"number" - }, "IsFilled": { "type":"boolean" }, @@ -224,8 +221,8 @@ "Orientation", "Links", "IsFilled", - "IsDungeon", "ID", + "IsDungeon", "Depth", "ChildIDs" ] From 4d39d13703490cc62f4a1ef8d0eb9965c69f7af9 Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Wed, 25 Jun 2014 14:04:08 -0400 Subject: [PATCH 110/187] Changes to Monolith Behavior 1. Stopped Monoliths from teleporting players while in Limbo. This was a serious issue on some modpacks if players got unlucky. 2. Decreased the required Monolith aggro level to start spawning particles around a target player. The required level was so high, combined with the current Monolith speed, that players would hardly see the particles. 3. Disabled Monolith sounds in Limbo. Some of the sounds were really annoying in Limbo. Usually they only get to play for a moment before a player is teleported, but since no teleports occur in Limbo and the area is full of Monoliths, the constant noise is aggravating. It would also drown out the background music. --- .../mod_pocketDim/ticking/MobMonolith.java | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/ticking/MobMonolith.java b/src/main/java/StevenDimDoors/mod_pocketDim/ticking/MobMonolith.java index e19aa65..f54f515 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/ticking/MobMonolith.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/ticking/MobMonolith.java @@ -145,9 +145,13 @@ public class MobMonolith extends EntityFlying implements IMob if (player != null) { this.facePlayer(player); - if (!this.worldObj.isRemote) + if (!this.worldObj.isRemote && !(this.worldObj.provider instanceof LimboProvider)) { - // Play sounds on the server side + // 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); } @@ -161,7 +165,8 @@ public class MobMonolith extends EntityFlying implements IMob // Teleport the target player if various conditions are met if (aggro >= MAX_AGGRO && !this.worldObj.isRemote && - properties.MonolithTeleportationEnabled && !player.capabilities.isCreativeMode) + properties.MonolithTeleportationEnabled && !player.capabilities.isCreativeMode && + !(this.worldObj.provider instanceof LimboProvider)) { this.aggro = 0; Point4D destination = LimboProvider.getLimboSkySpawn(player, properties); @@ -239,7 +244,7 @@ public class MobMonolith extends EntityFlying implements IMob 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.90) && this.soundTime < 200) + 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; From 1410d4b251a15d9350edf0d69b7c18670da1b365 Mon Sep 17 00:00:00 2001 From: StevenRS11 Date: Wed, 25 Jun 2014 14:13:49 -0400 Subject: [PATCH 111/187] made versioning slightly better --- .../saving/DimDataProcessor.java | 61 ++++++++++++++----- 1 file changed, 47 insertions(+), 14 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/saving/DimDataProcessor.java b/src/main/java/StevenDimDoors/mod_pocketDim/saving/DimDataProcessor.java index b6880f6..d42b8ef 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/saving/DimDataProcessor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/saving/DimDataProcessor.java @@ -19,17 +19,22 @@ import com.google.gson.stream.JsonReader; public class DimDataProcessor extends BaseConfigurationProcessor { public final String JSON_VERSION_PROPERTY_NAME = "SAVE_DATA_VERSION_ID_INSTANCE"; - private HashMap SAVE_DATA_DEFINITIONS; + private HashMap SAVE_DATA_SCHEMA; private static final JsonParser jsonParser = new JsonParser(); - public static final String currentSaveVersionPath = "/assets/dimdoors/text/Dim_Data_Schema_v1-0-0.json"; - - + + public static final String BASE_SCHEMA_PATH = "/assets/dimdoors/text/"; + + //TODO dont load the schemas every time public DimDataProcessor() { - SAVE_DATA_DEFINITIONS = new HashMap(); - SAVE_DATA_DEFINITIONS.put(982405775, "/assets/dimdoors/text/Dim_Data_Schema_v982405775.json"); - SAVE_DATA_DEFINITIONS.put(PackedDimData.SAVE_DATA_VERSION_ID, currentSaveVersionPath); + 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 current schema + SAVE_DATA_SCHEMA.put(PackedDimData.SAVE_DATA_VERSION_ID, loadSchema(BASE_SCHEMA_PATH+"Dim_Data_Schema_v1-0-0.json")); } @Override @@ -59,14 +64,15 @@ public class DimDataProcessor extends BaseConfigurationProcessor { //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 { //ensure our json object corresponds to our schema JSONValidator.validate(getSaveDataSchema(ele.getAsJsonObject()), ele); - outputStream.write(ele.toString().getBytes("UTF-8")); + outputStream.write(gson.toJson(ele).getBytes("UTF-8")); outputStream.close(); } catch (Exception e) @@ -77,14 +83,28 @@ public class DimDataProcessor extends BaseConfigurationProcessor } - + /** + * 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 readDimDataJson(JsonReader reader) throws IOException { + //read the save file into a Json element JsonElement ele = jsonParser.parse(reader); + + //get the schema that corresponds to the save file's listed version number JsonObject schema = this.getSaveDataSchema(ele.getAsJsonObject()); + + //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); } @@ -97,13 +117,24 @@ public class DimDataProcessor extends BaseConfigurationProcessor */ public JsonObject getSaveDataSchema(JsonObject obj) { - String schemaPath = this.SAVE_DATA_DEFINITIONS.get(obj.get(JSON_VERSION_PROPERTY_NAME).getAsInt()); + JsonObject schema = this.SAVE_DATA_SCHEMA.get(obj.get(JSON_VERSION_PROPERTY_NAME).getAsInt()); - if(schemaPath == null) + if(schema == null) { throw new IllegalStateException("Invalid save data version"); } - InputStream in = this.getClass().getResourceAsStream(schemaPath); + + 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(); @@ -118,6 +149,7 @@ public class DimDataProcessor extends BaseConfigurationProcessor e.printStackTrace(); throw new IllegalStateException("Could not load Json Save Data definitions"); } + return schema; } @@ -152,6 +184,7 @@ public class DimDataProcessor extends BaseConfigurationProcessor save.addProperty("DimensionType",type.index); save.remove(this.JSON_VERSION_PROPERTY_NAME); save.addProperty(this.JSON_VERSION_PROPERTY_NAME, PackedDimData.SAVE_DATA_VERSION_ID); + return processSaveData(this.getSaveDataSchema(save), save); } JSONValidator.validate(this.getSaveDataSchema(save), save); From 660ff4255e7da6b6a36b3e8477ca56a114e11bf2 Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Wed, 25 Jun 2014 14:33:19 -0400 Subject: [PATCH 112/187] Code Cleaning 1. Cleaned up some spacing and unused imports in EventHookContainer. Also changed an indirect reference to BaseItemDoor.trytoPlaceDoor() to a direct reference seeing as the function is static and should be accessed that way. 2. Renamed getDoortoItemMapping() to getDoorBlock(). The original named had a minor capitalization mistake and implied that it would return a mapping table or would associate doors to items. The function actually associates items to door blocks. --- .../mod_pocketDim/EventHookContainer.java | 10 +++------- .../mod_pocketDim/items/BaseItemDoor.java | 6 +++--- .../mod_pocketDim/items/ItemDimensionalDoor.java | 2 +- .../mod_pocketDim/items/ItemGoldDimDoor.java | 2 +- .../mod_pocketDim/items/ItemUnstableDoor.java | 2 +- .../mod_pocketDim/items/ItemWarpDoor.java | 2 +- 6 files changed, 10 insertions(+), 14 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java b/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java index 4e47d8f..773877b 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java @@ -1,14 +1,11 @@ package StevenDimDoors.mod_pocketDim; -import net.minecraft.block.Block; import net.minecraft.client.audio.SoundManager; import net.minecraft.client.audio.SoundPoolEntry; import net.minecraft.entity.Entity; 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.ChunkCoordinates; import net.minecraft.world.World; import net.minecraftforge.client.event.sound.PlayBackgroundMusicEvent; import net.minecraftforge.client.event.sound.SoundLoadEvent; @@ -20,7 +17,6 @@ import net.minecraftforge.event.entity.player.PlayerInteractEvent; import net.minecraftforge.event.entity.player.PlayerInteractEvent.Action; import net.minecraftforge.event.terraingen.InitMapGenEvent; import net.minecraftforge.event.world.WorldEvent; -import StevenDimDoors.mod_pocketDim.blocks.BaseDimDoor; import StevenDimDoors.mod_pocketDim.config.DDProperties; import StevenDimDoors.mod_pocketDim.core.DDTeleporter; import StevenDimDoors.mod_pocketDim.core.PocketManager; @@ -84,7 +80,7 @@ public class EventHookContainer public void onPlayerEvent(PlayerInteractEvent event) { // Handle all door placement here - if(event.action == Action.LEFT_CLICK_BLOCK) + if (event.action == Action.LEFT_CLICK_BLOCK) { return; } @@ -92,9 +88,9 @@ public class EventHookContainer ItemStack stack = event.entityPlayer.inventory.getCurrentItem(); if (stack != null && stack.getItem() instanceof ItemDoor) { - if(BaseItemDoor.getDoorToPlace(stack.getItem())!=null) + if (BaseItemDoor.getDoorToPlace(stack.getItem()) != null) { - if (mod_pocketDim.itemDimensionalDoor.tryToPlaceDoor(stack, event.entityPlayer, world, + 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 diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/items/BaseItemDoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/items/BaseItemDoor.java index dafcd91..ddd2502 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/items/BaseItemDoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/items/BaseItemDoor.java @@ -2,6 +2,7 @@ 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; @@ -64,7 +65,7 @@ public abstract class BaseItemDoor extends ItemDoor * * @return */ - protected abstract BaseDimDoor getDoortoItemMapping(); + protected abstract BaseDimDoor getDoorBlock(); /** * Overriden here to remove vanilla block placement functionality from @@ -73,7 +74,6 @@ public abstract class BaseItemDoor extends ItemDoor @Override public boolean onItemUse(ItemStack stack, EntityPlayer player, World world, int x, int y, int z, int side, float hitX, float hitY, float hitZ) { - // TODO Auto-generated method stub return false; } @@ -87,7 +87,7 @@ public abstract class BaseItemDoor extends ItemDoor { return null; } - return ((BaseItemDoor) item).getDoortoItemMapping(); + return ((BaseItemDoor) item).getDoorBlock(); } /** diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemDimensionalDoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemDimensionalDoor.java index d6bb9ce..18f123d 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemDimensionalDoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemDimensionalDoor.java @@ -28,7 +28,7 @@ public class ItemDimensionalDoor extends BaseItemDoor } @Override - protected BaseDimDoor getDoortoItemMapping() + protected BaseDimDoor getDoorBlock() { return (BaseDimDoor) mod_pocketDim.dimensionalDoor; } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemGoldDimDoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemGoldDimDoor.java index 9dde8f5..abf9f09 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemGoldDimDoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemGoldDimDoor.java @@ -28,7 +28,7 @@ public class ItemGoldDimDoor extends BaseItemDoor } @Override - protected BaseDimDoor getDoortoItemMapping() + protected BaseDimDoor getDoorBlock() { return (BaseDimDoor) mod_pocketDim.goldenDimensionalDoor; } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemUnstableDoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemUnstableDoor.java index c859443..e51bcaa 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemUnstableDoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemUnstableDoor.java @@ -25,7 +25,7 @@ public class ItemUnstableDoor extends BaseItemDoor } @Override - protected BaseDimDoor getDoortoItemMapping() + protected BaseDimDoor getDoorBlock() { return (BaseDimDoor) mod_pocketDim.unstableDoor; } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemWarpDoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemWarpDoor.java index 35c5737..403bbc1 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemWarpDoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemWarpDoor.java @@ -28,7 +28,7 @@ public class ItemWarpDoor extends BaseItemDoor } @Override - protected BaseDimDoor getDoortoItemMapping() + protected BaseDimDoor getDoorBlock() { return (BaseDimDoor) mod_pocketDim.warpDoor; } From e4e84644acedf54ccae9807391b4a6b8876a0297 Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Wed, 25 Jun 2014 14:56:59 -0400 Subject: [PATCH 113/187] Changed Door Item Mapping Code 1. Changed EventHookContainer to remove a check against BaseItemDoor.getDoorToPlace(). The checks performed there can be done in BaseItemDoor.tryToPlaceDoor(), which removes the need for callers to know more internal details about how doors are handled. I moved the checks inside. 2. Renamed vanillaDoorMapping to doorItemMapping. It now maps dim door items to themselves to remove the need for various checks we were performing. Updated BaseItemDoor's constructor to reflect this change. 3. Removed BaseItemDoor.getDoorToPlace() and integrated its functionality into BaseItemDoor.tryToPlaceDoor(). 4. Changed BaseItemDoor.tryToPlaceDoor() so that it simply returns false if a given item stack cannot be used to place any doors. We don't need to check if the item is an ItemDoor or anything like that now. --- .../mod_pocketDim/EventHookContainer.java | 11 ++---- .../mod_pocketDim/items/BaseItemDoor.java | 39 ++++++++----------- 2 files changed, 20 insertions(+), 30 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java b/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java index 773877b..4130aaf 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java @@ -88,14 +88,11 @@ public class EventHookContainer ItemStack stack = event.entityPlayer.inventory.getCurrentItem(); if (stack != null && stack.getItem() instanceof ItemDoor) { - if (BaseItemDoor.getDoorToPlace(stack.getItem()) != null) + if (BaseItemDoor.tryToPlaceDoor(stack, event.entityPlayer, world, + event.x, event.y, event.z, event.face)) { - 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); - } + // Cancel the event so that we don't get two doors from vanilla doors + event.setCanceled(true); } } } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/items/BaseItemDoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/items/BaseItemDoor.java index ddd2502..538d059 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/items/BaseItemDoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/items/BaseItemDoor.java @@ -24,9 +24,9 @@ import StevenDimDoors.mod_pocketDim.tileentities.TileEntityDimDoor; public abstract class BaseItemDoor extends ItemDoor { - // maps non-dimensional door items to their corresponding dimensional door - // item - private static HashMap vanillaDoorMapping = new HashMap(); + // 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; /** @@ -35,7 +35,7 @@ public abstract class BaseItemDoor extends ItemDoor * @param material * @param door */ - public BaseItemDoor(int itemID, Material material, ItemDoor door) + public BaseItemDoor(int itemID, Material material, ItemDoor vanillaDoor) { super(itemID, material); this.setMaxStackSize(64); @@ -43,9 +43,10 @@ public abstract class BaseItemDoor extends ItemDoor if (properties == null) properties = DDProperties.instance(); - if(door!=null) + doorItemMapping.put(this, this); + if (vanillaDoor != null) { - vanillaDoorMapping.put(door, this); + doorItemMapping.put(vanillaDoor, this); } } @@ -77,19 +78,6 @@ public abstract class BaseItemDoor extends ItemDoor return false; } - public static BaseDimDoor getDoorToPlace(Item item) - { - if (!(item instanceof BaseItemDoor)) - { - item = BaseItemDoor.vanillaDoorMapping.get(item); - } - if(item == null) - { - return null; - } - return ((BaseItemDoor) item).getDoorBlock(); - } - /** * Tries to place a door block, called in EventHookContainer * @@ -111,15 +99,20 @@ public abstract class BaseItemDoor extends ItemDoor { return false; } - if (!(stack.getItem() instanceof ItemDoor)) + // 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) { - throw new IllegalArgumentException("The itemstack must correspond to some type of door"); + return false; } - if (BaseItemDoor.placeDoorOnBlock(getDoorToPlace(stack.getItem()), stack, player, world, x, y, z, side)) + BaseDimDoor doorBlock = mappedItem.getDoorBlock(); + if (BaseItemDoor.placeDoorOnBlock(doorBlock, stack, player, world, x, y, z, side)) { return true; } - return BaseItemDoor.placeDoorOnRift(getDoorToPlace(stack.getItem()), world, player, stack); + return BaseItemDoor.placeDoorOnRift(doorBlock, world, player, stack); } /** From a4d0f3939099de2926fd1e034439ebfd824b6199 Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Wed, 25 Jun 2014 15:08:30 -0400 Subject: [PATCH 114/187] Minor Change Cleaned up comments for BaseItemDoor.tryToPlaceDoor() --- .../StevenDimDoors/mod_pocketDim/items/BaseItemDoor.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/items/BaseItemDoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/items/BaseItemDoor.java index 538d059..3ad3a4b 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/items/BaseItemDoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/items/BaseItemDoor.java @@ -79,9 +79,8 @@ public abstract class BaseItemDoor extends ItemDoor } /** - * Tries to place a door block, called in EventHookContainer + * Tries to place a door as a dimensional door * - * @param doorBlock * @param stack * @param player * @param world @@ -89,8 +88,6 @@ public abstract class BaseItemDoor extends ItemDoor * @param y * @param z * @param side - * @param requireLink - * @param reduceStack * @return */ public static boolean tryToPlaceDoor(ItemStack stack, EntityPlayer player, World world, int x, int y, int z, int side) From 794310bd986cf9a94320a5daa7bceea933493d08 Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Wed, 25 Jun 2014 15:18:50 -0400 Subject: [PATCH 115/187] Fixed Max Stack Size of ItemGoldDoor Changed the max stack size of ItemGoldDoor to 16 as it is for Vanilla doors on some modpacks. Later versions of Vanilla have door stacking to 64 so this will need to change eventually. --- .../java/StevenDimDoors/mod_pocketDim/items/ItemGoldDoor.java | 1 + 1 file changed, 1 insertion(+) 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 From 0f3d40ba600d7dd87a7d34916922c225e1fa60f6 Mon Sep 17 00:00:00 2001 From: StevenRS11 Date: Wed, 25 Jun 2014 15:26:42 -0400 Subject: [PATCH 116/187] Various Finished implementing Personal Pockets -any pocket created from within a personal pocket retains personal status -exit doors cannot be used in any personal pockets -personal status is saved with dimData fixed a bug that let trapdoors get around locks fixed FoR not rendering properly -inventory and world --- .../mod_pocketDim/EventHookContainer.java | 15 +++--- .../mod_pocketDim/blocks/TransTrapdoor.java | 6 +-- .../mod_pocketDim/core/PocketManager.java | 50 +++++++++++++----- .../mod_pocketDim/world/PocketBuilder.java | 2 +- .../PrivatePocketRender.java | 51 ++++++++++++++++++- 5 files changed, 96 insertions(+), 28 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java b/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java index 7a2ed8b..61d388d 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java @@ -18,8 +18,10 @@ import net.minecraftforge.event.entity.player.PlayerInteractEvent; import net.minecraftforge.event.entity.player.PlayerInteractEvent.Action; import net.minecraftforge.event.terraingen.InitMapGenEvent; import net.minecraftforge.event.world.WorldEvent; +import StevenDimDoors.mod_pocketDim.blocks.TransTrapdoor; import StevenDimDoors.mod_pocketDim.config.DDProperties; import StevenDimDoors.mod_pocketDim.core.DDTeleporter; +import StevenDimDoors.mod_pocketDim.core.DimensionType; import StevenDimDoors.mod_pocketDim.core.NewDimData; import StevenDimDoors.mod_pocketDim.core.PocketManager; import StevenDimDoors.mod_pocketDim.items.ItemWarpDoor; @@ -96,15 +98,12 @@ public class EventHookContainer if(stack.getItem() instanceof ItemWarpDoor) { NewDimData data = PocketManager.getDimensionData(world); - while(data.depth()>0) + + if(data.getDimensionType() == DimensionType.PERSONAL) { - if(PocketManager.getPersonalPocketMapping().containsValue(data)) - { - mod_pocketDim.sendChat(event.entityPlayer,("Something prevents the Warp Door from tunneling out here")); - event.setCanceled(true); - return; - } - data = data.parent(); + mod_pocketDim.sendChat(event.entityPlayer,("Something prevents the Warp Door from tunneling out here")); + event.setCanceled(true); + return; } } if (mod_pocketDim.itemDimensionalDoor.tryToPlaceDoor(stack, event.entityPlayer, world, diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/TransTrapdoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/TransTrapdoor.java index a8f774b..52a0e9e 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/TransTrapdoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/TransTrapdoor.java @@ -50,7 +50,7 @@ public class TransTrapdoor extends BlockTrapDoor implements IDimDoor, ITileEntit public boolean checkCanOpen(World world, int x, int y, int z, EntityPlayer player) { - DimLink link = PocketManager.getLink( x, y,z, world); + DimLink link = PocketManager.getLink( x, y, z, world); if(link==null||player==null) { return link==null; @@ -78,7 +78,7 @@ public class TransTrapdoor extends BlockTrapDoor implements IDimDoor, ITileEntit 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, par3, par3, par4, par5EntityPlayer)) + if(this.checkCanOpen(par1World, par2, par3, par4, par5EntityPlayer)) { return super.onBlockActivated(par1World, par2, par3, par4, par5EntityPlayer, par6, par7, par8, par9); } @@ -97,13 +97,13 @@ public class TransTrapdoor extends BlockTrapDoor implements IDimDoor, ITileEntit { 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); } } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/core/PocketManager.java b/src/main/java/StevenDimDoors/mod_pocketDim/core/PocketManager.java index 4cbca5f..b609b70 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/core/PocketManager.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/core/PocketManager.java @@ -429,7 +429,14 @@ public class PocketManager return registerDimension(world.provider.dimensionId, null, DimensionType.ROOT); } - public static NewDimData registerPersonalPocket(NewDimData parent, String playerName) + /** + * 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) { @@ -438,23 +445,38 @@ public class PocketManager DDProperties properties = DDProperties.instance(); int dimensionID = DimensionManager.getNextFreeDimId(); - DimensionManager.registerDimension(dimensionID, properties.PersonalPocketProviderID); - NewDimData data = registerDimension(dimensionID, (InnerDimData) parent, DimensionType.PERSONAL); - personalPocketsMapping.put(playerName, data); - return data; + + //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) { - 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, type); + return registerPocket(parent, type, null); } /** * Registers a dimension with DD but NOT with forge. diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/world/PocketBuilder.java b/src/main/java/StevenDimDoors/mod_pocketDim/world/PocketBuilder.java index 13bda15..5292c1f 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/world/PocketBuilder.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/world/PocketBuilder.java @@ -337,7 +337,7 @@ public class PocketBuilder { //Register a new dimension NewDimData parent = PocketManager.getDimensionData(link.source().getDimension()); - NewDimData dimension = PocketManager.registerPersonalPocket(parent, player.getEntityName()); + NewDimData dimension = PocketManager.registerPocket(parent, DimensionType.PERSONAL, player.getEntityName()); //Load a world diff --git a/src/main/java/StevenDimDoors/mod_pocketDimClient/PrivatePocketRender.java b/src/main/java/StevenDimDoors/mod_pocketDimClient/PrivatePocketRender.java index dde9506..08458ea 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDimClient/PrivatePocketRender.java +++ b/src/main/java/StevenDimDoors/mod_pocketDimClient/PrivatePocketRender.java @@ -15,15 +15,62 @@ public class PrivatePocketRender implements ISimpleBlockRenderingHandler public PrivatePocketRender(int renderID) { - super(); 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) From 96d84ed2fa5bb20e29bec7acc4e4495c25f059d4 Mon Sep 17 00:00:00 2001 From: StevenRS11 Date: Wed, 25 Jun 2014 16:17:26 -0400 Subject: [PATCH 117/187] Fixed Json Schema The schema incorrectly listed the array of children in LinkData as an Array of numbers, not an array of objects with properties. --- .../mod_pocketDim/blocks/IDimDoor.java | 23 +++++++++++++++++++ .../mod_pocketDim/blocks/TransTrapdoor.java | 1 - .../dimdoors/text/Dim_Data_Schema_v1-0-0.json | 22 +++++++++++++++--- .../text/Dim_Data_Schema_v982405775.json | 22 +++++++++++++++--- 4 files changed, 61 insertions(+), 7 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/IDimDoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/IDimDoor.java index 9701b15..942af4e 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/IDimDoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/IDimDoor.java @@ -6,14 +6,37 @@ 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 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/TransTrapdoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/TransTrapdoor.java index 52a0e9e..5d864f0 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/TransTrapdoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/TransTrapdoor.java @@ -97,7 +97,6 @@ public class TransTrapdoor extends BlockTrapDoor implements IDimDoor, ITileEntit { if (!world.isRemote && isTrapdoorOpen(world.getBlockMetadata(x, y, z))) { - DimLink link = PocketManager.getLink(x, y, z, world); if (link != null) { 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 index cd2d416..c08afe0 100644 --- 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 @@ -64,10 +64,26 @@ "type": "object", "properties": { "children": { - "type": "array", + "type":"array", "items":{ - "type": "number" - } + "type": "object", + "properties":{ + "x": { + "type": "integer" + }, + "y": { + "type": "integer" + }, + "z": { + "type": "integer" + } + }, + "required": [ + "x", + "y", + "z" + ] + } }, "orientation": { "type": "number" 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 index 84d8cd3..2fa616d 100644 --- a/src/main/resources/assets/dimdoors/text/Dim_Data_Schema_v982405775.json +++ b/src/main/resources/assets/dimdoors/text/Dim_Data_Schema_v982405775.json @@ -64,10 +64,26 @@ "type": "object", "properties": { "children": { - "type": "array", + "type":"array", "items":{ - "type": "number" - } + "type": "object", + "properties":{ + "x": { + "type": "integer" + }, + "y": { + "type": "integer" + }, + "z": { + "type": "integer" + } + }, + "required": [ + "x", + "y", + "z" + ] + } }, "orientation": { "type": "number" From eff8379325ded4a55d11b626c7e777b0b3f35c51 Mon Sep 17 00:00:00 2001 From: StevenRS11 Date: Wed, 25 Jun 2014 17:46:33 -0400 Subject: [PATCH 118/187] Added lock removal ability to keys also fixed a network bug --- .../mod_pocketDim/core/NewDimData.java | 15 ++++ .../mod_pocketDim/items/ItemDDKey.java | 84 ++++++++++++++++++- .../mod_pocketDim/watcher/ClientLinkData.java | 2 +- 3 files changed, 99 insertions(+), 2 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/core/NewDimData.java b/src/main/java/StevenDimDoors/mod_pocketDim/core/NewDimData.java index 612117b..a91e17f 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/core/NewDimData.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/core/NewDimData.java @@ -124,6 +124,14 @@ public abstract class NewDimData implements IPackable return true; } + public void removeLock(ItemStack itemStack, InnerDimLink link) + { + if(link.doesKeyUnlock(itemStack)) + { + link.lock = null; + } + } + } protected static Random random = new Random(); @@ -601,6 +609,13 @@ public abstract class NewDimData implements IPackable 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() { diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemDDKey.java b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemDDKey.java index a93ec03..4812f74 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemDDKey.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemDDKey.java @@ -8,11 +8,14 @@ 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; @@ -24,6 +27,7 @@ import StevenDimDoors.mod_pocketDim.watcher.ClientLinkData; public class ItemDDKey extends Item { + public static final int TIME_TO_UNLOCK = 50; public ItemDDKey(int itemID) { super(itemID); @@ -63,8 +67,10 @@ public class ItemDDKey extends Item } - public boolean onItemUse(ItemStack par1ItemStack, EntityPlayer par2EntityPlayer, World par3World, int par4, int par5, int par6, int par7, float par8, float par9, float par10) + 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; } @@ -75,6 +81,11 @@ public class ItemDDKey extends Item { 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)) @@ -104,6 +115,7 @@ public class ItemDDKey extends Item } PocketManager.getDimensionData(world).lock(link, !link.getLockState()); PocketManager.getLinkWatcher().update(new ClientLinkData(link)); + } else { @@ -121,7 +133,77 @@ public class ItemDDKey extends Item } 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) + { + 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(itemStack)&& !world.isRemote) + { + PocketManager.getDimensionData(world).removeLock(link, itemStack); + world.playSoundAtEntity(player, mod_pocketDim.modid + ":keyUnlock", 1F, 1F); + } + } + } + } + player.clearItemInUse(); + + + } + + /** + * Raytrace to make sure we are still looking at the right block + */ + @Override + public void onUsingItemTick(ItemStack stack, EntityPlayer player, int count) + { + + //no need to check every tick + 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) { diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/watcher/ClientLinkData.java b/src/main/java/StevenDimDoors/mod_pocketDim/watcher/ClientLinkData.java index 434b17d..c23c137 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/watcher/ClientLinkData.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/watcher/ClientLinkData.java @@ -39,7 +39,7 @@ public class ClientLinkData public void write(DataOutputStream output) throws IOException { Point4D.write(point, output); - output.write(this.type.index); + output.writeInt(this.type.index); boolean hasLock = this.lock != null; output.writeBoolean(hasLock); From 0029d9dac02e5b8274cd33fa770f547e63d1cb18 Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Wed, 25 Jun 2014 19:00:41 -0400 Subject: [PATCH 119/187] Reduced Usage of Stable Fabric 1. Changed the crafting recipes for most DD items to use Ender Pearls instead of Stable Fabric. The items that still use Stable Fabric are Dimensional Doors, Golden Dimensional Doors, Rift Blades, and Stabilized Rift Signatures. Steven had already made this change in another branch but I'd like to push this out with several bug fixes. The SRS recipe is different from his version - it's now just 4 Iron Ingots and a Stable Fabric. 2. Change Stabilized Rift Signatures back to consuming Ender Pearls instead of Stable Fabric. --- .../mod_pocketDim/CraftingManager.java | 14 +++++++------- .../items/ItemStabilizedRiftSignature.java | 8 ++++---- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/CraftingManager.java b/src/main/java/StevenDimDoors/mod_pocketDim/CraftingManager.java index 508a041..5f76964 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/CraftingManager.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/CraftingManager.java @@ -48,22 +48,22 @@ public class CraftingManager if (properties.CraftingWarpDoorAllowed) { GameRegistry.addRecipe(new ItemStack(mod_pocketDim.itemWarpDoor, 1), - "yxy", 'x', mod_pocketDim.itemStableFabric, 'y', Item.doorWood); + "yxy", 'x', Item.enderPearl, 'y', Item.doorWood); } if (properties.CraftingTransTrapdoorAllowed) { GameRegistry.addRecipe(new ItemStack(mod_pocketDim.transTrapdoor, 1), - "y", "x", "y", 'x', mod_pocketDim.itemStableFabric, 'y', Block.trapdoor); + "y", "x", "y", 'x', Item.enderPearl, 'y', Block.trapdoor); } if (properties.CraftingRiftSignatureAllowed) { GameRegistry.addRecipe(new ItemStack(mod_pocketDim.itemRiftSignature, 1), - " y ", "yxy", " y ", 'x', mod_pocketDim.itemStableFabric, 'y', Item.ingotIron); + " y ", "yxy", " y ", 'x', Item.enderPearl, 'y', Item.ingotIron); } if (properties.CraftingRiftRemoverAllowed) { GameRegistry.addRecipe(new ItemStack(mod_pocketDim.itemRiftRemover, 1), - "yyy", "yxy", "yyy", 'x', mod_pocketDim.itemStableFabric, 'y', Item.ingotGold); + "yyy", "yxy", "yyy", 'x', Item.enderPearl, 'y', Item.ingotGold); } if (properties.CraftingRiftBladeAllowed) { @@ -72,12 +72,12 @@ public class CraftingManager } if (properties.CraftingStabilizedRiftSignatureAllowed) { - GameRegistry.addRecipe(new ItemStack(mod_pocketDim.itemStabilizedLinkSignature,1), - " y ", "yxy", " y ", 'x', mod_pocketDim.itemRiftSignature, 'y', mod_pocketDim.itemStableFabric); + GameRegistry.addRecipe(new ItemStack(mod_pocketDim.itemStabilizedLinkSignature, 1), + " y ", "yxy", " y ", 'x', mod_pocketDim.itemStableFabric, 'y', Item.ingotIron); } if (properties.CraftingGoldenDimensionalDoorAllowed) { - GameRegistry.addRecipe(new ItemStack(mod_pocketDim.itemGoldenDimensionalDoor,1), + GameRegistry.addRecipe(new ItemStack(mod_pocketDim.itemGoldenDimensionalDoor, 1), "yxy", 'x', mod_pocketDim.itemStableFabric, 'y', mod_pocketDim.itemGoldenDoor); } if (properties.CraftingGoldenDoorAllowed) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemStabilizedRiftSignature.java b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemStabilizedRiftSignature.java index 4d1cf84..e04afdf 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemStabilizedRiftSignature.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemStabilizedRiftSignature.java @@ -54,10 +54,10 @@ public class ItemStabilizedRiftSignature extends ItemRiftSignature 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)) + // or if the player can pay with an Ender Pearl to create a rift. + if (!player.capabilities.isCreativeMode && !player.inventory.hasItem(Item.enderPearl.itemID)) { - mod_pocketDim.sendChat(player, "You don't have any Stable Fabric!"); + 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 @@ -88,7 +88,7 @@ public class ItemStabilizedRiftSignature extends ItemRiftSignature if (!player.capabilities.isCreativeMode) { - player.inventory.consumeInventoryItem(mod_pocketDim.itemStableFabric.itemID); + player.inventory.consumeInventoryItem(Item.enderPearl.itemID); } mod_pocketDim.sendChat(player,"Rift Created"); world.playSoundAtEntity(player,"mods.DimDoors.sfx.riftEnd", 0.6f, 1); From 4192270ef34540db112e11c2c89d1b0fc2af2953 Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Wed, 25 Jun 2014 20:13:03 -0400 Subject: [PATCH 120/187] Changes and Fixes to Rift Signature Variants 1. Changed hasEffect() override since we were overriding a deprecated version. 2. Fixed a bug where we checked if a block could be edited before deciding whether to change the Y coordinate of the rift to be placed. Sometimes we would place the rift in a different block. This is the result of sticking in support for special blocks like grass and snow without considering the impact on surrounding code. It also contradicted comments that specifically said special blocks were ignored... 3. Cleaned up the code for checking for special blocks. 4. Fixed a bug in loading NBT data. There were no null checks on orientation data. If a Rift Signature or Stabilized Rift Signature had been created in a version of DD before orientations were set up, then it cause an exception when so much as looked at in later versions of DD. 5. Partially implemented free redirects for Stabilized Rift Signatures. The check to determine if a redirect is being done is missing. --- .../items/ItemRiftSignature.java | 41 ++++++---- .../items/ItemStabilizedRiftSignature.java | 82 +++++++++++-------- 2 files changed, 71 insertions(+), 52 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemRiftSignature.java b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemRiftSignature.java index a20bc46..14cf081 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemRiftSignature.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemRiftSignature.java @@ -34,12 +34,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,14 +61,14 @@ 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. @@ -113,6 +114,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,26 +142,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==null) + 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+2; + return targetY + 2; } - if(block.isBlockReplaceable(world, x, y, z)) + if (block.isBlockReplaceable(world, x, targetY, z)) { - return y+1;//move block placement down (-2+1) one so its directly over things like snow + return targetY + 1; // Move block placement down (-2+1) one so its directly over things like snow } - if(block instanceof BaseDimDoor) + if (block instanceof BaseDimDoor) { - if(world.getBlockId(x, y-1, z)==block.blockID&&world.getBlockMetadata(x, y, z)==8) + if (BaseDimDoor.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(); @@ -200,11 +204,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; diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemStabilizedRiftSignature.java b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemStabilizedRiftSignature.java index e04afdf..043cc27 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemStabilizedRiftSignature.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemStabilizedRiftSignature.java @@ -14,7 +14,6 @@ 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.util.Point4D; import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; @@ -40,62 +39,77 @@ 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); // 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; if (source != null) { - // Yes, it's initialized. Check if the player is in creative - // or if the player can pay with an Ender Pearl to create a rift. - if (!player.capabilities.isCreativeMode && !player.inventory.hasItem(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; - } - - //The link was used before and already has an endpoint stored. Create links connecting the two endpoints. + // Yes, it's initialized. + DimLink link; + DimLink reverse; 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)) + + // 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 (false) //TODO Add proper check! { - 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(), LinkTypes.NORMAL, source.getOrientation()); + destinationDimension.setDestination(link, x, adjustedY, z); + } + 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(), LinkTypes.NORMAL, source.getOrientation()); + 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); + } } - //Try placing a rift at the source point, but check if its world is loaded first + // Try placing a rift at the source point, but check if its world is loaded first 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(Item.enderPearl.itemID); - } - mod_pocketDim.sendChat(player,"Rift Created"); - world.playSoundAtEntity(player,"mods.DimDoors.sfx.riftEnd", 0.6f, 1); + + 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. + // 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); From fe035f6677767c9180278c6e8171be84bd175121 Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Wed, 25 Jun 2014 20:15:43 -0400 Subject: [PATCH 121/187] Renamed Function in NewDimData Renamed NewDimData.setDestination() to setLinkDestination(). I realized that the name was a little confusing at first sight - it confused me! --- .../StevenDimDoors/mod_pocketDim/core/DDTeleporter.java | 6 +++--- .../java/StevenDimDoors/mod_pocketDim/core/NewDimData.java | 6 +++--- .../mod_pocketDim/dungeon/DungeonSchematic.java | 2 +- .../mod_pocketDim/items/ItemRiftSignature.java | 4 ++-- .../mod_pocketDim/items/ItemStabilizedRiftSignature.java | 6 +++--- .../StevenDimDoors/mod_pocketDim/saving/DDSaveHandler.java | 2 +- .../StevenDimDoors/mod_pocketDim/world/PocketBuilder.java | 2 +- 7 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/core/DDTeleporter.java b/src/main/java/StevenDimDoors/mod_pocketDim/core/DDTeleporter.java index 0c95b06..c7d0c2b 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/core/DDTeleporter.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/core/DDTeleporter.java @@ -574,7 +574,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; } } @@ -745,7 +745,7 @@ public class DDTeleporter 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()); + sourceDim.setLinkDestination(reverse, source.getX(), source.getY(), source.getZ()); // Set up the warp door at the destination orientation = BlockRotator.transformMetadata(orientation, 2, properties.WarpDoorID); @@ -753,7 +753,7 @@ public class DDTeleporter // 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/NewDimData.java b/src/main/java/StevenDimDoors/mod_pocketDim/core/NewDimData.java index 22b783f..15182ed 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/core/NewDimData.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/core/NewDimData.java @@ -503,7 +503,7 @@ 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; @@ -566,13 +566,13 @@ 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); diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/dungeon/DungeonSchematic.java b/src/main/java/StevenDimDoors/mod_pocketDim/dungeon/DungeonSchematic.java index 23bd064..e978832 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/dungeon/DungeonSchematic.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/dungeon/DungeonSchematic.java @@ -325,7 +325,7 @@ public class DungeonSchematic extends Schematic { DimLink reverseLink = dimension.createLink(pocketCenter.getX(), pocketCenter.getY(), pocketCenter.getZ(), LinkTypes.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); } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemRiftSignature.java b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemRiftSignature.java index 14cf081..b4b52e4 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemRiftSignature.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemRiftSignature.java @@ -76,8 +76,8 @@ public class ItemRiftSignature extends Item 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()); + destinationDimension.setLinkDestination(link, x, adjustedY, z); + sourceDimension.setLinkDestination(reverse, source.getX(), source.getY(), source.getZ()); //Try placing a rift at the destination point if (!mod_pocketDim.blockRift.isBlockImmune(world, x, adjustedY, z)) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemStabilizedRiftSignature.java b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemStabilizedRiftSignature.java index 043cc27..488227c 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemStabilizedRiftSignature.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemStabilizedRiftSignature.java @@ -67,7 +67,7 @@ public class ItemStabilizedRiftSignature extends ItemRiftSignature { // Only the source-to-destination link is needed. link = sourceDimension.createLink(source.getX(), source.getY(), source.getZ(), LinkTypes.NORMAL, source.getOrientation()); - destinationDimension.setDestination(link, x, adjustedY, z); + destinationDimension.setLinkDestination(link, x, adjustedY, z); } else { @@ -86,8 +86,8 @@ public class ItemStabilizedRiftSignature extends ItemRiftSignature // Create links connecting the two endpoints. link = sourceDimension.createLink(source.getX(), source.getY(), source.getZ(), LinkTypes.NORMAL, source.getOrientation()); reverse = destinationDimension.createLink(x, adjustedY, z, LinkTypes.NORMAL, orientation); - destinationDimension.setDestination(link, x, adjustedY, z); - sourceDimension.setDestination(reverse, source.getX(), source.getY(), source.getZ()); + destinationDimension.setLinkDestination(link, x, adjustedY, z); + sourceDimension.setLinkDestination(reverse, source.getX(), source.getY(), source.getZ()); // Try placing a rift at the destination point if (!mod_pocketDim.blockRift.isBlockImmune(world, x, adjustedY, z)) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/saving/DDSaveHandler.java b/src/main/java/StevenDimDoors/mod_pocketDim/saving/DDSaveHandler.java index 28929dc..3a7bb70 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/saving/DDSaveHandler.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/saving/DDSaveHandler.java @@ -201,7 +201,7 @@ public class DDSaveHandler Point4D destination = packedLink.tail.destination; if(destination!=null) { - PocketManager.getDimensionData(destination.getDimension()).setDestination(link, destination.getX(),destination.getY(),destination.getZ()); + PocketManager.getDimensionData(destination.getDimension()).setLinkDestination(link, destination.getX(),destination.getY(),destination.getZ()); } unpackedLinks.add(packedLink); } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/world/PocketBuilder.java b/src/main/java/StevenDimDoors/mod_pocketDim/world/PocketBuilder.java index f26939b..15ddecc 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/world/PocketBuilder.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/world/PocketBuilder.java @@ -415,7 +415,7 @@ public class PocketBuilder //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()); + 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); From 9baceb8e3c2df716c32e5a912f6979714c7486ce Mon Sep 17 00:00:00 2001 From: StevenRS11 Date: Thu, 26 Jun 2014 00:08:20 -0400 Subject: [PATCH 122/187] Added backwards light and bugfixes Light in pockets is now reversed added sound to lock removal fixed monolith name fixed other names --- .../mod_pocketDim/EventHookContainer.java | 1 + .../mod_pocketDim/blocks/BlockDimWall.java | 2 +- .../mod_pocketDim/items/ItemDDKey.java | 169 +++++++++--------- .../mod_pocketDim/mod_pocketDim.java | 8 +- .../mod_pocketDim/world/PocketProvider.java | 11 +- .../assets/dimdoors/sound/doorLockRemoved.mp3 | Bin 0 -> 7477 bytes .../assets/dimdoors/sound/doorLockRemoved.ogg | Bin 0 -> 7062 bytes .../textures/items/itemQuartzDimDoor.png | Bin 3031 -> 3127 bytes 8 files changed, 101 insertions(+), 90 deletions(-) create mode 100644 src/main/resources/assets/dimdoors/sound/doorLockRemoved.mp3 create mode 100644 src/main/resources/assets/dimdoors/sound/doorLockRemoved.ogg diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java b/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java index 61d388d..255f2a6 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java @@ -59,6 +59,7 @@ public class EventHookContainer @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"); diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockDimWall.java b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockDimWall.java index d33ab48..d51c9b1 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockDimWall.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockDimWall.java @@ -93,7 +93,7 @@ public class BlockDimWall extends Block public int damageDropped(int metadata) { //Return 0 to avoid dropping Ancient Fabric even if the player somehow manages to break it - return metadata == 1 ? 0 : 2; + return metadata == 1 ? 0 : metadata; } @Override diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemDDKey.java b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemDDKey.java index 4812f74..78d38cd 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemDDKey.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemDDKey.java @@ -27,7 +27,8 @@ import StevenDimDoors.mod_pocketDim.watcher.ClientLinkData; public class ItemDDKey extends Item { - public static final int TIME_TO_UNLOCK = 50; + public static final int TIME_TO_UNLOCK = 30; + public ItemDDKey(int itemID) { super(itemID); @@ -35,24 +36,24 @@ public class ItemDDKey extends Item 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"); - } - } + 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) { @@ -65,118 +66,120 @@ public class ItemDDKey extends Item { 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) + + 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) + if (world.isRemote) { return false; } - - if(player.getItemInUse() != null) + + if (player.getItemInUse() != null) { return true; } int blockID = world.getBlockId(x, y, z); - //make sure we are dealing with a door + // 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 + // 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()) + // what to do if the door has a lock already + if (link.hasLock()) { - if(link.doesKeyUnlock(itemStack)) + if (link.doesKeyUnlock(itemStack)) { - if(link.getLockState()) + if (link.getLockState()) { - world.playSoundAtEntity(player, mod_pocketDim.modid + ":keyUnlock", 1F, 1F); + world.playSoundAtEntity(player, mod_pocketDim.modid + ":keyUnlock", 1F, 1F); } else { - world.playSoundAtEntity(player, mod_pocketDim.modid + ":keyLock", 1F, 1F); + 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); + world.playSoundAtEntity(player, mod_pocketDim.modid + ":doorLocked", 1F, 1F); } } else { - if(!DDLock.hasCreatedLock(itemStack)) + if (!DDLock.hasCreatedLock(itemStack)) { - world.playSoundAtEntity(player, mod_pocketDim.modid + ":keyLock", 1F, 1F); + 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) - { - MovingObjectPosition pos = getMovingObjectPositionFromPlayer(player.worldObj, player, true); - if(pos!=null&&pos.typeOfHit == EnumMovingObjectType.TILE) + 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()) { - 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) { - if (link.doesKeyUnlock(itemStack)&& !world.isRemote) - { - PocketManager.getDimensionData(world).removeLock(link, itemStack); - world.playSoundAtEntity(player, mod_pocketDim.modid + ":keyUnlock", 1F, 1F); + PocketManager.getDimensionData(world).removeLock(link, itemStack); + world.playSoundAtEntity(player, mod_pocketDim.modid + ":doorLockRemoved", 1F, 1F); - } } } - } - player.clearItemInUse(); + } + } + player.clearItemInUse(); + } - } - - /** - * Raytrace to make sure we are still looking at the right block - */ - @Override - public void onUsingItemTick(ItemStack stack, EntityPlayer player, int count) - { - - //no need to check every tick - if(count%10 == 0) + /** + * 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) + 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 != null && link.hasLock()) { if (link.doesKeyUnlock(stack)) { @@ -184,29 +187,27 @@ public class ItemDDKey extends Item } } } - 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 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) + ".name"); + return StatCollector.translateToLocal(this.getUnlocalizedName(par1ItemStack)); } } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java b/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java index 5b1a3cd..fb6a5e2 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java @@ -264,7 +264,7 @@ public class mod_pocketDim 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 LimboProvider from Dimensional Doors and another provider type. Fix your configuration!"); + 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); @@ -292,12 +292,16 @@ public class mod_pocketDim 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"); @@ -309,7 +313,7 @@ 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); GameRegistry.registerCraftingHandler(new CraftingManager()); diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/world/PocketProvider.java b/src/main/java/StevenDimDoors/mod_pocketDim/world/PocketProvider.java index 257efed..29fe690 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/world/PocketProvider.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/world/PocketProvider.java @@ -81,16 +81,21 @@ public class PocketProvider extends WorldProvider return false; } + public float calculateCelestialAngle(long par1, float par3) + { + return .5F; + } + @Override protected void generateLightBrightnessTable() - { + { float modifier = 0.0F; for (int steps = 0; steps <= 15; ++steps) { float var3 = 1.0F - steps / 15.0F; - this.lightBrightnessTable[steps] = 10; - // System.out.println( this.lightBrightnessTable[steps]+"light"); + this.lightBrightnessTable[steps] = var3; + System.out.println( this.lightBrightnessTable[steps]+"light"); } } @Override 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 0000000000000000000000000000000000000000..d7f1ec26b2f2a1b8587ded33152036835baf52fd GIT binary patch literal 7477 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 krm`@?*z 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/dimdoors/textures/items/itemQuartzDimDoor.png b/src/main/resources/assets/dimdoors/textures/items/itemQuartzDimDoor.png index 33fc4ef0d20c0dcb0c3ec6ce282eeb03dfabc664..ca9f2e4c3c7521690c29a16d4147d622c7694bdb 100644 GIT binary patch delta 385 zcmV-{0e=417q=L&zzTn2Nkl6?t2?=5C-hmh31$YEr zfWa5w4P2FIjERX+BLTDqwUp9wZR@3_bag)th6;%kj1Ff#_y4}{W`N9J$o#7yjy#qu zLV*+pQWywJM_4+cv=h0OrOjU907X+Nw_C)K$64n% zU65}!P&AcnwS;31$W}`nKA!9zA&?WKFp?-z7;90smKaAKQjBoSKF+A0O!-TJ@gt$M z(>n;ILmc@8{$zRmRXHK>#@jparZ0rjWboQ=~95gOMpb>wzKKlHk~re=oRRU;SNRWOjaphD(1i&lKcG@vN6`;Mt%LHJZAdZsih<+n;X1RXcdrXb%;}zjBPL-sS~XZzrAq zbpL_i34L&&y_gr!Uf|P8G_^w4T6C?&!Ae-YMJ2O=S;5QmEktq;RU}aFF?O$y5Xl{q nhc)8O3h`!z?CBY1BKR5ru(Lx8v}RT700000NkvXXu0mjf4PlKz From 46f55b22d93ea53eb6b95ef8105fae74015b41d7 Mon Sep 17 00:00:00 2001 From: StevenRS11 Date: Thu, 26 Jun 2014 02:16:57 -0400 Subject: [PATCH 123/187] restricted brightness inversion to dungeons only --- .../mod_pocketDim/world/PocketProvider.java | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/world/PocketProvider.java b/src/main/java/StevenDimDoors/mod_pocketDim/world/PocketProvider.java index 29fe690..04d16a4 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/world/PocketProvider.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/world/PocketProvider.java @@ -11,6 +11,7 @@ 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.DimensionType; import StevenDimDoors.mod_pocketDim.core.PocketManager; import StevenDimDoors.mod_pocketDim.ticking.CustomLimboPopulator; import cpw.mods.fml.relauncher.Side; @@ -88,13 +89,18 @@ public class PocketProvider extends WorldProvider @Override protected void generateLightBrightnessTable() - { + { + if(PocketManager.getDimensionData(this.dimensionId).getDimensionType() == DimensionType.POCKET) + { + super.generateLightBrightnessTable(); + return; + } float modifier = 0.0F; for (int steps = 0; steps <= 15; ++steps) { - float var3 = 1.0F - steps / 15.0F; - this.lightBrightnessTable[steps] = var3; + 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"); } } From 448890207f17315f6bb55d867f6ba7fd818c9e53 Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Thu, 26 Jun 2014 04:52:03 -0400 Subject: [PATCH 124/187] Completed Changes to Stabilized Rift Signature Completed the change to Stabilized Rift Signatures so that overwriting links that already belonged to an SRS is done for free. --- .../mod_pocketDim/items/ItemRiftSignature.java | 11 +++++++++-- .../items/ItemStabilizedRiftSignature.java | 6 +++--- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemRiftSignature.java b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemRiftSignature.java index b4b52e4..9cc5053 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemRiftSignature.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemRiftSignature.java @@ -219,10 +219,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() @@ -244,10 +245,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 488227c..66ee5fd 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemStabilizedRiftSignature.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemStabilizedRiftSignature.java @@ -52,10 +52,10 @@ public class ItemStabilizedRiftSignature extends ItemRiftSignature if (source != null) { // Yes, it's initialized. - DimLink link; - DimLink reverse; NewDimData sourceDimension = PocketManager.getDimensionData(source.getDimension()); NewDimData destinationDimension = PocketManager.getDimensionData(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 @@ -63,7 +63,7 @@ public class ItemStabilizedRiftSignature extends ItemRiftSignature // intention of overwriting the source-side link to point there. // Those benign redirection operations will be handled for free. - if (false) //TODO Add proper check! + 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(), LinkTypes.NORMAL, source.getOrientation()); From 96238d6b53ee064c649cc1f6a2be305f21390bb8 Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Thu, 26 Jun 2014 04:52:32 -0400 Subject: [PATCH 125/187] Minor Change Minor spacing and annotation changes. --- .../java/StevenDimDoors/mod_pocketDim/core/DimLink.java | 3 +++ .../java/StevenDimDoors/mod_pocketDim/util/Point4D.java | 6 ++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/core/DimLink.java b/src/main/java/StevenDimDoors/mod_pocketDim/core/DimLink.java index 8ee3d9a..8b0e3d8 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/core/DimLink.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/core/DimLink.java @@ -60,6 +60,7 @@ public abstract class DimLink { return tail.getDestination(); } + public int getDestinationOrientation() { DimLink link = PocketManager.getLink(this.destination().getX(), this.destination().getY(), this.destination().getZ(), this.destination().getDimension()); @@ -69,6 +70,7 @@ public abstract class DimLink } return (this.orientation()+2)%4; } + public boolean hasDestination() { return (tail.getDestination() != null); @@ -94,6 +96,7 @@ public abstract class DimLink return tail.getLinkType(); } + @Override public String toString() { return link.point + " -> " + (hasDestination() ? destination() : ""); 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) From 364ba11f811002da3939a77db6c038ee6209b809 Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Thu, 26 Jun 2014 05:40:35 -0400 Subject: [PATCH 126/187] Updates to TileEntityRift 1. Fixed the bug where the setting that controls whether Endermen can spawn from rifts was being ignored. It was never checked at all. 2. Cleaned up some formatting and annotations. 3. Removed call to World.removeBlockTileEntity() following a call to World.setBlockToAir(). The latter function already handles removing the tile entity. --- .../tileentities/TileEntityRift.java | 44 ++++++------------- 1 file changed, 14 insertions(+), 30 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityRift.java b/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityRift.java index d6e781b..5b0dea3 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityRift.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityRift.java @@ -1,17 +1,10 @@ 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,12 +12,8 @@ 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.ServerPacketHandler; import StevenDimDoors.mod_pocketDim.mod_pocketDim; import StevenDimDoors.mod_pocketDim.config.DDProperties; @@ -61,22 +50,21 @@ public class TileEntityRift extends DDTileEntityBase public DimLink nearestRiftData; public int spawnedEndermenID = 0; public HashMap renderingCenters = new HashMap(); - + @Override public void updateEntity() { - //Determines if rift should render white closing particles and spread closing effect to other rifts nearby + // Determines if rift should render white closing particles and spread closing effect to other rifts nearby if (this.shouldClose) { closeRift(); } - else if( PocketManager.getLink(xCoord, yCoord, zCoord, worldObj.provider.dimensionId) == null) + 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; } @@ -101,21 +89,19 @@ public class TileEntityRift extends DDTileEntityBase **/ //This code should execute once every 10 seconds - if (updateTimer > 200) + if (updateTimer >= 200) { - this.spawnEndermen(); + this.spawnEndermen(mod_pocketDim.properties); this.grow(mod_pocketDim.properties); updateTimer = 0; } - else if(updateTimer==0) + else if (updateTimer == 0) { this.calculateOldParticleOffset(); //this also calculates the distance for the particle stuff. } updateTimer++; } - - private void clearBlocksOnRift() { //clears blocks for the new rending effect @@ -138,25 +124,23 @@ public class TileEntityRift extends DDTileEntityBase } } - private void spawnEndermen() + private void spawnEndermen(DDProperties properties) { - 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, @@ -210,10 +194,10 @@ public class TileEntityRift extends DDTileEntityBase if (riftCloseTimer > 40) { this.invalidate(); - if(!this.worldObj.isRemote) + if (!this.worldObj.isRemote) { DimLink link = PocketManager.getLink(this.xCoord, this.yCoord, this.zCoord, worldObj); - if(link!=null) + if (link != null) { dimension.deleteLink(link); } @@ -228,8 +212,7 @@ public class TileEntityRift extends DDTileEntityBase private void calculateOldParticleOffset() { - updateNearestRift(); - if (nearestRiftData != null) + if (updateNearestRift()) { Point4D location = nearestRiftData.source(); this.xOffset = this.xCoord - location.getX(); @@ -371,6 +354,7 @@ public class TileEntityRift extends DDTileEntityBase nbt.setInteger("spawnedEndermenID", this.spawnedEndermenID); } + @Override public Packet getDescriptionPacket() { if (PocketManager.getLink(xCoord, yCoord, zCoord, worldObj) != null) From a0629b51a369104f0b2c9b785fc8d337c07c8b92 Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Thu, 26 Jun 2014 07:06:17 -0400 Subject: [PATCH 127/187] Improvements to TileEntityRift 1. Removed several fields and functions referring to the newer rendering code. The functions were just cluttering up the code and the fields were consuming additional memory that was never being used for anything. 2. Updated NBT reading and writing functions to give some tags proper names and to remove references to unused fields. Removed the tag for riftCloseTimer because it was unnecessary alongside the shouldClose flag. If a server reboots while a rift is closing, the rift can start over upon reloading. 3. Renamed some fields and functions to have better names. 4. Changed the various checks for closing rifts. There were a few redundant parts. We don't have to put calls to "this.invalidate()" everywhere on top of explicitly removing the tile entity and destroying its block. 5. Rewrote update timing checks. The rift spread and Enderman spawning calls have been separated to distribute the impact of updating a rift. Also, a flaw in the timing logic meant that the calculations for particle offsets would only run when a rift was first created. That's been fixed. --- .../tileentities/TileEntityRift.java | 184 +++++------------- 1 file changed, 47 insertions(+), 137 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityRift.java b/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityRift.java index 5b0dea3..0effc8b 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityRift.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityRift.java @@ -1,7 +1,6 @@ package StevenDimDoors.mod_pocketDim.tileentities; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; import java.util.Random; @@ -13,7 +12,6 @@ import net.minecraft.network.INetworkManager; import net.minecraft.network.packet.Packet; import net.minecraft.network.packet.Packet132TileEntityData; import net.minecraft.util.AxisAlignedBB; -import net.minecraft.util.MathHelper; import StevenDimDoors.mod_pocketDim.ServerPacketHandler; import StevenDimDoors.mod_pocketDim.mod_pocketDim; import StevenDimDoors.mod_pocketDim.config.DDProperties; @@ -33,97 +31,71 @@ public class TileEntityRift extends DDTileEntityBase 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 float[] POCKET_RENDER_COLOR= {1,1,1,.7F}; - private static final float[] DEFAULT_RENDER_COLOR= {1,1,1,1}; + 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; public DimLink nearestRiftData; public int spawnedEndermenID = 0; - public HashMap renderingCenters = new HashMap(); + + 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); - this.invalidate(); - return; } + else + { + this.invalidate(); + } + return; } - + if (worldObj.getBlockId(xCoord, yCoord, zCoord) != mod_pocketDim.blockRift.blockID) { - worldObj.removeBlockTileEntity(xCoord, yCoord, zCoord); this.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 (this.shouldClose) + { + closeRift(); + return; + } + + if (updateTimer >= UPDATE_PERIOD) { this.spawnEndermen(mod_pocketDim.properties); - this.grow(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. + this.calculateParticleOffsets(); + this.spread(mod_pocketDim.properties); } updateTimer++; } - 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(DDProperties properties) { if (worldObj.isRemote || !properties.RiftsSpawnEndermenEnabled) @@ -174,14 +146,14 @@ public class TileEntityRift extends DDTileEntityBase private void closeRift() { NewDimData dimension = PocketManager.getDimensionData(worldObj); - if (riftCloseTimer == 20) + if (closeTimer == CLOSING_PERIOD / 2) { - ArrayList rifts= dimension.findRiftsInRange(worldObj, 6, xCoord, yCoord, zCoord); - if (rifts.size()>0) + ArrayList riftLinks = dimension.findRiftsInRange(worldObj, 6, xCoord, yCoord, zCoord); + if (riftLinks.size() > 0) { - for(DimLink riftToClose : rifts) + for (DimLink riftLink : riftLinks) { - Point4D location = riftToClose.source(); + Point4D location = riftLink.source(); TileEntityRift rift = (TileEntityRift) worldObj.getBlockTileEntity(location.getX(), location.getY(), location.getZ()); if (rift != null) { @@ -191,9 +163,8 @@ public class TileEntityRift extends DDTileEntityBase } } } - if (riftCloseTimer > 40) + if (closeTimer >= CLOSING_PERIOD) { - this.invalidate(); if (!this.worldObj.isRemote) { DimLink link = PocketManager.getLink(this.xCoord, this.yCoord, this.zCoord, worldObj); @@ -204,13 +175,12 @@ public class TileEntityRift extends DDTileEntityBase } 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; } - riftCloseTimer++; + closeTimer++; } - private void calculateOldParticleOffset() + private void calculateParticleOffsets() { if (updateNearestRift()) { @@ -218,68 +188,16 @@ public class TileEntityRift extends DDTileEntityBase 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); } 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) { @@ -292,13 +210,10 @@ public class TileEntityRift extends DDTileEntityBase { return countAncestorLinks(link.parent()) + 1; } - else - { - return 0; - } + return 0; } - public void grow(DDProperties properties) + public void spread(DDProperties properties) { if (worldObj.isRemote || !properties.RiftSpreadEnabled || random.nextInt(MAX_RIFT_SPREAD_CHANCE) < RIFT_SPREAD_CHANCE || this.shouldClose) @@ -329,13 +244,10 @@ public class TileEntityRift extends DDTileEntityBase 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.age = nbt.getInteger("age"); this.shouldClose = nbt.getBoolean("shouldClose"); this.spawnedEndermenID = nbt.getInteger("spawnedEndermenID"); } @@ -344,9 +256,7 @@ public class TileEntityRift extends DDTileEntityBase public void writeToNBT(NBTTagCompound nbt) { super.writeToNBT(nbt); - nbt.setInteger("age", this.age); - nbt.setInteger("count", this.updateTimer); - nbt.setInteger("count2", this.riftCloseTimer); + nbt.setInteger("updateTimer", this.updateTimer); nbt.setInteger("xOffset", this.xOffset); nbt.setInteger("yOffset", this.yOffset); nbt.setInteger("zOffset", this.zOffset); From 444b862b12e9d51c289c57b341a52838339b8467 Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Thu, 26 Jun 2014 09:19:04 -0400 Subject: [PATCH 128/187] Minor Change Renamed the field mod_pocketDim.itemStabilizedLinkSignature to itemStabilizedRiftSignature to follow the item's actual name. --- .../java/StevenDimDoors/mod_pocketDim/CraftingManager.java | 2 +- .../java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/CraftingManager.java b/src/main/java/StevenDimDoors/mod_pocketDim/CraftingManager.java index 5f76964..6ff7121 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/CraftingManager.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/CraftingManager.java @@ -72,7 +72,7 @@ public class CraftingManager } if (properties.CraftingStabilizedRiftSignatureAllowed) { - GameRegistry.addRecipe(new ItemStack(mod_pocketDim.itemStabilizedLinkSignature, 1), + GameRegistry.addRecipe(new ItemStack(mod_pocketDim.itemStabilizedRiftSignature, 1), " y ", "yxy", " y ", 'x', mod_pocketDim.itemStableFabric, 'y', Item.ingotIron); } if (properties.CraftingGoldenDimensionalDoorAllowed) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java b/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java index 239b137..267f644 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java @@ -135,7 +135,7 @@ public class mod_pocketDim public static Item itemRiftSignature; public static Item itemStableFabric; public static Item itemUnstableDoor; - public static Item itemStabilizedLinkSignature; + public static Item itemStabilizedRiftSignature; public static BiomeGenBase limboBiome; public static BiomeGenBase pocketBiome; @@ -218,7 +218,7 @@ public class mod_pocketDim itemStableFabric = (new ItemStableFabric(properties.StableFabricItemID, 0)).setUnlocalizedName("itemStableFabric"); 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 @@ -265,7 +265,7 @@ 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"); From 59f335ac8c7bdf37de0925748ee896540e05769a Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Thu, 26 Jun 2014 12:11:51 -0400 Subject: [PATCH 129/187] Added Dispenser Support for SRS Added support for using Stabilized Rift Signatures from dispensers under specific conditions. Everything works except for playing the sound that occurs when an SRS is used. Not sure why that's not working. --- .../mod_pocketDim/CraftingManager.java | 9 +++- .../items/ItemStabilizedRiftSignature.java | 52 ++++++++++++++++++- .../DispenserBehaviorStabilizedRS.java | 42 +++++++++++++++ .../mod_pocketDim/mod_pocketDim.java | 1 + 4 files changed, 101 insertions(+), 3 deletions(-) create mode 100644 src/main/java/StevenDimDoors/mod_pocketDim/items/behaviors/DispenserBehaviorStabilizedRS.java diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/CraftingManager.java b/src/main/java/StevenDimDoors/mod_pocketDim/CraftingManager.java index 6ff7121..7cc635d 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/CraftingManager.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/CraftingManager.java @@ -1,9 +1,11 @@ package StevenDimDoors.mod_pocketDim; -import StevenDimDoors.mod_pocketDim.config.DDProperties; import net.minecraft.block.Block; +import net.minecraft.block.BlockDispenser; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; +import StevenDimDoors.mod_pocketDim.config.DDProperties; +import StevenDimDoors.mod_pocketDim.items.behaviors.DispenserBehaviorStabilizedRS; import cpw.mods.fml.common.registry.GameRegistry; public class CraftingManager @@ -87,4 +89,9 @@ public class CraftingManager } } + public static void registerDispenserBehaviors() + { + // Register the dispenser behaviors for certain DD items + BlockDispenser.dispenseBehaviorRegistry.putObject(mod_pocketDim.itemStabilizedRiftSignature, new DispenserBehaviorStabilizedRS()); + } } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemStabilizedRiftSignature.java b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemStabilizedRiftSignature.java index 66ee5fd..b47bff6 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemStabilizedRiftSignature.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemStabilizedRiftSignature.java @@ -45,10 +45,10 @@ public class ItemStabilizedRiftSignature extends ItemRiftSignature { return true; } - Point4DOrientation source = getSource(stack); + 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. @@ -117,6 +117,54 @@ public class ItemStabilizedRiftSignature extends ItemRiftSignature 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.getDimensionData(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(), LinkTypes.NORMAL, source.getOrientation()); + destinationDimension.setLinkDestination(link, x, adjustedY, z); + + // Try placing a rift at the source point, but check if its world is loaded first + 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); + } + + // 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 */ 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/mod_pocketDim.java b/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java index 267f644..6554a6a 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java @@ -292,6 +292,7 @@ public class mod_pocketDim LanguageRegistry.instance().addStringLocalization("entity.DimDoors.Obelisk.name", "Monolith"); CraftingManager.registerRecipes(properties); + CraftingManager.registerDispenserBehaviors(); DungeonHelper.initialize(); gatewayGenerator = new GatewayGenerator(properties); GameRegistry.registerWorldGenerator(mod_pocketDim.gatewayGenerator); From e40168954f17b6832c4f3cea997c59641cd790f2 Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Thu, 26 Jun 2014 12:17:59 -0400 Subject: [PATCH 130/187] Minor Change to TileEntityRift Changed the function call for playing the rift-closing sound to match other similar calls in Minecraft - the sound should target the center of the block. I also switched the last flag argument. It seems to determine whether distance between the player and the source should be checked when playing back the sound, although documentation is lacking so I can't be sure. Other blocks that use that function use "false", while things involving sounds that should be heard uniformly, such as rainfall, use "true". --- I noticed that this code runs on the client and server. Some parts modify link data and rifts on the client side. We should really stop this from happening as it could lead to inconsistencies. --- .../mod_pocketDim/tileentities/TileEntityRift.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityRift.java b/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityRift.java index 0effc8b..13f9f96 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityRift.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityRift.java @@ -174,8 +174,7 @@ public class TileEntityRift extends DDTileEntityBase } } worldObj.setBlockToAir(xCoord, yCoord, zCoord); - worldObj.playSound(xCoord, yCoord, zCoord, "mods.DimDoors.sfx.riftClose", (float) .7, 1, true); - return; + worldObj.playSound(xCoord + 0.5, yCoord + 0.5, zCoord + 0.5, "mods.DimDoors.sfx.riftClose", 0.7f, 1, false); } closeTimer++; } From 42568a1864a5416eedf78b708c2a509754f3229d Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Thu, 26 Jun 2014 12:20:19 -0400 Subject: [PATCH 131/187] Removed RenderRift Removed the RenderRift class since it relates to unused functionality and references fields that I removed from TileEntityRift. --- .../mod_pocketDimClient/RenderRift.java | 218 ------------------ 1 file changed, 218 deletions(-) delete mode 100644 src/main/java/StevenDimDoors/mod_pocketDimClient/RenderRift.java diff --git a/src/main/java/StevenDimDoors/mod_pocketDimClient/RenderRift.java b/src/main/java/StevenDimDoors/mod_pocketDimClient/RenderRift.java deleted file mode 100644 index 07c1cf9..0000000 --- a/src/main/java/StevenDimDoors/mod_pocketDimClient/RenderRift.java +++ /dev/null @@ -1,218 +0,0 @@ -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 java.util.HashMap; - -import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer; -import net.minecraft.tileentity.TileEntity; - -import org.lwjgl.opengl.GL11; - -import StevenDimDoors.mod_pocketDim.tileentities.TileEntityRift; -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) - { - yWorld = yWorld+.75; - GL11.glPushMatrix(); - - GL11.glDisable(GL11.GL_CULL_FACE); - GL11.glDisable(GL_TEXTURE_2D); - GL11.glDisable(GL_LIGHTING); - - //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.glEnable(GL11.GL_CULL_FACE); - GL11.glEnable(GL11.GL_LIGHTING); - 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) - { - GL11.glBegin(GL11.GL_QUAD_STRIP); - - 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); - } - - - } - - } - - - GL11.glEnd(); - - - } - - public void drawCrackRotated(HashMap quads,double xWorld,double yWorld,double zWorld) - { - GL11.glBegin(GL11.GL_QUAD_STRIP); - - 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); - } - - } - 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); - } - - } - } - - 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) - { - - - rotatedCoords[0]=-coords[0]; - rotatedCoords[1]=-coords[1]; - - rotatedCoords[2]=-coords[2]; - rotatedCoords[3]=-coords[3]; - //return rotatedCoords; - } - return coords; - - } -} \ No newline at end of file From fb4643d7cf5e0b764bee546ec5b0b1ace79153b3 Mon Sep 17 00:00:00 2001 From: StevenRS11 Date: Fri, 27 Jun 2014 16:27:23 -0400 Subject: [PATCH 132/187] deleted renderRift --- .../mod_pocketDimClient/RenderRift.java | 218 ------------------ 1 file changed, 218 deletions(-) delete mode 100644 src/main/java/StevenDimDoors/mod_pocketDimClient/RenderRift.java diff --git a/src/main/java/StevenDimDoors/mod_pocketDimClient/RenderRift.java b/src/main/java/StevenDimDoors/mod_pocketDimClient/RenderRift.java deleted file mode 100644 index 8782e2b..0000000 --- a/src/main/java/StevenDimDoors/mod_pocketDimClient/RenderRift.java +++ /dev/null @@ -1,218 +0,0 @@ -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 java.util.HashMap; - -import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer; -import net.minecraft.tileentity.TileEntity; - -import org.lwjgl.opengl.GL11; - -import StevenDimDoors.mod_pocketDim.tileentities.TileEntityRift; -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) - { - yWorld = yWorld+.75; - GL11.glPushMatrix(); - - GL11.glDisable(GL11.GL_CULL_FACE); - GL11.glDisable(GL_TEXTURE_2D); - GL11.glDisable(GL_LIGHTING); - - //GL11.glLogicOp(GL11.GL_INVERT); - // GL11.glEnable(GL11.GL_COLOR_LOGIC_OP); - - GL11.glColor4f(.2F, .2F, .2F, 1F); - - GL11.glEnable(GL_BLEND); - glBlendFunc(GL11.GL_SRC_ALPHA_SATURATE,GL_ONE_MINUS_DST_COLOR); - - /** - * 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.glEnable(GL11.GL_CULL_FACE); - GL11.glEnable(GL11.GL_LIGHTING); - 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) - { - GL11.glBegin(GL11.GL_QUAD_STRIP); - - 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); - } - - - } - - } - - - GL11.glEnd(); - - - } - - public void drawCrackRotated(HashMap quads,double xWorld,double yWorld,double zWorld) - { - GL11.glBegin(GL11.GL_QUAD_STRIP); - - 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); - } - - } - 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); - } - - } - } - - 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) - { - - - rotatedCoords[0]=-coords[0]; - rotatedCoords[1]=-coords[1]; - - rotatedCoords[2]=-coords[2]; - rotatedCoords[3]=-coords[3]; - //return rotatedCoords; - } - return coords; - - } -} \ No newline at end of file From e3665c09dd4521e24c8b4b1528e448b1023ca936 Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Sat, 28 Jun 2014 13:06:22 -0400 Subject: [PATCH 133/187] Added Hunger Restoration on Limbo Respawn Added code to EventHookContainer.revivePlayerInLimbo() so that the player's food level is restored upon respawning in Limbo. Apparently it was possible for players to have death loops from starving to death in Hardcore Limbo. --- .../java/StevenDimDoors/mod_pocketDim/EventHookContainer.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java b/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java index 4130aaf..4a5fef3 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java @@ -30,6 +30,8 @@ import cpw.mods.fml.relauncher.SideOnly; public class EventHookContainer { + private static final int MAX_FOOD_LEVEL = 20; + private final DDProperties properties; public EventHookContainer(DDProperties properties) @@ -175,6 +177,7 @@ public class EventHookContainer 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); } From b2e086e7c1a07c24187b8f2c04116250c2d82a06 Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Tue, 1 Jul 2014 21:55:57 -0400 Subject: [PATCH 134/187] Added the Universal Limbo Setting Added the Universal Limbo config option to the world config settings. When enabled, it causes players to get teleported to Limbo if they die in any dimension except Limbo. It's disabled by default. This feature was requested by Mr_Turing. --- .../mod_pocketDim/EventHookContainer.java | 26 +++++++++++++++++-- .../config/DDWorldProperties.java | 9 +++++-- .../mod_pocketDim/mod_pocketDim.java | 5 ++-- 3 files changed, 34 insertions(+), 6 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java b/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java index 4a5fef3..1855963 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java @@ -7,6 +7,7 @@ import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.ItemDoor; import net.minecraft.item.ItemStack; import net.minecraft.world.World; +import net.minecraft.world.WorldProvider; import net.minecraftforge.client.event.sound.PlayBackgroundMusicEvent; import net.minecraftforge.client.event.sound.SoundLoadEvent; import net.minecraftforge.event.EventPriority; @@ -18,6 +19,7 @@ import net.minecraftforge.event.entity.player.PlayerInteractEvent.Action; import net.minecraftforge.event.terraingen.InitMapGenEvent; import net.minecraftforge.event.world.WorldEvent; import StevenDimDoors.mod_pocketDim.config.DDProperties; +import StevenDimDoors.mod_pocketDim.config.DDWorldProperties; import StevenDimDoors.mod_pocketDim.core.DDTeleporter; import StevenDimDoors.mod_pocketDim.core.PocketManager; import StevenDimDoors.mod_pocketDim.items.BaseItemDoor; @@ -33,11 +35,20 @@ public class EventHookContainer private static final int MAX_FOOD_LEVEL = 20; private final DDProperties properties; + private DDWorldProperties worldProperties; public EventHookContainer(DDProperties properties) { this.properties = properties; } + + public void setWorldProperties(DDWorldProperties worldProperties) + { + // SenseiKiwi: + // Why have a setter rather than accessing mod_pocketDim.worldProperties? + // I want to make this dependency explicit in our code. + this.worldProperties = worldProperties; + } @ForgeSubscribe(priority = EventPriority.LOW) public void onInitMapGen(InitMapGenEvent event) @@ -134,7 +145,7 @@ public class EventHookContainer Entity entity = event.entity; if (properties.LimboEnabled && properties.LimboReturnsInventoryEnabled && - entity instanceof EntityPlayer && entity.worldObj.provider instanceof PocketProvider) + entity instanceof EntityPlayer && isValidSourceForLimbo(entity.worldObj.provider)) { EntityPlayer player = (EntityPlayer) entity; mod_pocketDim.deathTracker.addUsername(player.username); @@ -156,7 +167,7 @@ public class EventHookContainer Entity entity = event.entity; - if (entity instanceof EntityPlayer && entity.worldObj.provider instanceof PocketProvider) + if (entity instanceof EntityPlayer && isValidSourceForLimbo(entity.worldObj.provider)) { EntityPlayer player = (EntityPlayer) entity; mod_pocketDim.deathTracker.addUsername(player.username); @@ -171,6 +182,17 @@ public class EventHookContainer } 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) { diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/config/DDWorldProperties.java b/src/main/java/StevenDimDoors/mod_pocketDim/config/DDWorldProperties.java index db2a498..b2a4569 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/config/DDWorldProperties.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/config/DDWorldProperties.java @@ -9,7 +9,6 @@ public class DDWorldProperties /** * World Generation Settings */ - public final DimensionFilter RiftClusterDimensions; public final DimensionFilter RiftGatewayDimensions; @@ -17,7 +16,7 @@ public class DDWorldProperties * General Flags */ public final boolean LimboEscapeEnabled; - + public final boolean UniversalLimboEnabled; //Names of categories private static final String CATEGORY_WORLD_GENERATION = "world generation"; @@ -44,6 +43,12 @@ public class DDWorldProperties "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(); } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java b/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java index 6554a6a..5512e67 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java @@ -63,7 +63,6 @@ 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.DDLogger; import StevenDimDoors.mod_pocketDim.world.BiomeGenLimbo; import StevenDimDoors.mod_pocketDim.world.BiomeGenPocket; import StevenDimDoors.mod_pocketDim.world.DDBiomeGenBase; @@ -148,6 +147,7 @@ public class mod_pocketDim public static FastRiftRegenerator fastRiftRegenerator; public static GatewayGenerator gatewayGenerator; public static DeathTracker deathTracker; + private static EventHookContainer hooks; //TODO this is a temporary workaround for saving data private String currrentSaveRootDirectory; @@ -177,7 +177,7 @@ public class mod_pocketDim 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); } @@ -336,6 +336,7 @@ public class mod_pocketDim // Load the config file that's specific to this world worldProperties = new DDWorldProperties(new File(currrentSaveRootDirectory + "/DimensionalDoors/DimDoorsWorld.cfg")); + hooks.setWorldProperties(worldProperties); // Initialize a new DeathTracker deathTracker = new DeathTracker(currrentSaveRootDirectory + "/DimensionalDoors/data/deaths.txt"); From 3d88e72ecbeb2ef3ab862d3c2920281dc3083f36 Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Wed, 2 Jul 2014 13:38:57 -0400 Subject: [PATCH 135/187] Fixed Bugs in Golden Dimensional Doors 1. We weren't giving old tickets to the doors that owned them. That would result in doors requesting new tickets and the old ones wouldn't be released. Each time a server rebooted, a new ticket would be created. Then Opis would report that many chunks were forcefully loaded in a pocket because it doesn't consider overlapping tickets. We now give doors their old tickets when they're reloaded and we release extra tickets referring to the same door. That will also deal with the excess tickets that already exist on servers. 2. Rewrote the logic for checking if a Golden Dimensional Door is allowed to force-load a pocket. We now check if the door is within the horizontal bounds of the pocket. This prevents the confusing scenario where someone places a door far away from the pocket but the only chunks affected are in the pocket. 3. Fixed the calculation for determining which chunks must be force-loaded to cover a pocket. This has the benefit that fewer chunks should need to be loaded. It should be enough to load 16 chunks. We previously loaded 25 chunks just to err on the side of caution. 4. Golden Dimensional Doors only try to initialize as chunk loaders once. We previously allowed them to keep trying every tick until they could get a ticket. --- .../mod_pocketDim/IChunkLoader.java | 3 +- .../helpers/ChunkLoaderHelper.java | 82 +++++++++--- .../tileentities/TileEntityDimDoorGold.java | 118 ++++++++++-------- .../mod_pocketDim/world/PocketBuilder.java | 41 +++++- 4 files changed, 166 insertions(+), 78 deletions(-) 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/helpers/ChunkLoaderHelper.java b/src/main/java/StevenDimDoors/mod_pocketDim/helpers/ChunkLoaderHelper.java index 06d22d5..e866ec4 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 + } + } + + public static Ticket createTicket(int x, int y, int z, World world) + { + 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++) { - IChunkLoader tile = (IChunkLoader) world.getBlockTileEntity(goldDimDoorX, goldDimDoorY, goldDimDoorZ); - tile.forceChunkLoading(ticket,goldDimDoorX,goldDimDoorZ); - } + ForgeChunkManager.forceChunk(ticket, new ChunkCoordIntPair(chunkX, chunkZ)); + } } } public static void loadChunkForcedWorlds(FMLServerStartingEvent event) { - for(NewDimData data : PocketManager.getDimensions()) + 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/tileentities/TileEntityDimDoorGold.java b/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityDimDoorGold.java index 7dc1c64..093c1e8 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.getDimensionData(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/world/PocketBuilder.java b/src/main/java/StevenDimDoors/mod_pocketDim/world/PocketBuilder.java index 15ddecc..515fbee 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/world/PocketBuilder.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/world/PocketBuilder.java @@ -8,7 +8,7 @@ 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.experimental.BoundingBox; import StevenDimDoors.mod_pocketDim.Point3D; import StevenDimDoors.mod_pocketDim.blocks.IDimDoor; import StevenDimDoors.mod_pocketDim.config.DDProperties; @@ -21,13 +21,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; @@ -559,4 +559,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); + } } From ec290b0dc15a757823d3647eeb2be1c959c05b88 Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Wed, 2 Jul 2014 13:59:55 -0400 Subject: [PATCH 136/187] Increased Version Number Increased the mod's version number to account for recent fixes and small features. --- build.gradle | 2 +- src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java | 2 +- src/main/resources/mcmod.info | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/build.gradle b/build.gradle index 2cbcf59..6d68944 100644 --- a/build.gradle +++ b/build.gradle @@ -15,7 +15,7 @@ apply plugin: 'forge' -version = "2.2.3-" + System.getenv("BUILD_NUMBER") +version = "2.2.4-" + System.getenv("BUILD_NUMBER") group= "com.stevenrs11.dimdoors" // http://maven.apache.org/guides/mini/guide-naming-conventions.html archivesBaseName = "DimensionalDoors" diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java b/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java index 5512e67..cf281e8 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java @@ -98,7 +98,7 @@ serverPacketHandlerSpec = @SidedPacketHandler(channels = {PacketConstants.CHANNEL_NAME}, packetHandler = ServerPacketHandler.class)) public class mod_pocketDim { - public static final String version = "1.6.4-R2.2.3"; + public static final String version = "1.6.4-R2.2.4"; public static final String modid = "dimdoors"; //TODO need a place to stick all these constants diff --git a/src/main/resources/mcmod.info b/src/main/resources/mcmod.info index 4687d32..92ac4ad 100644 --- a/src/main/resources/mcmod.info +++ b/src/main/resources/mcmod.info @@ -6,7 +6,7 @@ "modid": "dimdoors", "name": "Dimensional Doors", "description": "Bend and twist reality itself, creating pocket dimensions, rifts, and much more", -"version": "1.6.4-R2.2.3", +"version": "1.6.4-R2.2.4", "credits": "Created by StevenRS11, Coded by StevenRS11 and SenseiKiwi, Logo and Testing by Jaitsu", "logoFile": "/dimdoors_logo.png", "mcversion": "", From c29db9b7295e3051bc26caba74958a97f92f1e6b Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Thu, 3 Jul 2014 12:02:36 -0400 Subject: [PATCH 137/187] Minor Changes Cleaned up the code in DDCommandBase a little. --- .../mod_pocketDim/commands/DDCommandBase.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/commands/DDCommandBase.java b/src/main/java/StevenDimDoors/mod_pocketDim/commands/DDCommandBase.java index b62cc86..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 @@ -96,13 +95,15 @@ public abstract class DDCommandBase extends CommandBase * 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 */ - public int compareTo(ICommand par1ICommand) + @Override + public int compareTo(ICommand command) { - return this.getCommandName().compareTo(par1ICommand.getCommandName()); + return this.getCommandName().compareTo(command.getCommandName()); } - public int compareTo(Object par1Obj) + @Override + public int compareTo(Object other) { - return this.compareTo((ICommand)par1Obj); + return this.compareTo((ICommand) other); } } From 262595ff4d5555212943252b9b079a2774109cd8 Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Thu, 3 Jul 2014 12:25:00 -0400 Subject: [PATCH 138/187] Changes to Commands 1. Fixed some warnings in the affected commands. 2. Removed checks for whether a command is running on the server or client side. We have performed those checks inconsistently throughout our commands without problems. I assume that they must be running on the server side only. If I'm wrong, we can add a check to DDCommandBase. 3. Minor punctuation change in DDCommandResult --- .../commands/CommandCreateDungeonRift.java | 14 +-- .../commands/CommandCreatePocket.java | 32 +++--- .../commands/CommandCreateRandomRift.java | 11 +-- .../commands/CommandDeleteAllLinks.java | 11 +-- .../commands/CommandDeleteRifts.java | 2 - .../commands/CommandExportDungeon.java | 97 ++++++++----------- .../commands/CommandResetDungeons.java | 2 - .../commands/CommandTeleportPlayer.java | 11 +-- .../commands/DDCommandResult.java | 2 +- 9 files changed, 66 insertions(+), 116 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandCreateDungeonRift.java b/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandCreateDungeonRift.java index b1512e3..686b5d3 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandCreateDungeonRift.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandCreateDungeonRift.java @@ -1,5 +1,9 @@ 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; @@ -9,12 +13,6 @@ 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; @@ -38,10 +36,6 @@ public class CommandCreateDungeonRift extends DDCommandBase NewDimData dimension; DungeonHelper dungeonHelper = DungeonHelper.instance(); - if (sender.worldObj.isRemote) - { - return DDCommandResult.SUCCESS; - } if (command.length == 0) { return DDCommandResult.TOO_FEW_ARGUMENTS; diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandCreatePocket.java b/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandCreatePocket.java index b2843a6..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; @@ -24,26 +23,21 @@ public class CommandCreatePocket extends DDCommandBase @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 index 97cc1a5..646fda3 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandCreateRandomRift.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandCreateRandomRift.java @@ -38,11 +38,7 @@ public class CommandCreateRandomRift extends DDCommandBase { NewDimData dimension; DungeonHelper dungeonHelper = DungeonHelper.instance(); - - if (sender.worldObj.isRemote) - { - return DDCommandResult.SUCCESS; - } + if (command.length > 1) { return DDCommandResult.TOO_MANY_ARGUMENTS; @@ -118,9 +114,6 @@ public class CommandCreateRandomRift extends DDCommandBase { return null; } - else - { - return matches.get( random.nextInt(matches.size()) ); - } + 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 index 317b101..af9f915 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandDeleteAllLinks.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandDeleteAllLinks.java @@ -1,16 +1,13 @@ package StevenDimDoors.mod_pocketDim.commands; +import java.util.ArrayList; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.world.World; 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; diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandDeleteRifts.java b/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandDeleteRifts.java index 328576c..a2aac97 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandDeleteRifts.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandDeleteRifts.java @@ -2,7 +2,6 @@ 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; @@ -10,7 +9,6 @@ import StevenDimDoors.mod_pocketDim.core.DimLink; import StevenDimDoors.mod_pocketDim.core.NewDimData; import StevenDimDoors.mod_pocketDim.core.PocketManager; -@SuppressWarnings("deprecation") public class CommandDeleteRifts extends DDCommandBase { private static CommandDeleteRifts instance = null; diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandExportDungeon.java b/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandExportDungeon.java index 4c0ad4d..84b9584 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandExportDungeon.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandExportDungeon.java @@ -2,7 +2,6 @@ package StevenDimDoors.mod_pocketDim.commands; import java.io.File; -import net.minecraft.command.ICommandSender; import net.minecraft.entity.player.EntityPlayer; import StevenDimDoors.mod_pocketDim.config.DDProperties; import StevenDimDoors.mod_pocketDim.helpers.DungeonHelper; @@ -60,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) @@ -137,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/CommandResetDungeons.java b/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandResetDungeons.java index f9ed088..b3535cf 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandResetDungeons.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandResetDungeons.java @@ -2,7 +2,6 @@ package StevenDimDoors.mod_pocketDim.commands; import java.util.ArrayList; -import net.minecraft.command.ICommandSender; import net.minecraft.entity.player.EntityPlayer; import net.minecraftforge.common.DimensionManager; import StevenDimDoors.mod_pocketDim.core.DimLink; @@ -10,7 +9,6 @@ import StevenDimDoors.mod_pocketDim.core.LinkTypes; import StevenDimDoors.mod_pocketDim.core.NewDimData; import StevenDimDoors.mod_pocketDim.core.PocketManager; -@SuppressWarnings("deprecation") public class CommandResetDungeons extends DDCommandBase { private static CommandResetDungeons instance = null; diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandTeleportPlayer.java b/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandTeleportPlayer.java index 1b29999..93b4d3f 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandTeleportPlayer.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandTeleportPlayer.java @@ -1,16 +1,11 @@ package StevenDimDoors.mod_pocketDim.commands; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraftforge.common.DimensionManager; import StevenDimDoors.mod_pocketDim.core.DDTeleporter; 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; @@ -121,7 +116,7 @@ public class CommandTeleportPlayer extends DDCommandBase return DDCommandResult.SUCCESS; } - public boolean isInteger( String input ) + public static boolean isInteger( String input ) { try { diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/commands/DDCommandResult.java b/src/main/java/StevenDimDoors/mod_pocketDim/commands/DDCommandResult.java index 9ec0cf7..f34b282 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/commands/DDCommandResult.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/commands/DDCommandResult.java @@ -8,7 +8,7 @@ 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 int CUSTOM_ERROR_CODE = -1; From c5a77268fc6be470c5e06a0731b17081d8c20591 Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Thu, 3 Jul 2014 14:08:51 -0400 Subject: [PATCH 139/187] Changes to Commands Removed a few server-side checks that I missed on the previous commit. --- .../mod_pocketDim/commands/CommandListDungeons.java | 4 ---- .../mod_pocketDim/commands/CommandResetDungeons.java | 4 ---- src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java | 4 ---- 3 files changed, 12 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandListDungeons.java b/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandListDungeons.java index 043d0fd..222b481 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandListDungeons.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandListDungeons.java @@ -31,10 +31,6 @@ public class CommandListDungeons extends DDCommandBase int pageCount; ArrayList dungeonNames; - if (sender.worldObj.isRemote) - { - return DDCommandResult.SUCCESS; - } if (command.length > 1) { return DDCommandResult.TOO_MANY_ARGUMENTS; diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandResetDungeons.java b/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandResetDungeons.java index b3535cf..aad0671 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandResetDungeons.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandResetDungeons.java @@ -29,10 +29,6 @@ public class CommandResetDungeons extends DDCommandBase @Override protected DDCommandResult processCommand(EntityPlayer sender, String[] command) { - if(sender.worldObj.isRemote) - { - return DDCommandResult.SUCCESS; - } if (command.length > 0) { return DDCommandResult.TOO_FEW_ARGUMENTS; diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java b/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java index cf281e8..a1a93e6 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java @@ -351,15 +351,11 @@ public class mod_pocketDim event.registerServerCommand( CommandListDungeons.instance() ); event.registerServerCommand( CommandCreateRandomRift.instance() ); event.registerServerCommand( CommandDeleteAllLinks.instance() ); - //CommandDeleteDimensionData.instance().register(event); event.registerServerCommand( CommandDeleteRifts.instance() ); event.registerServerCommand( CommandExportDungeon.instance() ); - //CommandPrintDimensionData.instance().register(event); - //CommandPruneDimensions.instance().register(event); event.registerServerCommand( CommandCreatePocket.instance() ); event.registerServerCommand( CommandTeleportPlayer.instance() ); - try { ChunkLoaderHelper.loadChunkForcedWorlds(event); From 80bb87dac66c0c87024e399721e1c9b2148577ca Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Thu, 3 Jul 2014 14:19:08 -0400 Subject: [PATCH 140/187] Rewrote CommandDeleteRifts Rewrote CommandDeleteRifts for clarity and to remove several flaws. Previously, the command would have removed non-immune blocks that were in the same location as a rift. It also set blocks in the command sender's dimension rather than the target dimension, so blocks would have potentially disappeared from the wrong world. --- .../commands/CommandDeleteRifts.java | 86 +++++++++++-------- 1 file changed, 52 insertions(+), 34 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandDeleteRifts.java b/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandDeleteRifts.java index a2aac97..cc1a1a1 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandDeleteRifts.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandDeleteRifts.java @@ -8,6 +8,7 @@ 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; public class CommandDeleteRifts extends DDCommandBase { @@ -15,7 +16,7 @@ public class CommandDeleteRifts extends DDCommandBase private CommandDeleteRifts() { - super("dd-???", "???"); + super("dd-deleterifts", "[dimension number]"); } public static CommandDeleteRifts instance() @@ -29,47 +30,64 @@ public class CommandDeleteRifts extends DDCommandBase @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.getDimensionData(targetDimension); + 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 From b4a58f5c884e4ea40082412eb6e1c16dc5a2f530 Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Thu, 3 Jul 2014 17:20:59 -0400 Subject: [PATCH 141/187] Simplified PocketManager 1. Rewrote or removed a few bits that were causing minor warnings. 2. Rewrote deleteDimensionFiles() and deleteDimensionData() to remove unnecessary casts and checks. We can confirm that those checks are unnecessary because those functions are only used inside PocketManager. If they were ever exposed externally, then we would need to add checks again. --- .../mod_pocketDim/core/PocketManager.java | 51 ++++++++----------- 1 file changed, 22 insertions(+), 29 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/core/PocketManager.java b/src/main/java/StevenDimDoors/mod_pocketDim/core/PocketManager.java index 1882bba..acb6ed9 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/core/PocketManager.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/core/PocketManager.java @@ -315,44 +315,43 @@ public class PocketManager { if (deleteFolder) { - deleteDimensionFiles(target); + deleteDimensionFiles(dimension); } dimensionIDBlackList.add(dimension.id); - deleteDimensionData(dimension.id); + deleteDimensionData(dimension); return true; } return false; } - private static boolean deleteDimensionFiles(NewDimData target) + private static void deleteDimensionFiles(InnerDimData dimension) { - InnerDimData dimension = (InnerDimData) target; - if (dimension.isPocketDimension() && DimensionManager.getWorld(dimension.id()) == null) - { - 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(); - return true; - } - return false; + // 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 boolean deleteDimensionData(int dimensionID) + private static void deleteDimensionData(InnerDimData dimension) { - if (dimensionData.containsKey(dimensionID) && DimensionManager.getWorld(dimensionID) == null) + // 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) { - NewDimData target = PocketManager.getDimensionData(dimensionID); - InnerDimData dimension = (InnerDimData) target; - - dimensionData.remove(dimensionID); // 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) @@ -647,10 +646,7 @@ public class PocketManager { return dimension.getLink(x, y, z); } - else - { - return null; - } + return null; } public static boolean isBlackListed(int dimensionID) @@ -715,9 +711,6 @@ 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; From 592aabf62771e4da08b7118c4fefe3960822de94 Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Thu, 3 Jul 2014 17:32:40 -0400 Subject: [PATCH 142/187] Minor Change Added a comment in PocketManager to explain why we don't unregister pocket dimensions with Forge when we delete them. --- .../StevenDimDoors/mod_pocketDim/core/PocketManager.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/core/PocketManager.java b/src/main/java/StevenDimDoors/mod_pocketDim/core/PocketManager.java index acb6ed9..7c7c3e0 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/core/PocketManager.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/core/PocketManager.java @@ -317,6 +317,11 @@ public class PocketManager { 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); return true; From 972a67de766ec5784b92a337e8006ff160b1596a Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Thu, 3 Jul 2014 22:46:31 -0400 Subject: [PATCH 143/187] Rewrote CommandResetDungeons 1. Rewrote CommandResetDungeons to improve clarity and remove bugs. This version of the command preserves valid links. Those were previously removed, which would break some dungeons unnecessarily. 2. Fixed NewDimData.setParentToRoot(). The function did not account for the possibility that the target's parent might still exist and would need to be updated, leading to conflicting data. It also did not reset pack depth. We now correctly update a dimension and all its descendants. --- .../commands/CommandResetDungeons.java | 93 +++++++++++-------- .../mod_pocketDim/core/NewDimData.java | 32 +++++++ 2 files changed, 88 insertions(+), 37 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandResetDungeons.java b/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandResetDungeons.java index aad0671..69eaace 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandResetDungeons.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandResetDungeons.java @@ -1,9 +1,10 @@ package StevenDimDoors.mod_pocketDim.commands; import java.util.ArrayList; +import java.util.HashSet; +import java.util.Stack; 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.NewDimData; @@ -31,55 +32,73 @@ public class CommandResetDungeons extends DDCommandBase { 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.isDungeon()) { - 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() == LinkTypes.DUNGEON) { - data.createLink(link.source(), LinkTypes.DUNGEON_EXIT, link.orientation()); + dungeon.createLink(link.source(), LinkTypes.DUNGEON, link.orientation()); } - if(link.linkType()==LinkTypes.DUNGEON) + else if (link.linkType() == LinkTypes.REVERSE) { - data.createLink(link.source(), LinkTypes.DUNGEON, link.orientation()); + dungeon.createLink(link.source(), LinkTypes.DUNGEON_EXIT, link.orientation()); } } } } - - 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/core/NewDimData.java b/src/main/java/StevenDimDoors/mod_pocketDim/core/NewDimData.java index 15182ed..8ed8d83 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/core/NewDimData.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/core/NewDimData.java @@ -4,6 +4,7 @@ import java.util.ArrayList; 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; @@ -516,11 +517,42 @@ public abstract class NewDimData */ public void setParentToRoot() { + // 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.isDungeon) + { + 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.isDungeon) + { + this.packDepth = calculatePackDepth(this.parent, this.dungeon); + } + this.modified = true; } public static int calculatePackDepth(NewDimData parent, DungeonData current) From 805e9dd040e8ec5a27f737e926832f5845d4117b Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Thu, 3 Jul 2014 22:49:15 -0400 Subject: [PATCH 144/187] Minor Changes Fixed up a few spots to clear some warnings. --- .../mod_pocketDim/commands/CommandResetDungeons.java | 1 - .../StevenDimDoors/mod_pocketDim/core/NewDimData.java | 11 +++-------- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandResetDungeons.java b/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandResetDungeons.java index 69eaace..074124e 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandResetDungeons.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandResetDungeons.java @@ -2,7 +2,6 @@ package StevenDimDoors.mod_pocketDim.commands; import java.util.ArrayList; import java.util.HashSet; -import java.util.Stack; import net.minecraft.entity.player.EntityPlayer; import StevenDimDoors.mod_pocketDim.core.DimLink; diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/core/NewDimData.java b/src/main/java/StevenDimDoors/mod_pocketDim/core/NewDimData.java index 8ed8d83..326b7d4 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/core/NewDimData.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/core/NewDimData.java @@ -581,10 +581,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) @@ -621,10 +618,7 @@ public abstract class NewDimData { return linkList.get(random.nextInt(linkList.size())); } - else - { - return linkList.get(0); - } + return linkList.get(0); } public boolean isModified() @@ -637,6 +631,7 @@ public abstract class NewDimData this.modified = false; } + @Override public String toString() { return "DimID= " + this.id; From c1e58c25cc1fcb301a4128d59a0a35df99181cf5 Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Fri, 4 Jul 2014 01:17:25 -0400 Subject: [PATCH 145/187] Increased Max Monolith Aggro Increased the maximum Monolith aggro level and the cap range values by a factor of 1.25. The max aggro increase is to slow down how long it takes Monoliths to max out because they're just a little too fast right now. The cap adjustments will preserve the range of texture states they can have while idling. --- .../StevenDimDoors/mod_pocketDim/ticking/MobMonolith.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/ticking/MobMonolith.java b/src/main/java/StevenDimDoors/mod_pocketDim/ticking/MobMonolith.java index f54f515..279c123 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/ticking/MobMonolith.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/ticking/MobMonolith.java @@ -21,9 +21,9 @@ import StevenDimDoors.mod_pocketDim.world.PocketProvider; public class MobMonolith extends EntityFlying implements IMob { - private static final short MAX_AGGRO = 200; - private static final short MAX_AGGRO_CAP = 80; - private static final short MIN_AGGRO_CAP = 20; + 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; From f64768ed1631762f334b90a4a10fb897cee80305 Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Fri, 4 Jul 2014 02:14:24 -0400 Subject: [PATCH 146/187] Rewrote DeleteFolder Rewrote the helper class DeleteFolder. It was leaving behind empty directories when pockets were deleted. --- .../mod_pocketDim/helpers/DeleteFolder.java | 28 ++++++++++--------- 1 file changed, 15 insertions(+), 13 deletions(-) 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 From d3860119e9c5b569ac6b38194f8248b3bbd5ad13 Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Fri, 4 Jul 2014 13:05:08 -0400 Subject: [PATCH 147/187] Minor Change to PocketManager Added a minor check to PocketManager.loadDimension() so that an attempt to load an unregistered dimension won't be passed on to Forge where it would cause an exception - which is then caught by Forge before it can cause problems. This isn't strictly necessary, but it's a nice consideration. --- .../StevenDimDoors/mod_pocketDim/core/PocketManager.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/core/PocketManager.java b/src/main/java/StevenDimDoors/mod_pocketDim/core/PocketManager.java index 7c7c3e0..5a1f1d6 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/core/PocketManager.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/core/PocketManager.java @@ -483,6 +483,11 @@ public class PocketManager public static WorldServer loadDimension(int id) { + if (!DimensionManager.isDimensionRegistered(id)) + { + return null; + } + WorldServer world = DimensionManager.getWorld(id); if (world == null) { From 4d53ae5f6a38ccd9f54a8aed74f62cb7b23ad5b1 Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Fri, 4 Jul 2014 13:53:44 -0400 Subject: [PATCH 148/187] Removed CommandDeleteAllLinks I removed CommandDeleteAllLinks because of the significant risk that it would harm a server. It's possible that someone could run this by accident instead of CommandDeleteRifts. It takes the same arguments or even no arguments and it would immediately wipe all links in a dimension. We can restore it later if it's really needed. --- .../commands/CommandDeleteAllLinks.java | 66 ------------------- .../mod_pocketDim/mod_pocketDim.java | 1 - 2 files changed, 67 deletions(-) delete mode 100644 src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandDeleteAllLinks.java 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 af9f915..0000000 --- a/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandDeleteAllLinks.java +++ /dev/null @@ -1,66 +0,0 @@ -package StevenDimDoors.mod_pocketDim.commands; - -import java.util.ArrayList; - -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.world.World; -import StevenDimDoors.mod_pocketDim.core.DimLink; -import StevenDimDoors.mod_pocketDim.core.NewDimData; -import StevenDimDoors.mod_pocketDim.core.PocketManager; - -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 - 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/mod_pocketDim.java b/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java index a1a93e6..9130a86 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java @@ -350,7 +350,6 @@ public class mod_pocketDim event.registerServerCommand( CommandCreateDungeonRift.instance() ); event.registerServerCommand( CommandListDungeons.instance() ); event.registerServerCommand( CommandCreateRandomRift.instance() ); - event.registerServerCommand( CommandDeleteAllLinks.instance() ); event.registerServerCommand( CommandDeleteRifts.instance() ); event.registerServerCommand( CommandExportDungeon.instance() ); event.registerServerCommand( CommandCreatePocket.instance() ); From 1e3b32a15ca7d6c6b18852e8852d81a67e8d767c Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Fri, 4 Jul 2014 14:06:41 -0400 Subject: [PATCH 149/187] Minor Change Removed a reference to CommandDeleteAllLinks from mod_pocketDim. --- src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java b/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java index 9130a86..62dd845 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java @@ -30,7 +30,6 @@ import StevenDimDoors.mod_pocketDim.blocks.WarpDoor; import StevenDimDoors.mod_pocketDim.commands.CommandCreateDungeonRift; import StevenDimDoors.mod_pocketDim.commands.CommandCreatePocket; import StevenDimDoors.mod_pocketDim.commands.CommandCreateRandomRift; -import StevenDimDoors.mod_pocketDim.commands.CommandDeleteAllLinks; import StevenDimDoors.mod_pocketDim.commands.CommandDeleteRifts; import StevenDimDoors.mod_pocketDim.commands.CommandExportDungeon; import StevenDimDoors.mod_pocketDim.commands.CommandListDungeons; From 16f0a8303aca16a799f12cfc5c81b53e51083f0d Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Fri, 4 Jul 2014 20:20:46 -0400 Subject: [PATCH 150/187] Rewrote CommandTeleportPlayer Rewrote CommandTeleportPlayer for the same reason as usual. There were a few bugs before, such as that lookups for players were limited to within the world from which the command sender was using the command. Players in other dimensions could not be teleported. The command would also place people in the ground because it did not adjust its coordinates for the way that DDTeleporter interprets them - as the location of the top block of a door and the player's head. --- .../commands/CommandTeleportPlayer.java | 203 ++++++++++-------- .../commands/DDCommandResult.java | 1 + 2 files changed, 110 insertions(+), 94 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandTeleportPlayer.java b/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandTeleportPlayer.java index 93b4d3f..83bf268 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandTeleportPlayer.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandTeleportPlayer.java @@ -1,8 +1,10 @@ package StevenDimDoors.mod_pocketDim.commands; import net.minecraft.entity.player.EntityPlayer; -import net.minecraftforge.common.DimensionManager; +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; @@ -12,7 +14,10 @@ public class CommandTeleportPlayer extends DDCommandBase private CommandTeleportPlayer() { - super("dd-tp", new String[] {" "," "} ); + super("dd-tp", new String[] { + " ", + " ", + " "} ); } public static CommandTeleportPlayer instance() @@ -23,110 +28,120 @@ public class CommandTeleportPlayer extends DDCommandBase return instance; } - /** - * 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; + // SenseiKiwi: Will not be used, but I prefer not to leave 'world' as null + 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.getDimensionData(dimensionID); + 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; + z = Integer.parseInt(command[3]); + destination = new Point4D(x, y, z, dimensionID); + } + else + { + x = Integer.parseInt(command[2]); + y = Integer.parseInt(command[3]) + 1; + z = Integer.parseInt(command[4]); + destination = new Point4D(x, y, z, dimensionID); + } + // Teleport! + DDTeleporter.teleportEntity(targetPlayer, destination, checkOrientation); return DDCommandResult.SUCCESS; } - public static 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/DDCommandResult.java b/src/main/java/StevenDimDoors/mod_pocketDim/commands/DDCommandResult.java index f34b282..b6a31b9 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/commands/DDCommandResult.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/commands/DDCommandResult.java @@ -9,6 +9,7 @@ public class DDCommandResult { 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 PLAYER_OFFLINE = new DDCommandResult(6, "Error: Player is not online", false); public static final int CUSTOM_ERROR_CODE = -1; From 17a770eaf0b02858a3b9cc5d0e855d48cb140043 Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Fri, 4 Jul 2014 20:55:57 -0400 Subject: [PATCH 151/187] Minor Change Added two comments to CommandTeleportPlayer --- .../mod_pocketDim/commands/CommandTeleportPlayer.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandTeleportPlayer.java b/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandTeleportPlayer.java index 83bf268..b02222f 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandTeleportPlayer.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandTeleportPlayer.java @@ -116,14 +116,14 @@ public class CommandTeleportPlayer extends DDCommandBase else if (command.length == 4) { x = Integer.parseInt(command[1]); - y = Integer.parseInt(command[2]) + 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; + y = Integer.parseInt(command[3]) + 1; // Correct the Y value z = Integer.parseInt(command[4]); destination = new Point4D(x, y, z, dimensionID); } From 100fa38c52b67f31ac4e7343bd7beff5ea722be6 Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Sat, 5 Jul 2014 14:18:18 -0400 Subject: [PATCH 152/187] Minor Changes to DDTeleporter Made some minor changes to DDTeleporter to get rid of a few warnings. Also tweaked and commented DDTeleporter.initializeDestination(). There were inappropriate references to a link's internal variables instead of using its getters and there was a subtle link overwrite for blacklist destinations. Without comments, it would probably be unclear that overwriting that link is safe. This changes are in preparation for fixing issues with blacklisted destination redirection. --- .../mod_pocketDim/core/DDTeleporter.java | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/core/DDTeleporter.java b/src/main/java/StevenDimDoors/mod_pocketDim/core/DDTeleporter.java index c7d0c2b..fc793e5 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/core/DDTeleporter.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/core/DDTeleporter.java @@ -25,7 +25,6 @@ import StevenDimDoors.mod_pocketDim.mod_pocketDim; import StevenDimDoors.mod_pocketDim.blocks.BaseDimDoor; import StevenDimDoors.mod_pocketDim.config.DDProperties; import StevenDimDoors.mod_pocketDim.helpers.yCoordHelper; -import StevenDimDoors.mod_pocketDim.items.ItemDimensionalDoor; import StevenDimDoors.mod_pocketDim.schematic.BlockRotator; import StevenDimDoors.mod_pocketDim.tileentities.TileEntityDimDoor; import StevenDimDoors.mod_pocketDim.util.Point4D; @@ -483,9 +482,12 @@ public class DDTeleporter { if (link.hasDestination()) { - 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); + // Overwrite this link to a blacklisted destination with a safe exit link + // We don't need to change 'link' to a different reference. + // NewDimData will overwrite the existing link in-place. + PocketManager.getDimensionData(link.source().getDimension()).createLink(link.source(), LinkTypes.SAFE_EXIT, link.orientation()); } else { @@ -499,7 +501,7 @@ public class DDTeleporter case LinkTypes.DUNGEON: return PocketBuilder.generateNewDungeonPocket(link, properties); case LinkTypes.POCKET: - return PocketBuilder.generateNewPocket(link, properties,door); + return PocketBuilder.generateNewPocket(link, properties, door); case LinkTypes.SAFE_EXIT: return generateSafeExit(link, properties); case LinkTypes.DUNGEON_EXIT: @@ -544,10 +546,7 @@ public class DDTeleporter { return matches.get( random.nextInt(matches.size()) ); } - else - { - return null; - } + return null; } private static boolean generateUnsafeExit(DimLink link) @@ -749,7 +748,7 @@ public class DDTeleporter // 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 From 06cf72f9f73fd058099e63a589d13ff72a74ede9 Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Sat, 5 Jul 2014 21:28:10 -0400 Subject: [PATCH 153/187] Fixed Flawed Link Redirection Fixed the way in which we handle redirecting links to blacklisted dimensions. The previous method always converted links into safe exits. This lead to strange situations that could be seen as bugs. For instance, using a dungeon entrance in a root dimension would generate an exit door and a supporting platform directly above the entrance door. That also meant that any visited dungeons would be unusable if they were reset. We now do different things depending on the location of the link and its type. If the link is a dungeon link, then its destination is reset to allow a new dungeon to form. For other link types, if the link is in a pocket dimension, then it becomes a safe exit link, because it could be the only way out. If it's in a root dimension, then there are no reasonable destinations, so the teleport request is cancelled. --- .../mod_pocketDim/core/DDTeleporter.java | 29 ++++++++++++++++--- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/core/DDTeleporter.java b/src/main/java/StevenDimDoors/mod_pocketDim/core/DDTeleporter.java index fc793e5..f8f7bc1 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/core/DDTeleporter.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/core/DDTeleporter.java @@ -484,10 +484,31 @@ public class DDTeleporter { if (PocketManager.isBlackListed(link.destination().getDimension())) { - // Overwrite this link to a blacklisted destination with a safe exit link - // We don't need to change 'link' to a different reference. - // NewDimData will overwrite the existing link in-place. - PocketManager.getDimensionData(link.source().getDimension()).createLink(link.source(), LinkTypes.SAFE_EXIT, 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() == LinkTypes.DUNGEON) + { + // Ovewrite the link into a dungeon link with no destination + start.createLink(link.source(), LinkTypes.DUNGEON, link.orientation()); + } + 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(), LinkTypes.SAFE_EXIT, link.orientation()); + } + else + { + // Cancel the teleport attempt + return false; + } + } } else { From 58d5f6dd146f353b697a98f2e3b6bee5b26976ef Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Mon, 7 Jul 2014 01:59:26 -0400 Subject: [PATCH 154/187] Minor Changes Minor annotation changes to remove some warnings... and keep up my GitHub spree. --- .../mod_pocketDim/world/fortresses/ComponentNetherGateway.java | 3 ++- .../world/fortresses/DDNetherFortressGenerator.java | 3 ++- .../world/fortresses/DDStructureNetherBridgeStart.java | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) 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 8b05b39..db6ef44 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/world/fortresses/ComponentNetherGateway.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/world/fortresses/ComponentNetherGateway.java @@ -66,7 +66,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; 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 644a5c1..9531939 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/world/fortresses/DDNetherFortressGenerator.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/world/fortresses/DDNetherFortressGenerator.java @@ -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 bc7cc06..2778197 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/world/fortresses/DDStructureNetherBridgeStart.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/world/fortresses/DDStructureNetherBridgeStart.java @@ -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) { From dc55359aaf37e69de39a96d41766d238d5c42cbc Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Mon, 7 Jul 2014 03:56:47 -0400 Subject: [PATCH 155/187] Minor Changes Made various minor changes to eliminate warnings or to improve clarity. --- .../mod_pocketDim/blocks/BaseDimDoor.java | 40 +++++++------------ .../mod_pocketDim/blocks/BlockDimWall.java | 1 + .../mod_pocketDim/blocks/BlockDoorGold.java | 19 ++++----- .../mod_pocketDim/blocks/DimensionalDoor.java | 5 +-- .../mod_pocketDim/blocks/TransTrapdoor.java | 7 ++-- .../mod_pocketDim/blocks/WarpDoor.java | 1 - 6 files changed, 28 insertions(+), 45 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BaseDimDoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BaseDimDoor.java index 3b94723..f8bd4e1 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BaseDimDoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BaseDimDoor.java @@ -11,7 +11,6 @@ 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.Item; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.Icon; import net.minecraft.util.MathHelper; @@ -22,7 +21,6 @@ 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.tileentities.TileEntityDimDoor; import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; @@ -159,16 +157,13 @@ public abstract class BaseDimDoor extends BlockDoor implements IDimDoor, ITileEn reversed = !reversed; } } - if (isUpperDoorBlock(fullMetadata)) + { return this.upperTextures[reversed ? 1 : 0]; - else - return this.lowerTextures[reversed ? 1 : 0]; - } - else - { - return this.lowerTextures[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, @@ -180,29 +175,23 @@ public abstract class BaseDimDoor extends BlockDoor implements IDimDoor, ITileEn { int metadata = world.getBlockMetadata(x, y, z); TileEntityDimDoor dimTile = (TileEntityDimDoor) tile; - dimTile.openOrClosed = this.isDoorOnRift(world, x, y, z)&&this.isUpperDoorBlock(metadata); + 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) + public static boolean isDoorOnRift(World world, int x, int y, int z) { - if(this.isUpperDoorBlock( world.getBlockMetadata(x, y, z))) + if (isUpperDoorBlock(world.getBlockMetadata(x, y, z))) { - if(PocketManager.getLink(x, y, z, world.provider.dimensionId) != null||PocketManager.getLink(x, y-1, z, world.provider.dimensionId) != null) - { - return true; - } + // Target block is the upper block + return (PocketManager.getLink(x, y, z, world.provider.dimensionId) != null || + PocketManager.getLink(x, y - 1, z, world.provider.dimensionId) != null); } - else - { - if(PocketManager.getLink(x, y, z, world.provider.dimensionId) != null||PocketManager.getLink(x, y+1, z, world.provider.dimensionId) != null) - { - return true; - } - } - return false; + // Target block is the lower block + return (PocketManager.getLink(x, y, z, world.provider.dimensionId) != null || + PocketManager.getLink(x, y + 1, z, world.provider.dimensionId) != null); } /** @@ -359,7 +348,8 @@ public abstract class BaseDimDoor extends BlockDoor implements IDimDoor, ITileEn /** * Returns the ID of the items to drop on destruction. */ - public int idDropped(int metadata, Random random, int fortune) + @Override + public int idDropped(int metadata, Random random, int fortune) { return isUpperDoorBlock(metadata) ? 0 : this.getDrops(); } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockDimWall.java b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockDimWall.java index 82e451a..fd1b46c 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockDimWall.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockDimWall.java @@ -88,6 +88,7 @@ public class BlockDimWall extends Block subItems.add(new ItemStack(this, 1, ix)); } } + @Override public void onBlockDestroyedByPlayer(World par1World, int par2, int par3, int par4, int par5) {} diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockDoorGold.java b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockDoorGold.java index 1e8f91e..2d3ac30 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockDoorGold.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockDoorGold.java @@ -2,17 +2,15 @@ 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.mod_pocketDim; -import StevenDimDoors.mod_pocketDim.config.DDProperties; 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 StevenDimDoors.mod_pocketDim.mod_pocketDim; +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; public class BlockDoorGold extends BlockDoor { @@ -110,15 +108,12 @@ public class BlockDoorGold extends BlockDoor reversed = !reversed; } } - if (BaseDimDoor.isUpperDoorBlock(fullMetadata)) + { return this.upperTextures[reversed ? 1 : 0]; - else - return this.lowerTextures[reversed ? 1 : 0]; - } - else - { - return this.lowerTextures[0]; + } + return this.lowerTextures[reversed ? 1 : 0]; } + return this.lowerTextures[0]; } } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/DimensionalDoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/DimensionalDoor.java index 42d25f6..2d9eef5 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/DimensionalDoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/DimensionalDoor.java @@ -9,10 +9,8 @@ import StevenDimDoors.mod_pocketDim.core.LinkTypes; 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); @@ -27,10 +25,11 @@ public class DimensionalDoor extends BaseDimDoor 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, LinkTypes.POCKET, world.getBlockMetadata(x, y - 1, z)); } } } + @Override public int getDrops() { diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/TransTrapdoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/TransTrapdoor.java index d1b7fd4..aa4d4bc 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/TransTrapdoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/TransTrapdoor.java @@ -18,7 +18,6 @@ import StevenDimDoors.mod_pocketDim.core.NewDimData; import StevenDimDoors.mod_pocketDim.core.PocketManager; import StevenDimDoors.mod_pocketDim.tileentities.TileEntityTransTrapdoor; -@SuppressWarnings("deprecation") public class TransTrapdoor extends BlockTrapDoor implements IDimDoor, ITileEntityProvider { @@ -61,7 +60,7 @@ 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); + updateAttachedTile(world, x, y, z); } @Override @@ -76,8 +75,8 @@ public class TransTrapdoor extends BlockTrapDoor implements IDimDoor, ITileEntit { return new TileEntityTransTrapdoor(); } - - public void updateAttachedTile(World world, int x, int y, int z) + + public static void updateAttachedTile(World world, int x, int y, int z) { TileEntity tile = world.getBlockTileEntity(x, y, z); if (tile instanceof TileEntityTransTrapdoor) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/WarpDoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/WarpDoor.java index 6f7d881..58cfd05 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/WarpDoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/WarpDoor.java @@ -9,7 +9,6 @@ import StevenDimDoors.mod_pocketDim.core.LinkTypes; 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) From 52bae00dc6e0c01fd24857ba594c397c066fd791 Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Sun, 6 Jul 2014 04:01:07 -0400 Subject: [PATCH 156/187] Minor Change Minor change to remove a warning --- .../StevenDimDoors/mod_pocketDim/dungeon/DungeonSchematic.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/dungeon/DungeonSchematic.java b/src/main/java/StevenDimDoors/mod_pocketDim/dungeon/DungeonSchematic.java index e978832..7a443fc 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/dungeon/DungeonSchematic.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/dungeon/DungeonSchematic.java @@ -162,7 +162,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(); From 7d840ff895d2494197c2fb3b1bd5f9ce2a25d491 Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Sun, 6 Jul 2014 04:31:42 -0400 Subject: [PATCH 157/187] Fixed Pick Block Results We previously returned the Vanilla counterparts to our doors as the items to be used by the pick block button - used in Creative mode for replicating nearby blocks. This was incorrect because we would want to return the actual door item needed to place the particular door in question. More importantly, this might solve our issues with WAILA reporting the wrong information when players look at our doors. I read the code for the most recent version of WAILA and it uses various functions to choose how to identify a block. The result of Block.idPicked() is probably used as the main source for the identities of our blocks. --- .../mod_pocketDim/blocks/BaseDimDoor.java | 4 ++-- .../mod_pocketDim/blocks/BlockDoorGold.java | 8 +++++++ .../blocks/BlockGoldDimDoor.java | 6 ++++++ .../mod_pocketDim/blocks/DimensionalDoor.java | 7 +++++++ .../mod_pocketDim/blocks/IDimDoor.java | 2 ++ .../mod_pocketDim/blocks/TransTrapdoor.java | 21 ++++++++++++++++--- .../mod_pocketDim/blocks/TransientDoor.java | 6 ++++++ .../mod_pocketDim/blocks/UnstableDoor.java | 8 +++++++ .../mod_pocketDim/blocks/WarpDoor.java | 7 +++++++ 9 files changed, 64 insertions(+), 5 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BaseDimDoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BaseDimDoor.java index f8bd4e1..d26a0e3 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BaseDimDoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BaseDimDoor.java @@ -340,9 +340,9 @@ 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(); } /** diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockDoorGold.java b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockDoorGold.java index 2d3ac30..d3e703d 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockDoorGold.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockDoorGold.java @@ -8,6 +8,7 @@ import net.minecraft.client.renderer.IconFlipped; import net.minecraft.client.renderer.texture.IconRegister; import net.minecraft.util.Icon; import net.minecraft.world.IBlockAccess; +import net.minecraft.world.World; import StevenDimDoors.mod_pocketDim.mod_pocketDim; import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; @@ -35,6 +36,13 @@ public class BlockDoorGold extends BlockDoor upperTextures[1] = new IconFlipped(upperTextures[0], true, false); lowerTextures[1] = new IconFlipped(lowerTextures[0], true, false); } + + @Override + @SideOnly(Side.CLIENT) + public int idPicked(World world, int x, int y, int z) + { + return mod_pocketDim.itemGoldenDoor.itemID; + } @Override public int idDropped(int par1, Random par2Random, int par3) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockGoldDimDoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockGoldDimDoor.java index 5a788db..3feb075 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockGoldDimDoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockGoldDimDoor.java @@ -34,6 +34,12 @@ public class BlockGoldDimDoor extends BaseDimDoor } } + @Override + public int getDoorItem() + { + return mod_pocketDim.itemGoldenDimensionalDoor.itemID; + } + @Override public int getDrops() { diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/DimensionalDoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/DimensionalDoor.java index 2d9eef5..3537a77 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/DimensionalDoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/DimensionalDoor.java @@ -3,6 +3,7 @@ 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.mod_pocketDim; import StevenDimDoors.mod_pocketDim.config.DDProperties; import StevenDimDoors.mod_pocketDim.core.DimLink; import StevenDimDoors.mod_pocketDim.core.LinkTypes; @@ -30,6 +31,12 @@ public class DimensionalDoor extends BaseDimDoor } } + @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..82b4562 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/IDimDoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/IDimDoor.java @@ -12,5 +12,7 @@ public interface IDimDoor public int getDrops(); + public int getDoorItem(); + public TileEntity initDoorTE(World world, int x, int y, int z); } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/TransTrapdoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/TransTrapdoor.java index aa4d4bc..4a1df0d 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/TransTrapdoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/TransTrapdoor.java @@ -2,6 +2,9 @@ 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; @@ -99,18 +102,30 @@ public class TransTrapdoor extends BlockTrapDoor implements IDimDoor, ITileEntit } } } - + + @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) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/TransientDoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/TransientDoor.java index fb0a187..0eac631 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/TransientDoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/TransientDoor.java @@ -72,6 +72,12 @@ public class TransientDoor extends BaseDimDoor } } } + + @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 e59a94c..6f14c66 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/UnstableDoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/UnstableDoor.java @@ -3,6 +3,7 @@ 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.mod_pocketDim; import StevenDimDoors.mod_pocketDim.config.DDProperties; import StevenDimDoors.mod_pocketDim.core.LinkTypes; import StevenDimDoors.mod_pocketDim.core.NewDimData; @@ -24,6 +25,13 @@ public class UnstableDoor extends BaseDimDoor dimension.createLink(x, y, z, LinkTypes.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 58cfd05..f860f6e 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/WarpDoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/WarpDoor.java @@ -3,6 +3,7 @@ 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.mod_pocketDim; import StevenDimDoors.mod_pocketDim.config.DDProperties; import StevenDimDoors.mod_pocketDim.core.DimLink; import StevenDimDoors.mod_pocketDim.core.LinkTypes; @@ -30,6 +31,12 @@ public class WarpDoor extends BaseDimDoor } } + @Override + public int getDoorItem() + { + return mod_pocketDim.itemWarpDoor.itemID; + } + @Override public int getDrops() { From 2904ec146d241273f38738cc081a983167b3ae5e Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Wed, 9 Jul 2014 04:01:37 -0400 Subject: [PATCH 158/187] Implemented Automatic Versioning in Build Script 1. Changed build.gradle so that it edits the version numbers in mod_pocketDim.java and mcmod.info. 2. Changed mod_pocketDim to use a placeholder for its version number and fixed an annotation that was wrong. It would cause our mod_pocketDim instance to not initialize properly. I removed what seemed to be workarounds that were hiding the problem. 3. Fixed space in TileEntityDimDoor.invalidate() and corrected a non-static access to a static field in mod_pocketDim. 4. Changed mcmod.info so that it users placeholders for the mod version and MC version values. --- build.gradle | 12 ++++----- .../mod_pocketDim/mod_pocketDim.java | 7 +++-- .../tileentities/TileEntityDimDoor.java | 27 ++++++++++--------- src/main/resources/mcmod.info | 4 +-- 4 files changed, 25 insertions(+), 25 deletions(-) diff --git a/build.gradle b/build.gradle index 6d68944..abc1771 100644 --- a/build.gradle +++ b/build.gradle @@ -13,10 +13,8 @@ buildscript { apply plugin: 'forge' - - version = "2.2.4-" + System.getenv("BUILD_NUMBER") -group= "com.stevenrs11.dimdoors" // http://maven.apache.org/guides/mini/guide-naming-conventions.html +group = "com.stevenrs11.dimdoors" // http://maven.apache.org/guides/mini/guide-naming-conventions.html archivesBaseName = "DimensionalDoors" minecraft { @@ -28,17 +26,19 @@ sourceCompatibility = '1.6' processResources { - // replace stuff in mcmod.info, nothing else + // Replace stuff $version and $mcversion in mcmod.info and mod_pocketDim.java from(sourceSets.main.resources.srcDirs) { include 'mcmod.info' + include 'mod_pocketDim.java' - // 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' + exclude 'mod_pocketDim.java' } } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java b/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java index 62dd845..95dce46 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java @@ -97,7 +97,7 @@ serverPacketHandlerSpec = @SidedPacketHandler(channels = {PacketConstants.CHANNEL_NAME}, packetHandler = ServerPacketHandler.class)) public class mod_pocketDim { - public static final String version = "1.6.4-R2.2.4"; + public static final String version = "$version"; public static final String modid = "dimdoors"; //TODO need a place to stick all these constants @@ -107,8 +107,8 @@ public class mod_pocketDim @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 transientDoor; public static Block warpDoor; @@ -169,7 +169,6 @@ 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"); diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityDimDoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityDimDoor.java index 115aa64..fe478b6 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityDimDoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityDimDoor.java @@ -36,19 +36,20 @@ public class TileEntityDimDoor extends DDTileEntityBase } 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 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.fastRiftRegenerator.registerRiftForRegen(xCoord, yCoord, zCoord, this.worldObj.provider.dimensionId); + } + } + } @Override public void readFromNBT(NBTTagCompound nbt) diff --git a/src/main/resources/mcmod.info b/src/main/resources/mcmod.info index 92ac4ad..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.4-R2.2.4", +"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" ], From 1106319f8ca2b9c5d3accc2345b10d390b5d6b31 Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Wed, 9 Jul 2014 04:15:37 -0400 Subject: [PATCH 159/187] Fixed build.gradle Fixed a mistake in specifying the path for mod_pocketDim.java. --- build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index abc1771..1dc1451 100644 --- a/build.gradle +++ b/build.gradle @@ -29,7 +29,7 @@ processResources // Replace stuff $version and $mcversion in mcmod.info and mod_pocketDim.java from(sourceSets.main.resources.srcDirs) { include 'mcmod.info' - include 'mod_pocketDim.java' + include 'StevenDimDoors/mod_pocketDim/mod_pocketDim.java' // Replace version and mcversion expand 'version':project.version, 'mcversion':project.minecraft.version @@ -38,7 +38,7 @@ processResources // Copy everything else from(sourceSets.main.resources.srcDirs) { exclude 'mcmod.info' - exclude 'mod_pocketDim.java' + exclude 'StevenDimDoors/mod_pocketDim/mod_pocketDim.java' } } From c4abae8fdd658567729a57ea940955c56abbeaca Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Wed, 9 Jul 2014 15:11:16 -0400 Subject: [PATCH 160/187] Fixed build.gradle (again) Made some more changes to build.gradle in the hopes that the version information will automatically update in mod_pocketDim.java. It has only worked on mcmod.info in previous attempts. --- build.gradle | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/build.gradle b/build.gradle index 1dc1451..1555934 100644 --- a/build.gradle +++ b/build.gradle @@ -18,7 +18,10 @@ group = "com.stevenrs11.dimdoors" // http://maven.apache.org/guides/mini/guide-n 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' @@ -26,11 +29,10 @@ sourceCompatibility = '1.6' processResources { - // Replace stuff $version and $mcversion in mcmod.info and mod_pocketDim.java + // Replace stuff $version and $mcversion in mcmod.info from(sourceSets.main.resources.srcDirs) { include 'mcmod.info' - include 'StevenDimDoors/mod_pocketDim/mod_pocketDim.java' - + // Replace version and mcversion expand 'version':project.version, 'mcversion':project.minecraft.version } @@ -38,7 +40,6 @@ processResources // Copy everything else from(sourceSets.main.resources.srcDirs) { exclude 'mcmod.info' - exclude 'StevenDimDoors/mod_pocketDim/mod_pocketDim.java' } } From 83998969f623063c929ca4e2c5e143bc10e760b5 Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Wed, 9 Jul 2014 15:14:56 -0400 Subject: [PATCH 161/187] Fixed Version in mod_pocketDim Forgot to change the placeholder in mod_pocketDim --- src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java b/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java index 95dce46..a044a06 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java @@ -97,7 +97,7 @@ serverPacketHandlerSpec = @SidedPacketHandler(channels = {PacketConstants.CHANNEL_NAME}, packetHandler = ServerPacketHandler.class)) public class mod_pocketDim { - public static final String version = "$version"; + public static final String version = "@VERSION@"; public static final String modid = "dimdoors"; //TODO need a place to stick all these constants From 8da0339c78a1d7b0198afd59557251a3121fa73f Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Wed, 9 Jul 2014 23:44:49 -0400 Subject: [PATCH 162/187] Improved DDTeleporter Made various changes to clarify code in DDTeleporter. For instance, we had a whole switch block that was used to give the same outcome on every case except the default. I rewrote the code there to remove the block. Also changed DDTeleporter.checkDestination() since it was redoing the destination orientation checks unnecessarily, changing the entity's yaw when it shouldn't have side effects, and some other little things. --- .../mod_pocketDim/core/DDTeleporter.java | 103 +++++++----------- 1 file changed, 37 insertions(+), 66 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/core/DDTeleporter.java b/src/main/java/StevenDimDoors/mod_pocketDim/core/DDTeleporter.java index f8f7bc1..debd31a 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/core/DDTeleporter.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/core/DDTeleporter.java @@ -51,59 +51,49 @@ public class DDTeleporter 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; From c22479c0e885dd1d02d3304289b1d0eb6b449f44 Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Thu, 10 Jul 2014 08:28:42 -0400 Subject: [PATCH 163/187] Tick Handler Changes 1. Renamed CommonTickHandler to ServerTickHandler. Given that it only handles server ticks, this seems like a reasonable name. Also changed its profiler label to the new name. 2. Deleted ClientTickHandler and removed any references to it in mod_pocketDim. It was never used for anything. --- .../mod_pocketDim/mod_pocketDim.java | 6 +- ...ickHandler.java => ServerTickHandler.java} | 6 +- .../ClientTickHandler.java | 65 ------------------- 3 files changed, 5 insertions(+), 72 deletions(-) rename src/main/java/StevenDimDoors/mod_pocketDim/ticking/{CommonTickHandler.java => ServerTickHandler.java} (94%) delete mode 100644 src/main/java/StevenDimDoors/mod_pocketDimClient/ClientTickHandler.java diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java b/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java index a044a06..9468678 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java @@ -52,12 +52,12 @@ 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.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; @@ -69,7 +69,6 @@ import StevenDimDoors.mod_pocketDim.world.LimboProvider; import StevenDimDoors.mod_pocketDim.world.PocketProvider; import StevenDimDoors.mod_pocketDim.world.gateways.GatewayGenerator; import StevenDimDoors.mod_pocketDimClient.ClientPacketHandler; -import StevenDimDoors.mod_pocketDimClient.ClientTickHandler; import cpw.mods.fml.common.Mod; import cpw.mods.fml.common.Mod.EventHandler; import cpw.mods.fml.common.Mod.Instance; @@ -183,8 +182,7 @@ public class mod_pocketDim @EventHandler public void onInitialization(FMLInitializationEvent event) { - CommonTickHandler commonTickHandler = new CommonTickHandler(); - TickRegistry.registerTickHandler(new ClientTickHandler(), Side.CLIENT); + ServerTickHandler commonTickHandler = new ServerTickHandler(); TickRegistry.registerTickHandler(commonTickHandler, Side.SERVER); //MonolithSpawner should be initialized before any provider instances are created diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/ticking/CommonTickHandler.java b/src/main/java/StevenDimDoors/mod_pocketDim/ticking/ServerTickHandler.java similarity index 94% rename from src/main/java/StevenDimDoors/mod_pocketDim/ticking/CommonTickHandler.java rename to src/main/java/StevenDimDoors/mod_pocketDim/ticking/ServerTickHandler.java index 26057b4..2e2ccb1 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/ticking/CommonTickHandler.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/ticking/ServerTickHandler.java @@ -7,15 +7,15 @@ 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(); } 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 From c00c65eeee2493c1fe47bd8cdedbddb7a042526e Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Thu, 10 Jul 2014 15:11:44 -0400 Subject: [PATCH 164/187] Reorganized Tick Receivers 1. Reorganized our code to initialize tick receivers each time the server starts rather than once when the mod is initialized. This is needed because reusing a single instance of each class across different single-player sessions could cause scheduled events for one world to leak into another world. This approach ensures that we discard all pending events. 2. Separated the implementation of Limbo decay from a tick receiver that periodically triggers fast decay. All of the decay code has been kept in LimboDecay, while the ticking is handled by LimboDecayScheduler. This change separates some functionality that should be independent, but also, it's needed so that BlockLimbo can have access to LimboDecay's methods without holding on to a tick receiver instance. 3. Minor change: renamed ChunkLoaderHelper.loadChunkForcedWorlds() to loadForcedChunkWorlds(). --- .../mod_pocketDim/blocks/BlockLimbo.java | 2 +- .../helpers/ChunkLoaderHelper.java | 2 +- .../mod_pocketDim/mod_pocketDim.java | 42 ++++++++++++------- .../ticking/CustomLimboPopulator.java | 2 +- .../ticking/FastRiftRegenerator.java | 3 +- .../ticking/IRegularTickSender.java | 3 +- .../ticking/LimboDecayScheduler.java | 28 +++++++++++++ .../ticking/RiftRegenerator.java | 2 +- .../ticking/ServerTickHandler.java | 9 +++- .../{ticking => world}/LimboDecay.java | 19 ++------- 10 files changed, 75 insertions(+), 37 deletions(-) create mode 100644 src/main/java/StevenDimDoors/mod_pocketDim/ticking/LimboDecayScheduler.java rename src/main/java/StevenDimDoors/mod_pocketDim/{ticking => world}/LimboDecay.java (91%) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockLimbo.java b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockLimbo.java index 8da0dfe..07f1247 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockLimbo.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockLimbo.java @@ -9,7 +9,7 @@ import net.minecraft.util.Icon; import net.minecraft.world.IBlockAccess; import net.minecraft.world.World; import StevenDimDoors.mod_pocketDim.mod_pocketDim; -import StevenDimDoors.mod_pocketDim.ticking.LimboDecay; +import StevenDimDoors.mod_pocketDim.world.LimboDecay; import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/helpers/ChunkLoaderHelper.java b/src/main/java/StevenDimDoors/mod_pocketDim/helpers/ChunkLoaderHelper.java index e866ec4..6483afd 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/helpers/ChunkLoaderHelper.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/helpers/ChunkLoaderHelper.java @@ -83,7 +83,7 @@ public class ChunkLoaderHelper implements LoadingCallback } } - public static void loadChunkForcedWorlds(FMLServerStartingEvent event) + public static void loadForcedChunkWorlds(FMLServerStartingEvent event) { for (NewDimData data : PocketManager.getDimensions()) { diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java b/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java index 9468678..8329d25 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java @@ -54,7 +54,7 @@ import StevenDimDoors.mod_pocketDim.items.ItemWorldThread; import StevenDimDoors.mod_pocketDim.items.itemRiftRemover; import StevenDimDoors.mod_pocketDim.ticking.CustomLimboPopulator; import StevenDimDoors.mod_pocketDim.ticking.FastRiftRegenerator; -import StevenDimDoors.mod_pocketDim.ticking.LimboDecay; +import StevenDimDoors.mod_pocketDim.ticking.LimboDecayScheduler; import StevenDimDoors.mod_pocketDim.ticking.MobMonolith; import StevenDimDoors.mod_pocketDim.ticking.RiftRegenerator; import StevenDimDoors.mod_pocketDim.ticking.ServerTickHandler; @@ -65,6 +65,7 @@ import StevenDimDoors.mod_pocketDim.tileentities.TileEntityTransTrapdoor; import StevenDimDoors.mod_pocketDim.world.BiomeGenLimbo; import StevenDimDoors.mod_pocketDim.world.BiomeGenPocket; import StevenDimDoors.mod_pocketDim.world.DDBiomeGenBase; +import StevenDimDoors.mod_pocketDim.world.LimboDecay; import StevenDimDoors.mod_pocketDim.world.LimboProvider; import StevenDimDoors.mod_pocketDim.world.PocketProvider; import StevenDimDoors.mod_pocketDim.world.gateways.GatewayGenerator; @@ -142,9 +143,13 @@ public class mod_pocketDim public static DDProperties properties; public static DDWorldProperties worldProperties; public static CustomLimboPopulator spawner; //Added this field temporarily. Will be refactored out later. + private static RiftRegenerator riftRegenerator; public static FastRiftRegenerator fastRiftRegenerator; public static GatewayGenerator gatewayGenerator; public static DeathTracker deathTracker; + private static ServerTickHandler serverTickHandler; + private static LimboDecayScheduler limboDecayScheduler; + private static LimboDecay limboDecay; private static EventHookContainer hooks; //TODO this is a temporary workaround for saving data @@ -182,16 +187,14 @@ public class mod_pocketDim @EventHandler public void onInitialization(FMLInitializationEvent event) { - ServerTickHandler commonTickHandler = new ServerTickHandler(); - TickRegistry.registerTickHandler(commonTickHandler, Side.SERVER); - - //MonolithSpawner should be initialized before any provider instances are created - //Register the other regular tick receivers as well - spawner = new CustomLimboPopulator(commonTickHandler, properties); - new RiftRegenerator(commonTickHandler); //No need to store the reference - LimboDecay decay = new LimboDecay(commonTickHandler, properties); - fastRiftRegenerator = new FastRiftRegenerator(commonTickHandler); + // Initialize ServerTickHandler instance + serverTickHandler = new ServerTickHandler(); + TickRegistry.registerTickHandler(serverTickHandler, Side.SERVER); + + // Initialize LimboDecay instance: required for BlockLimbo + limboDecay = new LimboDecay(properties); + // Initialize blocks and items transientDoor = new TransientDoor(properties.TransientDoorID, Material.iron, properties).setHardness(1.0F) .setUnlocalizedName("transientDoor"); goldenDimensionalDoor = new BlockGoldDimDoor(properties.GoldenDimensionalDoorID, Material.iron, properties).setHardness(1.0F) .setUnlocalizedName("dimDoorGold"); @@ -200,7 +203,7 @@ public class mod_pocketDim blockDimWallPerm = (new BlockDimWallPerm(properties.PermaFabricBlockID, 0, Material.iron)).setLightValue(1.0F).setBlockUnbreakable().setResistance(6000000.0F).setUnlocalizedName("blockDimWallPerm"); warpDoor = new WarpDoor(properties.WarpDoorID, Material.wood, properties).setHardness(1.0F) .setUnlocalizedName("dimDoorWarp"); blockRift = (BlockRift) (new BlockRift(properties.RiftBlockID, 0, Material.air, properties).setHardness(1.0F) .setUnlocalizedName("rift")); - blockLimbo = new BlockLimbo(properties.LimboBlockID, 15, Material.iron, properties.LimboDimensionID, decay).setHardness(.2F).setUnlocalizedName("BlockLimbo").setLightValue(.0F); + blockLimbo = new BlockLimbo(properties.LimboBlockID, 15, Material.iron, properties.LimboDimensionID, limboDecay).setHardness(.2F).setUnlocalizedName("BlockLimbo").setLightValue(.0F); unstableDoor = (new UnstableDoor(properties.UnstableDoorID, Material.iron, properties).setHardness(.2F).setUnlocalizedName("chaosDoor").setLightValue(.0F) ); dimensionalDoor = (DimensionalDoor) (new DimensionalDoor(properties.DimensionalDoorID, Material.iron, properties).setHardness(1.0F).setResistance(2000.0F) .setUnlocalizedName("dimDoor")); transTrapdoor = (TransTrapdoor) (new TransTrapdoor(properties.TransTrapdoorID, Material.wood).setHardness(1.0F) .setUnlocalizedName("dimHatch")); @@ -317,7 +320,11 @@ public class mod_pocketDim deathTracker.writeToFile(); deathTracker = null; worldProperties = null; - this.currrentSaveRootDirectory=null; + currrentSaveRootDirectory = null; + + // Unregister all tick receivers from serverTickHandler to avoid leaking + // scheduled tasks between single-player game sessions + serverTickHandler.unregisterReceivers(); } catch (Exception e) { @@ -333,9 +340,16 @@ public class mod_pocketDim // Load the config file that's specific to this world worldProperties = new DDWorldProperties(new File(currrentSaveRootDirectory + "/DimensionalDoors/DimDoorsWorld.cfg")); hooks.setWorldProperties(worldProperties); - + // Initialize a new DeathTracker deathTracker = new DeathTracker(currrentSaveRootDirectory + "/DimensionalDoors/data/deaths.txt"); + + // Register regular tick receivers + // CustomLimboPopulator should be initialized before any provider instances are created + spawner = new CustomLimboPopulator(serverTickHandler, properties); + riftRegenerator = new RiftRegenerator(serverTickHandler); + limboDecayScheduler = new LimboDecayScheduler(serverTickHandler, limboDecay); + fastRiftRegenerator = new FastRiftRegenerator(serverTickHandler); } @EventHandler @@ -353,7 +367,7 @@ public class mod_pocketDim try { - ChunkLoaderHelper.loadChunkForcedWorlds(event); + ChunkLoaderHelper.loadForcedChunkWorlds(event); } catch (Exception e) { diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/ticking/CustomLimboPopulator.java b/src/main/java/StevenDimDoors/mod_pocketDim/ticking/CustomLimboPopulator.java index ddc018c..231eec2 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/ticking/CustomLimboPopulator.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/ticking/CustomLimboPopulator.java @@ -30,7 +30,7 @@ public class CustomLimboPopulator implements IRegularTickReceiver { { this.properties = properties; this.locations = new ConcurrentLinkedQueue(); - sender.registerForTicking(this, MONOLITH_SPAWNING_INTERVAL, false); + sender.registerReceiver(this, MONOLITH_SPAWNING_INTERVAL, false); } @Override diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/ticking/FastRiftRegenerator.java b/src/main/java/StevenDimDoors/mod_pocketDim/ticking/FastRiftRegenerator.java index b0f203f..e680b2a 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/ticking/FastRiftRegenerator.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/ticking/FastRiftRegenerator.java @@ -20,7 +20,7 @@ public class FastRiftRegenerator implements IRegularTickReceiver { public FastRiftRegenerator(IRegularTickSender sender) { - sender.registerForTicking(this, RIFT_REGENERATION_INTERVAL, false); + sender.registerReceiver(this, RIFT_REGENERATION_INTERVAL, false); } @Override @@ -33,6 +33,7 @@ public class FastRiftRegenerator implements IRegularTickReceiver { { if (!locationsToRegen.isEmpty()) { + @SuppressWarnings("cast") List loadedWorlds = (List) Arrays.asList(DimensionManager.getIDs()); for (Point4D point: locationsToRegen) { diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/ticking/IRegularTickSender.java b/src/main/java/StevenDimDoors/mod_pocketDim/ticking/IRegularTickSender.java index 6ed2dca..7b5502c 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/ticking/IRegularTickSender.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/ticking/IRegularTickSender.java @@ -3,6 +3,7 @@ package StevenDimDoors.mod_pocketDim.ticking; public interface IRegularTickSender { - public void registerForTicking(IRegularTickReceiver receiver, int interval, boolean onTickStart); + public void registerReceiver(IRegularTickReceiver receiver, int interval, boolean onTickStart); + public void unregisterReceivers(); } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/ticking/LimboDecayScheduler.java b/src/main/java/StevenDimDoors/mod_pocketDim/ticking/LimboDecayScheduler.java new file mode 100644 index 0000000..73f275c --- /dev/null +++ b/src/main/java/StevenDimDoors/mod_pocketDim/ticking/LimboDecayScheduler.java @@ -0,0 +1,28 @@ +package StevenDimDoors.mod_pocketDim.ticking; + +import StevenDimDoors.mod_pocketDim.world.LimboDecay; + +/** + * Handles scheduling of periodic fast Limbo decay operations. + */ +public class LimboDecayScheduler implements IRegularTickReceiver { + + private static final int LIMBO_DECAY_INTERVAL = 10; //Apply fast decay every 10 ticks + + private LimboDecay decay; + + public LimboDecayScheduler(IRegularTickSender tickSender, LimboDecay decay) + { + this.decay = decay; + tickSender.registerReceiver(this, LIMBO_DECAY_INTERVAL, false); + } + + /** + * Applies fast Limbo decay periodically. + */ + @Override + public void notifyTick() + { + decay.applyRandomFastDecay(); + } +} diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/ticking/RiftRegenerator.java b/src/main/java/StevenDimDoors/mod_pocketDim/ticking/RiftRegenerator.java index 192669c..23b0f9b 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/ticking/RiftRegenerator.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/ticking/RiftRegenerator.java @@ -20,7 +20,7 @@ public class RiftRegenerator implements IRegularTickReceiver { public RiftRegenerator(IRegularTickSender sender) { - sender.registerForTicking(this, RIFT_REGENERATION_INTERVAL, false); + sender.registerReceiver(this, RIFT_REGENERATION_INTERVAL, false); } @Override diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/ticking/ServerTickHandler.java b/src/main/java/StevenDimDoors/mod_pocketDim/ticking/ServerTickHandler.java index 2e2ccb1..58da365 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/ticking/ServerTickHandler.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/ticking/ServerTickHandler.java @@ -14,18 +14,23 @@ public class ServerTickHandler implements ITickHandler, IRegularTickSender private int tickCount = 0; private ArrayList receivers; - public ServerTickHandler() { this.receivers = new ArrayList(); } @Override - public void registerForTicking(IRegularTickReceiver receiver, int interval, boolean onTickStart) + public void registerReceiver(IRegularTickReceiver receiver, int interval, boolean onTickStart) { RegularTickReceiverInfo info = new RegularTickReceiverInfo(receiver, interval, onTickStart); receivers.add(info); } + + @Override + public void unregisterReceivers() + { + receivers.clear(); + } @Override public void tickStart(EnumSet type, Object... tickData) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/ticking/LimboDecay.java b/src/main/java/StevenDimDoors/mod_pocketDim/world/LimboDecay.java similarity index 91% rename from src/main/java/StevenDimDoors/mod_pocketDim/ticking/LimboDecay.java rename to src/main/java/StevenDimDoors/mod_pocketDim/world/LimboDecay.java index e5c9420..13edb19 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/ticking/LimboDecay.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/world/LimboDecay.java @@ -1,4 +1,4 @@ -package StevenDimDoors.mod_pocketDim.ticking; +package StevenDimDoors.mod_pocketDim.world; import java.util.Random; @@ -13,13 +13,12 @@ import StevenDimDoors.mod_pocketDim.config.DDProperties; * Provides methods for applying Limbo decay. Limbo decay refers to the effect that most blocks placed in Limbo * naturally change into stone, then cobble, then gravel, and finally Unraveled Fabric as time passes. */ -public class LimboDecay implements IRegularTickReceiver { +public class LimboDecay { private static final int MAX_DECAY_SPREAD_CHANCE = 100; private static final int DECAY_SPREAD_CHANCE = 50; private static final int CHUNK_SIZE = 16; private static final int SECTION_HEIGHT = 16; - private static final int LIMBO_DECAY_INTERVAL = 10; //Apply spread decay every 10 ticks //Provides a reversed list of the block IDs that blocks cycle through during decay. private final int[] decaySequence; @@ -28,7 +27,7 @@ public class LimboDecay implements IRegularTickReceiver { private final DDProperties properties; private final int[] blocksImmuneToDecay; - public LimboDecay(IRegularTickSender tickSender, DDProperties properties) + public LimboDecay(DDProperties properties) { decaySequence = new int[] { properties.LimboBlockID, @@ -51,16 +50,6 @@ public class LimboDecay implements IRegularTickReceiver { this.properties = properties; this.random = new Random(); - tickSender.registerForTicking(this, LIMBO_DECAY_INTERVAL, false); - } - - /** - * Applies fast Limbo decay periodically. - */ - @Override - public void notifyTick() - { - applyRandomFastDecay(); } /** @@ -88,7 +77,7 @@ public class LimboDecay implements IRegularTickReceiver { * Picks random blocks from each active chunk in Limbo and, if decay is applicable, converts them directly to Unraveled Fabric. * This decay method is designed to stop players from avoiding Limbo decay by building floating structures. */ - private void applyRandomFastDecay() + public void applyRandomFastDecay() { int x, y, z; int sectionY; From 782c6d5e50f18b07abaeb2ae1b8547c923bf5b7c Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Thu, 10 Jul 2014 17:13:10 -0400 Subject: [PATCH 165/187] Minor Changes to NewDimData Made some minor changes to NewDimData. Fixed some comments for the rift search functions that incorrectly indicated the search would not detect rifts adjacent to the center of the search range. That behavior changed some time ago. Also added an unused field called "chunkMapping" for associating chunks with lists of links. It'll be used for implementing queuing of rift regeneration when chunks load. --- .../mod_pocketDim/core/NewDimData.java | 47 +++++++++---------- 1 file changed, 22 insertions(+), 25 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/core/NewDimData.java b/src/main/java/StevenDimDoors/mod_pocketDim/core/NewDimData.java index 326b7d4..5d7e50a 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/core/NewDimData.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/core/NewDimData.java @@ -7,13 +7,14 @@ import java.util.Random; import java.util.Stack; import java.util.TreeMap; -import StevenDimDoors.mod_pocketDim.watcher.ClientLinkData; +import net.minecraft.world.ChunkCoordIntPair; import net.minecraft.world.World; import StevenDimDoors.mod_pocketDim.Point3D; import StevenDimDoors.mod_pocketDim.config.DDProperties; import StevenDimDoors.mod_pocketDim.dungeon.DungeonData; import StevenDimDoors.mod_pocketDim.dungeon.pack.DungeonPack; import StevenDimDoors.mod_pocketDim.util.Point4D; +import StevenDimDoors.mod_pocketDim.watcher.ClientLinkData; import StevenDimDoors.mod_pocketDim.watcher.IUpdateWatcher; public abstract class NewDimData @@ -134,6 +135,9 @@ public abstract class NewDimData protected boolean modified; public IUpdateWatcher linkWatcher; + // Don't write this field to a file - it should be recreated on startup + private Map> chunkMapping; + protected NewDimData(int id, NewDimData parent, boolean isPocket, boolean isDungeon, IUpdateWatcher linkWatcher) { @@ -204,23 +208,20 @@ public abstract class NewDimData public DimLink findNearestRift(World world, int range, int x, int y, int z) { - //TODO: Rewrite this later to use an octtree - - //Sanity check... + // Sanity check... if (world.provider.dimensionId != id) { throw new IllegalArgumentException("Attempted to search for links in a World instance for a different dimension!"); } - //Note: Only detect rifts at a distance > 1, so we ignore the rift - //that called this function and any adjacent rifts. - - DimLink nearest = null; + // Note: Only detect rifts at a distance > 0, so we ignore the rift + // at the center of the search space. DimLink link; - + DimLink nearest = null; + + int i, j, k; int distance; int minDistance = Integer.MAX_VALUE; - int i, j, k; DDProperties properties = DDProperties.instance(); for (i = -range; i <= range; i++) @@ -232,7 +233,7 @@ public abstract class NewDimData distance = getAbsoluteSum(i, j, k); if (distance > 0 && distance < minDistance && world.getBlockId(x + i, y + j, z + k) == properties.RiftBlockID) { - link = getLink(x+i, y+j, z+k); + link = getLink(x + i, y + j, z + k); if (link != null) { nearest = link; @@ -248,24 +249,20 @@ public abstract class NewDimData public ArrayList findRiftsInRange(World world, int range, int x, int y, int z) { - ArrayList links = new ArrayList(); - //TODO: Rewrite this later to use an octtree - - //Sanity check... + // Sanity check... if (world.provider.dimensionId != id) { throw new IllegalArgumentException("Attempted to search for links in a World instance for a different dimension!"); } - - //Note: Only detect rifts at a distance > 1, so we ignore the rift - //that called this function and any adjacent rifts. - - DimLink link; - - int distance; - int i, j, k; - DDProperties properties = DDProperties.instance(); + // Note: Only detect rifts at a distance > 0, so we ignore the rift + // at the center of the search space. + int i, j, k; + int distance; + DimLink link; + DDProperties properties = DDProperties.instance(); + ArrayList links = new ArrayList(); + for (i = -range; i <= range; i++) { for (j = -range; j <= range; j++) @@ -275,7 +272,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); From 85ff28298ebddd8a9e2bc003ba3838f788d0cc40 Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Thu, 10 Jul 2014 18:21:10 -0400 Subject: [PATCH 166/187] Implemented Chunk-Links Mapping Implemented support for tracking the list of links in each chunk in a dimension. This will be used for scheduling rift regeneration when chunks load. --- .../mod_pocketDim/core/DimLink.java | 7 +- .../mod_pocketDim/core/NewDimData.java | 70 ++++++++++++++++--- 2 files changed, 68 insertions(+), 9 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/core/DimLink.java b/src/main/java/StevenDimDoors/mod_pocketDim/core/DimLink.java index 8b0e3d8..409b815 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/core/DimLink.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/core/DimLink.java @@ -3,6 +3,7 @@ package StevenDimDoors.mod_pocketDim.core; import java.util.LinkedList; import java.util.List; +import net.minecraft.world.ChunkCoordIntPair; import StevenDimDoors.mod_pocketDim.util.Point4D; import StevenDimDoors.mod_pocketDim.watcher.ClientLinkData; @@ -15,7 +16,6 @@ public abstract class DimLink protected DimLink(ClientLinkData link, DimLink parent) { - if (parent.link.point.getDimension() != link.point.getDimension()) { // Ban having children in other dimensions to avoid serialization issues with cross-dimensional tails @@ -95,6 +95,11 @@ public abstract class DimLink { return tail.getLinkType(); } + + public ChunkCoordIntPair getChunkCoordinates() + { + return new ChunkCoordIntPair(link.point.getX() >> 4, link.point.getZ() >> 4); + } @Override public String toString() diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/core/NewDimData.java b/src/main/java/StevenDimDoors/mod_pocketDim/core/NewDimData.java index 5d7e50a..5045b9d 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/core/NewDimData.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/core/NewDimData.java @@ -1,6 +1,7 @@ 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; @@ -117,6 +118,8 @@ public abstract class NewDimData } } + private static int EXPECTED_LINKS_PER_CHUNK = 2; + protected static Random random = new Random(); protected int id; @@ -163,6 +166,7 @@ public abstract class NewDimData this.origin = null; this.dungeon = null; this.linkWatcher = linkWatcher; + this.chunkMapping = new HashMap>(); this.modified = true; //Register with parent @@ -203,6 +207,7 @@ public abstract class NewDimData this.linkWatcher = null; this.depth = 0; this.root = root; + this.chunkMapping = null; } @@ -297,13 +302,26 @@ public abstract class NewDimData public DimLink createLink(Point4D source, int linkType, int orientation) { - //Return an existing link if there is one to avoid creating multiple links starting at the same point. + // Return an existing link if there is one to avoid creating multiple links starting at the same point. InnerDimLink link = linkMapping.get(source); if (link == null) { link = new InnerDimLink(source, linkType, orientation); linkMapping.put(source, link); linkList.add(link); + + // If this code is running on the server side, add this link to chunkMapping. + if (linkType != LinkTypes.CLIENT_SIDE) + { + ChunkCoordIntPair chunk = link.getChunkCoordinates(); + List chunkLinks = chunkMapping.get(chunk); + if (chunkLinks == null) + { + chunkLinks = new ArrayList(EXPECTED_LINKS_PER_CHUNK); + chunkMapping.put(chunk, chunkLinks); + } + chunkLinks.add(link); + } } else { @@ -311,7 +329,7 @@ public abstract class NewDimData } modified = true; - //Link created! + // Link created! if (linkType != LinkTypes.CLIENT_SIDE) { linkWatcher.onCreated(link.link); @@ -331,8 +349,8 @@ public abstract class NewDimData private DimLink createChildLink(Point4D source, InnerDimLink parent) { - //To avoid having multiple links at a single point, if we find an existing link then we overwrite - //its destination data instead of creating a new instance. + // To avoid having multiple links at a single point, if we find an existing link then we overwrite + // its destination data instead of creating a new instance. InnerDimLink link = linkMapping.get(source); if (link == null) @@ -341,14 +359,28 @@ public abstract class NewDimData linkMapping.put(source, link); linkList.add(link); - //Link created! + // If this code is running on the server side, add this link to chunkMapping. + // Granted, the client side code should never create child links anyway... + if (link.linkType() != LinkTypes.CLIENT_SIDE) + { + ChunkCoordIntPair chunk = link.getChunkCoordinates(); + List chunkLinks = chunkMapping.get(chunk); + if (chunkLinks == null) + { + chunkLinks = new ArrayList(EXPECTED_LINKS_PER_CHUNK); + chunkMapping.put(chunk, chunkLinks); + } + chunkLinks.add(link); + } + + // Link created! linkWatcher.onCreated(link.link); } else { if (link.overwrite(parent, parent.link.orientation)) { - //Link created! + // Link created! linkWatcher.onCreated(link.link); } } @@ -366,7 +398,19 @@ public abstract class NewDimData if (target != null) { linkList.remove(target); - //Raise deletion event + + // If this code is running on the server side, remove this link to chunkMapping. + if (link.linkType() != LinkTypes.CLIENT_SIDE) + { + ChunkCoordIntPair chunk = target.getChunkCoordinates(); + List chunkLinks = chunkMapping.get(chunk); + if (chunkLinks != null) + { + chunkLinks.remove(target); + } + } + + // Raise deletion event linkWatcher.onDeleted(target.link); target.clear(); modified = true; @@ -388,7 +432,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) @@ -618,6 +662,16 @@ public abstract class NewDimData return linkList.get(0); } + public Iterable getChunkLinks(int chunkX, int chunkZ) + { + List chunkLinks = chunkMapping.get(new ChunkCoordIntPair(chunkX, chunkZ)); + if (chunkLinks != null) + { + return chunkLinks; + } + return new ArrayList(0); + } + public boolean isModified() { return modified; From b197237dfd3fb82a2c57bdbe3b27e3cc7511ee60 Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Thu, 10 Jul 2014 18:25:41 -0400 Subject: [PATCH 167/187] Minor Change Rewrote the NewDimData.deleteLink() version that would accept x, y, and z as parameters. There was some redundant code for getting the parameters from a Point4D instance just to create another one to find the target link. Now we pass the source point in directly. --- .../java/StevenDimDoors/mod_pocketDim/core/NewDimData.java | 3 +-- .../StevenDimDoors/mod_pocketDim/core/PocketManager.java | 5 ++--- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/core/NewDimData.java b/src/main/java/StevenDimDoors/mod_pocketDim/core/NewDimData.java index 5045b9d..9a8a0b5 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/core/NewDimData.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/core/NewDimData.java @@ -418,9 +418,8 @@ public abstract class NewDimData return (target != null); } - public boolean deleteLink(int x, int y, int z) + public boolean deleteLink(Point4D location) { - Point4D location = new Point4D(x, y, z, id); return this.deleteLink(this.getLink(location)); } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/core/PocketManager.java b/src/main/java/StevenDimDoors/mod_pocketDim/core/PocketManager.java index 5a1f1d6..1939e1d 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/core/PocketManager.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/core/PocketManager.java @@ -171,9 +171,8 @@ public class PocketManager public void onDeleted(ClientLinkData link) { Point4D source = link.point; - NewDimData dimension = getDimensionData(source.getDimension()); - dimension.deleteLink(source.getX(), source.getY(), source.getZ()); - } + getDimensionData(source.getDimension()).deleteLink(source); + } } private static class ClientDimWatcher implements IUpdateWatcher From 79bd5102bad6ea88a5b92f5d166b8f4f3a4748a0 Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Thu, 10 Jul 2014 18:29:48 -0400 Subject: [PATCH 168/187] Minor Changes Minor changes to DimLink to simplify DimLink.getDestinationOrientation() and to clarify the output of DimLink.toString() when no destination is available. --- .../StevenDimDoors/mod_pocketDim/core/DimLink.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/core/DimLink.java b/src/main/java/StevenDimDoors/mod_pocketDim/core/DimLink.java index 409b815..abfed4d 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/core/DimLink.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/core/DimLink.java @@ -63,12 +63,12 @@ public abstract class DimLink public int getDestinationOrientation() { - DimLink link = PocketManager.getLink(this.destination().getX(), this.destination().getY(), this.destination().getZ(), this.destination().getDimension()); - if(link !=null) + DimLink destinationLink = PocketManager.getLink(tail.getDestination()); + if (destinationLink != null) { - return link.orientation(); + return destinationLink.orientation(); } - return (this.orientation()+2)%4; + return (link.orientation + 2) % 4; } public boolean hasDestination() @@ -104,6 +104,6 @@ public abstract class DimLink @Override public String toString() { - return link.point + " -> " + (hasDestination() ? destination() : ""); + return link.point + " -> " + (hasDestination() ? destination() : "()"); } } From 1f59dc17d9b8e3f383f006c4a4493c1af0041b1d Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Fri, 11 Jul 2014 01:21:43 -0400 Subject: [PATCH 169/187] Implemented Scheduled Rift Regeneration 1. Implemented scheduled rift regeneration in RiftRegenerator. The previous randomized selection algorithm has been removed completely. All regeneration is scheduled now. We perform numerous checks to make sure that regenerating a rift is safe. 2. Removed FastRiftRegenerator as RiftRegenerator performs roughly the same task but with more flexibility. Updated TileEntityDimDoor to use RiftRegenerator instead for creating rifts when doors are broken. 3. Modified EventHookContainer to receive the chunk loaded event. We iterate over the list of links in a loaded chunk and schedule them for regeneration. 4. Reorganized the code in BlockRift. Divided the list of immune blocks into two lists - one for DD blocks and one for regular MC blocks. RiftRegenerator has to be able to distinguish between the two types. 5. Factored out some duplicate code from ItemRiftSignature and ItemStabilizedRiftSignature. Most of the block immunity checks were used to check if it would be safe to spawn a rift when using one of those items. BlockRift.tryPlacingRift() covers all that logic in a single function and makes the item code a little simpler. --- .../mod_pocketDim/EventHookContainer.java | 27 +++- .../mod_pocketDim/blocks/BlockRift.java | 64 ++++++---- .../items/ItemRiftSignature.java | 23 ++-- .../items/ItemStabilizedRiftSignature.java | 31 ++--- .../mod_pocketDim/mod_pocketDim.java | 13 +- .../ticking/FastRiftRegenerator.java | 54 -------- .../ticking/RiftRegenerator.java | 117 +++++++++++++----- .../mod_pocketDim/ticking/RiftTicket.java | 40 ++++++ .../tileentities/TileEntityDimDoor.java | 43 +++---- 9 files changed, 239 insertions(+), 173 deletions(-) delete mode 100644 src/main/java/StevenDimDoors/mod_pocketDim/ticking/FastRiftRegenerator.java create mode 100644 src/main/java/StevenDimDoors/mod_pocketDim/ticking/RiftTicket.java diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java b/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java index 1855963..9fd2d41 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java @@ -8,6 +8,7 @@ import net.minecraft.item.ItemDoor; import net.minecraft.item.ItemStack; import net.minecraft.world.World; import net.minecraft.world.WorldProvider; +import net.minecraft.world.chunk.Chunk; import net.minecraftforge.client.event.sound.PlayBackgroundMusicEvent; import net.minecraftforge.client.event.sound.SoundLoadEvent; import net.minecraftforge.event.EventPriority; @@ -17,12 +18,16 @@ import net.minecraftforge.event.entity.living.LivingFallEvent; import net.minecraftforge.event.entity.player.PlayerInteractEvent; import net.minecraftforge.event.entity.player.PlayerInteractEvent.Action; import net.minecraftforge.event.terraingen.InitMapGenEvent; +import net.minecraftforge.event.world.ChunkEvent; import net.minecraftforge.event.world.WorldEvent; import StevenDimDoors.mod_pocketDim.config.DDProperties; import StevenDimDoors.mod_pocketDim.config.DDWorldProperties; import StevenDimDoors.mod_pocketDim.core.DDTeleporter; +import StevenDimDoors.mod_pocketDim.core.DimLink; +import StevenDimDoors.mod_pocketDim.core.NewDimData; import StevenDimDoors.mod_pocketDim.core.PocketManager; import StevenDimDoors.mod_pocketDim.items.BaseItemDoor; +import StevenDimDoors.mod_pocketDim.ticking.RiftRegenerator; import StevenDimDoors.mod_pocketDim.util.Point4D; import StevenDimDoors.mod_pocketDim.world.LimboProvider; import StevenDimDoors.mod_pocketDim.world.PocketProvider; @@ -36,18 +41,20 @@ public class EventHookContainer private final DDProperties properties; private DDWorldProperties worldProperties; + private RiftRegenerator regenerator; public EventHookContainer(DDProperties properties) { this.properties = properties; } - public void setWorldProperties(DDWorldProperties worldProperties) + public void setSessionFields(DDWorldProperties worldProperties, RiftRegenerator regenerator) { // SenseiKiwi: - // Why have a setter rather than accessing mod_pocketDim.worldProperties? + // Why have a setter rather than accessing mod_pocketDim directly? // I want to make this dependency explicit in our code. this.worldProperties = worldProperties; + this.regenerator = regenerator; } @ForgeSubscribe(priority = EventPriority.LOW) @@ -217,6 +224,22 @@ public class EventHookContainer } } } + + @ForgeSubscribe + public void onChunkLoad(ChunkEvent.Load event) + { + // Schedule rift regeneration for any links located in this chunk. + // This event runs on both the client and server. Allow server only. + Chunk chunk = event.getChunk(); + if (!chunk.worldObj.isRemote) + { + NewDimData dimension = PocketManager.getDimensionData(chunk.worldObj); + for (DimLink link : dimension.getChunkLinks(chunk.xPosition, chunk.zPosition)) + { + regenerator.scheduleSlowRegeneration(link); + } + } + } public void playMusicForDim(World world) { diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockRift.java b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockRift.java index ada00b6..78f666a 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockRift.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockRift.java @@ -7,6 +7,7 @@ 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; @@ -47,25 +48,27 @@ public class BlockRift extends Block implements ITileEntityProvider public static final int MAX_WORLD_THREAD_DROP_CHANCE = 1000; private final DDProperties properties; - private final ArrayList blocksImmuneToRift; + private final ArrayList blocksImmuneToRift; // List of Vanilla blocks immune to rifts + private final ArrayList modBlocksImmuneToRift; // List of DD blocks immune to rifts public BlockRift(int i, int j, Material par2Material, DDProperties properties) { super(i, par2Material); this.setTickRandomly(true); this.properties = properties; + this.modBlocksImmuneToRift = new ArrayList(); + this.modBlocksImmuneToRift.add(properties.FabricBlockID); + this.modBlocksImmuneToRift.add(properties.PermaFabricBlockID); + this.modBlocksImmuneToRift.add(properties.DimensionalDoorID); + this.modBlocksImmuneToRift.add(properties.WarpDoorID); + this.modBlocksImmuneToRift.add(properties.TransTrapdoorID); + this.modBlocksImmuneToRift.add(properties.UnstableDoorID); + this.modBlocksImmuneToRift.add(properties.RiftBlockID); + this.modBlocksImmuneToRift.add(properties.TransientDoorID); + this.modBlocksImmuneToRift.add(properties.GoldenDimensionalDoorID); + this.modBlocksImmuneToRift.add(properties.GoldenDoorID); + this.blocksImmuneToRift = new ArrayList(); - this.blocksImmuneToRift.add(properties.FabricBlockID); - this.blocksImmuneToRift.add(properties.PermaFabricBlockID); - this.blocksImmuneToRift.add(properties.DimensionalDoorID); - this.blocksImmuneToRift.add(properties.WarpDoorID); - this.blocksImmuneToRift.add(properties.TransTrapdoorID); - this.blocksImmuneToRift.add(properties.UnstableDoorID); - this.blocksImmuneToRift.add(properties.RiftBlockID); - this.blocksImmuneToRift.add(properties.TransientDoorID); - this.blocksImmuneToRift.add(properties.GoldenDimensionalDoorID); - this.blocksImmuneToRift.add(properties.GoldenDoorID); - this.blocksImmuneToRift.add(Block.blockLapis.blockID); this.blocksImmuneToRift.add(Block.blockIron.blockID); this.blocksImmuneToRift.add(Block.blockGold.blockID); @@ -220,7 +223,7 @@ public class BlockRift extends Block implements ITileEntityProvider return targets; } - private void dropWorldThread(int blockID, World world, int x, int y, int z, Random random) + public void dropWorldThread(int blockID, World world, int x, int y, int z, Random random) { if (blockID != 0 && (random.nextInt(MAX_WORLD_THREAD_DROP_CHANCE) < properties.WorldThreadDropChance) && !(Block.blocksList[blockID] instanceof BlockFlowing || @@ -251,16 +254,6 @@ public class BlockRift extends Block implements ITileEntityProvider } } } - - public void regenerateRift(World world, int x, int y, int z, Random random) - { - if (!this.isBlockImmune(world, x, y, z) && world.getChunkProvider().chunkExists(x >> 4, z >> 4)) - { - int blockID = world.getBlockId(x, y, z); - if (world.setBlock(x, y, z, properties.RiftBlockID)) - dropWorldThread(blockID, world, x, y, z, random); - } - } public boolean spreadRift(NewDimData dimension, DimLink parent, World world, Random random) { @@ -412,6 +405,15 @@ public class BlockRift extends Block implements ITileEntityProvider } } } + + public boolean tryPlacingRift(World world, int x, int y, int z) + { + if (world != null && !isBlockImmune(world, x, y, z)) + { + return world.setBlock(x, y, z, mod_pocketDim.blockRift.blockID); + } + return false; + } public boolean isBlockImmune(World world, int x, int y, int z) { @@ -424,7 +426,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; } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemRiftSignature.java b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemRiftSignature.java index 9cc5053..84dbde6 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemRiftSignature.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemRiftSignature.java @@ -71,7 +71,8 @@ public class ItemRiftSignature extends Item int orientation = MathHelper.floor_double(((player.rotationYaw + 180.0F) * 4.0F / 360.0F) - 0.5D) & 3; if (source != null) { - //The link was used before and already has an endpoint stored. Create links connecting the two endpoints. + // The link was used before and already has an endpoint stored. + // Create links connecting the two endpoints. NewDimData sourceDimension = PocketManager.getDimensionData(source.getDimension()); NewDimData destinationDimension = PocketManager.getDimensionData(world); DimLink link = sourceDimension.createLink(source.getX(), source.getY(), source.getZ(), LinkTypes.NORMAL,source.getOrientation()); @@ -79,27 +80,21 @@ public class ItemRiftSignature extends Item destinationDimension.setLinkDestination(link, x, adjustedY, z); sourceDimension.setLinkDestination(reverse, source.getX(), source.getY(), source.getZ()); - //Try placing a rift at the destination point - if (!mod_pocketDim.blockRift.isBlockImmune(world, x, adjustedY, z)) - { - world.setBlock(x, adjustedY, z, mod_pocketDim.blockRift.blockID); - } + // Try placing a rift at the destination point + mod_pocketDim.blockRift.tryPlacingRift(world, x, adjustedY, z); - //Try placing a rift at the source point, but check if its world is loaded first + // Try placing a rift at the source point + // We don't need to check if sourceWorld is null - that's already handled. World sourceWorld = DimensionManager.getWorld(sourceDimension.id()); - if (sourceWorld != null && - !mod_pocketDim.blockRift.isBlockImmune(sourceWorld, source.getX(), source.getY(), source.getZ())) - { - sourceWorld.setBlock(source.getX(), source.getY(), source.getZ(), mod_pocketDim.blockRift.blockID); - } + mod_pocketDim.blockRift.tryPlacingRift(sourceWorld, source.getX(), source.getY(), source.getZ()); if (!player.capabilities.isCreativeMode) { stack.stackSize--; } clearSource(stack); - mod_pocketDim.sendChat(player,("Rift Created")); - world.playSoundAtEntity(player,mod_pocketDim.modid+":riftEnd", 0.6f, 1); + mod_pocketDim.sendChat(player, "Rift Created"); + world.playSoundAtEntity(player, mod_pocketDim.modid + ":riftEnd", 0.6f, 1); } else { diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemStabilizedRiftSignature.java b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemStabilizedRiftSignature.java index b47bff6..c06d598 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemStabilizedRiftSignature.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemStabilizedRiftSignature.java @@ -90,19 +90,13 @@ public class ItemStabilizedRiftSignature extends ItemRiftSignature sourceDimension.setLinkDestination(reverse, source.getX(), source.getY(), source.getZ()); // Try placing a rift at the destination point - if (!mod_pocketDim.blockRift.isBlockImmune(world, x, adjustedY, z)) - { - world.setBlock(x, adjustedY, z, mod_pocketDim.blockRift.blockID); - } + mod_pocketDim.blockRift.tryPlacingRift(world, x, adjustedY, z); } - - // Try placing a rift at the source point, but check if its world is loaded first + + // Try placing a rift at the source point + // We don't need to check if sourceWorld is null - that's already handled. World sourceWorld = DimensionManager.getWorld(sourceDimension.id()); - if (sourceWorld != null && - !mod_pocketDim.blockRift.isBlockImmune(sourceWorld, source.getX(), source.getY(), source.getZ())) - { - sourceWorld.setBlock(source.getX(), source.getY(), source.getZ(), mod_pocketDim.blockRift.blockID); - } + mod_pocketDim.blockRift.tryPlacingRift(sourceWorld, source.getX(), source.getY(), source.getZ()); mod_pocketDim.sendChat(player, "Rift Created"); world.playSoundAtEntity(player, "mods.DimDoors.sfx.riftEnd", 0.6f, 1); @@ -111,8 +105,8 @@ public class ItemStabilizedRiftSignature extends ItemRiftSignature { // The link signature has not been used. Store its current target as the first location. setSource(stack, x, adjustedY, z, orientation, PocketManager.getDimensionData(world)); - mod_pocketDim.sendChat(player,"Location Stored in Stabilized Rift Signature"); - world.playSoundAtEntity(player,"mods.DimDoors.sfx.riftStart", 0.6f, 1); + mod_pocketDim.sendChat(player, "Location Stored in Stabilized Rift Signature"); + world.playSoundAtEntity(player, "mods.DimDoors.sfx.riftStart", 0.6f, 1); } return true; } @@ -148,14 +142,11 @@ public class ItemStabilizedRiftSignature extends ItemRiftSignature // Only the source-to-destination link is needed. link = sourceDimension.createLink(source.getX(), source.getY(), source.getZ(), LinkTypes.NORMAL, source.getOrientation()); destinationDimension.setLinkDestination(link, x, adjustedY, z); - - // Try placing a rift at the source point, but check if its world is loaded first + + // Try placing a rift at the source point + // We don't need to check if sourceWorld is null - that's already handled. World sourceWorld = DimensionManager.getWorld(sourceDimension.id()); - if (sourceWorld != null && - !mod_pocketDim.blockRift.isBlockImmune(sourceWorld, source.getX(), source.getY(), source.getZ())) - { - sourceWorld.setBlock(source.getX(), source.getY(), source.getZ(), mod_pocketDim.blockRift.blockID); - } + mod_pocketDim.blockRift.tryPlacingRift(sourceWorld, source.getX(), source.getY(), source.getZ()); // This call doesn't seem to be working... world.playSoundEffect(x + 0.5, adjustedY + 0.5, z + 0.5, "mods.DimDoors.sfx.riftEnd", 0.6f, 1); diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java b/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java index 8329d25..a8633d9 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java @@ -53,7 +53,6 @@ import StevenDimDoors.mod_pocketDim.items.ItemWarpDoor; import StevenDimDoors.mod_pocketDim.items.ItemWorldThread; import StevenDimDoors.mod_pocketDim.items.itemRiftRemover; import StevenDimDoors.mod_pocketDim.ticking.CustomLimboPopulator; -import StevenDimDoors.mod_pocketDim.ticking.FastRiftRegenerator; import StevenDimDoors.mod_pocketDim.ticking.LimboDecayScheduler; import StevenDimDoors.mod_pocketDim.ticking.MobMonolith; import StevenDimDoors.mod_pocketDim.ticking.RiftRegenerator; @@ -143,8 +142,7 @@ public class mod_pocketDim public static DDProperties properties; public static DDWorldProperties worldProperties; public static CustomLimboPopulator spawner; //Added this field temporarily. Will be refactored out later. - private static RiftRegenerator riftRegenerator; - public static FastRiftRegenerator fastRiftRegenerator; + public static RiftRegenerator riftRegenerator; public static GatewayGenerator gatewayGenerator; public static DeathTracker deathTracker; private static ServerTickHandler serverTickHandler; @@ -325,6 +323,9 @@ public class mod_pocketDim // 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) { @@ -339,7 +340,6 @@ public class mod_pocketDim // Load the config file that's specific to this world worldProperties = new DDWorldProperties(new File(currrentSaveRootDirectory + "/DimensionalDoors/DimDoorsWorld.cfg")); - hooks.setWorldProperties(worldProperties); // Initialize a new DeathTracker deathTracker = new DeathTracker(currrentSaveRootDirectory + "/DimensionalDoors/data/deaths.txt"); @@ -347,9 +347,10 @@ public class mod_pocketDim // Register regular tick receivers // CustomLimboPopulator should be initialized before any provider instances are created spawner = new CustomLimboPopulator(serverTickHandler, properties); - riftRegenerator = new RiftRegenerator(serverTickHandler); + riftRegenerator = new RiftRegenerator(serverTickHandler, blockRift); limboDecayScheduler = new LimboDecayScheduler(serverTickHandler, limboDecay); - fastRiftRegenerator = new FastRiftRegenerator(serverTickHandler); + + hooks.setSessionFields(worldProperties, riftRegenerator); } @EventHandler 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 e680b2a..0000000 --- a/src/main/java/StevenDimDoors/mod_pocketDim/ticking/FastRiftRegenerator.java +++ /dev/null @@ -1,54 +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.registerReceiver(this, RIFT_REGENERATION_INTERVAL, false); - } - - @Override - public void notifyTick() - { - regenerateScheduledRifts(); - } - - public void regenerateScheduledRifts() - { - if (!locationsToRegen.isEmpty()) - { - @SuppressWarnings("cast") - 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/RiftRegenerator.java b/src/main/java/StevenDimDoors/mod_pocketDim/ticking/RiftRegenerator.java index 23b0f9b..0b957da 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/ticking/RiftRegenerator.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/ticking/RiftRegenerator.java @@ -1,56 +1,113 @@ 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) { + this.ticketQueue = new PriorityQueue(); + this.blockRift = blockRift; sender.registerReceiver(this, RIFT_REGENERATION_INTERVAL, false); } @Override public void notifyTick() { - regenerateRiftsInLoadedWorlds(); + processTicketQueue(); + tickCount++; } - private static void regenerateRiftsInLoadedWorlds() + public void scheduleSlowRegeneration(DimLink link) { - // Regenerate rifts that have been replaced (not permanently removed) by players - // Only do this in dimensions that are currently loaded - List loadedWorlds = Arrays.asList(DimensionManager.getIDs()); - for (Integer dimensionID : loadedWorlds) - { - NewDimData dimension = PocketManager.getDimensionData(dimensionID); - if (dimension.linkCount() > 0) - { - World world = DimensionManager.getWorld(dimension.id()); - - if (world != null) - { - for (int count = 0; count < RIFTS_REGENERATED_PER_DIMENSION; count++) - { - DimLink link = dimension.getRandomLink(); - Point4D source = link.source(); - mod_pocketDim.blockRift.regenerateRift(world, source.getX(), source.getY(), source.getZ(), random); - } - } - } - } + scheduleRegeneration(link, MIN_SLOW_DELAY, MAX_SLOW_DELAY); } + + public void scheduleFastRegeneration(DimLink link) + { + scheduleRegeneration(link, MIN_FAST_DELAY, MAX_FAST_DELAY); + } + + private void scheduleRegeneration(DimLink link, int minDelay, int maxDelay) + { + 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. + // FIXME: I can't figure out how to check if a chunk is loaded. + // Will only check if the chunk exists for now. This isn't a big deal. --SenseiKiwi + 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/tileentities/TileEntityDimDoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityDimDoor.java index fe478b6..9703ae1 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityDimDoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityDimDoor.java @@ -1,17 +1,13 @@ package StevenDimDoors.mod_pocketDim.tileentities; import java.util.Random; -import StevenDimDoors.mod_pocketDim.ServerPacketHandler; -import StevenDimDoors.mod_pocketDim.mod_pocketDim; -import StevenDimDoors.mod_pocketDim.blocks.IDimDoor; -import StevenDimDoors.mod_pocketDim.core.NewDimData; -import StevenDimDoors.mod_pocketDim.core.PocketManager; -import net.minecraft.block.Block; + import net.minecraft.nbt.NBTTagCompound; import net.minecraft.network.packet.Packet; -import net.minecraft.network.packet.Packet130UpdateSign; -import net.minecraft.network.packet.Packet250CustomPayload; -import net.minecraft.tileentity.TileEntity; +import StevenDimDoors.mod_pocketDim.ServerPacketHandler; +import StevenDimDoors.mod_pocketDim.mod_pocketDim; +import StevenDimDoors.mod_pocketDim.core.DimLink; +import StevenDimDoors.mod_pocketDim.core.PocketManager; public class TileEntityDimDoor extends DDTileEntityBase { @@ -28,25 +24,26 @@ public class TileEntityDimDoor extends DDTileEntityBase } @Override - public Packet getDescriptionPacket() - { - if(PocketManager.getLink(xCoord, yCoord, zCoord, worldObj)!=null) - { - return ServerPacketHandler.createLinkPacket(PocketManager.getLink(xCoord, yCoord, zCoord, worldObj).link()); - } - return null; - } + public Packet getDescriptionPacket() + { + DimLink link = PocketManager.getLink(xCoord, yCoord, zCoord, worldObj); + if (link != null) + { + return ServerPacketHandler.createLinkPacket(link.link()); + } + return null; + } @Override public void invalidate() { - this.tileEntityInvalid = true; - - if(this.worldObj.getBlockId(xCoord, yCoord, zCoord)==0&&!this.worldObj.isRemote) + super.invalidate(); + if (!worldObj.isRemote && worldObj.getBlockId(xCoord, yCoord, zCoord) == 0) { - if(PocketManager.getLink(xCoord, yCoord, zCoord, worldObj)!=null) + DimLink link = PocketManager.getLink(xCoord, yCoord, zCoord, worldObj); + if (link != null) { - mod_pocketDim.fastRiftRegenerator.registerRiftForRegen(xCoord, yCoord, zCoord, this.worldObj.provider.dimensionId); + mod_pocketDim.riftRegenerator.scheduleFastRegeneration(link); } } } @@ -74,7 +71,7 @@ public class TileEntityDimDoor extends DDTileEntityBase public void writeToNBT(NBTTagCompound nbt) { super.writeToNBT(nbt); - + nbt.setBoolean("openOrClosed", this.openOrClosed); nbt.setBoolean("hasExit", this.hasExit); nbt.setInteger("orientation", this.orientation); From 71e7fdaafce55ba5ff4ac9932d4bd644dc8b95a2 Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Fri, 11 Jul 2014 03:26:40 -0400 Subject: [PATCH 170/187] Implemented Regeneration for BlockRift 1. Made it so that rifts regenerate when rift blocks are replaced by other blocks. 2. Changed the rift regeneration scheduling functions to streamline their use in other classes. Common code that was needed to validate links before calling those functions has been moved into them so that the checks are always performed internally. --- .../mod_pocketDim/blocks/BlockRift.java | 19 +++++++++++++------ .../ticking/RiftRegenerator.java | 16 ++++++++++++---- .../tileentities/TileEntityDimDoor.java | 6 +----- 3 files changed, 26 insertions(+), 15 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockRift.java b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockRift.java index 78f666a..c7f8508 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; @@ -87,9 +86,6 @@ public class BlockRift extends Block implements ITileEntityProvider { return false; } - - @Override - public void onBlockDestroyedByPlayer(World par1World, int par2, int par3, int par4, int par5) {} @Override public boolean isOpaqueCube() @@ -116,10 +112,10 @@ public class BlockRift extends Block implements ITileEntityProvider return true; } - //this doesnt do anything yet. @Override public int getRenderType() { + // This doesn't do anything yet if (mod_pocketDim.isPlayerWearingGoogles) { return 0; @@ -235,7 +231,7 @@ public class BlockRift extends Block implements ITileEntityProvider } } - private void addAdjacentBlocks(int x, int y, int z, int distance, HashMap pointDistances, Queue points) + private static void addAdjacentBlocks(int x, int y, int z, int distance, HashMap pointDistances, Queue points) { Point3D[] neighbors = new Point3D[] { new Point3D(x - 1, y, z), @@ -462,4 +458,15 @@ 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 + mod_pocketDim.riftRegenerator.scheduleSlowRegeneration(x, y, z, world); + } } \ 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 0b957da..66bdd1d 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/ticking/RiftRegenerator.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/ticking/RiftRegenerator.java @@ -48,15 +48,23 @@ public class RiftRegenerator implements IRegularTickReceiver { scheduleRegeneration(link, MIN_SLOW_DELAY, MAX_SLOW_DELAY); } - public void scheduleFastRegeneration(DimLink link) + public void scheduleSlowRegeneration(int x, int y, int z, World world) { - scheduleRegeneration(link, MIN_FAST_DELAY, MAX_FAST_DELAY); + 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) { - int tickDelay = MathHelper.getRandomIntegerInRange(random, minDelay * TICKS_PER_SECOND, maxDelay * TICKS_PER_SECOND); - ticketQueue.add(new RiftTicket(link.source(), tickCount + tickDelay)); + 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() diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityDimDoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityDimDoor.java index 9703ae1..781427b 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityDimDoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityDimDoor.java @@ -40,11 +40,7 @@ public class TileEntityDimDoor extends DDTileEntityBase super.invalidate(); if (!worldObj.isRemote && worldObj.getBlockId(xCoord, yCoord, zCoord) == 0) { - DimLink link = PocketManager.getLink(xCoord, yCoord, zCoord, worldObj); - if (link != null) - { - mod_pocketDim.riftRegenerator.scheduleFastRegeneration(link); - } + mod_pocketDim.riftRegenerator.scheduleFastRegeneration(xCoord, yCoord, zCoord, worldObj); } } From 29c8a09218cdb4281ca29d1342cb928417a118b0 Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Fri, 11 Jul 2014 03:44:26 -0400 Subject: [PATCH 171/187] Improved Door Code 1. Removed code from BaseDimDoor that was already implemented almost identically in BlockDoor. Clarified some uses of setBlock() by changing them to setBlockToAir() instead. 2. Removed TileEntityDimDoor.invalidate() and moved the regeneration scheduling code to BaseDimDoor.breakBlock(). I would prefer to move away from overriding the invalidate() method. This also simplifies the code since we don't need to perform some of the checks we had in breakBlock(). --- .../mod_pocketDim/blocks/BaseDimDoor.java | 27 +++++++++---------- .../tileentities/TileEntityDimDoor.java | 10 ------- 2 files changed, 13 insertions(+), 24 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BaseDimDoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BaseDimDoor.java index d26a0e3..782acfa 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BaseDimDoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BaseDimDoor.java @@ -306,7 +306,7 @@ public abstract class BaseDimDoor extends BlockDoor implements IDimDoor, ITileEn { if (world.getBlockId(x, y - 1, z) != this.blockID) { - world.setBlock(x, y, z, 0); + world.setBlockToAir(x, y, z); } if (neighborID > 0 && neighborID != this.blockID) @@ -318,7 +318,7 @@ public abstract class BaseDimDoor extends BlockDoor implements IDimDoor, ITileEn { if (world.getBlockId(x, y + 1, z) != this.blockID) { - world.setBlock(x, y, z, 0); + world.setBlockToAir(x, y, z); if (!world.isRemote) { this.dropBlockAsItem(world, x, y, z, metadata, 0); @@ -354,18 +354,6 @@ public abstract class BaseDimDoor extends BlockDoor implements IDimDoor, ITileEn return isUpperDoorBlock(metadata) ? 0 : this.getDrops(); } - /** - * Called when the block is attempted to be harvested - */ - @Override - public void onBlockHarvested(World par1World, int par2, int par3, int par4, int par5, EntityPlayer par6EntityPlayer) - { - if (par6EntityPlayer.capabilities.isCreativeMode && (par5 & 8) != 0 && par1World.getBlockId(par2, par3 - 1, par4) == this.blockID) - { - par1World.setBlock(par2, par3 - 1, par4, 0); - } - } - @Override public TileEntity createNewTileEntity(World world) { @@ -445,4 +433,15 @@ 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 + mod_pocketDim.riftRegenerator.scheduleFastRegeneration(x, y, z, world); + } } \ No newline at end of file diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityDimDoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityDimDoor.java index 781427b..881577c 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityDimDoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityDimDoor.java @@ -34,16 +34,6 @@ public class TileEntityDimDoor extends DDTileEntityBase return null; } - @Override - public void invalidate() - { - super.invalidate(); - if (!worldObj.isRemote && worldObj.getBlockId(xCoord, yCoord, zCoord) == 0) - { - mod_pocketDim.riftRegenerator.scheduleFastRegeneration(xCoord, yCoord, zCoord, worldObj); - } - } - @Override public void readFromNBT(NBTTagCompound nbt) { From 1bf1f4f78c7db0e410dec147bedb0b50780af138 Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Fri, 11 Jul 2014 04:10:12 -0400 Subject: [PATCH 172/187] Improved Regeneration Code 1. Added code so that Transdimensional Trapdoors detect that they have been broken and schedule rift regeneration at their location. This had previously been neglected. Trapdoors deserve a little more attention. 2. Tweaked the breakBlock() code for BlockRift and BaseDimDoor so that rift regeneration is only scheduled if the underlying block was removed. We don't want that to happen if the only change was for metadata. --- .../mod_pocketDim/blocks/BaseDimDoor.java | 7 +++++-- .../mod_pocketDim/blocks/BlockRift.java | 7 +++++-- .../mod_pocketDim/blocks/TransTrapdoor.java | 14 ++++++++++++++ .../tileentities/TileEntityTransTrapdoor.java | 3 +-- 4 files changed, 25 insertions(+), 6 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BaseDimDoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BaseDimDoor.java index 782acfa..de8db5b 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BaseDimDoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BaseDimDoor.java @@ -441,7 +441,10 @@ public abstract class BaseDimDoor extends BlockDoor implements IDimDoor, ITileEn // 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 - mod_pocketDim.riftRegenerator.scheduleFastRegeneration(x, y, z, world); + // 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/BlockRift.java b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockRift.java index c7f8508..6400978 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockRift.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockRift.java @@ -466,7 +466,10 @@ public class BlockRift extends Block implements ITileEntityProvider // 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 - mod_pocketDim.riftRegenerator.scheduleSlowRegeneration(x, y, z, world); + // Schedule rift regeneration for this block if it was changed + if (world.getBlockId(x, y, z) != oldBlockID) + { + mod_pocketDim.riftRegenerator.scheduleSlowRegeneration(x, y, z, world); + } } } \ No newline at end of file diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/TransTrapdoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/TransTrapdoor.java index 4a1df0d..aefb277 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/TransTrapdoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/TransTrapdoor.java @@ -140,4 +140,18 @@ public class TransTrapdoor extends BlockTrapDoor implements IDimDoor, ITileEntit world.setBlockTileEntity(x, y, z, te); return te; } + + @Override + public void breakBlock(World world, int x, int y, int z, int oldBlockID, int oldMeta) + { + // This function runs on the server side after a block is replaced + // We MUST call super.breakBlock() since it involves removing tile entities + super.breakBlock(world, x, y, z, oldBlockID, oldMeta); + + // Schedule rift regeneration for this block if it was replaced + if (world.getBlockId(x, y, z) != oldBlockID) + { + mod_pocketDim.riftRegenerator.scheduleFastRegeneration(x, y, z, world); + } + } } \ No newline at end of file diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityTransTrapdoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityTransTrapdoor.java index d26b46f..25cc3b4 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityTransTrapdoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityTransTrapdoor.java @@ -1,9 +1,8 @@ package StevenDimDoors.mod_pocketDim.tileentities; import java.util.Random; + import StevenDimDoors.mod_pocketDim.mod_pocketDim; -import net.minecraft.nbt.NBTTagCompound; -import net.minecraft.tileentity.TileEntity; public class TileEntityTransTrapdoor extends DDTileEntityBase { From 107aa4b7f24c90b24ffca64a93b3f118b2253543 Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Fri, 11 Jul 2014 04:33:19 -0400 Subject: [PATCH 173/187] Cleaned up Transdimensional Trapdoor Code Removed unnecessary code for the Transdimensional Trapdoor. Most of it was code dedicated to updating TileEntityTransTrapdoor.hasRift. That flag was never used for anything. --- .../mod_pocketDim/blocks/TransTrapdoor.java | 20 +--------------- .../tileentities/TileEntityTransTrapdoor.java | 2 -- .../RenderTransTrapdoor.java | 24 ++++--------------- 3 files changed, 6 insertions(+), 40 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/TransTrapdoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/TransTrapdoor.java index aefb277..d2eda14 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/TransTrapdoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/TransTrapdoor.java @@ -63,14 +63,6 @@ public class TransTrapdoor extends BlockTrapDoor implements IDimDoor, ITileEntit { this.placeLink(world, x, y, z); world.setBlockTileEntity(x, y, z, this.createNewTileEntity(world)); - updateAttachedTile(world, x, y, z); - } - - @Override - public void updateTick(World world, int x, int y, int z, Random random) - { - TileEntityTransTrapdoor tile = (TileEntityTransTrapdoor) world.getBlockTileEntity(x, y, z); - tile.hasRift = PocketManager.getLink(x, y, z, world) != null; } @Override @@ -79,16 +71,6 @@ public class TransTrapdoor extends BlockTrapDoor implements IDimDoor, ITileEntit return new TileEntityTransTrapdoor(); } - public static void updateAttachedTile(World world, int x, int y, int z) - { - TileEntity tile = world.getBlockTileEntity(x, y, z); - if (tile instanceof TileEntityTransTrapdoor) - { - TileEntityTransTrapdoor trapdoorTile = (TileEntityTransTrapdoor) tile; - trapdoorTile.hasRift = (PocketManager.getLink(x, y, z, world) != null); - } - } - @Override public void placeLink(World world, int x, int y, int z) { @@ -98,7 +80,7 @@ public class TransTrapdoor extends BlockTrapDoor implements IDimDoor, ITileEntit DimLink link = dimension.getLink(x, y, z); if (link == null && dimension.isPocketDimension()) { - dimension.createLink(x, y, z, LinkTypes.UNSAFE_EXIT,0); + dimension.createLink(x, y, z, LinkTypes.UNSAFE_EXIT, 0); } } } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityTransTrapdoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityTransTrapdoor.java index 25cc3b4..3df7f6c 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityTransTrapdoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityTransTrapdoor.java @@ -6,8 +6,6 @@ import StevenDimDoors.mod_pocketDim.mod_pocketDim; public class TileEntityTransTrapdoor extends DDTileEntityBase { - public boolean hasRift; - @Override public boolean canUpdate() { diff --git a/src/main/java/StevenDimDoors/mod_pocketDimClient/RenderTransTrapdoor.java b/src/main/java/StevenDimDoors/mod_pocketDimClient/RenderTransTrapdoor.java index 0f3ea97..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; @@ -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) { From 2c7435585d08147a806ca5c3307eaf8b0e775c17 Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Fri, 11 Jul 2014 15:44:01 -0400 Subject: [PATCH 174/187] Minor Changes Removed a pointless check in yCoordHelper and corrected some comments in RiftRegenerator. It turns out that ChunkProviderServer.chunkExists() returns whether a chunk is loaded, not whether it has already been created. --- .../StevenDimDoors/mod_pocketDim/helpers/yCoordHelper.java | 5 +---- .../mod_pocketDim/ticking/RiftRegenerator.java | 4 ++-- 2 files changed, 3 insertions(+), 6 deletions(-) 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/ticking/RiftRegenerator.java b/src/main/java/StevenDimDoors/mod_pocketDim/ticking/RiftRegenerator.java index 66bdd1d..f23c38c 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/ticking/RiftRegenerator.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/ticking/RiftRegenerator.java @@ -95,8 +95,8 @@ public class RiftRegenerator implements IRegularTickReceiver { return; // The chunk at the given location must be loaded. - // FIXME: I can't figure out how to check if a chunk is loaded. - // Will only check if the chunk exists for now. This isn't a big deal. --SenseiKiwi + // 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; From fb1713ae0e665acc2a48611db1a99548949c6f26 Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Sat, 12 Jul 2014 03:36:56 -0400 Subject: [PATCH 175/187] Improvements to TileEntityRift Made some improvements to TileEntityRift. The main reason for these changes was to remove the field nearestRift - we should not hold on to references to links. Now we simply track the location of the nearest rift. I also confirmed that closeRift() and updateNearestRift() must be allowed to run on both the client and the server. If the client doesn't run those functions, then adjacent rifts don't connect as expected and the rift removal animation doesn't work. --- .../tileentities/TileEntityRift.java | 77 ++++++++++--------- 1 file changed, 39 insertions(+), 38 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityRift.java b/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityRift.java index 13f9f96..62bb62b 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityRift.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityRift.java @@ -1,6 +1,5 @@ package StevenDimDoors.mod_pocketDim.tileentities; -import java.util.ArrayList; import java.util.List; import java.util.Random; @@ -42,8 +41,7 @@ public class TileEntityRift extends DDTileEntityBase public int yOffset = 0; public int zOffset = 0; public boolean shouldClose = false; - - public DimLink nearestRiftData; + public Point4D nearestRiftLocation = null; public int spawnedEndermenID = 0; public TileEntityRift() @@ -64,20 +62,20 @@ public class TileEntityRift extends DDTileEntityBase } else { - this.invalidate(); + invalidate(); } return; } if (worldObj.getBlockId(xCoord, yCoord, zCoord) != mod_pocketDim.blockRift.blockID) { - this.invalidate(); + invalidate(); return; } // Check if this rift should render white closing particles and // spread the closing effect to other rifts nearby. - if (this.shouldClose) + if (shouldClose) { closeRift(); return; @@ -85,13 +83,13 @@ public class TileEntityRift extends DDTileEntityBase if (updateTimer >= UPDATE_PERIOD) { - this.spawnEndermen(mod_pocketDim.properties); + spawnEndermen(mod_pocketDim.properties); updateTimer = 0; } else if (updateTimer == UPDATE_PERIOD / 2) { - this.calculateParticleOffsets(); - this.spread(mod_pocketDim.properties); + updateNearestRift(); + spread(mod_pocketDim.properties); } updateTimer++; } @@ -136,57 +134,60 @@ public class TileEntityRift extends DDTileEntityBase } } } - - 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 (closeTimer == CLOSING_PERIOD / 2) { - ArrayList riftLinks = dimension.findRiftsInRange(worldObj, 6, xCoord, yCoord, zCoord); - if (riftLinks.size() > 0) + for (DimLink riftLink : dimension.findRiftsInRange(worldObj, 6, xCoord, yCoord, zCoord)) { - for (DimLink riftLink : riftLinks) + Point4D location = riftLink.source(); + TileEntityRift rift = (TileEntityRift) worldObj.getBlockTileEntity(location.getX(), location.getY(), location.getZ()); + if (rift != null && !rift.shouldClose) { - Point4D location = riftLink.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 (closeTimer >= CLOSING_PERIOD) { - 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 + 0.5, yCoord + 0.5, zCoord + 0.5, "mods.DimDoors.sfx.riftClose", 0.7f, 1, false); } closeTimer++; } - - private void calculateParticleOffsets() + + public boolean updateNearestRift() { - if (updateNearestRift()) + Point4D previousNearest = nearestRiftLocation; + DimLink nearestRiftLink = PocketManager.getDimensionData(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))) { - Point4D location = nearestRiftData.source(); - this.xOffset = this.xCoord - location.getX(); - this.yOffset = this.yCoord - location.getY(); - this.zOffset = this.zCoord - location.getZ(); + updateParticleOffsets(); + } + return (nearestRiftLocation != null); + } + + private void updateParticleOffsets() + { + if (nearestRiftLocation != null) + { + this.xOffset = this.xCoord - nearestRiftLocation.getX(); + this.yOffset = this.yCoord - nearestRiftLocation.getY(); + this.zOffset = this.zCoord - nearestRiftLocation.getZ(); } else { From b20a0a74d2e2c14cdba06885ed73df06cb7b6c9e Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Sun, 13 Jul 2014 07:17:30 -0400 Subject: [PATCH 176/187] Minor Change Autocorrected indentation in PocketManager. I'll be working on changing PocketManager to prevent the risk of creating data for a non-existent dimension through a bad call to getDimensionData(). --- .../mod_pocketDim/core/PocketManager.java | 128 +++++++++--------- 1 file changed, 64 insertions(+), 64 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/core/PocketManager.java b/src/main/java/StevenDimDoors/mod_pocketDim/core/PocketManager.java index 1939e1d..a509c38 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/core/PocketManager.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/core/PocketManager.java @@ -49,17 +49,17 @@ public class PocketManager // that any link destinations must be real dimensions controlled by PocketManager. public InnerDimData(int id, InnerDimData parent, boolean isPocket, boolean isDungeon, - IUpdateWatcher linkWatcher) + IUpdateWatcher linkWatcher) { super(id, parent, isPocket, isDungeon, linkWatcher); } - + public InnerDimData(int id, InnerDimData root) { // This constructor is meant for client-side code only super(id, root); } - + public void clear() { // If this dimension has a parent, remove it from its parent's list of children @@ -103,7 +103,7 @@ public class PocketManager ArrayList Links = new ArrayList(); ArrayList Tails = new ArrayList(); PackedDungeonData packedDungeon=null; - + if(this.dungeon!=null) { packedDungeon= new PackedDungeonData(dungeon.weight(), dungeon.isOpen(), dungeon.isInternal(), @@ -123,22 +123,22 @@ public class PocketManager { 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); } - - + + } int parentID=this.id; Point3D originPoint=new Point3D(0,0,0); @@ -151,30 +151,30 @@ public class PocketManager originPoint=this.origin.toPoint3D(); } return new PackedDimData(this.id, depth, this.packDepth, parentID, this.root().id(), orientation, - isDungeon, isFilled,packedDungeon, originPoint, ChildIDs, Links, Tails); + 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; - getDimensionData(source.getDimension()).deleteLink(source); - } - } - + 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; + getDimensionData(source.getDimension()).deleteLink(source); + } + } + private static class ClientDimWatcher implements IUpdateWatcher { @Override @@ -196,14 +196,14 @@ public class PocketManager // 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) { return registerClientDimension(dimensionID, rootID); } } - + private static int OVERWORLD_DIMENSION_ID = 0; private static volatile boolean isLoading = false; @@ -242,11 +242,11 @@ public class PocketManager return; } isLoading = true; - + dimensionData = new HashMap(); rootDimensions = new ArrayList(); dimensionIDBlackList = new ArrayList(); - + if(FMLCommonHandler.instance().getEffectiveSide().isClient()) { //Shouldnt try to load everything if we are a client @@ -258,19 +258,19 @@ public class PocketManager //Register Limbo DDProperties properties = DDProperties.instance(); registerDimension(properties.LimboDimensionID, null, false, false); - + loadInternal(); - + //Register pocket dimensions registerPockets(properties); - + isLoaded = true; isLoading = false; } - + public static boolean registerPackedDimData(PackedDimData packedData) { - + InnerDimData dimData; //register roots if(packedData.ID==packedData.ParentID) @@ -291,7 +291,7 @@ public class PocketManager 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.dungeon=DDSaveHandler.unpackDungeonData(packedData.DungeonData); @@ -303,7 +303,7 @@ 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. @@ -327,7 +327,7 @@ public class PocketManager } return false; } - + private static void deleteDimensionFiles(InnerDimData dimension) { // We assume that the caller checks if the dimension is loaded, for the @@ -339,7 +339,7 @@ public class PocketManager 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 @@ -357,7 +357,7 @@ public class PocketManager throw new IllegalArgumentException("The specified dimension is not listed with PocketManager."); } } - + private static void registerPockets(DDProperties properties) { for (NewDimData dimension : dimensionData.values()) @@ -427,7 +427,7 @@ public class PocketManager { System.out.println("Importing old DD save data..."); OldSaveImporter.importOldSave(oldSaveData); - + oldSaveData.renameTo(new File(oldSaveData.getAbsolutePath()+"_IMPORTED")); System.out.println("Import Succesful!"); @@ -440,7 +440,7 @@ public class PocketManager } return; } - + // Load save data System.out.println("Loading Dimensional Doors save data..."); if (DDSaveHandler.loadAll()) @@ -449,7 +449,7 @@ public class PocketManager } } } - + public static void save(boolean checkModified) { if (!isLoaded) @@ -462,7 +462,7 @@ public class PocketManager return; } isSaving = true; - + try { DDSaveHandler.saveAll(dimensionData.values(), dimensionIDBlackList, checkModified); @@ -479,14 +479,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) { @@ -512,7 +512,7 @@ public class PocketManager { 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); @@ -543,10 +543,10 @@ public class PocketManager rootDimensions.add(dimension); } getDimwatcher().onCreated(new ClientDimData(dimension)); - + return dimension; } - + @SideOnly(Side.CLIENT) private static NewDimData registerClientDimension(int dimensionID, int rootID) { @@ -556,7 +556,7 @@ public class PocketManager // SenseiKiwi: I'm a little worried about how getDimensionData will raise // an event when it creates any root dimensions... Needs checking later. - + InnerDimData root = (InnerDimData) getDimensionData(rootID); InnerDimData dimension; @@ -577,12 +577,12 @@ public class PocketManager { //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; + return dimension; } public static NewDimData getDimensionData(World world) @@ -597,7 +597,7 @@ public class PocketManager //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) { @@ -630,14 +630,14 @@ public class PocketManager { throw new IllegalStateException("Pocket dimensions have already been unloaded!"); } - + unregisterPockets(); dimensionData = 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); @@ -647,7 +647,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); @@ -657,7 +657,7 @@ public class PocketManager } return null; } - + public static boolean isBlackListed(int dimensionID) { return PocketManager.dimensionIDBlackList.contains(dimensionID); @@ -670,12 +670,12 @@ public class PocketManager { return getDimwatcher().unregisterReceiver(watcher); } - + public static void registerLinkWatcher(IUpdateWatcher watcher) { linkWatcher.registerReceiver(watcher); } - + public static boolean unregisterLinkWatcher(IUpdateWatcher watcher) { return linkWatcher.unregisterReceiver(watcher); @@ -685,18 +685,18 @@ 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 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 @@ -720,7 +720,7 @@ public class PocketManager // Load compacted client-side dimension data load(); Compactor.readDimensions(input, new DimRegistrationCallback()); - + isLoaded = true; isLoading = false; isConnected = true; From 8544aa17eea214363bb441f86215a2080ab05c11 Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Sun, 13 Jul 2014 14:22:23 -0400 Subject: [PATCH 177/187] Fixed Crash on World Creation Fixed an issue. DD would crash when MC created a completely new world because onChunkLoad() would be called before onWorldLoad(). That's not the usual order. PocketManager would be unloaded at that point and would return a null dimension. --- .../StevenDimDoors/mod_pocketDim/EventHookContainer.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java b/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java index 9fd2d41..e40d7c2 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java @@ -230,8 +230,11 @@ public class EventHookContainer { // 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) + if (!chunk.worldObj.isRemote && PocketManager.isLoaded()) { NewDimData dimension = PocketManager.getDimensionData(chunk.worldObj); for (DimLink link : dimension.getChunkLinks(chunk.xPosition, chunk.zPosition)) From e7934933313e576228cac652ab06730d7f12e9c9 Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Sun, 13 Jul 2014 20:03:00 -0400 Subject: [PATCH 178/187] Fixed Eager Dimension Data Creation 1. Fixed a design flaw in PocketManager. We originally assumed that all requests to PocketManager.getDimensionData() had to be legitimate requests for dimensions that existed. That was true in most cases, but for things like processing user commands, it was dangerously optimistic. It was possible that a flaw in DD's usage of that function could be exploited by a player to trick the mod into pre-registering dimension data for a non-existent dimension. That would declare the dimension as a root. DD would crash later if Forge ever allocated that ID for a pocket dimension. The new implementation is almost the same as the old one, but allows us to differentiate between cases when we can eagerly create dimension data, and cases in which the absence of a dimension should cause a crash to alert us of a design flaw. 2. Remove the pocket regeneration code from PocketBuilder. We simply don't support pocket regeneration and it's unlikely it'll ever be implemented because it's a difficult issue. Wiping out pockets completely is easier. We can always recover the code from this commit if it's needed later. 3. Minor changes: removed some debug prints from PocketManager and changed some static accesses in PocketBuilder. --- .../mod_pocketDim/ConnectionHandler.java | 9 +- .../mod_pocketDim/EventHookContainer.java | 2 +- .../blocks/BlockGoldDimDoor.java | 2 +- .../mod_pocketDim/blocks/DimensionalDoor.java | 2 +- .../mod_pocketDim/blocks/TransTrapdoor.java | 2 +- .../mod_pocketDim/blocks/TransientDoor.java | 2 +- .../mod_pocketDim/blocks/UnstableDoor.java | 2 +- .../mod_pocketDim/blocks/WarpDoor.java | 2 +- .../commands/CommandCreateDungeonRift.java | 2 +- .../commands/CommandCreateRandomRift.java | 4 +- .../commands/CommandDeleteRifts.java | 2 +- .../commands/CommandTeleportPlayer.java | 3 +- .../mod_pocketDim/core/DDTeleporter.java | 17 ++-- .../mod_pocketDim/core/PocketManager.java | 72 ++++++++-------- .../dungeon/DungeonSchematic.java | 2 +- .../mod_pocketDim/helpers/DungeonHelper.java | 2 +- .../items/ItemRiftSignature.java | 4 +- .../items/ItemStabilizedRiftSignature.java | 6 +- .../mod_pocketDim/items/itemRiftRemover.java | 4 +- .../mod_pocketDim/saving/DDSaveHandler.java | 6 +- .../tileentities/TileEntityDimDoorGold.java | 2 +- .../tileentities/TileEntityRift.java | 6 +- .../mod_pocketDim/world/PocketBuilder.java | 85 +------------------ .../mod_pocketDim/world/PocketGenerator.java | 2 +- .../mod_pocketDim/world/PocketProvider.java | 8 +- .../fortresses/ComponentNetherGateway.java | 2 +- .../world/gateways/BaseSchematicGateway.java | 2 +- .../world/gateways/GatewayGenerator.java | 2 +- .../world/gateways/GatewayLimbo.java | 2 +- .../mod_pocketDimClient/ClosingRiftFX.java | 2 +- .../mod_pocketDimClient/GoggleRiftFX.java | 2 +- .../mod_pocketDimClient/RiftFX.java | 2 +- 32 files changed, 85 insertions(+), 179 deletions(-) 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/EventHookContainer.java b/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java index e40d7c2..1f91b95 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/EventHookContainer.java @@ -236,7 +236,7 @@ public class EventHookContainer Chunk chunk = event.getChunk(); if (!chunk.worldObj.isRemote && PocketManager.isLoaded()) { - NewDimData dimension = PocketManager.getDimensionData(chunk.worldObj); + NewDimData dimension = PocketManager.createDimensionData(chunk.worldObj); for (DimLink link : dimension.getChunkLinks(chunk.xPosition, chunk.zPosition)) { regenerator.scheduleSlowRegeneration(link); diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockGoldDimDoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockGoldDimDoor.java index 3feb075..d9ca897 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockGoldDimDoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockGoldDimDoor.java @@ -25,7 +25,7 @@ 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) { diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/DimensionalDoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/DimensionalDoor.java index 3537a77..fc4f709 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/DimensionalDoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/DimensionalDoor.java @@ -22,7 +22,7 @@ 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) { diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/TransTrapdoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/TransTrapdoor.java index d2eda14..52be329 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/TransTrapdoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/TransTrapdoor.java @@ -76,7 +76,7 @@ public class TransTrapdoor extends BlockTrapDoor implements IDimDoor, ITileEntit { 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()) { diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/TransientDoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/TransientDoor.java index 0eac631..9f56a63 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/TransientDoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/TransientDoor.java @@ -64,7 +64,7 @@ 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()) { diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/UnstableDoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/UnstableDoor.java index 6f14c66..3a82941 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/UnstableDoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/UnstableDoor.java @@ -21,7 +21,7 @@ public class UnstableDoor extends BaseDimDoor { if (!world.isRemote && world.getBlockId(x, y - 1, z) == this.blockID) { - NewDimData dimension = PocketManager.getDimensionData(world); + NewDimData dimension = PocketManager.createDimensionData(world); dimension.createLink(x, y, z, LinkTypes.RANDOM,world.getBlockMetadata(x, y - 1, z)); } } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/WarpDoor.java b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/WarpDoor.java index f860f6e..c9ed904 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/WarpDoor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/WarpDoor.java @@ -22,7 +22,7 @@ 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()) { diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandCreateDungeonRift.java b/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandCreateDungeonRift.java index 686b5d3..588457e 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandCreateDungeonRift.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandCreateDungeonRift.java @@ -61,7 +61,7 @@ public class CommandCreateDungeonRift extends DDCommandBase // Check if we found any matches if (result != null) { - dimension = PocketManager.getDimensionData(sender.worldObj); + dimension = PocketManager.createDimensionData(sender.worldObj); link = dimension.createLink(x, y + 1, z, LinkTypes.DUNGEON, orientation); if (PocketBuilder.generateSelectedDungeonPocket(link, mod_pocketDim.properties, result)) { diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandCreateRandomRift.java b/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandCreateRandomRift.java index 646fda3..201279b 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandCreateRandomRift.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandCreateRandomRift.java @@ -53,7 +53,7 @@ public class CommandCreateRandomRift extends DDCommandBase if (command.length == 0) { - dimension = PocketManager.getDimensionData(sender.worldObj); + dimension = PocketManager.createDimensionData(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."); @@ -69,7 +69,7 @@ public class CommandCreateRandomRift extends DDCommandBase // Check if we found any matches if (result != null) { - dimension = PocketManager.getDimensionData(sender.worldObj); + dimension = PocketManager.createDimensionData(sender.worldObj); link = dimension.createLink(x, y + 1, z, LinkTypes.DUNGEON, orientation); if (PocketBuilder.generateSelectedDungeonPocket(link, mod_pocketDim.properties, result)) { diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandDeleteRifts.java b/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandDeleteRifts.java index cc1a1a1..9a50857 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandDeleteRifts.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandDeleteRifts.java @@ -63,7 +63,7 @@ public class CommandDeleteRifts extends DDCommandBase int y; int z; Point4D location; - NewDimData dimension = PocketManager.getDimensionData(targetDimension); + NewDimData dimension = PocketManager.createDimensionData(world); ArrayList links = dimension.getAllLinks(); for (DimLink link : links) { diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandTeleportPlayer.java b/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandTeleportPlayer.java index b02222f..b001c7a 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandTeleportPlayer.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/commands/CommandTeleportPlayer.java @@ -80,7 +80,6 @@ public class CommandTeleportPlayer extends DDCommandBase else { dimensionID = targetPlayer.worldObj.provider.dimensionId; - // SenseiKiwi: Will not be used, but I prefer not to leave 'world' as null world = targetPlayer.worldObj; } @@ -95,7 +94,7 @@ public class CommandTeleportPlayer extends DDCommandBase if (command.length == 2) { // Check if the destination is a pocket dimension - dimension = PocketManager.getDimensionData(dimensionID); + dimension = PocketManager.createDimensionData(world); if (dimension.isPocketDimension()) { // The destination is a pocket dimension. diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/core/DDTeleporter.java b/src/main/java/StevenDimDoors/mod_pocketDim/core/DDTeleporter.java index debd31a..0c29491 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/core/DDTeleporter.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/core/DDTeleporter.java @@ -227,7 +227,7 @@ public class DDTeleporter && blockID != properties.GoldenDimensionalDoorID) { //Return the pocket's orientation instead - return PocketManager.getDimensionData(door.getDimension()).orientation(); + return PocketManager.createDimensionData(world).orientation(); } //Return the orientation portion of its metadata @@ -294,7 +294,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(); @@ -552,7 +552,7 @@ 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.source().getDimension()); if (current.isPocketDimension()) { Point4D source = link.source(); @@ -606,9 +606,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.source().getDimension()); return generateSafeExit(current.root(), link, properties); } @@ -619,7 +620,7 @@ 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.source().getDimension()); ArrayList roots = PocketManager.getRootDimensions(); int shiftChance = START_ROOT_SHIFT_CHANCE + ROOT_SHIFT_CHANCE_PER_LEVEL * (current.packDepth() - 1); @@ -627,11 +628,11 @@ public class DDTeleporter { if (current.root().id() != OVERWORLD_DIMENSION_ID && random.nextInt(MAX_OVERWORLD_EXIT_CHANCE) < OVERWORLD_EXIT_CHANCE) { - return generateSafeExit(PocketManager.getDimensionData(OVERWORLD_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.getDimensionData(NETHER_DIMENSION_ID), link, properties); + return generateSafeExit(PocketManager.createDimensionDataDangerously(NETHER_DIMENSION_ID), link, properties); } for (int attempts = 0; attempts < 10; attempts++) { @@ -735,7 +736,7 @@ 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); + DimLink reverse = destinationDim.createLink(x, y + 2, z, LinkTypes.REVERSE, orientation); sourceDim.setLinkDestination(reverse, source.getX(), source.getY(), source.getZ()); // Set up the warp door at the destination diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/core/PocketManager.java b/src/main/java/StevenDimDoors/mod_pocketDim/core/PocketManager.java index a509c38..39d5cf3 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/core/PocketManager.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/core/PocketManager.java @@ -163,15 +163,15 @@ public class PocketManager 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); + NewDimData dimension = createDimensionData(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; - getDimensionData(source.getDimension()).deleteLink(source); + createDimensionData(source.getDimension()).deleteLink(source); } } @@ -270,7 +270,6 @@ public class PocketManager public static boolean registerPackedDimData(PackedDimData packedData) { - InnerDimData dimData; //register roots if(packedData.ID==packedData.ParentID) @@ -290,7 +289,7 @@ public class PocketManager 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); + dimData.root = PocketManager.createDimensionData(packedData.RootID); if(packedData.DungeonData!=null) { @@ -412,9 +411,7 @@ public class PocketManager * 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) { @@ -501,23 +498,19 @@ public class PocketManager return world; } - public static NewDimData registerDimension(World world) - { - return registerDimension(world.provider.dimensionId, null, false, false); - } - public static NewDimData registerPocket(NewDimData parent, boolean isDungeon) { 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); } + /** * Registers a dimension with DD but NOT with forge. * @param dimensionID @@ -548,16 +541,16 @@ public class PocketManager } @SideOnly(Side.CLIENT) - private static NewDimData registerClientDimension(int dimensionID, int rootID) + protected 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 + // 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 getDimensionData will raise + // 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) @@ -573,7 +566,7 @@ 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. @@ -584,26 +577,29 @@ public class PocketManager } return dimension; } - - public static NewDimData getDimensionData(World world) - { - return getDimensionData(world.provider.dimensionId); - } - + 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. + return PocketManager.dimensionData.get(dimensionID); + } - //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; - } + 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 (dimension == null) { diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/dungeon/DungeonSchematic.java b/src/main/java/StevenDimDoors/mod_pocketDim/dungeon/DungeonSchematic.java index 7a443fc..07231c5 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/dungeon/DungeonSchematic.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/dungeon/DungeonSchematic.java @@ -247,7 +247,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) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/helpers/DungeonHelper.java b/src/main/java/StevenDimDoors/mod_pocketDim/helpers/DungeonHelper.java index 1605202..a4aae50 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/helpers/DungeonHelper.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/helpers/DungeonHelper.java @@ -263,7 +263,7 @@ public class DungeonHelper public DimLink createCustomDungeonDoor(World world, int x, int y, int z) { //Create a link above the specified position. Link to a new pocket dimension. - NewDimData dimension = PocketManager.getDimensionData(world); + NewDimData dimension = PocketManager.createDimensionData(world); DimLink link = dimension.createLink(x, y + 1, z, LinkTypes.POCKET, 3); //Place a Warp Door linked to that pocket diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemRiftSignature.java b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemRiftSignature.java index 84dbde6..48121fd 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemRiftSignature.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemRiftSignature.java @@ -74,7 +74,7 @@ public class ItemRiftSignature extends Item // 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); + NewDimData destinationDimension = PocketManager.createDimensionData(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.setLinkDestination(link, x, adjustedY, z); @@ -99,7 +99,7 @@ public class ItemRiftSignature extends Item 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); } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemStabilizedRiftSignature.java b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemStabilizedRiftSignature.java index c06d598..94f4acb 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemStabilizedRiftSignature.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/items/ItemStabilizedRiftSignature.java @@ -53,7 +53,7 @@ public class ItemStabilizedRiftSignature extends ItemRiftSignature { // Yes, it's initialized. NewDimData sourceDimension = PocketManager.getDimensionData(source.getDimension()); - NewDimData destinationDimension = PocketManager.getDimensionData(world); + NewDimData destinationDimension = PocketManager.createDimensionData(world); DimLink reverse = destinationDimension.getLink(x, adjustedY, z); DimLink link; @@ -104,7 +104,7 @@ public class ItemStabilizedRiftSignature extends ItemRiftSignature 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 Stabilized Rift Signature"); world.playSoundAtEntity(player, "mods.DimDoors.sfx.riftStart", 0.6f, 1); } @@ -129,7 +129,7 @@ public class ItemStabilizedRiftSignature extends ItemRiftSignature if (source != null) { NewDimData sourceDimension = PocketManager.getDimensionData(source.getDimension()); - NewDimData destinationDimension = PocketManager.getDimensionData(world); + NewDimData destinationDimension = PocketManager.createDimensionData(world); DimLink reverse = destinationDimension.getLink(x, adjustedY, z); DimLink link; 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/saving/DDSaveHandler.java b/src/main/java/StevenDimDoors/mod_pocketDim/saving/DDSaveHandler.java index 3a7bb70..a0d214c 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/saving/DDSaveHandler.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/saving/DDSaveHandler.java @@ -189,7 +189,7 @@ public class DDSaveHandler { if(packedLink.parent.equals(fakePoint)) { - NewDimData data = PocketManager.getDimensionData(packedLink.source.getDimension()); + NewDimData data = PocketManager.createDimensionDataDangerously(packedLink.source.getDimension()); int linkType = packedLink.tail.linkType; if((linkType < LinkTypes.ENUM_MIN || linkType > LinkTypes.ENUM_MAX) && linkType != LinkTypes.CLIENT_SIDE) @@ -201,7 +201,7 @@ public class DDSaveHandler Point4D destination = packedLink.tail.destination; if(destination!=null) { - PocketManager.getDimensionData(destination.getDimension()).setLinkDestination(link, destination.getX(),destination.getY(),destination.getZ()); + PocketManager.createDimensionDataDangerously(destination.getDimension()).setLinkDestination(link, destination.getX(),destination.getY(),destination.getZ()); } unpackedLinks.add(packedLink); } @@ -213,7 +213,7 @@ 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)); diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityDimDoorGold.java b/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityDimDoorGold.java index 093c1e8..6b9696e 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityDimDoorGold.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityDimDoorGold.java @@ -46,7 +46,7 @@ public class TileEntityDimDoorGold extends TileEntityDimDoor implements IChunkLo // link associated with it. if (!worldObj.isRemote) { - NewDimData dimension = PocketManager.getDimensionData(worldObj); + NewDimData dimension = PocketManager.createDimensionData(worldObj); // Check whether a ticket has already been assigned to this door if (chunkTicket == null) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityRift.java b/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityRift.java index 62bb62b..cf6df98 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityRift.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityRift.java @@ -137,7 +137,7 @@ public class TileEntityRift extends DDTileEntityBase private void closeRift() { - NewDimData dimension = PocketManager.getDimensionData(worldObj); + NewDimData dimension = PocketManager.createDimensionData(worldObj); if (closeTimer == CLOSING_PERIOD / 2) { for (DimLink riftLink : dimension.findRiftsInRange(worldObj, 6, xCoord, yCoord, zCoord)) @@ -167,7 +167,7 @@ public class TileEntityRift extends DDTileEntityBase public boolean updateNearestRift() { Point4D previousNearest = nearestRiftLocation; - DimLink nearestRiftLink = PocketManager.getDimensionData(worldObj).findNearestRift( + DimLink nearestRiftLink = PocketManager.createDimensionData(worldObj).findNearestRift( worldObj, RIFT_INTERACTION_RANGE, xCoord, yCoord, zCoord); nearestRiftLocation = (nearestRiftLink == null) ? null : nearestRiftLink.source(); @@ -221,7 +221,7 @@ public class TileEntityRift extends DDTileEntityBase return; } - NewDimData dimension = PocketManager.getDimensionData(worldObj); + NewDimData dimension = PocketManager.createDimensionData(worldObj); DimLink link = dimension.getLink(xCoord, yCoord, zCoord); if (link.childCount() >= MAX_CHILD_LINKS || countAncestorLinks(link) >= MAX_ANCESTOR_LINKS) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/world/PocketBuilder.java b/src/main/java/StevenDimDoors/mod_pocketDim/world/PocketBuilder.java index 515fbee..fb29525 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/world/PocketBuilder.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/world/PocketBuilder.java @@ -3,6 +3,7 @@ package StevenDimDoors.mod_pocketDim.world; import java.util.Random; import net.minecraft.block.Block; +import net.minecraft.item.ItemDoor; import net.minecraft.util.MathHelper; import net.minecraft.world.World; import net.minecraft.world.chunk.Chunk; @@ -21,7 +22,6 @@ 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; @@ -40,87 +40,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; - } - - DungeonSchematic schematic = loadAndValidateDungeon(dimension.dungeon(), properties); - if (schematic == null) - { - return false; - } - Point3D destination = new Point3D(incomingLink.destination()); - schematic.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 @@ -479,7 +398,7 @@ public class PocketBuilder //Build the door int doorOrientation = BlockRotator.transformMetadata(BlockRotator.EAST_DOOR_METADATA, orientation - BlockRotator.EAST_DOOR_METADATA + 2, properties.DimensionalDoorID); - ItemDimensionalDoor.placeDoorBlock(world, x, y - 1, z, doorOrientation, doorBlock); + ItemDoor.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) 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 08924d8..910d0fb 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/world/PocketProvider.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/world/PocketProvider.java @@ -7,7 +7,6 @@ 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; @@ -103,11 +102,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 db6ef44..8a63b40 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/world/fortresses/ComponentNetherGateway.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/world/fortresses/ComponentNetherGateway.java @@ -154,7 +154,7 @@ 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) { diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/world/gateways/BaseSchematicGateway.java b/src/main/java/StevenDimDoors/mod_pocketDim/world/gateways/BaseSchematicGateway.java index 6eaa0da..c94554d 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/world/gateways/BaseSchematicGateway.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/world/gateways/BaseSchematicGateway.java @@ -44,7 +44,7 @@ public abstract class BaseSchematicGateway extends BaseGateway this.generateRandomBits(world, x, y, z); // Generate a dungeon link in the door - PocketManager.getDimensionData(world).createLink(x, y + doorLocation.getY(), z, LinkTypes.DUNGEON, orientation); + PocketManager.createDimensionData(world).createLink(x, y + doorLocation.getY(), z, LinkTypes.DUNGEON, orientation); return true; } 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 dfd855a..19b4ba4 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/world/gateways/GatewayGenerator.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/world/gateways/GatewayGenerator.java @@ -106,7 +106,7 @@ public class GatewayGenerator implements IWorldGenerator //Create a link. If this is not the first time, create a child link and connect it to the first link. if (link == null) { - dimension = PocketManager.getDimensionData(world); + dimension = PocketManager.createDimensionData(world); link = dimension.createLink(x, y + 1, z, LinkTypes.DUNGEON,0); } else 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 cb50437..665dbd8 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/world/gateways/GatewayLimbo.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/world/gateways/GatewayLimbo.java @@ -30,7 +30,7 @@ public class GatewayLimbo extends BaseGateway world.setBlock(x, y + 1, z - 1, blockID, 0, 3); world.setBlock(x, y + 1, z + 1, blockID, 0, 3); - PocketManager.getDimensionData(world).createLink(x, y + 2, z, LinkTypes.DUNGEON, 0); + PocketManager.createDimensionData(world).createLink(x, y + 2, z, LinkTypes.DUNGEON, 0); ItemDoor.placeDoorBlock(world, x, y + 1, z, 0, mod_pocketDim.transientDoor); return true; } 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/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; } From 20db828ac05577d7952c604a8f6731dc2eef18a0 Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Tue, 15 Jul 2014 14:51:46 -0400 Subject: [PATCH 179/187] Fixed Crash on Rift Removal Fixed a crash from manipulating rift data on the client side. I let this happen because it seemed like TileEntityRift already did that before. This crash also exposed another issue: that server-side functions are being used on the client side. I'm not sure how pervasive this is but some client dimensions are being constructed with the server-side constructor. --- .../mod_pocketDim/tileentities/TileEntityRift.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityRift.java b/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityRift.java index cf6df98..5e8dd9c 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityRift.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityRift.java @@ -151,7 +151,7 @@ public class TileEntityRift extends DDTileEntityBase } } } - if (closeTimer >= CLOSING_PERIOD) + if (closeTimer >= CLOSING_PERIOD && !worldObj.isRemote) { DimLink link = PocketManager.getLink(this.xCoord, this.yCoord, this.zCoord, worldObj); if (link != null) From 499c7d91d8c079afd218e6166317f1923d16fb93 Mon Sep 17 00:00:00 2001 From: StevenRS11 Date: Wed, 16 Jul 2014 10:41:27 -0500 Subject: [PATCH 180/187] Formatting change Aformentioned merge wouldnt commit for some reason PLEASE REVIEW THIS AND THE PREVIOUS COMMIT --- .../mod_pocketDim/core/PocketManager.java | 277 ++++++++++-------- 1 file changed, 153 insertions(+), 124 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/core/PocketManager.java b/src/main/java/StevenDimDoors/mod_pocketDim/core/PocketManager.java index 177e456..209c2fc 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/core/PocketManager.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/core/PocketManager.java @@ -29,25 +29,29 @@ 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 { - // 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, DimensionType type, - IUpdateWatcher linkWatcher) + public InnerDimData(int id, InnerDimData parent, DimensionType type, IUpdateWatcher linkWatcher) { super(id, parent, type, linkWatcher); } - + public InnerDimData(int id, NewDimData root, DimensionType type) { // This constructor is meant for client-side code only @@ -55,36 +59,36 @@ public class PocketManager } } - - private static class ClientLinkWatcher implements IUpdateWatcher - { - @Override - public void onCreated(ClientLinkData link) - { - Point4D source = link.point; - NewDimData dimension = getDimensionData(source.getDimension()); - dimension.createLink(source, LinkType.CLIENT, 0, link.lock); - } - @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 ClientLinkWatcher implements IUpdateWatcher + { + @Override + public void onCreated(ClientLinkData link) + { + Point4D source = link.point; + NewDimData dimension = getDimensionData(source.getDimension()); + dimension.createLink(source, LinkType.CLIENT, 0, link.lock); + } + + @Override + public void onDeleted(ClientLinkData link) + { + Point4D source = link.point; + NewDimData dimension = getDimensionData(source.getDimension()); + dimension.deleteLink(source.getX(), source.getY(), source.getZ()); + } + + @Override + public void update(ClientLinkData link) + { + Point4D source = link.point; + NewDimData dimension = getDimensionData(source.getDimension()); + DimLink dLink = dimension.getLink(source); + dLink.lock = link.lock; + + } + } - @Override - public void update(ClientLinkData link) - { - Point4D source = link.point; - NewDimData dimension = getDimensionData(source.getDimension()); - DimLink dLink = dimension.getLink(source); - dLink.lock=link.lock; - - } - } - private static class ClientDimWatcher implements IUpdateWatcher { @Override @@ -108,9 +112,12 @@ public class PocketManager 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 @@ -133,13 +140,15 @@ 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; + // Stores all the personal pocket mappings + private static HashMap personalPocketsMapping = null; public static boolean isLoaded() { @@ -147,7 +156,9 @@ public class PocketManager } /** - * 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() @@ -166,24 +177,22 @@ public class PocketManager rootDimensions = new ArrayList(); dimensionIDBlackList = new ArrayList(); personalPocketsMapping = new HashMap(); - - if(FMLCommonHandler.instance().getEffectiveSide().isClient()) + 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, DimensionType.ROOT); - loadInternal(); - //Register pocket dimensions + // Register pocket dimensions registerPockets(properties); isLoaded = true; @@ -194,33 +203,34 @@ public class PocketManager { InnerDimData dimData; DimensionType type = DimensionType.getTypeFromIndex(packedData.DimensionType); - if(type == null) + if (type == null) { throw new IllegalArgumentException("Invalid dimension type"); } - //register roots - if(packedData.ID==packedData.ParentID) + // 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); + 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, type, linkWatcher); - dimData.isFilled=packedData.IsFilled; - dimData.origin = new Point4D(packedData.Origin.getX(),packedData.Origin.getY(),packedData.Origin.getZ(),packedData.ID); + 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) + if (packedData.DungeonData != null) { - dimData.dungeon=DDSaveHandler.unpackDungeonData(packedData.DungeonData); + dimData.dungeon = DDSaveHandler.unpackDungeonData(packedData.DungeonData); } } @@ -232,8 +242,10 @@ public class PocketManager 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) @@ -292,7 +304,7 @@ public class PocketManager { try { - if(personalPocketsMapping.containsValue(dimension)) + if (personalPocketsMapping.containsValue(dimension)) { DimensionManager.registerDimension(dimension.id(), properties.PersonalPocketProviderID); } @@ -303,7 +315,8 @@ public class PocketManager } 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(); } } @@ -325,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 { @@ -342,30 +355,31 @@ 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() { 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.renameTo(new File(oldSaveData.getAbsolutePath()+"_IMPORTED")); + 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(); } @@ -387,7 +401,7 @@ public class PocketManager { 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; @@ -439,6 +453,7 @@ public class PocketManager /** * method to register a new pocket with DD and with forge. + * * @param parent * @param type * @param playername @@ -450,14 +465,14 @@ public class PocketManager { throw new IllegalArgumentException("parent cannot be null. A pocket dimension must always have a parent dimension."); } - + DDProperties properties = DDProperties.instance(); int dimensionID = DimensionManager.getNextFreeDimId(); - - //register a personal pocket - if(type == DimensionType.PERSONAL) + + // register a personal pocket + if (type == DimensionType.PERSONAL) { - if(playername == null) + if (playername == null) { throw new IllegalArgumentException("A personal pocket must be attached to a playername"); } @@ -467,28 +482,30 @@ public class PocketManager return data; } else - { //register a pocket as personal if its parents are personal, but without a mapping. - if(parent.type == DimensionType.PERSONAL) + { // 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); + NewDimData data = registerDimension(dimensionID, (InnerDimData) parent, DimensionType.PERSONAL); return data; } - - //register a standard pocket + + // 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 @@ -496,10 +513,10 @@ public class PocketManager * @return */ 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."); } @@ -524,7 +541,8 @@ public class PocketManager // 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 + // 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) createDimensionData(rootID); @@ -545,45 +563,52 @@ public class PocketManager } 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. + // 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 + // 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(int dimensionID) { 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. + // 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 + // 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) { @@ -643,10 +668,12 @@ public class PocketManager { return PocketManager.dimensionIDBlackList.contains(dimensionID); } + public static void registerDimWatcher(IUpdateWatcher watcher) { getDimwatcher().registerReceiver(watcher); } + public static boolean unregisterDimWatcher(IUpdateWatcher watcher) { return getDimwatcher().unregisterReceiver(watcher); @@ -669,7 +696,8 @@ public class PocketManager 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); } @@ -680,19 +708,20 @@ public class PocketManager 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) { @@ -707,25 +736,25 @@ public class PocketManager isConnected = true; } - public static UpdateWatcherProxy getDimwatcher() + public static UpdateWatcherProxy getDimwatcher() { return dimWatcher; } - - public static UpdateWatcherProxy getLinkWatcher() + + public static UpdateWatcherProxy getLinkWatcher() { return linkWatcher; } public static NewDimData getPersonalDimensionForPlayer(String name) { - if(personalPocketsMapping.containsKey(name)) + if (personalPocketsMapping.containsKey(name)) { return personalPocketsMapping.get(name); } return null; } - + public static void setPersonalPocketsMapping(HashMap ppMap) { personalPocketsMapping = ppMap; From 68ff8f692174aa24ca7729e78aef1ee142056063 Mon Sep 17 00:00:00 2001 From: StevenRS11 Date: Tue, 19 Aug 2014 17:36:07 -0500 Subject: [PATCH 181/187] Added triangulation library and rift render Major change is addition of fractal rift rendering, currently first pass. Curves are registered and pregenerated in mod_pocketDim. Rifts look up these curves, choose one, rotate it, and render it. The render is a TESR that does stuff. Hard to explain, look at RenderRift in the code and look at the actual rifts in game to get an idea of what it does. I had to add a triangulation library to accomplish this. Will hopefully do something else that drag around all this. (I tried(and used comments)) --- .../mod_pocketDim/CommonProxy.java | 1 - .../mod_pocketDim/blocks/BlockRift.java | 6 +- .../mod_pocketDim/mod_pocketDim.java | 13 + .../saving/DimDataProcessor.java | 34 +- .../tileentities/TileEntityRift.java | 8 + .../mod_pocketDim/util/l_systems/LSystem.java | 501 +++++++ .../mod_pocketDimClient/ClientProxy.java | 3 +- .../mod_pocketDimClient/RenderRift.java | 169 +++ src/main/java/org/poly2tri/Poly2Tri.java | 124 ++ .../poly2tri/geometry/polygon/Polygon.java | 269 ++++ .../geometry/polygon/PolygonPoint.java | 39 + .../poly2tri/geometry/polygon/PolygonSet.java | 58 + .../geometry/polygon/PolygonUtil.java | 15 + .../poly2tri/geometry/primitives/Edge.java | 17 + .../poly2tri/geometry/primitives/Point.java | 31 + .../coordinate/AnyToXYTransform.java | 71 + .../coordinate/CoordinateTransform.java | 12 + .../coordinate/Matrix3Transform.java | 38 + .../transform/coordinate/NoTransform.java | 21 + .../coordinate/XYToAnyTransform.java | 74 + .../triangulation/Triangulatable.java | 22 + .../triangulation/TriangulationAlgorithm.java | 36 + .../TriangulationConstraint.java | 55 + .../triangulation/TriangulationContext.java | 171 +++ .../TriangulationDebugContext.java | 13 + .../triangulation/TriangulationMode.java | 6 + .../triangulation/TriangulationPoint.java | 112 ++ .../triangulation/TriangulationProcess.java | 341 +++++ .../TriangulationProcessEvent.java | 36 + .../TriangulationProcessListener.java | 36 + .../triangulation/TriangulationUtil.java | 213 +++ .../delaunay/DelaunayTriangle.java | 685 +++++++++ .../delaunay/sweep/AdvancingFront.java | 179 +++ .../delaunay/sweep/AdvancingFrontIndex.java | 43 + .../delaunay/sweep/AdvancingFrontNode.java | 84 ++ .../triangulation/delaunay/sweep/DTSweep.java | 1290 +++++++++++++++++ .../delaunay/sweep/DTSweepConstraint.java | 103 ++ .../delaunay/sweep/DTSweepContext.java | 280 ++++ .../delaunay/sweep/DTSweepDebugContext.java | 105 ++ .../sweep/DTSweepPointComparator.java | 35 + .../delaunay/sweep/PointOnEdgeException.java | 15 + .../triangulation/point/FloatBufferPoint.java | 94 ++ .../poly2tri/triangulation/point/TPoint.java | 69 + .../sets/ConstrainedPointSet.java | 121 ++ .../poly2tri/triangulation/sets/PointSet.java | 95 ++ .../triangulation/util/PointGenerator.java | 38 + .../triangulation/util/PolygonGenerator.java | 94 ++ .../util/QuadTreeRefinement.java | 17 + .../poly2tri/triangulation/util/Tuple2.java | 43 + .../poly2tri/triangulation/util/Tuple3.java | 45 + 50 files changed, 5967 insertions(+), 13 deletions(-) create mode 100644 src/main/java/StevenDimDoors/mod_pocketDim/util/l_systems/LSystem.java create mode 100644 src/main/java/StevenDimDoors/mod_pocketDimClient/RenderRift.java create mode 100644 src/main/java/org/poly2tri/Poly2Tri.java create mode 100644 src/main/java/org/poly2tri/geometry/polygon/Polygon.java create mode 100644 src/main/java/org/poly2tri/geometry/polygon/PolygonPoint.java create mode 100644 src/main/java/org/poly2tri/geometry/polygon/PolygonSet.java create mode 100644 src/main/java/org/poly2tri/geometry/polygon/PolygonUtil.java create mode 100644 src/main/java/org/poly2tri/geometry/primitives/Edge.java create mode 100644 src/main/java/org/poly2tri/geometry/primitives/Point.java create mode 100644 src/main/java/org/poly2tri/transform/coordinate/AnyToXYTransform.java create mode 100644 src/main/java/org/poly2tri/transform/coordinate/CoordinateTransform.java create mode 100644 src/main/java/org/poly2tri/transform/coordinate/Matrix3Transform.java create mode 100644 src/main/java/org/poly2tri/transform/coordinate/NoTransform.java create mode 100644 src/main/java/org/poly2tri/transform/coordinate/XYToAnyTransform.java create mode 100644 src/main/java/org/poly2tri/triangulation/Triangulatable.java create mode 100644 src/main/java/org/poly2tri/triangulation/TriangulationAlgorithm.java create mode 100644 src/main/java/org/poly2tri/triangulation/TriangulationConstraint.java create mode 100644 src/main/java/org/poly2tri/triangulation/TriangulationContext.java create mode 100644 src/main/java/org/poly2tri/triangulation/TriangulationDebugContext.java create mode 100644 src/main/java/org/poly2tri/triangulation/TriangulationMode.java create mode 100644 src/main/java/org/poly2tri/triangulation/TriangulationPoint.java create mode 100644 src/main/java/org/poly2tri/triangulation/TriangulationProcess.java create mode 100644 src/main/java/org/poly2tri/triangulation/TriangulationProcessEvent.java create mode 100644 src/main/java/org/poly2tri/triangulation/TriangulationProcessListener.java create mode 100644 src/main/java/org/poly2tri/triangulation/TriangulationUtil.java create mode 100644 src/main/java/org/poly2tri/triangulation/delaunay/DelaunayTriangle.java create mode 100644 src/main/java/org/poly2tri/triangulation/delaunay/sweep/AdvancingFront.java create mode 100644 src/main/java/org/poly2tri/triangulation/delaunay/sweep/AdvancingFrontIndex.java create mode 100644 src/main/java/org/poly2tri/triangulation/delaunay/sweep/AdvancingFrontNode.java create mode 100644 src/main/java/org/poly2tri/triangulation/delaunay/sweep/DTSweep.java create mode 100644 src/main/java/org/poly2tri/triangulation/delaunay/sweep/DTSweepConstraint.java create mode 100644 src/main/java/org/poly2tri/triangulation/delaunay/sweep/DTSweepContext.java create mode 100644 src/main/java/org/poly2tri/triangulation/delaunay/sweep/DTSweepDebugContext.java create mode 100644 src/main/java/org/poly2tri/triangulation/delaunay/sweep/DTSweepPointComparator.java create mode 100644 src/main/java/org/poly2tri/triangulation/delaunay/sweep/PointOnEdgeException.java create mode 100644 src/main/java/org/poly2tri/triangulation/point/FloatBufferPoint.java create mode 100644 src/main/java/org/poly2tri/triangulation/point/TPoint.java create mode 100644 src/main/java/org/poly2tri/triangulation/sets/ConstrainedPointSet.java create mode 100644 src/main/java/org/poly2tri/triangulation/sets/PointSet.java create mode 100644 src/main/java/org/poly2tri/triangulation/util/PointGenerator.java create mode 100644 src/main/java/org/poly2tri/triangulation/util/PolygonGenerator.java create mode 100644 src/main/java/org/poly2tri/triangulation/util/QuadTreeRefinement.java create mode 100644 src/main/java/org/poly2tri/triangulation/util/Tuple2.java create mode 100644 src/main/java/org/poly2tri/triangulation/util/Tuple3.java diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/CommonProxy.java b/src/main/java/StevenDimDoors/mod_pocketDim/CommonProxy.java index 952b796..5f48227 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/CommonProxy.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/CommonProxy.java @@ -21,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) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockRift.java b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockRift.java index 987e0c5..3a314c7 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockRift.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockRift.java @@ -396,14 +396,14 @@ public class BlockRift extends Block implements ITileEntityProvider - 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)); + //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)); 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(par1World,par2+.5, par3+.5, par4+.5, rand.nextGaussian() * 0.01D, rand.nextGaussian() * 0.01D, rand.nextGaussian() * 0.01D, FMLClientHandler.instance().getClient().effectRenderer)); } if(tile.shouldClose) { diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java b/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java index c22b4c2..20bc9fb 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java @@ -65,6 +65,7 @@ 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; @@ -325,6 +326,18 @@ public class mod_pocketDim DDLoot.registerInfo(properties); proxy.loadTextures(); proxy.registerRenderers(); + + + LSystem.generateLSystem("terdragon 9", LSystem.TERDRAGON, 9); + LSystem.generateLSystem("terdragon 8", LSystem.TERDRAGON, 8); + LSystem.generateLSystem("terdragon 7", LSystem.TERDRAGON, 7); + LSystem.generateLSystem("terdragon 6", LSystem.TERDRAGON, 6); + LSystem.generateLSystem("terdragon 5", LSystem.TERDRAGON, 5); + LSystem.generateLSystem("terdragon 4", LSystem.TERDRAGON, 4); + + LSystem.generateLSystem("dragon 15", LSystem.DRAGON, 15); + + } @EventHandler diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/saving/DimDataProcessor.java b/src/main/java/StevenDimDoors/mod_pocketDim/saving/DimDataProcessor.java index d42b8ef..1c6f248 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/saving/DimDataProcessor.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/saving/DimDataProcessor.java @@ -18,14 +18,21 @@ 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/"; - - //TODO dont load the schemas every time + /** + * Need to manually include a schema defintion for every save file version currently supported + */ public DimDataProcessor() { SAVE_DATA_SCHEMA = new HashMap(); @@ -33,7 +40,7 @@ public class DimDataProcessor extends BaseConfigurationProcessor //Load the old schema/s SAVE_DATA_SCHEMA.put(982405775, loadSchema(BASE_SCHEMA_PATH+"Dim_Data_Schema_v982405775.json")); - //load the current schema + //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")); } @@ -159,7 +166,18 @@ public class DimDataProcessor extends BaseConfigurationProcessor */ public JsonObject processSaveData(JsonObject schema, JsonObject save) { - if(save.get(JSON_VERSION_PROPERTY_NAME).getAsInt()== 982405775) + int incomingSaveVersionID = save.get(JSON_VERSION_PROPERTY_NAME).getAsInt(); + + // Handle save data versions that are current + if(incomingSaveVersionID == PackedDimData.SAVE_DATA_VERSION_ID) + { + 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; @@ -183,11 +201,11 @@ public class DimDataProcessor extends BaseConfigurationProcessor save.remove("IsDungeon"); save.addProperty("DimensionType",type.index); save.remove(this.JSON_VERSION_PROPERTY_NAME); - save.addProperty(this.JSON_VERSION_PROPERTY_NAME, PackedDimData.SAVE_DATA_VERSION_ID); - return processSaveData(this.getSaveDataSchema(save), save); + + //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); } - JSONValidator.validate(this.getSaveDataSchema(save), save); - return save; + return processSaveData(this.getSaveDataSchema(save), save); } } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityRift.java b/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityRift.java index db31843..c7548f7 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityRift.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityRift.java @@ -44,12 +44,15 @@ public class TileEntityRift extends DDTileEntityBase public boolean shouldClose = false; public Point4D nearestRiftLocation = null; public int spawnedEndermenID = 0; + public int riftRotation; 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); + this.riftRotation = random.nextInt(360); + } @Override @@ -74,6 +77,7 @@ public class TileEntityRift extends DDTileEntityBase return; } + // Check if this rift should render white closing particles and // spread the closing effect to other rifts nearby. if (shouldClose) @@ -251,6 +255,8 @@ public class TileEntityRift extends DDTileEntityBase this.zOffset = nbt.getInteger("zOffset"); this.shouldClose = nbt.getBoolean("shouldClose"); this.spawnedEndermenID = nbt.getInteger("spawnedEndermenID"); + this.riftRotation = nbt.getInteger("riftRotation"); + } @Override @@ -263,6 +269,8 @@ public class TileEntityRift extends DDTileEntityBase nbt.setInteger("zOffset", this.zOffset); nbt.setBoolean("shouldClose", this.shouldClose); nbt.setInteger("spawnedEndermenID", this.spawnedEndermenID); + + nbt.setInteger("riftRotation", this.riftRotation); } @Override 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..184fe33 --- /dev/null +++ b/src/main/java/StevenDimDoors/mod_pocketDim/util/l_systems/LSystem.java @@ -0,0 +1,501 @@ +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 HashMap curves = new HashMap(); + + /** + * 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"}; + + + + /** + * 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.put(key, polygon); + + } + + /** + * 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; + } + else if (xCoord < minX) + { + minX = xCoord; + } + + if (yCoord > maxY) + { + maxY = yCoord; + } + else 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_pocketDimClient/ClientProxy.java b/src/main/java/StevenDimDoors/mod_pocketDimClient/ClientProxy.java index 873aa8f..004e4ce 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDimClient/ClientProxy.java +++ b/src/main/java/StevenDimDoors/mod_pocketDimClient/ClientProxy.java @@ -7,6 +7,7 @@ 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; @@ -23,7 +24,7 @@ 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)); diff --git a/src/main/java/StevenDimDoors/mod_pocketDimClient/RenderRift.java b/src/main/java/StevenDimDoors/mod_pocketDimClient/RenderRift.java new file mode 100644 index 0000000..ea352c6 --- /dev/null +++ b/src/main/java/StevenDimDoors/mod_pocketDimClient/RenderRift.java @@ -0,0 +1,169 @@ +package StevenDimDoors.mod_pocketDimClient; + +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) + { + // 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.glLogicOp(GL11.GL_INVERT); + * GL11.glEnable(GL11.GL_COLOR_LOGIC_OP); + */ + + // draws the verticies corresponding to the passed it + this.drawCrack(((TileEntityRift) te).riftRotation, LSystem.curves.get("terdragon 7"), 3, xWorld, yWorld, zWorld); + + // reenable all the stuff we disabled + GL11.glEnable(GL11.GL_CULL_FACE); + GL11.glEnable(GL11.GL_LIGHTING); + GL11.glEnable(GL_TEXTURE_2D); + + GL11.glPopMatrix(); + } + + /** + * 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) + { + // calculate the proper size for the rift render + double scale = size / (poly.maxX - poly.minX); + + // 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 = 2.0F; + + // changes how quickly the triangles move + float motionSpeed = 800.0F; + + // number of individual jitter waveforms to generate + // changes how "together" the overall motions are + int jCount = 10; + + // Calculate jitter like for monoliths + float time = (float) (((Minecraft.getSystemTime() + 0xF1234568 * this.hashCode()) % 2000000) / motionSpeed); + double[] jitters = new double[jCount]; + + // generate a series of waveforms + for (int i = 0; i < jCount; i += 2) + { + 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; + } + + // 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(.15F, .15F, .1F, 1F); + + //set the blending mode + GL11.glEnable(GL_BLEND); + glBlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ONE); + + // start rendering triangles for the moving shards + GL11.glBegin(GL11.GL_TRIANGLES); + for (Point p : poly.points) + { + 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]); + double z = (((p.x + jitters[(jIndex + 2) % jCount]) - offsetX) * Math.sin(Math.toRadians(riftRotation)) + 0 * 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.glDisable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_DST_COLOR); + //glBlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ZERO); + + GL11.glBegin(GL11.GL_TRIANGLES); + + // draw the next set of triangles to form a background and change their + // color slightly over time + 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; + 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; + + // the additional divisors here determine the color of the + // stationary shards + if (jIndex % 3 == 0) + { + GL11.glColor4d(jitters[(jIndex + 1) % jCount] / 11, jitters[(jIndex + 2) % jCount] / 8, jitters[(jIndex) % 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/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; + } +} From 04ec4b3d2d809a9c0db4d0ff591c04316ad20739 Mon Sep 17 00:00:00 2001 From: StevenRS11 Date: Tue, 19 Aug 2014 18:50:18 -0500 Subject: [PATCH 182/187] jitter together! --- .../mod_pocketDim/util/l_systems/LSystem.java | 2 +- .../mod_pocketDimClient/RenderRift.java | 11 +++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) 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 index 184fe33..b9c358d 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/util/l_systems/LSystem.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/util/l_systems/LSystem.java @@ -368,7 +368,7 @@ public class LSystem Poly2Tri.triangulate(poly); ArrayList tris =(ArrayList) poly.getTriangles(); - + for(DelaunayTriangle tri : tris) { for(TriangulationPoint tpoint : tri.points) diff --git a/src/main/java/StevenDimDoors/mod_pocketDimClient/RenderRift.java b/src/main/java/StevenDimDoors/mod_pocketDimClient/RenderRift.java index ea352c6..ef7ae05 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDimClient/RenderRift.java +++ b/src/main/java/StevenDimDoors/mod_pocketDimClient/RenderRift.java @@ -93,17 +93,18 @@ public class RenderRift extends TileEntitySpecialRenderer int jIndex = 0; // set the color for the render - GL11.glColor4f(.15F, .15F, .1F, 1F); + GL11.glColor4f(.3F, .3F, .3F, 1F); //set the blending mode GL11.glEnable(GL_BLEND); - glBlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ONE); + //glBlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ONE); + glBlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ZERO); // start rendering triangles for the moving shards GL11.glBegin(GL11.GL_TRIANGLES); for (Point p : poly.points) { - jIndex++; + jIndex = Math.abs(p.x+p.y); // calculate the rotation for the fractal, apply offset, and apply // jitter @@ -131,9 +132,10 @@ public class RenderRift extends TileEntitySpecialRenderer GL11.glEnd(); //GL11.glDisable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_DST_COLOR); + //glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_DST_COLOR); //glBlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ZERO); + /** GL11.glBegin(GL11.GL_TRIANGLES); // draw the next set of triangles to form a background and change their @@ -165,5 +167,6 @@ public class RenderRift extends TileEntitySpecialRenderer } // stop drawing triangles GL11.glEnd(); + **/ } } \ No newline at end of file From dc7a19c2f3e3ac20b1616ea4f8353a4f61b41157 Mon Sep 17 00:00:00 2001 From: StevenRS11 Date: Wed, 20 Aug 2014 16:58:52 -0500 Subject: [PATCH 183/187] render effect iteration --- .../mod_pocketDim/blocks/BlockRift.java | 103 ++---------------- .../mod_pocketDim/mod_pocketDim.java | 34 ++++-- .../tileentities/TileEntityRift.java | 23 +++- .../mod_pocketDim/util/l_systems/LSystem.java | 64 ++++++++++- .../mod_pocketDimClient/RenderRift.java | 58 +++++----- 5 files changed, 150 insertions(+), 132 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockRift.java b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockRift.java index 3a314c7..6fc5845 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockRift.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockRift.java @@ -307,99 +307,16 @@ 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. @@ -408,10 +325,10 @@ public class BlockRift extends Block implements ITileEntityProvider 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) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java b/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java index 20bc9fb..b4d6069 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/mod_pocketDim.java @@ -327,15 +327,33 @@ public class mod_pocketDim proxy.loadTextures(); proxy.registerRenderers(); - - LSystem.generateLSystem("terdragon 9", LSystem.TERDRAGON, 9); - LSystem.generateLSystem("terdragon 8", LSystem.TERDRAGON, 8); - LSystem.generateLSystem("terdragon 7", LSystem.TERDRAGON, 7); - LSystem.generateLSystem("terdragon 6", LSystem.TERDRAGON, 6); - LSystem.generateLSystem("terdragon 5", LSystem.TERDRAGON, 5); - LSystem.generateLSystem("terdragon 4", LSystem.TERDRAGON, 4); + 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("dragon 15", LSystem.DRAGON, 15); + + // 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); } diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityRift.java b/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityRift.java index c7548f7..c0d538c 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityRift.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityRift.java @@ -1,8 +1,8 @@ package StevenDimDoors.mod_pocketDim.tileentities; +import java.util.ArrayList; import java.util.List; import java.util.Random; - import net.minecraft.entity.Entity; import net.minecraft.entity.monster.EntityEnderman; import net.minecraft.entity.player.EntityPlayer; @@ -11,6 +11,7 @@ import net.minecraft.network.INetworkManager; import net.minecraft.network.packet.Packet; import net.minecraft.network.packet.Packet132TileEntityData; import net.minecraft.util.AxisAlignedBB; +import net.minecraft.util.MathHelper; import StevenDimDoors.mod_pocketDim.ServerPacketHandler; import StevenDimDoors.mod_pocketDim.mod_pocketDim; import StevenDimDoors.mod_pocketDim.config.DDProperties; @@ -18,6 +19,8 @@ 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 DDTileEntityBase @@ -44,7 +47,10 @@ public class TileEntityRift extends DDTileEntityBase public boolean shouldClose = false; public Point4D nearestRiftLocation = null; public int spawnedEndermenID = 0; + public int riftRotation; + public int renderKey; + public int growth; public TileEntityRift() { @@ -52,6 +58,7 @@ public class TileEntityRift extends DDTileEntityBase // from updating at the same time. updateTimer = random.nextInt(UPDATE_PERIOD); this.riftRotation = random.nextInt(360); + this.renderKey = random.nextInt(LSystem.curves.size()); } @@ -96,6 +103,7 @@ public class TileEntityRift extends DDTileEntityBase updateNearestRift(); spread(mod_pocketDim.properties); } + growth++; updateTimer++; } @@ -256,6 +264,8 @@ public class TileEntityRift extends DDTileEntityBase this.shouldClose = nbt.getBoolean("shouldClose"); this.spawnedEndermenID = nbt.getInteger("spawnedEndermenID"); this.riftRotation = nbt.getInteger("riftRotation"); + this.renderKey = nbt.getInteger("renderKey"); + this.growth = nbt.getInteger("growth"); } @@ -269,8 +279,10 @@ public class TileEntityRift extends DDTileEntityBase 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.setInteger("growth", this.growth); + } @Override @@ -294,4 +306,11 @@ public class TileEntityRift extends DDTileEntityBase { return null; } + + public PolygonStorage getCurve() + { + + + return (LSystem.curves.get(renderKey)); + } } 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 index b9c358d..46d83ec 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/util/l_systems/LSystem.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/util/l_systems/LSystem.java @@ -16,7 +16,7 @@ import org.poly2tri.triangulation.delaunay.DelaunayTriangle; public class LSystem { - public static HashMap curves = new HashMap(); + public static ArrayList curves = new ArrayList(); /** * An array containing the args to generate a curve. @@ -26,6 +26,8 @@ public class LSystem */ 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"}; @@ -64,7 +66,61 @@ public class LSystem //replace the boundary of the polygon with a series of points representing triangles for rendering polygon.points = tesselate(polygon); - curves.put(key, 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); } @@ -105,7 +161,7 @@ public class LSystem { maxX = xCoord; } - else if (xCoord < minX) + if (xCoord < minX) { minX = xCoord; } @@ -114,7 +170,7 @@ public class LSystem { maxY = yCoord; } - else if (yCoord < minY) + if (yCoord < minY) { minY = yCoord; } diff --git a/src/main/java/StevenDimDoors/mod_pocketDimClient/RenderRift.java b/src/main/java/StevenDimDoors/mod_pocketDimClient/RenderRift.java index ef7ae05..7eff8e2 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDimClient/RenderRift.java +++ b/src/main/java/StevenDimDoors/mod_pocketDimClient/RenderRift.java @@ -28,15 +28,16 @@ public class RenderRift extends TileEntitySpecialRenderer GL11.glDisable(GL11.GL_CULL_FACE); 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(((TileEntityRift) te).riftRotation, LSystem.curves.get("terdragon 7"), 3, xWorld, yWorld, zWorld); + this.drawCrack(rift.riftRotation, rift.getCurve(), Math.log(2+rift.growth)/5D, xWorld, yWorld, zWorld); + GL11.glDisable(GL_BLEND); // reenable all the stuff we disabled GL11.glEnable(GL11.GL_CULL_FACE); GL11.glEnable(GL11.GL_LIGHTING); @@ -68,24 +69,26 @@ public class RenderRift extends TileEntitySpecialRenderer double offsetZ = 0; // changes how far the triangles move - float motionMagnitude = 2.0F; + float motionMagnitude = 3.0F; // changes how quickly the triangles move - float motionSpeed = 800.0F; + float motionSpeed = 2000.0F; // number of individual jitter waveforms to generate // changes how "together" the overall motions are - int jCount = 10; + int jCount = 5; // Calculate jitter like for monoliths float time = (float) (((Minecraft.getSystemTime() + 0xF1234568 * this.hashCode()) % 2000000) / motionSpeed); double[] jitters = new double[jCount]; // generate a series of waveforms - for (int i = 0; i < jCount; i += 2) + 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; + + } // determines which jitter waveform we select. Modulo so the same point @@ -95,25 +98,25 @@ public class RenderRift extends TileEntitySpecialRenderer // set the color for the render GL11.glColor4f(.3F, .3F, .3F, 1F); - //set the blending mode - GL11.glEnable(GL_BLEND); - //glBlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ONE); - glBlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ZERO); - - // start rendering triangles for the moving shards + /**best ones so far + * glBlendFunc(GL_SRC_COLOR, GL_ONE); + * glBlendFunc(GL_SRC_COLOR, GL_ONE); + */ + glBlendFunc(GL_SRC_COLOR, GL_ONE); GL11.glBegin(GL11.GL_TRIANGLES); for (Point p : poly.points) { - jIndex = Math.abs(p.x+p.y); - + 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] + 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]); - double z = (((p.x + jitters[(jIndex + 2) % jCount]) - offsetX) * Math.sin(Math.toRadians(riftRotation)) + 0 * Math + 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; @@ -131,15 +134,19 @@ public class RenderRift extends TileEntitySpecialRenderer } GL11.glEnd(); - //GL11.glDisable(GL_BLEND); - //glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_DST_COLOR); - //glBlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ZERO); - - /** - GL11.glBegin(GL11.GL_TRIANGLES); + + /**best one so far + * glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_DST_COLOR); + * glBlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ZERO ); + */ + 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++; @@ -160,13 +167,14 @@ public class RenderRift extends TileEntitySpecialRenderer // stationary shards if (jIndex % 3 == 0) { - GL11.glColor4d(jitters[(jIndex + 1) % jCount] / 11, jitters[(jIndex + 2) % jCount] / 8, jitters[(jIndex) % jCount] / 8, 1); + // GL11.glColor4d(jitters[(jIndex + 1) % jCount]/8F , jitters[(jIndex + 2) % jCount] /8F, jitters[(jIndex) % jCount]/8F , 1); } GL11.glVertex3d(xWorld + x, yWorld + y, zWorld + z); } + // stop drawing triangles GL11.glEnd(); - **/ + } } \ No newline at end of file From 0dd1f1b29397a69a71d711fc96b4a8df4df51240 Mon Sep 17 00:00:00 2001 From: StevenRS11 Date: Wed, 20 Aug 2014 17:15:04 -0500 Subject: [PATCH 184/187] more changes --- .../mod_pocketDimClient/RenderRift.java | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDimClient/RenderRift.java b/src/main/java/StevenDimDoors/mod_pocketDimClient/RenderRift.java index 7eff8e2..317d7cc 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDimClient/RenderRift.java +++ b/src/main/java/StevenDimDoors/mod_pocketDimClient/RenderRift.java @@ -96,13 +96,13 @@ public class RenderRift extends TileEntitySpecialRenderer int jIndex = 0; // set the color for the render - GL11.glColor4f(.3F, .3F, .3F, 1F); + GL11.glColor4f(.1F, .1F, .1F, 1F); /**best ones so far * glBlendFunc(GL_SRC_COLOR, GL_ONE); * glBlendFunc(GL_SRC_COLOR, GL_ONE); */ - glBlendFunc(GL_SRC_COLOR, GL_ONE); + glBlendFunc(GL_ONE_MINUS_SRC_COLOR, GL_ONE); GL11.glBegin(GL11.GL_TRIANGLES); for (Point p : poly.points) { @@ -139,6 +139,7 @@ public class RenderRift extends TileEntitySpecialRenderer * glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_DST_COLOR); * glBlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ZERO ); */ + GL11.glColor4f(.3F, .3F, .3F, .2F); glBlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ZERO ); @@ -162,13 +163,6 @@ public class RenderRift extends TileEntitySpecialRenderer x += .5; y += .5; z += .5; - - // the additional divisors here determine the color of the - // stationary shards - if (jIndex % 3 == 0) - { - // GL11.glColor4d(jitters[(jIndex + 1) % jCount]/8F , jitters[(jIndex + 2) % jCount] /8F, jitters[(jIndex) % jCount]/8F , 1); - } GL11.glVertex3d(xWorld + x, yWorld + y, zWorld + z); } From a55fdbfd0f7f8590b404747c7edd1bb964ab2117 Mon Sep 17 00:00:00 2001 From: StevenRS11 Date: Wed, 20 Aug 2014 21:44:16 -0500 Subject: [PATCH 185/187] rift render canidate --- .../mod_pocketDimClient/RenderRift.java | 24 ++++++++----------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDimClient/RenderRift.java b/src/main/java/StevenDimDoors/mod_pocketDimClient/RenderRift.java index 317d7cc..ba1463a 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDimClient/RenderRift.java +++ b/src/main/java/StevenDimDoors/mod_pocketDimClient/RenderRift.java @@ -94,15 +94,12 @@ public class RenderRift extends TileEntitySpecialRenderer // 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); + GL11.glColor4f(.02F, .02F, .02F, 1F); - /**best ones so far - * glBlendFunc(GL_SRC_COLOR, GL_ONE); - * glBlendFunc(GL_SRC_COLOR, GL_ONE); - */ - glBlendFunc(GL_ONE_MINUS_SRC_COLOR, GL_ONE); + //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) { @@ -117,6 +114,7 @@ public class RenderRift extends TileEntitySpecialRenderer .cos(Math.toRadians(riftRotation))); + // apply scaling x *= scale; y *= scale; @@ -135,13 +133,7 @@ public class RenderRift extends TileEntitySpecialRenderer GL11.glEnd(); - /**best one so far - * glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_DST_COLOR); - * glBlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ZERO ); - */ - GL11.glColor4f(.3F, .3F, .3F, .2F); - - glBlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ZERO ); + glBlendFunc(GL_ONE, GL_ONE_MINUS_DST_COLOR); @@ -164,6 +156,10 @@ public class RenderRift extends TileEntitySpecialRenderer y += .5; z += .5; + if (jIndex % 3 == 0) + { + GL11.glColor4d(jitters[(jIndex + 5) % jCount] / 11, jitters[(jIndex + 4) % jCount] / 8, jitters[(jIndex+3) % jCount] / 8, 1); + } GL11.glVertex3d(xWorld + x, yWorld + y, zWorld + z); } From 910f991734b9effe90c01900b0ea54f0c48e1fd7 Mon Sep 17 00:00:00 2001 From: StevenRS11 Date: Wed, 20 Aug 2014 22:55:29 -0500 Subject: [PATCH 186/187] render color final --- .../mod_pocketDim/blocks/BlockRift.java | 2 +- .../mod_pocketDimClient/RenderRift.java | 13 +++++++------ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockRift.java b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockRift.java index 6fc5845..5890b49 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockRift.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/blocks/BlockRift.java @@ -320,7 +320,7 @@ public class BlockRift extends Block implements ITileEntityProvider 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) { diff --git a/src/main/java/StevenDimDoors/mod_pocketDimClient/RenderRift.java b/src/main/java/StevenDimDoors/mod_pocketDimClient/RenderRift.java index ba1463a..457c878 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDimClient/RenderRift.java +++ b/src/main/java/StevenDimDoors/mod_pocketDimClient/RenderRift.java @@ -95,7 +95,7 @@ public class RenderRift extends TileEntitySpecialRenderer // gets the same jitter waveform over multiple frames int jIndex = 0; // set the color for the render - GL11.glColor4f(.02F, .02F, .02F, 1F); + GL11.glColor4f(.1F, .1F, .1F, 1F); //set the blending mode GL11.glEnable(GL_BLEND); @@ -109,7 +109,7 @@ public class RenderRift extends TileEntitySpecialRenderer // 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]); + 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))); @@ -132,8 +132,9 @@ public class RenderRift extends TileEntitySpecialRenderer } GL11.glEnd(); - - glBlendFunc(GL_ONE, GL_ONE_MINUS_DST_COLOR); + GL11.glColor4f(.3F, .3F, .3F, .2F); + + glBlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ZERO ); @@ -145,7 +146,7 @@ public class RenderRift extends TileEntitySpecialRenderer jIndex++; double x = (((p.x) - offsetX) * Math.cos(Math.toRadians(riftRotation)) - 0 * Math.sin(Math.toRadians(riftRotation))); - double y = p.y; + double y = p.y - offsetY; double z = (((p.x) - offsetX) * Math.sin(Math.toRadians(riftRotation)) + 0 * Math.cos(Math.toRadians(riftRotation))); x *= scale; @@ -158,7 +159,7 @@ public class RenderRift extends TileEntitySpecialRenderer if (jIndex % 3 == 0) { - GL11.glColor4d(jitters[(jIndex + 5) % jCount] / 11, jitters[(jIndex + 4) % jCount] / 8, jitters[(jIndex+3) % jCount] / 8, 1); + //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); } From 7b77b268bf525d619aed7dbc67829ce9ac21a3bd Mon Sep 17 00:00:00 2001 From: StevenRS11 Date: Thu, 21 Aug 2014 18:42:24 -0500 Subject: [PATCH 187/187] rift render growth and removal --- .../tileentities/TileEntityRift.java | 21 ++++++----- .../mod_pocketDimClient/RenderRift.java | 35 +++++++++---------- 2 files changed, 26 insertions(+), 30 deletions(-) diff --git a/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityRift.java b/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityRift.java index c0d538c..b5ee488 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityRift.java +++ b/src/main/java/StevenDimDoors/mod_pocketDim/tileentities/TileEntityRift.java @@ -48,17 +48,15 @@ public class TileEntityRift extends DDTileEntityBase public Point4D nearestRiftLocation = null; public int spawnedEndermenID = 0; - public int riftRotation; - public int renderKey; - public int growth; + 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); - this.riftRotation = random.nextInt(360); - this.renderKey = random.nextInt(LSystem.curves.size()); } @@ -103,7 +101,7 @@ public class TileEntityRift extends DDTileEntityBase updateNearestRift(); spread(mod_pocketDim.properties); } - growth++; + growth += 1F/(growth+1); updateTimer++; } @@ -151,7 +149,7 @@ public class TileEntityRift extends DDTileEntityBase private void closeRift() { NewDimData dimension = PocketManager.createDimensionData(worldObj); - if (closeTimer == CLOSING_PERIOD / 2) + if (growth < CLOSING_PERIOD / 2) { for (DimLink riftLink : dimension.findRiftsInRange(worldObj, 6, xCoord, yCoord, zCoord)) { @@ -164,7 +162,7 @@ public class TileEntityRift extends DDTileEntityBase } } } - if (closeTimer >= CLOSING_PERIOD && !worldObj.isRemote) + if (growth == 0 && !worldObj.isRemote) { DimLink link = PocketManager.getLink(this.xCoord, this.yCoord, this.zCoord, worldObj); if (link != null) @@ -174,7 +172,8 @@ public class TileEntityRift extends DDTileEntityBase worldObj.setBlockToAir(xCoord, yCoord, zCoord); worldObj.playSound(xCoord + 0.5, yCoord + 0.5, zCoord + 0.5, "mods.DimDoors.sfx.riftClose", 0.7f, 1, false); } - closeTimer++; + + growth --; } public boolean updateNearestRift() @@ -265,7 +264,7 @@ public class TileEntityRift extends DDTileEntityBase this.spawnedEndermenID = nbt.getInteger("spawnedEndermenID"); this.riftRotation = nbt.getInteger("riftRotation"); this.renderKey = nbt.getInteger("renderKey"); - this.growth = nbt.getInteger("growth"); + this.growth = nbt.getFloat("growth"); } @@ -281,7 +280,7 @@ public class TileEntityRift extends DDTileEntityBase nbt.setInteger("spawnedEndermenID", this.spawnedEndermenID); nbt.setInteger("renderKey", this.renderKey); nbt.setInteger("riftRotation", this.riftRotation); - nbt.setInteger("growth", this.growth); + nbt.setFloat("growth", this.growth); } diff --git a/src/main/java/StevenDimDoors/mod_pocketDimClient/RenderRift.java b/src/main/java/StevenDimDoors/mod_pocketDimClient/RenderRift.java index 457c878..762bca4 100644 --- a/src/main/java/StevenDimDoors/mod_pocketDimClient/RenderRift.java +++ b/src/main/java/StevenDimDoors/mod_pocketDimClient/RenderRift.java @@ -35,7 +35,7 @@ public class RenderRift extends TileEntitySpecialRenderer */ TileEntityRift rift = (TileEntityRift) te; // draws the verticies corresponding to the passed it - this.drawCrack(rift.riftRotation, rift.getCurve(), Math.log(2+rift.growth)/5D, xWorld, yWorld, zWorld); + this.drawCrack(rift.riftRotation, rift.getCurve(), rift.growth/15, xWorld, yWorld, zWorld); GL11.glDisable(GL_BLEND); // reenable all the stuff we disabled @@ -83,11 +83,10 @@ public class RenderRift extends TileEntitySpecialRenderer double[] jitters = new double[jCount]; // generate a series of waveforms - for (int i = 0; i < jCount-1; i += 1) + 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; - } @@ -97,24 +96,22 @@ public class RenderRift extends TileEntitySpecialRenderer // 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); + // 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++; + 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))); + 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; @@ -134,10 +131,8 @@ public class RenderRift extends TileEntitySpecialRenderer GL11.glColor4f(.3F, .3F, .3F, .2F); - glBlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ZERO ); - - - + 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); @@ -156,16 +151,18 @@ public class RenderRift extends TileEntitySpecialRenderer 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.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