Tools.java 9.09 KB
Newer Older
Melledy's avatar
Melledy committed
1
2
package emu.grasscutter.tools;

3
import java.io.File;
4
import java.io.FileInputStream;
5
import java.io.FileOutputStream;
6
import java.io.InputStreamReader;
7
import java.io.OutputStreamWriter;
Melledy's avatar
Melledy committed
8
import java.io.PrintWriter;
9
import java.nio.charset.StandardCharsets;
Melledy's avatar
Melledy committed
10
11
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
12
import java.util.*;
Melledy's avatar
Melledy committed
13
14
15

import com.google.gson.reflect.TypeToken;

16
import emu.grasscutter.GameConstants;
Melledy's avatar
Melledy committed
17
import emu.grasscutter.Grasscutter;
18
19
import emu.grasscutter.command.Command;
import emu.grasscutter.command.CommandMap;
20
import emu.grasscutter.data.GameData;
Melledy's avatar
Melledy committed
21
import emu.grasscutter.data.ResourceLoader;
Melledy's avatar
Melledy committed
22
23
24
25
26
27
import emu.grasscutter.data.binout.MainQuestData;
import emu.grasscutter.data.excels.AvatarData;
import emu.grasscutter.data.excels.ItemData;
import emu.grasscutter.data.excels.MonsterData;
import emu.grasscutter.data.excels.QuestData;
import emu.grasscutter.data.excels.SceneData;
28
import emu.grasscutter.utils.Utils;
Melledy's avatar
Melledy committed
29

方块君's avatar
方块君 committed
30
import static emu.grasscutter.utils.Language.translate;
31
import static emu.grasscutter.Configuration.*;
方块君's avatar
方块君 committed
32

KingRainbow44's avatar
KingRainbow44 committed
33
public final class Tools {
34
35
36
37
38
39
40
41
	public static void createGmHandbook() throws Exception {
		ToolsWithLanguageOption.createGmHandbook(getLanguageOption());
	}

	public static void createGachaMapping(String location) throws Exception {
		ToolsWithLanguageOption.createGachaMapping(location, getLanguageOption());
	}

42
43
44
45
46
47
	public static List<String> getAvailableLanguage() {
		File textMapFolder = new File(RESOURCE("TextMap"));
		List<String> availableLangList = new ArrayList<>();
		for (String textMapFileName : Objects.requireNonNull(textMapFolder.list((dir, name) -> name.startsWith("TextMap") && name.endsWith(".json")))) {
			availableLangList.add(textMapFileName.replace("TextMap", "").replace(".json", "").toLowerCase());
		} return availableLangList;
48
49
	}

50
	public static String getLanguageOption() {
51
		List<String> availableLangList = getAvailableLanguage();
Melledy's avatar
Melledy committed
52
	
53
54
55
56
		// Use system out for better format
		if (availableLangList.size() == 1) {
			return availableLangList.get(0).toUpperCase();
		}
57
58
59
60
		StringBuilder stagedMessage = new StringBuilder();
		stagedMessage.append("The following languages mappings are available, please select one: [default: EN] \n");
		
		StringBuilder groupedLangList = new StringBuilder(">\t"); String input;
61
		int groupedLangCount = 0;
62
		
63
64
		for (String availableLanguage: availableLangList){
			groupedLangCount++;
65
66
			groupedLangList.append(availableLanguage).append("\t");
			
67
			if (groupedLangCount == 6) {
68
				stagedMessage.append(groupedLangList).append("\n");
69
				groupedLangCount = 0;
70
				groupedLangList = new StringBuilder(">\t");
71
72
			}
		}
73
		
74
		if (groupedLangCount > 0) {
75
			stagedMessage.append(groupedLangList).append("\n");
76
		}
mingjun97's avatar
mingjun97 committed
77
		
78
79
80
		stagedMessage.append("\nYour choice:[EN] ");
		
		input = Grasscutter.getConsole().readLine(stagedMessage.toString());
81
82
83
84
85
86
87
88
89
90
		if (availableLangList.contains(input.toLowerCase())) {
			return input.toUpperCase();
		}
		Grasscutter.getLogger().info("Invalid option. Will use EN(English) as fallback");

		return "EN";
	}
}

