From 4af510f6360b6b17beac5e854c1d6cd89502d20a Mon Sep 17 00:00:00 2001 From: Waverunner Date: Mon, 25 May 2015 17:59:07 -0400 Subject: [PATCH 1/3] Refactored slots to not require a slot name and added in foundation for containers --- src/resources/objects/SWGObject.java | 285 ++++++++++-------- .../buildouts/TerrainBuildoutLoader.java | 9 +- .../objects/creature/CreatureObject.java | 35 --- src/resources/slots/ContainmentSlot.java | 64 ++++ src/resources/slots/Slot.java | 55 ++++ src/services/objects/ObjectCreator.java | 51 +++- src/services/objects/ObjectManager.java | 43 ++- src/services/player/ZoneService.java | 22 +- 8 files changed, 365 insertions(+), 199 deletions(-) create mode 100644 src/resources/slots/ContainmentSlot.java create mode 100644 src/resources/slots/Slot.java diff --git a/src/resources/objects/SWGObject.java b/src/resources/objects/SWGObject.java index d885200ce..9ffb8ec9c 100644 --- a/src/resources/objects/SWGObject.java +++ b/src/resources/objects/SWGObject.java @@ -30,14 +30,8 @@ package resources.objects; import java.io.IOException; import java.io.ObjectInputStream; import java.io.Serializable; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.LinkedList; +import java.util.*; import java.util.List; -import java.util.Map; -import java.util.Vector; import network.packets.Packet; import network.packets.swg.zone.SceneCreateObjectByCrc; @@ -54,21 +48,23 @@ import resources.network.BaselineBuilder; import resources.network.DeltaBuilder; import resources.player.Player; import resources.player.PlayerState; +import resources.server_info.Log; import utilities.Encoder.StringType; public class SWGObject implements Serializable, Comparable { private static final long serialVersionUID = 1L; - - private final List children; // TODO Move this into slot-type system as only containers can have multiple children in 1 slot + private final Location location; private final long objectId; - private final Map slots; // Can only be occupied one time, containers are slots who have children + private final HashMap slots; // HashMap used for null value support + private final Map containedObjects; private final Map attributes; private final Map templateAttributes; private transient List objectsAware; private List > arrangement; - + private List descriptor; // TODO Remove this as slots can be used? + private Player owner = null; private SWGObject parent = null; private Stf stf = new Stf("", ""); @@ -76,9 +72,12 @@ public class SWGObject implements Serializable, Comparable { private String template = ""; private int crc = 0; private String objectName = ""; - private int volume = 0; // applies to containers only + private int volume = 0; private float complexity = 1; - private int containmentType = 4; + private int containerType = 0; + + private int slotArrangement = -1; + private int transformCounter = 0; public SWGObject() { @@ -88,9 +87,9 @@ public class SWGObject implements Serializable, Comparable { public SWGObject(long objectId) { this.objectId = objectId; this.location = new Location(); - this.children = new Vector(); this.objectsAware = new Vector(); - this.slots = new HashMap(); // Concurrent maps wont allow for null keys/values, which is what the empty slots are set to :/ + this.slots = new HashMap<>(); + this.containedObjects = Collections.synchronizedMap(new HashMap()); this.attributes = new LinkedHashMap(); this.templateAttributes = new HashMap(); } @@ -99,115 +98,101 @@ public class SWGObject implements Serializable, Comparable { ois.defaultReadObject(); objectsAware = new LinkedList(); } - - // TODO: Use a "transfer" method for switching objects between parents, this will also check volume limits - public void addChild(SWGObject object) { - synchronized (children) { - if (!children.contains(object)) - children.add(object); + + /** + * Adds the specified object to this object and places it in the appropriate slot if needed + * @param object + */ + public void addObject(SWGObject object) { + // If the arrangement is -1, then this object will be a contained object + int arrangementId = getArrangementId(object); + if (arrangementId == -1) { + containedObjects.put(object.getObjectId(), object); + object.parent = this; + return; } - updateContainment(object); + // Not a child object, so time to check the slots! + + // Check to make sure this object is able to go into a slot in the parent + List requiredSlots = object.getArrangement().get(0); + // Note that some objects don't have a descriptor, meaning it has no slots + if (descriptor != null && !descriptor.containsAll(requiredSlots)) + return; + + // Add object to the slot + for (String requiredSlot : requiredSlots) { + slots.put(requiredSlot, object); + } + + object.parent = this; + object.slotArrangement = arrangementId; } - - private void updateContainment(SWGObject child) { - if (child.parent != null) - child.parent.removeChild(child); // Is this necessary? - child.parent = this; - Integer containmentType = (Integer)child.getTemplateAttribute("containerType"); - if (containmentType == null) - child.containmentType = 4; - else - child.containmentType = containmentType; - // TODO: Set containmentType based on if object is in a slot (4) or a container (-1) - sendObserversAndSelf(new UpdateContainmentMessage(child.objectId, objectId, containmentType)); + + /** + * Moves the current object to the target object + * @param requester Object that is requesting to move the object, used for permission checking + * @param target Where this object should be moved to + */ + public void moveToContainer(SWGObject requester, SWGObject target) { + Log.d("Slots", "Attempting to move %s to %s", this, target); + + + // TODO Update the observers in the new object + + // TODO Return an enum for a container error? } - + + // TODO: Use a "transfer" method for switching objects between parents, this will also check volume limits + public void addAttribute(String attribute, String value) { attributes.put(attribute, value); } - - public void addObjectSlot(String name, SWGObject object) { - synchronized (slots) { - slots.put(name, object); - } - } - - public SWGObject getSlottedObject(String slot) { - if (!slots.containsKey(slot)) { - System.err.println(getTemplate() + " doesn't contain slot " + slot + "!"); + + /** + * 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; } - - return slots.get(slot); - } - - public boolean hasSlot(String slot) { - return slots.containsKey(slot); } - // TODO Refactor slots to just be used in addChild and removeChild as the proper slots can be set by using arrangement descriptors - - public boolean setSlot(String slot, SWGObject obj) { - if (!slots.containsKey(slot)) { - System.err.println("Could not set " + obj.getTemplate() + " to " + getTemplate() + " as it doesn't contain slot " + slot + "!"); - return false; - } - - List occupiedAvailSlots = new ArrayList(); - List arrangement = obj.getArrangement().get(0); // We only care about the main list here, not the children lists - for (String occupies : arrangement) { - if (hasSlot(occupies)) - occupiedAvailSlots.add(slot); - else - break; - } - - if (occupiedAvailSlots.size() != arrangement.size()) { - System.err.println("Needed slots are not available for " + obj); - return false; - } - - for (String availSlot : occupiedAvailSlots) { - obj.setParent(this); - addObjectSlot(availSlot, obj); - sendObserversAndSelf(new UpdateContainmentMessage(obj.objectId, objectId, containmentType)); - } - - return true; + /** + * 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); } - private void clearSlot(String slot) { - if (!slots.containsKey(slot)) { - System.err.println("Could not clear " + slot + " as it doesn't contain that slot!"); - return; - } - - synchronized(slots) { - slots.put(slot, null); - } + /** + * 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()); } - - // TODO: Use a "transfer" method for switching objects between parents, this will also check volume limits - public void removeChild(SWGObject object) { - synchronized (children) { - children.remove(object); - } - for (String slot : object.getArrangement().get(0)) { - clearSlot(slot); - } + public boolean hasSlot(String slotName) { + return slots.containsKey(slotName); + } - object.parent = null; + public List getAvailableSlots() { + return Collections.unmodifiableList(descriptor); } - - public Map getSlots() { - return new HashMap(slots); + + public Map getSlots() { + return slots; } - - public List getChildren() { - return new ArrayList(children); - } - + public void setOwner(Player player) { this.owner = player; } @@ -262,7 +247,8 @@ public class SWGObject implements Serializable, Comparable { public Player getOwner() { if (owner != null) return owner; - + + // TODO getOwner() should also search for the "master" container that has a PlayerObject if (getParent() != null) return getParent().getOwner(); // Ziggy: Player owner is found recursively @@ -312,7 +298,7 @@ public class SWGObject implements Serializable, Comparable { public Object getTemplateAttribute(String key) { return templateAttributes.get(key); } - + public void setTemplateAttribute(String key, Object value) { templateAttributes.put(key, value); } @@ -332,15 +318,70 @@ public class SWGObject implements Serializable, Comparable { 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()); + } + + /** + * 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 (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; + } + if (slots.get(slot) != null) { + passesCompletely = false; + } + } + if (isValid && passesCompletely) + return arrangementId; + else if (isValid) + filledId = arrangementId; + + arrangementId++; + } + return (filledId != -1) ? arrangementId : 4; + } + protected final void sendSceneCreateObject(Player target) { SceneCreateObjectByCrc create = new SceneCreateObjectByCrc(); create.setObjectId(objectId); create.setLocation(location); create.setObjectCrc(crc); target.sendPacket(create); + // TODO: Move this to createChildrenObjects? if (parent != null) - target.sendPacket(new UpdateContainmentMessage(objectId, parent.getObjectId(), containmentType)); + target.sendPacket(new UpdateContainmentMessage(objectId, parent.getObjectId(), slotArrangement)); } @@ -352,8 +393,7 @@ public class SWGObject implements Serializable, Comparable { protected void createObject(Player target) { sendSceneCreateObject(target); - //if (target.getCreatureObject().getOwner() == getOwner()) //TODO: Update for view permissions - createChildrenObjects(target); + createChildrenObjects(target); target.sendPacket(new SceneEndBaselines(getObjectId())); } @@ -457,15 +497,18 @@ public class SWGObject implements Serializable, Comparable { } protected void createChildrenObjects(Player target) { - for (SWGObject child : children) { - child.createObject(target); + // TODO Permission check for the target + + // First create the objects in the slots + for (SWGObject slotObject : slots.values()) { + if (slotObject != null) + slotObject.createObject(target); } - // TODO: We will need permission checks here in the future which will create the object based on another players permissions to view that slot. - for (SWGObject slotEntry : slots.values()) { - if (slotEntry == null) - continue; - - slotEntry.createObject(target); + + // Now create the contained objects + for (SWGObject containedObject : containedObjects.values()) { + if (containedObject != null) + containedObject.createObject(target); } } diff --git a/src/resources/objects/buildouts/TerrainBuildoutLoader.java b/src/resources/objects/buildouts/TerrainBuildoutLoader.java index 358d44047..4bd383af1 100644 --- a/src/resources/objects/buildouts/TerrainBuildoutLoader.java +++ b/src/resources/objects/buildouts/TerrainBuildoutLoader.java @@ -95,13 +95,14 @@ class TerrainBuildoutLoader { } private void finalizeCells() { + // TODO This will need to be re-looked at since the slot update for (Entry > entry : buildingCells.entrySet()) { SWGObject building = objectTable.get(entry.getKey()); if (building == null) continue; List cells = entry.getValue(); for (CellObject cell : cells) { - building.addChild(cell); + building.addObject(cell); } cells.clear(); } @@ -178,6 +179,7 @@ class TerrainBuildoutLoader { } private void matchParent(SWGObject obj, long containerId) { + // TODO This will need to be relooked at since the slot update if (containerId == 0) { obj.setLocation(obj.getLocation().translate(areaLocation)); objects.add(obj); @@ -187,18 +189,19 @@ class TerrainBuildoutLoader { if (container == null) { parentless.add(new Orphan(obj, containerId)); } else { - container.addChild(obj); + container.addObject(obj); objects.add(obj); } } private void updateParentless() { + // TODO This will need to be relooked at since the slot update Iterator orphanIt = parentless.iterator(); while (orphanIt.hasNext()) { Orphan orphan = orphanIt.next(); SWGObject container = objectTable.get(orphan.getContainer()); if (container != null) { - container.addChild(orphan.getObject()); + container.addObject(orphan.getObject()); orphanIt.remove(); } } diff --git a/src/resources/objects/creature/CreatureObject.java b/src/resources/objects/creature/CreatureObject.java index 5b2222ea3..080bc04b8 100644 --- a/src/resources/objects/creature/CreatureObject.java +++ b/src/resources/objects/creature/CreatureObject.java @@ -112,41 +112,6 @@ public class CreatureObject extends TangibleObject { initCurrentAttributes(); initBaseAttributes(); } - - /** - * It is only recommended that this method be used when you have - * an item and you won't know which slots it will occupy until you've - * looped through the arrangement list that resides within SWGObject. - * - * If you know the slot which your object is supposed to occupy, it's - * recommended that you instead use setSlot(), effectively skipping - * the process of looping. - * - * @param item to equip - */ - public void equipItem(TangibleObject item) { - equipItemToContainer(item, this); - } - - public void equipAppearanceItem(TangibleObject item) { - equipItemToContainer(item, super.getSlottedObject("appearance_inventory")); - } - - public void unequipAppearanceItem(TangibleObject item) { - unequipItemFromContainer(item, super.getSlottedObject("appearance_inventory")); - } - - private void equipItemToContainer(TangibleObject item, SWGObject container) { - for(List slotNameList : item.getArrangement()) - for(String slotName : slotNameList) - container.setSlot(slotName, item); - } - - private void unequipItemFromContainer(TangibleObject item, SWGObject container) { - for(List slotNameList : item.getArrangement()) - for(String slotName : slotNameList) - container.setSlot(slotName, null); - } public void removeEquipment(SWGObject obj) { synchronized (equipmentList) { diff --git a/src/resources/slots/ContainmentSlot.java b/src/resources/slots/ContainmentSlot.java new file mode 100644 index 000000000..0481ad2c4 --- /dev/null +++ b/src/resources/slots/ContainmentSlot.java @@ -0,0 +1,64 @@ +/******************************************************************************* + * Copyright (c) 2015 /// Project SWG /// www.projectswg.com + * + * ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on + * July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. + * Our goal is to create an emulator which will provide a server for players to + * continue playing a game similar to the one they used to play. We are basing + * it on the final publish of the game prior to end-game events. + * + * This file is part of Holocore. + * + * -------------------------------------------------------------------------------- + * + * Holocore is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * Holocore is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Holocore. If not, see + ******************************************************************************/ + +package resources.slots; + +import resources.objects.SWGObject; + +public class ContainmentSlot extends Slot { + private volatile SWGObject object; + + public ContainmentSlot(String name) { + super(name); + } + + @Override + public boolean isEmpty() { + return (object == null); + } + + @Override + public SWGObject getObject() { + return object; + } + + @Override + public void insert(SWGObject object) { + this.object = object; + } + + @Override + public void remove(SWGObject object) { + if (this.object == object) + this.object = null; + } + + @Override + public void clear() { + this.object = null; + } +} diff --git a/src/resources/slots/Slot.java b/src/resources/slots/Slot.java new file mode 100644 index 000000000..2b8e12b4a --- /dev/null +++ b/src/resources/slots/Slot.java @@ -0,0 +1,55 @@ +/******************************************************************************* + * Copyright (c) 2015 /// Project SWG /// www.projectswg.com + * + * ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on + * July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. + * Our goal is to create an emulator which will provide a server for players to + * continue playing a game similar to the one they used to play. We are basing + * it on the final publish of the game prior to end-game events. + * + * This file is part of Holocore. + * + * -------------------------------------------------------------------------------- + * + * Holocore is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * Holocore is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Holocore. If not, see + ******************************************************************************/ + +package resources.slots; + +import resources.objects.SWGObject; + +public abstract class Slot { + protected final String name; + + public Slot(String name) { + this.name = name; + } + + public abstract boolean isEmpty(); + + public abstract SWGObject getObject(); + + public abstract void insert(SWGObject object); + public abstract void remove(SWGObject object); + public abstract void clear(); + + public final String getName() { + return name; + } + + @Override + public String toString() { + return getName(); + } +} diff --git a/src/services/objects/ObjectCreator.java b/src/services/objects/ObjectCreator.java index bbc130a2a..e940022a4 100644 --- a/src/services/objects/ObjectCreator.java +++ b/src/services/objects/ObjectCreator.java @@ -48,6 +48,7 @@ import resources.objects.staticobject.StaticObject; import resources.objects.tangible.TangibleObject; import resources.objects.waypoint.WaypointObject; import resources.objects.weapon.WeaponObject; +import resources.server_info.Log; public final class ObjectCreator { @@ -61,8 +62,9 @@ public final class ObjectCreator { SWGObject obj = createObjectFromType(objectId, getFirstTemplatePart(template.substring(7, template.length()-7-4))); if (obj == null) return null; - addObjectAttributes(obj, template); obj.setTemplate(template); + + handlePostCreation(obj); return obj; } @@ -85,10 +87,15 @@ public final class ObjectCreator { } return null; } - + + private static void handlePostCreation(SWGObject object) { + addObjectAttributes(object, object.getTemplate()); + createObjectSlots(object); + } + private static void addObjectAttributes(SWGObject obj, String template) { ObjectData attributes = (ObjectData) clientFac.getInfoFromFile(ClientFactory.formatToSharedFile(template)); - + String stf = (String) attributes.getAttribute(ObjectData.OBJ_STF); String detailStf = (String) attributes.getAttribute(ObjectData.DETAIL_STF); Integer volumeLimit = (Integer) attributes.getAttribute(ObjectData.VOLUME_LIMIT); @@ -100,28 +107,40 @@ public final class ObjectCreator { obj.setVolume(volumeLimit); for (Entry e : attributes.getAttributes().entrySet()) { obj.setTemplateAttribute(e.getKey(), e.getValue()); + + setObjectAttribute(e.getKey(), e.getValue().toString(), obj); } - - addSlotsToObject(obj, attributes); } - - private static void addSlotsToObject(SWGObject obj, ObjectData attributes) { - if (attributes.getAttribute(ObjectData.SLOT_DESCRIPTOR) != null) { + + private static void setObjectAttribute(String key, String value, SWGObject object) { + switch(key) { + case "volume": object.setVolume(Integer.valueOf(value)); break; + case "containerType": object.setContainerType(Integer.valueOf(value)); break; + default: break; + } + } + + private static void createObjectSlots(SWGObject object) { + System.out.println(object.getTemplate()); + if (object.getTemplateAttribute(ObjectData.SLOT_DESCRIPTOR) != null) { // These are the slots that the object *HAS* - SlotDescriptorData descriptor = (SlotDescriptorData) clientFac.getInfoFromFile((String) attributes.getAttribute(ObjectData.SLOT_DESCRIPTOR)); - + SlotDescriptorData descriptor = (SlotDescriptorData) clientFac.getInfoFromFile((String) object.getTemplateAttribute(ObjectData.SLOT_DESCRIPTOR)); + for (String slotName : descriptor.getSlots()) { - obj.addObjectSlot(slotName, null); + object.getSlots().put(slotName, null); } } - if (attributes.getAttribute(ObjectData.ARRANGEMENT_FILE) != null) { - // This is what slots the object *USES* - SlotArrangementData arrangementData = (SlotArrangementData) clientFac.getInfoFromFile((String) attributes.getAttribute(ObjectData.ARRANGEMENT_FILE)); - obj.setArrangement(arrangementData.getArrangement()); + if (object.getTemplateAttribute(ObjectData.ARRANGEMENT_FILE) != null) { + // This is what slots the created object is able to go into/use + SlotArrangementData arrangementData = (SlotArrangementData) clientFac.getInfoFromFile((String) object.getTemplateAttribute(ObjectData.ARRANGEMENT_FILE)); + object.setArrangement(arrangementData.getArrangement()); } } - + + /* + Misc helper methods + */ private static String getFirstTemplatePart(String template) { int ind = template.indexOf('/'); if (ind == -1) diff --git a/src/services/objects/ObjectManager.java b/src/services/objects/ObjectManager.java index b760d46c1..a2aa67511 100644 --- a/src/services/objects/ObjectManager.java +++ b/src/services/objects/ObjectManager.java @@ -31,10 +31,7 @@ import intents.ObjectTeleportIntent; import intents.PlayerEventIntent; import intents.network.GalacticPacketIntent; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; import main.ProjectSWG; import network.packets.Packet; @@ -228,12 +225,18 @@ public class ObjectManager extends Manager { if (obj == null) return null; objectAwareness.remove(obj); - for (SWGObject child : obj.getChildren()) - if (child != null) - deleteObject(child.getObjectId()); - for (SWGObject slot : obj.getSlots().values()) - if (slot != null) - deleteObject(slot.getObjectId()); + +/* for (Slot slot : obj.getSlots()) { + if (slot != null) { + if (slot instanceof Container) { + for (SWGObject child : ((Container) slot).getContainedObjects()) { + deleteObject(child.getObjectId()); + } + } + if (slot.getObject() != null) + deleteObject(slot.getObject().getObjectId()); + } + }*/ Log.i("ObjectManager", "Deleted object %d [%s]", obj.getObjectId(), obj.getTemplate()); return obj; } @@ -249,12 +252,20 @@ public class ObjectManager extends Manager { long objId = object.getObjectId(); - List children = object.getChildren(); - synchronized (children) { - for (SWGObject child : children) { - destroyObject(child.getObjectId()); +/* Collection slots = object.getSlots(); + synchronized (slots) { + for (Slot slot : slots) { + if (slot != null) { + if (slot instanceof Container) { + for (SWGObject child : ((Container) slot).getContainedObjects()) { + deleteObject(child.getObjectId()); + } + } + if (slot.getObject() != null) + deleteObject(slot.getObject().getObjectId()); + } } - } + }*/ // Remove object from the parent SWGObject parent = object.getParent(); @@ -262,7 +273,7 @@ public class ObjectManager extends Manager { if (parent instanceof CreatureObject) { ((CreatureObject) parent).removeEquipment(object); } - parent.removeChild(object); + //parent.removeChild(object); } object.sendObservers(new SceneDestroyObject(objId)); diff --git a/src/services/player/ZoneService.java b/src/services/player/ZoneService.java index 775e890c8..ba1d16a3b 100644 --- a/src/services/player/ZoneService.java +++ b/src/services/player/ZoneService.java @@ -341,7 +341,7 @@ public class ZoneService extends Service { creatureObj.setVolume(0x000F4240); creatureObj.setOwner(player); - creatureObj.setSlot("ghost", playerObj); + creatureObj.addObject(playerObj); // ghost slot playerObj.setAdminTag(player.getAccessLevel()); playerObj.setOwner(player); player.setCreatureObject(creatureObj); @@ -375,7 +375,7 @@ public class ZoneService extends Service { TangibleObject hairObj = createTangible(objManager, ClientFactory.formatToSharedFile(hair)); hairObj.setAppearanceData(customization); - creatureObj.setSlot("hair", hairObj); + creatureObj.addObject(hairObj); // slot = hair creatureObj.addEquipment(hairObj); } @@ -390,9 +390,10 @@ public class ZoneService extends Service { creatureObj.setName(create.getName()); creatureObj.setPvpType(20); creatureObj.getSkills().add("species_" + creatureObj.getRace().getSpecies()); - creatureObj.setSlot("inventory", inventory); - creatureObj.setSlot("datapad", datapad); - creatureObj.setSlot("appearance_inventory", apprncInventory); + + creatureObj.addObject(inventory); // slot = inventory + creatureObj.addObject(datapad); // slot = datapad + creatureObj.addObject(apprncInventory); // slot = appearance_inventory creatureObj.addEquipment(inventory); creatureObj.addEquipment(datapad); @@ -412,9 +413,14 @@ public class ZoneService extends Service { private void createStarterClothing(ObjectManager objManager, CreatureObject player, String race, String profession) { if (player.getSlottedObject("inventory") == null) return; - - for (String template : profTemplates.get(profession).getItems(ClientFactory.formatToSharedFile(race))) - player.equipItem(createTangible(objManager, template)); + + TangibleObject inventory = (TangibleObject) player.getSlottedObject("inventory"); + + for (String template : profTemplates.get(profession).getItems(ClientFactory.formatToSharedFile(race))) { + TangibleObject item = createTangible(objManager, template); + + item.moveToContainer(player, inventory); + } } From e706c3b1f9b61e020a9fb3a9b66dac6b539e0ab3 Mon Sep 17 00:00:00 2001 From: Waverunner Date: Tue, 26 May 2015 14:51:48 -0400 Subject: [PATCH 2/3] Updated awareness for objects in slots and containers, added removeObject, updated transferItemMisc command for slots refactor --- scripts/commands/generic/transferItemMisc.py | 31 +++--- src/resources/objects/SWGObject.java | 105 +++++++++++++++--- .../objects/creature/CreatureObject.java | 9 +- src/services/objects/ObjectCreator.java | 1 - src/services/player/ZoneService.java | 7 +- 5 files changed, 118 insertions(+), 35 deletions(-) diff --git a/scripts/commands/generic/transferItemMisc.py b/scripts/commands/generic/transferItemMisc.py index de1b8aaf5..1b13ef7eb 100644 --- a/scripts/commands/generic/transferItemMisc.py +++ b/scripts/commands/generic/transferItemMisc.py @@ -2,18 +2,21 @@ import sys def execute(galacticManager, player, target, args): actor = player.getCreatureObject() - argsSplit = args.split(" ") - objManager = galacticManager.getObjectManager(); - containerId = long(args[1]) - containerObject = objManager.getObjectById(containerId) # Ziggy: The target container + if actor is None or target is None: + return + inventory = actor.getSlottedObject("inventory") - - if target.getParent().equals(actor) or not containerObject.equals(inventory): # Ziggy: We're already wearing this item, transfer it to the container - containerObject.addChild(target) - elif containerObject.equals(inventory): # We're transfering this item to our inventory but we don't want to equip it - containerObject.addChild(target) - else: # Ziggy: This is an item in our inventory that we want to equip - actor.equipItem(target) - - return - \ No newline at end of file + + if inventory is None: + return + + if target.getParent() == actor: + actor.removeEquipment(target) + target.moveToContainer(actor, inventory) + return + else: + target.moveToContainer(actor, actor) + # actor.addEquipment(target) # This seems to crash the client, look to + return + + return \ No newline at end of file diff --git a/src/resources/objects/SWGObject.java b/src/resources/objects/SWGObject.java index 9ffb8ec9c..e1bd9823a 100644 --- a/src/resources/objects/SWGObject.java +++ b/src/resources/objects/SWGObject.java @@ -114,7 +114,7 @@ public class SWGObject implements Serializable, Comparable { // Not a child object, so time to check the slots! // Check to make sure this object is able to go into a slot in the parent - List requiredSlots = object.getArrangement().get(0); + List requiredSlots = object.getArrangement().get(arrangementId - 4); // Note that some objects don't have a descriptor, meaning it has no slots if (descriptor != null && !descriptor.containsAll(requiredSlots)) return; @@ -129,20 +129,70 @@ public class SWGObject implements Serializable, Comparable { } /** - * Moves the current object to the target object - * @param requester Object that is requesting to move the object, used for permission checking - * @param target Where this object should be moved to + * Removes the specified object from this current object. + * @param object Object to remove */ - public void moveToContainer(SWGObject requester, SWGObject target) { - Log.d("Slots", "Attempting to move %s to %s", this, target); + public void removeObject(SWGObject object) { + // This object is a container object, so remove it from the container + if (object.getSlotArrangement() == -1) { + containedObjects.remove(object.objectId); + object.parent = null; + return; + } + for (String slot : (slotArrangement == -1 ? + object.getArrangement().get(0) : object.getArrangement().get(slotArrangement - 4))) { + slots.put(slot, null); + } - // TODO Update the observers in the new object - - // TODO Return an enum for a container error? + object.parent = null; + object.slotArrangement = -1; } - // TODO: Use a "transfer" method for switching objects between parents, this will also check volume limits + /** + * Moves the current object to the target object + * @param requester Object that is requesting to move the object, used for permission checking + * @param container Where this object should be moved to + */ + public void moveToContainer(SWGObject requester, SWGObject container) { + // Before doing anything, get a list of the observers so we can send create/destroy/update messages + List oldObservers = getObjectsAware(); + + // Remove this object from the old parent if one exists + if (parent != null) { + parent.removeObject(this); + } + + container.addObject(this); + + List newObservers = new ArrayList<>(container.getObjectsAware()); + + 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 addAttribute(String attribute, String value) { attributes.put(attribute, value); @@ -410,15 +460,30 @@ public class SWGObject implements Serializable, Comparable { public List getObjectsAware() { synchronized (objectsAware) { - return Collections.unmodifiableList(objectsAware); + return Collections.unmodifiableList(getChildrenAwareness()); } } - + + private 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()); + + // TODO Permission checking + + return awareness; + } + public void sendObserversAndSelf(Packet ... packets) { sendSelf(packets); sendObservers(packets); } - + public void sendObservers(Packet ... packets) { synchronized (objectsAware) { for (SWGObject obj : objectsAware) { @@ -427,12 +492,22 @@ public class SWGObject implements Serializable, Comparable { continue; p.sendPacket(packets); } - + + List childrenAwareness = getChildrenAwareness(); + childrenAwareness.removeAll(objectsAware); + childrenAwareness.remove(this); // Remove self since only observers being notified + + for (SWGObject childObserver : childrenAwareness) { + Player p = childObserver.getOwner(); + if (p == null || p.getPlayerState() != PlayerState.ZONED_IN) + continue; + p.sendPacket(packets); + } + SWGObject parent = getParent(); if(parent != null) parent.sendObservers(packets); - } } diff --git a/src/resources/objects/creature/CreatureObject.java b/src/resources/objects/creature/CreatureObject.java index 60f070dcf..f963ce247 100644 --- a/src/resources/objects/creature/CreatureObject.java +++ b/src/resources/objects/creature/CreatureObject.java @@ -136,7 +136,14 @@ public class CreatureObject extends TangibleObject { appearanceList.sendDeltaMessage(this); } } - + + public void removeAppearanceItem(SWGObject obj) { + synchronized (appearanceList) { + if (appearanceList.remove(obj)) + appearanceList.sendDeltaMessage(this); + } + } + public SWGList getEquipmentList() { return equipmentList; } diff --git a/src/services/objects/ObjectCreator.java b/src/services/objects/ObjectCreator.java index e940022a4..274cd117b 100644 --- a/src/services/objects/ObjectCreator.java +++ b/src/services/objects/ObjectCreator.java @@ -121,7 +121,6 @@ public final class ObjectCreator { } private static void createObjectSlots(SWGObject object) { - System.out.println(object.getTemplate()); if (object.getTemplateAttribute(ObjectData.SLOT_DESCRIPTOR) != null) { // These are the slots that the object *HAS* SlotDescriptorData descriptor = (SlotDescriptorData) clientFac.getInfoFromFile((String) object.getTemplateAttribute(ObjectData.SLOT_DESCRIPTOR)); diff --git a/src/services/player/ZoneService.java b/src/services/player/ZoneService.java index 994baa0a6..ebfb3da9f 100644 --- a/src/services/player/ZoneService.java +++ b/src/services/player/ZoneService.java @@ -477,12 +477,11 @@ public class ZoneService extends Service { if (player.getSlottedObject("inventory") == null) return; - TangibleObject inventory = (TangibleObject) player.getSlottedObject("inventory"); - for (String template : profTemplates.get(profession).getItems(ClientFactory.formatToSharedFile(race))) { TangibleObject item = createTangible(objManager, template); - - item.moveToContainer(player, inventory); + // Move the new item to the player's clothing slots and add to equipment list + item.moveToContainer(player, player); + player.addEquipment(item); } } From 2e5596cad681512bd8e4771e111fd3d0e30bc496 Mon Sep 17 00:00:00 2001 From: Waverunner Date: Tue, 26 May 2015 14:55:59 -0400 Subject: [PATCH 3/3] Removed old slot classes --- src/resources/slots/ContainmentSlot.java | 64 ------------------------ src/resources/slots/Slot.java | 55 -------------------- 2 files changed, 119 deletions(-) delete mode 100644 src/resources/slots/ContainmentSlot.java delete mode 100644 src/resources/slots/Slot.java diff --git a/src/resources/slots/ContainmentSlot.java b/src/resources/slots/ContainmentSlot.java deleted file mode 100644 index 0481ad2c4..000000000 --- a/src/resources/slots/ContainmentSlot.java +++ /dev/null @@ -1,64 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 /// Project SWG /// www.projectswg.com - * - * ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on - * July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. - * Our goal is to create an emulator which will provide a server for players to - * continue playing a game similar to the one they used to play. We are basing - * it on the final publish of the game prior to end-game events. - * - * This file is part of Holocore. - * - * -------------------------------------------------------------------------------- - * - * Holocore is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * Holocore is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with Holocore. If not, see - ******************************************************************************/ - -package resources.slots; - -import resources.objects.SWGObject; - -public class ContainmentSlot extends Slot { - private volatile SWGObject object; - - public ContainmentSlot(String name) { - super(name); - } - - @Override - public boolean isEmpty() { - return (object == null); - } - - @Override - public SWGObject getObject() { - return object; - } - - @Override - public void insert(SWGObject object) { - this.object = object; - } - - @Override - public void remove(SWGObject object) { - if (this.object == object) - this.object = null; - } - - @Override - public void clear() { - this.object = null; - } -} diff --git a/src/resources/slots/Slot.java b/src/resources/slots/Slot.java deleted file mode 100644 index 2b8e12b4a..000000000 --- a/src/resources/slots/Slot.java +++ /dev/null @@ -1,55 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 /// Project SWG /// www.projectswg.com - * - * ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on - * July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. - * Our goal is to create an emulator which will provide a server for players to - * continue playing a game similar to the one they used to play. We are basing - * it on the final publish of the game prior to end-game events. - * - * This file is part of Holocore. - * - * -------------------------------------------------------------------------------- - * - * Holocore is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * Holocore is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with Holocore. If not, see - ******************************************************************************/ - -package resources.slots; - -import resources.objects.SWGObject; - -public abstract class Slot { - protected final String name; - - public Slot(String name) { - this.name = name; - } - - public abstract boolean isEmpty(); - - public abstract SWGObject getObject(); - - public abstract void insert(SWGObject object); - public abstract void remove(SWGObject object); - public abstract void clear(); - - public final String getName() { - return name; - } - - @Override - public String toString() { - return getName(); - } -}