From 955004343f09bc97692aaac1fa6beb1eb8cb8e71 Mon Sep 17 00:00:00 2001
From: AnimeGitB <AnimeGitB@bigblueball.in>
Date: Sun, 21 Aug 2022 20:23:39 +0930
Subject: [PATCH] Improve translate function Make commands pass ints and floats
 instead of manually casting them to string first

---
 .../command/commands/AccountCommand.java      |  2 +-
 .../command/commands/GiveCommand.java         |  8 +++---
 .../command/commands/KickCommand.java         |  6 ++--
 .../command/commands/KillAllCommand.java      |  2 +-
 .../command/commands/ListCommand.java         |  2 +-
 .../command/commands/PositionCommand.java     |  3 +-
 .../command/commands/SendMailCommand.java     |  6 ++--
 .../command/commands/SetPropCommand.java      |  8 ++----
 .../command/commands/SpawnCommand.java        |  2 +-
 .../command/commands/TalentCommand.java       |  6 ++--
 .../command/commands/TeleportCommand.java     |  3 +-
 .../command/commands/WeatherCommand.java      |  4 +--
 .../java/emu/grasscutter/utils/Language.java  | 28 +++++++++++++++++++
 src/main/resources/languages/en-US.json       |  4 +--
 14 files changed, 54 insertions(+), 30 deletions(-)

diff --git a/src/main/java/emu/grasscutter/command/commands/AccountCommand.java b/src/main/java/emu/grasscutter/command/commands/AccountCommand.java
index 4127a3a2..45eb7ce4 100644
--- a/src/main/java/emu/grasscutter/command/commands/AccountCommand.java
+++ b/src/main/java/emu/grasscutter/command/commands/AccountCommand.java
@@ -87,7 +87,7 @@ public final class AccountCommand implements CommandHandler {
                     account.addPermission("*");
                     account.save(); // Save account to database.
 
-                    CommandHandler.sendMessage(sender, translate(sender, "commands.account.create", Integer.toString(account.getReservedPlayerUid())));
+                    CommandHandler.sendMessage(sender, translate(sender, "commands.account.create", account.getReservedPlayerUid()));
                 }
                 return;
             case "delete":
