From 086e6535b0c8bf8d4403cd01f9e9cf36e1b57c7e Mon Sep 17 00:00:00 2001 From: wallaceg09 Date: Fri, 14 Aug 2015 22:02:28 -0500 Subject: [PATCH] Basic admin system. This should automatically prevent most admin commands from being called by players that shouldn't be calling them, and even supports multiple levels of admins. There are some outlier commands that don't follow the assumed convention of "admin" ability + godLevel, for example /setGodMode does not require the "admin" ability, but neither does it have a godLevel. So without manually checking in that instance, any player could grant themselves god mode and have access to low level admin commands. In order for admins to gain access to most of their commands, they must call the /setGodMode command. This command gives them the "admin" ability, and this ability works in tandem with their godLevel (which is determined by their access level). Adds a minor implementation for abilities to enable the admin system to work. This implementation should come in handy in GU3 when we start on combat, since it will automatically prevent players from calling combat commands that they do not have the ability to call. --- scripts/commands/generic/admin_setGodMode.js | 20 ++++++++ .../client_info/visitors/DatatableData.java | 6 +++ .../objects/creature/CreatureObject.java | 6 +++ .../objects/player/PlayerObject.java | 9 ++-- src/resources/player/AccessLevel.java | 51 +++++++++++++++++-- src/services/commands/CommandService.java | 31 +++++++---- src/services/player/LoginService.java | 7 +-- 7 files changed, 109 insertions(+), 21 deletions(-) create mode 100644 scripts/commands/generic/admin_setGodMode.js diff --git a/scripts/commands/generic/admin_setGodMode.js b/scripts/commands/generic/admin_setGodMode.js new file mode 100644 index 000000000..605d8f1c8 --- /dev/null +++ b/scripts/commands/generic/admin_setGodMode.js @@ -0,0 +1,20 @@ +var execute = function(galManager, player, target, args) { + //TODO: Move to java callback + if(player.getAccessLevel() == (Java.type('resources.player.AccessLevel')).PLAYER){ + intentFactory.sendSystemMessage(player, "Players cannot use this command :("); + return; + } + + var creatureObject = player.getCreatureObject(); + if(target){ + creatureObject = target.getCreatureObject(); + } + + if(creatureObject.hasAbility("admin")){ + creatureObject.removeAbility("admin"); + intentFactory.sendSystemMessage(player, "God Mode Disabled");//TODO: See if there's an STF to send + }else{ + creatureObject.addAbility("admin"); + intentFactory.sendSystemMessage(player, "God Mode Enabled");//TODO: See if there's an STF to send + } +} \ No newline at end of file diff --git a/src/resources/client_info/visitors/DatatableData.java b/src/resources/client_info/visitors/DatatableData.java index 859163c83..96028112a 100644 --- a/src/resources/client_info/visitors/DatatableData.java +++ b/src/resources/client_info/visitors/DatatableData.java @@ -31,6 +31,8 @@ import resources.client_info.ClientData; import resources.client_info.IffNode; import resources.client_info.SWGFile; +import java.util.Arrays; + public class DatatableData extends ClientData { private String[] columnNames; @@ -263,6 +265,10 @@ public class DatatableData extends ClientData { return columnTypes[column]; } + public int getColumnFromName(String name){ + return Arrays.asList(columnNames).indexOf(name); + } + public void handleRows(DatatableRowHandler handler) { for (int r = 0; r < getRowCount(); r++) { handler.handleRow(r); diff --git a/src/resources/objects/creature/CreatureObject.java b/src/resources/objects/creature/CreatureObject.java index 233323596..38a46a679 100644 --- a/src/resources/objects/creature/CreatureObject.java +++ b/src/resources/objects/creature/CreatureObject.java @@ -634,6 +634,12 @@ public class CreatureObject extends TangibleObject { public int getBaseAction() { return attributes.get(2); } + + public void addAbility(String abilityName){ abilities.put(abilityName, 1); }//TODO: Figure out what the integer value should be for each ability + + public void removeAbility(String abilityName) { abilities.remove(abilityName); } + + public boolean hasAbility(String abilityName) { return abilities.get(abilityName) != null; } public void setHealth(int health) { synchronized(attributes) { diff --git a/src/resources/objects/player/PlayerObject.java b/src/resources/objects/player/PlayerObject.java index e3fd1b828..f0d289c4a 100644 --- a/src/resources/objects/player/PlayerObject.java +++ b/src/resources/objects/player/PlayerObject.java @@ -250,10 +250,11 @@ public class PlayerObject extends IntangibleObject { public void setAdminTag(AccessLevel access) { switch(access) { - case PLAYER: break; - case ADMIN: adminTag = 1; break; - case DEV: adminTag = 2; break; - case QA: adminTag = 4; break; + case PLAYER: break; + case CSR: adminTag = 1; break; + case DEV: adminTag = 2; break; + case WARDEN: adminTag = 3; break; + case QA: adminTag = 4; break; } sendDelta(6, 2, adminTag); } diff --git a/src/resources/player/AccessLevel.java b/src/resources/player/AccessLevel.java index dc1c293e1..8254aa5c0 100644 --- a/src/resources/player/AccessLevel.java +++ b/src/resources/player/AccessLevel.java @@ -27,9 +27,52 @@ ***********************************************************************************/ package resources.player; +/** + * I believe that the godLevel value in the iffs corresponds to the access level of the command. + * This might not be correct, since there are at least 69 commands with godLevel 0 that require the "admin" ability, + * however, the godLevels seem to follow this hierarchy relatively decently. + * + * The way the admin system is currently set up is that each level has access to all levels beneath it. + * + * For example: WARDENSs have access to all PLAYER commands, CSRs have access to all WARDEN commands and PLAYER commands, + * QAs have access to all CSR commands ... etc. + * + * With that in mind, if we restrict the ability to have the "admin" ability to those with WARDEN+ then the godLevel 0 + * commands with the "admin" ability would effectively just become WARDEN commands. + * + * We can change the names/swap the values of these as needed. This is just a rough estimate on my part. + */ public enum AccessLevel { - PLAYER, - QA, - ADMIN, - DEV + PLAYER(0), + WARDEN(5), + CSR(10), + QA(15), + DEV(50); + + private final int value; + + private AccessLevel(int value){ + this.value = value; + } + + public int getValue(){ + return value; + } + + public static AccessLevel getFromValue(int value){ + switch(value){ + case 0: + return PLAYER; + case 5: + return WARDEN; + case 10: + return CSR; + case 15: + return QA; + case 50: + return DEV; + default: + return PLAYER; + } + } } diff --git a/src/services/commands/CommandService.java b/src/services/commands/CommandService.java index 6b6b0cc01..197f7ce7e 100644 --- a/src/services/commands/CommandService.java +++ b/src/services/commands/CommandService.java @@ -112,15 +112,21 @@ public class CommandService extends Service { Log.e("CommandService", "No creature object associated with the player '%s'!", player.getUsername()); return; } - - if (command.getGodLevel() > 0 || command.getCharacterAbility().toLowerCase().equals("admin")) {//HACK @Glen characterAbility check should be handled in the "has ability" TODO below. Not sure if abilities are implemented yet. - if (player.getAccessLevel() == AccessLevel.PLAYER) { - System.out.printf("[%s] failed to use admin command \"%s\" with access level %s with parameters \"%s\"\n", player.getCharacterName(), command.getName(), player.getAccessLevel().toString(), args); - return; - } - System.out.printf("[%s] successfully used admin command \"%s\" with access level %s with parameters \"%s\"\n", player.getCharacterName(), command.getName(), player.getAccessLevel().toString(), args); + + if(player.getAccessLevel().getValue() < command.getGodLevel()) { + String commandAccessLevel = AccessLevel.getFromValue(command.getGodLevel()).toString(); + String playerAccessLevel = player.getAccessLevel().toString(); + Log.i("CommandService", "[%s] attempted to use the command \"%s\", but did not have the minimum access level. Access Level Required: %s, Player Access Level: %s", + player.getCharacterName(), command.getName(), commandAccessLevel, playerAccessLevel); + return; } - + + if(!command.getCharacterAbility().isEmpty() && !player.getCreatureObject().hasAbility(command.getCharacterAbility())){ + Log.i("CommandService", "[%s] attempted to use the command \"%s\", but did not have the required ability. Ability Required: %s", + player.getCharacterName(), command.getName(), command.getCharacterAbility()); + return; + } + // TODO: Check if the player has the ability // TODO: Cool-down checks // TODO: Handle for different target @@ -148,7 +154,8 @@ public class CommandService extends Service { private void loadBaseCommands(String table) { DatatableData baseCommands = (DatatableData) ClientFactory.getInfoFromFile("datatables/command/"+table+".iff"); - + + int godLevel = baseCommands.getColumnFromName("godLevel"); for (int row = 0; row < baseCommands.getRowCount(); row++) { Object [] cmdRow = baseCommands.getRow(row); @@ -158,7 +165,11 @@ public class CommandService extends Service { command.setCppHook((String)cmdRow[4]); command.setDefaultTime((float) cmdRow[6]); command.setCharacterAbility((String) cmdRow[7]); - + + if(godLevel >= 0){ + command.setGodLevel((int) cmdRow[godLevel]); + } + addCommand(command); } } diff --git a/src/services/player/LoginService.java b/src/services/player/LoginService.java index a3cbf9f3c..6fc59d2ad 100644 --- a/src/services/player/LoginService.java +++ b/src/services/player/LoginService.java @@ -200,9 +200,10 @@ public class LoginService extends Service { player.setPlayerState(PlayerState.LOGGING_IN); switch(user.getString("access_level")) { case "player": player.setAccessLevel(AccessLevel.PLAYER); break; - case "admin": player.setAccessLevel(AccessLevel.ADMIN); break; - case "dev": player.setAccessLevel(AccessLevel.DEV); break; + case "warden": player.setAccessLevel(AccessLevel.WARDEN); break; + case "csr": player.setAccessLevel(AccessLevel.CSR); break; case "qa": player.setAccessLevel(AccessLevel.QA); break; + case "dev": player.setAccessLevel(AccessLevel.DEV); break; default: player.setAccessLevel(AccessLevel.PLAYER); break; } sendLoginSuccessPacket(player); @@ -338,7 +339,7 @@ public class LoginService extends Service { g.setRecommended(true); g.setPopulationStatus(populationStatus(consumed)); // If locked, restricted, or full - if (p.getAccessLevel() == AccessLevel.ADMIN && g.getStatus() != GalaxyStatus.UP) + if (p.getAccessLevel() == AccessLevel.QA && g.getStatus() != GalaxyStatus.UP) g.setStatus(GalaxyStatus.UP); galaxies.add(g); }