diff --git a/src/main/java/emu/lunarcore/Config.java b/src/main/java/emu/lunarcore/Config.java index b421d3d..374818a 100644 --- a/src/main/java/emu/lunarcore/Config.java +++ b/src/main/java/emu/lunarcore/Config.java @@ -1,5 +1,8 @@ package emu.lunarcore; +import java.util.HashSet; +import java.util.Set; + import lombok.Getter; @Getter @@ -15,6 +18,7 @@ public class Config { public ServerConfig httpServer = new ServerConfig("127.0.0.1", 443); public GameServerConfig gameServer = new GameServerConfig("127.0.0.1", 23301); + public ServerOptions serverOptions = new ServerOptions(); public DownloadData downloadData = new DownloadData(); public String resourceDir = "./resources"; @@ -70,6 +74,12 @@ public class Config { } } + @Getter + public static class ServerOptions { + public int entitySceneLimit = 2000; + public Set defaultPermissions = Set.of("*"); + } + @Getter public static class DownloadData { public String assetBundleUrl = null; diff --git a/src/main/java/emu/lunarcore/command/Command.java b/src/main/java/emu/lunarcore/command/Command.java index 18a18d0..5afb734 100644 --- a/src/main/java/emu/lunarcore/command/Command.java +++ b/src/main/java/emu/lunarcore/command/Command.java @@ -10,4 +10,6 @@ public @interface Command { public String[] aliases() default ""; public String desc() default ""; + + public String permission() default ""; } diff --git a/src/main/java/emu/lunarcore/command/CommandArgs.java b/src/main/java/emu/lunarcore/command/CommandArgs.java index 552f1e5..7d6a7d0 100644 --- a/src/main/java/emu/lunarcore/command/CommandArgs.java +++ b/src/main/java/emu/lunarcore/command/CommandArgs.java @@ -14,7 +14,7 @@ public class CommandArgs { private int targetUid; private int level; - private int count; + private int amount; private int rank; private int promotion; @@ -35,7 +35,7 @@ public class CommandArgs { this.targetUid = Utils.parseSafeInt(arg.substring(1)); it.remove(); } else if (arg.startsWith("x")) { - this.count = Utils.parseSafeInt(arg.substring(1)); + this.amount = Utils.parseSafeInt(arg.substring(1)); it.remove(); } else if (arg.startsWith("lv")) { this.level = Utils.parseSafeInt(arg.substring(2)); diff --git a/src/main/java/emu/lunarcore/command/CommandManager.java b/src/main/java/emu/lunarcore/command/CommandManager.java index 8e38e88..8ab0020 100644 --- a/src/main/java/emu/lunarcore/command/CommandManager.java +++ b/src/main/java/emu/lunarcore/command/CommandManager.java @@ -77,6 +77,22 @@ public class CommandManager { return this; } + private boolean checkPermission(Player sender, Command command) { + if (sender == null || command.permission().isEmpty()) { + return true; + } + + return sender.getAccount().hasPermission(command.permission()); + } + + 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) { List args = Arrays.stream(message.split(" ")).collect(Collectors.toCollection(ArrayList::new)); @@ -89,8 +105,24 @@ public class CommandManager { // Get handler CommandHandler handler = this.commands.get(label); + + // Execute if (handler != null) { - handler.execute(sender, new CommandArgs(sender, args)); + // Command annotation data + Command command = handler.getClass().getAnnotation(Command.class); + // Check permission + if (this.checkPermission(sender, command)) { + // Check targetted permission + CommandArgs cmdArgs = new CommandArgs(sender, args); + if (sender != cmdArgs.getTarget() && !this.checkTargetPermission(sender, command)) { + handler.sendMessage(sender, "You do not have permission to use this command on another player"); + return; + } + // Run command + handler.execute(sender, cmdArgs); + } else { + handler.sendMessage(sender, "You do not have permission to use this command"); + } } else { if (sender != null) { sender.sendMessage("Inavlid Command!"); diff --git a/src/main/java/emu/lunarcore/command/commands/AccountCommand.java b/src/main/java/emu/lunarcore/command/commands/AccountCommand.java index d1c4244..4011eaa 100644 --- a/src/main/java/emu/lunarcore/command/commands/AccountCommand.java +++ b/src/main/java/emu/lunarcore/command/commands/AccountCommand.java @@ -7,7 +7,7 @@ import emu.lunarcore.game.account.AccountHelper; import emu.lunarcore.game.player.Player; import emu.lunarcore.util.Utils; -@Command(label = "account") +@Command(label = "account", permission = "server.account") public class AccountCommand implements CommandHandler { @Override diff --git a/src/main/java/emu/lunarcore/command/commands/ClearCommand.java b/src/main/java/emu/lunarcore/command/commands/ClearCommand.java index 43d3081..b6dbe80 100644 --- a/src/main/java/emu/lunarcore/command/commands/ClearCommand.java +++ b/src/main/java/emu/lunarcore/command/commands/ClearCommand.java @@ -10,7 +10,7 @@ import emu.lunarcore.game.inventory.GameItem; import emu.lunarcore.game.inventory.ItemMainType; import emu.lunarcore.game.player.Player; -@Command(label = "clear") +@Command(label = "clear", permission = "player.clear") public class ClearCommand implements CommandHandler { @Override diff --git a/src/main/java/emu/lunarcore/command/commands/GenderCommand.java b/src/main/java/emu/lunarcore/command/commands/GenderCommand.java index e9b734a..22c3b23 100644 --- a/src/main/java/emu/lunarcore/command/commands/GenderCommand.java +++ b/src/main/java/emu/lunarcore/command/commands/GenderCommand.java @@ -7,7 +7,7 @@ import emu.lunarcore.game.player.Player; import emu.lunarcore.game.player.PlayerGender; import emu.lunarcore.server.packet.send.PacketGetHeroBasicTypeInfoScRsp; -@Command(label = "gender") +@Command(label = "gender", permission = "player.gender") public class GenderCommand implements CommandHandler { @Override diff --git a/src/main/java/emu/lunarcore/command/commands/GiveAllCommand.java b/src/main/java/emu/lunarcore/command/commands/GiveAllCommand.java index 1ed6b26..682b4f1 100644 --- a/src/main/java/emu/lunarcore/command/commands/GiveAllCommand.java +++ b/src/main/java/emu/lunarcore/command/commands/GiveAllCommand.java @@ -13,7 +13,7 @@ import emu.lunarcore.game.inventory.ItemMainType; import emu.lunarcore.game.inventory.ItemSubType; import emu.lunarcore.game.player.Player; -@Command(label = "giveall", aliases = {"ga"}) +@Command(label = "giveall", aliases = {"ga"}, permission = "player.give") public class GiveAllCommand implements CommandHandler { @Override diff --git a/src/main/java/emu/lunarcore/command/commands/GiveCommand.java b/src/main/java/emu/lunarcore/command/commands/GiveCommand.java index d681dcc..d1d1dc2 100644 --- a/src/main/java/emu/lunarcore/command/commands/GiveCommand.java +++ b/src/main/java/emu/lunarcore/command/commands/GiveCommand.java @@ -12,7 +12,7 @@ import emu.lunarcore.game.inventory.GameItem; import emu.lunarcore.game.player.Player; import emu.lunarcore.util.Utils; -@Command(label = "give", aliases = {"g"}) +@Command(label = "give", aliases = {"g"}, permission = "player.give") public class GiveCommand implements CommandHandler { @Override @@ -24,7 +24,7 @@ public class GiveCommand implements CommandHandler { } int itemId = Utils.parseSafeInt(args.get(0)); - int amount = Math.max(args.getCount(), 1); + int amount = Math.max(args.getAmount(), 1); ItemExcel itemData = GameData.getItemExcelMap().get(itemId); diff --git a/src/main/java/emu/lunarcore/command/commands/PermissionCommand.java b/src/main/java/emu/lunarcore/command/commands/PermissionCommand.java new file mode 100644 index 0000000..de53b6e --- /dev/null +++ b/src/main/java/emu/lunarcore/command/commands/PermissionCommand.java @@ -0,0 +1,50 @@ +package emu.lunarcore.command.commands; + +import emu.lunarcore.command.Command; +import emu.lunarcore.command.CommandArgs; +import emu.lunarcore.command.CommandHandler; +import emu.lunarcore.game.player.Player; + +@Command(label = "permission", aliases = {"perm"}, permission = "server.permission") +public class PermissionCommand implements CommandHandler { + + @Override + public void execute(Player sender, CommandArgs args) { + // Check target + if (args.getTarget() == null) { + this.sendMessage(sender, "Error: Targeted player not found or offline"); + return; + } else if (args.size() < 2) { + this.sendMessage(sender, "Error: Not enough arguments"); + return; + } + + String type = args.get(0).toLowerCase(); + String permission = args.get(1).toLowerCase(); + + switch (type) { + case "add" -> { + // Add permission + args.getTarget().getAccount().addPermission(permission); + // Send message + this.sendMessage(sender, "Added permission for " + args.getTarget().getName()); + } + case "remove" -> { + // Remove permission + args.getTarget().getAccount().removePermission(permission); + // Send message + this.sendMessage(sender, "Removed permission for " + args.getTarget().getName()); + } + case "clear" -> { + // Clear permissions + args.getTarget().getAccount().clearPermission(); + // Send message + this.sendMessage(sender, "Cleared permissions for " + args.getTarget().getName()); + } + default -> { + this.sendMessage(sender, "Error: Invalid argument"); + } + } + } + +} diff --git a/src/main/java/emu/lunarcore/command/commands/ReloadCommand.java b/src/main/java/emu/lunarcore/command/commands/ReloadCommand.java index 0f24828..8bfe40e 100644 --- a/src/main/java/emu/lunarcore/command/commands/ReloadCommand.java +++ b/src/main/java/emu/lunarcore/command/commands/ReloadCommand.java @@ -6,7 +6,7 @@ import emu.lunarcore.command.CommandArgs; import emu.lunarcore.command.CommandHandler; import emu.lunarcore.game.player.Player; -@Command(label = "reload") +@Command(label = "reload", permission = "server.reload") public class ReloadCommand implements CommandHandler { @Override diff --git a/src/main/java/emu/lunarcore/command/commands/SpawnCommand.java b/src/main/java/emu/lunarcore/command/commands/SpawnCommand.java index 923f896..41d0f49 100644 --- a/src/main/java/emu/lunarcore/command/commands/SpawnCommand.java +++ b/src/main/java/emu/lunarcore/command/commands/SpawnCommand.java @@ -11,7 +11,7 @@ import emu.lunarcore.game.scene.entity.EntityMonster; import emu.lunarcore.util.Position; import emu.lunarcore.util.Utils; -@Command(label = "spawn") +@Command(label = "spawn", permission = "player.spawn") public class SpawnCommand implements CommandHandler { @Override @@ -32,7 +32,7 @@ public class SpawnCommand implements CommandHandler { // Get id int id = Utils.parseSafeInt(args.get(0)); int stage = Math.max(Utils.parseSafeInt(args.get(1)), 1); - int amount = Math.max(args.getCount(), 1); + int amount = Math.max(args.getAmount(), 1); int radius = Math.max(args.getRank(), 5) * 1000; // Spawn monster diff --git a/src/main/java/emu/lunarcore/command/commands/WorldLevelCommand.java b/src/main/java/emu/lunarcore/command/commands/WorldLevelCommand.java index dda64cc..95f0373 100644 --- a/src/main/java/emu/lunarcore/command/commands/WorldLevelCommand.java +++ b/src/main/java/emu/lunarcore/command/commands/WorldLevelCommand.java @@ -6,7 +6,7 @@ import emu.lunarcore.command.CommandHandler; import emu.lunarcore.game.player.Player; import emu.lunarcore.util.Utils; -@Command(label = "worldlevel", aliases = {"wl"}) +@Command(label = "worldlevel", aliases = {"wl"}, permission = "player.worldlevel") public class WorldLevelCommand implements CommandHandler { @Override diff --git a/src/main/java/emu/lunarcore/game/account/Account.java b/src/main/java/emu/lunarcore/game/account/Account.java index b81f77f..25e3254 100644 --- a/src/main/java/emu/lunarcore/game/account/Account.java +++ b/src/main/java/emu/lunarcore/game/account/Account.java @@ -1,5 +1,8 @@ package emu.lunarcore.game.account; +import java.util.*; +import java.util.stream.Stream; + import dev.morphia.annotations.*; import emu.lunarcore.LunarRail; import emu.lunarcore.util.Crypto; @@ -21,6 +24,8 @@ public class Account { private String comboToken; // Combo token private String dispatchToken; // Session token for dispatch server + + private Set permissions; @Deprecated public Account() { @@ -30,6 +35,7 @@ public class Account { public Account(String username) { this.uid = Long.toString(Snowflake32.newUid()); this.username = username; + this.permissions = new HashSet<>(); } public String getEmail() { @@ -39,20 +45,108 @@ public class Account { public void setReservedPlayerUid(int uid) { this.reservedPlayerUid = uid; } + + // Permissions + + public Set getPermissions() { + if (this.permissions == null) { + this.permissions = new HashSet<>(); + this.save(); + } + return this.permissions; + } + + public boolean addPermission(String permission) { + if (this.getPermissions().contains(permission)) { + return false; + } + this.getPermissions().add(permission); + this.save(); + return true; + } + + public static boolean permissionMatchesWildcard(String wildcard, String[] permissionParts) { + String[] wildcardParts = wildcard.split("\\."); + if (permissionParts.length < wildcardParts.length) { // A longer wildcard can never match a shorter permission + return false; + } + + for (int i = 0; i < wildcardParts.length; i++) { + switch (wildcardParts[i]) { + case "**": // Recursing match + return true; + case "*": // Match only one layer + if (i >= (permissionParts.length-1)) { + return true; + } + break; + default: // This layer isn't a wildcard, it needs to match exactly + if (!wildcardParts[i].equals(permissionParts[i])) { + return false; + } + } + } + // At this point the wildcard will have matched every layer, but if it is shorter then the permission then this is not a match at this point (no **). + return wildcardParts.length == permissionParts.length; + } + + public boolean hasPermission(String permission) { + // Skip if permission isnt required + if (permission.isEmpty()) { + return true; + } + + // Default permissions + var defaultPermissions = LunarRail.getConfig().getServerOptions().getDefaultPermissions(); + + if (defaultPermissions.contains("*")) { + return true; + } + + // Add default permissions if it doesn't exist + List permissions = Stream.of(this.getPermissions(), defaultPermissions) + .flatMap(Collection::stream) + .distinct().toList(); + + if (permissions.contains(permission)) { + return true; + } + + String[] permissionParts = permission.split("\\."); + for (String p : permissions) { + if (p.startsWith("-") && permissionMatchesWildcard(p.substring(1), permissionParts)) return false; + if (permissionMatchesWildcard(p, permissionParts)) return true; + } + + return permissions.contains("*"); + } + + public boolean removePermission(String permission) { + boolean res = this.getPermissions().remove(permission); + if (res) this.save(); + return res; + } + + public void clearPermission() { + this.getPermissions().clear(); + this.save(); + } + + // Tokens - // TODO make unique public String generateComboToken() { - this.comboToken = Utils.bytesToHex(Crypto.createSessionKey(32)); + this.comboToken = Utils.bytesToHex(Crypto.createSessionKey(32)); // TODO make unique this.save(); return this.comboToken; } - // TODO make unique public String generateDispatchToken() { - this.dispatchToken = Utils.bytesToHex(Crypto.createSessionKey(32)); + this.dispatchToken = Utils.bytesToHex(Crypto.createSessionKey(32)); // TODO make unique this.save(); return this.dispatchToken; } + + // Database public void save() { LunarRail.getAccountDatabase().save(this);