From 1c4d263dd25478df6a7a633532c351cf6a4fbcca Mon Sep 17 00:00:00 2001
From: AnimeGitB <AnimeGitB@bigblueball.in>
Date: Thu, 24 Nov 2022 23:09:55 +1030
Subject: [PATCH] Add Data TSJ loading, replace and update Banners

---
 .../java/emu/grasscutter/data/DataLoader.java | 13 +++
 .../emu/grasscutter/data/ResourceLoader.java  |  4 +-
 .../grasscutter/game/gacha/GachaBanner.java   |  2 +-
 .../grasscutter/game/gacha/GachaSystem.java   |  2 +-
 .../java/emu/grasscutter/utils/FileUtils.java | 25 ++++--
 .../java/emu/grasscutter/utils/TsvUtils.java  |  4 +-
 src/main/resources/defaults/data/Banners.json | 83 -------------------
 src/main/resources/defaults/data/Banners.tsj  |  6 ++
 8 files changed, 43 insertions(+), 96 deletions(-)
 delete mode 100644 src/main/resources/defaults/data/Banners.json
 create mode 100644 src/main/resources/defaults/data/Banners.tsj

diff --git a/src/main/java/emu/grasscutter/data/DataLoader.java b/src/main/java/emu/grasscutter/data/DataLoader.java
index 9b19336b..f40337dc 100644
--- a/src/main/java/emu/grasscutter/data/DataLoader.java
+++ b/src/main/java/emu/grasscutter/data/DataLoader.java
@@ -5,6 +5,8 @@ import emu.grasscutter.server.http.handlers.GachaHandler;
 import emu.grasscutter.tools.Tools;
 import emu.grasscutter.utils.FileUtils;
 import emu.grasscutter.utils.JsonUtils;
+import emu.grasscutter.utils.TsvUtils;
+import lombok.val;
 
 import java.io.FileNotFoundException;
 import java.io.IOException;
@@ -88,6 +90,17 @@ public class DataLoader {
         }
     }
 
