From 53568707f09895de12b1893784b3a688d6c8d8bc Mon Sep 17 00:00:00 2001 From: Mathijs Riezebos Date: Fri, 5 May 2017 17:35:02 +0200 Subject: [PATCH] Mapping coordinates to Pocket IDs and back -Changed the Pocket placement algorithm. Instead of following a rectangular spiral path expanding outwards from (0;0), Pockets now get placed in a fan-shaped area expanding from (0;0) to (infinity;infinity). -Changed maximum configurable grid size and defaulted to that -Added a way to retrieve the Pocket ID from a Location -Schematic loading streams are only closed if they were opened to begin with -Added some easier ways of testing if a Dimension is a Pocket dimension --- .../com/zixiken/dimdoors/shared/DDConfig.java | 14 ++-- .../com/zixiken/dimdoors/shared/Pocket.java | 37 +++++++--- .../dimdoors/shared/PocketRegistry.java | 67 ++++++++++++++++--- .../dimdoors/shared/PocketTemplate.java | 2 +- .../dimdoors/shared/SchematicHandler.java | 27 +++++--- .../shared/world/DimDoorDimensions.java | 28 ++++++-- 6 files changed, 134 insertions(+), 41 deletions(-) diff --git a/src/main/java/com/zixiken/dimdoors/shared/DDConfig.java b/src/main/java/com/zixiken/dimdoors/shared/DDConfig.java index 2611ac66..f61ceb78 100644 --- a/src/main/java/com/zixiken/dimdoors/shared/DDConfig.java +++ b/src/main/java/com/zixiken/dimdoors/shared/DDConfig.java @@ -23,8 +23,8 @@ public class DDConfig { public static final boolean HAVE_CONFIG_DEFAULTS_BEEN_CHECKED_FOR_CORRECTNESS = false; //@todo check this at each non-alpha release. This field does not have a use in the mod itself, but should ensure that the developers of this mod, don't forget to reset the config defaults to the right values before releasing a non-alpha release public static File configurationFolder; - private static int pocketGridSize = 8; - private static int maxPocketSize = 4; + private static int pocketGridSize = 32; + private static int maxPocketSize = 15; private static int privatePocketSize = 3; private static int publicPocketSize = 2; private static int baseDimID = 684; @@ -68,17 +68,17 @@ public class DDConfig { //@todo a comment in the config files about how these values only influence new worlds Property prop; pocketGridSize = setConfigIntWithMaxAndMin(config, Configuration.CATEGORY_GENERAL, "pocketGridSize", pocketGridSize, - "Sets how many chunks apart all pockets in pocket dimensions should be placed. [min: 4, max: 16, default: 8]", 4, 16); + "Sets how many chunks apart all pockets in pocket dimensions should be placed. [min: 4, max: 32, default: 32]", 4, 32); DimDoors.log(DDConfig.class, "pocketGridSize was set to " + pocketGridSize); maxPocketSize = setConfigIntWithMaxAndMin(config, Configuration.CATEGORY_GENERAL, "maxPocketSize", maxPocketSize, - "Sets how deep and wide any pocket can be. [min: 1, max: pocketGridSize/2, default: 4]", 1, (int) (((double) pocketGridSize / 2) - 0.5)); + "Sets how deep and wide any pocket can be. [min: 0, max: pocketGridSize/2, default: 4]", 0, (int) (((double) pocketGridSize / 2) - 0.5)); privatePocketSize = setConfigIntWithMaxAndMin(config, Configuration.CATEGORY_GENERAL, "privatePocketSize", privatePocketSize, - "Sets how deep and wide any personal pocket can be. [min: 1, max: maxPocketsSize, default: 3]", 1, maxPocketSize); + "Sets how deep and wide any personal pocket can be. [min: 0, max: maxPocketsSize, default: 3]", 0, maxPocketSize); publicPocketSize = setConfigIntWithMaxAndMin(config, Configuration.CATEGORY_GENERAL, "publicPocketSize", publicPocketSize, - "Sets how deep and wide any public pocket can be. [min: 1, max: maxPocketsSize, default: 2]", 1, maxPocketSize); + "Sets how deep and wide any public pocket can be. [min: 0, max: maxPocketsSize, default: 2]", 0, maxPocketSize); prop = config.get(Configuration.CATEGORY_GENERAL, "dungeonSchematicNames", dungeonSchematicNames, "List of names of Pockets' jSon- and Schematic file names excluding extension. Custom json and schematic files can be dropped in the corresponding folders."); @@ -109,9 +109,11 @@ public class DDConfig { prop = config.get(Configuration.CATEGORY_GENERAL, "dangerousLimboMonolithsDisabled", DangerousLimboMonolithsDisabled, "Is Monoliths Dangerous in Limbo disabled?"); + DangerousLimboMonolithsDisabled = prop.getBoolean(); prop = config.get(Configuration.CATEGORY_GENERAL, "dangerousLimboMonolithsDisabled", MonolithTeleportationEnabled, "Is Monolith Teleportation disabled?"); + MonolithTeleportationEnabled = prop.getBoolean(); checkAndCorrectDoorRelativeDepths(config); diff --git a/src/main/java/com/zixiken/dimdoors/shared/Pocket.java b/src/main/java/com/zixiken/dimdoors/shared/Pocket.java index 67500798..ac535eed 100644 --- a/src/main/java/com/zixiken/dimdoors/shared/Pocket.java +++ b/src/main/java/com/zixiken/dimdoors/shared/Pocket.java @@ -28,7 +28,7 @@ import net.minecraft.world.WorldServer; public class Pocket { private int ID; //this gets reset every server-load - private final int size; //in chunks + private final int size; //in chunks 0 -> 1*1 chunk, 1 -> 2*2 chunks private final int depth; private final EnumPocketType typeID; // dungeon, pocket, or personal pocket private final int x; //pocket-relative 0 coordinate, should be at x * PocketRegistry.INSTANCE.gridSize * 16 @@ -78,7 +78,7 @@ public class Pocket { public void setID(int newID) { ID = newID; - + //propagate this ID to the rifts in this pocket for (int riftID : riftIDs) { Location riftLocation = RiftRegistry.INSTANCE.getRiftLocation(riftID); @@ -103,9 +103,9 @@ public class Pocket { riftIDs.add(doorID); } Location depthZeroLocation = Location.readFromNBT(pocketNBT.getCompoundTag("depthZeroLocation")); - + Pocket pocket = new Pocket(size, depth, typeID, x, z, riftIDs, depthZeroLocation); - + pocket.setID(pocketNBT.getInteger("ID")); //basically re-register the pocket NBTTagList playersTagList = (NBTTagList) pocketNBT.getTag("playerUUIDs"); for (int i = 0; i < playersTagList.tagCount(); i++) { @@ -167,15 +167,34 @@ public class Pocket { public void validatePlayerEntry(EntityPlayer player) { String playerUUID = player.getCachedUniqueIdString(); - for (String allowedPlayerUUID : playerUUIDs) { - if (allowedPlayerUUID.equals(playerUUID)) { - return; - } + if (!playerUUIDs.contains(playerUUID)) { //the 'contains' method uses the 'equals' method to check, so for Strings, this should work. + playerUUIDs.add(playerUUID); } - playerUUIDs.add(playerUUID); + } + + public boolean isPlayerAllowedInPocket(EntityPlayer player) { + String playerUUID = player.getCachedUniqueIdString(); + return playerUUIDs.contains(playerUUID); } public void setDepthZeroLocation(Location teleportTargetLocation) { depthZeroLocation.loadfrom(teleportTargetLocation); } + + boolean isLocationWithinPocketBounds(final Location location, final int gridSize) { + int locX = location.getPos().getX(); + int locZ = location.getPos().getY(); + //minimum bounds of the pocket + int pocX = x * gridSize; + int pocZ = z * gridSize; + if (pocX <= locX && pocZ <= locZ) { + //convert to maximum bounds of the pocket + pocX = pocX + (size + 1) * 16; + pocZ = pocZ + (size + 1) * 16; + if (locX < pocX && locZ < pocZ) { + return true; + } + } + return false; + } } diff --git a/src/main/java/com/zixiken/dimdoors/shared/PocketRegistry.java b/src/main/java/com/zixiken/dimdoors/shared/PocketRegistry.java index 358be45f..418b3e40 100644 --- a/src/main/java/com/zixiken/dimdoors/shared/PocketRegistry.java +++ b/src/main/java/com/zixiken/dimdoors/shared/PocketRegistry.java @@ -13,6 +13,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagList; @@ -136,11 +137,11 @@ public class PocketRegistry { nbt.setTag("nextUnusedIDs", nextUnusedIDTagCompound); NBTTagCompound privatePocketsTagCompound = new NBTTagCompound(); - for (String UUID: privatePockets.keySet()) { + for (String UUID : privatePockets.keySet()) { privatePocketsTagCompound.setInteger(UUID, privatePockets.get(UUID)); } nbt.setTag("privatePockets", privatePocketsTagCompound); - + NBTTagCompound pocketsTagCompound = new NBTTagCompound(); for (EnumPocketType pocketType : pocketLists.keySet()) { Map pocketList = pocketLists.get(pocketType); @@ -197,7 +198,7 @@ public class PocketRegistry { return generatePocketAt(typeID, depth, origRiftLocation, pocketTemplate); } - + public Pocket generatePocketAt(EnumPocketType typeID, int depth, Location origRiftLocation, PocketTemplate pocketTemplate) { //Getting the physical grid-location and the Overworld coordinates Location shortenedLocation = getGenerationlocation(nextUnusedIDs.get(typeID), typeID); @@ -221,19 +222,32 @@ public class PocketRegistry { public int getPrivateDimDoorID(String playerUUID) { if (!privatePockets.containsKey(playerUUID)) { //generate a new private pocket - int doorID = getEntranceDoorIDOfNewPocket(EnumPocketType.PRIVATE, 0, new Location(0,0,0,0)); //Location doesn't really matter in this case + int doorID = getEntranceDoorIDOfNewPocket(EnumPocketType.PRIVATE, 0, new Location(0, 0, 0, 0)); //Location doesn't really matter in this case privatePockets.put(playerUUID, doorID); return doorID; - } + } return privatePockets.get(playerUUID); } - private Location getGenerationlocation(int nextUnusedID, EnumPocketType typeID) { - int x = getSimpleX(nextUnusedID); + private Location getGenerationlocation(final int nextUnusedID, EnumPocketType typeID) { + int x; int y = 0; - int z = getSimpleZ(nextUnusedID); + int z; int dimID = DimDoorDimensions.getPocketDimensionType(typeID).getId(); - + if (nextUnusedID == 0) { + x = 0; + z = 0; + } else { + int radius = (int) Math.sqrt(nextUnusedID); //casting to int rounds down the double resulting from taking the square root + int radiusNumber = nextUnusedID - (radius * radius); + double splitter = ((double) radiusNumber) / ((double) radius); //always between 0 and 2 + DimDoors.log(this.getClass(), "id is " + nextUnusedID); + DimDoors.log(this.getClass(), "Radius is " + radius); + DimDoors.log(this.getClass(), "Radius number is " + radiusNumber); + DimDoors.log(this.getClass(), "Splitter is " + splitter); + x = splitter <= 1.0 ? radius : radius - (radiusNumber - radius); + z = splitter >= 1.0 ? radius : radiusNumber; + } Location location = new Location(dimID, x, y, z); return location; } @@ -250,6 +264,7 @@ public class PocketRegistry { } } + /* private int getSimpleX(int ID) { //@todo check for smaller than 0 if (ID == 0) { @@ -300,4 +315,38 @@ public class PocketRegistry { } return group; } + */ + private int getPocketIDFromCoords(Location location) { + final int dimID = location.getDimensionID(); + if (DimDoorDimensions.isPocketDimensionID(dimID)) { + int x = location.getPos().getX(); + int z = location.getPos().getZ(); + int shortX = x / (gridSize * 16); + int shortZ = z / (gridSize * 16); + if (shortX >= shortZ) { + return shortX * shortX + shortZ; + } else { + return (shortZ + 2) * shortZ - shortX; + } + } + return -1; //not in a pocket dimension + } + + public boolean isPlayerAllowedToBeHere(final EntityPlayerMP player, final Location location) { + if (player.isCreative()) { + return true; + } else { + int pocketID = getPocketIDFromCoords(location); + if (pocketID < 0) { //not in a pocket dimension + return true; + } else { + EnumPocketType type = DimDoorDimensions.getPocketType(location.getDimensionID()); + Pocket pocket = pocketLists.get(type).get(pocketID); + if (pocket.isPlayerAllowedInPocket(player) && pocket.isLocationWithinPocketBounds(location, gridSize)) { + return true; + } + return false; + } + } + } } diff --git a/src/main/java/com/zixiken/dimdoors/shared/PocketTemplate.java b/src/main/java/com/zixiken/dimdoors/shared/PocketTemplate.java index a6bab82c..c24ce0bc 100644 --- a/src/main/java/com/zixiken/dimdoors/shared/PocketTemplate.java +++ b/src/main/java/com/zixiken/dimdoors/shared/PocketTemplate.java @@ -44,7 +44,7 @@ public class PocketTemplate { //there is exactly one pocket placer for each diff this.weights = weights; //chance that this Pocket will get generated this.minDepth = minDepth; //pocket will only be generated from this Pocket-depth this.maxDepth = maxDepth; //to this pocket depth - this.size = size; //size of content of pocket in chunks (walls are 5 thick, so size 0 will be 6*6 blocks, size 1 will be 22*22 blocks, etc. + this.size = size; //size of pocket in chunks (0 -> 1*1 chunk, 1 -> 2*2 chunks etc.) this.schematic = schematic; this.typeID = typeID; } diff --git a/src/main/java/com/zixiken/dimdoors/shared/SchematicHandler.java b/src/main/java/com/zixiken/dimdoors/shared/SchematicHandler.java index 2f110ec4..5f280753 100644 --- a/src/main/java/com/zixiken/dimdoors/shared/SchematicHandler.java +++ b/src/main/java/com/zixiken/dimdoors/shared/SchematicHandler.java @@ -49,7 +49,7 @@ public class SchematicHandler { final private Map> dungeonNameMap = new HashMap(); //@todo, sort templates by depth over here? that'd mean that that doesn't have to be done on pocket placement each and every time - PocketTemplate getRandomDungeonPocketTemplate(int depth, int maxPocketSize) { + PocketTemplate getRandomDungeonPocketTemplate(int depth, int maxPocketSize) { //@todo maxPocketSize is passed for no reason at all here; pockets exceeding maxPocketSize have not been loaded in the first place... List validTemplates = new ArrayList(); int totalWeight = 0; for (PocketTemplate template : dungeonTemplates) { @@ -168,7 +168,7 @@ public class SchematicHandler { //DimDoors.log(SchematicHandler.class, "Checkpoint 4 reached; " + validTemplates.size() + " templates were loaded"); String subDirectory = jsonTemplate.get("directory").getAsString(); //get the subfolder in which the schematics are stored - + for (PocketTemplate template : validTemplates) { //it's okay to "tap" this for-loop, even if validTemplates is empty. String extendedTemplatelocation = subDirectory.equals("") ? template.getName() : subDirectory + "/" + template.getName(); //transform the filename accordingly @@ -180,19 +180,24 @@ public class SchematicHandler { //determine which location to load the schematic file from (and what format) DataInputStream schematicDataStream = null; + boolean streamOpened = false; if (schematicStream != null) { schematicDataStream = new DataInputStream(schematicStream); + streamOpened = true; } else if (oldVersionSchematicStream != null) { schematicDataStream = new DataInputStream(oldVersionSchematicStream); + streamOpened = true; } else if (schematicFile.exists()) { try { schematicDataStream = new DataInputStream(new FileInputStream(schematicFile)); + streamOpened = true; } catch (FileNotFoundException ex) { Logger.getLogger(SchematicHandler.class.getName()).log(Level.SEVERE, "Schematic file " + template.getName() + ".schem did not load correctly from config folder.", ex); } } else if (oldVersionSchematicFile.exists()) { try { schematicDataStream = new DataInputStream(new FileInputStream(oldVersionSchematicFile)); + streamOpened = true; } catch (FileNotFoundException ex) { Logger.getLogger(SchematicHandler.class.getName()).log(Level.SEVERE, "Schematic file " + template.getName() + ".schematic did not load correctly from config folder.", ex); } @@ -202,17 +207,19 @@ public class SchematicHandler { NBTTagCompound schematicNBT; Schematic schematic = null; - try { - schematicNBT = CompressedStreamTools.readCompressed(schematicDataStream); - schematic = Schematic.loadFromNBT(schematicNBT, template.getName()); - schematicDataStream.close(); - } catch (IOException ex) { - Logger.getLogger(SchematicHandler.class.getName()).log(Level.SEVERE, "Schematic file for " + template.getName() + " could not be read as a valid schematic NBT file.", ex); - } finally { + if (streamOpened) { try { + schematicNBT = CompressedStreamTools.readCompressed(schematicDataStream); + schematic = Schematic.loadFromNBT(schematicNBT, template.getName()); schematicDataStream.close(); } catch (IOException ex) { - Logger.getLogger(SchematicHandler.class.getName()).log(Level.SEVERE, "Error occured while closing schematicDataStream", ex); + Logger.getLogger(SchematicHandler.class.getName()).log(Level.SEVERE, "Schematic file for " + template.getName() + " could not be read as a valid schematic NBT file.", ex); + } finally { + try { + schematicDataStream.close(); + } catch (IOException ex) { + Logger.getLogger(SchematicHandler.class.getName()).log(Level.SEVERE, "Error occured while closing schematicDataStream", ex); + } } } diff --git a/src/main/java/com/zixiken/dimdoors/shared/world/DimDoorDimensions.java b/src/main/java/com/zixiken/dimdoors/shared/world/DimDoorDimensions.java index 6f9bf471..9c1660a1 100644 --- a/src/main/java/com/zixiken/dimdoors/shared/world/DimDoorDimensions.java +++ b/src/main/java/com/zixiken/dimdoors/shared/world/DimDoorDimensions.java @@ -17,25 +17,32 @@ import net.minecraftforge.common.DimensionManager; public class DimDoorDimensions { public static DimensionType LIMBO; - private static Map pocketDimensionTypes = new HashMap<>(); - public static List CUSTOM; + private static int minPocketDimID; + private static int maxPocketDimID; + private static final List pocketTypes = new ArrayList<>(); + private static final Map pocketDimensionTypes = new HashMap<>(); + private static final List CUSTOM = new ArrayList<>(); public static void init() { int dimID = DDConfig.getBaseDimID(); LIMBO = DimensionType.register("Limbo", "_limbo", dimID, WorldProviderLimbo.class, false); - dimID++; + dimID++; //@todo make this a loop over a function + minPocketDimID = dimID; + pocketTypes.add(EnumPocketType.PRIVATE); pocketDimensionTypes.put(EnumPocketType.PRIVATE, DimensionType.register("Private", "_private", dimID, WorldProviderPersonalPocket.class, false)); dimID++; + pocketTypes.add(EnumPocketType.PUBLIC); pocketDimensionTypes.put(EnumPocketType.PUBLIC, DimensionType.register("Public", "_public", dimID, WorldProviderPublicPocket.class, false)); dimID++; + maxPocketDimID = dimID; + pocketTypes.add(EnumPocketType.DUNGEON); pocketDimensionTypes.put(EnumPocketType.DUNGEON, DimensionType.register("Dungeon", "_dungeon", dimID, WorldProviderDungeonPocket.class, false)); registerDimension(LIMBO); - for(EnumPocketType pocketType: pocketDimensionTypes.keySet()) { + for (EnumPocketType pocketType : pocketDimensionTypes.keySet()) { registerDimension(pocketDimensionTypes.get(pocketType)); } - CUSTOM = new ArrayList<>(); for (int i = 0; i < 0; i++) { //@todo: For future use? Like, server owners can add their own set of DimDoors DimensionTypes via the configs? Or is this nonsense? dimID++; DimensionType tempType = DimensionType.register("Name", "_name", dimID, WorldProvider.class, false); @@ -47,8 +54,17 @@ public class DimDoorDimensions { public static void registerDimension(DimensionType dimension) { DimensionManager.registerDimension(dimension.getId(), dimension); } - + public static DimensionType getPocketDimensionType(EnumPocketType pocketType) { return pocketDimensionTypes.get(pocketType); } + + public static boolean isPocketDimensionID(int id) { + return id >= minPocketDimID && id <= maxPocketDimID; + } + + public static EnumPocketType getPocketType(int dimID) { + int index = dimID - minPocketDimID; + return pocketTypes.get(index); + } }