diff --git a/src/main/java/emu/grasscutter/command/commands/GiveCommand.java b/src/main/java/emu/grasscutter/command/commands/GiveCommand.java
index b6f29e84..f1d4c5ee 100644
--- a/src/main/java/emu/grasscutter/command/commands/GiveCommand.java
+++ b/src/main/java/emu/grasscutter/command/commands/GiveCommand.java
@@ -211,7 +211,7 @@ public final class GiveCommand implements CommandHandler {
             if (param.avatarData != null) {
                 Avatar avatar = makeAvatar(param);
                 targetPlayer.addAvatar(avatar);
-                CommandHandler.sendTranslatedMessage(sender, "commands.give.given_avatar", Integer.toString(param.id), Integer.toString(param.lvl), Integer.toString(targetPlayer.getUid()));
+                CommandHandler.sendTranslatedMessage(sender, "commands.give.given_avatar", param.id, param.lvl, targetPlayer.getUid());
                 return;
             }
             // If it's not an avatar, it needs to be a valid item
@@ -223,15 +223,15 @@ public final class GiveCommand implements CommandHandler {
             switch (param.data.getItemType()) {
                 case ITEM_WEAPON:
                     targetPlayer.getInventory().addItems(makeUnstackableItems(param), ActionReason.SubfieldDrop);
-                    CommandHandler.sendTranslatedMessage(sender, "commands.give.given_with_level_and_refinement", Integer.toString(param.id), Integer.toString(param.lvl), Integer.toString(param.refinement), Integer.toString(param.amount), Integer.toString(targetPlayer.getUid()));
+                    CommandHandler.sendTranslatedMessage(sender, "commands.give.given_with_level_and_refinement", param.id, param.lvl, param.refinement, param.amount, targetPlayer.getUid());
                     return;
                 case ITEM_RELIQUARY:
                     targetPlayer.getInventory().addItems(makeArtifacts(param), ActionReason.SubfieldDrop);
-                    CommandHandler.sendTranslatedMessage(sender, "commands.give.given_level", Integer.toString(param.id), Integer.toString(param.lvl), Integer.toString(param.amount), Integer.toString(targetPlayer.getUid()));
+                    CommandHandler.sendTranslatedMessage(sender, "commands.give.given_level", param.id, param.lvl, param.amount, targetPlayer.getUid());
                     return;
                 default:
                     targetPlayer.getInventory().addItem(new GameItem(param.data, param.amount), ActionReason.SubfieldDrop);
-                    CommandHandler.sendTranslatedMessage(sender, "commands.give.given", Integer.toString(param.amount), Integer.toString(param.id), Integer.toString(targetPlayer.getUid()));
+                    CommandHandler.sendTranslatedMessage(sender, "commands.give.given", param.amount, param.id, targetPlayer.getUid());
                     return;
             }
         } catch (IllegalArgumentException ignored) {
diff --git a/src/main/java/emu/grasscutter/command/commands/KickCommand.java b/src/main/java/emu/grasscutter/command/commands/KickCommand.java
index 32e0c9b1..265a97fa 100644
--- a/src/main/java/emu/grasscutter/command/commands/KickCommand.java
+++ b/src/main/java/emu/grasscutter/command/commands/KickCommand.java
@@ -13,11 +13,11 @@ public final class KickCommand implements CommandHandler {
     public void execute(Player sender, Player targetPlayer, List<String> args) {
         if (sender != null) {
             CommandHandler.sendTranslatedMessage(sender, "commands.kick.player_kick_player",
-                Integer.toString(sender.getUid()), sender.getAccount().getUsername(),
-                Integer.toString(targetPlayer.getUid()), targetPlayer.getAccount().getUsername());
+                sender.getUid(), sender.getAccount().getUsername(),
+                targetPlayer.getUid(), targetPlayer.getAccount().getUsername());
         } else {
             CommandHandler.sendTranslatedMessage(sender, "commands.kick.server_kick_player",
-                Integer.toString(targetPlayer.getUid()), targetPlayer.getAccount().getUsername());
+                targetPlayer.getUid(), targetPlayer.getAccount().getUsername());
         }
 
         targetPlayer.getSession().close();
diff --git a/src/main/java/emu/grasscutter/command/commands/KillAllCommand.java b/src/main/java/emu/grasscutter/command/commands/KillAllCommand.java
index dbc68886..3346cb1c 100644
--- a/src/main/java/emu/grasscutter/command/commands/KillAllCommand.java
+++ b/src/main/java/emu/grasscutter/command/commands/KillAllCommand.java
@@ -42,6 +42,6 @@ public final class KillAllCommand implements CommandHandler {
                 .filter(entity -> entity instanceof EntityMonster)
                 .toList();
         toKill.forEach(entity -> sceneF.killEntity(entity, 0));
-        CommandHandler.sendMessage(sender, translate(sender, "commands.killall.kill_monsters_in_scene", Integer.toString(toKill.size()), Integer.toString(scene.getId())));
+        CommandHandler.sendMessage(sender, translate(sender, "commands.killall.kill_monsters_in_scene", toKill.size(), scene.getId()));
     }
 }
diff --git a/src/main/java/emu/grasscutter/command/commands/ListCommand.java b/src/main/java/emu/grasscutter/command/commands/ListCommand.java
index 90ef724b..42e9b498 100644
--- a/src/main/java/emu/grasscutter/command/commands/ListCommand.java
+++ b/src/main/java/emu/grasscutter/command/commands/ListCommand.java
@@ -22,7 +22,7 @@ public final class ListCommand implements CommandHandler {
             needUID = args.get(0).equals("uid");
         }
 
-        CommandHandler.sendMessage(sender, translate(sender, "commands.list.success", Integer.toString(playersMap.size())));
+        CommandHandler.sendMessage(sender, translate(sender, "commands.list.success", playersMap.size()));
 
         if (playersMap.size() != 0) {
             StringBuilder playerSet = new StringBuilder();
diff --git a/src/main/java/emu/grasscutter/command/commands/PositionCommand.java b/src/main/java/emu/grasscutter/command/commands/PositionCommand.java
index 84298857..92a6ee0a 100644
--- a/src/main/java/emu/grasscutter/command/commands/PositionCommand.java
+++ b/src/main/java/emu/grasscutter/command/commands/PositionCommand.java
@@ -14,7 +14,6 @@ public final class PositionCommand implements CommandHandler {
     public void execute(Player sender, Player targetPlayer, List<String> args) {
         Position pos = targetPlayer.getPosition();
         CommandHandler.sendTranslatedMessage(sender, "commands.position.success",
-                Float.toString(pos.getX()), Float.toString(pos.getY()), Float.toString(pos.getZ()),
-                Integer.toString(targetPlayer.getSceneId()));
+                pos.getX(), pos.getY(), pos.getZ(), targetPlayer.getSceneId());
     }
 }
diff --git a/src/main/java/emu/grasscutter/command/commands/SendMailCommand.java b/src/main/java/emu/grasscutter/command/commands/SendMailCommand.java
index e909a53f..458ac598 100644
--- a/src/main/java/emu/grasscutter/command/commands/SendMailCommand.java
+++ b/src/main/java/emu/grasscutter/command/commands/SendMailCommand.java
@@ -76,7 +76,7 @@ public final class SendMailCommand implements CommandHandler {
                         if (mailBuilder.constructionStage == 3) {
                             if (!mailBuilder.sendToAll) {
                                 Grasscutter.getGameServer().getPlayerByUid(mailBuilder.recipient, true).sendMail(mailBuilder.mail);
-                                CommandHandler.sendMessage(sender, translate(sender, "commands.sendMail.send_done", Integer.toString(mailBuilder.recipient)));
+                                CommandHandler.sendMessage(sender, translate(sender, "commands.sendMail.send_done", mailBuilder.recipient));
                             } else {
                                 for (Player player : DatabaseHelper.getAllPlayers()) {
                                     Grasscutter.getGameServer().getPlayerByUid(player.getUid(), true).sendMail(mailBuilder.mail);
@@ -154,7 +154,7 @@ public final class SendMailCommand implements CommandHandler {
                                         return;
                                 }
                                 mailBuilder.mail.itemList.add(new Mail.MailItem(item, amount, lvl));
-                                CommandHandler.sendMessage(sender, translate(sender, "commands.sendMail.send", Integer.toString(amount), Integer.toString(item), Integer.toString(lvl)));
+                                CommandHandler.sendMessage(sender, translate(sender, "commands.sendMail.send", amount, item, lvl));
                             }
                         }
                     }
@@ -171,7 +171,7 @@ public final class SendMailCommand implements CommandHandler {
             case 1 -> translate(sender, "commands.sendMail.message");
             case 2 -> translate(sender, "commands.sendMail.sender");
             case 3 -> translate(sender, "commands.sendMail.arguments");
-            default -> translate(sender, "commands.sendMail.error", Integer.toString(stage));
+            default -> translate(sender, "commands.sendMail.error", stage);
         };
     }
 
diff --git a/src/main/java/emu/grasscutter/command/commands/SetPropCommand.java b/src/main/java/emu/grasscutter/command/commands/SetPropCommand.java
index cefb25c5..1d9a0138 100644
--- a/src/main/java/emu/grasscutter/command/commands/SetPropCommand.java
+++ b/src/main/java/emu/grasscutter/command/commands/SetPropCommand.java
@@ -160,8 +160,8 @@ public final class SetPropCommand implements CommandHandler {
             }
         } else {
             if (prop.prop != PlayerProperty.PROP_NONE) {  // PseudoProps need to do their own error messages
-                String min = Integer.toString(targetPlayer.getPropertyMin(prop.prop));
-                String max = Integer.toString(targetPlayer.getPropertyMax(prop.prop));
+                int min = targetPlayer.getPropertyMin(prop.prop);
+                int max = targetPlayer.getPropertyMax(prop.prop);
                 CommandHandler.sendTranslatedMessage(sender, "commands.generic.invalid.value_between", prop.name, min, max);
             }
         }
