mirror of
https://github.com/Grasscutters/Grasscutter.git
synced 2024-11-26 22:00:26 +00:00
Introduce a new arguments parser (#1629)
Original commits: * Clean-up * Introduce a new application arguments parser & handler * Clean-up and deprecate `Tools#getLanguageOption` * Fix `-debug` and `-debugall` parameters * found this while debugging, ...why * Remove deprecated parameters * Invoke startup argument parser before handbook generation * Move command map instantiation to `Grasscutter `(prevent making 3 instances on startup) * Ensure \n at EOF Co-authored-by: AnimeGitB <AnimeGitB@bigblueball.in>
This commit is contained in:
parent
e20b185dc0
commit
3121e3e67d
@ -5,10 +5,10 @@ charset = utf-8
|
||||
end_of_line = lf
|
||||
indent_size = 4
|
||||
indent_style = space
|
||||
insert_final_newline = false
|
||||
insert_final_newline = true
|
||||
max_line_length = 120
|
||||
tab_width = 4
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[{*.json,*.xml}]
|
||||
indent_size = 2
|
||||
indent_size = 2
|
||||
|
6
.gitattributes
vendored
Normal file
6
.gitattributes
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
*.java text=auto
|
||||
*.json text=auto
|
||||
*.md text=auto
|
||||
*.properties text=auto
|
||||
*.py text=auto
|
||||
*.sh text=auto
|
@ -29,7 +29,10 @@ import emu.grasscutter.server.http.handlers.LogHandler;
|
||||
import emu.grasscutter.tools.Tools;
|
||||
import emu.grasscutter.utils.Crypto;
|
||||
import emu.grasscutter.utils.Language;
|
||||
import emu.grasscutter.utils.StartupArguments;
|
||||
import emu.grasscutter.utils.Utils;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.jline.reader.EndOfFileException;
|
||||
import org.jline.reader.LineReader;
|
||||
import org.jline.reader.LineReaderBuilder;
|
||||
@ -57,10 +60,13 @@ public final class Grasscutter {
|
||||
public static final File configFile = new File("./config.json");
|
||||
|
||||
private static int day; // Current day of week.
|
||||
@Getter @Setter private static String preferredLanguage;
|
||||
|
||||
private static HttpServer httpServer;
|
||||
private static GameServer gameServer;
|
||||
private static PluginManager pluginManager;
|
||||
@Getter private static CommandMap commandMap;
|
||||
|
||||
private static AuthenticationSystem authenticationSystem;
|
||||
private static PermissionHandler permissionHandler;
|
||||
|
||||
@ -89,59 +95,16 @@ public final class Grasscutter {
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
Crypto.loadKeys(); // Load keys from buffers.
|
||||
Tools.createGmHandbooks();
|
||||
|
||||
// Parse arguments.
|
||||
boolean exitEarly = false;
|
||||
for (String arg : args) {
|
||||
switch (arg.toLowerCase()) {
|
||||
case "-dumppacketids" -> {
|
||||
PacketOpcodesUtils.dumpPacketIds();
|
||||
exitEarly = true;
|
||||
}
|
||||
case "-version" -> {
|
||||
System.out.println("Grasscutter version: " + BuildConfig.VERSION + "-" + BuildConfig.GIT_HASH);
|
||||
exitEarly = true;
|
||||
}
|
||||
case "-debug" -> {
|
||||
// Set the logger to debug.
|
||||
log.setLevel(Level.DEBUG);
|
||||
log.debug("The logger is now running in debug mode.");
|
||||
|
||||
// Change loggers to debug.
|
||||
((Logger) LoggerFactory.getLogger("express"))
|
||||
.setLevel(Level.INFO);
|
||||
((Logger) LoggerFactory.getLogger("org.quartz"))
|
||||
.setLevel(Level.INFO);
|
||||
((Logger) LoggerFactory.getLogger("org.reflections"))
|
||||
.setLevel(Level.INFO);
|
||||
((Logger) LoggerFactory.getLogger("org.eclipse.jetty"))
|
||||
.setLevel(Level.INFO);
|
||||
((Logger) LoggerFactory.getLogger("org.mongodb.driver"))
|
||||
.setLevel(Level.INFO);
|
||||
}
|
||||
case "-debugall" -> {
|
||||
// Set the logger to debug.
|
||||
log.setLevel(Level.DEBUG);
|
||||
log.debug("The logger is now running in debug mode.");
|
||||
|
||||
// Change loggers to debug.
|
||||
((Logger) LoggerFactory.getLogger("express"))
|
||||
.setLevel(Level.DEBUG);
|
||||
((Logger) LoggerFactory.getLogger("org.quartz"))
|
||||
.setLevel(Level.DEBUG);
|
||||
((Logger) LoggerFactory.getLogger("org.reflections"))
|
||||
.setLevel(Level.DEBUG);
|
||||
((Logger) LoggerFactory.getLogger("org.eclipse.jetty"))
|
||||
.setLevel(Level.DEBUG);
|
||||
((Logger) LoggerFactory.getLogger("org.mongodb.driver"))
|
||||
.setLevel(Level.DEBUG);
|
||||
}
|
||||
}
|
||||
// Parse start-up arguments.
|
||||
if(StartupArguments.parse(args)) {
|
||||
System.exit(0); // Exit early.
|
||||
}
|
||||
|
||||
// Exit early if an argument sets it.
|
||||
if (exitEarly) System.exit(0);
|
||||
// Create command map.
|
||||
commandMap = new CommandMap(true);
|
||||
// Generate handbooks.
|
||||
Tools.createGmHandbooks();
|
||||
|
||||
// Initialize server.
|
||||
Grasscutter.getLogger().info(translate("messages.status.starting"));
|
||||
|
@ -23,7 +23,7 @@ public final class CommandMap {
|
||||
}
|
||||
|
||||
public static CommandMap getInstance() {
|
||||
return Grasscutter.getGameServer().getCommandMap();
|
||||
return Grasscutter.getCommandMap();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -421,7 +421,7 @@ public class ResourceLoader {
|
||||
GameData.getMainQuestDataMap().put(mainQuest.getId(), mainQuest);
|
||||
}
|
||||
|
||||
try (Reader reader = new FileReader(new File(RESOURCE("QuestEncryptionKeys.json")))) {
|
||||
try (Reader reader = new FileReader(RESOURCE("QuestEncryptionKeys.json"))) {
|
||||
List<QuestEncryptionKey> keys = Grasscutter.getGsonFactory().fromJson(
|
||||
reader,
|
||||
TypeToken.getParameterized(List.class, QuestEncryptionKey.class).getType());
|
||||
|
@ -85,7 +85,6 @@ public final class PluginManager {
|
||||
PluginConfig pluginConfig = Grasscutter.getGsonFactory().fromJson(fileReader, PluginConfig.class);
|
||||
// Check if the plugin config is valid.
|
||||
if (!pluginConfig.validate()) {
|
||||
Utils.logObject(pluginConfig);
|
||||
Grasscutter.getLogger().warn("Plugin " + plugin.getName() + " has an invalid config file.");
|
||||
return;
|
||||
}
|
||||
@ -211,11 +210,7 @@ public final class PluginManager {
|
||||
public void disablePlugins() {
|
||||
this.plugins.forEach((name, plugin) -> {
|
||||
Grasscutter.getLogger().info("Disabling plugin: " + name);
|
||||
try {
|
||||
plugin.onDisable();
|
||||
} catch (Throwable exception) {
|
||||
Grasscutter.getLogger().error("Failed to disable plugin: " + name, exception);
|
||||
}
|
||||
this.disablePlugin(plugin);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,7 @@ import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.auth.AuthenticationSystem;
|
||||
import emu.grasscutter.command.Command;
|
||||
import emu.grasscutter.command.CommandHandler;
|
||||
import emu.grasscutter.command.CommandMap;
|
||||
import emu.grasscutter.command.PermissionHandler;
|
||||
import emu.grasscutter.game.player.Player;
|
||||
import emu.grasscutter.server.game.GameServer;
|
||||
@ -72,7 +73,7 @@ public final class ServerHook {
|
||||
if(!clazz.isAnnotationPresent(Command.class))
|
||||
throw new IllegalArgumentException("Command handler must be annotated with @Command.");
|
||||
Command commandData = clazz.getAnnotation(Command.class);
|
||||
this.gameServer.getCommandMap().registerCommand(commandData.label(), handler);
|
||||
CommandMap.getInstance().registerCommand(commandData.label(), handler);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -72,7 +72,6 @@ public final class GameServer extends KcpServer {
|
||||
|
||||
// Extra
|
||||
private final ServerTaskScheduler scheduler;
|
||||
private final CommandMap commandMap;
|
||||
private final TaskMap taskMap;
|
||||
|
||||
private ChatManagerHandler chatManager;
|
||||
@ -107,7 +106,6 @@ public final class GameServer extends KcpServer {
|
||||
|
||||
// Extra
|
||||
this.scheduler = new ServerTaskScheduler();
|
||||
this.commandMap = new CommandMap(true);
|
||||
this.taskMap = new TaskMap(true);
|
||||
|
||||
// Create game systems
|
||||
|
@ -54,7 +54,7 @@ final class HandbookRequestHandler implements DocumentationHandler {
|
||||
sbs.add(new StringBuilder(""));
|
||||
|
||||
// Commands table
|
||||
new CommandMap(true).getHandlersAsList().forEach(cmd -> {
|
||||
CommandMap.getInstance().getHandlersAsList().forEach(cmd -> {
|
||||
String label = cmd.getLabel();
|
||||
String descKey = cmd.getDescriptionKey();
|
||||
for (int langIdx = 0; langIdx < NUM_LANGUAGES; langIdx++)
|
||||
|
@ -48,7 +48,7 @@ public final class Tools {
|
||||
.append("// Created " + now + "\n\n")
|
||||
.append("// Commands\n"));
|
||||
// Commands
|
||||
final List<CommandHandler> cmdList = new CommandMap(true).getHandlersAsList();
|
||||
final List<CommandHandler> cmdList = CommandMap.getInstance().getHandlersAsList();
|
||||
final String padCmdLabel = "%" + cmdList.stream().map(CommandHandler::getLabel).map(String::length).max(Integer::compare).get().toString() + "s : ";
|
||||
for (CommandHandler cmd : cmdList) {
|
||||
final String label = padCmdLabel.formatted(cmd.getLabel());
|
||||
@ -65,7 +65,7 @@ public final class Tools {
|
||||
final Int2IntMap h = handbookNames[section];
|
||||
final String s = "\n\n// " + handbookSections[section] + "\n";
|
||||
handbookBuilders.forEach(b -> b.append(s));
|
||||
final String padId = "%" + Integer.toString(Integer.toString(h.keySet().intStream().max().getAsInt()).length()) + "s : ";
|
||||
final String padId = "%" + Integer.toString(h.keySet().intStream().max().getAsInt()).length() + "s : ";
|
||||
h.keySet().intStream().sorted().forEach(id -> {
|
||||
final String sId = padId.formatted(id);
|
||||
final TextStrings t = textMaps.get(h.get(id));
|
||||
@ -76,7 +76,7 @@ public final class Tools {
|
||||
// Scenes - no translations
|
||||
handbookBuilders.forEach(b -> b.append("\n\n// Scenes\n"));
|
||||
final var sceneDataMap = GameData.getSceneDataMap();
|
||||
final String padSceneId = "%" + Integer.toString(Integer.toString(sceneDataMap.keySet().intStream().max().getAsInt()).length()) + "d : ";
|
||||
final String padSceneId = "%" + Integer.toString(sceneDataMap.keySet().intStream().max().getAsInt()).length() + "d : ";
|
||||
sceneDataMap.keySet().intStream().sorted().forEach(id -> {
|
||||
final String sId = padSceneId.formatted(id);
|
||||
final String data = sceneDataMap.get(id).getScriptData();
|
||||
@ -85,7 +85,7 @@ public final class Tools {
|
||||
// Quests
|
||||
handbookBuilders.forEach(b -> b.append("\n\n// Quests\n"));
|
||||
final var questDataMap = GameData.getQuestDataMap();
|
||||
final String padQuestId = "%" + Integer.toString(Integer.toString(questDataMap.keySet().intStream().max().getAsInt()).length()) + "d : ";
|
||||
final String padQuestId = "%" + Integer.toString(questDataMap.keySet().intStream().max().getAsInt()).length() + "d : ";
|
||||
questDataMap.keySet().intStream().sorted().forEach(id -> {
|
||||
final String sId = padQuestId.formatted(id);
|
||||
final QuestData data = questDataMap.get(id);
|
||||
@ -206,7 +206,7 @@ public final class Tools {
|
||||
try (PrintWriter writer = new PrintWriter(new OutputStreamWriter(new FileOutputStream(location), StandardCharsets.UTF_8), false)) {
|
||||
// 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.
|
||||
// The end-user can still modify the `gacha/mappings.js` directly to enable multilingual for the gacha record system.
|
||||
writer.println(sb);
|
||||
Grasscutter.getLogger().info("Mappings generated to " + location + " !");
|
||||
}
|
||||
@ -220,6 +220,7 @@ public final class Tools {
|
||||
} return availableLangList;
|
||||
}
|
||||
|
||||
@Deprecated(forRemoval = true, since = "1.2.3")
|
||||
public static String getLanguageOption() {
|
||||
List<String> availableLangList = getAvailableLanguage();
|
||||
|
||||
@ -248,17 +249,13 @@ public final class Tools {
|
||||
stagedMessage.append(groupedLangList).append("\n");
|
||||
}
|
||||
|
||||
stagedMessage.append("\nYour choice:[EN] ");
|
||||
stagedMessage.append("\nYour choice: [EN] ");
|
||||
|
||||
input = Grasscutter.getConsole().readLine(stagedMessage.toString());
|
||||
if (availableLangList.contains(input.toLowerCase())) {
|
||||
return input.toUpperCase();
|
||||
}
|
||||
Grasscutter.getLogger().info("Invalid option. Will use EN(English) as fallback");
|
||||
|
||||
return "EN";
|
||||
Grasscutter.getLogger().info("Invalid option. Will use EN (English) as fallback."); return "EN";
|
||||
}
|
||||
}
|
||||
|
||||
final class ToolsWithLanguageOption {
|
||||
}
|
||||
|
99
src/main/java/emu/grasscutter/utils/StartupArguments.java
Normal file
99
src/main/java/emu/grasscutter/utils/StartupArguments.java
Normal file
@ -0,0 +1,99 @@
|
||||
package emu.grasscutter.utils;
|
||||
|
||||
import ch.qos.logback.classic.Level;
|
||||
import ch.qos.logback.classic.Logger;
|
||||
import emu.grasscutter.BuildConfig;
|
||||
import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.net.packet.PacketOpcodesUtils;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* A parser for start-up arguments.
|
||||
*/
|
||||
public final class StartupArguments {
|
||||
private StartupArguments() {
|
||||
// This class is not meant to be instantiated.
|
||||
}
|
||||
|
||||
/* A map of parameter -> argument handler. */
|
||||
private static final Map<String, Function<String, Boolean>> argumentHandlers = Map.of(
|
||||
"-dumppacketids", parameter -> {
|
||||
PacketOpcodesUtils.dumpPacketIds(); return true;
|
||||
},
|
||||
"-version", StartupArguments::printVersion,
|
||||
"-debug", StartupArguments::enableDebug,
|
||||
"-lang", parameter -> {
|
||||
Grasscutter.setPreferredLanguage(parameter); return false;
|
||||
},
|
||||
|
||||
// Aliases.
|
||||
"-v", StartupArguments::printVersion,
|
||||
"-debugall", parameter -> {
|
||||
StartupArguments.enableDebug("all"); return false;
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* Parses the provided start-up arguments.
|
||||
* @param args The application start-up arguments.
|
||||
* @return If the application should exit.
|
||||
*/
|
||||
public static boolean parse(String[] args) {
|
||||
boolean exitEarly = false;
|
||||
|
||||
// Parse the arguments.
|
||||
for(var input : args) {
|
||||
var containsParameter = input.contains("=");
|
||||
|
||||
var argument = containsParameter ? input.split("=")[0] : input;
|
||||
var handler = argumentHandlers.get(argument.toLowerCase());
|
||||
|
||||
if (handler != null) {
|
||||
exitEarly |= handler.apply(containsParameter ? input.split("=")[1] : null);
|
||||
}
|
||||
}
|
||||
|
||||
return exitEarly;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints the server version.
|
||||
* @param parameter Additional parameters.
|
||||
* @return True to exit early.
|
||||
*/
|
||||
private static boolean printVersion(String parameter) {
|
||||
System.out.println("Grasscutter version: " + BuildConfig.VERSION + "-" + BuildConfig.GIT_HASH); return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables debug logging.
|
||||
* @param parameter Additional parameters.
|
||||
* @return False to continue execution.
|
||||
*/
|
||||
private static boolean enableDebug(String parameter) {
|
||||
// Get the level by parameter.
|
||||
var loggerLevel = parameter != null && parameter.equals("all")
|
||||
? Level.DEBUG : Level.INFO;
|
||||
|
||||
// Set the logger to debug.
|
||||
Grasscutter.getLogger().setLevel(Level.DEBUG);
|
||||
Grasscutter.getLogger().debug("The logger is now running in debug mode.");
|
||||
|
||||
// Change loggers to debug.
|
||||
((Logger) LoggerFactory.getLogger("express"))
|
||||
.setLevel(loggerLevel);
|
||||
((Logger) LoggerFactory.getLogger("org.quartz"))
|
||||
.setLevel(loggerLevel);
|
||||
((Logger) LoggerFactory.getLogger("org.reflections"))
|
||||
.setLevel(loggerLevel);
|
||||
((Logger) LoggerFactory.getLogger("org.eclipse.jetty"))
|
||||
.setLevel(loggerLevel);
|
||||
((Logger) LoggerFactory.getLogger("org.mongodb.driver"))
|
||||
.setLevel(loggerLevel);
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user