From 44dfa2a10d3b76ecf7fdfe391b74a2bc2c2bdbca Mon Sep 17 00:00:00 2001 From: EpicKnarvik97 Date: Sun, 28 Feb 2021 21:53:27 +0100 Subject: [PATCH] Greatly refactors gate loading --- .../net/knarcraft/stargate/portal/Gate.java | 6 +- .../stargate/portal/GateHandler.java | 296 ++++++++++++------ .../knarcraft/stargate/portal/GateLayout.java | 1 - 3 files changed, 210 insertions(+), 93 deletions(-) diff --git a/src/main/java/net/knarcraft/stargate/portal/Gate.java b/src/main/java/net/knarcraft/stargate/portal/Gate.java index c4fa646..cd1afb4 100644 --- a/src/main/java/net/knarcraft/stargate/portal/Gate.java +++ b/src/main/java/net/knarcraft/stargate/portal/Gate.java @@ -23,7 +23,7 @@ public class Gate { private final String filename; private final GateLayout layout; - private final HashMap types; + private final Map types; //Gate materials private Material portalOpenBlock; @@ -50,7 +50,7 @@ public class Gate { * @param destroyCost

The cost of destroying a portal with this gate layout (-1 to disable)

* @param toOwner

Whether any payment should go to the owner of the gate, as opposed to just disappearing

*/ - public Gate(String filename, GateLayout layout, HashMap types, Material portalOpenBlock, + public Gate(String filename, GateLayout layout, Map types, Material portalOpenBlock, Material portalClosedBlock, Material portalButton, int useCost, int createCost, int destroyCost, boolean toOwner) { this.filename = filename; @@ -79,7 +79,7 @@ public class Gate { * * @return

The material types each layout character represents

*/ - public HashMap getTypes() { + public Map getTypes() { return types; } diff --git a/src/main/java/net/knarcraft/stargate/portal/GateHandler.java b/src/main/java/net/knarcraft/stargate/portal/GateHandler.java index 521838c..5e62635 100644 --- a/src/main/java/net/knarcraft/stargate/portal/GateHandler.java +++ b/src/main/java/net/knarcraft/stargate/portal/GateHandler.java @@ -10,7 +10,9 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Scanner; +import java.util.Set; import java.util.logging.Level; /** @@ -72,7 +74,12 @@ public class GateHandler { return CONTROL_BLOCK; } - public static void registerGate(Gate gate) { + /** + * Register a gate into the list of available gates + * + * @param gate

The gate to register

+ */ + private static void registerGate(Gate gate) { gates.put(gate.getFilename(), gate); Material blockID = gate.getControlBlock(); @@ -84,7 +91,13 @@ public class GateHandler { controlBlocks.get(blockID).add(gate); } - public static Gate loadGate(File file) { + /** + * Loads a gate + * + * @param file

The file containing the gate's layout

+ * @return

The loaded gate or null if unable to load the gate

+ */ + private static Gate loadGate(File file) { try (Scanner scanner = new Scanner(file)) { return loadGate(file.getName(), file.getParent(), scanner); } catch (Exception ex) { @@ -93,88 +106,56 @@ public class GateHandler { } } - public static Gate loadGate(String fileName, String parentFolder, Scanner scanner) { - boolean designing = false; + /** + * Loads a gate + * + * @param fileName

The name of the file containing the gate layout

+ * @param parentFolder

The parent folder of the layout file

+ * @param scanner

The scanner to use for reading the gate layout

+ * @return

The loaded gate or null if unable to load the gate

+ */ + private static Gate loadGate(String fileName, String parentFolder, Scanner scanner) { List> design = new ArrayList<>(); - HashMap types = new HashMap<>(); - HashMap config = new HashMap<>(); - HashSet frameTypes = new HashSet<>(); - int cols = 0; + Map types = new HashMap<>(); + Map config = new HashMap<>(); + Set frameTypes = new HashSet<>(); - // Init types map + //Initialize types map types.put(ENTRANCE, Material.AIR); types.put(EXIT, Material.AIR); types.put(ANYTHING, Material.AIR); - try { - while (scanner.hasNextLine()) { - String line = scanner.nextLine(); - - if (designing) { - List row = new ArrayList<>(); - - if (line.length() > cols) { - cols = line.length(); - } - - for (Character symbol : line.toCharArray()) { - if ((symbol.equals('?')) || (!types.containsKey(symbol))) { - Stargate.log.log(Level.SEVERE, "Could not load Gate " + fileName + " - Unknown symbol '" + symbol + "' in diagram"); - return null; - } - row.add(symbol); - } - - design.add(row); - } else { - if (!line.isEmpty() && !line.startsWith("#")) { - String[] split = line.split("="); - String key = split[0].trim(); - String value = split[1].trim(); - - if (key.length() == 1) { - Character symbol = key.charAt(0); - Material id = Material.getMaterial(value); - if (id == null) { - throw new Exception("Invalid material in line: " + line); - } - types.put(symbol, id); - frameTypes.add(id); - } else { - config.put(key, value); - } - } else if ((line.isEmpty()) || (!line.contains("=") && !line.startsWith("#"))) { - designing = true; - } - } - } - } catch (Exception ex) { - Stargate.log.log(Level.SEVERE, "Could not load Gate " + fileName + " - " + ex.getMessage()); + //Read the file into appropriate lists and maps + int cols = readGateFile(scanner, types, fileName, design, frameTypes, config); + if (cols < 0) { + return null; + } + Character[][] layout = generateLayoutMatrix(design, cols); + + //Create and validate the new gate + Gate gate = createGate(config, fileName, layout, types); + if (gate == null) { return null; - } finally { - if (scanner != null) { - scanner.close(); - } } - Character[][] layout = new Character[design.size()][cols]; + //Update list of all frame blocks + frameBlocks.addAll(frameTypes); - //y = relative line number of layout file - for (int y = 0; y < design.size(); y++) { - List row = design.get(y); - Character[] result = new Character[cols]; - - for (int x = 0; x < cols; x++) { - if (x < row.size()) { - result[x] = row.get(x); - } else { - result[x] = ' '; - } - } - - layout[y] = result; - } + gate.save(parentFolder + "/"); // Updates format for version changes + return gate; + } + /** + * Creates a new gate + * + * @param config

The config map to get configuration values from

+ * @param fileName

The name of the saved gate config file

+ * @param layout

The layout matrix of the new gate

+ * @param types

The mapping for used gate material types

+ * @return

A new gate or null if the config is invalid

+ */ + private static Gate createGate(Map config, String fileName, Character[][] layout, + Map types) { Material portalOpenBlock = readConfig(config, fileName, "portal-open", defaultPortalBlockOpen); Material portalClosedBlock = readConfig(config, fileName, "portal-closed", defaultPortalBlockClosed); Material portalButton = readConfig(config, fileName, "button", defaultButton); @@ -186,26 +167,163 @@ public class GateHandler { Gate gate = new Gate(fileName, new GateLayout(layout), types, portalOpenBlock, portalClosedBlock, portalButton, useCost, createCost, destroyCost, toOwner); - - - if (gate.getLayout().getControls().length != 2) { - Stargate.log.log(Level.SEVERE, "Could not load Gate " + fileName + " - Gates must have exactly 2 control points."); + if (!validateGate(gate, fileName)) { return null; } - - if (!MaterialHelper.isButtonCompatible(gate.getPortalButton())) { - Stargate.log.log(Level.SEVERE, "Could not load Gate " + fileName + " - Gate button must be a type of button."); - return null; - } - - // Merge frame types, add open mat to list - frameBlocks.addAll(frameTypes); - - gate.save(parentFolder + "/"); // Updates format for version changes return gate; } - private static int readConfig(HashMap config, String fileName, String key, int defaultInteger) { + /** + * Validate that a gate is valid + * + * @param gate

The gate to validate

+ * @param fileName

The filename of the loaded gate file

+ * @return

True if the gate is valid. False otherwise

+ */ + private static boolean validateGate(Gate gate, String fileName) { + if (gate.getLayout().getControls().length != 2) { + Stargate.log.log(Level.SEVERE, "Could not load Gate " + fileName + + " - Gates must have exactly 2 control points."); + return false; + } + + if (!MaterialHelper.isButtonCompatible(gate.getPortalButton())) { + Stargate.log.log(Level.SEVERE, "Could not load Gate " + fileName + + " - Gate button must be a type of button."); + return false; + } + return true; + } + + /** + * Generates a matrix storing the gate layout + * + * @param design

The design of the gate layout

+ * @param cols

The largest amount of columns in the design

+ * @return

A matrix containing the gate's layout

+ */ + private static Character[][] generateLayoutMatrix(List> design, int cols) { + Character[][] layout = new Character[design.size()][cols]; + for (int lineIndex = 0; lineIndex < design.size(); lineIndex++) { + List row = design.get(lineIndex); + Character[] result = new Character[cols]; + + for (int rowIndex = 0; rowIndex < cols; rowIndex++) { + if (rowIndex < row.size()) { + result[rowIndex] = row.get(rowIndex); + } else { + //Add spaces to all lines which are too short + result[rowIndex] = ' '; + } + } + + layout[lineIndex] = result; + } + return layout; + } + + /** + * Reads the gate file + * + * @param scanner

The scanner to read from

+ * @param types

The map of characters to store valid symbols in

+ * @param fileName

The filename of the loaded gate config file

+ * @param design

The list to store the loaded design to

+ * @param frameTypes

The set of gate frame types to store to

+ * @param config

The map of config values to store to

+ * @return

The column count/width of the loaded gate

+ */ + private static int readGateFile(Scanner scanner, Map types, String fileName, + List> design, Set frameTypes, Map config) { + boolean designing = false; + int cols = 0; + try { + while (scanner.hasNextLine()) { + String line = scanner.nextLine(); + + if (designing) { + cols = readGateDesignLine(line, cols, types, fileName, design); + if (cols < 0) { + return -1; + } + } else { + if (!line.isEmpty() && !line.startsWith("#")) { + readGateConfigValue(line, types, frameTypes, config); + } else if ((line.isEmpty()) || (!line.contains("=") && !line.startsWith("#"))) { + designing = true; + } + } + } + } catch (Exception ex) { + Stargate.log.log(Level.SEVERE, "Could not load Gate " + fileName + " - " + ex.getMessage()); + return -1; + } finally { + if (scanner != null) { + scanner.close(); + } + } + return cols; + } + + /** + * Reads one design line of the gate layout file + * + * @param line

The line to read

+ * @param cols

The current max columns value of the design

+ * @param types

The map of characters to check for valid symbols

+ * @param fileName

The filename of the loaded gate config file

+ * @param design

The list to store the loaded design to

+ * @return

The new max columns value of the design

+ */ + private static int readGateDesignLine(String line, int cols, Map types, String fileName, + List> design) { + List row = new ArrayList<>(); + + if (line.length() > cols) { + cols = line.length(); + } + + for (Character symbol : line.toCharArray()) { + if ((symbol.equals('?')) || (!types.containsKey(symbol))) { + Stargate.log.log(Level.SEVERE, "Could not load Gate " + fileName + " - Unknown symbol '" + symbol + "' in diagram"); + return -1; + } + row.add(symbol); + } + + design.add(row); + return cols; + } + + /** + * Reads one config value from the gate layout file + * + * @param line

The line to read

+ * @param types

The map of characters to materials to store to

+ * @param frameTypes

The set of gate frame types to store to

+ * @param config

The map of config values to store to

+ * @throws Exception

If an invalid material is encountered

+ */ + private static void readGateConfigValue(String line, Map types, Set frameTypes, + Map config) throws Exception { + String[] split = line.split("="); + String key = split[0].trim(); + String value = split[1].trim(); + + if (key.length() == 1) { + Character symbol = key.charAt(0); + Material id = Material.getMaterial(value); + if (id == null) { + throw new Exception("Invalid material in line: " + line); + } + types.put(symbol, id); + frameTypes.add(id); + } else { + config.put(key, value); + } + } + + private static int readConfig(Map config, String fileName, String key, int defaultInteger) { if (config.containsKey(key)) { try { return Integer.parseInt(config.get(key)); @@ -226,7 +344,7 @@ public class GateHandler { * @param defaultMaterial

The default material to use, in case the config is invalid

* @return

The material to use

*/ - private static Material readConfig(HashMap config, String fileName, String key, Material defaultMaterial) { + private static Material readConfig(Map config, String fileName, String key, Material defaultMaterial) { if (config.containsKey(key)) { Material material = Material.getMaterial(config.get(key)); if (material != null) { diff --git a/src/main/java/net/knarcraft/stargate/portal/GateLayout.java b/src/main/java/net/knarcraft/stargate/portal/GateLayout.java index ec22c81..dfb5ab2 100644 --- a/src/main/java/net/knarcraft/stargate/portal/GateLayout.java +++ b/src/main/java/net/knarcraft/stargate/portal/GateLayout.java @@ -5,7 +5,6 @@ import net.knarcraft.stargate.RelativeBlockVector; import java.io.BufferedWriter; import java.io.IOException; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; /**