mirror of
https://github.com/Melledy/Grasscutter.git
synced 2024-11-22 07:37:43 +00:00
Utils for gacha history record subsystem
* Auto generate mapping files with command `java -jar grasscutter.jar -gachamap` * Static file provider * For gacha record webpage * All static files should be stored at `GRASSCUTTER_RESOURCE/gcstatic/` * Can benefit other subsystem in future when webpages involved
This commit is contained in:
parent
6a20e383f7
commit
a102613313
@ -102,6 +102,8 @@ You can find the output jar in the root of the project folder.
|
|||||||
|
|
||||||
You might want to use this command (`java -jar grasscutter.jar -handbook`) in a cmd that is in the grasscutter folder. It will create a handbook file (GM Handbook.txt) where you can find the item IDs for stuff you want
|
You might want to use this command (`java -jar grasscutter.jar -handbook`) in a cmd that is in the grasscutter folder. It will create a handbook file (GM Handbook.txt) where you can find the item IDs for stuff you want
|
||||||
|
|
||||||
|
You may want to use this command (`java -jar grasscutter.jar -gachamap`) to generate a mapping file for the gacha record subsystem. The file will be generated to `GRASSCUTTER_RESOURCE/gcstatic` folder. Otherwise you may only see number IDs in the gacha record page.
|
||||||
|
|
||||||
There is a dummy user named "Server" in every player's friends list that you can message to use commands. Commands also work in other chat rooms, such as private/team chats. to run commands ingame, you need to add prefix `/` or `!` such as `/pos`
|
There is a dummy user named "Server" in every player's friends list that you can message to use commands. Commands also work in other chat rooms, such as private/team chats. to run commands ingame, you need to add prefix `/` or `!` such as `/pos`
|
||||||
|
|
||||||
| Commands | Usage | Permission node | Availability | description | Alias |
|
| Commands | Usage | Permission node | Availability | description | Alias |
|
||||||
|
@ -102,6 +102,8 @@ chmod +x gradlew
|
|||||||
|
|
||||||
你可能需要在终端中运行 `java -jar grasscutter.jar -handbook` 它将会创建一个 `GM Handbook.txt` 以方便您查阅物品ID等
|
你可能需要在终端中运行 `java -jar grasscutter.jar -handbook` 它将会创建一个 `GM Handbook.txt` 以方便您查阅物品ID等
|
||||||
|
|
||||||
|
你可能需要在终端中运行 `java -jar grasscutter.jar -gachamap` 来使得祈愿历史记录系统正常显示物品信息。 这个命令生成一个配置文件到如下文件夹:`GRASSCUTTER_RESOURCE/gcstatic`。 不执行此命令,您的祈愿历史记录中将只会显示数字ID而非物品名称。(目前仅支持自动生成英文记录信息)
|
||||||
|
|
||||||
在每个玩家的朋友列表中都有一个名为“Server”的虚拟用户,你可以通过发送消息来使用命令。命令也适用于其他聊天室,例如私人/团队聊天。
|
在每个玩家的朋友列表中都有一个名为“Server”的虚拟用户,你可以通过发送消息来使用命令。命令也适用于其他聊天室,例如私人/团队聊天。
|
||||||
要在游戏中使用命令,需要添加 `/` 或 `!` 前缀,如 `/pos`
|
要在游戏中使用命令,需要添加 `/` 或 `!` 前缀,如 `/pos`
|
||||||
|
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
|
<!--Not sure the page is provided in UTF-8 acutally, just put meta here-->
|
||||||
|
<meta charset="utf-8" />
|
||||||
<script>
|
<script>
|
||||||
// Debug entry
|
// Debug entry
|
||||||
// record = [
|
// record = [
|
||||||
@ -35,7 +37,13 @@
|
|||||||
302: "Event Weapon",
|
302: "Event Weapon",
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
mappings['default'] = mappings['en-us'];
|
</script>
|
||||||
|
<!-- This file could be generated automatically using `java -jar grasscutter.jar -gachamap` -->
|
||||||
|
<!-- You can also modify the file manually to customize it -->
|
||||||
|
<!-- Otherwise you may onle see number IDs in the gacha record -->
|
||||||
|
<script type="text/javascript" src="/gcstatic/mappings.js"></script>
|
||||||
|
<script>
|
||||||
|
mappings['default'] = mappings['en-us']; // make en-us as default/fallback option
|
||||||
</script>
|
</script>
|
||||||
<!-- TODO: Refine the CSS -->
|
<!-- TODO: Refine the CSS -->
|
||||||
<style>
|
<style>
|
||||||
@ -43,7 +51,7 @@
|
|||||||
text-decoration: none !important;
|
text-decoration: none !important;
|
||||||
}
|
}
|
||||||
.content {
|
.content {
|
||||||
width: 400px;
|
width: 600px;
|
||||||
margin: auto;
|
margin: auto;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
@ -119,7 +127,7 @@
|
|||||||
" "+String(date.getHours()).padStart(2, "0")+
|
" "+String(date.getHours()).padStart(2, "0")+
|
||||||
":"+String(date.getMinutes()).padStart(2, "0")+
|
":"+String(date.getMinutes()).padStart(2, "0")+
|
||||||
":"+String(date.getSeconds()).padStart(2, "0")+
|
":"+String(date.getSeconds()).padStart(2, "0")+
|
||||||
"."+date.getMilliseconds();
|
"."+String(date.getMilliseconds()).padStart(3, "0");
|
||||||
} else if (lang == "zh-cn") { // YYYY/MM/DD hh:mm:ss.SSS
|
} else if (lang == "zh-cn") { // YYYY/MM/DD hh:mm:ss.SSS
|
||||||
return date.getFullYear()+
|
return date.getFullYear()+
|
||||||
"/" + String(date.getMonth()+1).padStart(2, "0") +
|
"/" + String(date.getMonth()+1).padStart(2, "0") +
|
||||||
@ -127,7 +135,7 @@
|
|||||||
" "+String(date.getHours()).padStart(2, "0")+
|
" "+String(date.getHours()).padStart(2, "0")+
|
||||||
":"+String(date.getMinutes()).padStart(2, "0")+
|
":"+String(date.getMinutes()).padStart(2, "0")+
|
||||||
":"+String(date.getSeconds()).padStart(2, "0")+
|
":"+String(date.getSeconds()).padStart(2, "0")+
|
||||||
"."+date.getMilliseconds();
|
"."+String(date.getMilliseconds()).padStart(3, "0");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(function (){
|
(function (){
|
||||||
|
@ -60,6 +60,9 @@ public final class Grasscutter {
|
|||||||
case "-handbook" -> {
|
case "-handbook" -> {
|
||||||
Tools.createGmHandbook(); return;
|
Tools.createGmHandbook(); return;
|
||||||
}
|
}
|
||||||
|
case "-gachamap" -> {
|
||||||
|
Tools.createGachaMapping(); return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,6 +21,7 @@ import emu.grasscutter.server.dispatch.json.ComboTokenReqJson.LoginTokenData;
|
|||||||
import emu.grasscutter.server.event.dispatch.QueryAllRegionsEvent;
|
import emu.grasscutter.server.event.dispatch.QueryAllRegionsEvent;
|
||||||
import emu.grasscutter.server.event.dispatch.QueryCurrentRegionEvent;
|
import emu.grasscutter.server.event.dispatch.QueryCurrentRegionEvent;
|
||||||
import emu.grasscutter.server.http.gacha.GachaRecordHandler;
|
import emu.grasscutter.server.http.gacha.GachaRecordHandler;
|
||||||
|
import emu.grasscutter.server.http.gcstatic.StaticFileHandler;
|
||||||
import emu.grasscutter.utils.FileUtils;
|
import emu.grasscutter.utils.FileUtils;
|
||||||
import express.Express;
|
import express.Express;
|
||||||
import org.eclipse.jetty.server.Connector;
|
import org.eclipse.jetty.server.Connector;
|
||||||
@ -445,8 +446,12 @@ public final class DispatchServer {
|
|||||||
// webstatic-sea.hoyoverse.com
|
// webstatic-sea.hoyoverse.com
|
||||||
httpServer.get("/admin/mi18n/plat_oversea/m202003048/m202003048-version.json", new DispatchHttpJsonHandler("{\"version\":51}"));
|
httpServer.get("/admin/mi18n/plat_oversea/m202003048/m202003048-version.json", new DispatchHttpJsonHandler("{\"version\":51}"));
|
||||||
|
|
||||||
|
// gacha record
|
||||||
httpServer.get("/gacha", new GachaRecordHandler());
|
httpServer.get("/gacha", new GachaRecordHandler());
|
||||||
|
|
||||||
|
// static file provider
|
||||||
|
httpServer.get("/gcstatic/*", new StaticFileHandler());
|
||||||
|
|
||||||
httpServer.listen(Grasscutter.getConfig().getDispatchOptions().Port);
|
httpServer.listen(Grasscutter.getConfig().getDispatchOptions().Port);
|
||||||
Grasscutter.getLogger().info("[Dispatch] Dispatch server started on port " + httpServer.raw().port());
|
Grasscutter.getLogger().info("[Dispatch] Dispatch server started on port " + httpServer.raw().port());
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,31 @@
|
|||||||
|
package emu.grasscutter.server.http.gcstatic;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import emu.grasscutter.Grasscutter;
|
||||||
|
import express.http.HttpContextHandler;
|
||||||
|
import express.http.Request;
|
||||||
|
import express.http.Response;
|
||||||
|
|
||||||
|
public final class StaticFileHandler implements HttpContextHandler {
|
||||||
|
String static_folder;
|
||||||
|
public StaticFileHandler() {
|
||||||
|
static_folder = Grasscutter.getConfig().RESOURCE_FOLDER + "/gcstatic";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handle(Request req, Response res) throws IOException {
|
||||||
|
// Grasscutter.getLogger().info( req.path());
|
||||||
|
|
||||||
|
String reqFilename = req.path().replace("/gcstatic", ""); // remove the leading path
|
||||||
|
reqFilename = reqFilename.replace("/../", "/./"); // security guard to prevent arbitrary read
|
||||||
|
File resFile = new File(static_folder + reqFilename);
|
||||||
|
if (resFile.exists()) {
|
||||||
|
res.sendFile(resFile.toPath());
|
||||||
|
} else {
|
||||||
|
res.status(404);
|
||||||
|
res.send("404");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,6 @@
|
|||||||
package emu.grasscutter.tools;
|
package emu.grasscutter.tools;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.FileReader;
|
import java.io.FileReader;
|
||||||
@ -93,4 +94,96 @@ public final class Tools {
|
|||||||
|
|
||||||
Grasscutter.getLogger().info("GM Handbook generated!");
|
Grasscutter.getLogger().info("GM Handbook generated!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
|
public static void createGachaMapping() throws Exception {
|
||||||
|
ResourceLoader.loadResources();
|
||||||
|
|
||||||
|
Map<Long, String> map;
|
||||||
|
try (InputStreamReader fileReader = new InputStreamReader(new FileInputStream(Utils.toFilePath(Grasscutter.getConfig().RESOURCE_FOLDER + "TextMap/TextMapEN.json")), StandardCharsets.UTF_8)) {
|
||||||
|
map = Grasscutter.getGsonFactory().fromJson(fileReader, new TypeToken<Map<Long, String>>() {}.getType());
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Integer> list;
|
||||||
|
|
||||||
|
|
||||||
|
String fileName = Grasscutter.getConfig().RESOURCE_FOLDER + "/gcstatic";
|
||||||
|
File folder = new File(fileName);
|
||||||
|
if (!folder.exists()) { folder.mkdirs(); } // create folder if it doesn't exist
|
||||||
|
fileName = fileName + "/mappings.js";
|
||||||
|
|
||||||
|
try (PrintWriter writer = new PrintWriter(new OutputStreamWriter(new FileOutputStream(fileName), StandardCharsets.UTF_8), false)) {
|
||||||
|
|
||||||
|
list = new ArrayList<>(GameData.getAvatarDataMap().keySet());
|
||||||
|
Collections.sort(list);
|
||||||
|
|
||||||
|
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(",");
|
||||||
|
}
|
||||||
|
String color;
|
||||||
|
switch (data.getQualityType()){
|
||||||
|
case "QUALITY_PURPLE":
|
||||||
|
color = "purple";
|
||||||
|
break;
|
||||||
|
case "QUALITY_ORANGE":
|
||||||
|
color = "yellow";
|
||||||
|
break;
|
||||||
|
case "QUALITY_BLUE":
|
||||||
|
default:
|
||||||
|
color = "blue";
|
||||||
|
}
|
||||||
|
|
||||||
|
writer.println(
|
||||||
|
"\"" + (avatarID % 1000 + 1000) + "\" : [\""
|
||||||
|
+ map.get(data.getNameTextMapHash()) + "(Avatar)\", \""
|
||||||
|
+ 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
|
||||||
|
}
|
||||||
|
writer.println(",\"" + data.getId() +
|
||||||
|
"\" : [\"" + map.get(data.getNameTextMapHash()).replaceAll("\"", "")
|
||||||
|
+ "(Weapon)\",\""+ color + "\"]");
|
||||||
|
}
|
||||||
|
writer.println(",\"200\": \"Standard\", \"301\": \"Avatar Event\", \"302\": \"Weapon event\"");
|
||||||
|
writer.println("}\n}");
|
||||||
|
}
|
||||||
|
Grasscutter.getLogger().info("Mappings generated!");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user