From db652d6ce805fd795aa22996bcfcecdd2b9ef58d Mon Sep 17 00:00:00 2001 From: Obique PSWG Date: Tue, 11 Apr 2017 08:16:02 -0500 Subject: [PATCH] Additional syntax based refactoring to CommandService --- src/services/commands/CommandLauncher.java | 6 +- src/services/commands/CommandService.java | 304 ++++----------------- 2 files changed, 55 insertions(+), 255 deletions(-) diff --git a/src/services/commands/CommandLauncher.java b/src/services/commands/CommandLauncher.java index f98083336..0525b3dbd 100644 --- a/src/services/commands/CommandLauncher.java +++ b/src/services/commands/CommandLauncher.java @@ -102,10 +102,14 @@ public class CommandLauncher { // TODO implement locomotion and state checks up here. See action and error in CommandQueueDequeue! // TODO target and targetType checks + Log.d("doCommand %s", command.getName()); + sendCommandDequeue(player, command, enqueued.getRequest(), 0, 0); - if (!cooldownHandler.startCooldowns(creature, enqueued)) + if (!cooldownHandler.startCooldowns(creature, enqueued)) { + Log.w("Not starting command %s - cooldown not ready yet!", command.getName()); return; // This ability is currently on cooldown + } executeCommand(player, enqueued); new ChatCommandIntent(creature, enqueued.getTarget(), command, enqueued.getRequest().getArguments().split(" ")).broadcast(); diff --git a/src/services/commands/CommandService.java b/src/services/commands/CommandService.java index c8f49de5a..947ac4a2c 100644 --- a/src/services/commands/CommandService.java +++ b/src/services/commands/CommandService.java @@ -28,15 +28,10 @@ package services.commands; import intents.PlayerEventIntent; -import intents.chat.ChatBroadcastIntent; -import intents.chat.ChatCommandIntent; import intents.network.GalacticPacketIntent; import intents.player.PlayerTransformedIntent; -import java.io.FileNotFoundException; - import network.packets.Packet; -import network.packets.swg.zone.object_controller.CommandQueueDequeue; import network.packets.swg.zone.object_controller.CommandQueueEnqueue; import resources.client_info.ClientFactory; import resources.client_info.visitors.DatatableData; @@ -48,30 +43,17 @@ import resources.commands.Command; import resources.commands.ICmdCallback; import resources.commands.callbacks.*; import resources.common.CRC; -import resources.encodables.ProsePackage; -import resources.encodables.StringId; import resources.objects.SWGObject; import resources.objects.weapon.WeaponType; -import resources.player.AccessLevel; import resources.player.Player; import resources.server_info.Log; -import utilities.Scripts; +import services.commands.CommandLauncher.EnqueuedCommand; import services.galaxy.GalacticManager; -import java.util.HashMap; -import java.util.HashSet; import java.util.List; import java.util.Locale; -import java.util.Map; -import java.util.Queue; -import java.util.Set; -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.PriorityBlockingQueue; -import com.projectswg.common.concurrency.PswgScheduledThreadPool; -import com.projectswg.common.concurrency.SynchronizedMap; import com.projectswg.common.control.Service; -import network.packets.swg.zone.object_controller.CommandTimer; import resources.combat.DelayAttackEggPosition; import resources.combat.HitType; import resources.commands.DefaultPriority; @@ -79,16 +61,12 @@ import resources.objects.creature.CreatureObject; public class CommandService extends Service { - private final Map >combatQueueMap; - private final Map > cooldownMap; - private final PswgScheduledThreadPool cooldownThread; - private final CommandContainer commandContainer; + private final CommandContainer commandContainer; + private final CommandLauncher commandLauncher; public CommandService() { - this.combatQueueMap = new SynchronizedMap<>(); - this.cooldownMap = new HashMap<>(); - this.cooldownThread = new PswgScheduledThreadPool(1, "command-service-cooldown-thread"); this.commandContainer = new CommandContainer(); + this.commandLauncher = new CommandLauncher(); registerForIntent(GalacticPacketIntent.class, gpi -> handleGalacticPacketIntent(gpi)); registerForIntent(PlayerEventIntent.class, pei -> handlePlayerEventIntent(pei)); @@ -100,15 +78,13 @@ public class CommandService extends Service { loadBaseCommands(); loadCombatCommands(); registerCallbacks(); - - cooldownThread.start(); - cooldownThread.executeWithFixedRate(1000, 1000, () -> pollQueues()); + commandLauncher.start(); return super.initialize(); } @Override public boolean terminate() { - cooldownThread.stop(); + commandLauncher.stop(); return super.terminate(); } @@ -121,11 +97,11 @@ public class CommandService extends Service { } private void handlePlayerEventIntent(PlayerEventIntent pei) { - switch(pei.getEvent()) { + switch (pei.getEvent()) { case PE_LOGGED_OUT: // No reason to keep their combat queue in the map if they log out // This also prevents queued commands from executing after the player logs out - combatQueueMap.remove(pei.getPlayer()); + commandLauncher.removePlayerFromQueue(pei.getPlayer()); break; default: break; @@ -134,18 +110,13 @@ public class CommandService extends Service { private void handlePlayerTransformedIntent(PlayerTransformedIntent pti) { CreatureObject creature = pti.getPlayer(); - + if (creature.isPerforming()) { // A performer can transform while dancing... return; } - - Player player = creature.getOwner(); - Queue combatQueue = combatQueueMap.get(player); - - if (combatQueue != null) { - combatQueue.clear(); - } + + commandLauncher.removePlayerFromQueue(creature.getOwner()); } private void handleCommandRequest(Player player, GalacticManager galacticManager, CommandQueueEnqueue request) { @@ -158,160 +129,22 @@ public class CommandService extends Service { Command command = commandContainer.getCommand(request.getCommandCrc()); // TODO target and target type checks below. Work with Set targets from there long targetId = request.getTargetId(); - final SWGObject target = targetId != 0 ? galacticManager.getObjectManager().getObjectById(targetId) : null; + SWGObject target = targetId != 0 ? galacticManager.getObjectManager().getObjectById(targetId) : null; + EnqueuedCommand enqueued = new EnqueuedCommand(command, galacticManager, target, request); if (!command.getCooldownGroup().equals("defaultCooldownGroup") && command.isAddToCombatQueue()) { - // Schedule for later execution - BlockingQueue combatQueue = combatQueueMap.get(player); - - if (combatQueue == null) { - combatQueue = new PriorityBlockingQueue<>(); // Has natural ordering. QueuedCommand implements Comparable for this purpose. - combatQueueMap.put(player, combatQueue); - } - - if (!combatQueue.offer(new QueuedCommand(command, galacticManager, target, request))) { - // Ziggy: Shouldn't happen, unless the Queue implementation is changed - Log.e("Unable to enqueue command %s from %s because the combat queue is full", command.getName(), player.getCreatureObject()); - } + commandLauncher.addToQueue(player, enqueued); } else { // Execute it now - doCommand(galacticManager, player, command, target, request); + commandLauncher.doCommand(player, enqueued); } } - private void pollQueues() { - // Takes the head of each queue and executes the command - combatQueueMap.forEach((player, combatQueue) -> { - QueuedCommand queueHead = combatQueue.poll(); - - if (queueHead != null) { // Can be null if the combat queue is empty - doCommand(queueHead.getGalacticManager(), player, queueHead.getCommand(), queueHead.getTarget(), queueHead.getRequest()); - } - }); - } - - private void doCommand(GalacticManager galacticManager, Player player, Command command, SWGObject target, CommandQueueEnqueue request) { - CreatureObject creature = player.getCreatureObject(); - // TODO implement locomotion and state checks up here. See action and error in CommandQueueDequeue! - - // TODO target and targetType checks - - // Let's check if this ability is on cooldown - String cooldownGroup = command.getCooldownGroup(); - String cooldownGroup2 = command.getCooldownGroup2(); - - synchronized (cooldownMap) { - Set cooldowns = cooldownMap.get(creature); - - if (cooldowns == null) { - // This is the first time they're using a cooldown command - cooldowns = new HashSet<>(); - cooldownMap.put(creature, cooldowns); - } else if (cooldowns.contains(cooldownGroup) || cooldowns.contains(cooldownGroup2)) { - // This ability is currently on cooldown - sendCommandDequeue(player, command, request, 0, 0); - return; - } - } - - sendCommandDequeue(player, command, request, 0, 0); - - String argumentString = request.getArguments(); - String[] arguments = argumentString.split(" "); - executeCommand(galacticManager, player, command, target, argumentString); - new ChatCommandIntent(creature, target, command, arguments).broadcast(); - - // TODO custom cooldown times. Scripts might be a good idea. - - startCooldownGroup(creature, request.getCounter(), command.getCrc(), cooldownGroup, command.getCooldownTime()); - startCooldownGroup(creature, request.getCounter(), command.getCrc(), cooldownGroup2, command.getCooldownTime2()); - } - - private void sendCommandDequeue(Player player, Command command, CommandQueueEnqueue request, int action, int error) { - CommandQueueDequeue dequeue = new CommandQueueDequeue(player.getCreatureObject().getObjectId()); - dequeue.setCounter(request.getCounter()); - dequeue.setAction(action); - dequeue.setError(error); - dequeue.setTimer(command.getExecuteTime()); - player.sendPacket(dequeue); - } - - private void startCooldownGroup(CreatureObject creature, int sequenceId, int commandNameCrc, String cooldownGroup, float cooldownTime) { - if(!cooldownGroup.isEmpty() && !cooldownGroup.equals("defaultCooldownGroup")) { - synchronized(cooldownMap) { - if(cooldownMap.get(creature).add(cooldownGroup)) { - CommandTimer commandTimer = new CommandTimer(creature.getObjectId()); - commandTimer.setCooldownGroupCrc(CRC.getCrc(cooldownGroup)); - commandTimer.setCooldownMax(cooldownTime); - commandTimer.setCommandNameCrc(commandNameCrc); - commandTimer.setSequenceId(sequenceId); - creature.sendSelf(commandTimer); - - cooldownThread.execute((long) (cooldownTime * 1000), () -> removeCooldown(creature, cooldownGroup)); - } - } - } - } - - private void removeCooldown(CreatureObject creature, String cooldownGroup) { - synchronized (cooldownMap) { - Set cooldownGroups = cooldownMap.get(creature); - if (cooldownGroups.remove(cooldownGroup)) { - - } else { - Log.w("%s doesn't have cooldown group %s!", creature, cooldownGroup); - } - } - } - - private void executeCommand(GalacticManager galacticManager, Player player, Command command, SWGObject target, String args) { - if (player.getCreatureObject() == null) { - Log.e("No creature object associated with the player '%s'!", player.getUsername()); - return; - } - - if(player.getAccessLevel().getValue() < command.getGodLevel()) { - String commandAccessLevel = AccessLevel.getFromValue(command.getGodLevel()).toString(); - String playerAccessLevel = player.getAccessLevel().toString(); - Log.i("[%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); - String errorProseString1 = "use that command"; - new ChatBroadcastIntent(player, new ProsePackage("StringId", new StringId("cmd_err", "state_must_have_prose"), "TO", errorProseString1, "TU", commandAccessLevel)).broadcast(); - return; - } - - if(!command.getCharacterAbility().isEmpty() && !player.getCreatureObject().hasAbility(command.getCharacterAbility())){ - Log.i("[%s] attempted to use the command \"%s\", but did not have the required ability. Ability Required: %s", - player.getCharacterName(), command.getName(), command.getCharacterAbility()); - String errorProseString = String.format("use the %s command", command.getName()); - new ChatBroadcastIntent(player, new ProsePackage("StringId", new StringId("cmd_err", "ability_prose"), "TO", errorProseString)).broadcast(); - return; - } - - // TODO: Check if the player has the ability - // TODO: Cool-down checks - // TODO: Handle for different target - // TODO: Handle for different targetType - - if (command.hasJavaCallback()) { - try { - command.getJavaCallback().newInstance().execute(galacticManager, player, target, args); - } catch (InstantiationException | IllegalAccessException e) { - Log.e(e); - } - } - else - try { - Scripts.invoke("commands/generic/" + command.getDefaultScriptCallback(), "executeCommand", galacticManager, player, target, args); - } catch (FileNotFoundException ex) { - } - } - private void loadBaseCommands() { // First = Higher Priority, Last = Lower Priority ---- Some tables contain duplicates, ORDER MATTERS! - final String [] commandTables = new String [] { - "command_table", "command_table_ground", "client_command_table", - "command_table_space", "client_command_table_ground", "client_command_table_space" + String [] commandTables = new String[] { + "command_table", "command_table_ground", "client_command_table", + "command_table_space", "client_command_table_ground", "client_command_table_space" }; commandContainer.clearCommands(); @@ -321,16 +154,16 @@ public class CommandService extends Service { } private void loadBaseCommands(String table) { - DatatableData baseCommands = (DatatableData) ClientFactory.getInfoFromFile("datatables/command/"+table+".iff"); - + DatatableData baseCommands = (DatatableData) ClientFactory.getInfoFromFile("datatables/command/" + table + ".iff"); + int godLevel = baseCommands.getColumnFromName("godLevel"); int cooldownGroup = baseCommands.getColumnFromName("cooldownGroup"); int cooldownGroup2 = baseCommands.getColumnFromName("cooldownGroup2"); int cooldownTime = baseCommands.getColumnFromName("cooldownTime"); int cooldownTime2 = baseCommands.getColumnFromName("cooldownTime2"); - + for (int row = 0; row < baseCommands.getRowCount(); row++) { - Object [] cmdRow = baseCommands.getRow(row); + Object[] cmdRow = baseCommands.getRow(row); String commandName = ((String) cmdRow[0]).toLowerCase(Locale.ENGLISH); if (commandContainer.isCommand(commandName)) continue; // skip duplicates - first is higher priority @@ -340,7 +173,7 @@ public class CommandService extends Service { command.setCrc(CRC.getCrc(commandName)); command.setDefaultPriority(DefaultPriority.getDefaultPriority((int) cmdRow[1])); command.setScriptHook((String) cmdRow[2]); - command.setCppHook((String)cmdRow[4]); + command.setCppHook((String) cmdRow[4]); command.setDefaultTime((float) cmdRow[6]); command.setCharacterAbility((String) cmdRow[7]); command.setCombatCommand(false); @@ -350,16 +183,16 @@ public class CommandService extends Service { command.setCooldownTime2((float) cmdRow[cooldownTime2]); // Ziggy: The amount of columns in the table seems to change for each row - if(cmdRow.length >= 83) { + if (cmdRow.length >= 83) { Object addToCombatQueue = cmdRow[82]; - + // Ziggy: Sometimes this column contains a String... uwot SOE? - if(addToCombatQueue instanceof Boolean) { + if (addToCombatQueue instanceof Boolean) { command.setAddToCombatQueue((Boolean) addToCombatQueue); } } - if(godLevel >= 0){ + if (godLevel >= 0) { command.setGodLevel((int) cmdRow[godLevel]); } @@ -409,11 +242,11 @@ public class CommandService extends Service { int delayAttackLoops = combatCommands.getColumnFromName("delayAttackLoops"); int delayAttackEggPosition = combatCommands.getColumnFromName("delayAttackEggPosition"); int coneLength = combatCommands.getColumnFromName("coneLength"); - // animDefault anim_unarmed anim_onehandmelee anim_twohandmelee anim_polearm - // anim_pistol anim_lightRifle anim_carbine anim_rifle anim_heavyweapon - // anim_thrown anim_onehandlightsaber anim_twohandlightsaber anim_polearmlightsaber + // animDefault anim_unarmed anim_onehandmelee anim_twohandmelee anim_polearm + // anim_pistol anim_lightRifle anim_carbine anim_rifle anim_heavyweapon + // anim_thrown anim_onehandlightsaber anim_twohandlightsaber anim_polearmlightsaber for (int row = 0; row < combatCommands.getRowCount(); row++) { - Object [] cmdRow = combatCommands.getRow(row); + Object[] cmdRow = combatCommands.getRow(row); Command c = commandContainer.getCommand(CRC.getCrc(((String) cmdRow[0]).toLowerCase(Locale.ENGLISH))); if (c == null) @@ -443,24 +276,24 @@ public class CommandService extends Service { cc.setDelayAttackLoops((int) cmdRow[delayAttackLoops]); cc.setEggPosition(DelayAttackEggPosition.getEggPosition((int) cmdRow[delayAttackEggPosition])); cc.setConeLength((float) cmdRow[coneLength]); - cc.setAnimations(WeaponType.UNARMED, getAnimationList((String) cmdRow[animDefault+1])); - cc.setAnimations(WeaponType.ONE_HANDED_MELEE, getAnimationList((String) cmdRow[animDefault+2])); - cc.setAnimations(WeaponType.TWO_HANDED_MELEE, getAnimationList((String) cmdRow[animDefault+3])); - cc.setAnimations(WeaponType.POLEARM_MELEE, getAnimationList((String) cmdRow[animDefault+4])); - cc.setAnimations(WeaponType.POLEARM_MELEE, getAnimationList((String) cmdRow[animDefault+5])); - cc.setAnimations(WeaponType.PISTOL, getAnimationList((String) cmdRow[animDefault+6])); - cc.setAnimations(WeaponType.LIGHT_RIFLE, getAnimationList((String) cmdRow[animDefault+7])); - cc.setAnimations(WeaponType.CARBINE, getAnimationList((String) cmdRow[animDefault+8])); - cc.setAnimations(WeaponType.RIFLE, getAnimationList((String) cmdRow[animDefault+9])); - cc.setAnimations(WeaponType.THROWN, getAnimationList((String) cmdRow[animDefault+10])); - cc.setAnimations(WeaponType.ONE_HANDED_SABER, getAnimationList((String) cmdRow[animDefault+11])); - cc.setAnimations(WeaponType.TWO_HANDED_SABER, getAnimationList((String) cmdRow[animDefault+12])); - cc.setAnimations(WeaponType.POLEARM_SABER, getAnimationList((String) cmdRow[animDefault+13])); + cc.setAnimations(WeaponType.UNARMED, getAnimationList((String) cmdRow[animDefault + 1])); + cc.setAnimations(WeaponType.ONE_HANDED_MELEE, getAnimationList((String) cmdRow[animDefault + 2])); + cc.setAnimations(WeaponType.TWO_HANDED_MELEE, getAnimationList((String) cmdRow[animDefault + 3])); + cc.setAnimations(WeaponType.POLEARM_MELEE, getAnimationList((String) cmdRow[animDefault + 4])); + cc.setAnimations(WeaponType.POLEARM_MELEE, getAnimationList((String) cmdRow[animDefault + 5])); + cc.setAnimations(WeaponType.PISTOL, getAnimationList((String) cmdRow[animDefault + 6])); + cc.setAnimations(WeaponType.LIGHT_RIFLE, getAnimationList((String) cmdRow[animDefault + 7])); + cc.setAnimations(WeaponType.CARBINE, getAnimationList((String) cmdRow[animDefault + 8])); + cc.setAnimations(WeaponType.RIFLE, getAnimationList((String) cmdRow[animDefault + 9])); + cc.setAnimations(WeaponType.THROWN, getAnimationList((String) cmdRow[animDefault + 10])); + cc.setAnimations(WeaponType.ONE_HANDED_SABER, getAnimationList((String) cmdRow[animDefault + 11])); + cc.setAnimations(WeaponType.TWO_HANDED_SABER, getAnimationList((String) cmdRow[animDefault + 12])); + cc.setAnimations(WeaponType.POLEARM_SABER, getAnimationList((String) cmdRow[animDefault + 13])); commandContainer.addCommand(cc); } } - private String [] getAnimationList(String cell) { + private String[] getAnimationList(String cell) { if (cell.isEmpty()) return new String[0]; return cell.split(","); @@ -472,7 +305,7 @@ public class CommandService extends Service { registerCallback(comand, callback); return comand; } - + private void registerCallback(Command command, Class callback) { try { if (callback.getConstructor() == null) @@ -481,18 +314,17 @@ public class CommandService extends Service { Log.e(e); } command.setJavaCallback(callback); - + List scriptCommands = commandContainer.getScriptCommandList(command.getDefaultScriptCallback()); - for(Command unregistered : scriptCommands){ - if(unregistered != command && !unregistered.hasJavaCallback()){ + for (Command unregistered : scriptCommands) { + if (unregistered != command && !unregistered.hasJavaCallback()) { registerCallback(unregistered, command.getJavaCallback()); } } - + } private void registerCallbacks() { - registerCallback("waypoint", WaypointCmdCallback.class); registerCallback("requestWaypointAtPosition", RequestWaypointCmdCallback.class); registerCallback("server", ServerCmdCallback.class); @@ -519,40 +351,4 @@ public class CommandService extends Service { registerCallback("transferItemWeapon", TransferItemCallback.class); } - private static class QueuedCommand implements Comparable { - - private final Command command; - private final GalacticManager galacticManager; - private final SWGObject target; - private final CommandQueueEnqueue request; - - public QueuedCommand(Command command, GalacticManager galacticManager, SWGObject target, CommandQueueEnqueue request) { - this.command = command; - this.galacticManager = galacticManager; - this.target = target; - this.request = request; - } - - @Override - public int compareTo(QueuedCommand o) { - return command.getDefaultPriority().compareTo(o.getCommand().getDefaultPriority()); - } - - public Command getCommand() { - return command; - } - - public GalacticManager getGalacticManager() { - return galacticManager; - } - - public SWGObject getTarget() { - return target; - } - - public CommandQueueEnqueue getRequest() { - return request; - } - - } }