|
|
|
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<AbstractWorldObject> 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);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|