@@ -170,9 +170,7 @@ public final class SetPropCommand implements CommandHandler {
     private boolean setTowerLevel(Player sender, Player targetPlayer, int topFloor) {
         List<Integer> floorIds = targetPlayer.getServer().getTowerSystem().getAllFloors();
         if (topFloor < 0 || topFloor > floorIds.size()) {
-            String min = Integer.toString(0);
-            String max = Integer.toString(floorIds.size());
-            CommandHandler.sendTranslatedMessage(sender, "commands.generic.invalid.value_between", "Tower Level", min, max);
+            CommandHandler.sendTranslatedMessage(sender, "commands.generic.invalid.value_between", "Tower Level", 0, floorIds.size());
             return false;
         }
 
diff --git a/src/main/java/emu/grasscutter/command/commands/SpawnCommand.java b/src/main/java/emu/grasscutter/command/commands/SpawnCommand.java
index 17758157..f7bec979 100644
--- a/src/main/java/emu/grasscutter/command/commands/SpawnCommand.java
+++ b/src/main/java/emu/grasscutter/command/commands/SpawnCommand.java
@@ -116,7 +116,7 @@ public final class SpawnCommand implements CommandHandler {
 
             scene.addEntity(entity);
         }
-        CommandHandler.sendMessage(sender, translate(sender, "commands.spawn.success", Integer.toString(amount), Integer.toString(id)));
+        CommandHandler.sendMessage(sender, translate(sender, "commands.spawn.success", amount, id));
     }
 
     private Position GetRandomPositionInCircle(Position origin, double radius) {
diff --git a/src/main/java/emu/grasscutter/command/commands/TalentCommand.java b/src/main/java/emu/grasscutter/command/commands/TalentCommand.java
index 63bc84b7..908ba597 100644
--- a/src/main/java/emu/grasscutter/command/commands/TalentCommand.java
+++ b/src/main/java/emu/grasscutter/command/commands/TalentCommand.java
@@ -91,9 +91,9 @@ public final class TalentCommand implements CommandHandler {
                 }
             }
             case "getid" -> {
-                CommandHandler.sendTranslatedMessage(sender, "commands.talent.normal_attack_id", Integer.toString(skillIdNorAtk));
-                CommandHandler.sendTranslatedMessage(sender, "commands.talent.e_skill_id", Integer.toString(skillIdE));
-                CommandHandler.sendTranslatedMessage(sender, "commands.talent.q_skill_id", Integer.toString(skillIdQ));
+                CommandHandler.sendTranslatedMessage(sender, "commands.talent.normal_attack_id", skillIdNorAtk);
+                CommandHandler.sendTranslatedMessage(sender, "commands.talent.e_skill_id", skillIdE);
+                CommandHandler.sendTranslatedMessage(sender, "commands.talent.q_skill_id", skillIdQ);
             }
         }
     }
