From 5c383bde1db9088f31b9b748e27480126c21482f Mon Sep 17 00:00:00 2001 From: Mathijs Riezebos Date: Tue, 24 Jan 2017 00:45:16 +0100 Subject: [PATCH] Finished Pocket creation -Added dependency on Vazkii's Pillar mod for "schematic" loading -Added config directory for DimDoors -Fixed entrance door placement coords -Refractored some methods -Added json-reader functionality -Code compiles now Todo: -Make code added in SchematicHandler more modular -Game gets stuck on world-load. Probably because the default json file for "defaultPersonal" is not available yet at the saves directory. --- build.gradle | 8 + .../java/com/zixiken/dimdoors/DDConfig.java | 15 +- .../dimdoors/shared/PocketTemplate.java | 58 +++++-- .../dimdoors/shared/SchematicHandler.java | 154 ++++++++++++++++-- 4 files changed, 202 insertions(+), 33 deletions(-) diff --git a/build.gradle b/build.gradle index 6d5b7fe3..3a59e0ae 100644 --- a/build.gradle +++ b/build.gradle @@ -33,8 +33,16 @@ minecraft { // makeObfSourceJar = false // an Srg named sources jar is made by default. uncomment this to disable. } +repositories { + ivy { + name "Pillar" + artifactPattern "https://addons-origin.cursecdn.com/files/2318/492/[module]-[revision].[ext]" + } +} + dependencies { compile 'com.flowpowered:flow-math:1.0.3' + compile name: 'Pillar', version: '1.0-5', ext: 'jar' } processResources diff --git a/src/main/java/com/zixiken/dimdoors/DDConfig.java b/src/main/java/com/zixiken/dimdoors/DDConfig.java index 35545d2f..e6df22b6 100644 --- a/src/main/java/com/zixiken/dimdoors/DDConfig.java +++ b/src/main/java/com/zixiken/dimdoors/DDConfig.java @@ -5,8 +5,12 @@ */ package com.zixiken.dimdoors; +import java.io.File; +import java.io.IOException; import java.util.ArrayList; import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; import net.minecraftforge.common.config.Configuration; import net.minecraftforge.common.config.Property; import net.minecraftforge.fml.common.event.FMLPreInitializationEvent; @@ -17,11 +21,12 @@ import net.minecraftforge.fml.common.event.FMLPreInitializationEvent; */ public class DDConfig { + public static File configurationFolder; private static int pocketGridSize = 8; private static int maxPocketSize = 4; private static int privatePocketSize = 3; private static int publicPocketSize = 2; - private static String[] dungeonSchematicNames = {"", ""}; //@todo set default dungeon names + private static String[] dungeonSchematicNames = {}; //@todo set default dungeon names private static int setConfigIntWithMaxAndMin(Configuration config, String category, String key, int defaultValue, String comment, int minValue, int maxValue) { Property prop = config.get(category, key, defaultValue, @@ -39,6 +44,14 @@ public class DDConfig { public static void loadConfig(FMLPreInitializationEvent event) { // Load config + configurationFolder = new File(event.getModConfigurationDirectory(), "/DimDoors"); + if (!configurationFolder.exists()) { + try { + configurationFolder.createNewFile(); + } catch (IOException ex) { + Logger.getLogger(DDConfig.class.getName()).log(Level.SEVERE, "Dimdoors config folder could not be created.", ex); + } + } Configuration config = new Configuration(event.getSuggestedConfigurationFile()); config.load(); diff --git a/src/main/java/com/zixiken/dimdoors/shared/PocketTemplate.java b/src/main/java/com/zixiken/dimdoors/shared/PocketTemplate.java index 579e43a6..a6aa9d57 100644 --- a/src/main/java/com/zixiken/dimdoors/shared/PocketTemplate.java +++ b/src/main/java/com/zixiken/dimdoors/shared/PocketTemplate.java @@ -8,14 +8,19 @@ package com.zixiken.dimdoors.shared; import com.zixiken.dimdoors.DimDoors; import com.zixiken.dimdoors.blocks.ModBlocks; import com.zixiken.dimdoors.tileentities.DDTileEntityBase; +import java.util.Random; import net.minecraft.block.BlockDoor; import net.minecraft.block.BlockDoor.EnumDoorHalf; import net.minecraft.block.state.IBlockState; import net.minecraft.init.Blocks; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.EnumFacing; +import net.minecraft.util.Rotation; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; +import net.minecraft.world.WorldServer; +import vazkii.pillar.schema.StructureSchema; +import vazkii.pillar.StructureGenerator; /** * @@ -23,20 +28,26 @@ import net.minecraft.world.World; */ class PocketTemplate { //there is exactly one pocket placer for each different schematic that is loaded into the game (a Json might load several schematics though) - private final int[] weights; //weights for chanced generation of dungeons per depth level | weights[0] is the weight for depth "minDepth" - private final int minDepth; - private final int maxDepth; + //generation parameters + private StructureSchema schematic; private final int size; - private final Schematic schematic; private final int entranceDoorX; private final int entranceDoorY; private final int entranceDoorZ; - private final EnumPocketType typeID; private final int wallThickness; //determines the thickness of the wall around the pocket. Set to 1 to only generate the "bedRock" outer layer private final int floorThickness; private final int roofThickness; + private final EnumPocketType typeID; + //selection parameters + private final String variantName; + private final int minDepth; + private final int maxDepth; + private final int[] weights; //weights for chanced generation of dungeons per depth level | weights[0] is the weight for depth "minDepth" - public PocketTemplate(int minDepth, int maxDepth, int[] weights, int size, Schematic schematic, int entranceDoorX, int entranceDoorY, int entranceDoorZ, EnumPocketType typeID, int wallThickness, int floorThickness, int roofThickness) { + //this class should contain the actual schematic info, as well as some of the Json info (placement of Rifts and stuff) + public PocketTemplate(String variantName, StructureSchema schematic, int size, int entranceDoorX, int entranceDoorY, int entranceDoorZ, int wallThickness, int floorThickness, int roofThickness, EnumPocketType typeID, + int minDepth, int maxDepth, int[] weights) { + this.variantName = variantName; 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 @@ -51,8 +62,11 @@ class PocketTemplate { //there is exactly one pocket placer for each different s this.roofThickness = roofThickness; } - //@todo about everything - //this class should contain the actual schematic info, as well as some of the Json info (placement of Rifts and stuff) + public PocketTemplate(String variantName, int size, int entranceDoorX, int entranceDoorY, int entranceDoorZ, int wallThickness, int floorThickness, int roofThickness, EnumPocketType typeID, + int minDepth, int maxDepth, int[] weights) { + this(variantName, null, size, entranceDoorX, entranceDoorY, entranceDoorZ, wallThickness, floorThickness, roofThickness, typeID, minDepth, maxDepth, weights); + } + int getSize() { return size; } @@ -64,7 +78,7 @@ class PocketTemplate { //there is exactly one pocket placer for each different s int getMaxDepth() { return maxDepth; } - + int getWeight(int depth) { int index = depth - minDepth; if (index >= 0 && index < weights.length) { @@ -73,6 +87,18 @@ class PocketTemplate { //there is exactly one pocket placer for each different s return 0; //do not generate } + String getName() { + return variantName; + } + + Object getSchematic() { + return schematic; + } + + void setSchematic(StructureSchema schematic) { + this.schematic = schematic; + } + int place(int xBase, int yBase, int zBase, int dimID) { //returns the riftID of the entrance DimDoor IBlockState outerWallBlock = ModBlocks.blockDimWall.getStateFromMeta(2); //@todo, does this return the correct wall? IBlockState innerWallBlock; @@ -85,7 +111,7 @@ class PocketTemplate { //there is exactly one pocket placer for each different s entryDoorBlock = ModBlocks.blockDimDoor.getDefaultState(); } - World world = DimDoors.proxy.getWorldServer(dimID); + WorldServer world = DimDoors.proxy.getWorldServer(dimID); int hLimit = (size + 1) * 16; //horizontal relative limit int yLimit = roofThickness > 0 ? hLimit : 256 - yBase; //vertical relative limit (build-height + 1) @@ -172,16 +198,20 @@ class PocketTemplate { //there is exactly one pocket placer for each different s } } } - //@todo Place content from schematic starting at (wallthickness, floorthickness, wallthickness) - + + BlockPos dungeonBasePos = new BlockPos(xBase + wallThickness, yBase + floorThickness, zBase + wallThickness); + + //Place the Dungeon content structure + StructureGenerator.placeStructureAtPosition(new Random(), schematic, Rotation.NONE, world, dungeonBasePos, true); + //Place the door - BlockPos doorPos = new BlockPos(entranceDoorX, entranceDoorY, entranceDoorZ); + BlockPos doorPos = dungeonBasePos.offset(EnumFacing.EAST, entranceDoorX).offset(EnumFacing.UP, entranceDoorY).offset(EnumFacing.SOUTH, entranceDoorZ); EnumFacing facing = getAdjacentAirBlockFacing(world, doorPos); entryDoorBlock = entryDoorBlock.withProperty(BlockDoor.FACING, facing); world.setBlockState(doorPos, entryDoorBlock.withProperty(BlockDoor.HALF, EnumDoorHalf.UPPER)); world.setBlockState(doorPos, entryDoorBlock.withProperty(BlockDoor.HALF, EnumDoorHalf.LOWER)); TileEntity newTileEntity = world.getTileEntity(doorPos); - + //Register the rift and return its ID if (newTileEntity instanceof DDTileEntityBase) { DDTileEntityBase newTileEntityDimDoor = (DDTileEntityBase) newTileEntity; diff --git a/src/main/java/com/zixiken/dimdoors/shared/SchematicHandler.java b/src/main/java/com/zixiken/dimdoors/shared/SchematicHandler.java index d701bbaa..3df64495 100644 --- a/src/main/java/com/zixiken/dimdoors/shared/SchematicHandler.java +++ b/src/main/java/com/zixiken/dimdoors/shared/SchematicHandler.java @@ -5,10 +5,26 @@ */ package com.zixiken.dimdoors.shared; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; import com.zixiken.dimdoors.DDConfig; +import com.zixiken.dimdoors.DimDoors; +import java.io.File; +import java.io.IOException; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Paths; import java.util.ArrayList; import java.util.List; import java.util.Random; +import java.util.Scanner; +import java.util.logging.Level; +import java.util.logging.Logger; +import vazkii.pillar.StructureLoader; +import vazkii.pillar.schema.StructureSchema; /** * @@ -17,22 +33,23 @@ import java.util.Random; public class SchematicHandler { public static final SchematicHandler Instance = new SchematicHandler(); - private PocketTemplate personalPocketSchematic; - private PocketTemplate publicPocketSchematic; - private List dungeonSchematics; + private PocketTemplate personalPocketTemplate; + private PocketTemplate publicPocketTemplate; + private List dungeonTemplates; + //@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 getPersonalPocketSchematic(int maxPocketSize) { - return personalPocketSchematic; + return personalPocketTemplate; } PocketTemplate getPublicPocketSchematic(int maxPocketSize) { - return publicPocketSchematic; + return publicPocketTemplate; } PocketTemplate getRandomDungeonPocketTemplate(int depth, int maxPocketSize) { List validTemplates = new ArrayList(); int totalWeight = 0; - for (PocketTemplate template : dungeonSchematics) { + for (PocketTemplate template : dungeonTemplates) { if (template.getMinDepth() > depth || template.getMaxDepth() < depth) { //do nothing } else { @@ -40,11 +57,11 @@ public class SchematicHandler { totalWeight += template.getWeight(depth); } } - + Random random = new Random(); int chosenTemplatePointer = random.nextInt(totalWeight); for (PocketTemplate template : validTemplates) { - if (chosenTemplatePointer < 0) { + if (chosenTemplatePointer < 0) { return template; } chosenTemplatePointer -= template.getWeight(depth); @@ -53,23 +70,124 @@ public class SchematicHandler { } public void loadSchematics() { - personalPocketSchematic = loadSchematicsFromJson("defaultPersonal", PocketRegistry.Instance.getPrivatePocketSize()).get(0); - publicPocketSchematic = loadSchematicsFromJson("defaultPublic", PocketRegistry.Instance.getPublicPocketSize()).get(0); - dungeonSchematics = new ArrayList(); + //@todo, extend the Pillar StructureLoader, so we can load the structures from a different location? + StructureLoader.loadStructures(DimDoors.getDefWorld()); //@todo change this to get the DimDoors Dimension? + personalPocketTemplate = loadTemplatesFromJson("defaultPersonal", PocketRegistry.Instance.getPrivatePocketSize()).get(0); + publicPocketTemplate = loadTemplatesFromJson("defaultPublic", PocketRegistry.Instance.getPublicPocketSize()).get(0); + dungeonTemplates = new ArrayList(); List dungeonSchematicNameStrings = DDConfig.getDungeonSchematicNames(); int maxPocketSize = PocketRegistry.Instance.getMaxPocketSize(); for (String nameString : dungeonSchematicNameStrings) { - List schematics = loadSchematicsFromJson(nameString, maxPocketSize); - if (schematics != null) { - for (PocketTemplate schematic : schematics) { - dungeonSchematics.add(schematic); + List templates = loadTemplatesFromJson(nameString, maxPocketSize); + if (templates != null) { + for (PocketTemplate template : templates) { + if (template != null && template.getSchematic() != null) { + dungeonTemplates.add(template); + } } } } } - private List loadSchematicsFromJson(String nameString, int maxPocketSize) { //depending on the "jSonType" value in the jSon, this might load several variations of a pocket at once - //check for json files in both directories (inside the mod jar, and inside the dimdoors config folder) - //check if the json has a "variant" with the correct pocket size, if it doesn't, pick the largest smaller variant. If there's only bigger variants, cancel + private List loadTemplatesFromJson(String nameString, int maxPocketSize) { //depending on the "jSonType" value in the jSon, this might load several variations of a pocket at once, hence loadTemplate -->s<-- + File jsonFolder = new File(DDConfig.configurationFolder, "/Jsons"); + File jsonFile = new File(jsonFolder, "/" + nameString + ".json"); + String jsonString = null; + try { + jsonString = readFile(jsonFile.getAbsolutePath(), StandardCharsets.UTF_8); + } catch (IOException ex) { + Logger.getLogger(SchematicHandler.class.getName()).log(Level.SEVERE, "Template Json file for template " + nameString + " was not found in template folder.", ex); + } + JsonParser parser = new JsonParser(); + JsonElement jsonElement = parser.parse(jsonString); + JsonObject jsonTemplate = jsonElement.getAsJsonObject(); + List validTemplates = getAllValidVariations(jsonTemplate, maxPocketSize); + + for (PocketTemplate template : validTemplates) { //it's okay to "tap" this for-loop, even if validTemplates is empty. + StructureSchema schematic = StructureLoader.loadedSchemas.get(template.getName()); + template.setSchematic(schematic); + //@todo make sure that the dungeon content fits inside the pocket walls (and floor and roof) and otherwise ¿crop it? + } + //@todo check for json files in both directories (inside the mod jar, and inside the dimdoors config folder) + return validTemplates; + } + + static String readFile(String path, Charset encoding) + throws IOException { + byte[] encoded = Files.readAllBytes(Paths.get(path)); + return new String(encoded, encoding); + } + + private List getAllValidVariations(JsonObject jsonTemplate, int maxPocketSize) { + String jsonType = jsonTemplate.get("jsonType").getAsString(); + EnumPocketType pocketType = EnumPocketType.getFromInt(jsonTemplate.get("pocketType").getAsInt()); + JsonArray variations = jsonTemplate.getAsJsonArray("variations"); + + List pocketTemplates = new ArrayList(); + if (jsonType.equals("Singular")) { //@todo, make sure there is only one Json-reader block, instead of one and its copy + JsonObject chosenVariation = null; + int chosenVariationSize = 0; + for (int i = 0; i < variations.size(); i++) { + JsonObject variation = variations.get(i).getAsJsonObject(); + int variationSize = variation.get("size").getAsInt(); + if (variationSize <= maxPocketSize && variationSize > chosenVariationSize) { + chosenVariationSize = variationSize; + chosenVariation = variation; + if (variationSize == maxPocketSize) { + break; //this one gets chosen + } + } + } + if (chosenVariation != null) { + //this block equals + String variantName = chosenVariation.get("variantName").getAsString(); + int entranceDoorX = chosenVariation.get("entranceDoorX").getAsInt(); + int entranceDoorY = chosenVariation.get("entranceDoorY").getAsInt(); + int entranceDoorZ = chosenVariation.get("entranceDoorZ").getAsInt(); + int wallThickness = chosenVariation.get("wallThickness").getAsInt(); + int floorThickness = chosenVariation.get("floorThickness").getAsInt(); + int roofThickness = chosenVariation.get("roofThickness").getAsInt(); + EnumPocketType typeID = EnumPocketType.getFromInt(chosenVariation.get("typeID").getAsInt()); + int minDepth = chosenVariation.get("minDepth").getAsInt(); + int maxDepth = chosenVariation.get("maxDepth").getAsInt(); + JsonArray weightsJsonArray = chosenVariation.get("weights").getAsJsonArray(); + int[] weights = new int[weightsJsonArray.size()]; + for (int i = 0; i < weightsJsonArray.size(); i++) { + weights[i] = weightsJsonArray.get(i).getAsInt(); + } + PocketTemplate pocketTemplate = new PocketTemplate(variantName, chosenVariationSize, entranceDoorX, entranceDoorY, entranceDoorZ, + wallThickness, floorThickness, roofThickness, typeID, minDepth, maxDepth, weights); + pocketTemplates.add(pocketTemplate); + ///this block equals + } + } else if (jsonType.equals("Multiple")) { + for (int i = 0; i < variations.size(); i++) { + JsonObject variation = variations.get(i).getAsJsonObject(); + int variationSize = variation.get("size").getAsInt(); + if (variationSize <= maxPocketSize) { + //this block + String variantName = variation.get("variantName").getAsString(); + int entranceDoorX = variation.get("entranceDoorX").getAsInt(); + int entranceDoorY = variation.get("entranceDoorY").getAsInt(); + int entranceDoorZ = variation.get("entranceDoorZ").getAsInt(); + int wallThickness = variation.get("wallThickness").getAsInt(); + int floorThickness = variation.get("floorThickness").getAsInt(); + int roofThickness = variation.get("roofThickness").getAsInt(); + EnumPocketType typeID = EnumPocketType.getFromInt(variation.get("typeID").getAsInt()); + int minDepth = variation.get("minDepth").getAsInt(); + int maxDepth = variation.get("maxDepth").getAsInt(); + JsonArray weightsJsonArray = variation.get("weights").getAsJsonArray(); + int[] weights = new int[weightsJsonArray.size()]; + for (int j = 0; j < weightsJsonArray.size(); j++) { + weights[j] = weightsJsonArray.get(j).getAsInt(); + } + PocketTemplate pocketTemplate = new PocketTemplate(variantName, variationSize, entranceDoorX, entranceDoorY, entranceDoorZ, + wallThickness, floorThickness, roofThickness, typeID, minDepth, maxDepth, weights); + pocketTemplates.add(pocketTemplate); + ///this block + } + } + } //@todo, more options? + return pocketTemplates; } }