diff --git a/README.md b/README.md
index 26702e096..fee7f4707 100644
--- a/README.md
+++ b/README.md
@@ -31,4 +31,25 @@ 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 .
\ No newline at end of file
+along with Holocore. If not, see .
+
+### Running Holocore ###
+In order to successfully build and run Holocore, you must:
+
+1. Have a valid Star Wars Galaxies installation that is updated from the final patch.
+2. Setup a postgresql server, preferably on localhost, with a database and user named nge with read/write permissions.
+ * Note: You will need to restore the database that you created using nge.backup in order to create the proper tables.
+3. Extract the following contents of the sku's to a new clientdata folder in the holocore directory:
+ * abstract
+ * appearance
+ * creation
+ * customization
+ * datatables
+ * footprint
+ * interiorlayout
+ * misc
+ * object
+ * quest
+ * snapshot
+ * string
+ * terrain
\ No newline at end of file
diff --git a/scripts/commands/generic/setWaypointActiveStatus.py b/scripts/commands/generic/setWaypointActiveStatus.py
index b25d0d2b0..d79f89439 100644
--- a/scripts/commands/generic/setWaypointActiveStatus.py
+++ b/scripts/commands/generic/setWaypointActiveStatus.py
@@ -2,7 +2,7 @@ import sys
def execute(objManager, player, target, args):
ghost = player.getPlayerObject()
- if ghost is None:
+ if ghost is None or target is None:
return
waypoint = ghost.getWaypoint(target.getObjectId())
diff --git a/src/network/packets/swg/zone/SceneDestroyObject.java b/src/network/packets/swg/zone/SceneDestroyObject.java
index eecfdfe31..e3ec45195 100644
--- a/src/network/packets/swg/zone/SceneDestroyObject.java
+++ b/src/network/packets/swg/zone/SceneDestroyObject.java
@@ -42,7 +42,7 @@ public class SceneDestroyObject extends SWGPacket {
}
public SceneDestroyObject(long objId) {
-
+ this.objId = objId;
}
public SceneDestroyObject(ByteBuffer data) {
diff --git a/src/resources/commands/callbacks/RequestWaypointCmdCallback.java b/src/resources/commands/callbacks/RequestWaypointCmdCallback.java
index 1ac0744b1..3c7364c9a 100644
--- a/src/resources/commands/callbacks/RequestWaypointCmdCallback.java
+++ b/src/resources/commands/callbacks/RequestWaypointCmdCallback.java
@@ -39,7 +39,7 @@ public class RequestWaypointCmdCallback implements ICmdCallback {
@Override
public void execute(GalacticManager galacticManager, Player player, SWGObject target, String args) {
// Args: (^-,=+_)color_1(,+-=_^)=1 planet x 0.0 z
- PlayerObject ghost = (PlayerObject) player.getPlayerObject();
+ PlayerObject ghost = player.getPlayerObject();
if (ghost == null)
return;
diff --git a/src/resources/commands/callbacks/ServerDestroyObjectCmdCallback.java b/src/resources/commands/callbacks/ServerDestroyObjectCmdCallback.java
new file mode 100644
index 000000000..0aec3e83e
--- /dev/null
+++ b/src/resources/commands/callbacks/ServerDestroyObjectCmdCallback.java
@@ -0,0 +1,57 @@
+/*******************************************************************************
+ * 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.commands.callbacks;
+
+import resources.commands.ICmdCallback;
+import resources.objects.SWGObject;
+import resources.objects.player.PlayerObject;
+import resources.objects.waypoint.WaypointObject;
+import resources.player.Player;
+import services.galaxy.GalacticManager;
+import services.objects.ObjectManager;
+
+public class ServerDestroyObjectCmdCallback implements ICmdCallback {
+ @Override
+ public void execute(GalacticManager galacticManager, Player player, SWGObject target, String args) {
+
+ if (target == null)
+ return;
+
+ ObjectManager objectManager = galacticManager.getObjectManager();
+
+ // TODO Take into account container permissions
+
+ if (target instanceof WaypointObject) {
+ PlayerObject ghost = player.getPlayerObject();
+ ghost.removeWaypoint(target.getObjectId());
+ objectManager.deleteObject(target.getObjectId());
+ } else {
+ objectManager.destroyObject(target);
+ }
+ }
+}
diff --git a/src/resources/objects/SWGObject.java b/src/resources/objects/SWGObject.java
index 5521bcac6..3aee4ed4d 100644
--- a/src/resources/objects/SWGObject.java
+++ b/src/resources/objects/SWGObject.java
@@ -60,7 +60,7 @@ public class SWGObject implements Serializable, Comparable {
private static final long serialVersionUID = 1L;
- private final List children;
+ 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
@@ -111,13 +111,13 @@ public class SWGObject implements Serializable, Comparable {
private void updateContainment(SWGObject child) {
if (child.parent != null)
- child.parent.removeChild(child);
+ 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.intValue();
+ child.containmentType = containmentType;
// TODO: Set containmentType based on if object is in a slot (4) or a container (-1)
}
@@ -143,7 +143,9 @@ public class SWGObject implements Serializable, Comparable {
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 + "!");
@@ -160,7 +162,7 @@ public class SWGObject implements Serializable, Comparable {
}
if (occupiedAvailSlots.size() != arrangement.size()) {
- System.err.println("Doesn't have all the slots.");
+ System.err.println("Needed slots are not available for " + obj);
return false;
}
@@ -171,8 +173,8 @@ public class SWGObject implements Serializable, Comparable {
return true;
}
-
- public void clearSlot(String slot) {
+
+ private void clearSlot(String slot) {
if (!slots.containsKey(slot)) {
System.err.println("Could not clear " + slot + " as it doesn't contain that slot!");
return;
@@ -188,6 +190,11 @@ public class SWGObject implements Serializable, Comparable {
synchronized (children) {
children.remove(object);
}
+
+ for (String slot : object.getArrangement().get(0)) {
+ clearSlot(slot);
+ }
+
object.parent = null;
}
@@ -305,8 +312,8 @@ public class SWGObject implements Serializable, Comparable {
public List> getArrangement() {
return arrangement;
}
-
- public void setArrangment(List> arrangement) {
+
+ public void setArrangement(List> arrangement) {
this.arrangement = arrangement;
}
@@ -341,11 +348,7 @@ public class SWGObject implements Serializable, Comparable {
createChildrenObjects(target);
target.sendPacket(new SceneEndBaselines(getObjectId()));
}
-
- protected void destroyObject(Player target) {
- sendSceneDestroyObject(target);
- }
-
+
public void clearAware() {
SWGObject [] objects;
synchronized (objectsAware) {
@@ -399,7 +402,7 @@ public class SWGObject implements Serializable, Comparable {
synchronized (objectsAware) {
if (objectsAware.remove(o)) {
if (o.getOwner() != null) {
- destroyObject(o.getOwner());
+ sendSceneDestroyObject(o.getOwner());
}
if (getOwner() != null)
o.awarenessOutOfRange(this);
diff --git a/src/resources/objects/creature/CreatureObject.java b/src/resources/objects/creature/CreatureObject.java
index ba2e89dbb..8c84c3f98 100644
--- a/src/resources/objects/creature/CreatureObject.java
+++ b/src/resources/objects/creature/CreatureObject.java
@@ -147,7 +147,14 @@ public class CreatureObject extends TangibleObject {
for(String slotName : slotNameList)
container.setSlot(slotName, null);
}
-
+
+ public void removeEquipment(SWGObject obj) {
+ synchronized (equipmentList) {
+ if (equipmentList.remove(obj))
+ equipmentList.sendDeltaMessage(this);
+ }
+ }
+
public void addEquipment(SWGObject obj) {
synchronized(equipmentList) {
if (obj instanceof WeaponObject)
diff --git a/src/services/commands/CommandService.java b/src/services/commands/CommandService.java
index 6eb8984e9..b8b06faa3 100644
--- a/src/services/commands/CommandService.java
+++ b/src/services/commands/CommandService.java
@@ -86,7 +86,8 @@ public class CommandService extends Service {
private void handleCommandRequest(Player player, GalacticManager galacticManager, CommandQueueEnqueue request) {
if (!commands.containsKey(request.getCommandCrc()))
return;
-// System.out.println(commands.get(request.getCrc()).toString());
+// System.out.println(commands.get(request.getCommandCrc()).toString());
+
SWGObject target = null;
if (request.getTargetId() != 0) { target = galacticManager.getObjectManager().getObjectById(request.getTargetId()); }
@@ -159,5 +160,6 @@ public class CommandService extends Service {
registerCallback("kneel", new KneelCmdCallback());
registerCallback("toggleAwayFromKeyBoard", new AfkCmdCallback());
registerCallback("jumpServer", new JumpCmdCallback());
+ registerCallback("serverDestroyObject", new ServerDestroyObjectCmdCallback());
}
}
diff --git a/src/services/objects/ObjectCreator.java b/src/services/objects/ObjectCreator.java
index cb3a8e169..bbc130a2a 100644
--- a/src/services/objects/ObjectCreator.java
+++ b/src/services/objects/ObjectCreator.java
@@ -118,7 +118,7 @@ public final class ObjectCreator {
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.setArrangment(arrangementData.getArrangement());
+ obj.setArrangement(arrangementData.getArrangement());
}
}
diff --git a/src/services/objects/ObjectManager.java b/src/services/objects/ObjectManager.java
index d9b98cd2f..2048c347a 100644
--- a/src/services/objects/ObjectManager.java
+++ b/src/services/objects/ObjectManager.java
@@ -40,6 +40,7 @@ import main.ProjectSWG;
import network.packets.Packet;
import network.packets.swg.zone.HeartBeatMessage;
import network.packets.swg.zone.ParametersMessage;
+import network.packets.swg.zone.SceneDestroyObject;
import network.packets.swg.zone.UpdatePvpStatusMessage;
import network.packets.swg.zone.chat.ChatOnConnectAvatar;
import network.packets.swg.zone.chat.VoiceChatStatus;
@@ -232,7 +233,41 @@ public class ObjectManager extends Manager {
return obj;
}
}
-
+
+ public SWGObject destroyObject(long objectId) {
+ SWGObject object = objects.get(objectId);
+
+ return (object != null ? destroyObject(object) : null);
+ }
+
+ public SWGObject destroyObject(SWGObject object) {
+
+ long objId = object.getObjectId();
+
+ List children = object.getChildren();
+ synchronized (children) {
+ for (SWGObject child : children) {
+ destroyObject(child.getObjectId());
+ }
+ }
+
+ // Remove object from the parent
+ SWGObject parent = object.getParent();
+ if (parent != null) {
+ if (parent instanceof CreatureObject) {
+ ((CreatureObject) parent).removeEquipment(object);
+ }
+ parent.removeChild(object);
+ }
+
+ object.sendObservers(new SceneDestroyObject(objId));
+
+ // Finally, remove from the awareness tree
+ deleteObject(object.getObjectId());
+
+ return object;
+ }
+
public SWGObject createObject(String template) {
return createObject(template, null);
}
diff --git a/src/services/player/LoginService.java b/src/services/player/LoginService.java
index a2ab572f3..9c69cb6b2 100644
--- a/src/services/player/LoginService.java
+++ b/src/services/player/LoginService.java
@@ -127,7 +127,7 @@ public class LoginService extends Service {
}
private void handleCharDeletion(GalacticIntent intent, Player player, DeleteCharacterRequest request) {
- SWGObject obj = intent.getObjectManager().deleteObject(request.getPlayerId());
+ SWGObject obj = intent.getObjectManager().destroyObject(request.getPlayerId());
if (obj != null && obj instanceof CreatureObject)
System.out.println("[" + player.getUsername() + "] Delete Character: " + ((CreatureObject)obj).getName() + ". IP: " + request.getAddress() + ":" + request.getPort());
sendPacket(player, new DeleteCharacterResponse(deleteCharacter(request.getPlayerId())));