diff --git a/src/main/java/emu/grasscutter/command/commands/TeleportCommand.java b/src/main/java/emu/grasscutter/command/commands/TeleportCommand.java
index 6e5f99cc..3bb59c36 100644
--- a/src/main/java/emu/grasscutter/command/commands/TeleportCommand.java
+++ b/src/main/java/emu/grasscutter/command/commands/TeleportCommand.java
@@ -60,8 +60,7 @@ public final class TeleportCommand implements CommandHandler {
             CommandHandler.sendMessage(sender, translate(sender, "commands.teleport.exists_error"));
         } else {
             CommandHandler.sendMessage(sender, translate(sender, "commands.teleport.success",
-                    targetPlayer.getNickname(), Float.toString(x), Float.toString(y),
-                    Float.toString(z), Integer.toString(sceneId))
+                    targetPlayer.getNickname(), x, y, z, sceneId)
             );
         }
 
diff --git a/src/main/java/emu/grasscutter/command/commands/WeatherCommand.java b/src/main/java/emu/grasscutter/command/commands/WeatherCommand.java
index dd85d32c..4ec279c7 100644
--- a/src/main/java/emu/grasscutter/command/commands/WeatherCommand.java
+++ b/src/main/java/emu/grasscutter/command/commands/WeatherCommand.java
@@ -17,7 +17,7 @@ public final class WeatherCommand implements CommandHandler {
 
         if (args.isEmpty()) {
             climate = targetPlayer.getClimate();
-            CommandHandler.sendTranslatedMessage(sender, "commands.weather.status", Integer.toString(weatherId), climate.getShortName());
+            CommandHandler.sendTranslatedMessage(sender, "commands.weather.status", weatherId, climate.getShortName());
             return;
         }
 
@@ -38,6 +38,6 @@ public final class WeatherCommand implements CommandHandler {
 
         targetPlayer.setWeather(weatherId, climate);
         climate = targetPlayer.getClimate();  // Might be different to what we set
-        CommandHandler.sendTranslatedMessage(sender, "commands.weather.success", Integer.toString(weatherId), climate.getShortName());
+        CommandHandler.sendTranslatedMessage(sender, "commands.weather.success", weatherId, climate.getShortName());
     }
 }
