From 85cc76a022f201786089cc69f26ab30a852968eb Mon Sep 17 00:00:00 2001 From: Oth3r <68134921+Oth3r@users.noreply.github.com> Date: Mon, 16 Jun 2025 20:36:32 -0500 Subject: [PATCH] otterlib language system --- src/main/java/one/oth3r/sit/SitClient.java | 16 +-- .../one/oth3r/sit/command/SitCommand.java | 6 +- .../java/one/oth3r/sit/file/FileData.java | 30 +++++ .../java/one/oth3r/sit/file/LangReader.java | 124 ------------------ .../oth3r/sit/mixin/ReloadCommandMixin.java | 5 +- src/main/java/one/oth3r/sit/utl/Chat.java | 16 +++ src/main/java/one/oth3r/sit/utl/Events.java | 8 +- src/main/java/one/oth3r/sit/utl/Logic.java | 7 +- src/main/java/one/oth3r/sit/utl/Utl.java | 29 +--- 9 files changed, 69 insertions(+), 172 deletions(-) delete mode 100644 src/main/java/one/oth3r/sit/file/LangReader.java create mode 100644 src/main/java/one/oth3r/sit/utl/Chat.java diff --git a/src/main/java/one/oth3r/sit/SitClient.java b/src/main/java/one/oth3r/sit/SitClient.java index c39fbba..a1796ec 100644 --- a/src/main/java/one/oth3r/sit/SitClient.java +++ b/src/main/java/one/oth3r/sit/SitClient.java @@ -7,9 +7,9 @@ import one.oth3r.otterlib.client.screen.ConfigScreen; import one.oth3r.otterlib.client.screen.utl.CustomImage; import one.oth3r.otterlib.client.screen.utl.SimpleButton; import one.oth3r.sit.file.FileData; +import one.oth3r.sit.utl.Chat; import one.oth3r.sit.utl.Data; import one.oth3r.sit.utl.Events; -import one.oth3r.sit.utl.Utl; import java.net.URI; import java.util.List; @@ -23,17 +23,17 @@ public class SitClient implements ClientModInitializer { } public static Screen getConfigScreen(Screen parent) { - return new ConfigScreen(parent, Utl.lang("sit!.screen.config"), + return new ConfigScreen(parent, Chat.lang("sit!.screen.config"), new CustomImage(Identifier.of(Data.MOD_ID, "textures/gui/banner.png"),128, 72), List.of( - SimpleButton.Templates.fileEditor(Utl.lang("config.server"), FileData.getServerConfig(), new CustomImage(Identifier.of(Data.MOD_ID, "server_button"),246,26)).build(), - SimpleButton.Templates.fileEditor(Utl.lang("config.sitting"), FileData.getSittingConfig(), new CustomImage(Identifier.of(Data.MOD_ID, "sitting_button"), 246, 26)).build() + SimpleButton.Templates.fileEditor(Chat.lang("config.server"), FileData.getServerConfig(), new CustomImage(Identifier.of(Data.MOD_ID, "server_button"),246,26)).build(), + SimpleButton.Templates.fileEditor(Chat.lang("config.sitting"), FileData.getSittingConfig(), new CustomImage(Identifier.of(Data.MOD_ID, "sitting_button"), 246, 26)).build() ), List.of( - SimpleButton.Templates.warning(Utl.lang("sit!.gui.button.issues")).openLink("https://github.com/Oth3r/Sit/issues").build(), - new SimpleButton.Builder(Utl.lang("sit!.gui.button.website")).openLink("https://modrinth.com/mod/sit!").build(), - SimpleButton.Templates.done(Utl.lang("gui.done")).build(), - SimpleButton.Templates.donate(Utl.lang("sit!.gui.button.donate")).openLink(URI.create("https://ko-fi.com/oth3r")).build() + SimpleButton.Templates.warning(Chat.lang("sit!.gui.button.issues")).openLink("https://github.com/Oth3r/Sit/issues").build(), + new SimpleButton.Builder(Chat.lang("sit!.gui.button.website")).openLink("https://modrinth.com/mod/sit!").build(), + SimpleButton.Templates.done(Chat.lang("gui.done")).build(), + SimpleButton.Templates.donate(Chat.lang("sit!.gui.button.donate")).openLink(URI.create("https://ko-fi.com/oth3r")).build() )); } } diff --git a/src/main/java/one/oth3r/sit/command/SitCommand.java b/src/main/java/one/oth3r/sit/command/SitCommand.java index 7abd2f3..ad928ed 100644 --- a/src/main/java/one/oth3r/sit/command/SitCommand.java +++ b/src/main/java/one/oth3r/sit/command/SitCommand.java @@ -8,8 +8,8 @@ import com.mojang.brigadier.suggestion.SuggestionsBuilder; import net.minecraft.server.command.CommandManager; import net.minecraft.server.command.ServerCommandSource; import net.minecraft.server.network.ServerPlayerEntity; -import net.minecraft.util.Formatting; import net.minecraft.util.math.BlockPos; +import one.oth3r.sit.utl.Chat; import one.oth3r.sit.utl.Data; import one.oth3r.sit.utl.Logic; import one.oth3r.sit.utl.Utl; @@ -50,7 +50,7 @@ public class SitCommand { if (player == null) { if (args[0].equalsIgnoreCase("reload")) { Logic.reload(); - Data.LOGGER.info(Utl.lang("sit!.chat.reloaded").toString()); + Data.LOGGER.info(Chat.lang("sit!.chat.reloaded").toString()); } return 1; } @@ -76,7 +76,7 @@ public class SitCommand { if (args[0].equalsIgnoreCase("reload")) { Logic.reload(); - player.sendMessage(Utl.messageTag().append(Utl.lang("sit!.chat.reloaded").color(Color.GREEN)).b()); + player.sendMessage(Chat.tag().append(Chat.lang("sit!.chat.reloaded").color(Color.GREEN)).b()); } if (args[0].equalsIgnoreCase("purgeChairEntities")) Utl.Entity.purge(player,true); diff --git a/src/main/java/one/oth3r/sit/file/FileData.java b/src/main/java/one/oth3r/sit/file/FileData.java index 4e95a66..e64879f 100644 --- a/src/main/java/one/oth3r/sit/file/FileData.java +++ b/src/main/java/one/oth3r/sit/file/FileData.java @@ -1,9 +1,15 @@ package one.oth3r.sit.file; import net.minecraft.server.network.ServerPlayerEntity; +import one.oth3r.otterlib.file.LanguageReader; +import one.oth3r.sit.Sit; import one.oth3r.sit.utl.Data; import one.oth3r.sit.utl.Utl; +import java.net.URISyntaxException; +import java.net.URL; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; @@ -56,11 +62,21 @@ public class FileData { return playerSettings.getOrDefault(player, sittingConfig); } + /// the language / text system for the mod + private static final LanguageReader langReader = new LanguageReader( + getLangPath(),Path.of(Data.CONFIG_DIR),"en_us","en_us"); + + public static LanguageReader getLangReader() { + return langReader; + } + /** * loads all config files to memory */ public static void loadFiles() { getServerConfig().load(); + // load the language reader + langReader.updateLanguage(getServerConfig().getLang()); getSittingConfig().load(); // if loading file and is on supported server on client, send the new settings over @@ -77,6 +93,20 @@ public class FileData { getServerConfig().save(); } + private static Path getLangPath() { + ClassLoader classLoader = Sit.class.getClassLoader(); + URL resource = classLoader.getResource("assets/sit-oth3r/lang/"); + if (resource == null) { + throw new RuntimeException("Language file not found."); + } + + try { + return Paths.get(resource.toURI()); + } catch (URISyntaxException e) { + throw new RuntimeException(e); + } + } + public static class Defaults { public static final ArrayList SITTING_BLOCKS = new ArrayList<>(Arrays.asList( new SittingBlock(new ArrayList<>(),new ArrayList<>(Arrays.asList("#minecraft:campfires")), new ArrayList<>(Arrays.asList("lit=false")),.437), diff --git a/src/main/java/one/oth3r/sit/file/LangReader.java b/src/main/java/one/oth3r/sit/file/LangReader.java deleted file mode 100644 index d503bfb..0000000 --- a/src/main/java/one/oth3r/sit/file/LangReader.java +++ /dev/null @@ -1,124 +0,0 @@ -package one.oth3r.sit.file; - -import com.google.gson.Gson; -import com.google.gson.reflect.TypeToken; -import net.minecraft.text.MutableText; -import net.minecraft.text.Text; -import one.oth3r.otterlib.chat.CTxT; -import one.oth3r.sit.Sit; -import one.oth3r.sit.utl.Data; - -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.Reader; -import java.lang.reflect.Type; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.Map; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -public class LangReader { - private static final Map defaultLangMap = new HashMap<>(); - private static final Map languageMap = new HashMap<>(); - - private final String translationKey; - - private final Object[] placeholders; - - public LangReader(String translationKey, Object... placeholders) { - this.translationKey = translationKey; - this.placeholders = placeholders; - } - - public CTxT getTxT() { - String translated = getLanguageValue(translationKey); - if (placeholders != null && placeholders.length > 0) { - //removed all double \\ and replaces with \ - translated = translated.replaceAll("\\\\\\\\", "\\\\"); - String regex = "%\\d*\\$?[dfs]"; - Matcher anyMatch = Pattern.compile(regex).matcher(translated); - Matcher endMatch = Pattern.compile(regex+"$").matcher(translated); - - // Arraylist with all the %(#$)[dfs] - ArrayList matches = new ArrayList<>(); - while (anyMatch.find()) { - String match = anyMatch.group(); - matches.add(match); - } - //SPLITS the text at each regex and remove the regex - String[] parts = translated.split(regex); - //if the last element of the array ends with regex, remove it and add an empty string to the end of the array - if (endMatch.find()) { - String[] newParts = Arrays.copyOf(parts, parts.length + 1); - newParts[parts.length] = ""; - parts = newParts; - } - //if there are placeholders specified, and the split is more than 1, it will replace %(dfs) with the placeholder objects - if (parts.length > 1) { - CTxT txt = new CTxT(""); - int i = 0; - for (String match : matches) { - int get = i; - //if the match is numbered, change GET to the number it wants - if (match.contains("$")) { - match = match.substring(1,match.indexOf('$')); - get = Integer.parseInt(match)-1; - } - if (parts.length != i) txt.append(parts[i]); - //convert the obj into txt - txt.append(getTxTFromObj(placeholders[get])); - i++; - } - if (parts.length != i) txt.append(parts[i]); - return new CTxT(txt); - } - } - return new CTxT(translated); - } - - private CTxT getTxTFromObj(Object obj) { - if (obj instanceof CTxT) return (((CTxT) obj)); - else if (obj instanceof Text) return new CTxT((MutableText) obj); - else return new CTxT(String.valueOf(obj)); - } - - public static LangReader of(String translationKey, Object... placeholders) { - return new LangReader(translationKey, placeholders); - } - - public static void loadLanguageFile() { - Type tToken = new TypeToken>(){}.getType(); - try { - // load the config language - Reader selectionReader = new InputStreamReader(getInputStream(false), StandardCharsets.UTF_8); - languageMap.putAll(new Gson().fromJson(selectionReader, tToken)); - // load the default language as well (fallback) - Reader defaultReader = new InputStreamReader(getInputStream(true), StandardCharsets.UTF_8); - defaultLangMap.putAll(new Gson().fromJson(defaultReader, tToken)); - } catch (Exception e) { - Data.LOGGER.error("ERROR WITH LANGUAGE FILE - PLEASE REPORT WITH THE ERROR LOG"); - Data.LOGGER.error(e.getMessage()); - } - } - - private static InputStream getInputStream(boolean english) { - ClassLoader classLoader = Sit.class.getClassLoader(); - InputStream inputStream = classLoader.getResourceAsStream("assets/sit-oth3r/lang/"+FileData.getServerConfig().getLang()+".json"); - // make null if english - if (english) inputStream = null; - - // if it cant read (null), try again, but with the english file - if (inputStream == null) inputStream = classLoader.getResourceAsStream("assets/sit-oth3r/lang/"+new ServerConfig().getLang()+".json"); - - // if null after that, throw an exception - if (inputStream == null) throw new IllegalArgumentException("CANT LOAD THE LANGUAGE FILE. SIT! WILL BREAK."); - return inputStream; - } - - public static String getLanguageValue(String key) { - return languageMap.getOrDefault(key, defaultLangMap.getOrDefault(key, key)); - } -} \ No newline at end of file diff --git a/src/main/java/one/oth3r/sit/mixin/ReloadCommandMixin.java b/src/main/java/one/oth3r/sit/mixin/ReloadCommandMixin.java index 81d15fb..6edd652 100644 --- a/src/main/java/one/oth3r/sit/mixin/ReloadCommandMixin.java +++ b/src/main/java/one/oth3r/sit/mixin/ReloadCommandMixin.java @@ -5,10 +5,9 @@ import net.minecraft.server.MinecraftServer; import net.minecraft.server.command.ReloadCommand; import net.minecraft.server.command.ServerCommandSource; import net.minecraft.server.network.ServerPlayerEntity; -import net.minecraft.util.Formatting; +import one.oth3r.sit.utl.Chat; import one.oth3r.sit.utl.Data; import one.oth3r.sit.utl.Logic; -import one.oth3r.sit.utl.Utl; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; @@ -29,7 +28,7 @@ public class ReloadCommandMixin { // send a reloaded message to all players with permissions for (ServerPlayerEntity player : server.getPlayerManager().getPlayerList()) { if (player.isCreativeLevelTwoOp()) { - player.sendMessage(Utl.messageTag().append(Utl.lang("sit!.chat.reloaded").color(Color.GREEN)).b()); + player.sendMessage(Chat.tag().append(Chat.lang("sit!.chat.reloaded").color(Color.GREEN)).b()); } } } diff --git a/src/main/java/one/oth3r/sit/utl/Chat.java b/src/main/java/one/oth3r/sit/utl/Chat.java new file mode 100644 index 0000000..6dc2867 --- /dev/null +++ b/src/main/java/one/oth3r/sit/utl/Chat.java @@ -0,0 +1,16 @@ +package one.oth3r.sit.utl; + +import one.oth3r.otterlib.chat.CTxT; +import one.oth3r.sit.file.FileData; + +import java.awt.*; + +public class Chat { + public static CTxT tag() { + return new CTxT("Sit!").btn(true).color(Color.decode("#c400ff")).append(" "); + } + + public static CTxT lang(String key, Object... args) { + return FileData.getLangReader().dynamicTranslatable(key, args); + } +} diff --git a/src/main/java/one/oth3r/sit/utl/Events.java b/src/main/java/one/oth3r/sit/utl/Events.java index f62ea77..f4f2c64 100644 --- a/src/main/java/one/oth3r/sit/utl/Events.java +++ b/src/main/java/one/oth3r/sit/utl/Events.java @@ -23,7 +23,6 @@ import net.minecraft.util.ActionResult; import one.oth3r.sit.SitClient; import one.oth3r.sit.command.SitCommand; import one.oth3r.sit.file.FileData; -import one.oth3r.sit.file.LangReader; import one.oth3r.sit.file.SittingConfig; import one.oth3r.sit.packet.SitPayloads; import org.lwjgl.glfw.GLFW; @@ -78,7 +77,7 @@ public class Events { player.networkHandler.sendCommand("sit"); } else { // unsupported server message if not in a Sit! server - player.sendMessage(Utl.lang("sit!.chat.unsupported") + player.sendMessage(Chat.lang("sit!.chat.unsupported") .color(Color.RED).b(), true); } } @@ -104,7 +103,7 @@ public class Events { ServerPlayNetworking.send(context.player(),new SitPayloads.ResponsePayload(SitPayloads.ResponsePayload.VERSION)); // log the receiving of the packet from the player - Data.LOGGER.info(Utl.lang("sit!.console.player_settings",context.player().getName().getString()).toString()); + Data.LOGGER.info(Chat.lang("sit!.console.player_settings",context.player().getName().getString()).toString()); }))); } @@ -114,7 +113,7 @@ public class Events { // only update when needed if (!Data.isSupportedServer()) { Data.setSupportedServer(true); - Data.LOGGER.info(Utl.lang("sit!.console.connected",payload.value()).toString()); + Data.LOGGER.info(Chat.lang("sit!.console.connected",payload.value()).toString()); } })); } @@ -172,7 +171,6 @@ public class Events { private static void serverLifecycle() { ServerLifecycleEvents.SERVER_STARTED.register(s -> { Data.setServer(s); - LangReader.loadLanguageFile(); // right click on block event UseBlockCallback.EVENT.register((pl, world, hand, hitResult) -> { diff --git a/src/main/java/one/oth3r/sit/utl/Logic.java b/src/main/java/one/oth3r/sit/utl/Logic.java index b128b94..0433259 100644 --- a/src/main/java/one/oth3r/sit/utl/Logic.java +++ b/src/main/java/one/oth3r/sit/utl/Logic.java @@ -201,7 +201,6 @@ public class Logic { public static void reload() { FileData.loadFiles(); FileData.saveFiles(); - LangReader.loadLanguageFile(); } /** @@ -228,11 +227,11 @@ public class Logic { Formatting messageColor = config.getEnabled()?Formatting.GREEN:Formatting.RED; // send the player the actionbar message - return Utl.lang("sit!.chat.toggle_sit", - Utl.lang(messageKey).color(config.getEnabled()? Color.GREEN : Color.RED)).b(); + return Chat.lang("sit!.chat.toggle_sit", + Chat.lang(messageKey).color(config.getEnabled()? Color.GREEN : Color.RED)).b(); } else { // unsupported server message if not in a Sit! server - return Utl.lang("sit!.chat.unsupported") + return Chat.lang("sit!.chat.unsupported") .color(Color.RED).b(); } } diff --git a/src/main/java/one/oth3r/sit/utl/Utl.java b/src/main/java/one/oth3r/sit/utl/Utl.java index 4470d4b..d6d53bb 100644 --- a/src/main/java/one/oth3r/sit/utl/Utl.java +++ b/src/main/java/one/oth3r/sit/utl/Utl.java @@ -281,35 +281,14 @@ public class Utl { // send a message if needed if (message) { - player.sendMessage(messageTag() - .append(lang("sit!.chat.purged",lang("sit!.chat.purged.total",count).color(Color.gray).b()).color(Color.GREEN)).b()); + player.sendMessage(Chat.tag() + .append(Chat.lang("sit!.chat.purged", + Chat.lang("sit!.chat.purged.total",count).color(Color.gray).b() + ).color(Color.GREEN)).b()); } } } - public static CTxT messageTag() { - return new CTxT("Sit!").btn(true).color(Color.decode("#c400ff")).append(" "); - } - - /** - * gets a MutableText using the language key, if on server, using the custom lang reader - */ - public static CTxT lang(String key, Object... args) { - if (Data.isClient()) { - // we have to first convert all the CTxT's to the built version because minecraft lang reader doesn't know how to process it - // make a array with the same size of the args - Object[] fixedArgs = new Object[args.length]; - // for every arg, build & add if CTxT or just add if not - for (var i = 0; i < args.length; i++) { - if (args[i] instanceof CTxT) fixedArgs[i] = ((CTxT) args[i]).b(); - else fixedArgs[i] = args[i]; - } - // return the translated text - return new CTxT(Text.translatable(key,fixedArgs)); - } - else return LangReader.of(key, args).getTxT(); - } - /** * sends the settings packets to the server, if client & in game */