Files
Stargate/src/main/java/net/knarcraft/stargate/utility/GateReader.java
EpicKnarvik97 1c906528f2 Cleans up message logging quite a bit
Adds methods to Stargate for easier logging and less redundancy
Loads the language loader in two parts to make it available while loading
Adds a translated string to the reload-message
Uses String.format to make long messages more readable
Makes it possible to get strings directly from the backup language to make debugging easier
2021-10-26 15:05:05 +02:00

211 lines
8.7 KiB
Java

package net.knarcraft.stargate.utility;
import net.knarcraft.stargate.Stargate;
import org.bukkit.Material;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Scanner;
import java.util.Set;
/**
* Helper class for reading gate files
*/
public final class GateReader {
private GateReader() {
}
/**
* Reads a gate file
*
* @param scanner <p>The scanner to read from</p>
* @param characterMaterialMap <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/layout to</p>
* @param frameTypes <p>The set to store frame/border materials 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>
*/
public static int readGateFile(Scanner scanner, Map<Character, Material> characterMaterialMap, String fileName,
List<List<Character>> design, Set<Material> frameTypes, Map<String, String> config) {
boolean designing = false;
int columns = 0;
try {
while (scanner.hasNextLine()) {
String line = scanner.nextLine();
if (designing) {
//If we have reached the gate's layout/design, read it
columns = readGateDesignLine(line, columns, characterMaterialMap, fileName, design);
if (columns < 0) {
return -1;
}
} else {
if (!line.isEmpty() && !line.startsWith("#")) {
//Read a normal config value
readGateConfigValue(line, characterMaterialMap, frameTypes, config);
} else if ((line.isEmpty()) || (!line.contains("=") && !line.startsWith("#"))) {
//An empty line marks the start of the gate's layout/design
designing = true;
}
}
}
} catch (Exception exception) {
Stargate.logSevere(String.format("Could not load Gate %s - %s", fileName, exception.getMessage()));
return -1;
} finally {
if (scanner != null) {
scanner.close();
}
}
return columns;
}
/**
* Reads one design line of the gate layout file
*
* <p>The max columns value is sent through this method in such a way that when the last gate design line is read,
* the max columns value contains the largest amount of columns (character) found in any of the design's lines.</p>
*
* @param line <p>The line to read</p>
* @param maxColumns <p>The current max columns value of the design</p>
* @param characterMaterialMap <p>The map between characters and the corresponding materials to use</p>
* @param fileName <p>The filename of the loaded gate config file</p>
* @param design <p>The two-dimensional 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 maxColumns, Map<Character, Material> characterMaterialMap,
String fileName, List<List<Character>> design) {
List<Character> row = new ArrayList<>();
//Update the max columns number if this line has more columns
if (line.length() > maxColumns) {
maxColumns = line.length();
}
for (Character symbol : line.toCharArray()) {
//Refuse read gate designs with unknown characters
if (symbol.equals('?') || (!characterMaterialMap.containsKey(symbol))) {
Stargate.logSevere(String.format("Could not load Gate %s - Unknown symbol '%s' in diagram", fileName,
symbol));
return -1;
}
//Add the read character to the row
row.add(symbol);
}
//Add this row of the gate's design to the two-dimensional design list
design.add(row);
return maxColumns;
}
/**
* Reads one config value from the gate layout file
*
* @param line <p>The line to read</p>
* @param characterMaterialMap <p>The character to material map to store to</p>
* @param frameTypes <p>The set to store gate frame/border types to</p>
* @param config <p>The config value map to store to</p>
* @throws Exception <p>If an invalid material is encountered</p>
*/
private static void readGateConfigValue(String line, Map<Character, Material> characterMaterialMap,
Set<Material> frameTypes, Map<String, String> config) throws Exception {
String[] split = line.split("=");
String key = split[0].trim();
String value = split[1].trim();
if (key.length() == 1) {
//Read a gate frame material
Character symbol = key.charAt(0);
Material material = Material.getMaterial(value);
if (material == null) {
throw new Exception("Invalid material in line: " + line);
}
//Register the map between the read symbol and the corresponding material
characterMaterialMap.put(symbol, material);
//Save the material as one of the frame materials used for this kind of gate
frameTypes.add(material);
} else {
//Read a normal config value
config.put(key, value);
}
}
/**
* Reads an integer configuration value
*
* @param config <p>The configuration to read</p>
* @param fileName <p>The filename of the config file</p>
* @param key <p>The config key to read</p>
* @return <p>The read value, or -1 if it could not be read</p>
*/
public static int readGateConfig(Map<String, String> config, String fileName, String key) {
if (config.containsKey(key)) {
try {
return Integer.parseInt(config.get(key));
} catch (NumberFormatException ex) {
Stargate.logWarning(String.format("%s reading %s: %s is not numeric", ex.getClass().getName(),
fileName, key));
}
}
return -1;
}
/**
* Reads a material configuration value
*
* @param config <p>The configuration to read</p>
* @param fileName <p>The filename of the config file</p>
* @param key <p>The config key to read</p>
* @param defaultMaterial <p>The default material to use, in case the config is invalid</p>
* @return <p>The material specified in the config, or the default material if it could not be read</p>
*/
public static Material readGateConfig(Map<String, String> config, String fileName, String key,
Material defaultMaterial) {
if (config.containsKey(key)) {
Material material = Material.getMaterial(config.get(key));
if (material != null) {
return material;
} else {
Stargate.logWarning(String.format("Error reading %s: %s is not a material", fileName, key));
}
}
return defaultMaterial;
}
/**
* Generates a matrix containing the gate layout
*
* <p>This basically changes the list of lists into a primitive matrix. Additionally, spaces are added to the end of
* each row which to too short relative to the longest row.</p>
*
* @param design <p>The design of the gate layout</p>
* @param columns <p>The largest amount of columns in the design</p>
* @return <p>A matrix containing the gate's layout</p>
*/
public static Character[][] generateLayoutMatrix(List<List<Character>> design, int columns) {
Character[][] layout = new Character[design.size()][columns];
for (int lineIndex = 0; lineIndex < design.size(); lineIndex++) {
List<Character> row = design.get(lineIndex);
Character[] result = new Character[columns];
for (int rowIndex = 0; rowIndex < columns; 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;
}
}