diff --git a/src/resources/objects/SWGObject.java b/src/resources/objects/SWGObject.java index dad85f80c..b2e2e5589 100644 --- a/src/resources/objects/SWGObject.java +++ b/src/resources/objects/SWGObject.java @@ -119,7 +119,7 @@ public abstract class SWGObject extends BaselineObject implements Comparable(); + objectsAware = new HashSet<>(); buildoutArea = null; owner = null; } @@ -128,7 +128,7 @@ public abstract class SWGObject extends BaselineObject implements Comparable oldObservers = getObservers(); + Player prevOwner = (getParent() != null) ? getParent().getOwner() : null; + if (prevOwner != null) + oldObservers.add(prevOwner.getCreatureObject()); + + // Remove this object from the old parent if one exists + if (parent != null) { + parent.removeObject(this); + } + + Player newOwner = null; + if (container != null) { + if (!container.addObject(this)) + Log.e("SWGObject", "Failed adding " + this + " to " + container); + newOwner = container.getOwner(); + } + + // Observer notification + Set containerObservers = getObservers(); + if (newOwner != null) + containerObservers.add(newOwner.getCreatureObject()); + sendUpdatedContainment(oldObservers, containerObservers); + + return ContainerResult.SUCCESS; + } + + /** + * Attempts to move this object to the defined container without checking for permissions + * @param container + * @return {@link ContainerResult} + */ + public ContainerResult moveToContainer(SWGObject container) { + return moveToContainer(null, container); + } + + private ContainerResult moveToContainerChecks(SWGObject requester, SWGObject container) { if(!hasPermission(requester, ContainerPermissions.Permission.MOVE)) { return ContainerResult.NO_PERMISSION; } + if (container == null) + return ContainerResult.SUCCESS; // Check if the requester has MOVE permissions to the destination container if (!container.hasPermission(requester, ContainerPermissions.Permission.MOVE)) { @@ -196,8 +247,8 @@ public abstract class SWGObject extends BaselineObject implements Comparable 0) { + Log.w("SWGObject", "Unable to add object to container! Container Full. Max Size: %d", container.getMaxContainerSize()); return ContainerResult.CONTAINER_FULL; } } else { @@ -210,49 +261,9 @@ public abstract class SWGObject extends BaselineObject implements Comparable oldObservers = getObservers(); - Player prevOwner = getOwner(); - if (prevOwner != null) - oldObservers.add(prevOwner.getCreatureObject()); - - // Remove this object from the old parent if one exists -// SWGObject oldParent = null; - if (parent != null) { -// oldParent = parent; - parent.removeObject(this); - } - - if (!container.addObject(this)) - Log.e("SWGObject", "Failed adding " + this + " to " + container); - - // Observer notification - Player newOwner = getOwner(); - Set containerObservers = getObservers(); - if (newOwner != null) - containerObservers.add(newOwner.getCreatureObject()); - if (prevOwner != newOwner) { - if (prevOwner != null) - oldObservers.add(prevOwner.getCreatureObject()); - if (newOwner != null) - containerObservers.add(newOwner.getCreatureObject()); - } - sendUpdatedContainment(oldObservers, containerObservers); - -// Log.i("Container", "Moved %s from %s to %s", this, oldParent, container); return ContainerResult.SUCCESS; } - /** - * Attempts to move this object to the defined container without checking for permissions - * @param container - * @return {@link ContainerResult} - */ - public ContainerResult moveToContainer(SWGObject container) { - return moveToContainer(null, container); - } - /** * Checks if the passed object has all of the passed permissions * @param object Requester to view this container @@ -401,10 +412,6 @@ public abstract class SWGObject extends BaselineObject implements Comparable objects; - synchronized (objectsAware) { - objects = new ArrayList<>(objectsAware); - } + Set objects = getObjectsAware(); for (SWGObject o : objects) { - o.awarenessOutOfRange(this, updateSelf); - awarenessOutOfRange(o, true); + o.awarenessOutOfRange(this, true); + awarenessOutOfRange(o, updateSelf); } } public Set getObjectsAware() { + Set aware; synchronized (objectsAware) { - return Collections.unmodifiableSet(objectsAware); + aware = new HashSet<>(objectsAware); } + if (parent != null) { + aware.addAll(parent.getObjectsAware()); + aware.add(getSuperParent()); + } + return aware; + } + + private boolean isAware(SWGObject obj) { + if (equals(obj)) + return true; + synchronized (objectsAware) { + if (objectsAware.contains(obj)) + return true; + } + if (parent != null) + return parent.isAware(obj); + return false; } public Set getObservers() { @@ -740,19 +772,13 @@ public abstract class SWGObject extends BaselineObject implements Comparable getObservers(Player owner, boolean initial) { - Set nearby = new HashSet<>(); + Set nearby; synchronized (containedObjects) { - nearby.addAll(containedObjects.values()); + nearby = new HashSet<>(containedObjects.values()); } if (initial) { - synchronized (objectsAware) { - nearby.addAll(objectsAware); - } + nearby.addAll(getObjectsAware()); } - return getObserversFromSet(nearby, owner); - } - - private Set getObserversFromSet(Set nearby, Player owner) { Set observers = new HashSet<>(); for (SWGObject aware : nearby) { if (aware instanceof CreatureObject) { @@ -796,27 +822,17 @@ public abstract class SWGObject extends BaselineObject implements Comparable oldObservers, Set newObservers) { - if (parent == null) - return; - Set same = new HashSet<>(oldObservers); - same.retainAll(newObservers); - - Set added = new HashSet<>(newObservers); - added.removeAll(oldObservers); - - Set removed = new HashSet<>(oldObservers); - removed.removeAll(newObservers); - - for (SWGObject swgObject : same) { - swgObject.getOwner().sendPacket(new UpdateContainmentMessage(objectId, parent.getObjectId(), slotArrangement)); + long newId = (parent == null) ? 0 : parent.getObjectId(); + for (SWGObject swgObject : oldObservers) { + if (newObservers.contains(swgObject)) + swgObject.getOwner().sendPacket(new UpdateContainmentMessage(objectId, newId, slotArrangement)); + else + destroyObject(swgObject.getOwner()); } - for (SWGObject swgObject : added) { - createObject(swgObject.getOwner()); - } - - for (SWGObject swgObject : removed) { - destroyObject(swgObject.getOwner()); + for (SWGObject swgObject : newObservers) { + if (!oldObservers.contains(swgObject)) + createObject(swgObject.getOwner()); } } @@ -825,45 +841,47 @@ public abstract class SWGObject extends BaselineObject implements Comparable(objectsAware); } - outOfRange.addAll(getObservers()); - Set observers = getObserversFromSet(withinRange, getOwner()); - outOfRange.removeAll(withinRange); - outOfRange.removeAll(observers); + if (outOfRange.contains(this)) { + Log.e("SWGObject", "outOfRange contains this"); + } + if (withinRange.contains(this)) { + Log.e("SWGObject", "withinRange contains this"); + } for (SWGObject o : outOfRange) { - awarenessOutOfRange(o, true); - o.awarenessOutOfRange(this, true); + if (!withinRange.contains(o)) { + awarenessOutOfRange(o, true); + o.awarenessOutOfRange(this, true); + } } for (SWGObject o : withinRange) { - awarenessInRange(o, true); - o.awarenessInRange(this, true); - } - for (SWGObject o : observers) { - awarenessInRange(o, true); - o.awarenessInRange(this, true); + if (!outOfRange.contains(o)) { + awarenessInRange(o, true); + o.awarenessInRange(this, true); + } } } protected void awarenessOutOfRange(SWGObject o, boolean sendDestroy) { - boolean success = false; + boolean success = isAware(o); synchronized (objectsAware) { - success = objectsAware.remove(o); + success = objectsAware.remove(o) && success; } if (success && sendDestroy) { - Player owner = o.getOwner(); + Player owner = getOwner(); if (owner != null) - destroyObject(owner); + o.destroyObject(owner); } } protected void awarenessInRange(SWGObject o, boolean sendCreate) { - boolean success = false; + boolean success = !isAware(o); synchronized (objectsAware) { - success = objectsAware.add(o); + success = objectsAware.add(o) && success; } if (success && sendCreate) { - Player owner = o.getOwner(); + Player owner = getOwner(); if (owner != null) - createObject(owner); + o.createObject(owner); } } diff --git a/src/resources/objects/building/BuildingObject.java b/src/resources/objects/building/BuildingObject.java index 6469a54cb..f7374d7e1 100644 --- a/src/resources/objects/building/BuildingObject.java +++ b/src/resources/objects/building/BuildingObject.java @@ -82,7 +82,7 @@ public class BuildingObject extends TangibleObject { } @Override - public boolean addObject(SWGObject object) { + protected boolean addObject(SWGObject object) { boolean added = super.addObject(object); if (!added || !(object instanceof CellObject)) return added; diff --git a/src/resources/objects/buildouts/TerrainBuildoutLoader.java b/src/resources/objects/buildouts/TerrainBuildoutLoader.java index b6d7ec330..b6885b6ae 100644 --- a/src/resources/objects/buildouts/TerrainBuildoutLoader.java +++ b/src/resources/objects/buildouts/TerrainBuildoutLoader.java @@ -112,12 +112,9 @@ class TerrainBuildoutLoader { objectTable.put(object.getObjectId(), object); if (containerId != 0) { SWGObject container = objectTable.get(containerId); - if (container != null) - container.addObject(object); - else { + object.moveToContainer(container); + if (container == null) Log.e("TerrainBuildoutLoader", "Failed to load object: " + object.getTemplate()); -// objects.add(object); - } } else { List list = objects.get(areaName); if (list == null) { diff --git a/src/resources/objects/buildouts/TerrainSnapshotLoader.java b/src/resources/objects/buildouts/TerrainSnapshotLoader.java index 92e20f8f0..698103087 100644 --- a/src/resources/objects/buildouts/TerrainSnapshotLoader.java +++ b/src/resources/objects/buildouts/TerrainSnapshotLoader.java @@ -102,11 +102,9 @@ public class TerrainSnapshotLoader { objectTable.put(object.getObjectId(), object); if (containerId != 0) { SWGObject container = objectTable.get(containerId); - if (container != null) - container.addObject(object); - else { + object.moveToContainer(container); + if (container == null) Log.e("TerrainSnapshotLoader", "Failed to load object: " + object.getTemplate()); - } } else { objects.add(object); } diff --git a/src/services/faction/FactionService.java b/src/services/faction/FactionService.java index 1427e00d0..d57cc68f4 100644 --- a/src/services/faction/FactionService.java +++ b/src/services/faction/FactionService.java @@ -164,32 +164,32 @@ public final class FactionService extends Service { } private void handleFlagChange(TangibleObject object) { - Player objOwner = object.getOwner(); - for (SWGObject o : object.getObservers()) { - if (!(o instanceof TangibleObject)) - continue; - TangibleObject observer = (TangibleObject) o; - Player obsOwner = observer.getOwner(); - int pvpBitmask = 0; - - // They CAN be enemies if they're not from the same faction and neither of them are neutral - if (object.getPvpFaction() != observer.getPvpFaction() && observer.getPvpFaction() != PvpFaction.NEUTRAL) { - if (object.getPvpStatus() == PvpStatus.SPECIALFORCES && observer.getPvpStatus() == PvpStatus.SPECIALFORCES) { - pvpBitmask |= PvpFlag.AGGRESSIVE.getBitmask() | PvpFlag.ATTACKABLE.getBitmask(); - } - } - UpdatePvpStatusMessage objectPacket = createPvpStatusMessage(object, observer, object.getPvpFlags() | pvpBitmask); - UpdatePvpStatusMessage targetPacket = createPvpStatusMessage(object, observer, observer.getPvpFlags() | pvpBitmask); - if (objOwner != null) - objOwner.sendPacket(objectPacket, targetPacket); - if (obsOwner != null) - obsOwner.sendPacket(objectPacket); - } +// Player objOwner = object.getOwner(); +// for (SWGObject o : object.getObservers()) { +// if (!(o instanceof TangibleObject)) +// continue; +// TangibleObject observer = (TangibleObject) o; +// Player obsOwner = observer.getOwner(); +// int pvpBitmask = 0; +// +// // They CAN be enemies if they're not from the same faction and neither of them are neutral +// if (object.getPvpFaction() != observer.getPvpFaction() && observer.getPvpFaction() != PvpFaction.NEUTRAL) { +// if (object.getPvpStatus() == PvpStatus.SPECIALFORCES && observer.getPvpStatus() == PvpStatus.SPECIALFORCES) { +// pvpBitmask |= PvpFlag.AGGRESSIVE.getBitmask() | PvpFlag.ATTACKABLE.getBitmask(); +// } +// } +// UpdatePvpStatusMessage objectPacket = createPvpStatusMessage(object, observer, object.getPvpFlags() | pvpBitmask); +// UpdatePvpStatusMessage targetPacket = createPvpStatusMessage(object, observer, observer.getPvpFlags() | pvpBitmask); +// if (objOwner != null) +// objOwner.sendPacket(objectPacket, targetPacket); +// if (obsOwner != null) +// obsOwner.sendPacket(objectPacket); +// } } - private UpdatePvpStatusMessage createPvpStatusMessage(TangibleObject object, TangibleObject observer, int flags) { - Set flagSet = PvpFlag.getFlags(object.getPvpFlags()); - return new UpdatePvpStatusMessage(object.getPvpFaction(), object.getObjectId(), flagSet.toArray(new PvpFlag[flagSet.size()])); - } +// private UpdatePvpStatusMessage createPvpStatusMessage(TangibleObject object, TangibleObject observer, int flags) { +// Set flagSet = PvpFlag.getFlags(object.getPvpFlags()); +// return new UpdatePvpStatusMessage(object.getPvpFaction(), object.getObjectId(), flagSet.toArray(new PvpFlag[flagSet.size()])); +// } } \ No newline at end of file diff --git a/src/services/objects/ClientBuildoutService.java b/src/services/objects/ClientBuildoutService.java index c7e77b6b8..afe82e0fa 100644 --- a/src/services/objects/ClientBuildoutService.java +++ b/src/services/objects/ClientBuildoutService.java @@ -132,7 +132,7 @@ public class ClientBuildoutService extends Service { private void checkChild(Map objects, SWGObject obj, long container) { if (container != 0) - objects.get(container).addObject(obj); + obj.moveToContainer(objects.get(container)); } private List getEvents() { diff --git a/src/services/objects/ObjectAwareness.java b/src/services/objects/ObjectAwareness.java index 2344f73df..18d2d7241 100644 --- a/src/services/objects/ObjectAwareness.java +++ b/src/services/objects/ObjectAwareness.java @@ -33,7 +33,6 @@ import intents.network.GalacticPacketIntent; import intents.object.MoveObjectIntent; import intents.object.ObjectCreatedIntent; import intents.object.ObjectTeleportIntent; -import intents.object.UpdateObjectAwareness; import intents.player.PlayerTransformedIntent; import java.util.HashMap; @@ -45,7 +44,6 @@ import java.util.Set; import main.ProjectSWG; import network.packets.Packet; import network.packets.swg.zone.CmdSceneReady; -import network.packets.swg.zone.UpdateContainmentMessage; import network.packets.swg.zone.object_controller.DataTransform; import network.packets.swg.zone.object_controller.DataTransformWithParent; import resources.Location; @@ -73,7 +71,6 @@ public class ObjectAwareness extends Service { registerForIntent(ObjectCreatedIntent.TYPE); registerForIntent(ObjectTeleportIntent.TYPE); registerForIntent(GalacticPacketIntent.TYPE); - registerForIntent(UpdateObjectAwareness.TYPE); registerForIntent(MoveObjectIntent.TYPE); loadQuadTree(); } @@ -97,10 +94,6 @@ public class ObjectAwareness extends Service { if (i instanceof GalacticPacketIntent) processGalacticPacketIntent((GalacticPacketIntent) i); break; - case UpdateObjectAwareness.TYPE: - if (i instanceof UpdateObjectAwareness) - processUpdateObjectAwarenessIntent((UpdateObjectAwareness) i); - break; case MoveObjectIntent.TYPE: if (i instanceof MoveObjectIntent) processMoveObjectIntent((MoveObjectIntent) i); @@ -172,25 +165,6 @@ public class ObjectAwareness extends Service { } } - private void processUpdateObjectAwarenessIntent(UpdateObjectAwareness i) { - SWGObject obj = i.getObject(); - Location l = obj.getLocation(); - QuadTree tree = getTree(l); - List objects; - synchronized (tree) { - objects = tree.get(l.getX(), l.getZ()); - } - if (objects.contains(obj)) { - if (!i.isInAwareness()) { - remove(obj); - obj.clearAware(false); - } - return; - } - add(obj); - update(obj); - } - private void processMoveObjectIntent(MoveObjectIntent i) { if (i.getParent() != null) processMoveObjectIntentParent(i); @@ -333,8 +307,7 @@ public class ObjectAwareness extends Service { */ private void move(SWGObject object, Location nLocation, boolean update) { if (object.getParent() != null) { - object.getParent().removeObject(object); // Moving from cell to world - object.sendObserversAndSelf(new UpdateContainmentMessage(object.getObjectId(), 0, object.getSlotArrangement())); + object.moveToContainer(null); } else { remove(object); // World to World } @@ -356,16 +329,14 @@ public class ObjectAwareness extends Service { private void move(SWGObject object, SWGObject nParent, Location nLocation) { SWGObject parent = object.getParent(); if (parent != null && nParent != parent) { - parent.removeObject(object); // Moving from cell to cell, for instance + object.moveToContainer(null); } else if (parent == null) { remove(object); // Moving from world to cell } if (object.getParent() == null) { // Should have been updated in removeObject() - nParent.addObject(object); // If necessary, add to new cell - object.sendObserversAndSelf(new UpdateContainmentMessage(object.getObjectId(), nParent.getObjectId(), object.getSlotArrangement())); + object.moveToContainer(nParent); } object.setLocation(nLocation); - object.clearAware(false); } /** @@ -394,8 +365,7 @@ public class ObjectAwareness extends Service { private void moveFromOld(SWGObject object, Location oldLocation, boolean update) { if (object.getParent() != null) { - object.getParent().removeObject(object); // Moving from cell to world - object.sendObserversAndSelf(new UpdateContainmentMessage(object.getObjectId(), 0, object.getSlotArrangement())); + object.moveToContainer(null); } else { removeFromLocation(object, oldLocation); // World to World } diff --git a/src/services/objects/ObjectManager.java b/src/services/objects/ObjectManager.java index a793e5040..18e72bfce 100644 --- a/src/services/objects/ObjectManager.java +++ b/src/services/objects/ObjectManager.java @@ -150,13 +150,10 @@ public class ObjectManager extends Manager { if (obj.getParent() != null) { if (!obj.getParent().isGenerated()) { long id = obj.getParent().getObjectId(); - obj.getParent().removeObject(obj); SWGObject parent = getObjectById(id); - if (parent != null) - parent.addObject(obj); - else { + obj.moveToContainer(parent); + if (parent == null) Log.e("ObjectManager", "Parent for %s is null! ParentID: %d", obj, id); - } } else { updateBuildoutParent(obj.getParent()); } @@ -313,7 +310,7 @@ public class ObjectManager extends Manager { } object.sendObserversAndSelf(new SceneDestroyObject(objId)); - parent.removeObject(object); + object.moveToContainer(null); } else { object.sendObservers(new SceneDestroyObject(objId)); } @@ -355,9 +352,7 @@ public class ObjectManager extends Manager { return null; } obj.setLocation(l); - if (parent != null) { - parent.addObject(obj); - } + obj.moveToContainer(parent); synchronized (database) { if (addToDatabase) { database.put(obj.getObjectId(), obj); diff --git a/src/services/player/CharacterCreationService.java b/src/services/player/CharacterCreationService.java index 5385da8cf..aeb3d98c5 100644 --- a/src/services/player/CharacterCreationService.java +++ b/src/services/player/CharacterCreationService.java @@ -313,10 +313,10 @@ public class CharacterCreationService extends Service { createStarterClothing(objManager, creatureObj, create.getRace(), create.getClothes()); creatureObj.setVolume(0x000F4240); - creatureObj.setOwner(player); - creatureObj.addObject(playerObj); // ghost slot + playerObj.moveToContainer(creatureObj); // ghost slot playerObj.setAdminTag(player.getAccessLevel()); + creatureObj.setOwner(player); player.setCreatureObject(creatureObj); new SkillBoxGrantedIntent(create.getStartingPhase(), creatureObj).broadcast(); return creatureObj.getObjectId(); @@ -350,7 +350,7 @@ public class CharacterCreationService extends Service { return null; } SWGObject obj = objManager.createObject(template, info.location); - cell.addObject(obj); + obj.moveToContainer(cell); if (obj instanceof CreatureObject) return (CreatureObject) obj; return null; @@ -382,7 +382,7 @@ public class CharacterCreationService extends Service { TangibleObject hairObj = createTangible(objManager, ClientFactory.formatToSharedFile(hair)); hairObj.setAppearanceData(customization); - creatureObj.addObject(hairObj); // slot = hair + hairObj.moveToContainer(creatureObj); // hair slot creatureObj.addEquipment(hairObj); } diff --git a/src/services/spawn/SpawnerService.java b/src/services/spawn/SpawnerService.java index 61fa12e52..5b5e38ee2 100644 --- a/src/services/spawn/SpawnerService.java +++ b/src/services/spawn/SpawnerService.java @@ -164,7 +164,7 @@ public final class SpawnerService extends Service { DefaultAIObject object = ObjectCreator.createObjectFromTemplate(createTemplate(getRandomIff(set.getString("iff"))), DefaultAIObject.class); object.setLocation(loc); if (parent != null) - parent.addObject(object); + object.moveToContainer(parent); object.setName(getCreatureName(name)); object.setLevel((short) set.getInt("combat_level")); object.setDifficulty(difficulty); diff --git a/src/services/spawn/StaticService.java b/src/services/spawn/StaticService.java index 48629536a..fe85e8b7e 100644 --- a/src/services/spawn/StaticService.java +++ b/src/services/spawn/StaticService.java @@ -147,9 +147,8 @@ public class StaticService extends Service { Location loc = new Location(x, y, z, parent.getTerrain()); loc.setHeading(heading); SWGObject obj = ObjectCreator.createObjectFromTemplate(iff); - obj.setParent(parent); obj.setLocation(loc); - parent.addObject(obj); + obj.moveToContainer(parent); new ObjectCreatedIntent(obj).broadcast(); return obj; } diff --git a/test/resources/control/TestIntentQueue.java b/test/resources/control/TestIntentQueue.java index 31afcf1e5..5b23c66eb 100644 --- a/test/resources/control/TestIntentQueue.java +++ b/test/resources/control/TestIntentQueue.java @@ -6,7 +6,6 @@ import intents.LoginEventIntent; import intents.PlayerEventIntent; import intents.object.ObjectCreatedIntent; import intents.object.ObjectTeleportIntent; -import intents.object.UpdateObjectAwareness; import org.junit.Assert; import org.junit.Test; @@ -21,7 +20,7 @@ public class TestIntentQueue { Intent [] intents = new Intent[5]; intents[0] = new PlayerEventIntent(null, null); intents[1] = new ObjectTeleportIntent(null, null); - intents[2] = new UpdateObjectAwareness(null, false); + intents[2] = new ObjectCreatedIntent(null); intents[3] = new ObjectCreatedIntent(null); intents[4] = new LoginEventIntent(0, null); IntentQueue queue = new IntentQueue();