mirror of
https://github.com/Melledy/Grasscutter.git
synced 2024-11-25 20:56:28 +00:00
Generate handbooks on every launch, fix html docs
This commit is contained in:
parent
e963419956
commit
c1ff7332fe
@ -89,13 +89,13 @@ public final class Grasscutter {
|
|||||||
|
|
||||||
public static void main(String[] args) throws Exception {
|
public static void main(String[] args) throws Exception {
|
||||||
Crypto.loadKeys(); // Load keys from buffers.
|
Crypto.loadKeys(); // Load keys from buffers.
|
||||||
|
Tools.createGmHandbooks();
|
||||||
|
|
||||||
// Parse arguments.
|
// Parse arguments.
|
||||||
boolean exitEarly = false;
|
boolean exitEarly = false;
|
||||||
for (String arg : args) {
|
for (String arg : args) {
|
||||||
switch (arg.toLowerCase()) {
|
switch (arg.toLowerCase()) {
|
||||||
case "-handbook", "-handbooks" -> {
|
case "-handbook", "-handbooks" -> {
|
||||||
Tools.createGmHandbooks();
|
|
||||||
exitEarly = true;
|
exitEarly = true;
|
||||||
}
|
}
|
||||||
case "-dumppacketids" -> {
|
case "-dumppacketids" -> {
|
||||||
|
@ -3,6 +3,8 @@ package emu.grasscutter.command;
|
|||||||
import emu.grasscutter.Grasscutter;
|
import emu.grasscutter.Grasscutter;
|
||||||
import emu.grasscutter.game.player.Player;
|
import emu.grasscutter.game.player.Player;
|
||||||
import emu.grasscutter.server.event.game.ReceiveCommandFeedbackEvent;
|
import emu.grasscutter.server.event.game.ReceiveCommandFeedbackEvent;
|
||||||
|
import emu.grasscutter.utils.Language;
|
||||||
|
|
||||||
import static emu.grasscutter.utils.Language.translate;
|
import static emu.grasscutter.utils.Language.translate;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -68,10 +70,13 @@ public interface CommandHandler {
|
|||||||
return this.getClass().getAnnotation(Command.class).label();
|
return this.getClass().getAnnotation(Command.class).label();
|
||||||
}
|
}
|
||||||
|
|
||||||
default String getDescriptionString(Player player) {
|
default String getDescriptionKey() {
|
||||||
Command annotation = this.getClass().getAnnotation(Command.class);
|
Command annotation = this.getClass().getAnnotation(Command.class);
|
||||||
String key = "commands.%s.description".formatted(annotation.label());
|
return "commands.%s.description".formatted(annotation.label());
|
||||||
return translate(player, key);
|
}
|
||||||
|
|
||||||
|
default String getDescriptionString(Player player) {
|
||||||
|
return translate(player, getDescriptionKey());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,154 +1,117 @@
|
|||||||
package emu.grasscutter.server.http.documentation;
|
package emu.grasscutter.server.http.documentation;
|
||||||
|
|
||||||
import com.google.gson.reflect.TypeToken;
|
|
||||||
import emu.grasscutter.Grasscutter;
|
|
||||||
import emu.grasscutter.data.GameData;
|
import emu.grasscutter.data.GameData;
|
||||||
import emu.grasscutter.data.excels.AvatarData;
|
import emu.grasscutter.data.excels.AvatarData;
|
||||||
import emu.grasscutter.data.excels.ItemData;
|
import emu.grasscutter.data.excels.ItemData;
|
||||||
import emu.grasscutter.utils.Utils;
|
import emu.grasscutter.utils.Language;
|
||||||
import express.http.Request;
|
import express.http.Request;
|
||||||
import express.http.Response;
|
import express.http.Response;
|
||||||
|
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
||||||
|
import it.unimi.dsi.fastutil.ints.IntList;
|
||||||
|
|
||||||
import static emu.grasscutter.config.Configuration.DOCUMENT_LANGUAGE;
|
import static emu.grasscutter.config.Configuration.DOCUMENT_LANGUAGE;
|
||||||
import static emu.grasscutter.config.Configuration.RESOURCE;
|
|
||||||
|
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
final class GachaMappingRequestHandler implements DocumentationHandler {
|
final class GachaMappingRequestHandler implements DocumentationHandler {
|
||||||
|
private List<String> gachaJsons;
|
||||||
private Map<Long, String> map;
|
|
||||||
|
|
||||||
GachaMappingRequestHandler() {
|
GachaMappingRequestHandler() {
|
||||||
final String textMapFile = "TextMap/TextMap" + DOCUMENT_LANGUAGE + ".json";
|
this.gachaJsons = createGachaMappingJsons();
|
||||||
try (InputStreamReader fileReader = new InputStreamReader(new FileInputStream(
|
|
||||||
Utils.toFilePath(RESOURCE(textMapFile))), StandardCharsets.UTF_8)) {
|
|
||||||
map = Grasscutter.getGsonFactory().fromJson(fileReader,
|
|
||||||
new TypeToken<Map<Long, String>>() {
|
|
||||||
}.getType());
|
|
||||||
} catch (IOException e) {
|
|
||||||
Grasscutter.getLogger().warn("Resource does not exist: " + textMapFile);
|
|
||||||
map = new HashMap<>();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handle(Request request, Response response) {
|
public void handle(Request request, Response response) {
|
||||||
if (map.isEmpty()) {
|
final int langIdx = Language.TextStrings.MAP_LANGUAGES.getOrDefault(DOCUMENT_LANGUAGE, 0); // TODO: This should really be based off the client language somehow
|
||||||
response.status(500);
|
response.set("Content-Type", "application/json")
|
||||||
} else {
|
.ctx()
|
||||||
response.set("Content-Type", "application/json")
|
.result(gachaJsons.get(langIdx));
|
||||||
.ctx()
|
|
||||||
.result(createGachaMappingJson());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private String createGachaMappingJson() {
|
private List<String> createGachaMappingJsons() {
|
||||||
List<Integer> list;
|
final int NUM_LANGUAGES = Language.TextStrings.NUM_LANGUAGES;
|
||||||
|
final Language.TextStrings CHARACTER = Language.getTextMapKey(4233146695L); // "Character" in EN
|
||||||
final StringBuilder sb = new StringBuilder();
|
final Language.TextStrings WEAPON = Language.getTextMapKey(4231343903L); // "Weapon" in EN
|
||||||
list = new ArrayList<>(GameData.getAvatarDataMap().keySet());
|
final Language.TextStrings STANDARD_WISH = Language.getTextMapKey(332935371L); // "Standard Wish" in EN
|
||||||
Collections.sort(list);
|
final Language.TextStrings CHARACTER_EVENT_WISH = Language.getTextMapKey(2272170627L); // "Character Event Wish" in EN
|
||||||
|
final Language.TextStrings CHARACTER_EVENT_WISH_2 = Language.getTextMapKey(3352513147L); // "Character Event Wish-2" in EN
|
||||||
final String newLine = System.lineSeparator();
|
final Language.TextStrings WEAPON_EVENT_WISH = Language.getTextMapKey(2864268523L); // "Weapon Event Wish" in EN
|
||||||
|
final List<StringBuilder> sbs = new ArrayList<>(NUM_LANGUAGES);
|
||||||
// if the user made choices for language, I assume it's okay to assign his/her selected language to "en-us"
|
for (int langIdx = 0; langIdx < NUM_LANGUAGES; langIdx++)
|
||||||
// since it's the fallback language and there will be no difference in the gacha record page.
|
sbs.add(new StringBuilder("{\n")); // Web requests should never need Windows line endings
|
||||||
// The enduser can still modify the `gacha_mappings.js` directly to enable multilingual for the gacha record system.
|
|
||||||
sb.append("{").append(newLine);
|
|
||||||
|
|
||||||
// Avatars
|
// Avatars
|
||||||
boolean first = true;
|
IntList list = new IntArrayList(GameData.getAvatarDataMap().keySet().intStream().sorted().toArray());
|
||||||
for (Integer id : list) {
|
for (int id : list) {
|
||||||
AvatarData data = GameData.getAvatarDataMap().get(id);
|
AvatarData data = GameData.getAvatarDataMap().get(id);
|
||||||
int avatarID = data.getId();
|
int avatarID = data.getId();
|
||||||
if (avatarID >= 11000000) { // skip test avatar
|
if (avatarID >= 11000000) { // skip test avatar
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (first) { // skip adding comma for the first element
|
String color = switch (data.getQualityType()) {
|
||||||
first = false;
|
case "QUALITY_PURPLE" -> "purple";
|
||||||
} else {
|
case "QUALITY_ORANGE" -> "yellow";
|
||||||
sb.append(",");
|
case "QUALITY_BLUE" -> "blue";
|
||||||
}
|
default -> "";
|
||||||
String color;
|
};
|
||||||
switch (data.getQualityType()) {
|
Language.TextStrings avatarName = Language.getTextMapKey(data.getNameTextMapHash());
|
||||||
case "QUALITY_PURPLE":
|
for (int langIdx = 0; langIdx < NUM_LANGUAGES; langIdx++) {
|
||||||
color = "purple";
|
sbs.get(langIdx)
|
||||||
break;
|
.append("\"")
|
||||||
case "QUALITY_ORANGE":
|
|
||||||
color = "yellow";
|
|
||||||
break;
|
|
||||||
case "QUALITY_BLUE":
|
|
||||||
default:
|
|
||||||
color = "blue";
|
|
||||||
}
|
|
||||||
// Got the magic number 4233146695 from manually search in the json file
|
|
||||||
sb.append("\"")
|
|
||||||
.append(avatarID % 1000 + 1000)
|
.append(avatarID % 1000 + 1000)
|
||||||
.append("\" : [\"")
|
.append("\" : [\"")
|
||||||
.append(map.get(data.getNameTextMapHash()))
|
.append(avatarName.get(langIdx))
|
||||||
.append("(")
|
.append("(")
|
||||||
.append(map.get(4233146695L))
|
.append(CHARACTER.get(langIdx))
|
||||||
.append(")\", \"")
|
.append(")\", \"")
|
||||||
.append(color)
|
.append(color)
|
||||||
.append("\"]")
|
.append("\"],\n");
|
||||||
.append(newLine);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
list = new ArrayList<>(GameData.getItemDataMap().keySet());
|
list = new IntArrayList(GameData.getItemDataMap().keySet().intStream().sorted().toArray());
|
||||||
Collections.sort(list);
|
|
||||||
|
|
||||||
// Weapons
|
// Weapons
|
||||||
for (Integer id : list) {
|
for (int id : list) {
|
||||||
ItemData data = GameData.getItemDataMap().get(id);
|
ItemData data = GameData.getItemDataMap().get(id);
|
||||||
if (data.getId() <= 11101 || data.getId() >= 20000) {
|
if (data.getId() <= 11101 || data.getId() >= 20000) {
|
||||||
continue; //skip non weapon items
|
continue; //skip non weapon items
|
||||||
}
|
}
|
||||||
String color;
|
String color = switch (data.getRankLevel()) {
|
||||||
|
case 3 -> "blue";
|
||||||
switch (data.getRankLevel()) {
|
case 4 -> "purple";
|
||||||
case 3:
|
case 5 -> "yellow";
|
||||||
color = "blue";
|
default -> null;
|
||||||
break;
|
};
|
||||||
case 4:
|
if (color == null) continue; // skip unnecessary entries
|
||||||
color = "purple";
|
Language.TextStrings weaponName = Language.getTextMapKey(data.getNameTextMapHash());
|
||||||
break;
|
for (int langIdx = 0; langIdx < NUM_LANGUAGES; langIdx++) {
|
||||||
case 5:
|
sbs.get(langIdx)
|
||||||
color = "yellow";
|
.append("\"")
|
||||||
break;
|
|
||||||
default:
|
|
||||||
continue; // skip unnecessary entries
|
|
||||||
}
|
|
||||||
|
|
||||||
// Got the magic number 4231343903 from manually search in the json file
|
|
||||||
|
|
||||||
sb.append(",\"")
|
|
||||||
.append(data.getId())
|
.append(data.getId())
|
||||||
.append("\" : [\"")
|
.append("\" : [\"")
|
||||||
.append(map.get(data.getNameTextMapHash()).replaceAll("\"", ""))
|
.append(weaponName.get(langIdx).replaceAll("\"", "\\\\\""))
|
||||||
.append("(")
|
.append("(")
|
||||||
.append(map.get(4231343903L))
|
.append(WEAPON.get(langIdx))
|
||||||
.append(")\",\"")
|
.append(")\",\"")
|
||||||
.append(color)
|
.append(color)
|
||||||
.append("\"]")
|
.append("\"],\n");
|
||||||
.append(newLine);
|
}
|
||||||
}
|
}
|
||||||
sb.append(",\"200\": \"")
|
|
||||||
.append(map.get(332935371L))
|
for (int langIdx = 0; langIdx < NUM_LANGUAGES; langIdx++) {
|
||||||
|
sbs.get(langIdx)
|
||||||
|
.append("\"200\": \"")
|
||||||
|
.append(STANDARD_WISH.get(langIdx))
|
||||||
.append("\", \"301\": \"")
|
.append("\", \"301\": \"")
|
||||||
.append(map.get(2272170627L))
|
.append(CHARACTER_EVENT_WISH.get(langIdx))
|
||||||
|
.append("\", \"400\": \"")
|
||||||
|
.append(CHARACTER_EVENT_WISH_2.get(langIdx))
|
||||||
.append("\", \"302\": \"")
|
.append("\", \"302\": \"")
|
||||||
.append(map.get(2864268523L))
|
.append(WEAPON_EVENT_WISH.get(langIdx))
|
||||||
.append("\"")
|
.append("\"\n}\n");
|
||||||
.append("}\n}")
|
}
|
||||||
.append(newLine);
|
return sbs.stream().map(StringBuilder::toString).toList();
|
||||||
return sb.toString();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,7 @@
|
|||||||
package emu.grasscutter.server.http.documentation;
|
package emu.grasscutter.server.http.documentation;
|
||||||
|
|
||||||
import static emu.grasscutter.config.Configuration.*;
|
import static emu.grasscutter.config.Configuration.*;
|
||||||
import static emu.grasscutter.utils.Language.translate;
|
|
||||||
|
|
||||||
import com.google.gson.reflect.TypeToken;
|
|
||||||
import emu.grasscutter.Grasscutter;
|
import emu.grasscutter.Grasscutter;
|
||||||
import emu.grasscutter.command.CommandMap;
|
import emu.grasscutter.command.CommandMap;
|
||||||
import emu.grasscutter.data.GameData;
|
import emu.grasscutter.data.GameData;
|
||||||
@ -12,112 +10,129 @@ import emu.grasscutter.data.excels.ItemData;
|
|||||||
import emu.grasscutter.data.excels.MonsterData;
|
import emu.grasscutter.data.excels.MonsterData;
|
||||||
import emu.grasscutter.data.excels.SceneData;
|
import emu.grasscutter.data.excels.SceneData;
|
||||||
import emu.grasscutter.utils.FileUtils;
|
import emu.grasscutter.utils.FileUtils;
|
||||||
|
import emu.grasscutter.utils.Language;
|
||||||
import emu.grasscutter.utils.Utils;
|
import emu.grasscutter.utils.Utils;
|
||||||
import express.http.Request;
|
import express.http.Request;
|
||||||
import express.http.Response;
|
import express.http.Response;
|
||||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.HashMap;
|
import java.util.ArrayList;
|
||||||
import java.util.Map;
|
import java.util.List;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
final class HandbookRequestHandler implements DocumentationHandler {
|
final class HandbookRequestHandler implements DocumentationHandler {
|
||||||
|
private List<String> handbookHtmls;
|
||||||
private final String template;
|
private final String template;
|
||||||
private Map<Long, String> map;
|
|
||||||
|
|
||||||
|
|
||||||
public HandbookRequestHandler() {
|
public HandbookRequestHandler() {
|
||||||
final File templateFile = new File(Utils.toFilePath(DATA("documentation/handbook.html")));
|
final File templateFile = new File(Utils.toFilePath(DATA("documentation/handbook.html")));
|
||||||
if (templateFile.exists()) {
|
if (templateFile.exists()) {
|
||||||
template = new String(FileUtils.read(templateFile), StandardCharsets.UTF_8);
|
this.template = new String(FileUtils.read(templateFile), StandardCharsets.UTF_8);
|
||||||
|
this.handbookHtmls = generateHandbookHtmls();
|
||||||
} else {
|
} else {
|
||||||
Grasscutter.getLogger().warn("File does not exist: " + templateFile);
|
Grasscutter.getLogger().warn("File does not exist: " + templateFile);
|
||||||
template = null;
|
this.template = null;
|
||||||
}
|
|
||||||
|
|
||||||
final String textMapFile = "TextMap/TextMap" + DOCUMENT_LANGUAGE + ".json";
|
|
||||||
try (InputStreamReader fileReader = new InputStreamReader(new FileInputStream(
|
|
||||||
Utils.toFilePath(RESOURCE(textMapFile))), StandardCharsets.UTF_8)) {
|
|
||||||
map = Grasscutter.getGsonFactory()
|
|
||||||
.fromJson(fileReader, new TypeToken<Map<Long, String>>() {
|
|
||||||
}.getType());
|
|
||||||
} catch (IOException e) {
|
|
||||||
Grasscutter.getLogger().warn("Resource does not exist: " + textMapFile);
|
|
||||||
map = new HashMap<>();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handle(Request request, Response response) {
|
public void handle(Request request, Response response) {
|
||||||
|
final int langIdx = Language.TextStrings.MAP_LANGUAGES.getOrDefault(DOCUMENT_LANGUAGE, 0); // TODO: This should really be based off the client language somehow
|
||||||
if (template == null) {
|
if (template == null) {
|
||||||
response.status(500);
|
response.status(500);
|
||||||
return;
|
} else {
|
||||||
|
response.send(handbookHtmls.get(langIdx));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
final CommandMap cmdMap = new CommandMap(true);
|
private List<String> generateHandbookHtmls() {
|
||||||
|
final int NUM_LANGUAGES = Language.TextStrings.NUM_LANGUAGES;
|
||||||
|
final List<String> output = new ArrayList<>(NUM_LANGUAGES);
|
||||||
|
final List<Language> languages = Language.TextStrings.getLanguages();
|
||||||
|
final List<StringBuilder> sbs = new ArrayList<>(NUM_LANGUAGES);
|
||||||
|
for (int langIdx = 0; langIdx < NUM_LANGUAGES; langIdx++)
|
||||||
|
sbs.add(new StringBuilder(""));
|
||||||
|
|
||||||
|
// Commands table
|
||||||
|
new CommandMap(true).getHandlersAsList().forEach(cmd -> {
|
||||||
|
String label = cmd.getLabel();
|
||||||
|
String descKey = cmd.getDescriptionKey();
|
||||||
|
for (int langIdx = 0; langIdx < NUM_LANGUAGES; langIdx++)
|
||||||
|
sbs.get(langIdx).append("<tr><td><code>" + label + "</code></td><td>" + languages.get(langIdx).get(descKey) + "</td></tr>\n");
|
||||||
|
});
|
||||||
|
sbs.forEach(sb -> sb.setLength(sb.length()-1)); // Remove trailing \n
|
||||||
|
final List<String> cmdsTable = sbs.stream().map(StringBuilder::toString).toList();
|
||||||
|
|
||||||
|
// Avatars table
|
||||||
final Int2ObjectMap<AvatarData> avatarMap = GameData.getAvatarDataMap();
|
final Int2ObjectMap<AvatarData> avatarMap = GameData.getAvatarDataMap();
|
||||||
|
sbs.forEach(sb -> sb.setLength(0));
|
||||||
|
avatarMap.keySet().intStream().sorted().mapToObj(avatarMap::get).forEach(data -> {
|
||||||
|
int id = data.getId();
|
||||||
|
Language.TextStrings name = Language.getTextMapKey(data.getNameTextMapHash());
|
||||||
|
for (int langIdx = 0; langIdx < NUM_LANGUAGES; langIdx++)
|
||||||
|
sbs.get(langIdx).append("<tr><td><code>" + id + "</code></td><td>" + name.get(langIdx) + "</td></tr>\n");
|
||||||
|
});
|
||||||
|
sbs.forEach(sb -> sb.setLength(sb.length()-1)); // Remove trailing \n
|
||||||
|
final List<String> avatarsTable = sbs.stream().map(StringBuilder::toString).toList();
|
||||||
|
|
||||||
|
// Items table
|
||||||
final Int2ObjectMap<ItemData> itemMap = GameData.getItemDataMap();
|
final Int2ObjectMap<ItemData> itemMap = GameData.getItemDataMap();
|
||||||
|
sbs.forEach(sb -> sb.setLength(0));
|
||||||
|
itemMap.keySet().intStream().sorted().mapToObj(itemMap::get).forEach(data -> {
|
||||||
|
int id = data.getId();
|
||||||
|
Language.TextStrings name = Language.getTextMapKey(data.getNameTextMapHash());
|
||||||
|
for (int langIdx = 0; langIdx < NUM_LANGUAGES; langIdx++)
|
||||||
|
sbs.get(langIdx).append("<tr><td><code>" + id + "</code></td><td>" + name.get(langIdx) + "</td></tr>\n");
|
||||||
|
});
|
||||||
|
sbs.forEach(sb -> sb.setLength(sb.length()-1)); // Remove trailing \n
|
||||||
|
final List<String> itemsTable = sbs.stream().map(StringBuilder::toString).toList();
|
||||||
|
|
||||||
|
// Scenes table
|
||||||
final Int2ObjectMap<SceneData> sceneMap = GameData.getSceneDataMap();
|
final Int2ObjectMap<SceneData> sceneMap = GameData.getSceneDataMap();
|
||||||
|
sceneMap.keySet().intStream().sorted().mapToObj(sceneMap::get).forEach(data -> {
|
||||||
|
int id = data.getId();
|
||||||
|
for (int langIdx = 0; langIdx < NUM_LANGUAGES; langIdx++)
|
||||||
|
sbs.get(langIdx).append("<tr><td><code>" + id + "</code></td><td>" + data.getScriptData() + "</td></tr>\n");
|
||||||
|
});
|
||||||
|
sbs.forEach(sb -> sb.setLength(sb.length()-1)); // Remove trailing \n
|
||||||
|
final List<String> scenesTable = sbs.stream().map(StringBuilder::toString).toList();
|
||||||
|
|
||||||
|
// Monsters table
|
||||||
final Int2ObjectMap<MonsterData> monsterMap = GameData.getMonsterDataMap();
|
final Int2ObjectMap<MonsterData> monsterMap = GameData.getMonsterDataMap();
|
||||||
|
monsterMap.keySet().intStream().sorted().mapToObj(monsterMap::get).forEach(data -> {
|
||||||
|
int id = data.getId();
|
||||||
|
Language.TextStrings name = Language.getTextMapKey(data.getNameTextMapHash());
|
||||||
|
for (int langIdx = 0; langIdx < NUM_LANGUAGES; langIdx++)
|
||||||
|
sbs.get(langIdx).append("<tr><td><code>" + id + "</code></td><td>" + name.get(langIdx) + "</td></tr>\n");
|
||||||
|
});
|
||||||
|
sbs.forEach(sb -> sb.setLength(sb.length()-1)); // Remove trailing \n
|
||||||
|
final List<String> monstersTable = sbs.stream().map(StringBuilder::toString).toList();
|
||||||
|
|
||||||
// Add translated title etc. to the page.
|
// Add translated title etc. to the page.
|
||||||
String content = template.replace("{{TITLE}}", translate("documentation.handbook.title"))
|
for (int langIdx = 0; langIdx < NUM_LANGUAGES; langIdx++) {
|
||||||
.replace("{{TITLE_COMMANDS}}", translate("documentation.handbook.title_commands"))
|
Language lang = languages.get(langIdx);
|
||||||
.replace("{{TITLE_AVATARS}}", translate("documentation.handbook.title_avatars"))
|
output.add(template
|
||||||
.replace("{{TITLE_ITEMS}}", translate("documentation.handbook.title_items"))
|
.replace("{{TITLE}}", lang.get("documentation.handbook.title"))
|
||||||
.replace("{{TITLE_SCENES}}", translate("documentation.handbook.title_scenes"))
|
.replace("{{TITLE_COMMANDS}}", lang.get("documentation.handbook.title_commands"))
|
||||||
.replace("{{TITLE_MONSTERS}}", translate("documentation.handbook.title_monsters"))
|
.replace("{{TITLE_AVATARS}}", lang.get("documentation.handbook.title_avatars"))
|
||||||
.replace("{{HEADER_ID}}", translate("documentation.handbook.header_id"))
|
.replace("{{TITLE_ITEMS}}", lang.get("documentation.handbook.title_items"))
|
||||||
.replace("{{HEADER_COMMAND}}", translate("documentation.handbook.header_command"))
|
.replace("{{TITLE_SCENES}}", lang.get("documentation.handbook.title_scenes"))
|
||||||
.replace("{{HEADER_DESCRIPTION}}",
|
.replace("{{TITLE_MONSTERS}}", lang.get("documentation.handbook.title_monsters"))
|
||||||
translate("documentation.handbook.header_description"))
|
.replace("{{HEADER_ID}}", lang.get("documentation.handbook.header_id"))
|
||||||
.replace("{{HEADER_AVATAR}}", translate("documentation.handbook.header_avatar"))
|
.replace("{{HEADER_COMMAND}}", lang.get("documentation.handbook.header_command"))
|
||||||
.replace("{{HEADER_ITEM}}", translate("documentation.handbook.header_item"))
|
.replace("{{HEADER_DESCRIPTION}}", lang.get("documentation.handbook.header_description"))
|
||||||
.replace("{{HEADER_SCENE}}", translate("documentation.handbook.header_scene"))
|
.replace("{{HEADER_AVATAR}}", lang.get("documentation.handbook.header_avatar"))
|
||||||
.replace("{{HEADER_MONSTER}}", translate("documentation.handbook.header_monster"))
|
.replace("{{HEADER_ITEM}}", lang.get("documentation.handbook.header_item"))
|
||||||
|
.replace("{{HEADER_SCENE}}", lang.get("documentation.handbook.header_scene"))
|
||||||
|
.replace("{{HEADER_MONSTER}}", lang.get("documentation.handbook.header_monster"))
|
||||||
// Commands table
|
// Commands table
|
||||||
.replace("{{COMMANDS_TABLE}}", cmdMap.getHandlersAsList()
|
.replace("{{COMMANDS_TABLE}}", cmdsTable.get(langIdx))
|
||||||
.stream()
|
.replace("{{AVATARS_TABLE}}", avatarsTable.get(langIdx))
|
||||||
.map(cmd -> "<tr><td><code>" + cmd.getLabel() + "</code></td><td>" +
|
.replace("{{ITEMS_TABLE}}", itemsTable.get(langIdx))
|
||||||
cmd.getDescriptionString(null) + "</td></tr>")
|
.replace("{{SCENES_TABLE}}", scenesTable.get(langIdx))
|
||||||
.collect(Collectors.joining("\n")))
|
.replace("{{MONSTERS_TABLE}}", monstersTable.get(langIdx))
|
||||||
// Avatars table
|
);
|
||||||
.replace("{{AVATARS_TABLE}}", GameData.getAvatarDataMap().keySet()
|
}
|
||||||
.intStream()
|
return output;
|
||||||
.sorted()
|
|
||||||
.mapToObj(avatarMap::get)
|
|
||||||
.map(data -> "<tr><td><code>" + data.getId() + "</code></td><td>" +
|
|
||||||
map.get(data.getNameTextMapHash()) + "</td></tr>")
|
|
||||||
.collect(Collectors.joining("\n")))
|
|
||||||
// Items table
|
|
||||||
.replace("{{ITEMS_TABLE}}", GameData.getItemDataMap().keySet()
|
|
||||||
.intStream()
|
|
||||||
.sorted()
|
|
||||||
.mapToObj(itemMap::get)
|
|
||||||
.map(data -> "<tr><td><code>" + data.getId() + "</code></td><td>" +
|
|
||||||
map.get(data.getNameTextMapHash()) + "</td></tr>")
|
|
||||||
.collect(Collectors.joining("\n")))
|
|
||||||
// Scenes table
|
|
||||||
.replace("{{SCENES_TABLE}}", GameData.getSceneDataMap().keySet()
|
|
||||||
.intStream()
|
|
||||||
.sorted()
|
|
||||||
.mapToObj(sceneMap::get)
|
|
||||||
.map(data -> "<tr><td><code>" + data.getId() + "</code></td><td>" +
|
|
||||||
data.getScriptData() + "</td></tr>")
|
|
||||||
.collect(Collectors.joining("\n")))
|
|
||||||
.replace("{{MONSTERS_TABLE}}", GameData.getMonsterDataMap().keySet()
|
|
||||||
.intStream()
|
|
||||||
.sorted()
|
|
||||||
.mapToObj(monsterMap::get)
|
|
||||||
.map(data -> "<tr><td><code>" + data.getId() + "</code></td><td>" +
|
|
||||||
map.get(data.getNameTextMapHash()) + "</td></tr>")
|
|
||||||
.collect(Collectors.joining("\n")));
|
|
||||||
|
|
||||||
response.send(content);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -240,7 +240,7 @@ public final class Language {
|
|||||||
private static final int TEXTMAP_CACHE_VERSION = 0x9CCACE02;
|
private static final int TEXTMAP_CACHE_VERSION = 0x9CCACE02;
|
||||||
@EqualsAndHashCode public static class TextStrings implements Serializable {
|
@EqualsAndHashCode public static class TextStrings implements Serializable {
|
||||||
public static final String[] ARR_LANGUAGES = {"EN", "CHS", "CHT", "JP", "KR", "DE", "ES", "FR", "ID", "PT", "RU", "TH", "VI"};
|
public static final String[] ARR_LANGUAGES = {"EN", "CHS", "CHT", "JP", "KR", "DE", "ES", "FR", "ID", "PT", "RU", "TH", "VI"};
|
||||||
public static final String[] ARR_GC_LANGUAGES = {"en-US", "zh-CN", "zh-TW", "JP", "KR", "DE", "es-ES", "fr-FR", "ID", "PT", "ru-RU", "TH", "VI"};
|
public static final String[] ARR_GC_LANGUAGES = {"en-US", "zh-CN", "zh-TW", "ja-JP", "ko-KR", "DE", "es-ES", "fr-FR", "ID", "PT", "ru-RU", "TH", "VI"};
|
||||||
public static final int NUM_LANGUAGES = ARR_LANGUAGES.length;
|
public static final int NUM_LANGUAGES = ARR_LANGUAGES.length;
|
||||||
public static final List<String> LIST_LANGUAGES = Arrays.asList(ARR_LANGUAGES);
|
public static final List<String> LIST_LANGUAGES = Arrays.asList(ARR_LANGUAGES);
|
||||||
public static final Object2IntMap<String> MAP_LANGUAGES = // Map "EN": 0, "CHS": 1, ..., "VI": 12
|
public static final Object2IntMap<String> MAP_LANGUAGES = // Map "EN": 0, "CHS": 1, ..., "VI": 12
|
||||||
@ -276,6 +276,14 @@ public final class Language {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static List<Language> getLanguages() {
|
||||||
|
return Arrays.stream(ARR_GC_LANGUAGES).map(Language::getLanguage).toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String get(int languageIndex) {
|
||||||
|
return strings[languageIndex];
|
||||||
|
}
|
||||||
|
|
||||||
public String get(String languageCode) {
|
public String get(String languageCode) {
|
||||||
return strings[MAP_LANGUAGES.getOrDefault(languageCode, 0)];
|
return strings[MAP_LANGUAGES.getOrDefault(languageCode, 0)];
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user