diff --git a/build.gradle b/build.gradle index 2e2c3b5..9f8b69d 100644 --- a/build.gradle +++ b/build.gradle @@ -27,10 +27,10 @@ allprojects { processResources { from(sourceSets.main.resources.srcDirs) { filter ReplaceTokens, tokens: [version: version] - filter ReplaceTokens, tokens: [name: pluginName] - filter ReplaceTokens, tokens: [groupId: pluginGroup] - filter ReplaceTokens, tokens: [author: pluginAuthor] - filter ReplaceTokens, tokens: [apiVersion: pluginApiVersion] + filter ReplaceTokens, tokens: [name: pluginName] + filter ReplaceTokens, tokens: [groupId: pluginGroup] + filter ReplaceTokens, tokens: [author: pluginAuthor] + filter ReplaceTokens, tokens: [apiVersion: pluginApiVersion] } } } @@ -52,6 +52,8 @@ dependencies { //Spigot API compileOnly 'org.spigotmc:spigot-api:1.16.1-R0.1-SNAPSHOT' + + compile 'dev.array21:classvalidator:1.0.0' } @@ -61,6 +63,7 @@ shadowJar() { relocate 'com.google.code.gson', 'nl.thedutchmc.skinfixer.libs.com.google.code.gson' relocate 'nl.thedutchmc.httplib', 'nl.thedutchmc.skinfixer.libs.nl.thedutchmc.httplib' relocate 'org.slf4j', 'nl.thedutchmc.skinfixer.libs.org.slf4j' + relocate 'dev.array21.classvalidator', 'nl.thedutchmc.skinfixer.libs.dev.array21.classvalidator' } task testJar(type: ShadowJar) { diff --git a/gradle.properties b/gradle.properties index 88a2ba0..fec26bd 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ -pluginVersion = 1.3.1 +pluginVersion = 1.4.0 pluginGroup = nl.thedutchmc pluginName = SkinFixer pluginAuthor = TheDutchMC diff --git a/src/main/java/nl/thedutchmc/SkinFixer/SkinFixer.java b/src/main/java/nl/thedutchmc/SkinFixer/SkinFixer.java index ea6f7d3..53a378d 100644 --- a/src/main/java/nl/thedutchmc/SkinFixer/SkinFixer.java +++ b/src/main/java/nl/thedutchmc/SkinFixer/SkinFixer.java @@ -10,6 +10,7 @@ import nl.thedutchmc.SkinFixer.commandexecutors.SkinFixerCommandExecutor; import nl.thedutchmc.SkinFixer.fileHandlers.ConfigurationHandler; import nl.thedutchmc.SkinFixer.fileHandlers.StorageHandler; +import nl.thedutchmc.SkinFixer.language.LangHandler; import nl.thedutchmc.SkinFixer.minecraftevents.PlayerJoinEventListener; public class SkinFixer extends JavaPlugin { @@ -35,12 +36,18 @@ public void onEnable() { ConfigurationHandler configHandler = new ConfigurationHandler(); configHandler.loadConfig(); + LangHandler langHandler = new LangHandler(this); + if(ConfigurationHandler.language != null) { + langHandler.loadLang(ConfigurationHandler.language); + } else { + SkinFixer.logWarn("Configuration entry 'language' is missing. Using English as default."); + langHandler.loadLang("en"); + } + //Storage of skins and pending keys STORAGE = new StorageHandler(); STORAGE.loadConfig(); - - if(Bukkit.getOnlineMode() == true) logInfo("This plugin is not needed on servers running in online mode!"); - + //Register command executors this.getCommand("setskin").setExecutor(new SetSkinCommandExecutor()); this.getCommand("getcode").setExecutor(new GetCodeCommandExecutor()); diff --git a/src/main/java/nl/thedutchmc/SkinFixer/changeSkin/SkinChangeHandler.java b/src/main/java/nl/thedutchmc/SkinFixer/changeSkin/SkinChangeHandler.java index d73eee9..df6d362 100644 --- a/src/main/java/nl/thedutchmc/SkinFixer/changeSkin/SkinChangeHandler.java +++ b/src/main/java/nl/thedutchmc/SkinFixer/changeSkin/SkinChangeHandler.java @@ -21,6 +21,7 @@ import nl.thedutchmc.SkinFixer.apis.MineskinApi; import nl.thedutchmc.SkinFixer.fileHandlers.StorageHandler; import nl.thedutchmc.SkinFixer.gson.GetSkinResponse; +import nl.thedutchmc.SkinFixer.language.LangHandler; import nl.thedutchmc.SkinFixer.util.ReflectionUtil; import nl.thedutchmc.SkinFixer.util.Triple; @@ -35,7 +36,8 @@ public static void changeSkinJson(String skinUrl, UUID internalUuid, UUID extern public void run() { Player player = Bukkit.getPlayer(internalUuid); - player.sendMessage(ChatColor.GOLD + "Fetching skin value and signature..."); + //player.sendMessage(ChatColor.GOLD + "Fetching skin value and signature..."); + player.sendMessage(ChatColor.GOLD + LangHandler.model.skinFetching); //Fetch the skin from Mineskin.org's API Triple apiResponse; @@ -46,7 +48,8 @@ public void run() { } if(!apiResponse.getA()) { - player.sendMessage(ChatColor.RED + "Something went wrong applying your skin:\n" + ChatColor.GRAY + apiResponse.getC()); + //player.sendMessage(ChatColor.RED + "Something went wrong applying your skin:\n" + ChatColor.GRAY + apiResponse.getC()); + player.sendMessage(ChatColor.RED + LangHandler.model.skinApplyFailed.replaceAll("%ERROR%", ChatColor.GRAY + apiResponse.getC() + ChatColor.RED)); return; } @@ -63,7 +66,6 @@ public static void changeSkinFromObject(SkinObject skin) { private static void changeSkin(String skinValue, String skinSignature, UUID caller, boolean slim ) { Player player = Bukkit.getPlayer(caller); - //Store the skin to the storage file, so it can be reapplied when they join. if(StorageHandler.skins.containsKey(caller)) { SkinObject skin = StorageHandler.skins.get(caller); if(slim) skin.setSlim(true); @@ -74,13 +76,13 @@ private static void changeSkin(String skinValue, String skinSignature, UUID call StorageHandler.skins.put(caller, skin); } - player.sendMessage(ChatColor.GOLD + "Applying skin..."); + player.sendMessage(ChatColor.GOLD + LangHandler.model.skinApplying); applySkin(player, skinValue, skinSignature); reloadPlayer(player); //Inform the player that we're done - player.sendMessage(ChatColor.GOLD + "Done."); + player.sendMessage(ChatColor.GOLD + LangHandler.model.skinApplied); } private static void applySkin(Player player, String skinValue, String skinSignature) { diff --git a/src/main/java/nl/thedutchmc/SkinFixer/commandexecutors/GetCodeCommandExecutor.java b/src/main/java/nl/thedutchmc/SkinFixer/commandexecutors/GetCodeCommandExecutor.java index f4b8776..848de52 100644 --- a/src/main/java/nl/thedutchmc/SkinFixer/commandexecutors/GetCodeCommandExecutor.java +++ b/src/main/java/nl/thedutchmc/SkinFixer/commandexecutors/GetCodeCommandExecutor.java @@ -7,6 +7,7 @@ import net.md_5.bungee.api.ChatColor; import nl.thedutchmc.SkinFixer.common.AddNewSkin; +import nl.thedutchmc.SkinFixer.language.LangHandler; public class GetCodeCommandExecutor implements CommandExecutor { @@ -14,23 +15,25 @@ public class GetCodeCommandExecutor implements CommandExecutor { public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { if(!(sender instanceof Player)) { - sender.sendMessage(ChatColor.RED + "This command is for players only!"); + sender.sendMessage(ChatColor.RED + LangHandler.model.commandPlayerOnly); return true; } if(!sender.hasPermission("skinfixer.getcode") ) { - sender.sendMessage(ChatColor.RED + "You don't have permission to use this command!"); + //sender.sendMessage(ChatColor.RED + "You don't have permission to use this command!"); + sender.sendMessage(ChatColor.RED + LangHandler.model.commandNoPermission); return true; } if(args.length == 0) { - sender.sendMessage(ChatColor.RED + "You need to provide a URL to your skin!"); + //sender.sendMessage(ChatColor.RED + "You need to provide a URL to your skin!"); + sender.sendMessage(ChatColor.RED + LangHandler.model.getCodeUrlRequired); return true; } int code = AddNewSkin.add(args[0]); - sender.sendMessage(ChatColor.GOLD + "Your skin has been added! You can apply it with /setskin " + code); - + //sender.sendMessage(ChatColor.GOLD + "Your skin has been added! You can apply it with /setskin " + code); + sender.sendMessage(ChatColor.GOLD + LangHandler.model.getCodeSkinAdded.replaceAll("%CODE%", ChatColor.RED + String.valueOf(code) + ChatColor.GOLD)); return true; } } diff --git a/src/main/java/nl/thedutchmc/SkinFixer/commandexecutors/SetSkinCommandExecutor.java b/src/main/java/nl/thedutchmc/SkinFixer/commandexecutors/SetSkinCommandExecutor.java index 57b3156..fe40a6a 100644 --- a/src/main/java/nl/thedutchmc/SkinFixer/commandexecutors/SetSkinCommandExecutor.java +++ b/src/main/java/nl/thedutchmc/SkinFixer/commandexecutors/SetSkinCommandExecutor.java @@ -9,6 +9,7 @@ import nl.thedutchmc.SkinFixer.SkinFixer; import nl.thedutchmc.SkinFixer.changeSkin.SkinChangeHandler; import nl.thedutchmc.SkinFixer.fileHandlers.StorageHandler; +import nl.thedutchmc.SkinFixer.language.LangHandler; public class SetSkinCommandExecutor implements CommandExecutor { @@ -16,17 +17,17 @@ public class SetSkinCommandExecutor implements CommandExecutor { public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { if(!(sender instanceof Player)) { - sender.sendMessage(ChatColor.RED + "This command is for players only!"); + sender.sendMessage(ChatColor.RED + LangHandler.model.commandPlayerOnly); return true; } if(!sender.hasPermission("skinfixer.setskin") ) { - sender.sendMessage(ChatColor.RED + "You don't have permission to use this command!"); + sender.sendMessage(ChatColor.RED + LangHandler.model.commandNoPermission); return true; } if(args.length == 0) { - sender.sendMessage(ChatColor.RED + "You need to provide a code!"); + sender.sendMessage(ChatColor.RED + LangHandler.model.setSkinCodeRequired); return true; } @@ -34,12 +35,13 @@ public boolean onCommand(CommandSender sender, Command command, String label, St try { code = getIntFromString(args[0]); } catch(NumberFormatException e) { - sender.sendMessage(ChatColor.RED + "The code you entered is not a number!"); + sender.sendMessage(ChatColor.RED + LangHandler.model.setSkinCodeNotANumber); return true; } if(!StorageHandler.pendingLinks.containsKey(code)) { - sender.sendMessage(ChatColor.RED + "Unkown code!"); + //sender.sendMessage(ChatColor.RED + "Unkown code!"); + sender.sendMessage(ChatColor.RED + LangHandler.model.setSkinCodeUnknown); return true; } diff --git a/src/main/java/nl/thedutchmc/SkinFixer/commandexecutors/SkinFixerCommandExecutor.java b/src/main/java/nl/thedutchmc/SkinFixer/commandexecutors/SkinFixerCommandExecutor.java index 7db9a98..c5e91cf 100644 --- a/src/main/java/nl/thedutchmc/SkinFixer/commandexecutors/SkinFixerCommandExecutor.java +++ b/src/main/java/nl/thedutchmc/SkinFixer/commandexecutors/SkinFixerCommandExecutor.java @@ -6,6 +6,7 @@ import net.md_5.bungee.api.ChatColor; import nl.thedutchmc.SkinFixer.SkinFixer; +import nl.thedutchmc.SkinFixer.language.LangHandler; public class SkinFixerCommandExecutor implements CommandExecutor { @@ -16,23 +17,23 @@ public boolean onCommand(CommandSender sender, Command command, String label, St final ChatColor cw = ChatColor.WHITE; if(args.length == 0) { - sender.sendMessage(cg + "No option provided. See " + ChatColor.RED + "/skinfixer help " + cg + "for help!"); + sender.sendMessage(ChatColor.GOLD + LangHandler.model.skinFixerNoOptionProvided); return true; } if(args[0].equals("help")) { sender.sendMessage(cg + "SkinFixer help"); sender.sendMessage(cg + "------------"); - sender.sendMessage("- " + cg + "/setskin [slim true/false]" + cw + " Set your skin from a code."); - sender.sendMessage("- " + cg + "/getcode " + cw + " Generate a code from a Skin url. URL must be the skinfie itself."); - sender.sendMessage("- " + cg + "/skinfixer help" + cw + " Shows this page"); - sender.sendMessage("- " + cg + "/skinfixer version" + cw + " Returns the version of SkinFixer you are using"); + sender.sendMessage("- " + cg + "/setskin [slim true/false]" + cw + " " + LangHandler.model.skinFixerSetSkinHelp); + sender.sendMessage("- " + cg + "/getcode " + cw + " " + LangHandler.model.skinFixerGetCodeHelp); + sender.sendMessage("- " + cg + "/skinfixer help" + cw + " " + LangHandler.model.skinFixerShowHelp); + sender.sendMessage("- " + cg + "/skinfixer version" + cw + " " + LangHandler.model.skinFixerVersionHelp); return true; } if(args[0].equals("version")) { - sender.sendMessage(cg + "You are using SkinFixer version " + ChatColor.RED + SkinFixer.PLUGIN_VERSION); + sender.sendMessage(cg + LangHandler.model.skinFixerVersion.replaceAll("%VERSION%", ChatColor.RED + SkinFixer.PLUGIN_VERSION + ChatColor.GOLD)); return true; } diff --git a/src/main/java/nl/thedutchmc/SkinFixer/discordEvents/MessageReceivedEventListener.java b/src/main/java/nl/thedutchmc/SkinFixer/discordEvents/MessageReceivedEventListener.java index 67c307c..9ef9ac4 100644 --- a/src/main/java/nl/thedutchmc/SkinFixer/discordEvents/MessageReceivedEventListener.java +++ b/src/main/java/nl/thedutchmc/SkinFixer/discordEvents/MessageReceivedEventListener.java @@ -9,6 +9,7 @@ import net.dv8tion.jda.api.hooks.ListenerAdapter; import nl.thedutchmc.SkinFixer.JdaHandler; import nl.thedutchmc.SkinFixer.common.AddNewSkin; +import nl.thedutchmc.SkinFixer.language.LangHandler; public class MessageReceivedEventListener extends ListenerAdapter { @@ -25,7 +26,7 @@ public void onMessageReceived(MessageReceivedEvent event) { for(Attachment a : attachments) { int n = AddNewSkin.add(a.getUrl()); - msgChannel.sendMessage("You can set this as your skin in-game using /setskin " + n).queue(); + msgChannel.sendMessage(LangHandler.model.discordSetSkin.replaceAll("%CODE%", String.valueOf(n))).queue(); } } } diff --git a/src/main/java/nl/thedutchmc/SkinFixer/fileHandlers/ConfigurationHandler.java b/src/main/java/nl/thedutchmc/SkinFixer/fileHandlers/ConfigurationHandler.java index e0f9210..a94b47a 100644 --- a/src/main/java/nl/thedutchmc/SkinFixer/fileHandlers/ConfigurationHandler.java +++ b/src/main/java/nl/thedutchmc/SkinFixer/fileHandlers/ConfigurationHandler.java @@ -14,6 +14,11 @@ public class ConfigurationHandler { public static boolean useDiscord; public static String token, channel; + /** + * @since 1.4.0 + */ + public static String language; + private File file; private FileConfiguration config; @@ -53,5 +58,7 @@ public void readConfig() { useDiscord = false; } } + + language = this.getConfig().getString("language"); } } diff --git a/src/main/java/nl/thedutchmc/SkinFixer/language/LangHandler.java b/src/main/java/nl/thedutchmc/SkinFixer/language/LangHandler.java new file mode 100644 index 0000000..9926a0e --- /dev/null +++ b/src/main/java/nl/thedutchmc/SkinFixer/language/LangHandler.java @@ -0,0 +1,97 @@ +package nl.thedutchmc.SkinFixer.language; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.LinkedHashMap; + +import org.bukkit.Bukkit; +import org.yaml.snakeyaml.Yaml; + +import com.google.common.io.Files; +import com.google.gson.Gson; + +import dev.array21.classvalidator.ClassValidator; +import dev.array21.classvalidator.Pair; +import nl.thedutchmc.SkinFixer.SkinFixer; +import nl.thedutchmc.SkinFixer.util.Utils; + +public class LangHandler { + + private SkinFixer plugin; + + public static LanguageModel model; + + public LangHandler(SkinFixer plugin) { + this.plugin = plugin; + + File langFolder = new File(this.plugin.getDataFolder() + File.separator + "langs"); + if(!langFolder.exists()) { + langFolder.mkdirs(); + } + } + + public void loadLang(String lang) { + File langFile = new File(this.plugin.getDataFolder() + File.separator + "langs", lang + ".yml"); + if(!langFile.exists()) { + SkinFixer.logWarn("Failed to load language model " + lang + ".yml!"); + langFile = getEngModel(); + } + + LanguageModel model = loadModel(langFile); + LangHandler.model = model; + } + + private File getEngModel() { + File langFile = new File(this.plugin.getDataFolder() + File.separator + "langs", "en.yml"); + if(!langFile.exists()) { + SkinFixer.logInfo("Language model 'en.yml' does not exist. Saving from JAR."); + this.plugin.saveResource("en.yml", false); + + try { + Files.move(new File(this.plugin.getDataFolder(), "en.yml"), langFile); + } catch(IOException e) { + SkinFixer.logWarn("Failed to save language model 'en.yml': " + e.getMessage()); + SkinFixer.logWarn(Utils.getStackTrace(e)); + + Bukkit.getPluginManager().disablePlugin(this.plugin); + return null; + } + } + + return langFile; + } + + private LanguageModel loadModel(File modelFile) { + final Yaml yaml = new Yaml(); + final Gson gson = new Gson(); + + Object yamlData; + try { + yamlData = yaml.load(new FileInputStream(modelFile)); + } catch(FileNotFoundException e) { + SkinFixer.logWarn(String.format("Failed to load LanguuageModel '%s'. It does not exist.", modelFile.getAbsolutePath())); + Bukkit.getPluginManager().disablePlugin(this.plugin); + return null; + } + + String jsonData = gson.toJson(yamlData, LinkedHashMap.class); + LanguageModel model = gson.fromJson(jsonData, LanguageModel.class); + + Pair validationResult = ClassValidator.validateType(model); + if(validationResult.getA() == null) { + SkinFixer.logWarn("Failed to validate language model: " + validationResult.getB()); + Bukkit.getPluginManager().disablePlugin(this.plugin); + return null; + } + + if(!validationResult.getA() ) { + SkinFixer.logWarn(String.format("LanguageModel '%s' failed validation: %s", modelFile.getAbsolutePath(), validationResult.getB())); + Bukkit.getPluginManager().disablePlugin(this.plugin); + return null; + } + + return model; + } +} diff --git a/src/main/java/nl/thedutchmc/SkinFixer/language/LanguageModel.java b/src/main/java/nl/thedutchmc/SkinFixer/language/LanguageModel.java new file mode 100644 index 0000000..a6b900c --- /dev/null +++ b/src/main/java/nl/thedutchmc/SkinFixer/language/LanguageModel.java @@ -0,0 +1,58 @@ +package nl.thedutchmc.SkinFixer.language; + +import dev.array21.classvalidator.annotations.Required; + +public class LanguageModel { + + // SkinChangeHandler + @Required + public String skinFetching; + @Required + //Variable: %ERROR% + public String skinApplyFailed; + @Required + public String skinApplying; + @Required + public String skinApplied; + + //General commands + @Required + public String commandPlayerOnly; + @Required + public String commandNoPermission; + + //GetCodeCommandExecutor + @Required + public String getCodeUrlRequired; + @Required + //Variable: %CODE% + public String getCodeSkinAdded; + + //SetSkinCommandExecutor + @Required + public String setSkinCodeRequired; + @Required + public String setSkinCodeNotANumber; + @Required + public String setSkinCodeUnknown; + + //SkinFixerCommandExecutor + @Required + public String skinFixerNoOptionProvided; + @Required + public String skinFixerSetSkinHelp; + @Required + public String skinFixerGetCodeHelp; + @Required + public String skinFixerShowHelp; + @Required + public String skinFixerVersionHelp; + @Required + //Variable: %VERSION% + public String skinFixerVersion; + + //MessageReceivedEventListener + @Required + //Variable: %CODE% + public String discordSetSkin; +} diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 2868a75..6b11fcd 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -6,3 +6,5 @@ discordToken: "" #Discord Channel used for uploading skins skinDiscordChannel: "" + +language: en \ No newline at end of file diff --git a/src/main/resources/en.yml b/src/main/resources/en.yml new file mode 100644 index 0000000..9cd392a --- /dev/null +++ b/src/main/resources/en.yml @@ -0,0 +1,23 @@ +skinFetching: Fetching skin value and signature... +skinApplyFailed: Something went wrong applying your skin %ERROR% +skinApplying: Applying skin... +skinApplied: Done. + +commandPlayerOnly: This command is for players only! +commandNoPermission: You don't have permission to use this command! + +getCodeUrlRequired: You need to provide a URL to your skin! +getCodeSkinAdded: Your skin has been added! You can apply it with /setskin %CODE%. + +setSkinCodeRequired: You need to provide a code! +setSkinCodeNotANumber: The code you entered is not a number! +setSkinCodeUnknown: Unknown code! + +skinFixerNoOptionProvided: No option provided. See /skinfixer help for help! +skinFixerSetSkinHelp: Set your skin from a code. +skinFixerGetCodeHelp: Generate a code from a Skin url. URL must be the skinfie itself. +skinFixerShowHelp: Shows this page. +skinFixerVersionHelp: Returns the version of SkinFixer you are using +skinFixerVersion: You are using SkinFixer version %VERSION% + +discordSetSkin: You can set this as your skin in-game using /setskin %CODE% \ No newline at end of file