diff --git a/scripts/commands/generic/transferItemArmor.js b/scripts/commands/generic/transferItemArmor.js index 3edeb56cf..eaf377a70 100644 --- a/scripts/commands/generic/transferItemArmor.js +++ b/scripts/commands/generic/transferItemArmor.js @@ -12,11 +12,6 @@ function executeCommand(galacticManager, player, target, args) { switch (containerResult) { case ContainerResult.SUCCESS: - if (actor.getEquipmentList().contains(target)) { - actor.removeEquipment(target); - } else if (newContainer === actor) { - actor.addEquipment(target); - } break; case ContainerResult.CONTAINER_FULL: // TODO container03_prose if container is named diff --git a/scripts/commands/generic/transferItemMisc.js b/scripts/commands/generic/transferItemMisc.js index 3edeb56cf..eaf377a70 100644 --- a/scripts/commands/generic/transferItemMisc.js +++ b/scripts/commands/generic/transferItemMisc.js @@ -12,11 +12,6 @@ function executeCommand(galacticManager, player, target, args) { switch (containerResult) { case ContainerResult.SUCCESS: - if (actor.getEquipmentList().contains(target)) { - actor.removeEquipment(target); - } else if (newContainer === actor) { - actor.addEquipment(target); - } break; case ContainerResult.CONTAINER_FULL: // TODO container03_prose if container is named diff --git a/scripts/commands/generic/transferItemWeapon.js b/scripts/commands/generic/transferItemWeapon.js index 5a7dfb6e0..6769e34db 100644 --- a/scripts/commands/generic/transferItemWeapon.js +++ b/scripts/commands/generic/transferItemWeapon.js @@ -12,16 +12,6 @@ function executeCommand(galacticManager, player, target, args) { switch (containerResult) { case ContainerResult.SUCCESS: - var defaultWeapon = actor.getDefaultWeapon(); - if (actor.getEquipmentList().contains(target)) { - actor.removeEquipment(target); - actor.addEquipment(defaultWeapon); - actor.setEquippedWeapon(defaultWeapon); - } else if (newContainer === actor) { - actor.removeEquipment(defaultWeapon); - actor.addEquipment(target); - actor.setEquippedWeapon(target); - } break; case ContainerResult.CONTAINER_FULL: // TODO container03_prose if container is named diff --git a/scripts/commands/helper/qatool/details.js b/scripts/commands/helper/qatool/details.js index fe6f24560..71d6b0983 100644 --- a/scripts/commands/helper/qatool/details.js +++ b/scripts/commands/helper/qatool/details.js @@ -1,13 +1,25 @@ function sendDetails(player, object, args) { if (object == null) { - intentFactory.sendSystemMessage(player, "Null target"); - return; + object = player.getCreatureObject(); } if (args.length >= 2 && args[1].equalsIgnoreCase("observers")) { - intentFactory.sendSystemMessage(player, "Aware: " + object.getObjectsAware()); intentFactory.sendSystemMessage(player, "Observers: " + object.getObservers()); return; } + if (args.length >= 3 && args[1].equalsIgnoreCase("aware-of")) { + aware = object.getObjectsAware(); + count = 0; + for (var iterator = aware.iterator(); iterator.hasNext();) { + var obj = iterator.next(); + if (obj.getObjectId() == parseInt(args[2]) || obj.getTemplate().contains(args[2])) { + intentFactory.sendSystemMessage(player, "True: " + obj); + return; + } + count++; + } + intentFactory.sendSystemMessage(player, "False. Checked " + count + " in aware"); + return; + } intentFactory.sendSystemMessage(player, object.getName() + " - " + object.getClass().getSimpleName() + " [" + object.getObjectId() + "]"); intentFactory.sendSystemMessage(player, " STR: " + object.getStringId() + " / " + object.getDetailStringId()); intentFactory.sendSystemMessage(player, " Template: " + object.getTemplate()); diff --git a/src/resources/commands/callbacks/FindFriendCallback.java b/src/resources/commands/callbacks/FindFriendCallback.java index ec42835fa..3d172775e 100644 --- a/src/resources/commands/callbacks/FindFriendCallback.java +++ b/src/resources/commands/callbacks/FindFriendCallback.java @@ -56,7 +56,7 @@ public class FindFriendCallback implements ICmdCallback { String friendName = args.split(" ")[0].toLowerCase(Locale.US); - if (!ghost.getFriendsList().contains(friendName)) { + if (!ghost.isFriend(friendName)) { new ChatBroadcastIntent(player, "@ui_cmnty:friend_location_failed_noname").broadcast(); return; } @@ -68,7 +68,7 @@ public class FindFriendCallback implements ICmdCallback { } PlayerObject friendGhost = friend.getPlayerObject(); - if (friendGhost == null || !friendGhost.getFriendsList().contains(player.getCharacterName().split(" ")[0].toLowerCase(Locale.US))) { + if (friendGhost == null || !friendGhost.isFriend(player.getCharacterName().split(" ")[0].toLowerCase(Locale.US))) { new ChatBroadcastIntent(player, new ProsePackage("@ui_cmnty:friend_location_failed", "TU", friendName)).broadcast(); return; } diff --git a/src/resources/containers/ContainerPermissions.java b/src/resources/containers/ContainerPermissions.java index c0cee9bc4..7cf969c1f 100644 --- a/src/resources/containers/ContainerPermissions.java +++ b/src/resources/containers/ContainerPermissions.java @@ -26,182 +26,38 @@ ******************************************************************************/ package resources.containers; -import java.util.ArrayList; -import java.util.EnumSet; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import resources.network.NetBufferStream; import resources.objects.SWGObject; -import resources.persistable.Persistable; - -/** - * Structure for creating permission sets that will allow the object to be viewed/modified/added/removed by a requested - * object depending on the implemented abstract methods. - * @author Waverunner - */ -public abstract class ContainerPermissions implements Persistable { - - public static final WorldPermissions WORLD = new WorldPermissions(); - public static final InventoryPermissions INVENTORY = new InventoryPermissions(); - - private Map permissionGroups; - private List joinedGroups; +public abstract class ContainerPermissions { + public ContainerPermissions() { - this.permissionGroups = new HashMap<>(); - this.joinedGroups = new ArrayList<>(); - } - - protected boolean hasPermissions(String group, Permission... permissions) { - if (!hasPermissionGroup(group)) - return false; - - EnumSet groupPermissions = Permission.getFlags(permissionGroups.get(group)); - - for (Permission permission : permissions) { - if (!groupPermissions.contains(permission)) - return false; - } - - return true; - } - - public boolean hasPermissions(List requesterGroups, Permission ... permission) { - for (String group : requesterGroups) { - if (hasPermissions(group, permission)) - return true; - } - return false; - } - - public void addPermissions(String group, Permission... permissions) { - if (!hasPermissionGroup(group)) { - permissionGroups.put(group, Permission.valueOf(permissions)); - return; - } - - EnumSet groupPermissions = Permission.getFlags(permissionGroups.get(group)); - - for (Permission permission : permissions) { - groupPermissions.add(permission); - } - - synchronized (permissionGroups) { - permissionGroups.put(group, Permission.valueOf(groupPermissions)); - } - } - - public void removePermissions(String group, Permission... permissions) { - - if (!hasPermissionGroup(group)) - return; - - EnumSet groupPermissions = Permission.getFlags(permissionGroups.get(group)); - - for (Permission permission : permissions) { - groupPermissions.add(permission); - } - - synchronized (permissionGroups) { - permissionGroups.put(group, Permission.valueOf(groupPermissions)); - } - } - - public void clearPermissions(String group) { - synchronized (permissionGroups) { - if (permissionGroups.containsKey(group)) - permissionGroups.put(group, 0); - } - } - - public boolean hasPermissionGroup(String group) { - return permissionGroups.containsKey(group); - } - - public Set getPermissionGroups() { - synchronized(permissionGroups) { - return permissionGroups.keySet(); - } - } - - public List getJoinedGroups() { - return joinedGroups; - } - - public void addDefaultWorldPermissions() { - addPermissions("world", Permission.VIEW, Permission.ENTER); + } - @Override - public void save(NetBufferStream stream) { - stream.addByte(0); - synchronized (permissionGroups) { - stream.addMap(permissionGroups, (e) -> { - stream.addAscii(e.getKey()); - stream.addInt(e.getValue()); - }); - } - synchronized (joinedGroups) { - stream.addList(joinedGroups, (g) -> stream.addAscii(g)); - } - } - - @Override - public void read(NetBufferStream stream) { - stream.getByte(); - stream.getList((i) -> permissionGroups.put(stream.getAscii(), stream.getInt())); - stream.getList((i) -> joinedGroups.add(stream.getAscii())); - } - public abstract boolean canView(SWGObject viewer, SWGObject container); public abstract boolean canEnter(SWGObject requester, SWGObject container); public abstract boolean canRemove(SWGObject requester, SWGObject container); public abstract boolean canMove(SWGObject requester, SWGObject container); public abstract boolean canAdd(SWGObject requester, SWGObject container); - - public enum Permission { - VIEW(1), - REMOVE(1<<1), - ADD(1<<2), - MOVE(1<<3), - ENTER(1<<4); - - int bitmask; - - Permission(int bitmask) { - this.bitmask = bitmask; - } - - public static EnumSet getFlags(int bits) { - EnumSet states = EnumSet.noneOf(Permission.class); - for (Permission state : values()) { - if ((state.bitmask & bits) != 0) - states.add(state); - } - return states; - } - - public static int valueOf(EnumSet bitmaskSet) { - int value = 0; - - for (Permission permission : bitmaskSet) { - value += permission.bitmask; - } - - return value; - } - - public static int valueOf(Permission... permissions) { - int value = 0; - - for (Permission permission : permissions) { - value += permission.bitmask; - } - - return value; - } + + public boolean canView(SWGObject container) { + return canView(null, container); } + + public boolean canEnter(SWGObject container) { + return canEnter(null, container); + } + + public boolean canRemove(SWGObject container) { + return canRemove(null, container); + } + + public boolean canMove(SWGObject container) { + return canMove(null, container); + } + + public boolean canAdd(SWGObject container) { + return canAdd(null, container); + } + } diff --git a/src/resources/containers/ContainerPermissionsType.java b/src/resources/containers/ContainerPermissionsType.java new file mode 100644 index 000000000..1feb242f1 --- /dev/null +++ b/src/resources/containers/ContainerPermissionsType.java @@ -0,0 +1,66 @@ +/************************************************************************************ + * 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.containers; + +import resources.objects.SWGObject; + +public enum ContainerPermissionsType { + DEFAULT (new DefaultPermissions()), + INVENTORY (new InventoryPermissions()); + + private final ContainerPermissions permissions; + + ContainerPermissionsType(ContainerPermissions permissions) { + this.permissions = permissions; + } + + public ContainerPermissions getContainerPermissions() { + return permissions; + } + + public boolean canView(SWGObject viewer, SWGObject container) { + return permissions.canView(viewer, container); + } + + public boolean canEnter(SWGObject viewer, SWGObject container) { + return permissions.canEnter(viewer, container); + } + + public boolean canRemove(SWGObject viewer, SWGObject container) { + return permissions.canRemove(viewer, container); + } + + public boolean canMove(SWGObject viewer, SWGObject container) { + return permissions.canMove(viewer, container); + } + + public boolean canAdd(SWGObject viewer, SWGObject container) { + return permissions.canAdd(viewer, container); + } + +} diff --git a/src/resources/containers/DefaultPermissions.java b/src/resources/containers/DefaultPermissions.java index 94e0a85dc..95fe30a00 100644 --- a/src/resources/containers/DefaultPermissions.java +++ b/src/resources/containers/DefaultPermissions.java @@ -34,30 +34,42 @@ import resources.objects.SWGObject; * for every new object. * @author Waverunner */ -public class DefaultPermissions extends ContainerPermissions { +class DefaultPermissions extends ContainerPermissions { @Override public boolean canView(SWGObject requester, SWGObject container) { return true; } - + @Override public boolean canEnter(SWGObject requester, SWGObject container) { return true; } - + @Override public boolean canRemove(SWGObject requester, SWGObject container) { - return requester.getOwner() == container.getOwner(); + if (requester == null || requester.getOwner() == null) + return true; + if (container.getOwner() == null) + return false; + return requester.getOwner().equals(container.getOwner()); } - + @Override public boolean canMove(SWGObject requester, SWGObject container) { - return requester.getOwner() == container.getOwner(); + if (requester == null || requester.getOwner() == null) + return true; + if (container.getOwner() == null) + return false; + return requester.getOwner().equals(container.getOwner()); } - + @Override public boolean canAdd(SWGObject requester, SWGObject container) { - return requester.getOwner() == container.getOwner(); + if (requester == null || requester.getOwner() == null) + return true; + if (container.getOwner() == null) + return false; + return requester.getOwner().equals(container.getOwner()); } } diff --git a/src/resources/containers/InventoryPermissions.java b/src/resources/containers/InventoryPermissions.java index 5b039f600..743a6cf13 100644 --- a/src/resources/containers/InventoryPermissions.java +++ b/src/resources/containers/InventoryPermissions.java @@ -29,20 +29,23 @@ package resources.containers; import resources.objects.SWGObject; -/** - * This set of permissions will allow only the owner to view the container. - * - * @author Waverunner - */ -public class InventoryPermissions extends DefaultPermissions { +class InventoryPermissions extends DefaultPermissions { @Override public boolean canView(SWGObject requester, SWGObject container) { - return requester.getOwner() == container.getOwner(); + if (requester == null || requester.getOwner() == null) + return true; + if (container.getOwner() == null) + return false; + return requester.getOwner().equals(container.getOwner()); } @Override public boolean canEnter(SWGObject requester, SWGObject container) { - return requester.getOwner() == container.getOwner(); + if (requester == null || requester.getOwner() == null) + return true; + if (container.getOwner() == null) + return false; + return requester.getOwner().equals(container.getOwner()); } } diff --git a/src/resources/containers/WorldPermissions.java b/src/resources/containers/WorldPermissions.java deleted file mode 100644 index 301f9cb68..000000000 --- a/src/resources/containers/WorldPermissions.java +++ /dev/null @@ -1,81 +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.containers; - -import resources.objects.SWGObject; - -/** - * This is essentially a universal "all-in-one" permission set for managing permission groups for world objects. This - * class makes use of permission groups. Every player joins the world permission group upon creation. When a specific - * group is needed, the object will have to remove the world permission set and replace it with their own group of - * permissions. - *

Example: In order to allow only certain players into an area of Jabba's palace, you would first - * create a permission group for the CellObject with a unique name. Then you need to add the named group to the - * players ContainerPermissions joinedGroups list in order for them to properly pass the checks. - *

- * This set of permissions will allow: - *
    - *
  1. View - If the viewer has joined a group that is recognized by the container with viewing permissions
  2. - *
  3. Enter - If the viewer has joined a group that is recognized by the container with enter permissions
  4. - *
  5. Remove, Move, Add - If the container has the same owner as the requester
  6. - *
- * @author Waverunner - */ -public class WorldPermissions extends DefaultPermissions { - - @Override - public boolean canView(SWGObject viewer, SWGObject container) { - if (super.canView(viewer, container)) - return true; - - return hasPermissions(viewer.getContainerPermissions().getJoinedGroups(), Permission.VIEW); - } - - @Override - public boolean canEnter(SWGObject requester, SWGObject container) { - if (super.canView(requester, container)) - return true; - - return hasPermissions(requester.getContainerPermissions().getJoinedGroups(), Permission.ENTER); - } - - @Override - public boolean canRemove(SWGObject requester, SWGObject container) { - return super.canRemove(requester, container); - } - - @Override - public boolean canMove(SWGObject requester, SWGObject container) { - return super.canMove(requester, container); - } - - @Override - public boolean canAdd(SWGObject requester, SWGObject container) { - return super.canAdd(requester, container); - } -} diff --git a/src/resources/encodables/player/Equipment.java b/src/resources/encodables/player/Equipment.java index 3879747c8..35b79f0ba 100644 --- a/src/resources/encodables/player/Equipment.java +++ b/src/resources/encodables/player/Equipment.java @@ -52,23 +52,23 @@ public class Equipment implements Encodable, Persistable { private CRC template; public Equipment() { - this(0, null); + this(0, "", 4); } - public Equipment(long objectId, String template) { + public Equipment(SWGObject obj) { + this(obj.getObjectId(), obj.getTemplate(), obj.getSlotArrangement()); + if (obj instanceof WeaponObject) + this.weapon = (WeaponObject) obj; + } + + private Equipment(long objectId, String template, int arrangementId) { this.objectId = objectId; this.template = new CRC(template); this.customizationString = new byte[0]; this.arrangementId = 4; - this.objectId = 0; this.weapon = null; } - public Equipment(WeaponObject weapon) { - this(weapon.getObjectId(), weapon.getTemplate()); - this.weapon = weapon; - } - @Override public byte [] encode() { byte [] weaponData = new byte[0]; @@ -175,10 +175,10 @@ public class Equipment implements Encodable, Persistable { @Override public boolean equals(Object o) { - if (!(o instanceof SWGObject)) - return super.equals(o); + if (!(o instanceof Equipment)) + return false; - return ((SWGObject) o).getObjectId() == objectId; + return ((Equipment) o).getObjectId() == objectId; } @Override diff --git a/src/resources/objects/SWGObject.java b/src/resources/objects/SWGObject.java index 91e73de5d..46031cdd5 100644 --- a/src/resources/objects/SWGObject.java +++ b/src/resources/objects/SWGObject.java @@ -42,9 +42,8 @@ import resources.Terrain; import resources.buildout.BuildoutArea; import resources.client_info.visitors.ObjectData.ObjectDataAttribute; import resources.common.CRC; -import resources.containers.ContainerPermissions; +import resources.containers.ContainerPermissionsType; import resources.containers.ContainerResult; -import resources.containers.DefaultPermissions; import resources.encodables.StringId; import resources.network.BaselineBuilder; import resources.network.BaselineObject; @@ -58,47 +57,46 @@ import resources.player.Player; import resources.player.PlayerState; import resources.server_info.Log; import services.CoreManager; +import services.objects.ObjectCreator; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; -import java.util.Hashtable; -import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Set; public abstract class SWGObject extends BaselineObject implements Comparable, Persistable { - private final Location location; - private final long objectId; - private final HashMap slots; // HashMap used for null value support - private final Set containedObjects; - private final Map attributes; - private final Map dataAttributes; - private transient Set objectsAware; - private transient Set customAware; - private transient BuildoutArea buildoutArea; - private transient Player owner; - private List > arrangement; - - private ObjectClassification classification = ObjectClassification.GENERATED; - private GameObjectType gameObjectType = GameObjectType.GOT_NONE; - private ContainerPermissions containerPermissions; - private SWGObject parent = null; - private StringId stringId = new StringId("", ""); - private StringId detailStringId = new StringId("", ""); - private String template = ""; - private int crc = 0; - private String objectName = ""; - private int volume = 0; - private float complexity = 1; - private int containerType = 0; - private double loadRange = 0; - private int areaId = -1; - - private int slotArrangement = -1; + private final long objectId; + private final Location location = new Location(0, 0, 0, null); + private final Set containedObjects= new HashSet<>(); + private final Map attributes = new HashMap<>(); + private final Set objectsAware = new HashSet<>(); + private final Set customAware = new HashSet<>(); + private final HashMap slots = new HashMap<>(); // HashMap used for null value support + private final Map dataAttributes = new HashMap<>(); + + private ObjectClassification classification = ObjectClassification.GENERATED; + private GameObjectType gameObjectType = GameObjectType.GOT_NONE; + private ContainerPermissionsType permissions = ContainerPermissionsType.DEFAULT; + private List > arrangement = new ArrayList<>(); + private BuildoutArea buildoutArea = null; + private Player owner = null; + + private SWGObject parent = null; + private StringId stringId = new StringId("", ""); + private StringId detailStringId = new StringId("", ""); + private String template = ""; + private int crc = 0; + private String objectName = ""; + private int volume = 0; + private float complexity = 1; + private int containerType = 0; + private double loadRange = 0; + private int areaId = -1; + private int slotArrangement = -1; public SWGObject() { this(0, null); @@ -107,73 +105,50 @@ public abstract class SWGObject extends BaselineObject implements Comparable(); - this.customAware = new HashSet<>(); - this.slots = new HashMap<>(); - this.containedObjects = new HashSet<>(); - this.attributes = new LinkedHashMap<>(); - this.dataAttributes = new Hashtable<>(); - this.containerPermissions = new DefaultPermissions(); } - + /** * Adds the specified object to this object and places it in the appropriate slot if needed * @param object Object to add to this container, which will either be put into the appropriate slot(s) or become a contained 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) { + object.setSlotArrangement(getArrangementId(object)); + if (object.getSlotArrangement() == -1) { synchronized (containedObjects) { containedObjects.add(object); } } else { - // 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(arrangementId - 4); - // Note that some objects don't have a descriptor, meaning it has no slots - - // Add object to the slot - for (String requiredSlot : requiredSlots) { + for (String requiredSlot : object.getArrangement().get(object.getSlotArrangement() - 4)) { setSlot(requiredSlot, object); } } - object.parent = this; - object.slotArrangement = arrangementId; synchronized (object.objectsAware) { - object.objectsAware.clear(); + for (SWGObject obj : new ArrayList<>(object.objectsAware)) { + object.awarenessOutOfRange(obj, false); + } } } - + /** * Removes the specified object from this current object. * @param object Object to remove */ - public void removeObject(SWGObject object) { - synchronized (object.objectsAware) { - object.objectsAware.clear(); - object.objectsAware.addAll(getObjectsAware()); - object.objectsAware.remove(object); - } - // This object is a container object, so remove it from the container + protected void removeObject(SWGObject object) { if (object.getSlotArrangement() == -1) { synchronized (containedObjects) { - containedObjects.remove(object.objectId); + containedObjects.remove(object); } } else { - for (String slot : (slotArrangement == -1 ? - object.getArrangement().get(0) : object.getArrangement().get(slotArrangement - 4))) { - setSlot(slot, null); + for (String requiredSlot : object.getArrangement().get(object.getSlotArrangement() - 4)) { + setSlot(requiredSlot, null); } } object.parent = null; object.slotArrangement = -1; } - + /** * Moves this object to the passed container if the requester has the MOVE permission for the container * @param requester Object that is requesting to move the object, used for permission checking @@ -181,34 +156,24 @@ 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) { + Set oldObservers = getObserversAndParent(); + SWGObject parent = this.parent; + if (parent != null) parent.removeObject(this); - } - Player newOwner = null; if (container != null) { + int arrangement = container.getArrangementId(this); + if (arrangement != -1) + container.handleSlotReplacement(parent, this, arrangement); container.addObject(this); - newOwner = container.getOwner(); - } + } else + recreateWorldAwareness(parent); - // Observer notification - Set containerObservers = getObservers(); - if (newOwner != null) - containerObservers.add(newOwner.getCreatureObject()); - sendUpdatedContainment(oldObservers, containerObservers); - + sendUpdatedContainment(oldObservers, getObserversAndParent()); return ContainerResult.SUCCESS; } @@ -222,127 +187,64 @@ 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 { - // Item is going into slot(s) - for (String slotName : getArrangement().get(arrangementId - 4)) { - SWGObject equippedItem = container.getSlottedObject(slotName); - if (equippedItem != null) { - equippedItem.moveToContainer(requester, container.getSlottedObject("inventory")); - } - } } return ContainerResult.SUCCESS; } - - /** - * 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) - 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; - } + + private Set getObserversAndParent() { + Set observers = getObservers(); + Player prevOwner = (getParent() != null) ? getParent().getOwner() : null; + if (prevOwner != null) + observers.add(prevOwner.getCreatureObject()); + return observers; + } + + private void recreateWorldAwareness(SWGObject oldParent) { + for (SWGObject obj : oldParent.getObjectsAware()) { + awarenessInRange(obj, false); } + } + + protected void handleSlotReplacement(SWGObject oldParent, SWGObject obj, int arrangement) { + for (String slot : obj.getArrangement().get(arrangement-4)) { + SWGObject slotObj = getSlottedObject(slot); + if (slotObj != null) + slotObj.moveToContainer(oldParent); + } + } + + public boolean isVisible(SWGObject target) { + if (target == null) + return true; + if (!permissions.canView(target, this)) + return false; + if (getParent() != null) + return getParent().isVisible(target); 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); } @@ -455,7 +357,7 @@ public abstract class SWGObject extends BaselineObject implements Comparable objects = getObjectsAware(); for (SWGObject o : objects) { - o.awarenessOutOfRange(this, true); - awarenessOutOfRange(o, updateSelf); + awarenessOutOfRange(o, true); } } @@ -741,20 +644,6 @@ public abstract class SWGObject extends BaselineObject implements Comparable copy; synchronized (customAware) { @@ -820,7 +703,7 @@ public abstract class SWGObject extends BaselineObject implements Comparable observers = new HashSet<>(); for (SWGObject aware : nearby) { - if (!aware.hasPermission(original, ContainerPermissions.Permission.VIEW)) + if (!aware.isVisible(original)) continue; if (aware instanceof CreatureObject) { Player awareOwner = aware.getOwner(); @@ -887,21 +770,29 @@ public abstract class SWGObject extends BaselineObject implements Comparable attributes; - private ContainerPermissions containerPermissions; - private ObjectClassification classification = ObjectClassification.GENERATED; - private String objectName = ""; - private int volume = 0; - private float complexity = 1; - private int containerType = 0; - private double loadRange = 0; - private int areaId = -1; - - private final HashMap slots; - private final Map containedObjects; - */ @Override public void save(NetBufferStream stream) { stream.addByte(0); location.save(stream); - containerPermissions.save(stream); + stream.addBoolean(parent != null && parent.getClassification() != ObjectClassification.GENERATED); + if (parent != null && parent.getClassification() != ObjectClassification.GENERATED) + SWGObjectFactory.save(ObjectCreator.createObjectFromTemplate(parent.getObjectId(), parent.getTemplate()), stream); + stream.addAscii(permissions.name()); + stream.addAscii(classification.name()); + stream.addUnicode(objectName); + stream.addInt(volume); + stream.addFloat(complexity); + stream.addFloat((float) loadRange); synchronized (attributes) { stream.addMap(attributes, (e) -> { stream.addAscii(e.getKey()); stream.addAscii(e.getValue()); }); } - stream.addAscii(classification.name()); - stream.addUnicode(objectName); - stream.addInt(volume); - stream.addFloat(complexity); - stream.addFloat((float) loadRange); Set contained; synchronized (containedObjects) { contained = new HashSet<>(containedObjects); @@ -1124,17 +987,16 @@ public abstract class SWGObject extends BaselineObject implements Comparable attributes.put(stream.getAscii(), stream.getAscii())); + if (stream.getBoolean()) + parent = SWGObjectFactory.create(stream); + permissions = ContainerPermissionsType.valueOf(stream.getAscii()); classification = ObjectClassification.valueOf(stream.getAscii()); objectName = stream.getUnicode(); volume = stream.getInt(); complexity = stream.getFloat(); loadRange = stream.getFloat(); - Set contained = new HashSet<>(); - stream.getList((i) -> contained.add(SWGObjectFactory.create(stream))); - for (SWGObject obj : contained) - obj.moveToContainer(this); + stream.getList((i) -> attributes.put(stream.getAscii(), stream.getAscii())); + stream.getList((i) -> SWGObjectFactory.create(stream).moveToContainer(this)); } public enum ObjectClassification { diff --git a/src/resources/objects/buildouts/TerrainBuildoutLoader.java b/src/resources/objects/buildouts/TerrainBuildoutLoader.java index b6885b6ae..a2ba07e34 100644 --- a/src/resources/objects/buildouts/TerrainBuildoutLoader.java +++ b/src/resources/objects/buildouts/TerrainBuildoutLoader.java @@ -37,7 +37,6 @@ import resources.Terrain; import resources.client_info.ClientFactory; import resources.client_info.visitors.CrcStringTableData; import resources.client_info.visitors.DatatableData; -import resources.containers.ContainerPermissions; import resources.objects.SWGObject; import resources.objects.SWGObject.ObjectClassification; import resources.objects.cell.CellObject; @@ -96,7 +95,6 @@ class TerrainBuildoutLoader { object.setBuildoutAreaId(area.getIndex()); setCellInformation(object, buildoutRow.getCellIndex()); addObject(area.getName(), object, buildoutRow.getContainerId()); - updatePermissions(object); } } @@ -132,8 +130,4 @@ class TerrainBuildoutLoader { cell.setNumber(cellIndex); } - private void updatePermissions(SWGObject object) { - object.setContainerPermissions(ContainerPermissions.WORLD); - } - } diff --git a/src/resources/objects/buildouts/TerrainSnapshotLoader.java b/src/resources/objects/buildouts/TerrainSnapshotLoader.java index 698103087..d02252f6a 100644 --- a/src/resources/objects/buildouts/TerrainSnapshotLoader.java +++ b/src/resources/objects/buildouts/TerrainSnapshotLoader.java @@ -37,7 +37,6 @@ import resources.Terrain; import resources.client_info.ClientFactory; import resources.client_info.visitors.WorldSnapshotData; import resources.client_info.visitors.WorldSnapshotData.Node; -import resources.containers.ContainerPermissions; import resources.objects.SWGObject; import resources.objects.SWGObject.ObjectClassification; import resources.objects.cell.CellObject; @@ -83,8 +82,7 @@ public class TerrainSnapshotLoader { object.setLoadRange(node.getRadius()); setCellInformation(object, node.getCellIndex()); addObject(object, node.getContainerId()); - updatePermissions(object); - + for (Node child : node.getChildren()) { createFromNode(templates, child); } @@ -117,8 +115,4 @@ public class TerrainSnapshotLoader { cell.setNumber(cellIndex); } - private void updatePermissions(SWGObject object) { - object.setContainerPermissions(ContainerPermissions.WORLD); - } - } diff --git a/src/resources/objects/creature/CreatureObject.java b/src/resources/objects/creature/CreatureObject.java index 45fcdec6c..931b56dcf 100644 --- a/src/resources/objects/creature/CreatureObject.java +++ b/src/resources/objects/creature/CreatureObject.java @@ -44,7 +44,6 @@ import resources.collections.SWGSet; import resources.network.BaselineBuilder; import resources.network.NetBuffer; import resources.network.NetBufferStream; -import resources.objects.GameObjectType; import resources.objects.SWGObject; import resources.objects.player.PlayerObject; import resources.objects.tangible.TangibleObject; @@ -87,46 +86,38 @@ public class CreatureObject extends TangibleObject { @Override public void addObject(SWGObject obj) { super.addObject(obj); - if (isEquipment(obj.getGameObjectType())) + if (obj.getSlotArrangement() != -1 && !(obj instanceof PlayerObject)) { addEquipment(obj); + if (obj instanceof WeaponObject && defaultWeapon != null && !obj.equals(defaultWeapon)) { + removeObject(defaultWeapon); + } + } } @Override public void removeObject(SWGObject obj) { super.removeObject(obj); - if (isEquipment(obj.getGameObjectType())) - removeEquipment(obj); + removeEquipment(obj); + if (obj instanceof WeaponObject && defaultWeapon != null && !obj.equals(defaultWeapon)) { + addObject(defaultWeapon); + } } - private boolean isEquipment(GameObjectType type) { - switch (type.getMask()) { - case GOTM_ARMOR: - case GOTM_CLOTHING: - case GOTM_CYBERNETIC: - case GOTM_JEWELRY: - case GOTM_TOOL: - case GOTM_WEAPON: - return true; - case GOTM_MISC: - switch (type) { - case GOT_MISC_CONTAINER: - case GOT_MISC_CONTAINER_PUBLIC: - case GOT_MISC_CONTAINER_SHIP_LOOT: - case GOT_MISC_CONTAINER_WEARABLE: - return true; - default: - return false; - } - default: - return false; + protected void handleSlotReplacement(SWGObject oldParent, SWGObject obj, int arrangement) { + SWGObject inventory = getSlottedObject("inventory"); + for (String slot : obj.getArrangement().get(arrangement-4)) { + SWGObject slotObj = getSlottedObject(slot); + if (slotObj != null) { + slotObj.moveToContainer(inventory); + } } } - public void addEquipment(SWGObject obj) { + private void addEquipment(SWGObject obj) { creo6.addEquipment(obj, this); } - public void removeEquipment(SWGObject obj) { + private void removeEquipment(SWGObject obj) { creo6.removeEquipment(obj, this); } diff --git a/src/resources/objects/creature/CreatureObjectSharedNP.java b/src/resources/objects/creature/CreatureObjectSharedNP.java index 8b7a59170..503520061 100644 --- a/src/resources/objects/creature/CreatureObjectSharedNP.java +++ b/src/resources/objects/creature/CreatureObjectSharedNP.java @@ -66,10 +66,10 @@ class CreatureObjectSharedNP implements Persistable { private boolean shownOnRadar = true; private boolean beast = false; - private SWGList attributes = new SWGList(6, 21); - private SWGList maxAttributes = new SWGList(6, 22); - private SWGList equipmentList = new SWGList(6, 23); - private SWGList appearanceList = new SWGList(6, 33); + private SWGList attributes = new SWGList<>(6, 21); + private SWGList maxAttributes = new SWGList<>(6, 22); + private SWGList equipmentList = new SWGList<>(6, 23); + private SWGList appearanceList = new SWGList<>(6, 33); private SWGMap buffs = new SWGMap<>(6, 26); @@ -79,44 +79,61 @@ class CreatureObjectSharedNP implements Persistable { } public void addEquipment(SWGObject obj, SWGObject target) { + if (getEquipment(obj) != null) + return; synchronized (equipmentList) { - if (obj instanceof WeaponObject) - equipmentList.add(new Equipment((WeaponObject) obj)); - else - equipmentList.add(new Equipment(obj.getObjectId(), obj.getTemplate())); + equipmentList.add(new Equipment(obj)); equipmentList.sendDeltaMessage(target); } } public void removeEquipment(SWGObject obj, SWGObject target) { + Equipment e = getEquipment(obj); + if (e == null) + return; + synchronized (equipmentList) { + equipmentList.remove(e); + equipmentList.sendDeltaMessage(target); + } + } + + public Equipment getEquipment(SWGObject obj) { synchronized (equipmentList) { for (Equipment equipment : equipmentList) { if (equipment.getObjectId() == obj.getObjectId()) { - equipmentList.remove(equipment); - equipmentList.sendDeltaMessage(target); - return; + return equipment; } } } + return null; } public void addAppearanceItem(SWGObject obj, SWGObject target) { synchronized (appearanceList) { - appearanceList.add(new Equipment(obj.getObjectId(), obj.getTemplate())); + appearanceList.add(new Equipment(obj)); appearanceList.sendDeltaMessage(target); } } public void removeAppearanceItem(SWGObject obj, SWGObject target) { + Equipment e = getEquipment(obj); + if (e == null) + return; + synchronized (appearanceList) { + appearanceList.remove(e); + appearanceList.sendDeltaMessage(target); + } + } + + public Equipment getAppearance(SWGObject obj) { synchronized (appearanceList) { for (Equipment equipment : appearanceList) { if (equipment.getObjectId() == obj.getObjectId()) { - appearanceList.remove(equipment); - appearanceList.sendDeltaMessage(target); - return; + return equipment; } } } + return null; } public SWGList getEquipmentList() { diff --git a/src/resources/objects/group/GroupObject.java b/src/resources/objects/group/GroupObject.java index 4ce6f22f4..c67cd1720 100644 --- a/src/resources/objects/group/GroupObject.java +++ b/src/resources/objects/group/GroupObject.java @@ -118,7 +118,6 @@ public class GroupObject extends SWGObject { // Extends INTO or TANO? groupMembers.remove(member); object.setGroupId(0); - awarenessOutOfRange(object, true); groupMembers.sendDeltaMessage(this); } diff --git a/src/resources/objects/player/PlayerObject.java b/src/resources/objects/player/PlayerObject.java index daaa14374..d572762c1 100644 --- a/src/resources/objects/player/PlayerObject.java +++ b/src/resources/objects/player/PlayerObject.java @@ -283,6 +283,10 @@ public class PlayerObject extends IntangibleObject { play9.addFriend(friend, this); } + public boolean isFriend(String target) { + return play9.isFriend(target); + } + public List getFriendsList() { return play9.getFriendsList(); } diff --git a/src/resources/objects/player/PlayerObjectPrivateNP.java b/src/resources/objects/player/PlayerObjectPrivateNP.java index b79579968..2e7611f2f 100644 --- a/src/resources/objects/player/PlayerObjectPrivateNP.java +++ b/src/resources/objects/player/PlayerObjectPrivateNP.java @@ -72,6 +72,12 @@ class PlayerObjectPrivateNP implements Persistable { friendsList.sendDeltaMessage(target); } + public boolean isFriend(String friend) { + synchronized (friendsList) { + return friendsList.contains(friend); + } + } + public List getFriendsList() { return friendsList; } diff --git a/src/resources/objects/quadtree/QuadTree.java b/src/resources/objects/quadtree/QuadTree.java index 7fba1c265..795e2ef55 100644 --- a/src/resources/objects/quadtree/QuadTree.java +++ b/src/resources/objects/quadtree/QuadTree.java @@ -56,6 +56,18 @@ public class QuadTree { headNode.insert(x, y, value); } + public boolean contains(double x, double y, V obj) { + return containsWithinRange(x, y, obj, DEFAULT_RANGE); + } + + public boolean containsWithinRange(double x, double y, V obj, double range) { + if (Double.isNaN(x) || Double.isNaN(y)) + return false; + if (x < minX || y < minY || x > maxX || y > maxY) + return false; + return headNode.containsWithinRange(x, y, obj, range); + } + public List get(double x, double y) { return getWithinRange(x, y, DEFAULT_RANGE); } @@ -198,6 +210,26 @@ public class QuadTree { obj.insert(v); } + public boolean containsWithinRange(double x, double y, V v, double range) { + if (obj != null && square(obj.x - x) + square(obj.y - y) <= square(range)) { + return obj.contains(v); + } + int mnX = (x - range <= minX) ? 0 : getIndex(x - range, minX, cellWidth); + int mnY = (y - range <= minY) ? 0 : getIndex(y - range, minY, cellHeight); + int mxX = (x + range >= maxX) ? subnodes.length() - 1 : getIndex(x + range, minX, cellWidth); + int mxY = (y + range >= maxY) ? subnodes.length() - 1 : getIndex(y + range, minY, cellHeight); + for (int xInd = mnX; xInd <= mxX; xInd++) { + for (int yInd = mnY-1; yInd <= mxY; yInd++) { + if (yInd < 0) + continue; + QuadNode node = subnodes.getSubnode(xInd, yInd); + if (node != null && node.containsWithinRange(x, y, v, range)) + return true; + } + } + return false; + } + public void getWithinRange(List list, double x, double y, double range) { if (obj != null && square(obj.x - x) + square(obj.y - y) <= square(range)) { obj.addAll(list); @@ -250,6 +282,14 @@ public class QuadTree { next.insert(value); } + public boolean contains(V v) { + if (value.equals(v)) + return true; + if (next != null) + return next.contains(v); + return false; + } + public int addAll(List list) { list.add(value); if (next != null) diff --git a/src/resources/server_info/RelationalServerData.java b/src/resources/server_info/RelationalServerData.java index 5e4796843..430944cf3 100644 --- a/src/resources/server_info/RelationalServerData.java +++ b/src/resources/server_info/RelationalServerData.java @@ -357,19 +357,40 @@ public class RelationalServerData extends RelationalDatabase { return; switch (lineNum) { case 1: - columnNames = line.split("\t"); + columnNames = fastTabSplit(line); break; case 2: - columnTypes = line.split("\t"); + columnTypes = fastTabSplit(line); createTable(); createPreparedStatement(); break; default: - generateInsert(line.split("\t"), lineNum); + generateInsert(fastTabSplit(line), lineNum); break; } } + private String [] fastTabSplit(String str) { + int count = 1; + for (int i = 0; i < str.length(); i++) { + if (str.charAt(i) == '\t') { + count++; + } + } + String [] tabs = new String[count]; + int tabInd = 0; + int prevInd = 0; + for (int i = 0; i < str.length(); i++) { + if (str.charAt(i) == '\t') { + tabs[tabInd++] = str.substring(prevInd, i); + prevInd = i+1; + } + } + if (prevInd < str.length()) + tabs[tabInd++] = str.substring(prevInd); + return tabs; + } + private void createTable() { if (columnNames.length != columnTypes.length) throw new IllegalArgumentException("Names length and types length mismatch"); diff --git a/src/services/chat/ChatManager.java b/src/services/chat/ChatManager.java index 89f7cf9dc..adfdc9942 100644 --- a/src/services/chat/ChatManager.java +++ b/src/services/chat/ChatManager.java @@ -55,6 +55,7 @@ import resources.player.Player; import resources.player.PlayerState; import resources.server_info.RelationalServerData; import resources.server_info.RelationalServerFactory; +import services.CoreManager; import services.player.PlayerManager; import java.sql.PreparedStatement; @@ -214,7 +215,7 @@ public class ChatManager extends Manager { if (ghost == null) return; - if (!ghost.getFriendsList().contains(target)) { + if (!ghost.isFriend(target)) { sendSystemMessage(player, "@cmnty:friend_not_found", target); return; } @@ -237,7 +238,7 @@ public class ChatManager extends Manager { return; } - if (ghost.getFriendsList().contains(target)) { + if (ghost.isFriend(target)) { sendSystemMessage(player, "@cmnty:friend_duplicate", target); return; } @@ -250,10 +251,7 @@ public class ChatManager extends Manager { ghost.addFriend(target); sendSystemMessage(player, "@cmnty:friend_added", target); - Player targetPlayer = player.getPlayerManager().getPlayerByCreatureFirstName(target); - - if (targetPlayer != null && targetPlayer.getPlayerState() == PlayerState.ZONED_IN) - player.sendPacket(new ChatFriendsListUpdate(new ChatAvatar(0, target, targetPlayer.getGalaxyName()), true)); + player.sendPacket(new ChatFriendsListUpdate(new ChatAvatar(0, target, CoreManager.getGalaxy().getName()), true)); } /* Ignore List */ diff --git a/src/services/galaxy/travel/TravelService.java b/src/services/galaxy/travel/TravelService.java index 66a9b6237..9e8bba394 100644 --- a/src/services/galaxy/travel/TravelService.java +++ b/src/services/galaxy/travel/TravelService.java @@ -555,7 +555,7 @@ public class TravelService extends Service { } private boolean isTicketUsable(SWGObject ticket) { - Location worldLoc = ticket.getOwner().getCreatureObject().getWorldLocation(); + Location worldLoc = ticket.getWorldLocation(); TravelPoint nearest = getNearestTravelPoint(worldLoc); String departurePoint = ticket.getAttribute("@obj_attr_n:travel_departure_point"); String departurePlanet = ticket.getAttribute("@obj_attr_n:travel_departure_planet"); diff --git a/src/services/objects/ObjectAwareness.java b/src/services/objects/ObjectAwareness.java index ba2f8b20c..fc24b2a23 100644 --- a/src/services/objects/ObjectAwareness.java +++ b/src/services/objects/ObjectAwareness.java @@ -52,6 +52,7 @@ import resources.buildout.BuildoutArea; import resources.control.Intent; import resources.control.Service; import resources.objects.SWGObject; +import resources.objects.SWGObject.ObjectClassification; import resources.objects.creature.CreatureObject; import resources.objects.quadtree.QuadTree; import resources.objects.tangible.TangibleObject; @@ -64,9 +65,11 @@ public class ObjectAwareness extends Service { private static final int DEFAULT_LOAD_RANGE = (int) square(200); // Squared for speed private final Map > quadTree; + private final Map locations; public ObjectAwareness() { - quadTree = new HashMap>(); + quadTree = new HashMap<>(); + locations = new HashMap<>(); registerForIntent(PlayerEventIntent.TYPE); registerForIntent(ObjectCreatedIntent.TYPE); registerForIntent(ObjectTeleportIntent.TYPE); @@ -120,6 +123,13 @@ public class ObjectAwareness extends Service { creature.resetAwareness(); add(creature); update(creature); + if (creature.getParent() != null && creature.getOwner() != null) { + for (SWGObject observer : creature.getObservers()) + creature.createObject(observer.getOwner()); + for (SWGObject object : creature.getObjectsAware()) { + object.createObject(creature.getOwner()); + } + } p.sendPacket(new CmdSceneReady()); break; default: @@ -136,12 +146,11 @@ public class ObjectAwareness extends Service { private void processObjectTeleportIntent(ObjectTeleportIntent oti) { SWGObject object = oti.getObject(); Player owner = object.getOwner(); - Location old = object.getLocation(); object.setLocation(oti.getNewLocation()); if (oti.getParent() != null) { move(object, oti.getParent(), oti.getNewLocation()); } else { - moveFromOld(object, old, false); + move(object, oti.getNewLocation(), false); } object.clearAware(); if (object instanceof CreatureObject && ((CreatureObject) object).isLoggedInPlayer()) @@ -175,9 +184,7 @@ public class ObjectAwareness extends Service { SWGObject obj = i.getObject(); Location newLocation = i.getNewLocation(); BuildoutArea area = obj.getBuildoutArea(); - if (area == null) - Log.e(this, "Unknown buildout area at: " + obj.getWorldLocation()); - else + if (area != null) newLocation = area.adjustLocation(newLocation); move(obj, newLocation, true); if (area != null) @@ -210,20 +217,9 @@ public class ObjectAwareness extends Service { transform = new DataTransform(transform); Location newLocation = transform.getLocation(); newLocation.setTerrain(obj.getTerrain()); - double time = ((CreatureObject) obj).getTimeSinceLastTransform() / 1000; - obj.updateLastTransformTime(); - Location l = obj.getWorldLocation(); - double speed = Math.sqrt(square(l.getX()-newLocation.getX()) + square(l.getZ()-newLocation.getZ())) / time; - if (speed > obj.getMovementScale()*7.3) { - double angle = (newLocation.getX() == l.getX() ? 0 : Math.atan2(newLocation.getZ()-l.getZ(), newLocation.getX()-l.getX())); - newLocation.setX(l.getX()+obj.getMovementScale()*7.3*time*Math.cos(angle)); - newLocation.setZ(l.getZ()+obj.getMovementScale()*7.3*time*Math.sin(angle)); - transform.setSpeed((float) (obj.getMovementScale()*7.3)); - } + moveObjectSpeedChecks(obj, newLocation); BuildoutArea area = obj.getBuildoutArea(); - if (area == null) - Log.e(this, "Unknown buildout area at: " + obj.getWorldLocation()); - else + if (area != null) newLocation = area.adjustLocation(newLocation); new PlayerTransformedIntent(obj, obj.getParent(), null, obj.getLocation(), newLocation).broadcast(); move(obj, newLocation, true); @@ -239,6 +235,25 @@ public class ObjectAwareness extends Service { Log.e("ObjectManager", "Could not find parent for transform! Cell: %d Object: %s", transformWithParent.getCellId(), obj); return; } + moveObjectSpeedChecks(obj, parent, newLocation); + new PlayerTransformedIntent((CreatureObject) obj, obj.getParent(), parent, obj.getLocation(), newLocation).broadcast(); + move(obj, parent, newLocation); + obj.sendParentDataTransforms(transformWithParent); + } + + private void moveObjectSpeedChecks(CreatureObject obj, Location newLocation) { + double time = ((CreatureObject) obj).getTimeSinceLastTransform() / 1000; + obj.updateLastTransformTime(); + Location l = obj.getWorldLocation(); + double speed = Math.sqrt(square(l.getX()-newLocation.getX()) + square(l.getZ()-newLocation.getZ())) / time; + if (speed > obj.getMovementScale()*7.3) { + double angle = (newLocation.getX() == l.getX() ? 0 : Math.atan2(newLocation.getZ()-l.getZ(), newLocation.getX()-l.getX())); + newLocation.setX(l.getX()+obj.getMovementScale()*7.3*time*Math.cos(angle)); + newLocation.setZ(l.getZ()+obj.getMovementScale()*7.3*time*Math.sin(angle)); + } + } + + private void moveObjectSpeedChecks(CreatureObject obj, SWGObject parent, Location newLocation) { double time = ((CreatureObject) obj).getTimeSinceLastTransform() / 1000; obj.updateLastTransformTime(); Location l = obj.getWorldLocation(); @@ -249,11 +264,7 @@ public class ObjectAwareness extends Service { double angle = (nWorld.getX() == l.getX() ? 0 : Math.atan2(nWorld.getZ()-l.getZ(), nWorld.getX()-l.getX())) + Math.PI; newLocation.setX(newLocation.getX()+obj.getMovementScale()*7.3*time*invertNormalizedValue(Math.cos(angle))); newLocation.setZ(newLocation.getZ()+obj.getMovementScale()*7.3*time*invertNormalizedValue(Math.sin(angle))); - transformWithParent.setSpeed((float) (obj.getMovementScale()*7.3)); } - new PlayerTransformedIntent((CreatureObject) obj, obj.getParent(), parent, obj.getLocation(), newLocation).broadcast(); - move(obj, parent, newLocation); - obj.sendParentDataTransforms(transformWithParent); } private void loadQuadTree() { @@ -265,9 +276,15 @@ public class ObjectAwareness extends Service { private boolean isInAwareness(SWGObject object) { if (object instanceof CreatureObject && ((CreatureObject) object).isLoggedOutPlayer()) return false; + if (object.getTerrain() == null) + return false; return object.getParent() == null && object instanceof TangibleObject; } + private boolean isInMap(SWGObject object) { + return object.getClassification() == ObjectClassification.GENERATED; + } + private double invertNormalizedValue(double x) { if (x < 0) return -1 - x; @@ -281,9 +298,13 @@ public class ObjectAwareness extends Service { public void add(SWGObject object) { if (!isInAwareness(object)) return; + remove(object); Location l = object.getLocation(); - if (invalidLocation(l)) - return; + if (isInMap(object)) { + synchronized (locations) { + locations.put(object.getObjectId(), l); + } + } QuadTree tree = getTree(l); synchronized (tree) { tree.put(l.getX(), l.getZ(), object); @@ -295,7 +316,20 @@ public class ObjectAwareness extends Service { * @param object the object to remove */ public void remove(SWGObject object) { - removeFromLocation(object, object.getLocation()); + Location l; + if (isInMap(object)) { + synchronized (locations) { + l = locations.remove(object.getObjectId()); + } + } else { + l = object.getLocation(); + } + if (l == null) + return; + QuadTree tree = getTree(l); + synchronized (tree) { + tree.remove(l.getX(), l.getZ(), object); + } } /** @@ -328,12 +362,10 @@ public class ObjectAwareness extends Service { */ private void move(SWGObject object, SWGObject nParent, Location nLocation) { SWGObject parent = object.getParent(); - if (parent != null && nParent != parent) { - object.moveToContainer(null); - } else if (parent == null) { + if (parent == null) { remove(object); // Moving from world to cell } - if (object.getParent() == null) { // Should have been updated in removeObject() + if (nParent != parent) { // Intentional. Just in case the ID matches or one is null object.moveToContainer(nParent); } object.setLocation(nLocation); @@ -348,8 +380,6 @@ public class ObjectAwareness extends Service { if (!obj.isGenerated() || !isInAwareness(obj)) return; Location l = obj.getWorldLocation(); - if (invalidLocation(l)) - return; Set objectAware = new HashSet(); QuadTree tree = getTree(l); List range; @@ -363,34 +393,10 @@ public class ObjectAwareness extends Service { obj.updateObjectAwareness(objectAware); } - private void moveFromOld(SWGObject object, Location oldLocation, boolean update) { - if (object.getParent() != null) { - object.moveToContainer(null); - } else { - removeFromLocation(object, oldLocation); // World to World - } - add(object); - if (update) - update(object); - } - - private void removeFromLocation(SWGObject object, Location l) { - if (invalidLocation(l)) - return; - QuadTree tree = getTree(l); - synchronized (tree) { - tree.remove(l.getX(), l.getZ(), object); - } - } - private QuadTree getTree(Location l) { return quadTree.get(l.getTerrain()); } - private boolean invalidLocation(Location l) { - return l == null || l.getTerrain() == null; - } - private boolean isValidInRange(SWGObject obj, SWGObject inRange, Location objLoc) { if (inRange.getObjectId() == obj.getObjectId()) return false; diff --git a/src/services/objects/ObjectCreator.java b/src/services/objects/ObjectCreator.java index e5c9b3e90..84725ed45 100644 --- a/src/services/objects/ObjectCreator.java +++ b/src/services/objects/ObjectCreator.java @@ -61,12 +61,18 @@ import resources.server_info.Log; public final class ObjectCreator { private static final Object OBJECT_ID_MUTEX = new Object(); - private static long maxObjectId = 1; + private static long nextObjectId = 1; - public static void updateMaxObjectId(long objectId) { + private static void updateMaxObjectId(long objectId) { synchronized (OBJECT_ID_MUTEX) { - if (objectId > maxObjectId) - maxObjectId = objectId; + if (objectId >= nextObjectId) + nextObjectId = objectId+1; + } + } + + private static long getNextObjectId() { + synchronized (OBJECT_ID_MUTEX) { + return nextObjectId++; } } @@ -108,19 +114,11 @@ public final class ObjectCreator { } public static SWGObject createObjectFromTemplate(String template) { - long id = 0; - synchronized (OBJECT_ID_MUTEX) { - id = maxObjectId++; - } - return createObjectFromTemplate(id, template); + return createObjectFromTemplate(getNextObjectId(), template); } public static T createObjectFromTemplate(String template, Class c) { - long id = 0; - synchronized (OBJECT_ID_MUTEX) { - id = maxObjectId++; - } - return createObjectFromTemplate(id, template, c); + return createObjectFromTemplate(getNextObjectId(), template, c); } private static SWGObject createObjectFromType(long objectId, String template, GameObjectType got) { diff --git a/src/services/objects/ObjectManager.java b/src/services/objects/ObjectManager.java index a0514ce81..49ea15a8d 100644 --- a/src/services/objects/ObjectManager.java +++ b/src/services/objects/ObjectManager.java @@ -99,9 +99,16 @@ public class ObjectManager extends Manager { @Override public boolean initialize() { - loadClientObjects(); + Collection buildouts = clientBuildoutService.loadClientObjects(); if (!loadObjects()) return false; + for (SWGObject obj : buildouts) { + putObject(obj); + new ObjectCreatedIntent(obj).broadcast(); + } + synchronized (database) { + database.traverse((obj) -> loadObject(obj)); + } return super.initialize(); } @@ -111,52 +118,37 @@ public class ObjectManager extends Manager { synchronized (database) { if (!database.load() && database.fileExists()) return false; - database.traverse((obj) -> loadObject(obj)); } double loadTime = (System.nanoTime() - startLoad) / 1E6; Log.i("ObjectManager", "Finished loading %d objects. Time: %fms", database.size(), loadTime); return true; } - private void loadClientObjects() { - Collection objects = clientBuildoutService.loadClientObjects(); - for (SWGObject object : objects) { - putObject(object); - new ObjectCreatedIntent(object).broadcast(); - } - } - private void loadObject(SWGObject obj) { - obj.setOwner(null); - // if creature is not a player - if (!(obj instanceof CreatureObject && ((CreatureObject) obj).isLoggedOutPlayer())) - objectAwareness.add(obj); - else // If creature is a player + if (obj instanceof CreatureObject && ((CreatureObject) obj).isPlayer()) Scripts.invoke("objects/load_creature", "onLoad", obj); - putObject(obj); updateBuildoutParent(obj); addChildrenObjects(obj); - new ObjectCreatedIntent(obj).broadcast(); } private void updateBuildoutParent(SWGObject obj) { if (obj.getParent() != null) { - if (!obj.getParent().isGenerated()) { - long id = obj.getParent().getObjectId(); - SWGObject parent = getObjectById(id); - obj.moveToContainer(parent); - if (parent == null) - Log.e("ObjectManager", "Parent for %s is null! ParentID: %d", obj, id); - } else { - updateBuildoutParent(obj.getParent()); - } + long id = obj.getParent().getObjectId(); + SWGObject parent = getObjectById(id); + obj.moveToContainer(parent); + if (parent == null) + Log.e("ObjectManager", "Parent for %s is null! ParentID: %d", obj, id); } } private void addChildrenObjects(SWGObject obj) { + new ObjectCreatedIntent(obj).broadcast(); + for (SWGObject child : obj.getSlots().values()) { + if (child != null) + addChildrenObjects(child); + } for (SWGObject child : obj.getContainedObjects()) { - putObject(child); addChildrenObjects(child); } } @@ -255,9 +247,10 @@ public class ObjectManager extends Manager { } private void putObject(SWGObject object) { - ObjectCreator.updateMaxObjectId(object.getObjectId()); synchronized (objectMap) { - objectMap.put(object.getObjectId(), object); + SWGObject replaced = objectMap.put(object.getObjectId(), object); + if (replaced != null && replaced != object) + Log.e(this, "Replaced object in object map! Old: %s New: %s", replaced, object); } } diff --git a/src/services/player/CharacterCreationService.java b/src/services/player/CharacterCreationService.java index 42619a0b1..065e470b7 100644 --- a/src/services/player/CharacterCreationService.java +++ b/src/services/player/CharacterCreationService.java @@ -58,7 +58,7 @@ import resources.Race; import resources.client_info.ClientFactory; import resources.client_info.visitors.ProfTemplateData; import resources.config.ConfigFile; -import resources.containers.ContainerPermissions; +import resources.containers.ContainerPermissionsType; import resources.control.Service; import resources.objects.SWGObject; import resources.objects.building.BuildingObject; @@ -378,7 +378,7 @@ public class CharacterCreationService extends Service { private SWGObject createInventoryObject(ObjectManager objManager, CreatureObject creatureObj, String template) { SWGObject obj = ObjectCreator.createObjectFromTemplate(template); obj.moveToContainer(creatureObj); - obj.setContainerPermissions(ContainerPermissions.INVENTORY); + obj.setContainerPermissions(ContainerPermissionsType.INVENTORY); new ObjectCreatedIntent(obj).broadcast(); return obj; } @@ -390,7 +390,6 @@ public class CharacterCreationService extends Service { hairObj.setAppearanceData(customization); hairObj.moveToContainer(creatureObj); // hair slot - creatureObj.addEquipment(hairObj); } private void setCreatureObjectValues(ObjectManager objManager, CreatureObject creatureObj, ClientCreateCharacter create) { @@ -406,17 +405,14 @@ public class CharacterCreationService extends Service { creatureObj.setDefaultWeapon(defWeapon); defWeapon.setMaxRange(5); creatureObj.setEquippedWeapon(defWeapon); - creatureObj.addEquipment(createInventoryObject(objManager, creatureObj, "object/tangible/inventory/shared_character_inventory.iff")); - creatureObj.addEquipment(createInventoryObject(objManager, creatureObj, "object/tangible/datapad/shared_character_datapad.iff")); - creatureObj.addEquipment(createInventoryObject(objManager, creatureObj, "object/tangible/inventory/shared_appearance_inventory.iff")); - creatureObj.addEquipment(defWeapon); + createInventoryObject(objManager, creatureObj, "object/tangible/inventory/shared_character_inventory.iff"); + createInventoryObject(objManager, creatureObj, "object/tangible/datapad/shared_character_datapad.iff"); + createInventoryObject(objManager, creatureObj, "object/tangible/inventory/shared_appearance_inventory.iff"); createInventoryObject(objManager, creatureObj, "object/tangible/bank/shared_character_bank.iff"); createInventoryObject(objManager, creatureObj, "object/tangible/mission_bag/shared_mission_bag.iff"); // Any character can perform the basic dance. creatureObj.addAbility("startDance+basic"); - - creatureObj.joinPermissionGroup("world"); } private void setPlayerObjectValues(PlayerObject playerObj, ClientCreateCharacter create) { @@ -435,7 +431,6 @@ public class CharacterCreationService extends Service { return; // Move the new item to the player's clothing slots and add to equipment list item.moveToContainer(player, player); - player.addEquipment(item); } SWGObject inventory = player.getSlottedObject("inventory"); diff --git a/src/utilities/IntentFactory.java b/src/utilities/IntentFactory.java index f83b191a9..5bc0ea8be 100644 --- a/src/utilities/IntentFactory.java +++ b/src/utilities/IntentFactory.java @@ -46,9 +46,11 @@ import resources.server_info.Log; * This class is to be used exclusively in cases where using the intents directly isn't practical. */ public final class IntentFactory { - + + private final IntentChain broadcastChain = new IntentChain(); + private void broadcast(String message, Player source, BroadcastType type) { - new ChatBroadcastIntent(message, source, source.getCreatureObject().getTerrain(), type).broadcast(); + broadcastChain.broadcastAfter(new ChatBroadcastIntent(message, source, source.getCreatureObject().getTerrain(), type)); } /**