final class ToolsWithLanguageOption {
Melledy's avatar
Melledy committed
91
	@SuppressWarnings("deprecation")
92
	public static void createGmHandbook(String language) throws Exception {
Melledy's avatar
Melledy committed
93
		ResourceLoader.loadAll();
Melledy's avatar
Melledy committed
94
95
		
		Map<Long, String> map;
96
		try (InputStreamReader fileReader = new InputStreamReader(new FileInputStream(Utils.toFilePath(RESOURCE("TextMap/TextMap"+language+".json"))), StandardCharsets.UTF_8)) {
Melledy's avatar
Melledy committed
97
98
99
100
101
			map = Grasscutter.getGsonFactory().fromJson(fileReader, new TypeToken<Map<Long, String>>() {}.getType());
		}
		
		List<Integer> list;
		String fileName = "./GM Handbook.txt";
102
		try (PrintWriter writer = new PrintWriter(new OutputStreamWriter(new FileOutputStream(fileName), StandardCharsets.UTF_8), false)) {
Melledy's avatar
Melledy committed
103
104
105
			DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss");  
			LocalDateTime now = LocalDateTime.now();
			   
106
			writer.println("// Grasscutter " + GameConstants.VERSION + " GM Handbook");
Melledy's avatar
Melledy committed
107
			writer.println("// Created " + dtf.format(now) + System.lineSeparator() + System.lineSeparator());
108
109

			CommandMap cmdMap = new CommandMap(true);
方块君's avatar
方块君 committed
110
			List<Command> cmdList = new ArrayList<>(cmdMap.getAnnotationsAsList());
111
112

			writer.println("// Commands");
方块君's avatar
方块君 committed
113
			for (Command cmd : cmdList) {
114
				StringBuilder cmdName = new StringBuilder(cmd.label());
115
				while (cmdName.length() <= 15) {
116
					cmdName.insert(0, " ");
117
				}
方块君's avatar
方块君 committed
118
119
				writer.println(cmdName + " : " + translate(cmd.description()));
			}
120
121
			writer.println();

122
			list = new ArrayList<>(GameData.getAvatarDataMap().keySet());
Melledy's avatar
Melledy committed
123
124
125
126
			Collections.sort(list); 
			 
			writer.println("// Avatars");
			for (Integer id : list) {
127
				AvatarData data = GameData.getAvatarDataMap().get(id);
Melledy's avatar
Melledy committed
128
129
130
131
132
				writer.println(data.getId() + " : " + map.get(data.getNameTextMapHash()));
			}
			
			writer.println();
			
133
			list = new ArrayList<>(GameData.getItemDataMap().keySet());
Melledy's avatar
Melledy committed
134
135
136
137
			Collections.sort(list); 
			
			writer.println("// Items");
			for (Integer id : list) {
138
				ItemData data = GameData.getItemDataMap().get(id);
Melledy's avatar
Melledy committed
139
140
141
142
143
				writer.println(data.getId() + " : " + map.get(data.getNameTextMapHash()));
			}
			
			writer.println();
			
144
			writer.println("// Scenes");
145
			list = new ArrayList<>(GameData.getSceneDataMap().keySet());
146
147
148
			Collections.sort(list); 
			
			for (Integer id : list) {
149
				SceneData data = GameData.getSceneDataMap().get(id);
150
151
152
				writer.println(data.getId() + " : " + data.getScriptData());
			}
			
Melledy's avatar
Melledy committed
153
154
			writer.println();
			
Melledy's avatar
Melledy committed
155
			writer.println("// Quests");
Melledy's avatar
Melledy committed
156
			list = new ArrayList<>(GameData.getQuestDataMap().keySet());
Melledy's avatar
Melledy committed
157
158
159
			Collections.sort(list); 
			
			for (Integer id : list) {
Melledy's avatar
Melledy committed
160
161
				QuestData data = GameData.getQuestDataMap().get(id);
				MainQuestData mainQuest = GameData.getMainQuestDataMap().get(data.getMainId());
Melledy's avatar
Melledy committed
162
163
164
				if (mainQuest != null) {
					writer.println(data.getId() + " : " + map.get(mainQuest.getTitleTextMapHash()) + " - " + map.get(data.getDescTextMapHash()));
				}
Melledy's avatar
Melledy committed
165
166
			}
			
167
168
			writer.println();
			
Melledy's avatar
Melledy committed
169
			writer.println("// Monsters");
170
			list = new ArrayList<>(GameData.getMonsterDataMap().keySet());
Melledy's avatar
Melledy committed
171
172
173
			Collections.sort(list); 
			
			for (Integer id : list) {
174
				MonsterData data = GameData.getMonsterDataMap().get(id);
Melledy's avatar
Melledy committed
175
176
177
178
179
180
				writer.println(data.getId() + " : " + map.get(data.getNameTextMapHash()));
			}
		}
		
		Grasscutter.getLogger().info("GM Handbook generated!");
	}
181
182

