mirror of
https://github.com/Grasscutters/Grasscutter.git
synced 2025-01-25 22:32:52 +08:00
Create initial handbook data dumpers
these can be accessed by using `-dump=commands,en-us` or `-dump=avatars/items,EN` (all languages supported)
This commit is contained in:
parent
ac7b4d1238
commit
7c4186f5df
@ -1,16 +1,215 @@
|
|||||||
package emu.grasscutter.tools;
|
package emu.grasscutter.tools;
|
||||||
|
|
||||||
import emu.grasscutter.net.proto.GetGachaInfoRspOuterClass.GetGachaInfoRsp;
|
import emu.grasscutter.command.Command;
|
||||||
import emu.grasscutter.net.proto.GetShopRspOuterClass.GetShopRsp;
|
import emu.grasscutter.command.Command.TargetRequirement;
|
||||||
|
import emu.grasscutter.command.CommandMap;
|
||||||
|
import emu.grasscutter.data.GameData;
|
||||||
|
import emu.grasscutter.data.ResourceLoader;
|
||||||
|
import emu.grasscutter.game.inventory.ItemType;
|
||||||
|
import emu.grasscutter.utils.JsonUtils;
|
||||||
|
import emu.grasscutter.utils.Language;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
|
||||||
public final class Dumpers {
|
import java.io.File;
|
||||||
public static void extractBanner(byte[] data) throws Exception {
|
import java.io.IOException;
|
||||||
GetGachaInfoRsp proto = GetGachaInfoRsp.parseFrom(data);
|
import java.nio.file.Files;
|
||||||
System.out.println(proto);
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
public interface Dumpers {
|
||||||
|
/**
|
||||||
|
* Fetches the description of a command.
|
||||||
|
*
|
||||||
|
* @param locale The locale to use.
|
||||||
|
* @param command The command to get the description of.
|
||||||
|
* @return The description of the command.
|
||||||
|
*/
|
||||||
|
private static String commandDescription(String locale, Command command) {
|
||||||
|
try {
|
||||||
|
// Get the language by the locale.
|
||||||
|
var language = Language.getLanguage(locale);
|
||||||
|
if (language == null) throw new IllegalArgumentException("Invalid language.");
|
||||||
|
|
||||||
|
return language.get("commands." + command.label() + ".description");
|
||||||
|
} catch (IllegalArgumentException ignored) {
|
||||||
|
return command.label();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void extractShop(byte[] data) throws Exception {
|
/**
|
||||||
GetShopRsp proto = GetShopRsp.parseFrom(data);
|
* Encodes the dump into comma separated values.
|
||||||
System.out.println(proto);
|
*
|
||||||
|
* @param dump The dump to encode.
|
||||||
|
* @return The encoded dump.
|
||||||
|
*/
|
||||||
|
private static String miniEncode(Map<Integer, ?> dump) {
|
||||||
|
return dump.entrySet().stream()
|
||||||
|
.map(entry -> entry.getKey() + "," + entry.getValue().toString())
|
||||||
|
.collect(Collectors.joining("\n"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dumps all commands to a JSON file.
|
||||||
|
*
|
||||||
|
* @param locale The language to dump the commands in.
|
||||||
|
*/
|
||||||
|
static void dumpCommands(String locale) {
|
||||||
|
// Check that commands are registered.
|
||||||
|
var commandMap = CommandMap.getInstance();
|
||||||
|
if (commandMap == null) commandMap = new CommandMap(true);
|
||||||
|
|
||||||
|
// Convert all registered commands to an info map.
|
||||||
|
var dump = new HashMap<String, CommandInfo>();
|
||||||
|
commandMap.getAnnotationsAsList().forEach(command -> {
|
||||||
|
var description = Dumpers.commandDescription(locale, command);
|
||||||
|
var labels = new ArrayList<String>(){{
|
||||||
|
this.add(command.label());
|
||||||
|
this.addAll(List.of(command.aliases()));
|
||||||
|
}};
|
||||||
|
|
||||||
|
// Add the command info to the list.
|
||||||
|
dump.put(command.label(), new CommandInfo(
|
||||||
|
labels, description, List.of(command.usage()), List.of(
|
||||||
|
command.permission(), command.permissionTargeted()),
|
||||||
|
command.targetRequirement()));
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Create a file for the dump.
|
||||||
|
var file = new File("commands.json");
|
||||||
|
if (file.exists() && !file.delete())
|
||||||
|
throw new RuntimeException("Failed to delete file.");
|
||||||
|
if (!file.exists() && !file.createNewFile())
|
||||||
|
throw new RuntimeException("Failed to create file.");
|
||||||
|
|
||||||
|
// Write the dump to the file.
|
||||||
|
Files.writeString(file.toPath(), JsonUtils.encode(dump));
|
||||||
|
} catch (IOException ignored) {
|
||||||
|
throw new RuntimeException("Failed to write to file.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dumps all avatars to a JSON file.
|
||||||
|
*
|
||||||
|
* @param locale The language to dump the avatars in.
|
||||||
|
*/
|
||||||
|
static void dumpAvatars(String locale) {
|
||||||
|
// Reload resources.
|
||||||
|
ResourceLoader.loadAll();
|
||||||
|
Language.loadTextMaps();
|
||||||
|
|
||||||
|
// Convert all known avatars to an avatar map.
|
||||||
|
var dump = new HashMap<Integer, AvatarInfo>();
|
||||||
|
GameData.getAvatarDataMap().forEach((id, avatar) -> {
|
||||||
|
var langHash = avatar.getNameTextMapHash();
|
||||||
|
dump.put(id, new AvatarInfo(
|
||||||
|
langHash == 0 ? avatar.getName() : Language.getTextMapKey(langHash).get(locale),
|
||||||
|
avatar.getQualityType().equals("QUALITY_PURPLE") ? Quality.EPIC : Quality.LEGENDARY,
|
||||||
|
avatar.getId()
|
||||||
|
));
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Create a file for the dump.
|
||||||
|
var file = new File("avatars.json");
|
||||||
|
if (file.exists() && !file.delete())
|
||||||
|
throw new RuntimeException("Failed to delete file.");
|
||||||
|
if (!file.exists() && !file.createNewFile())
|
||||||
|
throw new RuntimeException("Failed to create file.");
|
||||||
|
|
||||||
|
// Write the dump to the file.
|
||||||
|
Files.writeString(file.toPath(), JsonUtils.encode(dump));
|
||||||
|
} catch (IOException ignored) {
|
||||||
|
throw new RuntimeException("Failed to write to file.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dumps all items to a JSON file.
|
||||||
|
*
|
||||||
|
* @param locale The language to dump the items in.
|
||||||
|
*/
|
||||||
|
static void dumpItems(String locale) {
|
||||||
|
// Reload resources.
|
||||||
|
ResourceLoader.loadAll();
|
||||||
|
Language.loadTextMaps();
|
||||||
|
|
||||||
|
// Convert all known items to an item map.
|
||||||
|
var dump = new HashMap<Integer, ItemData>();
|
||||||
|
GameData.getItemDataMap().forEach((id, item) -> dump.put(id, new ItemData(
|
||||||
|
item.getId(), Language.getTextMapKey(item.getNameTextMapHash()).get(locale),
|
||||||
|
Quality.from(item.getRankLevel()), item.getItemType()
|
||||||
|
)));
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Create a file for the dump.
|
||||||
|
var file = new File("items.csv");
|
||||||
|
if (file.exists() && !file.delete())
|
||||||
|
throw new RuntimeException("Failed to delete file.");
|
||||||
|
if (!file.exists() && !file.createNewFile())
|
||||||
|
throw new RuntimeException("Failed to create file.");
|
||||||
|
|
||||||
|
// Write the dump to the file.
|
||||||
|
Files.writeString(file.toPath(), Dumpers.miniEncode(dump));
|
||||||
|
} catch (IOException ignored) {
|
||||||
|
throw new RuntimeException("Failed to write to file.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@AllArgsConstructor
|
||||||
|
class CommandInfo {
|
||||||
|
public List<String> name;
|
||||||
|
public String description;
|
||||||
|
public List<String> usage;
|
||||||
|
public List<String> permission;
|
||||||
|
public TargetRequirement target;
|
||||||
|
}
|
||||||
|
|
||||||
|
@AllArgsConstructor
|
||||||
|
class AvatarInfo {
|
||||||
|
public String name;
|
||||||
|
public Quality quality;
|
||||||
|
public int id;
|
||||||
|
}
|
||||||
|
|
||||||
|
@AllArgsConstructor
|
||||||
|
class ItemData {
|
||||||
|
public int id;
|
||||||
|
public String name;
|
||||||
|
public Quality quality;
|
||||||
|
public ItemType type;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return this.id + ","
|
||||||
|
+ this.name + ","
|
||||||
|
+ this.quality + ","
|
||||||
|
+ this.type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum Quality {
|
||||||
|
LEGENDARY, EPIC, RARE, UNCOMMON, COMMON, UNKNOWN;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a rank level to a quality.
|
||||||
|
*
|
||||||
|
* @param rankLevel The rank level to convert.
|
||||||
|
* @return The quality.
|
||||||
|
*/
|
||||||
|
static Quality from(int rankLevel) {
|
||||||
|
return switch (rankLevel) {
|
||||||
|
case 0 -> UNKNOWN;
|
||||||
|
case 1 -> COMMON;
|
||||||
|
case 2 -> UNCOMMON;
|
||||||
|
case 3 -> RARE;
|
||||||
|
case 4 -> EPIC;
|
||||||
|
default -> LEGENDARY;
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,8 @@ import emu.grasscutter.Grasscutter.ServerRunMode;
|
|||||||
import emu.grasscutter.net.packet.PacketOpcodesUtils;
|
import emu.grasscutter.net.packet.PacketOpcodesUtils;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
import emu.grasscutter.tools.Dumpers;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
/** A parser for start-up arguments. */
|
/** A parser for start-up arguments. */
|
||||||
@ -47,6 +49,7 @@ public final class StartupArguments {
|
|||||||
SERVER.http.encryption.useEncryption = false;
|
SERVER.http.encryption.useEncryption = false;
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
|
"-dump", StartupArguments::dump,
|
||||||
|
|
||||||
// Aliases.
|
// Aliases.
|
||||||
"-v", StartupArguments::printVersion,
|
"-v", StartupArguments::printVersion,
|
||||||
@ -126,4 +129,36 @@ public final class StartupArguments {
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dumps the specified information.
|
||||||
|
*
|
||||||
|
* @param parameter The parameter to dump.
|
||||||
|
* @return True to exit early.
|
||||||
|
*/
|
||||||
|
private static boolean dump(String parameter) {
|
||||||
|
// Parse the parameter.
|
||||||
|
if (!parameter.contains(",")) {
|
||||||
|
Grasscutter.getLogger().error("Dumper usage: -dump=<content>,<language>");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
var split = parameter.split(",");
|
||||||
|
var content = split[0];
|
||||||
|
var language = split[1];
|
||||||
|
|
||||||
|
try {
|
||||||
|
switch (content.toLowerCase()) {
|
||||||
|
case "commands" -> Dumpers.dumpCommands(language);
|
||||||
|
case "avatars" -> Dumpers.dumpAvatars(language);
|
||||||
|
case "items" -> Dumpers.dumpItems(language);
|
||||||
|
}
|
||||||
|
|
||||||
|
Grasscutter.getLogger().info("Finished dumping.");
|
||||||
|
} catch (Exception exception) {
|
||||||
|
Grasscutter.getLogger().error("Unable to complete dump.", exception);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user