+    public static <T> List<T> loadTableToList(String resourcePath, Class<T> classType) throws IOException {
+        val path = FileUtils.getDataPathTsjJsonTsv(resourcePath);
+        Grasscutter.getLogger().info("Loading data table from: "+path);
+        return switch (FileUtils.getFileExtension(path)) {
+            case "json" -> JsonUtils.loadToList(path, classType);
+            case "tsj" -> TsvUtils.loadTsjToListSetField(path, classType);
+            case "tsv" -> TsvUtils.loadTsvToListSetField(path, classType);
+            default -> null;
+        };
+    }
+
     public static void checkAllFiles() {
         try {
             List<Path> filenames = FileUtils.getPathsFromResource("/defaults/data/");
diff --git a/src/main/java/emu/grasscutter/data/ResourceLoader.java b/src/main/java/emu/grasscutter/data/ResourceLoader.java
index b2f52d03..6c392cfd 100644
--- a/src/main/java/emu/grasscutter/data/ResourceLoader.java
+++ b/src/main/java/emu/grasscutter/data/ResourceLoader.java
@@ -152,8 +152,8 @@ public class ResourceLoader {
     protected static <T> void loadFromResource(Class<T> c, Path filename, Int2ObjectMap map) throws Exception {
         val results = switch (FileUtils.getFileExtension(filename)) {
             case "json" -> JsonUtils.loadToList(filename, c);
-            case "tsj" -> TsvUtils.loadTsjToListSetField(c, filename);
-            case "tsv" -> TsvUtils.loadTsvToListSetField(c, filename);
+            case "tsj" -> TsvUtils.loadTsjToListSetField(filename, c);
+            case "tsv" -> TsvUtils.loadTsvToListSetField(filename, c);
             default -> null;
         };
         if (results == null) return;
diff --git a/src/main/java/emu/grasscutter/game/gacha/GachaBanner.java b/src/main/java/emu/grasscutter/game/gacha/GachaBanner.java
index 7afb82cf..a9c6502d 100644
--- a/src/main/java/emu/grasscutter/game/gacha/GachaBanner.java
+++ b/src/main/java/emu/grasscutter/game/gacha/GachaBanner.java
@@ -27,7 +27,7 @@ public class GachaBanner {
     private int[] rateUpItems4 = {};
     private int[] rateUpItems5 = {};
     @Getter private int[] fallbackItems3 = {11301, 11302, 11306, 12301, 12302, 12305, 13303, 14301, 14302, 14304, 15301, 15302, 15304};
-    @Getter private int[] fallbackItems4Pool1 = {1014, 1020, 1023, 1024, 1025, 1027, 1031, 1032, 1034, 1036, 1039, 1043, 1044, 1045, 1048, 1053, 1055, 1056, 1064};
+    @Getter private int[] fallbackItems4Pool1 = {1014, 1020, 1023, 1024, 1025, 1027, 1031, 1032, 1034, 1036, 1039, 1043, 1044, 1045, 1048, 1053, 1055, 1056, 1059, 1064, 1065, 1067, 1068, 1072};
     @Getter private int[] fallbackItems4Pool2 = {11401, 11402, 11403, 11405, 12401, 12402, 12403, 12405, 13401, 13407, 14401, 14402, 14403, 14409, 15401, 15402, 15403, 15405};
     @Getter private int[] fallbackItems5Pool1 = {1003, 1016, 1042, 1035, 1041};
     @Getter private int[] fallbackItems5Pool2 = {11501, 11502, 12501, 12502, 13502, 13505, 14501, 14502, 15501, 15502};
diff --git a/src/main/java/emu/grasscutter/game/gacha/GachaSystem.java b/src/main/java/emu/grasscutter/game/gacha/GachaSystem.java
index a71caf87..f775570a 100644
--- a/src/main/java/emu/grasscutter/game/gacha/GachaSystem.java
+++ b/src/main/java/emu/grasscutter/game/gacha/GachaSystem.java
@@ -70,7 +70,7 @@ public class GachaSystem extends BaseGameSystem {
     public synchronized void load() {
         getGachaBanners().clear();
         try {
-            List<GachaBanner> banners = DataLoader.loadList("Banners.json", GachaBanner.class);
+            List<GachaBanner> banners = DataLoader.loadTableToList("Banners", GachaBanner.class);
             if (banners.size() > 0) {
                 for (GachaBanner banner : banners) {
                     banner.onLoad();
diff --git a/src/main/java/emu/grasscutter/utils/FileUtils.java b/src/main/java/emu/grasscutter/utils/FileUtils.java
index 574bfd6c..40b12af2 100644
--- a/src/main/java/emu/grasscutter/utils/FileUtils.java
+++ b/src/main/java/emu/grasscutter/utils/FileUtils.java
@@ -88,6 +88,19 @@ public final class FileUtils {
             : Path.of(scripts);
     };
 
+    private static final String[] TSJ_JSON_TSV = {"tsj", "json", "tsv"};
+    private static final Path[] DATA_PATHS = {DATA_USER_PATH, DATA_DEFAULT_PATH};
+    public static Path getDataPathTsjJsonTsv(String filename) {
+        val name = getFilenameWithoutExtension(filename);
+        for (val data_path : DATA_PATHS) {
+            for (val ext : TSJ_JSON_TSV) {
+                val path = data_path.resolve(name + "." + ext);
+                if (Files.exists(path)) return path;
+            }
+        }
+        return DATA_USER_PATH.resolve(name + ".tsj");  // Maybe they want to write to a new file
+    }
+
     public static Path getDataPath(String path) {
         Path userPath = DATA_USER_PATH.resolve(path);
         if (Files.exists(userPath)) return userPath;
@@ -121,13 +134,11 @@ public final class FileUtils {
     // If none exist, return the TSJ path, in case it wants to create a file
     public static Path getTsjJsonTsv(Path root, String filename) {
         val name = getFilenameWithoutExtension(filename);
-        val tsj = root.resolve(name + ".tsj");
-        if (Files.exists(tsj)) return tsj;
-        val json = root.resolve(name + ".json");
-        if (Files.exists(json)) return json;
-        val tsv = root.resolve(name + ".tsv");
-        if (Files.exists(tsv)) return tsv;
-        return tsj;
+        for (val ext : TSJ_JSON_TSV) {
+            val path = root.resolve(name + "." + ext);
+            if (Files.exists(path)) return path;
+        }
+        return root.resolve(name + ".tsj");
     }
 
     public static Path getScriptPath(String path) {
diff --git a/src/main/java/emu/grasscutter/utils/TsvUtils.java b/src/main/java/emu/grasscutter/utils/TsvUtils.java
index 32e31615..2e8f422b 100644
--- a/src/main/java/emu/grasscutter/utils/TsvUtils.java
+++ b/src/main/java/emu/grasscutter/utils/TsvUtils.java
@@ -402,7 +402,7 @@ public class TsvUtils {
     // Arrays are represented as arrayName.0, arrayName.1, etc. columns.
     // Maps/POJOs are represented as objName.fieldOneName, objName.fieldTwoName, etc. columns.
     // This is currently about 25x as slow as TSJ and Gson parsers, likely due to the tree spam.
-    public static <T> List<T> loadTsvToListSetField(Class<T> classType, Path filename) {
+    public static <T> List<T> loadTsvToListSetField(Path filename, Class<T> classType) {
         try (val fileReader = Files.newBufferedReader(filename, StandardCharsets.UTF_8)) {
             // val fieldMap = getClassFieldMap(classType);
             // val constructor = classType.getDeclaredConstructor();
@@ -453,7 +453,7 @@ public class TsvUtils {
 
     // This uses a hybrid format where columns can hold JSON-encoded values.
     // I'll term it TSJ (tab-separated JSON) for now, it has convenient properties.
-    public static <T> List<T> loadTsjToListSetField(Class<T> classType, Path filename) {
+    public static <T> List<T> loadTsjToListSetField(Path filename, Class<T> classType) {
         try (val fileReader = Files.newBufferedReader(filename, StandardCharsets.UTF_8)) {
             val fieldMap = getClassFieldMap(classType);
             val constructor = classType.getDeclaredConstructor();
diff --git a/src/main/resources/defaults/data/Banners.json b/src/main/resources/defaults/data/Banners.json
deleted file mode 100644
index 32c26e82..00000000
--- a/src/main/resources/defaults/data/Banners.json
+++ /dev/null
@@ -1,83 +0,0 @@
-[
-	{
-		"comment": "Beginner's Banner. Do not change for no reason.",
-		"gachaType": 100,
-		"scheduleId": 803,
-		"bannerType": "EVENT",
-		"prefabPath": "GachaShowPanel_A016",
-		"titlePath": "UI_GACHA_SHOW_PANEL_A016_TITLE",
-		"costItemId": 224,
-		"costItemAmount10": 8,
-		"gachaTimesLimit": 20,
-		"beginTime": 0,
-		"endTime": 1924992000,
-		"sortId": 9999,
-		"rateUpItems5": [],
-		"rateUpItems4": [1034]
-	},
-	{
-		"comment": "Standard",
-		"gachaType": 200,
-		"scheduleId": 893,
-		"bannerType": "STANDARD",
-		"prefabPath": "GachaShowPanel_A022",
-		"titlePath": "UI_GACHA_SHOW_PANEL_A022_TITLE",
-		"costItemId": 224,
-		"beginTime": 0,
-		"endTime": 1924992000,
-		"sortId": 1000,
-		"fallbackItems4Pool1": [1006, 1014, 1015, 1020, 1021, 1023, 1024, 1025, 1027, 1031, 1032, 1034, 1036, 1039, 1043, 1044, 1045, 1048, 1053, 1055, 1056, 1064],
-		"weights5": [[1,75], [73,150], [90,10000]]
-	},
-	{
-		"comment": "Character Event Banner 1",
-		"gachaType": 301,
-		"scheduleId": 903,
-		"bannerType": "EVENT",
-		"prefabPath": "GachaShowPanel_A103",
-		"titlePath": "UI_GACHA_SHOW_PANEL_A081_TITLE",
-		"costItemId": 223,
-		"beginTime": 0,
-		"endTime": 1924992000,
-		"sortId": 9998,
-		"rateUpItems4": [1032, 1020, 1034],
-		"rateUpItems5": [1073],
-		"fallbackItems5Pool2": [],
-		"weights5": [[1,80], [73,80], [90,10000]]
-	},
-	{
-		"comment": "Character Event Banner 2",
-		"gachaType": 400,
-		"scheduleId": 923,
-		"bannerType": "EVENT",
-		"prefabPath": "GachaShowPanel_A104",
-		"titlePath": "UI_GACHA_SHOW_PANEL_A049_TITLE",
-		"costItemId": 223,
-		"beginTime": 0,
-		"endTime": 1924992000,
-		"sortId": 9998,
-		"rateUpItems4": [1032, 1020, 1034],
-		"rateUpItems5": [1049],
-		"fallbackItems5Pool2": [],
-		"weights5": [[1,80], [73,80], [90,10000]]
-	},
-	{
-		"comment": "Weapon Event Banner",
-		"gachaType": 302,
-		"scheduleId": 913,
-		"bannerType": "WEAPON",
-		"prefabPath": "GachaShowPanel_A105",
-		"titlePath": "UI_GACHA_SHOW_PANEL_A021_TITLE",
-		"costItemId": 223,
-		"beginTime": 0,
-		"endTime": 1924992000,
-		"sortId": 9997,
-		"rateUpItems4":[15405, 11402, 13407, 14402, 12403],
-		"rateUpItems5": [14511, 15509],
-		"fallbackItems5Pool1": [],
-		"weights4": [[1,600], [7,600], [8,6600], [10,12600]],
-		"weights5": [[1,100], [62,100], [73,7800], [80,10000]],
-		"eventChance4": 75,
-		"eventChance5": 75
-	}
-]
diff --git a/src/main/resources/defaults/data/Banners.tsj b/src/main/resources/defaults/data/Banners.tsj
new file mode 100644
index 00000000..a619c247
--- /dev/null
+++ b/src/main/resources/defaults/data/Banners.tsj
@@ -0,0 +1,6 @@
+comment	gachaType	scheduleId	bannerType	prefabPath	titlePath	costItemId	beginTime	endTime	sortId	rateUpItems5	rateUpItems4	weights5	weights4	fallbackItems5Pool2	fallbackItems5Pool1	fallbackItems4Pool1	eventChance4	eventChance5	costItemAmount10	gachaTimesLimit
+Beginner's Banner. Do not change for no reason.	100	803	EVENT	GachaShowPanel_A016	UI_GACHA_SHOW_PANEL_A016_TITLE	224		1924992000	9999		[1034]								8	20
+Standard	200	893	STANDARD	GachaShowPanel_A022	UI_GACHA_SHOW_PANEL_A022_TITLE	224		1924992000	1000			[[1, 75], [73, 150], [90, 10000]]				[1006, 1014, 1015, 1020, 1021, 1023, 1024, 1025, 1027, 1031, 1032, 1034, 1036, 1039, 1043, 1044, 1045, 1048, 1053, 1055, 1056, 1059, 1064, 1065, 1067, 1068, 1072]
+Character Event Banner 1	301	903	EVENT	GachaShowPanel_A106	UI_GACHA_SHOW_PANEL_A071_TITLE	223		1924992000	9998	[1058]	[1050, 1059, 1074]	[[1, 80], [73, 80], [90, 10000]]		[]
+Character Event Banner 2	400	923	EVENT	GachaShowPanel_A107	UI_GACHA_SHOW_PANEL_A037_TITLE	223		1924992000	9998	[1033]	[1050, 1059, 1074]	[[1, 80], [73, 80], [90, 10000]]		[]
+Weapon Event Banner	302	913	WEAPON	GachaShowPanel_A108	UI_GACHA_SHOW_PANEL_A021_TITLE	223		1924992000	9997	[14509, 15507]	[11401, 12402, 13401, 14401, 15402]	[[1, 100], [62, 100], [73, 7800], [80, 10000]]	[[1, 600], [7, 600], [8, 6600], [10, 12600]]		[]		75	75
-- 
GitLab