Greatly refactors gate loading
This commit is contained in:
		@@ -23,7 +23,7 @@ public class Gate {
 | 
			
		||||
 | 
			
		||||
    private final String filename;
 | 
			
		||||
    private final GateLayout layout;
 | 
			
		||||
    private final HashMap<Character, Material> types;
 | 
			
		||||
    private final Map<Character, Material> types;
 | 
			
		||||
 | 
			
		||||
    //Gate materials
 | 
			
		||||
    private Material portalOpenBlock;
 | 
			
		||||
@@ -50,7 +50,7 @@ public class Gate {
 | 
			
		||||
     * @param destroyCost       <p>The cost of destroying a portal with this gate layout (-1 to disable)</p>
 | 
			
		||||
     * @param toOwner           <p>Whether any payment should go to the owner of the gate, as opposed to just disappearing</p>
 | 
			
		||||
     */
 | 
			
		||||
    public Gate(String filename, GateLayout layout, HashMap<Character, Material> types, Material portalOpenBlock,
 | 
			
		||||
    public Gate(String filename, GateLayout layout, Map<Character, Material> 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 <p>The material types each layout character represents</p>
 | 
			
		||||
     */
 | 
			
		||||
    public HashMap<Character, Material> getTypes() {
 | 
			
		||||
    public Map<Character, Material> getTypes() {
 | 
			
		||||
        return types;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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 <p>The gate to register</p>
 | 
			
		||||
     */
 | 
			
		||||
    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 <p>The file containing the gate's layout</p>
 | 
			
		||||
     * @return <p>The loaded gate or null if unable to load the gate</p>
 | 
			
		||||
     */
 | 
			
		||||
    private static Gate loadGate(File file) {
 | 
			
		||||
        try (Scanner scanner = new Scanner(file)) {
 | 
			
		||||
            return loadGate(file.getName(), file.getParent(), scanner);
 | 
			
		||||
        } catch (Exception ex) {
 | 
			
		||||
@@ -93,24 +106,177 @@ public class GateHandler {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static Gate loadGate(String fileName, String parentFolder, Scanner scanner) {
 | 
			
		||||
        boolean designing = false;
 | 
			
		||||
    /**
 | 
			
		||||
     * Loads a gate
 | 
			
		||||
     *
 | 
			
		||||
     * @param fileName <p>The name of the file containing the gate layout</p>
 | 
			
		||||
     * @param parentFolder <p>The parent folder of the layout file</p>
 | 
			
		||||
     * @param scanner <p>The scanner to use for reading the gate layout</p>
 | 
			
		||||
     * @return <p>The loaded gate or null if unable to load the gate</p>
 | 
			
		||||
     */
 | 
			
		||||
    private static Gate loadGate(String fileName, String parentFolder, Scanner scanner) {
 | 
			
		||||
        List<List<Character>> design = new ArrayList<>();
 | 
			
		||||
        HashMap<Character, Material> types = new HashMap<>();
 | 
			
		||||
        HashMap<String, String> config = new HashMap<>();
 | 
			
		||||
        HashSet<Material> frameTypes = new HashSet<>();
 | 
			
		||||
        int cols = 0;
 | 
			
		||||
        Map<Character, Material> types = new HashMap<>();
 | 
			
		||||
        Map<String, String> config = new HashMap<>();
 | 
			
		||||
        Set<Material> frameTypes = new HashSet<>();
 | 
			
		||||
 | 
			
		||||
        // Init types map
 | 
			
		||||
        //Initialize types map
 | 
			
		||||
        types.put(ENTRANCE, Material.AIR);
 | 
			
		||||
        types.put(EXIT, Material.AIR);
 | 
			
		||||
        types.put(ANYTHING, Material.AIR);
 | 
			
		||||
 | 
			
		||||
        //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;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //Update list of all frame blocks
 | 
			
		||||
        frameBlocks.addAll(frameTypes);
 | 
			
		||||
 | 
			
		||||
        gate.save(parentFolder + "/"); // Updates format for version changes
 | 
			
		||||
        return gate;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates a new gate
 | 
			
		||||
     *
 | 
			
		||||
     * @param config <p>The config map to get configuration values from</p>
 | 
			
		||||
     * @param fileName <p>The name of the saved gate config file</p>
 | 
			
		||||
     * @param layout <p>The layout matrix of the new gate</p>
 | 
			
		||||
     * @param types <p>The mapping for used gate material types</p>
 | 
			
		||||
     * @return <p>A new gate or null if the config is invalid</p>
 | 
			
		||||
     */
 | 
			
		||||
    private static Gate createGate(Map<String, String> config, String fileName, Character[][] layout,
 | 
			
		||||
                                   Map<Character, Material> types) {
 | 
			
		||||
        Material portalOpenBlock = readConfig(config, fileName, "portal-open", defaultPortalBlockOpen);
 | 
			
		||||
        Material portalClosedBlock = readConfig(config, fileName, "portal-closed", defaultPortalBlockClosed);
 | 
			
		||||
        Material portalButton = readConfig(config, fileName, "button", defaultButton);
 | 
			
		||||
        int useCost = readConfig(config, fileName, "usecost", -1);
 | 
			
		||||
        int createCost = readConfig(config, fileName, "createcost", -1);
 | 
			
		||||
        int destroyCost = readConfig(config, fileName, "destroycost", -1);
 | 
			
		||||
        boolean toOwner = (config.containsKey("toowner") ? Boolean.valueOf(config.get("toowner")) : EconomyHandler.toOwner);
 | 
			
		||||
 | 
			
		||||
        Gate gate = new Gate(fileName, new GateLayout(layout), types, portalOpenBlock, portalClosedBlock, portalButton, useCost,
 | 
			
		||||
                createCost, destroyCost, toOwner);
 | 
			
		||||
 | 
			
		||||
        if (!validateGate(gate, fileName)) {
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
        return gate;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Validate that a gate is valid
 | 
			
		||||
     *
 | 
			
		||||
     * @param gate <p>The gate to validate</p>
 | 
			
		||||
     * @param fileName <p>The filename of the loaded gate file</p>
 | 
			
		||||
     * @return <p>True if the gate is valid. False otherwise</p>
 | 
			
		||||
     */
 | 
			
		||||
    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 <p>The design of the gate layout</p>
 | 
			
		||||
     * @param cols <p>The largest amount of columns in the design</p>
 | 
			
		||||
     * @return <p>A matrix containing the gate's layout</p>
 | 
			
		||||
     */
 | 
			
		||||
    private static Character[][] generateLayoutMatrix(List<List<Character>> design, int cols) {
 | 
			
		||||
        Character[][] layout = new Character[design.size()][cols];
 | 
			
		||||
        for (int lineIndex = 0; lineIndex < design.size(); lineIndex++) {
 | 
			
		||||
            List<Character> 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 <p>The scanner to read from</p>
 | 
			
		||||
     * @param types <p>The map of characters to store valid symbols in</p>
 | 
			
		||||
     * @param fileName <p>The filename of the loaded gate config file</p>
 | 
			
		||||
     * @param design <p>The list to store the loaded design to</p>
 | 
			
		||||
     * @param frameTypes <p>The set of gate frame types to store to</p>
 | 
			
		||||
     * @param config <p>The map of config values to store to</p>
 | 
			
		||||
     * @return <p>The column count/width of the loaded gate</p>
 | 
			
		||||
     */
 | 
			
		||||
    private static int readGateFile(Scanner scanner, Map<Character, Material> types, String fileName,
 | 
			
		||||
                                    List<List<Character>> design, Set<Material> frameTypes, Map<String, String> 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 <p>The line to read</p>
 | 
			
		||||
     * @param cols <p>The current max columns value of the design</p>
 | 
			
		||||
     * @param types <p>The map of characters to check for valid symbols</p>
 | 
			
		||||
     * @param fileName <p>The filename of the loaded gate config file</p>
 | 
			
		||||
     * @param design <p>The list to store the loaded design to</p>
 | 
			
		||||
     * @return <p>The new max columns value of the design</p>
 | 
			
		||||
     */
 | 
			
		||||
    private static int readGateDesignLine(String line, int cols, Map<Character, Material> types, String fileName,
 | 
			
		||||
                                          List<List<Character>> design) {
 | 
			
		||||
        List<Character> row = new ArrayList<>();
 | 
			
		||||
 | 
			
		||||
        if (line.length() > cols) {
 | 
			
		||||
@@ -120,14 +286,26 @@ public class GateHandler {
 | 
			
		||||
        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;
 | 
			
		||||
                return -1;
 | 
			
		||||
            }
 | 
			
		||||
            row.add(symbol);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        design.add(row);
 | 
			
		||||
                } else {
 | 
			
		||||
                    if (!line.isEmpty() && !line.startsWith("#")) {
 | 
			
		||||
        return cols;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Reads one config value from the gate layout file
 | 
			
		||||
     *
 | 
			
		||||
     * @param line <p>The line to read</p>
 | 
			
		||||
     * @param types <p>The map of characters to materials to store to</p>
 | 
			
		||||
     * @param frameTypes <p>The set of gate frame types to store to</p>
 | 
			
		||||
     * @param config <p>The map of config values to store to</p>
 | 
			
		||||
     * @throws Exception <p>If an invalid material is encountered</p>
 | 
			
		||||
     */
 | 
			
		||||
    private static void readGateConfigValue(String line, Map<Character, Material> types, Set<Material> frameTypes,
 | 
			
		||||
                                            Map<String, String> config) throws Exception {
 | 
			
		||||
        String[] split = line.split("=");
 | 
			
		||||
        String key = split[0].trim();
 | 
			
		||||
        String value = split[1].trim();
 | 
			
		||||
@@ -143,69 +321,9 @@ public class GateHandler {
 | 
			
		||||
        } 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());
 | 
			
		||||
            return null;
 | 
			
		||||
        } finally {
 | 
			
		||||
            if (scanner != null) {
 | 
			
		||||
                scanner.close();
 | 
			
		||||
            }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
        Character[][] layout = new Character[design.size()][cols];
 | 
			
		||||
 | 
			
		||||
        //y = relative line number of layout file
 | 
			
		||||
        for (int y = 0; y < design.size(); y++) {
 | 
			
		||||
            List<Character> 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;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Material portalOpenBlock = readConfig(config, fileName, "portal-open", defaultPortalBlockOpen);
 | 
			
		||||
        Material portalClosedBlock = readConfig(config, fileName, "portal-closed", defaultPortalBlockClosed);
 | 
			
		||||
        Material portalButton = readConfig(config, fileName, "button", defaultButton);
 | 
			
		||||
        int useCost = readConfig(config, fileName, "usecost", -1);
 | 
			
		||||
        int createCost = readConfig(config, fileName, "createcost", -1);
 | 
			
		||||
        int destroyCost = readConfig(config, fileName, "destroycost", -1);
 | 
			
		||||
        boolean toOwner = (config.containsKey("toowner") ? Boolean.valueOf(config.get("toowner")) : EconomyHandler.toOwner);
 | 
			
		||||
 | 
			
		||||
        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.");
 | 
			
		||||
            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<String, String> config, String fileName, String key, int defaultInteger) {
 | 
			
		||||
    private static int readConfig(Map<String, String> 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 <p>The default material to use, in case the config is invalid</p>
 | 
			
		||||
     * @return <p>The material to use</p>
 | 
			
		||||
     */
 | 
			
		||||
    private static Material readConfig(HashMap<String, String> config, String fileName, String key, Material defaultMaterial) {
 | 
			
		||||
    private static Material readConfig(Map<String, String> config, String fileName, String key, Material defaultMaterial) {
 | 
			
		||||
        if (config.containsKey(key)) {
 | 
			
		||||
            Material material = Material.getMaterial(config.get(key));
 | 
			
		||||
            if (material != null) {
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user