package engine.devcmd.cmds; import engine.Enum; import engine.Enum.BuildingGroup; import engine.Enum.GameObjectType; import engine.InterestManagement.WorldGrid; import engine.devcmd.AbstractDevCmd; import engine.gameManager.BuildingManager; import engine.gameManager.DbManager; import engine.gameManager.ZoneManager; import engine.math.Vector3fImmutable; import engine.objects.*; import engine.server.MBServerStatics; import org.pmw.tinylog.Logger; import java.util.HashSet; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; /** * @author Summary: Game designer utility command to purge all * objects of a given type within a supplied range */ public class PurgeObjectsCmd extends AbstractDevCmd { // Instance variables private Vector3fImmutable _currentLocation; private float _targetRange; private int _targetMask; // Concurrency support private ReadWriteLock lock = new ReentrantReadWriteLock(); // Constructor public PurgeObjectsCmd() { super("purge"); } private static void PurgeWalls(Zone zone, PlayerCharacter pc) { if (!zone.isPlayerCity()) return; for (Building building : zone.zoneBuildingSet) { if (!BuildingManager.IsWallPiece(building)) continue; for (AbstractCharacter ac : building.getHirelings().keySet()) { NPC npc = null; Mob mobA = null; if (ac.getObjectType() == GameObjectType.NPC) npc = (NPC) ac; else if (ac.getObjectType() == GameObjectType.Mob) mobA = (Mob) ac; if (npc != null) { for (Integer minionUUID : npc.minions) { Mob mob = Mob.getMob(minionUUID); WorldGrid.RemoveWorldObject(mob); WorldGrid.removeObject(mob, pc); if (mob.getParentZone() != null) mob.getParentZone().zoneMobSet.remove(mob); } DbManager.NPCQueries.DELETE_NPC(npc); DbManager.removeFromCache(GameObjectType.NPC, npc.getObjectUUID()); WorldGrid.RemoveWorldObject(npc); } else if (mobA != null) { for (Integer minionUUID : mobA.minions) { Mob mob = Mob.getMob(minionUUID); WorldGrid.RemoveWorldObject(mob); WorldGrid.removeObject(mob, pc); if (mob.getParentZone() != null) mob.getParentZone().zoneMobSet.remove(mob); } DbManager.MobQueries.DELETE_MOB(mobA); DbManager.removeFromCache(GameObjectType.Mob, mobA.getObjectUUID()); WorldGrid.RemoveWorldObject(mobA); } } DbManager.BuildingQueries.DELETE_FROM_DATABASE(building); DbManager.removeFromCache(building); WorldGrid.RemoveWorldObject(building); WorldGrid.removeObject(building, pc); } } // AbstractDevCmd Overridden methods private static boolean validateUserInput(String[] userInput) { int stringIndex; String commandSet = "npcmobmeshall"; // incorrect number of arguments test if (userInput.length != 2) return false; // Test of game object type argument stringIndex = commandSet.indexOf(userInput[0].toLowerCase()); if (stringIndex == -1) return false; // Test if range argument can convert to a float try { Float.parseFloat(userInput[1]); } catch (NumberFormatException | NullPointerException e) { return false; } // User input passes validation return true; } private static void removeBuilding(PlayerCharacter pc, Building building) { if ((building.getBlueprintUUID() != 0) && (building.getBlueprint().getBuildingGroup() == BuildingGroup.TOL)) return; if ((building.getBlueprintUUID() != 0) && (building.getBlueprint().getBuildingGroup() == BuildingGroup.SHRINE)) Shrine.RemoveShrineFromCacheByBuilding(building); if ((building.getBlueprint() != null) && (building.getBlueprint().getBuildingGroup() == BuildingGroup.SPIRE)) building.disableSpire(false); for (AbstractCharacter ac : building.getHirelings().keySet()) { NPC npc = null; Mob mobA = null; if (ac.getObjectType() == GameObjectType.NPC) npc = (NPC) ac; else if (ac.getObjectType() == GameObjectType.Mob) mobA = (Mob) ac; if (npc != null) { for (Integer minionUUID : npc.minions) { Mob mob = Mob.getMob(minionUUID); WorldGrid.RemoveWorldObject(mob); WorldGrid.removeObject(mob, pc); if (mob.getParentZone() != null) mob.getParentZone().zoneMobSet.remove(mob); } DbManager.NPCQueries.DELETE_NPC(npc); DbManager.removeFromCache(Enum.GameObjectType.NPC, npc.getObjectUUID()); WorldGrid.RemoveWorldObject(npc); } else if (mobA != null) { for (Integer minionUUID : mobA.minions) { Mob mob = Mob.getMob(minionUUID); WorldGrid.RemoveWorldObject(mob); WorldGrid.removeObject(mob, pc); if (mob.getParentZone() != null) mob.getParentZone().zoneMobSet.remove(mob); } DbManager.MobQueries.DELETE_MOB(mobA); DbManager.removeFromCache(Enum.GameObjectType.Mob, mobA.getObjectUUID()); WorldGrid.RemoveWorldObject(mobA); } } DbManager.BuildingQueries.DELETE_FROM_DATABASE(building); DbManager.removeFromCache(building); WorldGrid.RemoveWorldObject(building); WorldGrid.removeObject(building, pc); } private static void removeNPC(PlayerCharacter pc, NPC npc) { DbManager.NPCQueries.DELETE_NPC(npc); DbManager.removeFromCache(npc); WorldGrid.RemoveWorldObject(npc); WorldGrid.removeObject(npc, pc); } // Class methods private static void removeMob(PlayerCharacter pc, Mob mob) { mob.setLoc(Vector3fImmutable.ZERO); //Move it off the plane.. mob.setBindLoc(Vector3fImmutable.ZERO); //Reset the bind loc.. //mob.setHealth(-1, pc); //Kill it! DbManager.MobQueries.DELETE_MOB(mob); DbManager.removeFromCache(mob); WorldGrid.RemoveWorldObject(mob); WorldGrid.removeObject(mob, pc); } @Override protected void _doCmd(PlayerCharacter pc, String[] args, AbstractGameObject target) { // Grab write lock due to use of instance variables lock.writeLock().lock(); try { if (args[0].toLowerCase().equals("walls")) { Zone zone = ZoneManager.findSmallestZone(pc.getLoc()); PurgeWalls(zone, pc); return; } if (validateUserInput(args) == false) { this.sendUsage(pc); return; } parseUserInput(args); // Arguments have been validated and parsed at this point // Build array of requested objects _currentLocation = pc.getLoc(); HashSet objectList = WorldGrid.getObjectsInRangePartial(_currentLocation, _targetRange, _targetMask); // Iterate through array and remove objects from game world and database for (AbstractWorldObject awo : objectList) { switch (awo.getObjectType()) { case Building: removeBuilding(pc, (Building) awo); break; case NPC: removeNPC(pc, (NPC) awo); break; case Mob: removeMob(pc, (Mob) awo); break; default: break; } } // Send results to user throwbackInfo(pc, "Purge: " + objectList.size() + " objects were removed in range " + _targetRange); } catch (Exception e) { Logger.error(e); } // Release Reentrant lock finally { lock.writeLock().unlock(); } } @Override protected String _getHelpString() { return "Purges game objects within range"; } @Override protected String _getUsageString() { return "/purge [npc|mob|mesh|all] [range <= 200]"; } private void parseUserInput(String[] userInput) { _targetMask = 0; _targetRange = 0f; // Build mask from user input switch (userInput[0].toLowerCase()) { case "npc": _targetMask = MBServerStatics.MASK_NPC; break; case "mob": _targetMask = MBServerStatics.MASK_MOB; break; case "mesh": _targetMask = MBServerStatics.MASK_BUILDING; break; case "all": _targetMask = MBServerStatics.MASK_NPC | MBServerStatics.MASK_MOB | MBServerStatics.MASK_BUILDING; break; default: break; } // Parse second argument into range parameter. Cap at 200 units. _targetRange = Float.parseFloat(userInput[1]); _targetRange = Math.min(_targetRange, 200f); } }