diff --git a/src/resources/containers/ContainerPermissions.java b/src/resources/containers/ContainerPermissions.java
new file mode 100644
index 00000000..5a69b87d
--- /dev/null
+++ b/src/resources/containers/ContainerPermissions.java
@@ -0,0 +1,148 @@
+/*******************************************************************************
+ * 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 java.io.Serializable;
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+public final class ContainerPermissions implements Serializable {
+ private static final long serialVersionUID = 1L;
+
+ private Map permissionGroups;
+ private long owner;
+
+ public ContainerPermissions(long owner) {
+ this.permissionGroups = new HashMap<>();
+ this.owner = owner;
+
+ permissionGroups.put("owner", Permission.valueOf(Permission.values()));
+ permissionGroups.put("admin", Permission.valueOf(Permission.values()));
+ }
+
+ public 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 void addPermissions(String group, Permission... permissions) {
+ EnumSet groupPermissions = Permission.getFlags(permissionGroups.get(group));
+
+ for (Permission permission : permissions) {
+ groupPermissions.add(permission);
+ }
+
+ 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);
+ }
+
+ permissionGroups.put(group, Permission.valueOf(groupPermissions));
+ }
+
+ public void addDefaultWorldPermissions() {
+ permissionGroups.put("world", Permission.valueOf(Permission.ENTER_BUILDING, Permission.OPEN));
+ }
+
+ public void clearPermissions(String group) {
+ if (permissionGroups.containsKey(group))
+ permissionGroups.put(group, 0);
+ }
+
+ public boolean hasPermissionGroup(String group) {
+ return permissionGroups.containsKey(group);
+ }
+
+ public Set getPermissionGroups() {
+ return permissionGroups.keySet();
+ }
+
+ public void setOwner(long owner) {
+ this.owner = owner;
+ }
+
+ public long getOwner() {
+ return owner;
+ }
+
+ public enum Permission {
+ OPEN(1),
+ REMOVE(1<<1),
+ ADD(1<<2),
+ MOVE(1<<3),
+ ENTER_BUILDING(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) {
+ return valueOf(bitmaskSet);
+ }
+
+ public static int valueOf(Permission... permissions) {
+ int value = 0;
+
+ for (Permission permission : permissions) {
+ value += permission.bitmask;
+ }
+
+ return value;
+ }
+ }
+}
diff --git a/src/resources/objects/SWGObject.java b/src/resources/objects/SWGObject.java
index e2c39b14..3e777058 100644
--- a/src/resources/objects/SWGObject.java
+++ b/src/resources/objects/SWGObject.java
@@ -43,6 +43,7 @@ import network.packets.swg.zone.baselines.Baseline.BaselineType;
import network.packets.swg.zone.object_controller.DataTransform;
import resources.Location;
import resources.common.CRC;
+import resources.containers.ContainerPermissions;
import resources.containers.ContainerResult;
import resources.encodables.Stf;
import resources.network.BaselineBuilder;
@@ -61,6 +62,7 @@ public class SWGObject implements Serializable, Comparable {
private final Map containedObjects;
private final Map attributes;
private final Map templateAttributes;
+ private final ContainerPermissions containerPermissions;
private transient List objectsAware;
private List > arrangement;
@@ -91,6 +93,7 @@ public class SWGObject implements Serializable, Comparable {
this.containedObjects = Collections.synchronizedMap(new HashMap());
this.attributes = new LinkedHashMap();
this.templateAttributes = new HashMap();
+ this.containerPermissions = new ContainerPermissions(objectId);
}
private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException {
@@ -108,6 +111,7 @@ public class SWGObject implements Serializable, Comparable {
if (arrangementId == -1) {
containedObjects.put(object.getObjectId(), object);
object.parent = this;
+ object.containerPermissions.setOwner(objectId);
return true;
}
// Not a child object, so time to check the slots!
@@ -123,6 +127,7 @@ public class SWGObject implements Serializable, Comparable {
object.parent = this;
object.slotArrangement = arrangementId;
+ object.containerPermissions.setOwner(objectId);
return true;
}
@@ -145,6 +150,7 @@ public class SWGObject implements Serializable, Comparable {
object.parent = null;
object.slotArrangement = -1;
+ object.containerPermissions.setOwner(-1);
}
/**
@@ -154,30 +160,20 @@ public class SWGObject implements Serializable, Comparable {
* @return {@link ContainerResult}
*/
public ContainerResult moveToContainer(SWGObject requester, SWGObject container) {
- // TODO ContainerPermission check
+ if (!container.hasPermission(requester, ContainerPermissions.Permission.MOVE))
+ return ContainerResult.NO_PERMISSION;
// Check if object can fit into container or slots
int arrangementId = container.getArrangementId(this);
if (arrangementId == -1) {
// Item is going to go into the container, so check to see if it'll fit
- if (container.getMaxContainerSize() >= container.getContainedObjects().size())
+ if (container.getMaxContainerSize() >= container.getContainedObjects().size()) {
return ContainerResult.CONTAINER_FULL;
- } else {
- List requiredSlots = getArrangement().get(arrangementId - 4);
- // Check to see if any of the required slots are occupied
- int emptySlots = 0;
- for (Map.Entry entry : container.getSlots().entrySet()) {
- if (emptySlots == requiredSlots.size())
- break;
-
- if (requiredSlots.contains(entry.getKey()) && entry.getValue() == null)
- emptySlots++;
}
-
- if (emptySlots != requiredSlots.size())
- return ContainerResult.SLOT_OCCUPIED;
}
+ // TODO Slot occupation check, old version was not working properly, always returning SLOT_OCCUPIED
+
// Get a pre-parent-removal list of the observers so we can send create/destroy/update messages
List oldObservers = getObjectsAware();
@@ -194,6 +190,44 @@ public class SWGObject implements Serializable, Comparable {
return ContainerResult.SUCCESS;
}
+ public boolean hasOwnerPermissions(SWGObject object) {
+ return (object.getObjectId() == containerPermissions.getOwner());
+ }
+
+ public boolean hasPermission(SWGObject object, ContainerPermissions.Permission... permissions) {
+ if (object == this || hasOwnerPermissions(object))
+ return true;
+
+ if (!containerPermissions.hasPermissions(String.valueOf(object.getObjectId()), permissions)) {
+ // Doesn't have any owner permissions or specific permissions, check to see if this object has an
+ // acceptable permission group with the specified permissions available.
+ for (String permissionGroup : object.containerPermissions.getPermissionGroups()) {
+ if (containerPermissions.hasPermissions(permissionGroup, permissions)) {
+ //System.out.println(object + " can view " + this);
+ return true;
+ }
+ }
+ return false;
+ }
+ else return true;
+ }
+
+ public void addPermissions(String group, ContainerPermissions.Permission... permissions) {
+ containerPermissions.addPermissions(group, permissions);
+ }
+
+ public void removePermissions(String group, ContainerPermissions.Permission... permissions) {
+ containerPermissions.removePermissions(group, permissions);
+ }
+
+ public void addPermissions(SWGObject permissionRequester, ContainerPermissions.Permission... permissions) {
+ addPermissions(String.valueOf(permissionRequester.getObjectId()), permissions);
+ }
+
+ public void removePermissions(SWGObject permissionRequester, ContainerPermissions.Permission... permissions) {
+ removePermissions(String.valueOf(permissionRequester.getObjectId()), permissions);
+ }
+
public void addAttribute(String attribute, String value) {
attributes.put(attribute, value);
}
@@ -384,6 +418,8 @@ public class SWGObject implements Serializable, Comparable {
return Integer.valueOf(templateAttributes.get("containerVolumeLimit").toString());
}
+ public ContainerPermissions getContainerPermissions() { return containerPermissions; }
+
/**
* Gets the arrangementId for the {@link SWGObject} for the current instance
* @param object
@@ -468,8 +504,6 @@ public class SWGObject implements Serializable, Comparable {
&& !(awareness.contains(getOwner().getCreatureObject())))
awareness.add(getOwner().getCreatureObject());
- // TODO Permission checking
-
return awareness;
}
@@ -492,6 +526,9 @@ public class SWGObject implements Serializable, Comparable {
childrenAwareness.remove(this); // Remove self since only observers being notified
for (SWGObject childObserver : childrenAwareness) {
+ if (childObserver == null)
+ continue;
+
Player p = childObserver.getOwner();
if (p == null || p.getPlayerState() != PlayerState.ZONED_IN)
continue;
@@ -593,18 +630,25 @@ public class SWGObject implements Serializable, Comparable {
}
protected void createChildrenObjects(Player target) {
- // TODO Permission check for the target
-
+ if (!hasPermission(target.getCreatureObject(), ContainerPermissions.Permission.OPEN)) {
+ // System.out.println(target.getCreatureObject() + " doesn't have permission to view " + this + " -- skipping packet sending");
+ return;
+ }
+
// First create the objects in the slots
for (SWGObject slotObject : slots.values()) {
- if (slotObject != null)
+ if (slotObject != null) {
+ // System.out.println("Sending slotObj " + slotObject + " to " + target);
slotObject.createObject(target);
+ }
}
// Now create the contained objects
for (SWGObject containedObject : containedObjects.values()) {
- if (containedObject != null)
+ if (containedObject != null) {
+ // System.out.println("Sending containedObj " + containedObject + " to " + target);
containedObject.createObject(target);
+ }
}
}
diff --git a/src/services/player/ZoneService.java b/src/services/player/ZoneService.java
index ebfb3da9..4707b28b 100644
--- a/src/services/player/ZoneService.java
+++ b/src/services/player/ZoneService.java
@@ -436,8 +436,9 @@ public class ZoneService extends Service {
if (hair.isEmpty())
return;
TangibleObject hairObj = createTangible(objManager, ClientFactory.formatToSharedFile(hair));
-
+ hairObj.getContainerPermissions().addDefaultWorldPermissions();
hairObj.setAppearanceData(customization);
+
creatureObj.addObject(hairObj); // slot = hair
creatureObj.addEquipment(hairObj);
}
@@ -461,12 +462,16 @@ public class ZoneService extends Service {
creatureObj.addEquipment(inventory);
creatureObj.addEquipment(datapad);
creatureObj.addEquipment(apprncInventory);
+
+ creatureObj.getContainerPermissions().addDefaultWorldPermissions();
}
private void setPlayerObjectValues(PlayerObject playerObj, ClientCreateCharacter create) {
playerObj.setProfession(create.getProfession());
Calendar date = Calendar.getInstance();
playerObj.setBornDate(date.get(Calendar.YEAR), date.get(Calendar.MONTH) + 1, date.get(Calendar.DAY_OF_MONTH));
+
+ playerObj.getContainerPermissions().addDefaultWorldPermissions();
}
private void handleGalaxyLoopTimesRequest(Player player, GalaxyLoopTimesRequest req) {