From caf33bd866487882b70450bd9aeff5edb4103609 Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Sat, 17 Aug 2013 20:32:30 -0400 Subject: [PATCH 1/3] Improved EventHookContainer Made some changes to EventHookContainer.onWorldLoad() to remove redundant code that encouraged bugs. Unfortunately, a lot of link-related code needs to be rewritten to get rid of bugs, so that'll come after dungeon packs are completed. --- .../mod_pocketDim/EventHookContainer.java | 38 ++++++++----------- 1 file changed, 16 insertions(+), 22 deletions(-) diff --git a/StevenDimDoors/mod_pocketDim/EventHookContainer.java b/StevenDimDoors/mod_pocketDim/EventHookContainer.java index 95742f3e..d2e12b14 100644 --- a/StevenDimDoors/mod_pocketDim/EventHookContainer.java +++ b/StevenDimDoors/mod_pocketDim/EventHookContainer.java @@ -46,32 +46,26 @@ public class EventHookContainer dimHelper.instance.interDimLinkList.clear(); dimHelper.instance.initPockets(); } - for (Integer ids : dimHelper.getIDs()) - { - World world = dimHelper.getWorld(ids); + + //TODO: In the future, we should iterate over DimHelper's dimension list. We ignore other dimensions anyway. + for (int dimensionID : dimHelper.getIDs()) + { + World world = dimHelper.getWorld(dimensionID); int linkCount = 0; - if (dimHelper.dimList.containsKey(world.provider.dimensionId)) + if (dimHelper.dimList.containsKey(dimensionID)) { - //TODO added temporary Try/catch block to prevent a crash here, getLinksInDim needs to be looked at - try - { - for (LinkData link:dimHelper.instance.getDimData(world.provider.dimensionId).getLinksInDim()) - { - if (!mod_pocketDim.blockRift.isBlockImmune(world, link.locXCoord, link.locYCoord, link.locZCoord)) - { - dimHelper.getWorld(link.locDimID).setBlock(link.locXCoord, link.locYCoord, link.locZCoord, properties.RiftBlockID); - } - linkCount++; - if (linkCount >= 100) - { - break; - } - } - } - catch(Exception e) + for (LinkData link : dimHelper.instance.getDimData(dimensionID).getLinksInDim()) { - e.printStackTrace(); + if (!mod_pocketDim.blockRift.isBlockImmune(world, link.locXCoord, link.locYCoord, link.locZCoord)) + { + world.setBlock(link.locXCoord, link.locYCoord, link.locZCoord, properties.RiftBlockID); + } + linkCount++; + if (linkCount >= 100) + { + break; + } } } } From acab06115abf45c7753b84dc99dbc51fab67a90d Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Tue, 20 Aug 2013 18:54:30 -0400 Subject: [PATCH 2/3] Progress on Implementing Dungeon Packs Added code for parsing dungeon pack config files. The settings for our built-in dungeons are now read from a file instead of being hardcoded. One or two settings aren't being accessed yet and we still don't search for other dungeon packs in the custom dungeon folder. That'll come in another commit. --- .../dungeon/pack/DungeonPackConfig.java | 48 +++ .../dungeon/pack/DungeonPackConfigReader.java | 386 ++++++++++++++++++ .../mod_pocketDim/helpers/DungeonHelper.java | 62 +-- schematics/ruins/rules.txt | 8 +- 4 files changed, 452 insertions(+), 52 deletions(-) create mode 100644 StevenDimDoors/mod_pocketDim/dungeon/pack/DungeonPackConfigReader.java diff --git a/StevenDimDoors/mod_pocketDim/dungeon/pack/DungeonPackConfig.java b/StevenDimDoors/mod_pocketDim/dungeon/pack/DungeonPackConfig.java index c99dd91f..842c94ce 100644 --- a/StevenDimDoors/mod_pocketDim/dungeon/pack/DungeonPackConfig.java +++ b/StevenDimDoors/mod_pocketDim/dungeon/pack/DungeonPackConfig.java @@ -7,6 +7,10 @@ public class DungeonPackConfig private String name; private ArrayList typeNames; private boolean allowDuplicatesInChain; + private boolean allowPackChangeIn; + private boolean allowPackChangeOut; + private boolean distortDoorCoordinates; + private int packWeight; private ArrayList rules; public DungeonPackConfig() { } @@ -17,6 +21,10 @@ public class DungeonPackConfig this.name = source.name; this.typeNames = (ArrayList) source.typeNames.clone(); this.allowDuplicatesInChain = source.allowDuplicatesInChain; + this.allowPackChangeIn = source.allowPackChangeIn; + this.allowPackChangeOut = source.allowPackChangeOut; + this.distortDoorCoordinates = source.distortDoorCoordinates; + this.packWeight = source.packWeight; this.rules = (ArrayList) source.rules.clone(); } @@ -75,4 +83,44 @@ public class DungeonPackConfig { return rules; } + + public boolean allowPackChangeIn() + { + return allowPackChangeIn; + } + + public void setAllowPackChangeIn(boolean value) + { + this.allowPackChangeIn = value; + } + + public boolean allowPackChangeOut() + { + return allowPackChangeOut; + } + + public void setAllowPackChangeOut(boolean value) + { + this.allowPackChangeOut = value; + } + + public int getPackWeight() + { + return packWeight; + } + + public void setPackWeight(int packWeight) + { + this.packWeight = packWeight; + } + + public boolean getDistortDoorCoordinates() + { + return distortDoorCoordinates; + } + + public void setDistortDoorCoordinates(boolean value) + { + this.distortDoorCoordinates = value; + } } diff --git a/StevenDimDoors/mod_pocketDim/dungeon/pack/DungeonPackConfigReader.java b/StevenDimDoors/mod_pocketDim/dungeon/pack/DungeonPackConfigReader.java new file mode 100644 index 00000000..cf907ef6 --- /dev/null +++ b/StevenDimDoors/mod_pocketDim/dungeon/pack/DungeonPackConfigReader.java @@ -0,0 +1,386 @@ +package StevenDimDoors.mod_pocketDim.dungeon.pack; + +import java.io.BufferedReader; +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 java.util.regex.Pattern; + +import StevenDimDoors.mod_pocketDim.util.BaseConfigurationProcessor; +import StevenDimDoors.mod_pocketDim.util.ConfigurationProcessingException; +import StevenDimDoors.mod_pocketDim.util.WeightedContainer; + +import com.google.common.base.CharMatcher; +import com.google.common.base.Splitter; +import com.google.common.primitives.Ints; + +public class DungeonPackConfigReader extends BaseConfigurationProcessor +{ + private interface ILineProcessor + { + public void process(String line, DungeonPackConfig config) throws ConfigurationProcessingException; + } + + //Note: These constants aren't static so that the memory will be released once + //we're done using it an instance. These aren't objects that we need to hold + //onto throughout the lifetime of MC, only at loading time. + + private final int CONFIG_VERSION = 1; + private final int LOOKAHEAD_LIMIT = 1024; + private final int MAX_PRODUCT_WEIGHT = 10000; + private final int DEFAULT_PRODUCT_WEIGHT = 100; + private final int MAX_DUNGEON_PACK_WEIGHT = 10000; + private final int DEFAULT_DUNGEON_PACK_WEIGHT = 100; + private final String COMMENT_MARKER = "##"; + + private final Pattern DUNGEON_TYPE_PATTERN = Pattern.compile("[A-Za-z0-9_\\-]{1,20}"); + + private final Splitter WHITESPACE_SPLITTER = Splitter.on(CharMatcher.WHITESPACE).omitEmptyStrings(); + private final String SETTING_SEPARATOR = "="; + private final String RULE_SEPARATOR = "->"; + private final String WEIGHT_SEPARATOR = "#"; + + public DungeonPackConfigReader() { } + + @Override + public DungeonPackConfig readFromStream(InputStream inputStream) throws ConfigurationProcessingException + { + BufferedReader reader = null; + try + { + DungeonPackConfig config = new DungeonPackConfig(); + reader = new BufferedReader(new InputStreamReader(inputStream)); + + //Check the config format version + int version = readVersion(reader); + if (version != CONFIG_VERSION) + { + throw new ConfigurationProcessingException("The dungeon pack config has an incompatible version."); + } + + config.setTypeNames(new ArrayList()); + config.setRules(new ArrayList()); + + //Read the dungeon types + if (findSection("Types", reader)) + { + processLines(reader, config, new DungeonTypeProcessor()); + } + + //Load default settings + config.setAllowDuplicatesInChain(true); + config.setAllowPackChangeIn(true); + config.setAllowPackChangeOut(true); + config.setDistortDoorCoordinates(false); + config.setPackWeight(DEFAULT_DUNGEON_PACK_WEIGHT); + + //Read the settings section + if (findSection("Settings", reader)) + { + processLines(reader, config, new DungeonSettingsParser()); + } + + //Read the rules section + if (findSection("Rules", reader)) + { + processLines(reader, config, new RuleDefinitionParser()); + } + + return config; + } + catch (ConfigurationProcessingException ex) + { + throw ex; + } + catch (Exception ex) + { + throw new ConfigurationProcessingException("An unexpected error occurred while trying to read the configuration file.", ex); + } + finally + { + if (reader != null) + { + try + { + reader.close(); + } + catch (IOException ex) { } + } + } + } + + private int readVersion(BufferedReader reader) throws ConfigurationProcessingException, IOException + { + String firstLine = reader.readLine(); + String[] parts = firstLine.split("\\s", 0); + Integer version = null; + + if (parts.length == 2 && parts[0].equalsIgnoreCase("version")) + { + version = Ints.tryParse(parts[1]); + } + + if (version == null) + { + throw new ConfigurationProcessingException("Could not parse the config format version."); + } + return version; + } + + private void processLines(BufferedReader reader, DungeonPackConfig config, ILineProcessor processor) throws IOException, ConfigurationProcessingException + { + String line; + + while (reader.ready()) + { + reader.mark(LOOKAHEAD_LIMIT); + line = reader.readLine(); + if (!line.startsWith(COMMENT_MARKER)) + { + line = line.trim(); + if (line.length() > 0) + { + if (line.endsWith(":")) + { + //Consider this line a section header, reset the reader to undo consuming it + reader.reset(); + break; + } + else + { + processor.process(line, config); + } + } + } + } + } + + private boolean findSection(String name, BufferedReader reader) throws IOException, ConfigurationProcessingException + { + boolean found = false; + boolean matched = false; + String line = null; + String label = name + ":"; + + //Find the next section header + //Ignore blank lines and comment lines, stop for headers, and throw an exception for anything else + while (!found && reader.ready()) + { + reader.mark(LOOKAHEAD_LIMIT); + line = reader.readLine(); + if (!line.startsWith(COMMENT_MARKER)) + { + line = line.trim(); + if (line.length() > 0) + { + if (line.endsWith(":")) + { + //Consider this line a section header + found = true; + matched = line.equalsIgnoreCase(label); + } + else + { + //This line is invalid + throw new ConfigurationProcessingException("The dungeon pack config has an incorrect line where a section was expected: " + line); + } + } + } + } + + //Check if the header matches the one we're looking for. + //If it doesn't match, undo consuming the line so it can be read later. + if (found && !matched) + { + reader.reset(); + } + return found; + } + + private class DungeonTypeProcessor implements ILineProcessor + { + public void process(String line, DungeonPackConfig config) throws ConfigurationProcessingException + { + List typeNames = config.getTypeNames(); + + //Check if the dungeon type has a name that meets our restrictions + if (DUNGEON_TYPE_PATTERN.matcher(line).matches()) + { + //Ignore duplicate dungeon types + line = line.toUpperCase(); + if (!typeNames.contains(line)) + { + typeNames.add(line); + } + } + else + { + throw new ConfigurationProcessingException("The dungeon pack config has a dungeon type with illegal characters in its name: " + line); + } + } + } + + private class DungeonSettingsParser implements ILineProcessor + { + public void process(String line, DungeonPackConfig config) throws ConfigurationProcessingException + { + //The various settings that we support will be hardcoded here. + //In the future, if we get more settings, then this should be + //refactored to use a more lookup-driven approach. + + boolean valid = true; + String[] settingParts = line.split(SETTING_SEPARATOR, 2); + if (settingParts.length == 2) + { + try + { + String name = settingParts[0]; + String value = settingParts[1]; + if (name.equalsIgnoreCase("AllowDuplicatesInChain")) + { + config.setAllowDuplicatesInChain(parseBoolean(value)); + } + else if (name.equalsIgnoreCase("AllowPackChangeOut")) + { + config.setAllowPackChangeOut(parseBoolean(value)); + } + else if (name.equalsIgnoreCase("AllowPackChangeIn")) + { + config.setAllowPackChangeIn(parseBoolean(value)); + } + else if (name.equalsIgnoreCase("DistortDoorCoordinates")) + { + config.setDistortDoorCoordinates(parseBoolean(value)); + } + else if (name.equalsIgnoreCase("PackWeight")) + { + int weight = Integer.parseInt(value); + if (weight >= 0 && weight <= MAX_DUNGEON_PACK_WEIGHT) + { + config.setPackWeight(weight); + } + else + { + valid = false; + } + } + } + catch (Exception e) + { + valid = false; + } + } + else + { + valid = false; + } + + if (!valid) + { + throw new ConfigurationProcessingException("The dungeon pack config has an invalid setting: " + line); + } + } + } + + private class RuleDefinitionParser implements ILineProcessor + { + public void process(String definition, DungeonPackConfig config) throws ConfigurationProcessingException + { + String[] ruleParts; + String[] productParts; + String ruleCondition; + String ruleProduct; + ArrayList condition; + ArrayList> products; + List typeNames = config.getTypeNames(); + + ruleParts = definition.toUpperCase().split(RULE_SEPARATOR, -1); + if (ruleParts.length != 2) + { + throw new ConfigurationProcessingException("The dungeon pack config has an invalid rule: " + definition); + } + + ruleCondition = ruleParts[0]; + ruleProduct = ruleParts[1]; + condition = new ArrayList(); + products = new ArrayList>(); + + for (String typeName : WHITESPACE_SPLITTER.split(ruleCondition)) + { + if (isKnownDungeonType(typeName, typeNames)) + { + condition.add(typeName); + } + else + { + throw new ConfigurationProcessingException("The dungeon pack config has a rule condition with an unknown dungeon type: " + typeName); + } + } + + for (String product : WHITESPACE_SPLITTER.split(ruleProduct)) + { + Integer weight; + String typeName; + + productParts = product.split(WEIGHT_SEPARATOR, -1); + if (productParts.length > 2 || productParts.length == 0) + { + throw new ConfigurationProcessingException("The dungeon pack config has a rule with an invalid product: " + product); + } + + typeName = productParts[0]; + if (isKnownDungeonType(typeName, typeNames)) + { + if (productParts.length > 1) + { + weight = Ints.tryParse(productParts[1]); + if (weight == null || (weight > MAX_PRODUCT_WEIGHT) || (weight < 0)) + { + throw new ConfigurationProcessingException("The dungeon pack config has a rule with an invalid product weight: " + product); + } + } + else + { + weight = DEFAULT_PRODUCT_WEIGHT; + } + products.add(new WeightedContainer(typeName, weight)); + } + else + { + throw new ConfigurationProcessingException("The dungeon pack config has an unknown dungeon type in a rule: " + typeName); + } + } + config.getRules().add( new DungeonChainRuleDefinition(condition, products) ); + } + } + + private static boolean isKnownDungeonType(String typeName, List typeNames) + { + return typeName.equals(DungeonType.WILDCARD_TYPE.Name) || typeNames.contains(typeName); + } + + private static boolean parseBoolean(String value) + { + if (value.equalsIgnoreCase("true")) + return true; + if (value.equalsIgnoreCase("false")) + return false; + throw new IllegalArgumentException("The boolean value must be either \"true\" or \"false\", ignoring case."); + } + + @Override + public boolean canWrite() + { + return false; + } + + @Override + public void writeToStream(OutputStream outputStream, DungeonPackConfig data) + throws ConfigurationProcessingException + { + throw new UnsupportedOperationException("DungeonPackConfigReader does not support writing."); + } +} diff --git a/StevenDimDoors/mod_pocketDim/helpers/DungeonHelper.java b/StevenDimDoors/mod_pocketDim/helpers/DungeonHelper.java index ae5e6c1e..4a4b9a49 100644 --- a/StevenDimDoors/mod_pocketDim/helpers/DungeonHelper.java +++ b/StevenDimDoors/mod_pocketDim/helpers/DungeonHelper.java @@ -5,7 +5,6 @@ import java.io.File; import java.io.InputStream; import java.io.InputStreamReader; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashSet; @@ -22,12 +21,12 @@ import StevenDimDoors.mod_pocketDim.DungeonGenerator; import StevenDimDoors.mod_pocketDim.LinkData; import StevenDimDoors.mod_pocketDim.mod_pocketDim; import StevenDimDoors.mod_pocketDim.dungeon.DungeonSchematic; -import StevenDimDoors.mod_pocketDim.dungeon.pack.DungeonChainRuleDefinition; import StevenDimDoors.mod_pocketDim.dungeon.pack.DungeonPack; 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.itemDimDoor; -import StevenDimDoors.mod_pocketDim.util.WeightedContainer; +import StevenDimDoors.mod_pocketDim.util.ConfigurationProcessingException; public class DungeonHelper { @@ -112,56 +111,21 @@ public class DungeonHelper { //This is a temporarily function for testing dungeon packs. //It'll be removed later when we read dungeon configurations from files. - - ArrayList rules = new ArrayList(); - - rules.add(parseDefinitionUnsafe("? ? ? ? ? ? ? ? -> Trap#20 SimpleHall#40 ComplexHall#10 Exit#20 DeadEnd#10")); - - rules.add(parseDefinitionUnsafe("? ? ? ? -> Trap#18 SimpleHall#40 ComplexHall#10 Exit#18 DeadEnd#10 Hub#4")); - - rules.add(parseDefinitionUnsafe("? ? ? -> ComplexHall Hub Trap SimpleHall Maze")); - - rules.add(parseDefinitionUnsafe("? ? -> ComplexHall Hub Trap SimpleHall Maze")); - - rules.add(parseDefinitionUnsafe("? -> ComplexHall#40 Hub#30 Trap#10 SimpleHall#10 Maze#10")); - - rules.add(parseDefinitionUnsafe("-> ComplexHall#40 Hub#30 Trap#10 SimpleHall#10 Maze#10")); - - String[] typeNames = "Hub Trap Maze Exit DeadEnd SimpleHall ComplexHall".toUpperCase().split(" "); - - DungeonPackConfig config = new DungeonPackConfig(); - config.setName("ruins"); - config.setAllowDuplicatesInChain(false); - config.setRules(rules); - config.setTypeNames(new ArrayList(Arrays.asList(typeNames))); - return config; - } - - private static DungeonChainRuleDefinition parseDefinitionUnsafe(String definition) - { - //This is an improvised parsing function for rule definitions. Only for testing!!! - definition = definition.toUpperCase(); - String[] parts = definition.split("->"); - ArrayList condition = new ArrayList(); - ArrayList> products = new ArrayList>(); - - for (String conditionPart : parts[0].split(" ")) + + DungeonPackConfig config; + try { - if (!conditionPart.isEmpty()) - condition.add(conditionPart); + config = (new DungeonPackConfigReader()).readFromResource("/schematics/ruins/rules.txt"); + config.setName("ruins"); + return config; } - - for (String product : parts[1].split(" ")) + catch (ConfigurationProcessingException e) { - if (!product.isEmpty()) - { - String[] productParts = product.split("#"); - String productType = productParts[0]; - int weight = (productParts.length > 1) ? Integer.parseInt(productParts[1]) : 100; - products.add(new WeightedContainer(productType, weight)); - } + //FIXME TEMPORARY DEBUG PRINT, DO SOMETHING BETTER HERE + System.err.println("OH GOD SOMETHING WENT WRONG WITH THE DEFAULT DUNGEON PACK CONFIG"); + e.printStackTrace(); + return null; } - return new DungeonChainRuleDefinition(condition, products); } public List getRegisteredDungeons() diff --git a/schematics/ruins/rules.txt b/schematics/ruins/rules.txt index 086036ab..ef838c18 100644 --- a/schematics/ruins/rules.txt +++ b/schematics/ruins/rules.txt @@ -9,10 +9,12 @@ DeadEnd Maze Settings: -AllowRepetitionsInBranch = false +AllowDuplicatesInChain = false AllowPackChangeOut = true -AllowPackChangeIn = true -PackWeight = 100 +DistortDoorCoordinates = true + +## Prevent this pack from being selected for transitioning in once we've transitioned out +AllowPackChangeIn = false Rules: From 4d1503db3fff45028ae060e1d2ce7f17a1aadaaa Mon Sep 17 00:00:00 2001 From: SenseiKiwi Date: Tue, 20 Aug 2013 18:55:26 -0400 Subject: [PATCH 3/3] Minor Change Minor change - fixing spacing that was messed up by Eclipse. --- .../dungeon/pack/DungeonPackConfigReader.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/StevenDimDoors/mod_pocketDim/dungeon/pack/DungeonPackConfigReader.java b/StevenDimDoors/mod_pocketDim/dungeon/pack/DungeonPackConfigReader.java index cf907ef6..8aac9674 100644 --- a/StevenDimDoors/mod_pocketDim/dungeon/pack/DungeonPackConfigReader.java +++ b/StevenDimDoors/mod_pocketDim/dungeon/pack/DungeonPackConfigReader.java @@ -378,9 +378,8 @@ public class DungeonPackConfigReader extends BaseConfigurationProcessor