	@SuppressWarnings("deprecation")
183
	public static void createGachaMapping(String location, String language) throws Exception {
184
185
186
		ResourceLoader.loadResources();
		
		Map<Long, String> map;
187
		try (InputStreamReader fileReader = new InputStreamReader(new FileInputStream(Utils.toFilePath(RESOURCE("TextMap/TextMap" + language + ".json"))), StandardCharsets.UTF_8)) {
188
189
190
191
192
			map = Grasscutter.getGsonFactory().fromJson(fileReader, new TypeToken<Map<Long, String>>() {}.getType());
		}
		
		List<Integer> list;

193
		try (PrintWriter writer = new PrintWriter(new OutputStreamWriter(new FileOutputStream(location), StandardCharsets.UTF_8), false)) {
194
195
196
			list = new ArrayList<>(GameData.getAvatarDataMap().keySet());
			Collections.sort(list); 
			 
197
198
199
			// if the user made choices for language, I assume it's okay to assign his/her selected language to "en-us"
			// since it's the fallback language and there will be no difference in the gacha record page. 
			// The enduser can still modify the `gacha_mappings.js` directly to enable multilingual for the gacha record system.
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
			writer.println("mappings = {\"en-us\": {"); 

			// Avatars
			boolean first = true;
			for (Integer id : list) {
				AvatarData data = GameData.getAvatarDataMap().get(id);
				int avatarID = data.getId();
				if (avatarID >= 11000000) { // skip test avatar
					continue;
				}
				if (first) { // skip adding comma for the first element
					first = false;
				} else {
					writer.print(",");
				}
215
216
217
218
219
				String color = switch (data.getQualityType()) {
					case "QUALITY_PURPLE" -> "purple";
					case "QUALITY_ORANGE" -> "yellow";
					default -> "blue";
				};
220
				// Got the magic number 4233146695 from manually search in the json file
221
222
				writer.println(
					"\"" + (avatarID % 1000 + 1000) + "\" : [\"" 
223
					+ map.get(data.getNameTextMapHash()) + "(" +  map.get(4233146695L)+ ")\", \"" 
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
					+ color + "\"]");
			}
			
			writer.println();
			
			list = new ArrayList<>(GameData.getItemDataMap().keySet());
			Collections.sort(list); 
			
			// Weapons
			for (Integer id : list) {
				ItemData data = GameData.getItemDataMap().get(id);
				if (data.getId() <= 11101 || data.getId() >= 20000) {
					continue; //skip non weapon items
				}
				String color;

				switch (data.getRankLevel()){
					case 3: 
						color = "blue";
						break;
					case 4:
						color = "purple";
						break;
					case 5:
						color = "yellow";
						break;
					default:
						continue; // skip unnecessary entries
				}
253
254
255
				
				// Got the magic number 4231343903 from manually search in the json file

256
257
				writer.println(",\"" + data.getId() +
						 "\" : [\"" + map.get(data.getNameTextMapHash()).replaceAll("\"", "")
258
						 + "("+ map.get(4231343903L)+")\",\""+ color + "\"]");
259
			}
260
			writer.println(",\"200\": \""+map.get(332935371L)+"\", \"301\": \""+ map.get(2272170627L) + "\", \"302\": \""+map.get(2864268523L)+"\"");
261
262
			writer.println("}\n}");
		}
263
		
mingjun97's avatar
mingjun97 committed
264
		Grasscutter.getLogger().info("Mappings generated to " + location + " !");
265
	}
Melledy's avatar
Melledy committed
266
}