diff --git a/StevenDimDoors/mod_pocketDim/DDLoot.java b/StevenDimDoors/mod_pocketDim/DDLoot.java index 42266978..41d80a9a 100644 --- a/StevenDimDoors/mod_pocketDim/DDLoot.java +++ b/StevenDimDoors/mod_pocketDim/DDLoot.java @@ -4,7 +4,10 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.Random; +import net.minecraft.inventory.IInventory; import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.util.WeightedRandom; import net.minecraft.util.WeightedRandomChestContent; import net.minecraftforge.common.ChestGenHooks; @@ -33,6 +36,8 @@ public class DDLoot { private static final int RARE_LOOT_WEIGHT = 1; //Same weight as music discs, golden apple private static final int DUNGEON_CHEST_WEIGHT_INFLATION = 10; // (weight of iron ingots in dungeon) / (weight of iron ingots in other chests) + private DDLoot() { } + public static void registerInfo() { DDProperties properties = DDProperties.instance(); @@ -156,4 +161,48 @@ public class DDLoot { //System.out.println(item.theItemId.getDisplayName() + "\t" + item.itemWeight); } } + + public static void generateChestContents(ChestGenHooks chestInfo, IInventory inventory, Random random) + { + //This is a custom version of net.minecraft.util.WeightedRandomChestContent.generateChestContents() + //It's designed to avoid the following bugs in MC 1.5: + //1. The randomized filling algorithm will sometimes overwrite item stacks with other stacks + //2. If multiple enchanted books appear, then they will have the same enchantment + + //The prime number below is used for choosing chest slots in a seemingly-random pattern. Its value + //was selected specifically to achieve a spread-out distribution for chests with up to 104 slots. + //Choosing a prime number ensures that our increments are relatively-prime to the chest size, which + //means we'll cover all the slots before repeating any. This is mathematically guaranteed. + final int primeOffset = 239333; + + int count = chestInfo.getCount(random); + int size = inventory.getSizeInventory(); + WeightedRandomChestContent[] content = chestInfo.getItems(random); + + for (int k = 0; k < count; k++) + { + WeightedRandomChestContent selection = (WeightedRandomChestContent)WeightedRandom.getRandomItem(random, content); + + //Call getChestGenBase() to make sure we generate a different enchantment for books. + //Don't just use a condition to check if the item is an instance of ItemEnchantedBook because + //we don't know if other mods might add items that also need to be regenerated. + selection = selection.theItemId.getItem().getChestGenBase(chestInfo, random, selection); + + ItemStack[] stacks = ChestGenHooks.generateStacks(random, selection.theItemId, selection.theMinimumChanceToGenerateItem, selection.theMaximumChanceToGenerateItem); + + for (ItemStack item : stacks) + { + int limit = size; + int index = random.nextInt(size); + + while (limit > 0 && inventory.getStackInSlot(index) != null) + { + limit--; + index = (index + primeOffset) % size; + } + + inventory.setInventorySlotContents(index, item); + } + } + } } diff --git a/StevenDimDoors/mod_pocketDim/SchematicLoader.java b/StevenDimDoors/mod_pocketDim/SchematicLoader.java index 630b21ff..0cc771c3 100644 --- a/StevenDimDoors/mod_pocketDim/SchematicLoader.java +++ b/StevenDimDoors/mod_pocketDim/SchematicLoader.java @@ -42,7 +42,7 @@ public class SchematicLoader if (dimList.get(destDimID).dungeonGenerator == null) { //TODO: We should centralize RNG initialization and world-seed modifiers for each specific application. - final long localSeed = world.getSeed() ^ 0x2F50DB9B4A8057E4L ^ computeDestinationHash(link); + final long localSeed = world.getSeed() ^ 0x2F50DB9B4A8057E4L ^ calculateDestinationSeed(link); final Random random = new Random(localSeed); dungeonHelper.generateDungeonLink(link, dungeonHelper.getDimDungeonPack(originDimID), random); @@ -155,43 +155,50 @@ public class SchematicLoader return dungeon; } - private static long computeDestinationHash(LinkData link) + private static long calculateDestinationSeed(LinkData link) { //Time for some witchcraft. //The code here is inspired by a discussion on Stack Overflow regarding hash codes for 3D. //Source: http://stackoverflow.com/questions/9858376/hashcode-for-3d-integer-coordinates-with-high-spatial-coherence - //Use 8 bits from Y and 24 bits from X and Z. Mix in 8 bits from the destination dim ID too - that means + //Use 8 bits from Y and 16 bits from X and Z. Mix in 8 bits from the destination dim ID too - that means //even if you aligned two doors perfectly between two pockets, it's unlikely they would lead to the same dungeon. + //We map bits in reverse order to produce more varied RNG output for nearly-identical points. The reason is + //that Java's Random outputs the 32 MSBs of its internal state to produce its output. If the differences + //between two seeds are small (i.e. in the LSBs), then they will tend to produce similar random outputs anyway! + + //Only bother to assign the 48 least-significant bits since Random only takes those bits from its seed. + //NOTE: The casts to long are necessary to get the right results from the bit shifts!!! int bit; int index; long hash; - int w = link.destDimID; - int x = link.destXCoord; - int y = link.destYCoord; - int z = link.destZCoord; + final int w = link.destDimID; + final int x = link.destXCoord; + final int y = link.destYCoord; + final int z = link.destZCoord; hash = 0; - index = 0; + index = 48; for (bit = 0; bit < 8; bit++) { - hash |= ((w >> bit) & 1) << index; - index++; - hash |= ((x >> bit) & 1) << index; - index++; - hash |= ((y >> bit) & 1) << index; - index++; - hash |= ((z >> bit) & 1) << index; - index++; + hash |= (long) ((w >> bit) & 1) << index; + index--; + hash |= (long) ((x >> bit) & 1) << index; + index--; + hash |= (long) ((y >> bit) & 1) << index; + index--; + hash |= (long) ((z >> bit) & 1) << index; + index--; } - for (; bit < 24; bit++) + for (; bit < 16; bit++) { - hash |= ((x >> bit) & 1) << index; - index++; - hash |= ((z >> bit) & 1) << index; - index++; + hash |= (long) ((x >> bit) & 1) << index; + index--; + hash |= (long) ((z >> bit) & 1) << index; + index--; } + return hash; } } \ No newline at end of file diff --git a/StevenDimDoors/mod_pocketDim/dungeon/FillContainersOperation.java b/StevenDimDoors/mod_pocketDim/dungeon/FillContainersOperation.java index 7979eafc..c51df0e5 100644 --- a/StevenDimDoors/mod_pocketDim/dungeon/FillContainersOperation.java +++ b/StevenDimDoors/mod_pocketDim/dungeon/FillContainersOperation.java @@ -10,9 +10,7 @@ import net.minecraft.item.ItemStack; import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntityChest; import net.minecraft.tileentity.TileEntityDispenser; -import net.minecraft.util.WeightedRandomChestContent; import net.minecraft.world.World; -import net.minecraftforge.common.ChestGenHooks; import StevenDimDoors.mod_pocketDim.DDLoot; import StevenDimDoors.mod_pocketDim.schematic.WorldOperation; @@ -42,8 +40,7 @@ public class FillContainersOperation extends WorldOperation TileEntityChest chest = (TileEntityChest) tileEntity; if (isInventoryEmpty(chest)) { - ChestGenHooks info = DDLoot.DungeonChestInfo; - WeightedRandomChestContent.generateChestContents(random, info.getItems(random), chest, info.getCount(random)); + DDLoot.generateChestContents(DDLoot.DungeonChestInfo, chest, random); } } diff --git a/schematics/ruins/rules.txt b/schematics/ruins/rules.txt index ef838c18..a14fe17d 100644 --- a/schematics/ruins/rules.txt +++ b/schematics/ruins/rules.txt @@ -22,14 +22,22 @@ Exit -> DeadEnd Exit DeadEnd -> DeadEnd Exit -? ? ? ? ? ? ? ? -> Trap#20 SimpleHall#40 ComplexHall#10 Exit#20 DeadEnd#10 +? ? ? ? ? ? ? ? ? -> DeadEnd#10 Exit#11 SimpleHall#24 ComplexHall#16 Trap#23 Maze#11 -? ? ? ? -> Trap#18 SimpleHall#40 ComplexHall#10 Exit#18 DeadEnd#10 Hub#4 +? ? ? ? ? ? ? ? -> DeadEnd#9 Exit#10 SimpleHall#24 ComplexHall#16 Trap#23 Maze#11 Hub#6 -? ? ? -> ComplexHall Hub Trap SimpleHall Maze +? ? ? ? ? ? ? -> DeadEnd#8 Exit#9 SimpleHall#25 ComplexHall#17 Trap#23 Maze#11 Hub#7 -? ? -> ComplexHall Hub Trap SimpleHall Maze +? ? ? ? ? ? -> DeadEnd#7 Exit#8 SimpleHall#26 ComplexHall#17 Trap#23 Maze#11 Hub#8 -? -> ComplexHall#40 Hub#30 Trap#10 SimpleHall#10 Maze#10 +? ? ? ? ? -> DeadEnd#6 Exit#6 SimpleHall#27 ComplexHall#18 Trap#23 Maze#11 Hub#9 --> ComplexHall#40 Hub#30 Trap#10 SimpleHall#10 Maze#10 \ No newline at end of file +? ? ? ? -> DeadEnd#5 Exit#5 SimpleHall#28 ComplexHall#18 Trap#23 Maze#11 Hub#10 + +? ? ? -> DeadEnd#3 Exit#3 SimpleHall#29 ComplexHall#19 Trap#23 Maze#11 Hub#11 + +? ? -> SimpleHall#9 ComplexHall#8 Trap#17 Maze#23 Hub#44 + +? -> SimpleHall#9 ComplexHall#8 Trap#17 Maze#23 Hub#44 + +-> SimpleHall#2 ComplexHall#54 Trap#2 Maze#2 Hub#41