Implement new command system

This commit is contained in:
KingRainbow44
2022-04-18 18:24:08 -04:00
parent b2466693ae
commit ce51e9d6c3
8 changed files with 453 additions and 20 deletions

View File

@@ -5,9 +5,11 @@ import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public @interface Command {
String label() default "";
String[] aliases() default "";
int gmLevel() default 1;
String helpText() default "";
String usage() default "";
}

View File

@@ -0,0 +1,28 @@
package emu.grasscutter.commands;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.game.GenshinPlayer;
import java.util.List;
public interface CommandHandler {
/* Invoked on player execution. */
void execute(GenshinPlayer player, List<String> args);
/* Invoked on server execution. */
void execute(List<String> args);
/*
* Utilities.
*/
/**
* Send a message to the target.
* @param player The player to send the message to, or null for the server console.
* @param message The message to send.
*/
static void sendMessage(GenshinPlayer player, String message) {
if(player == null) {
Grasscutter.getLogger().info(message);
} else player.dropMessage(message);
}
}

View File

@@ -0,0 +1,87 @@
package emu.grasscutter.commands;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.game.GenshinPlayer;
import org.reflections.Reflections;
import java.util.*;
@SuppressWarnings("UnusedReturnValue")
public final class CommandMap {
public static CommandMap getInstance() {
return Grasscutter.getGameServer().getCommandMap();
}
private final Map<String, CommandHandler> commands = new HashMap<>();
/**
* Register a command handler.
* @param label The command label.
* @param command The command handler.
* @return Instance chaining.
*/
public CommandMap registerCommand(String label, CommandHandler command) {
this.commands.put(label, command); return this;
}
/**
* Removes a registered command handler.
* @param label The command label.
* @return Instance chaining.
*/
public CommandMap unregisterCommand(String label) {
this.commands.remove(label); return this;
}
/**
* Invoke a command handler with the given arguments.
* @param player The player invoking the command or null for the server console.
* @param rawMessage The messaged used to invoke the command.
*/
public void invoke(GenshinPlayer player, String rawMessage) {
// Remove prefix if present.
if(!Character.isLetter(rawMessage.charAt(0)))
rawMessage = rawMessage.substring(1);
// Parse message.
String[] split = rawMessage.split(" ");
List<String> args = Arrays.asList(split);
String label = args.remove(0);
// Get command handler.
CommandHandler handler = this.commands.get(label);
if(handler == null) {
CommandHandler.sendMessage(player, "Unknown command: " + label); return;
}
// Invoke execute method for handler.
if(player == null)
handler.execute(args);
else handler.execute(player, args);
}
public CommandMap() {
this(false);
}
public CommandMap(boolean scan) {
if(scan) this.scan();
}
/**
* Scans for all classes annotated with {@link Command} and registers them.
*/
private void scan() {
Reflections reflector = Grasscutter.reflector;
Set<?> classes = reflector.getTypesAnnotatedWith(Command.class);
classes.forEach(annotated -> {
try {
Class<?> cls = annotated.getClass();
Command cmdData = cls.getAnnotation(Command.class);
Object object = cls.getDeclaredConstructors()[0].newInstance();
if (object instanceof CommandHandler)
this.registerCommand(cmdData.label(), (CommandHandler) object);
} catch (Exception ignored) { }
});
}
}

View File

@@ -1,171 +0,0 @@
package emu.grasscutter.commands;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.stream.Collectors;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.data.GenshinData;
import emu.grasscutter.data.def.ItemData;
import emu.grasscutter.database.DatabaseHelper;
import emu.grasscutter.game.GenshinPlayer;
import emu.grasscutter.game.inventory.GenshinItem;
import emu.grasscutter.utils.Crypto;
import emu.grasscutter.utils.Utils;
public class ServerCommands {
private static HashMap<String, ServerCommand> list = new HashMap<>();
static {
try {
// Look for classes
for (Class<?> cls : ServerCommands.class.getDeclaredClasses()) {
// Get non abstract classes
if (!Modifier.isAbstract(cls.getModifiers())) {
String commandName = cls.getSimpleName().toLowerCase();
list.put(commandName, (ServerCommand) cls.newInstance());
}
}
} catch (Exception e) {
}
}
public static void handle(String msg) {
String[] split = msg.split(" ");
// End if invalid
if (split.length == 0) {
return;
}
//
String first = split[0].toLowerCase();
ServerCommand c = ServerCommands.list.get(first);
if (c != null) {
// Execute
int len = Math.min(first.length() + 1, msg.length());
c.execute(msg.substring(len));
}
}
public static abstract class ServerCommand {
public abstract void execute(String raw);
}
// ================ Commands ================
public static class Reload extends ServerCommand {
@Override
public void execute(String raw) {
Grasscutter.getLogger().info("Reloading config.");
Grasscutter.loadConfig();
Grasscutter.getDispatchServer().loadQueries();
Grasscutter.getLogger().info("Reload complete.");
}
}
public static class sendMsg extends ServerCommand {
@Override
public void execute(String raw) {
List<String> split = Arrays.asList(raw.split(" "));
if (split.size() < 2) {
Grasscutter.getLogger().error("Invalid amount of args");
return;
}
String playerID = split.get(0);
String message = split.stream().skip(1).collect(Collectors.joining(" "));
emu.grasscutter.game.Account account = DatabaseHelper.getAccountByPlayerId(Integer.parseInt(playerID));
if (account != null) {
GenshinPlayer player = Grasscutter.getGameServer().getPlayerById(Integer.parseInt(playerID));
if(player != null) {
player.dropMessage(message);
Grasscutter.getLogger().info(String.format("Successfully sent message to %s: %s", playerID, message));
} else {
Grasscutter.getLogger().error("Player not online");
}
} else {
Grasscutter.getLogger().error(String.format("Player %s does not exist", playerID));
}
}
}
public static class Account extends ServerCommand {
@Override
public void execute(String raw) {
String[] split = raw.split(" ");
if (split.length < 2) {
Grasscutter.getLogger().error("Invalid amount of args");
return;
}
String command = split[0].toLowerCase();
String username = split[1];
switch (command) {
case "create":
if (split.length < 2) {
Grasscutter.getLogger().error("Invalid amount of args");
return;
}
int reservedId = 0;
try {
reservedId = Integer.parseInt(split[2]);
} catch (Exception e) {
reservedId = 0;
}
emu.grasscutter.game.Account account = DatabaseHelper.createAccountWithId(username, reservedId);
if (account != null) {
Grasscutter.getLogger().info("Account created" + (reservedId > 0 ? " with an id of " + reservedId : ""));
} else {
Grasscutter.getLogger().error("Account already exists");
}
break;
case "delete":
boolean success = DatabaseHelper.deleteAccount(username);
if (success) {
Grasscutter.getLogger().info("Account deleted");
}
break;
/*
case "setpw":
case "setpass":
case "setpassword":
if (split.length < 3) {
Grasscutter.getLogger().error("Invalid amount of args");
return;
}
account = DatabaseHelper.getAccountByName(username);
if (account == null) {
Grasscutter.getLogger().error("No account found!");
return;
}
token = split[2];
token = PasswordHelper.hashPassword(token);
account.setPassword(token);
DatabaseHelper.saveAccount(account);
Grasscutter.getLogger().info("Password set");
break;
*/
}
}
}
}