diff --git a/src/main/java/net/knarcraft/stargate/LanguageLoader.java b/src/main/java/net/knarcraft/stargate/LanguageLoader.java index 4367eae..e64bb99 100644 --- a/src/main/java/net/knarcraft/stargate/LanguageLoader.java +++ b/src/main/java/net/knarcraft/stargate/LanguageLoader.java @@ -1,20 +1,13 @@ package net.knarcraft.stargate; -import org.bukkit.ChatColor; +import net.knarcraft.stargate.utility.FileHelper; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.OutputStreamWriter; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; import java.util.HashMap; -import java.util.List; import java.util.Map; import java.util.Set; @@ -48,8 +41,8 @@ public class LanguageLoader { updateLanguage(chosenLanguage); loadedStringTranslations = load(chosenLanguage); - // We have a default hashMap used for when new text is added. - InputStream inputStream = getClass().getResourceAsStream("/lang/en.txt"); + //Load english as backup language in case the chosen language is missing newly added text strings + InputStream inputStream = FileHelper.getInputStreamForInternalFile("/lang/en.txt"); if (inputStream != null) { loadedBackupStrings = load("en", inputStream); } else { @@ -103,8 +96,6 @@ public class LanguageLoader { */ private void updateLanguage(String language) { // Load the current language file - List keyList = new ArrayList<>(); - List valueList = new ArrayList<>(); Map currentLanguageValues = load(language); @@ -118,46 +109,10 @@ public class LanguageLoader { return; } - boolean updated = false; - FileOutputStream fileOutputStream = null; try { - if (readChangedLanguageStrings(inputStream, keyList, valueList, currentLanguageValues)) { - updated = true; - } - - // Save file - fileOutputStream = new FileOutputStream(languageFolder + language + ".txt"); - OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream, StandardCharsets.UTF_8); - BufferedWriter bufferedWriter = new BufferedWriter(outputStreamWriter); - - // Output normal Language data - for (int i = 0; i < keyList.size(); i++) { - bufferedWriter.write(keyList.get(i) + valueList.get(i)); - bufferedWriter.newLine(); - } - bufferedWriter.newLine(); - // Output any custom language strings the user had - if (currentLanguageValues != null) { - for (String key : currentLanguageValues.keySet()) { - bufferedWriter.write(key + "=" + currentLanguageValues.get(key)); - bufferedWriter.newLine(); - } - } - - bufferedWriter.close(); + readChangedLanguageStrings(inputStream, language, currentLanguageValues); } catch (IOException ex) { ex.printStackTrace(); - } finally { - if (fileOutputStream != null) { - try { - fileOutputStream.close(); - } catch (Exception e) { - //Ignored - } - } - } - if (updated) { - Stargate.logger.info("[stargate] Your language file (" + language + ".txt) has been updated"); } } @@ -165,51 +120,70 @@ public class LanguageLoader { * Reads language strings * * @param inputStream

The input stream to read from

- * @param keyList

The key list to add keys to

- * @param valueList

The value list to add values to

+ * @param language

The selected language

* @param currentLanguageValues

The current values of the loaded/processed language

- * @return

True if at least one line was updated

* @throws IOException

if unable to read a language file

*/ - private boolean readChangedLanguageStrings(InputStream inputStream, List keyList, List valueList, - Map currentLanguageValues) throws IOException { - boolean updated = false; - // Input stuff - InputStreamReader inputStreamReader = new InputStreamReader(inputStream, StandardCharsets.UTF_8); - BufferedReader bufferedReader = new BufferedReader(inputStreamReader); + private void readChangedLanguageStrings(InputStream inputStream, String language, Map currentLanguageValues) throws IOException { - String line = bufferedReader.readLine(); - boolean firstLine = true; - while (line != null) { - // Strip UTF BOM - if (firstLine) { - line = removeUTF8BOM(line); - firstLine = false; - } - // Split at first "=" - int equalSignIndex = line.indexOf('='); - if (equalSignIndex == -1) { - keyList.add(""); - valueList.add(""); - line = bufferedReader.readLine(); - continue; - } - String key = line.substring(0, equalSignIndex); - String value = line.substring(equalSignIndex); + //Get language values + BufferedReader bufferedReader = FileHelper.getBufferedReaderFromInputStream(inputStream); + Map internalLanguageValues = FileHelper.readKeyValuePairs(bufferedReader); - if (currentLanguageValues == null || currentLanguageValues.get(key) == null) { - keyList.add(key); - valueList.add(value); - updated = true; - } else { - keyList.add(key); - valueList.add("=" + currentLanguageValues.get(key).replace('\u00A7', '&')); - currentLanguageValues.remove(key); - } - line = bufferedReader.readLine(); + //If currentLanguageValues is null; the chosen language is invalid, use the internal strings instead + if (currentLanguageValues == null) { + return; } - bufferedReader.close(); - return updated; + + //If a key is not found in the language file, add the one in the internal file. Must update the external file + if (!internalLanguageValues.keySet().equals(currentLanguageValues.keySet())) { + Map newLanguageValues = new HashMap<>(); + boolean updateNecessary = false; + for (String key : internalLanguageValues.keySet()) { + if (currentLanguageValues.get(key) == null) { + newLanguageValues.put(key, internalLanguageValues.get(key)); + //Found at least one value in the internal file not in the external file. Need to update + updateNecessary = true; + } else { + newLanguageValues.put(key, currentLanguageValues.get(key)); + currentLanguageValues.remove(key); + } + } + //Update the file itself + if (updateNecessary) { + updateLanguageFile(language, newLanguageValues, currentLanguageValues); + Stargate.logger.info("[stargate] Your language file (" + language + ".txt) has been updated"); + } + } + } + + /** + * Updates the language file for a given language + * + * @param language

The language to update

+ * @param languageStrings

The updated language strings

+ * @param customLanguageStrings

Any custom language strings not recognized

+ * @throws IOException

If unable to write to the language file

+ */ + private void updateLanguageFile(String language, Map languageStrings, + Map customLanguageStrings) throws IOException { + BufferedWriter bufferedWriter = FileHelper.getBufferedWriterFromString(languageFolder + language + ".txt"); + + //Output normal Language data + for (String key : languageStrings.keySet()) { + bufferedWriter.write(key + "=" + languageStrings.get(key)); + bufferedWriter.newLine(); + } + bufferedWriter.newLine(); + //Output any custom language strings the user had + if (customLanguageStrings != null) { + for (String key : customLanguageStrings.keySet()) { + bufferedWriter.write(key + "=" + customLanguageStrings.get(key)); + bufferedWriter.newLine(); + } + } + bufferedWriter.close(); } /** @@ -230,64 +204,24 @@ public class LanguageLoader { * @return

A mapping between loaded string indexes and the strings to display

*/ private Map load(String lang, InputStream inputStream) { - Map strings = new HashMap<>(); - FileInputStream fileInputStream = null; - InputStreamReader inputStreamReader; + Map strings; + BufferedReader bufferedReader; try { if (inputStream == null) { - fileInputStream = new FileInputStream(languageFolder + lang + ".txt"); - inputStreamReader = new InputStreamReader(fileInputStream, StandardCharsets.UTF_8); + bufferedReader = FileHelper.getBufferedReaderFromString(languageFolder + lang + ".txt"); } else { - inputStreamReader = new InputStreamReader(inputStream, StandardCharsets.UTF_8); + bufferedReader = FileHelper.getBufferedReaderFromInputStream(inputStream); } - readLanguageFile(inputStreamReader, strings); + strings = FileHelper.readKeyValuePairs(bufferedReader); } catch (Exception e) { if (Stargate.debuggingEnabled) { Stargate.logger.info("Unable to load chosen language"); } return null; - } finally { - if (fileInputStream != null) { - try { - fileInputStream.close(); - } catch (IOException e) { - //Ignored - } - } } return strings; } - /** - * Reads a language file given its input stream - * - * @param inputStreamReader

The input stream reader to read from

- * @param strings

The loaded string pairs

- * @throws IOException

If unable to read the file

- */ - private void readLanguageFile(InputStreamReader inputStreamReader, Map strings) throws IOException { - BufferedReader bufferedReader = new BufferedReader(inputStreamReader); - String line = bufferedReader.readLine(); - boolean firstLine = true; - while (line != null) { - // Strip UTF BOM - if (firstLine) { - line = removeUTF8BOM(line); - firstLine = false; - } - // Split at first "=" - int equalSignIndex = line.indexOf('='); - if (equalSignIndex == -1) { - line = bufferedReader.readLine(); - continue; - } - String key = line.substring(0, equalSignIndex); - String val = ChatColor.translateAlternateColorCodes('&', line.substring(equalSignIndex + 1)); - strings.put(key, val); - line = bufferedReader.readLine(); - } - } - /** * Prints debug output to the console for checking of loading language strings/translations */ @@ -303,18 +237,4 @@ public class LanguageLoader { } } - /** - * Removes the UTF-8 Byte Order Mark if present - * - * @param string

The string to remove the BOM from

- * @return

A string guaranteed without a BOM

- */ - private String removeUTF8BOM(String string) { - String UTF8_BOM = "\uFEFF"; - if (string.startsWith(UTF8_BOM)) { - string = string.substring(1); - } - return string; - } - } diff --git a/src/main/java/net/knarcraft/stargate/Stargate.java b/src/main/java/net/knarcraft/stargate/Stargate.java index d0c67c3..975c97c 100644 --- a/src/main/java/net/knarcraft/stargate/Stargate.java +++ b/src/main/java/net/knarcraft/stargate/Stargate.java @@ -3,7 +3,6 @@ package net.knarcraft.stargate; import net.knarcraft.stargate.command.CommandStarGate; import net.knarcraft.stargate.command.StarGateTabCompleter; import net.knarcraft.stargate.container.BlockChangeRequest; -import net.knarcraft.stargate.container.TwoTuple; import net.knarcraft.stargate.listener.BlockEventListener; import net.knarcraft.stargate.listener.BungeeCordListener; import net.knarcraft.stargate.listener.EntityEventListener; @@ -18,6 +17,7 @@ import net.knarcraft.stargate.portal.PortalHandler; import net.knarcraft.stargate.thread.BlockChangeThread; import net.knarcraft.stargate.thread.StarGateThread; import net.knarcraft.stargate.utility.EconomyHandler; +import net.knarcraft.stargate.utility.FileHelper; import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.Server; @@ -34,11 +34,9 @@ import org.bukkit.plugin.messaging.Messenger; import java.io.File; import java.io.IOException; -import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedList; -import java.util.List; import java.util.Map; import java.util.Queue; import java.util.concurrent.ConcurrentLinkedQueue; @@ -400,6 +398,7 @@ public class Stargate extends JavaPlugin { /** * Changes all configuration values from the old name to the new name + * * @param newConfig

The config to read from and write to

*/ private void migrateConfig(FileConfiguration newConfig) { @@ -411,42 +410,25 @@ public class Stargate extends JavaPlugin { return; } - List> migrationFields = new ArrayList<>(); - migrationFields.add(new TwoTuple<>("lang", "language")); - migrationFields.add(new TwoTuple<>("portal-folder", "folders.portalFolder")); - migrationFields.add(new TwoTuple<>("gate-folder", "folders.gateFolder")); - migrationFields.add(new TwoTuple<>("default-gate-network", "gates.defaultGateNetwork")); - migrationFields.add(new TwoTuple<>("destroyexplosion", "gates.integrity.destroyedByExplosion")); - migrationFields.add(new TwoTuple<>("maxgates", "gates.maxGatesEachNetwork")); - migrationFields.add(new TwoTuple<>("destMemory", "gates.cosmetic.rememberDestination")); - migrationFields.add(new TwoTuple<>("ignoreEntrance", "gates.integrity.ignoreEntrance")); - migrationFields.add(new TwoTuple<>("handleVehicles", "gates.functionality.handleVehicles")); - migrationFields.add(new TwoTuple<>("sortLists", "gates.cosmetic.sortNetworkDestinations")); - migrationFields.add(new TwoTuple<>("protectEntrance", "gates.integrity.protectEntrance")); - migrationFields.add(new TwoTuple<>("enableBungee", "gates.functionality.enableBungee")); - migrationFields.add(new TwoTuple<>("verifyPortals", "gates.integrity.verifyPortals")); - migrationFields.add(new TwoTuple<>("signColor", "gates.cosmetic.signColor")); - migrationFields.add(new TwoTuple<>("debug", "debugging.debug")); - migrationFields.add(new TwoTuple<>("permdebug", "debugging.permissionDebug")); - migrationFields.add(new TwoTuple<>("useiconomy", "economy.useEconomy")); - migrationFields.add(new TwoTuple<>("useeconomy", "economy.useEconomy")); - migrationFields.add(new TwoTuple<>("createcost", "economy.createCost")); - migrationFields.add(new TwoTuple<>("destroycost", "economy.destroyCost")); - migrationFields.add(new TwoTuple<>("usecost", "economy.useCost")); - migrationFields.add(new TwoTuple<>("toowner", "economy.toOwner")); - migrationFields.add(new TwoTuple<>("chargefreedestination", "economy.chargeFreeDestination")); - migrationFields.add(new TwoTuple<>("freegatesgreen", "economy.freeGatesGreen")); - migrationFields.add(new TwoTuple<>("CheckUpdates", "")); + Map migrationFields; + try { + migrationFields = FileHelper.readKeyValuePairs(FileHelper.getBufferedReaderFromInputStream( + FileHelper.getInputStreamForInternalFile("/config-migrations.txt"))); + } catch (IOException e) { + Stargate.debug("Stargate::migrateConfig", "Unable to load config migration file"); + e.printStackTrace(); + return; + } - for (TwoTuple migration : migrationFields) { - String oldPath = migration.getFirstValue(); - if (newConfig.contains(oldPath)) { - String newPath = migration.getSecondValue(); - Object oldValue = newConfig.get(oldPath); + //Replace old config names with the new ones + for (String key : migrationFields.keySet()) { + if (newConfig.contains(key)) { + String newPath = migrationFields.get(key); + Object oldValue = newConfig.get(key); if (!newPath.trim().isEmpty()) { newConfig.set(newPath, oldValue); } - newConfig.set(oldPath, null); + newConfig.set(key, null); } } } diff --git a/src/main/java/net/knarcraft/stargate/utility/FileHelper.java b/src/main/java/net/knarcraft/stargate/utility/FileHelper.java new file mode 100644 index 0000000..829b5dc --- /dev/null +++ b/src/main/java/net/knarcraft/stargate/utility/FileHelper.java @@ -0,0 +1,125 @@ +package net.knarcraft.stargate.utility; + +import org.bukkit.ChatColor; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.Map; + +/** + * Helper class for reading files + */ +public final class FileHelper { + + private FileHelper() { + + } + + /** + * Gets a buffered reader from a string pointing to a file + * + * @param file

The file to read

+ * @return

A buffered reader reading the file

+ */ + public static InputStream getInputStreamForInternalFile(String file) { + return FileHelper.class.getResourceAsStream(file); + } + + /** + * Gets a buffered reader from a string pointing to a file + * + * @param file

The file to read

+ * @return

A buffered reader reading the file

+ * @throws FileNotFoundException

If the given file does not exist

+ */ + public static BufferedReader getBufferedReaderFromString(String file) throws FileNotFoundException { + FileInputStream fileInputStream = new FileInputStream(file); + return getBufferedReaderFromInputStream(fileInputStream); + } + + /** + * Gets a buffered reader from an input stream + * + * @param inputStream

The input stream to read

+ * @return

A buffered reader reading the stream

+ */ + public static BufferedReader getBufferedReaderFromInputStream(InputStream inputStream) { + InputStreamReader inputStreamReader = new InputStreamReader(inputStream, StandardCharsets.UTF_8); + return new BufferedReader(inputStreamReader); + } + + /** + * Gets a buffered writer from a string pointing to a file + * + * @param file

The file to write to

+ * @return

A buffered writer writing to the file

+ * @throws FileNotFoundException

If the file does not exist

+ */ + public static BufferedWriter getBufferedWriterFromString(String file) throws FileNotFoundException { + FileOutputStream fileOutputStream = new FileOutputStream(file); + OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream, StandardCharsets.UTF_8); + return new BufferedWriter(outputStreamWriter); + } + + /** + * Reads key value pairs from an input stream + * + * @param bufferedReader

The buffered reader to read

+ * @return

A map containing the read pairs

+ * @throws IOException

If unable to read from the stream

+ */ + public static Map readKeyValuePairs(BufferedReader bufferedReader) throws IOException { + + Map readPairs = new HashMap<>(); + + String line = bufferedReader.readLine(); + boolean firstLine = true; + while (line != null) { + // Strip UTF BOM + if (firstLine) { + line = removeUTF8BOM(line); + firstLine = false; + } + //Split at first "=" + int equalSignIndex = line.indexOf('='); + if (equalSignIndex == -1) { + line = bufferedReader.readLine(); + continue; + } + + //Read the line + String key = line.substring(0, equalSignIndex); + String value = ChatColor.translateAlternateColorCodes('&', line.substring(equalSignIndex + 1)); + readPairs.put(key, value); + + line = bufferedReader.readLine(); + } + bufferedReader.close(); + + return readPairs; + } + + /** + * Removes the UTF-8 Byte Order Mark if present + * + * @param string

The string to remove the BOM from

+ * @return

A string guaranteed without a BOM

+ */ + private static String removeUTF8BOM(String string) { + String UTF8_BOM = "\uFEFF"; + if (string.startsWith(UTF8_BOM)) { + string = string.substring(1); + } + return string; + } + +} diff --git a/src/main/resources/config-migrations.txt b/src/main/resources/config-migrations.txt new file mode 100644 index 0000000..eb53155 --- /dev/null +++ b/src/main/resources/config-migrations.txt @@ -0,0 +1,25 @@ +lang=language +portal-folder=folders.portalFolder +gate-folder=folders.gateFolder +default-gate-network=gates.defaultGateNetwork +destroyexplosion=gates.integrity.destroyedByExplosion +maxgates=gates.maxGatesEachNetwork +destMemory=gates.cosmetic.rememberDestination +ignoreEntrance=gates.integrity.ignoreEntrance +handleVehicles=gates.functionality.handleVehicles +sortLists=gates.cosmetic.sortNetworkDestinations +protectEntrance=gates.integrity.protectEntrance +enableBungee=gates.functionality.enableBungee +verifyPortals=gates.integrity.verifyPortals +signColor=gates.cosmetic.signColor +debug=debugging.debug +permdebug=debugging.permissionDebug +useiconomy=economy.useEconomy +useeconomy=economy.useEconomy +createcost=economy.createCost +destroycost=economy.destroyCost +usecost=economy.useCost +toowner=economy.toOwner +chargefreedestination=economy.chargeFreeDestination +freegatesgreen=economy.freeGatesGreen +CheckUpdates= \ No newline at end of file