mirror of
https://github.com/Melledy/Nebula.git
synced 2025-12-18 15:24:45 +01:00
Initial Commit
This commit is contained in:
17
src/main/java/emu/nebula/command/Command.java
Normal file
17
src/main/java/emu/nebula/command/Command.java
Normal file
@@ -0,0 +1,17 @@
|
||||
package emu.nebula.command;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Command {
|
||||
public String label() default "";
|
||||
|
||||
public String[] aliases() default "";
|
||||
|
||||
public String desc() default "";
|
||||
|
||||
public String permission() default "";
|
||||
|
||||
public boolean requireTarget() default false;
|
||||
}
|
||||
130
src/main/java/emu/nebula/command/CommandArgs.java
Normal file
130
src/main/java/emu/nebula/command/CommandArgs.java
Normal file
@@ -0,0 +1,130 @@
|
||||
package emu.nebula.command;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import emu.nebula.Nebula;
|
||||
import emu.nebula.game.player.Player;
|
||||
import emu.nebula.util.Utils;
|
||||
import it.unimi.dsi.fastutil.ints.Int2IntMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectSet;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
public class CommandArgs {
|
||||
private String raw;
|
||||
private List<String> list;
|
||||
private Player sender;
|
||||
private Player target;
|
||||
|
||||
private int targetUid;
|
||||
private int amount;
|
||||
private int level = -1;
|
||||
private int rank = -1;
|
||||
private int promotion = -1;
|
||||
private int stage = -1;
|
||||
|
||||
private Int2IntMap map;
|
||||
private ObjectSet<String> flags;
|
||||
|
||||
public CommandArgs(Player sender, List<String> args) {
|
||||
this.sender = sender;
|
||||
this.raw = String.join(" ", args);
|
||||
this.list = args;
|
||||
|
||||
// Parse args. Maybe regex is better.
|
||||
var it = this.list.iterator();
|
||||
while (it.hasNext()) {
|
||||
// Lower case first
|
||||
String arg = it.next().toLowerCase();
|
||||
|
||||
try {
|
||||
if (arg.length() >= 2 && !Character.isDigit(arg.charAt(0)) && Character.isDigit(arg.charAt(arg.length() - 1))) {
|
||||
if (arg.startsWith("@")) { // Target UID
|
||||
this.targetUid = Utils.parseSafeInt(arg.substring(1));
|
||||
it.remove();
|
||||
} else if (arg.startsWith("x")) { // Amount
|
||||
this.amount = Utils.parseSafeInt(arg.substring(1));
|
||||
it.remove();
|
||||
} else if (arg.startsWith("lv")) { // Level
|
||||
this.level = Utils.parseSafeInt(arg.substring(2));
|
||||
it.remove();
|
||||
} else if (arg.startsWith("r")) { // Rank
|
||||
this.rank = Utils.parseSafeInt(arg.substring(1));
|
||||
it.remove();
|
||||
} else if (arg.startsWith("e")) { // Eidolons
|
||||
this.rank = Utils.parseSafeInt(arg.substring(1));
|
||||
it.remove();
|
||||
} else if (arg.startsWith("p")) { // Promotion
|
||||
this.promotion = Utils.parseSafeInt(arg.substring(1));
|
||||
it.remove();
|
||||
} else if (arg.startsWith("s")) { // Stage or Superimposition
|
||||
this.stage = Utils.parseSafeInt(arg.substring(1));
|
||||
it.remove();
|
||||
}
|
||||
} else if (arg.startsWith("-")) { // Flag
|
||||
if (this.flags == null) this.flags = new ObjectOpenHashSet<>();
|
||||
this.flags.add(arg);
|
||||
it.remove();
|
||||
} else if (arg.contains(":") || arg.contains(",")) {
|
||||
String[] split = arg.split("[:,]");
|
||||
if (split.length >= 2) {
|
||||
int key = Integer.parseInt(split[0]);
|
||||
int value = Integer.parseInt(split[1]);
|
||||
|
||||
if (this.map == null) this.map = new Int2IntOpenHashMap();
|
||||
this.map.put(key, value);
|
||||
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Get target player
|
||||
if (targetUid != 0) {
|
||||
if (Nebula.getGameContext() != null) {
|
||||
target = Nebula.getGameContext().getPlayerModule().getCachedPlayerByUid(targetUid);
|
||||
}
|
||||
} else {
|
||||
target = sender;
|
||||
}
|
||||
|
||||
if (target != null) {
|
||||
this.targetUid = target.getUid();
|
||||
}
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return this.list.size();
|
||||
}
|
||||
|
||||
public String get(int index) {
|
||||
if (index < 0 || index >= list.size()) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return this.list.get(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a message to the command sender
|
||||
* @param message
|
||||
*/
|
||||
public void sendMessage(String message) {
|
||||
if (sender != null) {
|
||||
sender.sendMessage(message);
|
||||
} else {
|
||||
Nebula.getLogger().info(message);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasFlag(String flag) {
|
||||
if (this.flags == null) return false;
|
||||
return this.flags.contains(flag);
|
||||
}
|
||||
|
||||
}
|
||||
15
src/main/java/emu/nebula/command/CommandHandler.java
Normal file
15
src/main/java/emu/nebula/command/CommandHandler.java
Normal file
@@ -0,0 +1,15 @@
|
||||
package emu.nebula.command;
|
||||
|
||||
public interface CommandHandler {
|
||||
|
||||
public default Command getData() {
|
||||
return this.getClass().getAnnotation(Command.class);
|
||||
}
|
||||
|
||||
public default String getLabel() {
|
||||
return getData().label();
|
||||
}
|
||||
|
||||
public void execute(CommandArgs args);
|
||||
|
||||
}
|
||||
168
src/main/java/emu/nebula/command/CommandManager.java
Normal file
168
src/main/java/emu/nebula/command/CommandManager.java
Normal file
@@ -0,0 +1,168 @@
|
||||
package emu.nebula.command;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.reflections.Reflections;
|
||||
|
||||
import emu.nebula.Nebula;
|
||||
import emu.nebula.game.player.Player;
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
public class CommandManager {
|
||||
private Object2ObjectMap<String, CommandHandler> labels;
|
||||
private Object2ObjectMap<String, CommandHandler> commands;
|
||||
|
||||
public CommandManager() {
|
||||
this.labels = new Object2ObjectOpenHashMap<>();
|
||||
this.commands = new Object2ObjectOpenHashMap<>();
|
||||
|
||||
// Scan for commands
|
||||
var commandClasses = new Reflections(CommandManager.class.getPackageName()).getTypesAnnotatedWith(Command.class);
|
||||
|
||||
for (var cls : commandClasses) {
|
||||
if (!CommandHandler.class.isAssignableFrom(cls)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
CommandHandler handler = (CommandHandler) cls.getDeclaredConstructor().newInstance();
|
||||
this.registerCommand(handler);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a command that players and server console users can use. Command handlers must have the proper command annotation attached to them.
|
||||
*/
|
||||
public CommandManager registerCommand(CommandHandler handler) {
|
||||
Command command = handler.getClass().getAnnotation(Command.class);
|
||||
if (command == null) return this;
|
||||
|
||||
this.getLabels().put(command.label(), handler);
|
||||
this.getCommands().put(command.label(), handler);
|
||||
|
||||
for (String alias : command.aliases()) {
|
||||
this.getCommands().put(alias, handler);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a command from use.
|
||||
* @param label The command name
|
||||
* @return
|
||||
*/
|
||||
public CommandManager unregisterCommand(String label) {
|
||||
CommandHandler handler = this.getLabels().get(label);
|
||||
if (handler == null) return this;
|
||||
|
||||
Command command = handler.getClass().getAnnotation(Command.class);
|
||||
if (command == null) {
|
||||
return this;
|
||||
}
|
||||
|
||||
this.getLabels().remove(command.label());
|
||||
this.getCommands().remove(command.label());
|
||||
|
||||
for (String alias : command.aliases()) {
|
||||
this.getCommands().remove(alias);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the sender has permission to use this command. Will always return true if the sender is the server console.
|
||||
* @param sender The sender of the command.
|
||||
* @param command
|
||||
* @return true if the sender has permission to use this command
|
||||
*/
|
||||
public boolean checkPermission(Player sender, Command command) {
|
||||
if (sender == null || command.permission().isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return sender.getAccount().hasPermission(command.permission());
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the sender has permission to use this command on other players. Will always return true if the sender is the server console.
|
||||
* @param sender The sender of the command.
|
||||
* @param command
|
||||
* @return true if the sender has permission to use this command
|
||||
*/
|
||||
private boolean checkTargetPermission(Player sender, Command command) {
|
||||
if (sender == null || command.permission().isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return sender.getAccount().hasPermission("target." + command.permission());
|
||||
}
|
||||
|
||||
public void invoke(Player sender, String message) {
|
||||
// Parse message into arguments
|
||||
List<String> args = Arrays.stream(message.split(" ")).collect(Collectors.toCollection(ArrayList::new));
|
||||
|
||||
// Get command label
|
||||
String label = args.remove(0).toLowerCase();
|
||||
|
||||
// Filter out command prefixes
|
||||
if (label.startsWith("/") || label.startsWith("!")) {
|
||||
label = label.substring(1);
|
||||
}
|
||||
|
||||
// Get command handler
|
||||
CommandHandler handler = this.commands.get(label);
|
||||
|
||||
// Execute command
|
||||
if (handler != null) {
|
||||
// Get command annotation data
|
||||
Command command = handler.getData();
|
||||
|
||||
// Check if sender has permission to run the command.
|
||||
if (sender != null && !this.checkPermission(sender, command)) {
|
||||
// We have a double null check here just in case
|
||||
sender.sendMessage("You do not have permission to use this command.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Build command arguments
|
||||
CommandArgs cmdArgs = new CommandArgs(sender, args);
|
||||
|
||||
// Check targeted permission
|
||||
if (sender != cmdArgs.getTarget() && !this.checkTargetPermission(sender, command)) {
|
||||
cmdArgs.sendMessage("You do not have permission to use this command on another player.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Make sure our command has a target
|
||||
if (command.requireTarget() && cmdArgs.getTarget() == null) {
|
||||
cmdArgs.sendMessage("Error: Targeted player not found or offline");
|
||||
return;
|
||||
}
|
||||
|
||||
// Log
|
||||
if (sender != null && Nebula.getConfig().getLogOptions().commands) {
|
||||
Nebula.getLogger().info("[UID: " + sender.getUid() + "] " + sender.getName() + " used command: " + message);
|
||||
}
|
||||
|
||||
// Run command
|
||||
handler.execute(cmdArgs);
|
||||
} else {
|
||||
if (sender != null) {
|
||||
sender.sendMessage("Invalid Command!");
|
||||
} else {
|
||||
Nebula.getLogger().info("Invalid Command!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package emu.nebula.command.commands;
|
||||
|
||||
import emu.nebula.command.Command;
|
||||
import emu.nebula.command.CommandArgs;
|
||||
import emu.nebula.command.CommandHandler;
|
||||
import emu.nebula.game.account.AccountHelper;
|
||||
import emu.nebula.util.Utils;
|
||||
|
||||
@Command(label = "account", permission = "admin.account", desc = "/account {create | delete} [username] (reserved player uid). Creates or deletes an account.")
|
||||
public class AccountCommand implements CommandHandler {
|
||||
|
||||
@Override
|
||||
public void execute(CommandArgs args) {
|
||||
if (args.size() < 2) {
|
||||
args.sendMessage("Invalid amount of args");
|
||||
return;
|
||||
}
|
||||
|
||||
String command = args.get(0).toLowerCase();
|
||||
String username = args.get(1);
|
||||
|
||||
switch (command) {
|
||||
case "create" -> {
|
||||
// Reserved player uid
|
||||
int reservedUid = 0;
|
||||
|
||||
if (args.size() >= 3) {
|
||||
reservedUid = Utils.parseSafeInt(args.get(2));
|
||||
}
|
||||
|
||||
if (AccountHelper.createAccount(username, null, reservedUid) != null) {
|
||||
args.sendMessage("Account created");
|
||||
} else {
|
||||
args.sendMessage("Account already exists");
|
||||
}
|
||||
}
|
||||
case "delete" -> {
|
||||
if (AccountHelper.deleteAccount(username)) {
|
||||
args.sendMessage("Account deleted");
|
||||
} else {
|
||||
args.sendMessage("Account doesnt exist");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
45
src/main/java/emu/nebula/command/commands/GiveCommand.java
Normal file
45
src/main/java/emu/nebula/command/commands/GiveCommand.java
Normal file
@@ -0,0 +1,45 @@
|
||||
package emu.nebula.command.commands;
|
||||
|
||||
import emu.nebula.util.Utils;
|
||||
import emu.nebula.data.GameData;
|
||||
import emu.nebula.game.mail.GameMail;
|
||||
import emu.nebula.command.Command;
|
||||
import emu.nebula.command.CommandArgs;
|
||||
import emu.nebula.command.CommandHandler;
|
||||
|
||||
@Command(
|
||||
label = "give",
|
||||
aliases = {"g", "item"},
|
||||
permission = "player.give",
|
||||
requireTarget = true,
|
||||
desc = "/give [item id] x(amount). Gives the targeted player an item."
|
||||
)
|
||||
public class GiveCommand implements CommandHandler {
|
||||
|
||||
@Override
|
||||
public void execute(CommandArgs args) {
|
||||
// Setup mail
|
||||
var mail = new GameMail("System", "Give Command Result", "");
|
||||
|
||||
// Get amount to give
|
||||
int amount = Math.max(args.getAmount(), 1);
|
||||
|
||||
// Parse items
|
||||
for (String arg : args.getList()) {
|
||||
// Parse item id
|
||||
int itemId = Utils.parseSafeInt(arg);
|
||||
|
||||
var itemData = GameData.getItemDataTable().get(itemId);
|
||||
if (itemData == null) {
|
||||
args.sendMessage("Item \"" + arg + "\" does not exist!");
|
||||
continue;
|
||||
}
|
||||
|
||||
// Add
|
||||
mail.addAttachment(itemId, amount);
|
||||
}
|
||||
|
||||
// Add mail
|
||||
args.getTarget().getMailbox().sendMail(mail);
|
||||
}
|
||||
}
|
||||
20
src/main/java/emu/nebula/command/commands/MailCommand.java
Normal file
20
src/main/java/emu/nebula/command/commands/MailCommand.java
Normal file
@@ -0,0 +1,20 @@
|
||||
package emu.nebula.command.commands;
|
||||
|
||||
import emu.nebula.command.Command;
|
||||
import emu.nebula.command.CommandArgs;
|
||||
import emu.nebula.command.CommandHandler;
|
||||
import emu.nebula.game.mail.GameMail;
|
||||
|
||||
@Command(label = "mail", aliases = {"m"}, permission = "player.mail", requireTarget = true, desc = "/mail [content]. Sends the targeted player a system mail.")
|
||||
public class MailCommand implements CommandHandler {
|
||||
|
||||
@Override
|
||||
public void execute(CommandArgs args) {
|
||||
// Setup mail
|
||||
var mail = new GameMail("System", "Test", "This is a test mail");
|
||||
|
||||
// Add mail
|
||||
args.getTarget().getMailbox().sendMail(mail);
|
||||
}
|
||||
|
||||
}
|
||||
17
src/main/java/emu/nebula/command/commands/ReloadCommand.java
Normal file
17
src/main/java/emu/nebula/command/commands/ReloadCommand.java
Normal file
@@ -0,0 +1,17 @@
|
||||
package emu.nebula.command.commands;
|
||||
|
||||
import emu.nebula.Nebula;
|
||||
import emu.nebula.command.Command;
|
||||
import emu.nebula.command.CommandArgs;
|
||||
import emu.nebula.command.CommandHandler;
|
||||
|
||||
@Command(label = "reload", permission = "admin.reload", desc = "/reload. Reloads the server config.")
|
||||
public class ReloadCommand implements CommandHandler {
|
||||
|
||||
@Override
|
||||
public void execute(CommandArgs args) {
|
||||
Nebula.loadConfig();
|
||||
args.sendMessage("Reloaded the server config");
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user