diff --git a/src/main/java/emu/grasscutter/utils/Language.java b/src/main/java/emu/grasscutter/utils/Language.java
index 5e0d22d3..3f34b955 100644
--- a/src/main/java/emu/grasscutter/utils/Language.java
+++ b/src/main/java/emu/grasscutter/utils/Language.java
@@ -84,6 +84,14 @@ public final class Language {
     public static String translate(String key, Object... args) {
         String translated = Grasscutter.getLanguage().get(key);
 
+        for (int i = 0; i < args.length; i++) {
+            args[i] = switch(args[i].getClass().getSimpleName()) {
+                case "String" -> args[i];
+                case "TextStrings" -> ((TextStrings) args[i]).get(0).replace("\\\\n", "\\n");  // TODO: Change this to server language
+                default -> args[i].toString();
+            };
+        }
+
         try {
             return translated.formatted(args);
         } catch (Exception exception) {
@@ -107,6 +115,14 @@ public final class Language {
         var langCode = Utils.getLanguageCode(player.getAccount().getLocale());
         String translated = getLanguage(langCode).get(key);
 
+        for (int i = 0; i < args.length; i++) {
+            args[i] = switch(args[i].getClass().getSimpleName()) {
+                case "String" -> args[i];
+                case "TextStrings" -> ((TextStrings) args[i]).getGC(langCode).replace("\\\\n", "\n");  // Note that we don't unescape \n for server console
+                default -> args[i].toString();
+            };
+        }
+
         try {
             return translated.formatted(args);
         } catch (Exception exception) {
@@ -248,6 +264,11 @@ public final class Language {
                 IntStream.range(0, ARR_LANGUAGES.length)
                 .boxed()
                 .collect(Collectors.toMap(i -> ARR_LANGUAGES[i], i -> i)));
+        public static final Object2IntMap<String> MAP_GC_LANGUAGES =  // Map "en-US": 0, "zh-CN": 1, ...
+            new Object2IntOpenHashMap<>(
+                IntStream.range(0, ARR_GC_LANGUAGES.length)
+                .boxed()
+                .collect(Collectors.toMap(i -> ARR_GC_LANGUAGES[i], i -> i, (i1, i2) -> i1)));  // Have to handle duplicates referring back to the first
         public String[] strings = new String[ARR_LANGUAGES.length];
 
         public TextStrings() {};
@@ -288,6 +309,10 @@ public final class Language {
             return strings[MAP_LANGUAGES.getOrDefault(languageCode, 0)];
         }
 
+        public String getGC(String languageCode) {
+            return strings[MAP_GC_LANGUAGES.getOrDefault(languageCode, 0)];
+        }
+
         public boolean set(String languageCode, String string) {
             int index = MAP_LANGUAGES.getOrDefault(languageCode, -1);
             if (index < 0) return false;
@@ -410,6 +435,9 @@ public final class Language {
         ResourceLoader.loadAll();
         IntSet usedHashes = new IntOpenHashSet();
         GameData.getAvatarDataMap().forEach((k, v) -> usedHashes.add((int) v.getNameTextMapHash()));
+        GameData.getAvatarSkillDataMap().forEach((k, v) -> {
+            usedHashes.add((int) v.getNameTextMapHash());
+        });
         GameData.getItemDataMap().forEach((k, v) -> usedHashes.add((int) v.getNameTextMapHash()));
         GameData.getMonsterDataMap().forEach((k, v) -> usedHashes.add((int) v.getNameTextMapHash()));
         GameData.getMainQuestDataMap().forEach((k, v) -> usedHashes.add((int) v.getTitleTextMapHash()));
diff --git a/src/main/resources/languages/en-US.json b/src/main/resources/languages/en-US.json
index 110e7068..87296bfd 100644
--- a/src/main/resources/languages/en-US.json
+++ b/src/main/resources/languages/en-US.json
@@ -305,7 +305,7 @@
     "team": {
       "invalid_usage": "Invalid usage.",
       "invalid_index": "Index is invalid.",
-      "add_too_much": "The server only allows you to have at most %d avatar(s) in your team.",
+      "add_too_much": "The server only allows you to have at most %s avatar(s) in your team.",
       "failed_to_add_avatar": "Failed to add avatar ID %s.",
       "failed_to_parse_index": "Failed to parse index: %s",
       "remove_too_much": "You can't remove all your avatars.",
@@ -313,7 +313,7 @@
       "index_out_of_range": "The index you specified is out of range.",
       "failed_parse_avatar_id": "Failed to parse avatar ID: %s",
       "avatar_already_in_team": "Avatar is already in team.",
-      "avatar_not_found": "Avatar %d not found.",
+      "avatar_not_found": "Avatar %s not found.",
       "description": "Modify your team manually."
     },
     "teleportAll": {
-- 
GitLab