oldObservers = getChildrenAwareness();
// 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))
System.err.println("Failed adding " + this + " to " + container);
// Observer notification
sendUpdatedContainment(oldObservers, new ArrayList<>(container.getChildrenAwareness()));
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
* @param permissions Permissions to check for
* @return
*/
public boolean hasPermission(SWGObject object, ContainerPermissions.Permission... permissions) {
if (object == null || object == this || object.getOwner() == getOwner())
return true;
for (ContainerPermissions.Permission permission : permissions) {
switch(permission) {
case VIEW:
if (!containerPermissions.canView(object, this))
return false;
break;
case MOVE:
if (!containerPermissions.canMove(object, this))
return false;
break;
case REMOVE:
if (!containerPermissions.canRemove(object, this))
return false;
break;
case ADD:
if (!containerPermissions.canAdd(object, this))
return false;
break;
case ENTER:
if (!containerPermissions.canEnter(object, this))
return false;
break;
}
}
return true;
}
/**
* Creates a new permission group for this object with the given permissions for that group
* @param group Name of the permission group
* @param permissions Permissions for the group
*/
public void addPermissions(String group, ContainerPermissions.Permission... permissions) {
containerPermissions.addPermissions(group, permissions);
}
/**
* Removes the stated permissions from the group.
* @param group Name of the permission group
* @param permissions Permissions to remove
*/
public void removePermissions(String group, ContainerPermissions.Permission... permissions) {
containerPermissions.removePermissions(group, permissions);
}
/**
* Creates a new permission group specific to the permission requester that has the defined permissions. The name of the
* new group for this object will be the objectId of this object plus the objectId of the requester.
*
This is the same as calling addPermissions(String.valueOf(permissionRequester.getObjectId() + getObjectId()), permissions)
* with the added benefit of adding the group to the permissionRequester's joined container groups
* @param permissionRequester The object that should be given unique permissions to this object
* @param permissions Permissions that the permissionRequester will have for this object
*/
public void addPermissions(SWGObject permissionRequester, ContainerPermissions.Permission... permissions) {
addPermissions(String.valueOf(permissionRequester.getObjectId() + getObjectId()), permissions);
permissionRequester.joinPermissionGroup(String.valueOf(getObjectId() + permissionRequester.getObjectId()));
}
/**
* Removes all the unique permissions for the permissionRequester from this object.
* @param permissionRequester The object that should no longer have unique permissions to this object
*/
public void removePermissions(SWGObject permissionRequester) {
String group = String.valueOf(permissionRequester.getObjectId() + getObjectId());
removePermissions(group);
permissionRequester.containerPermissions.getJoinedGroups().remove(group);
}
/**
* Assigns this object to a permission group
* @param group
*/
public void joinPermissionGroup(String group) {
containerPermissions.getJoinedGroups().add(group);
}
public void setContainerPermissions(ContainerPermissions permissions) {
this.containerPermissions = permissions;
}
public void addAttribute(String attribute, String value) {
attributes.put(attribute, value);
}
/**
* Gets the object that occupies the specified slot
* @param slotName
* @return The {@link SWGObject} occupying the slot. Returns null if there is nothing in the slot or it doesn't exist.
* If the slot doesn't exist, then an error is printed as well.
*/
public SWGObject getSlottedObject(String slotName) {
if (hasSlot(slotName))
return slots.get(slotName);
else {
System.err.println(this + " does not contain " + slotName);
return null;
}
}
/**
* Gets the object in the container with the specified objectId
* @param objectId of the {@link SWGObject} to retrieve
* @return {@link SWGObject} with the specified objectId
*/
public SWGObject getContainedObject(long objectId) {
return containedObjects.get(objectId);
}
/**
* Gets a list of all the objects in the current container. This should only be used for viewing the objects
* in the current container.
* @return An unmodifiable {@link Collection} of {@link SWGObject}'s in the container
*/
public Collection getContainedObjects() {
return Collections.unmodifiableCollection(containedObjects.values());
}
public boolean hasSlot(String slotName) {
return slots.containsKey(slotName);
}
public Map getSlots() {
return slots;
}
public void setOwner(Player player) {
this.owner = player;
}
public void setParent(SWGObject parent) {
this.parent = parent;
}
public void setLocation(Location l) {
if (l == null)
return;
location.mergeWith(l);
}
public void setLocation(double x, double y, double z) {
location.mergeLocation(x, y, z);
}
public void setStf(String stfFile, String stfKey) {
this.stf = new Stf(stfFile, stfKey);
}
public void setStf(String stf) {
this.stf = new Stf(stf);
}
public void setDetailStf(String stfFile, String stfKey) {
this.detailStf = new Stf(stfFile, stfKey);
}
public void setDetailStf(String stf) {
this.detailStf = new Stf(stf);
}
public void setTemplate(String template) {
this.template = template;
this.crc = CRC.getCrc(template);
}
public void setName(String name) {
this.objectName = name;
}
public void setVolume(int volume) {
this.volume = volume;
}
public void setComplexity(float complexity) {
this.complexity = complexity;
}
public Player getOwner() {
if (owner != null)
return owner;
if (getParent() != null)
return getParent().getOwner(); // Ziggy: Player owner is found recursively
return null;
}
public SWGObject getParent() {
return parent;
}
public Stf getStf() {
return stf;
}
public Stf getDetailStf() {
return detailStf;
}
public String getTemplate() {
return template;
}
public int getCrc() {
return crc;
}
public long getObjectId() {
return objectId;
}
public Location getLocation() {
return location;
}
public String getName() {
return objectName;
}
public int getVolume() {
return volume;
}
public float getComplexity() {
return complexity;
}
public Object getTemplateAttribute(String key) {
return templateAttributes.get(key);
}
public void setTemplateAttribute(String key, Object value) {
templateAttributes.put(key, value);
}
public List> getArrangement() {
return arrangement;
}
public void setArrangement(List> arrangement) {
this.arrangement = arrangement;
}
public String getAttribute(String attribute) {
return attributes.get(attribute);
}
public Map getAttributes() {
return attributes;
}
public int getContainerType() {
return containerType;
}
public void setContainerType(int containerType) {
this.containerType = containerType;
}
public int getSlotArrangement() {
return slotArrangement;
}
public void setSlotArrangement(int slotArrangement) {
this.slotArrangement = slotArrangement;
}
public int getMaxContainerSize() {
return Integer.valueOf(templateAttributes.get("containerVolumeLimit").toString());
}
public void setBuildout(boolean buildout) {
this.isBuildout = buildout;
}
public boolean isBuildout() {
return isBuildout;
}
public double getLoadRange() {
return loadRange;
}
public void setLoadRange(double range) {
this.loadRange = range;
}
public ContainerPermissions getContainerPermissions() { return containerPermissions; }
/**
* Gets the arrangementId for the {@link SWGObject} for the current instance
* @param object
* @return Arrangement ID for the object
*/
public int getArrangementId(SWGObject object) {
if (slots.size() == 0 || object.getArrangement() == null)
return -1;
int arrangementId = 4;
int filledId = -1;
for (List arrangementList : object.getArrangement()) {
boolean passesCompletely = true;
boolean isValid = true;
for (String slot : arrangementList) {
if (!hasSlot(slot)) {
isValid = false;
break;
} else if (slots.get(slot) != null) {
passesCompletely = false;
}
}
if (isValid && passesCompletely)
return arrangementId;
else if (isValid)
filledId = arrangementId;
arrangementId++;
}
return (filledId != -1) ? filledId : -1;
}
protected final void sendSceneCreateObject(Player target) {
SceneCreateObjectByCrc create = new SceneCreateObjectByCrc();
create.setObjectId(objectId);
create.setLocation(location);
create.setObjectCrc(crc);
target.sendPacket(create);
if (parent != null)
target.sendPacket(new UpdateContainmentMessage(objectId, parent.getObjectId(), slotArrangement));
}
protected final void sendSceneDestroyObject(Player target) {
SceneDestroyObject destroy = new SceneDestroyObject();
destroy.setObjectId(objectId);
target.sendPacket(destroy);
}
public void createObject(Player target) {
if (!hasPermission(target.getCreatureObject(), ContainerPermissions.Permission.VIEW)) {
// Log.i("SWGObject", target.getCreatureObject() + " doesn't have permission to view " + this + " -- skipping packet sending");
return;
}
sendSceneCreateObject(target);
sendBaselines(target);
createChildrenObjects(target);
target.sendPacket(new SceneEndBaselines(getObjectId()));
}
public void clearAware() {
SWGObject [] objects;
synchronized (objectsAware) {
objects = objectsAware.toArray(new SWGObject[objectsAware.size()]);
}
for (SWGObject o : objects) {
o.awarenessOutOfRange(this);
awarenessOutOfRange(o);
}
}
public List getObjectsAware() {
synchronized (objectsAware) {
return Collections.unmodifiableList(objectsAware);
}
}
public List getChildrenAwareness() {
List awareness = new ArrayList<>(objectsAware);
if (getParent() != null && !(awareness.contains(getParent())))
awareness.addAll(getParent().getObjectsAware());
if (getOwner() != null && getOwner().getCreatureObject() != null
&& !(awareness.contains(getOwner().getCreatureObject())))
awareness.add(getOwner().getCreatureObject());
return awareness;
}
public void sendObserversAndSelf(Packet ... packets) {
sendSelf(packets);
sendObservers(packets);
}
public void sendObservers(Packet ... packets) {
synchronized (objectsAware) {
for (SWGObject obj : objectsAware) {
Player p = obj.getOwner();
if (p == null || p.getPlayerState() != PlayerState.ZONED_IN)
continue;
p.sendPacket(packets);
//System.out.println("Sent " + packets + " for " + this + " to objAware " + obj);
}
List childrenAwareness = getChildrenAwareness();
childrenAwareness.removeAll(objectsAware);
childrenAwareness.remove(this); // Remove self since only observers being notified
for (SWGObject childObserver : childrenAwareness) {
if (childObserver == null || childObserver == this)
continue;
Player p = childObserver.getOwner();
if (p == null || getOwner() == p || p.getPlayerState() != PlayerState.ZONED_IN)
continue;
p.sendPacket(packets);
//System.out.println("Sent " + packets + " of " + this + " to child " + childObserver);
}
SWGObject parent = getParent();
if(parent != null) {
parent.sendObservers(packets);
//System.out.println("Sent " + packets + " to observers of " + this);
}
}
}
public void sendSelf(Packet ... packets) {
Player owner = getOwner();
if (owner != null)
owner.sendPacket(packets);
}
protected void sendBaselines(Player target) {
if (objectType == null)
return;
BaselineBuilder bb = new BaselineBuilder(this, objectType, 3);
createBaseline3(target, bb);
bb.sendTo(target);
bb = new BaselineBuilder(this, objectType, 6);
createBaseline6(target, bb);
bb.sendTo(target);
if (getOwner() == target) {
bb = new BaselineBuilder(this, objectType, 8);
createBaseline8(target, bb);
bb.sendTo(target);
bb = new BaselineBuilder(this, objectType, 9);
createBaseline9(target, bb);
bb.sendTo(target);
}
}
private void sendUpdatedContainment(List oldObservers, List newObservers) {
if (parent == null)
return;
List same = new ArrayList<>(oldObservers);
same.retainAll(newObservers);
List added = new ArrayList<>(newObservers);
added.removeAll(oldObservers);
List removed = new ArrayList<>(oldObservers);
removed.removeAll(newObservers);
for (SWGObject swgObject : same) {
swgObject.sendSelf(new UpdateContainmentMessage(objectId, parent.getObjectId(), slotArrangement));
}
for (SWGObject swgObject : added) {
if (swgObject.getOwner() != null) {
createObject(swgObject.getOwner());
}
}
for (SWGObject swgObject : removed) {
if (swgObject.getOwner() != null) {
sendSceneDestroyObject(swgObject.getOwner());
}
}
}
public void updateObjectAwareness(List withinRange) {
synchronized (objectsAware) {
List outOfRange = new ArrayList(objectsAware);
outOfRange.removeAll(withinRange);
for (SWGObject o : outOfRange)
awarenessOutOfRange(o);
for (SWGObject o : withinRange)
awarenessInRange(o);
}
}
private void awarenessOutOfRange(SWGObject o) {
synchronized (objectsAware) {
if (objectsAware.remove(o)) {
if (o.getOwner() != null) {
sendSceneDestroyObject(o.getOwner());
}
if (getOwner() != null)
o.awarenessOutOfRange(this);
}
}
}
private void awarenessInRange(SWGObject o) {
synchronized (objectsAware) {
if (!objectsAware.contains(o)) {
objectsAware.add(o);
if (o.getOwner() != null) {
createObject(o.getOwner());
}
if (getOwner() != null)
o.awarenessInRange(this);
}
}
}
public void sendDataTransforms(DataTransform dTransform) {
Location loc = dTransform.getLocation();
float speed = dTransform.getSpeed();
sendDataTransforms(loc, (byte) dTransform.getMovementAngle(), speed);
}
public void sendDataTransforms(Location loc, int direction, float speed) {
UpdateTransformsMessage transform = new UpdateTransformsMessage();
transform.setObjectId(getObjectId()); // (short) (xPosition * 4 + 0.5)
transform.setX((short) (loc.getX() * 4 + 0.5));
transform.setY((short) (loc.getY() * 4 + 0.5));
transform.setZ((short) (loc.getZ() * 4 + 0.5));
transform.setUpdateCounter(transformCounter++);
transform.setDirection((byte) direction);
transform.setSpeed(speed);
sendObserversAndSelf(transform);
}
protected void createChildrenObjects(Player target) {
if (slots.size() == 0 && containedObjects.size() == 0)
return;
List sentObjects = new ArrayList<>();
// First create the objects in the slots
for (SWGObject slotObject : slots.values()) {
if (slotObject != null && !sentObjects.contains(slotObject)) {
//Log.i("ChildrenObjects", "Sending slotObj " + slotObject + " to " + target);
slotObject.createObject(target);
sentObjects.add(slotObject);
}
}
// Now create the contained objects
for (SWGObject containedObject : containedObjects.values()) {
if (containedObject != null && !sentObjects.contains(containedObject)) {
//Log.i("ChildrenObjects", "Sending containedObj " + containedObject + " to " + target);
//Log.d("SWGObject", "Sending to location " + containedObject.getLocation());
containedObject.createObject(target);
}
}
}
@Override
public String toString() {
return "SWGObject[ID=" + objectId + " NAME=" + objectName + " TEMPLATE=" + template + "]";
}
@Override
public int compareTo(SWGObject obj) {
if (getObjectId() < obj.getObjectId())
return -1;
if (getObjectId() == obj.getObjectId())
return 0;
return 1;
}
@Override
public boolean equals(Object o) {
if (!(o instanceof SWGObject))
return false;
return getObjectId() == ((SWGObject)o).getObjectId();
}
@Override
public int hashCode() {
return Long.valueOf(getObjectId()).hashCode();
}
public void createBaseline1(Player target, BaselineBuilder bb) {
}
public void createBaseline3(Player target, BaselineBuilder bb) {
bb.addFloat(complexity); // 0
bb.addObject(stf); // 1
bb.addUnicode(objectName); // custom name -- 2
bb.addInt(volume); // 3
bb.incrementOperandCount(4);
}
public void createBaseline4(Player target, BaselineBuilder bb) {
}
public void createBaseline6(Player target, BaselineBuilder bb) {
bb.addInt(target.galaxyId); // 0
bb.addObject(detailStf); // 1
bb.incrementOperandCount(2);
}
public void createBaseline7(Player target, BaselineBuilder bb) {
}
public void createBaseline8(Player target, BaselineBuilder bb) {
}
public void createBaseline9(Player target, BaselineBuilder bb) {
}
public void sendDelta(int type, int update, Object value) {
}
public final void sendDelta(BaselineType baseline, int type, int update, Object value) {
Player owner = getOwner();
if (owner == null || (owner.getPlayerState() != PlayerState.ZONED_IN))
return;
DeltaBuilder builder = new DeltaBuilder(this, baseline, type, update, value);
builder.send();
}
public final void sendDelta(BaselineType baseline, int type, int update, Object value, StringType strType) {
Player owner = getOwner();
if (owner == null || (owner.getPlayerState() != PlayerState.ZONED_IN))
return;
DeltaBuilder builder = new DeltaBuilder(this, baseline, type, update, value, strType);
builder.send();
}
/* Baseline send permissions based on packet observations:
*
* Baseline1 sent if you have full permissions to the object.
* Baseline4 sent if you have full permissions to the object.
*
* Baseline8 sent if you have some permissions to the object.
* Baseline9 sent if you have some permissions to the object.
*
* Baseline3 always sent.
* Baseline6 always sent.
*
* Baseline7 sent on using the object.
*
* Only sent if they are defined (can still be empty if defined).
*/
}