diff --git a/src/main/ProjectSWG.java b/src/main/ProjectSWG.java
index e0ae16ea3..2510a3b07 100644
--- a/src/main/ProjectSWG.java
+++ b/src/main/ProjectSWG.java
@@ -31,13 +31,10 @@ import intents.server.ServerStatusIntent;
import resources.Galaxy.GalaxyStatus;
import resources.control.IntentManager;
import resources.control.ServerStatus;
-import resources.server_info.Log;
import services.CoreManager;
public class ProjectSWG {
- private static final String [] ENDINGS = {"B", "KB", "MB", "GB"};
-
private static ProjectSWG server;
private final Thread mainThread;
private CoreManager manager;
@@ -135,7 +132,6 @@ public class ProjectSWG {
private void loop() {
setStatus((manager.getGalaxyStatus() == GalaxyStatus.UP) ? ServerStatus.OPEN : ServerStatus.LOCKED);
- long iter = 0;
while (!shutdownRequested && !manager.isShutdownRequested() && manager.isOperational()) {
manager.flushPackets(); // Sends any packets that weren't sent
try {
@@ -143,25 +139,9 @@ public class ProjectSWG {
} catch (InterruptedException e) {
throw new CoreException("Main Thread Interrupted.");
}
- iter++;
- if (iter % 20 == 0) {
- final Runtime r = Runtime.getRuntime();
- Log.i("ProjectSWG", "Memory Consumption: %s", getMemory((r.totalMemory()-r.freeMemory())));
- }
}
}
- private String getMemory(long bytes) {
- double val = bytes;
- int iters = 0;
- while (val >= 1024) {
- val /= 1024;
- iters++;
- }
- val = ((int) (val * 1E5)) / 1E5;
- return val + ENDINGS[iters];
- }
-
private void stop() {
if (manager == null || status == ServerStatus.OFFLINE)
return;
diff --git a/src/network/OutboundNetworkHandler.java b/src/network/OutboundNetworkHandler.java
index 97788d1d3..31bbf1759 100644
--- a/src/network/OutboundNetworkHandler.java
+++ b/src/network/OutboundNetworkHandler.java
@@ -56,6 +56,8 @@ public class OutboundNetworkHandler {
}
public synchronized void reset() {
+ sequenced.clear();
+ assembleQueue.clear();
sendSequence = 0;
crc = 0;
}
@@ -91,7 +93,7 @@ public class OutboundNetworkHandler {
while (it.hasNext()) {
SequencedPacket sp = it.next();
if (sp.getSequence() <= sequence)
- pushAssembledEncrypted(sp.getPacket());
+ pushAssembledUnencrypted(sp.getPacket()); // Pre-encrypted before putting into list
else
break;
}
@@ -110,11 +112,12 @@ public class OutboundNetworkHandler {
}
}
- private void pushAssembledEncrypted(byte [] data) {
+ private byte [] pushAssembledEncrypted(byte [] data) {
data = Encryption.encode(data, crc);
synchronized (assembleQueue) {
assembleQueue.add(data);
}
+ return data;
}
private void pushAssembledUnencrypted(byte [] data) {
@@ -164,8 +167,8 @@ public class OutboundNetworkHandler {
int lastSeq = updateSequencesMulti((short)(sendSequence+count), m);
for (Fragmented f : Fragmented.encode(m.encode(), sendSequence)) {
byte [] encoded = f.encode().array();
- pushSequencedPacket(f.getSequence(), encoded);
- pushAssembledEncrypted(encoded);
+ byte [] encrypted = pushAssembledEncrypted(encoded);
+ pushSequencedPacket(f.getSequence(), encrypted);
}
sendSequence = (short) (lastSeq + 1);
return count;
@@ -183,16 +186,16 @@ public class OutboundNetworkHandler {
int lastSeq = updateSequenceData((short)(sendSequence+count), d);
for (Fragmented f : Fragmented.encode(d.encode(), sendSequence)) {
byte [] encoded = f.encode().array();
- pushSequencedPacket(f.getSequence(), encoded);
- pushAssembledEncrypted(encoded);
+ byte [] encrypted = pushAssembledEncrypted(encoded);
+ pushSequencedPacket(f.getSequence(), encrypted);
}
sendSequence = (short) lastSeq;
return count;
} else {
d.setSequence(sendSequence++);
byte [] encoded = d.encode().array();
- pushSequencedPacket(d.getSequence(), encoded);
- pushAssembledEncrypted(encoded);
+ byte [] encrypted = pushAssembledEncrypted(encoded);
+ pushSequencedPacket(d.getSequence(), encrypted);
return 1;
}
}
diff --git a/src/network/PacketType.java b/src/network/PacketType.java
index 1fef585c6..657c64edd 100644
--- a/src/network/PacketType.java
+++ b/src/network/PacketType.java
@@ -138,6 +138,8 @@ public enum PacketType {
CHAT_KICK_AVATAR_FROM_ROOM (ChatKickAvatarFromRoom.CRC, ChatKickAvatarFromRoom.class),
CHAT_BAN_AVATAR_FROM_ROOM (ChatBanAvatarFromRoom.CRC, ChatBanAvatarFromRoom.class),
CHAT_UNBAN_AVATAR_FROM_ROOM (ChatUnbanAvatarFromRoom.CRC, ChatUnbanAvatarFromRoom.class),
+ CHAT_ADD_MODERATOR_TO_ROOM (ChatAddModeratorToRoom.CRC, ChatAddModeratorToRoom.class),
+ CHAT_REMOVE_MODERATOR_FROM_ROOM (ChatRemoveModeratorFromRoom.CRC, ChatRemoveModeratorFromRoom.class),
CON_GENERIC_MESSAGE (ConGenericMessage.CRC, ConGenericMessage.class),
VOICE_CHAT_STATUS (VoiceChatStatus.CRC, VoiceChatStatus.class),
diff --git a/src/network/encryption/Encryption.java b/src/network/encryption/Encryption.java
index 73fe79230..7c7334b96 100644
--- a/src/network/encryption/Encryption.java
+++ b/src/network/encryption/Encryption.java
@@ -39,11 +39,21 @@ public class Encryption {
}
public static byte [] encode(byte [] input, int crc) {
- return assembleMessage(input, crc);
+ try {
+ return assembleMessage(input, crc);
+ } catch (Throwable t) {
+ t.printStackTrace();
+ return new byte[0];
+ }
}
public static byte [] decode(byte [] input, int crc) {
- return disassemble(input, crc);
+ try {
+ return disassemble(input, crc);
+ } catch (Throwable t) {
+ t.printStackTrace();
+ return new byte[0];
+ }
}
private static byte [] disassemble(byte [] data, int crcSeed) {
@@ -92,7 +102,12 @@ public class Encryption {
Deflater compressor = new Deflater();
compressor.setInput(data, 2, data.length - 2);
compressor.finish();
- int length = compressor.deflate(result);
+ int length = 0;
+ try {
+ length = compressor.deflate(result);
+ } finally {
+ compressor.end();
+ }
if (length < data.length) {
ByteBuffer bb = ByteBuffer.allocate(length+3);
bb.put(data[0]).put(data[1]);
@@ -132,11 +147,12 @@ public class Encryption {
try {
int length = decompressor.inflate(result);
- decompressor.end();
return length;
} catch (DataFormatException e) {
System.err.println("Failed to decompress packet. "+e.getClass().getSimpleName()+" Message: " + e.getMessage());
return -1;
+ } finally {
+ decompressor.end();
}
}
diff --git a/src/network/packets/swg/zone/chat/ChatAddModeratorToRoom.java b/src/network/packets/swg/zone/chat/ChatAddModeratorToRoom.java
new file mode 100644
index 000000000..cecc2b43a
--- /dev/null
+++ b/src/network/packets/swg/zone/chat/ChatAddModeratorToRoom.java
@@ -0,0 +1,76 @@
+/*******************************************************************************
+ * 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 network.packets.swg.zone.chat;
+
+import network.packets.swg.SWGPacket;
+import resources.chat.ChatAvatar;
+
+import java.nio.ByteBuffer;
+
+/**
+ * @author Waverunner
+ */
+public class ChatAddModeratorToRoom extends SWGPacket {
+ public static final int CRC = getCrc("ChatAddModeratorToRoom");
+
+ private ChatAvatar avatar;
+ private String room;
+ private int sequence;
+
+ @Override
+ public void decode(ByteBuffer data) {
+ if (!super.decode(data, CRC))
+ return;
+ avatar = getEncodable(data, ChatAvatar.class);
+ room = getAscii(data);
+ sequence = getInt(data);
+ }
+
+ @Override
+ public ByteBuffer encode() {
+ ByteBuffer bb = ByteBuffer.allocate(12 + room.length() + avatar.encode().length);
+ addShort(bb, 4);
+ addInt(bb, CRC);
+ addEncodable(bb, avatar);
+ addAscii(bb, room);
+ addInt(bb, sequence);
+ return bb;
+ }
+
+ public ChatAvatar getAvatar() {
+ return avatar;
+ }
+
+ public String getRoom() {
+ return room;
+ }
+
+ public int getSequence() {
+ return sequence;
+ }
+}
diff --git a/src/network/packets/swg/zone/chat/ChatOnAddModeratorToRoom.java b/src/network/packets/swg/zone/chat/ChatOnAddModeratorToRoom.java
new file mode 100644
index 000000000..620c7cfff
--- /dev/null
+++ b/src/network/packets/swg/zone/chat/ChatOnAddModeratorToRoom.java
@@ -0,0 +1,78 @@
+/*******************************************************************************
+ * 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 network.packets.swg.zone.chat;
+
+import network.packets.swg.SWGPacket;
+import resources.chat.ChatAvatar;
+
+import java.nio.ByteBuffer;
+
+/**
+ * @author Waverunner
+ */
+public class ChatOnAddModeratorToRoom extends SWGPacket {
+ public static final int CRC = getCrc("ChatOnAddModeratorToRoom");
+
+ private ChatAvatar target;
+ private ChatAvatar moderator;
+ private int result;
+ private String room;
+ private int sequence;
+
+ public ChatOnAddModeratorToRoom(ChatAvatar target, ChatAvatar moderator, int result, String room, int sequence) {
+ this.target = target;
+ this.moderator = moderator;
+ this.result = result;
+ this.room = room;
+ this.sequence = sequence;
+ }
+
+ @Override
+ public void decode(ByteBuffer data) {
+ if (!super.decode(data, CRC))
+ return;
+ target = getEncodable(data, ChatAvatar.class);
+ moderator = getEncodable(data, ChatAvatar.class);
+ result = getInt(data);
+ room = getAscii(data);
+ sequence = getInt(data);
+ }
+
+ @Override
+ public ByteBuffer encode() {
+ ByteBuffer bb = ByteBuffer.allocate(16 + target.encode().length + moderator.encode().length + room.length());
+ addShort(bb, 1);
+ addInt(bb, CRC);
+ addEncodable(bb, target);
+ addEncodable(bb, moderator);
+ addInt(bb, result);
+ addAscii(bb, room);
+ addInt(bb, sequence);
+ return bb;
+ }
+}
diff --git a/src/network/packets/swg/zone/chat/ChatOnRemoveModeratorFromRoom.java b/src/network/packets/swg/zone/chat/ChatOnRemoveModeratorFromRoom.java
new file mode 100644
index 000000000..5d559b9ab
--- /dev/null
+++ b/src/network/packets/swg/zone/chat/ChatOnRemoveModeratorFromRoom.java
@@ -0,0 +1,78 @@
+/*******************************************************************************
+ * 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 network.packets.swg.zone.chat;
+
+import network.packets.swg.SWGPacket;
+import resources.chat.ChatAvatar;
+
+import java.nio.ByteBuffer;
+
+/**
+ * @author Waverunner
+ */
+public class ChatOnRemoveModeratorFromRoom extends SWGPacket {
+ public static final int CRC = getCrc("ChatOnRemoveModeratorFromRoom");
+
+ private ChatAvatar target;
+ private ChatAvatar moderator;
+ private int result;
+ private String room;
+ private int sequence;
+
+ public ChatOnRemoveModeratorFromRoom(ChatAvatar target, ChatAvatar moderator, int result, String room, int sequence) {
+ this.target = target;
+ this.moderator = moderator;
+ this.result = result;
+ this.room = room;
+ this.sequence = sequence;
+ }
+
+ @Override
+ public void decode(ByteBuffer data) {
+ if (!super.decode(data, CRC))
+ return;
+ target = getEncodable(data, ChatAvatar.class);
+ moderator = getEncodable(data, ChatAvatar.class);
+ result = getInt(data);
+ room = getAscii(data);
+ sequence = getInt(data);
+ }
+
+ @Override
+ public ByteBuffer encode() {
+ ByteBuffer bb = ByteBuffer.allocate(16 + target.encode().length + moderator.encode().length + room.length());
+ addShort(bb, 1);
+ addInt(bb, CRC);
+ addEncodable(bb, target);
+ addEncodable(bb, moderator);
+ addInt(bb, result);
+ addAscii(bb, room);
+ addInt(bb, sequence);
+ return bb;
+ }
+}
diff --git a/src/network/packets/swg/zone/chat/ChatRemoveModeratorFromRoom.java b/src/network/packets/swg/zone/chat/ChatRemoveModeratorFromRoom.java
new file mode 100644
index 000000000..25204eb32
--- /dev/null
+++ b/src/network/packets/swg/zone/chat/ChatRemoveModeratorFromRoom.java
@@ -0,0 +1,76 @@
+/*******************************************************************************
+ * 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 network.packets.swg.zone.chat;
+
+import network.packets.swg.SWGPacket;
+import resources.chat.ChatAvatar;
+
+import java.nio.ByteBuffer;
+
+/**
+ * @author Waverunner
+ */
+public class ChatRemoveModeratorFromRoom extends SWGPacket {
+ public static final int CRC = getCrc("ChatRemoveModeratorFromRoom");
+
+ private ChatAvatar avatar;
+ private String room;
+ private int sequence;
+
+ @Override
+ public void decode(ByteBuffer data) {
+ if (!super.decode(data, CRC))
+ return;
+ avatar = getEncodable(data, ChatAvatar.class);
+ room = getAscii(data);
+ sequence = getInt(data);
+ }
+
+ @Override
+ public ByteBuffer encode() {
+ ByteBuffer bb = ByteBuffer.allocate(12 + room.length() + avatar.encode().length);
+ addShort(bb, 4);
+ addInt(bb, CRC);
+ addEncodable(bb, avatar);
+ addAscii(bb, room);
+ addInt(bb, sequence);
+ return bb;
+ }
+
+ public ChatAvatar getAvatar() {
+ return avatar;
+ }
+
+ public String getRoom() {
+ return room;
+ }
+
+ public int getSequence() {
+ return sequence;
+ }
+}
diff --git a/src/resources/chat/ChatResult.java b/src/resources/chat/ChatResult.java
index 764dfaede..fa237e24e 100644
--- a/src/resources/chat/ChatResult.java
+++ b/src/resources/chat/ChatResult.java
@@ -36,7 +36,7 @@ public enum ChatResult {
TARGET_AVATAR_DOESNT_EXIST(4),
ROOM_INVALID_ID(5),
ROOM_INVALID_NAME(6),
- ROOM_NOT_MODERATOR(9),
+ CUSTOM_FAILURE(9),
ROOM_AVATAR_BANNED(12),
ROOM_PRIVATE(13),
ROOM_AVATAR_NO_PERMISSION(16),
diff --git a/src/resources/chat/ChatRoom.java b/src/resources/chat/ChatRoom.java
index 948d3ce33..63596a7e3 100644
--- a/src/resources/chat/ChatRoom.java
+++ b/src/resources/chat/ChatRoom.java
@@ -32,12 +32,16 @@ import network.packets.swg.SWGPacket;
import network.packets.swg.zone.chat.ChatRoomMessage;
import resources.encodables.Encodable;
import resources.encodables.OutOfBandPackage;
+import resources.objects.SWGObject;
import resources.player.Player;
import services.player.PlayerManager;
+import java.io.IOException;
+import java.io.ObjectInputStream;
import java.io.Serializable;
import java.nio.ByteBuffer;
import java.util.ArrayList;
+import java.util.HashSet;
import java.util.List;
/**
@@ -54,7 +58,7 @@ public class ChatRoom implements Encodable, Serializable {
private String title;
private List moderators;
private List invited;
- private boolean muted; // No one but moderators can talk
+ private boolean moderated; // No one but moderators can talk
private List banned;
// Members are only actually apart of a room when they're "in the room", so we don't need to save this info
// as each player will automatically re-join the room based on their joined channels list
@@ -72,7 +76,12 @@ public class ChatRoom implements Encodable, Serializable {
members = new ArrayList<>();
banned = new ArrayList<>();
}
-
+
+ private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException {
+ members = new ArrayList<>();
+ ois.defaultReadObject();
+ }
+
public int getId() {
return id;
}
@@ -129,12 +138,12 @@ public class ChatRoom implements Encodable, Serializable {
return invited;
}
- public boolean isMuted() {
- return muted;
+ public boolean isModerated() {
+ return moderated;
}
- public void setMuted(boolean muted) {
- this.muted = muted;
+ public void setModerated(boolean moderated) {
+ this.moderated = moderated;
}
public List getMembers() {
@@ -173,8 +182,8 @@ public class ChatRoom implements Encodable, Serializable {
if (banned.contains(avatar))
return ChatResult.ROOM_AVATAR_BANNED;
- if (muted && !moderators.contains(avatar))
- return ChatResult.ROOM_NOT_MODERATOR;
+ if (moderated && !moderators.contains(avatar))
+ return ChatResult.CUSTOM_FAILURE;
return ChatResult.SUCCESS;
}
@@ -210,7 +219,7 @@ public class ChatRoom implements Encodable, Serializable {
public void decode(ByteBuffer data) {
id = Packet.getInt(data);
type = Packet.getInt(data);
- muted = Packet.getBoolean(data);
+ moderated = Packet.getBoolean(data);
path = Packet.getAscii(data);
owner = Packet.getEncodable(data, ChatAvatar.class);
creator = Packet.getEncodable(data, ChatAvatar.class);
@@ -237,7 +246,7 @@ public class ChatRoom implements Encodable, Serializable {
ByteBuffer bb = ByteBuffer.allocate(23 + path.length() + (title.length() * 2) + avatarIdSize);
Packet.addInt(bb, id);
Packet.addInt(bb, type);
- Packet.addBoolean(bb, muted);
+ Packet.addBoolean(bb, moderated);
Packet.addAscii(bb, path);
Packet.addEncodable(bb, owner);
Packet.addEncodable(bb, creator);
@@ -254,6 +263,6 @@ public class ChatRoom implements Encodable, Serializable {
@Override
public String toString() {
return "ChatRoom[id=" + id + ", type=" + type + ", path='" + path + "', title='" + title + '\'' +
- ", creator=" + creator + ", muted=" + muted + ", isPublic=" + isPublic() + "]";
+ ", creator=" + creator + ", moderated=" + moderated + ", isPublic=" + isPublic() + "]";
}
}
diff --git a/src/resources/commands/callbacks/PlayerAppearanceCallback.java b/src/resources/commands/callbacks/PlayerAppearanceCallback.java
new file mode 100644
index 000000000..54a835272
--- /dev/null
+++ b/src/resources/commands/callbacks/PlayerAppearanceCallback.java
@@ -0,0 +1,22 @@
+package resources.commands.callbacks;
+
+import resources.commands.ICmdCallback;
+import resources.objects.SWGObject;
+import resources.objects.creature.CreatureObject;
+import resources.player.Player;
+import services.galaxy.GalacticManager;
+
+public class PlayerAppearanceCallback implements ICmdCallback {
+
+ @Override
+ public void execute(GalacticManager galacticManager, Player player,
+ SWGObject target, String args) {
+ if(target instanceof CreatureObject) {
+ CreatureObject creatureTarget = (CreatureObject) target;
+
+ creatureTarget.setCostume(args);
+ }
+
+ }
+
+}
diff --git a/src/resources/commands/callbacks/RevertAppearanceCallback.java b/src/resources/commands/callbacks/RevertAppearanceCallback.java
new file mode 100644
index 000000000..bfa5e498d
--- /dev/null
+++ b/src/resources/commands/callbacks/RevertAppearanceCallback.java
@@ -0,0 +1,22 @@
+package resources.commands.callbacks;
+
+import resources.commands.ICmdCallback;
+import resources.objects.SWGObject;
+import resources.objects.creature.CreatureObject;
+import resources.player.Player;
+import services.galaxy.GalacticManager;
+
+public class RevertAppearanceCallback implements ICmdCallback {
+
+ @Override
+ public void execute(GalacticManager galacticManager, Player player,
+ SWGObject target, String args) {
+ if(target instanceof CreatureObject) {
+ CreatureObject creatureTarget = (CreatureObject) target;
+
+ creatureTarget.setCostume("");
+ }
+
+ }
+
+}
diff --git a/src/resources/objects/SWGObject.java b/src/resources/objects/SWGObject.java
index a670e8163..afb39d04b 100644
--- a/src/resources/objects/SWGObject.java
+++ b/src/resources/objects/SWGObject.java
@@ -46,6 +46,7 @@ import resources.containers.DefaultPermissions;
import resources.encodables.StringId;
import resources.network.BaselineBuilder;
import resources.network.DeltaBuilder;
+import resources.objects.creature.CreatureObject;
import resources.player.Player;
import resources.player.PlayerState;
import resources.server_info.Log;
@@ -578,7 +579,7 @@ public abstract class SWGObject implements Serializable, Comparable {
return (filledId != -1) ? filledId : -1;
}
- protected final void sendSceneCreateObject(Player target) {
+ private final void sendSceneCreateObject(Player target) {
SceneCreateObjectByCrc create = new SceneCreateObjectByCrc();
create.setObjectId(objectId);
create.setLocation(location);
@@ -589,7 +590,7 @@ public abstract class SWGObject implements Serializable, Comparable {
}
- protected final void sendSceneDestroyObject(Player target) {
+ private final void sendSceneDestroyObject(Player target) {
SceneDestroyObject destroy = new SceneDestroyObject();
destroy.setObjectId(objectId);
target.sendPacket(destroy);
@@ -607,6 +608,10 @@ public abstract class SWGObject implements Serializable, Comparable {
target.sendPacket(new SceneEndBaselines(getObjectId()));
}
+ public void destroyObject(Player target) {
+ sendSceneDestroyObject(target);
+ }
+
public void clearAware() {
SWGObject [] objects;
synchronized (objectsAware) {
@@ -741,7 +746,7 @@ public abstract class SWGObject implements Serializable, Comparable {
for (SWGObject swgObject : removed) {
if (swgObject.getOwner() != null) {
- sendSceneDestroyObject(swgObject.getOwner());
+ destroyObject(swgObject.getOwner());
}
}
}
@@ -766,7 +771,7 @@ public abstract class SWGObject implements Serializable, Comparable {
if (objectsAware.remove(o)) {
Player owner = o.getOwner();
if (owner != null)
- sendSceneDestroyObject(owner);
+ destroyObject(owner);
else
destroyObjectObservers(o);
}
@@ -797,7 +802,7 @@ public abstract class SWGObject implements Serializable, Comparable {
Set observers = new HashSet<>();
getChildrenObservers(observers, obj);
for (SWGObject observer : observers) {
- sendSceneDestroyObject(observer.getOwner());
+ destroyObject(observer.getOwner());
}
}
@@ -854,6 +859,8 @@ public abstract class SWGObject implements Serializable, Comparable {
// Now create the contained objects
for (SWGObject containedObject : containedObjects.values()) {
if (containedObject != null && !sentObjects.contains(containedObject)) {
+ if (containedObject instanceof CreatureObject && containedObject.hasSlot("ghost") && containedObject.getOwner() == null)
+ continue; // If it's a player, but that's logged out
containedObject.createObject(target);
}
}
diff --git a/src/resources/objects/creature/CreatureObject.java b/src/resources/objects/creature/CreatureObject.java
index 56498c884..a2f5eedb0 100644
--- a/src/resources/objects/creature/CreatureObject.java
+++ b/src/resources/objects/creature/CreatureObject.java
@@ -265,12 +265,12 @@ public class CreatureObject extends TangibleObject {
public void setCashBalance(int cashBalance) {
this.cashBalance = cashBalance;
- sendDelta(1, 0, cashBalance);
+ sendDelta(1, 1, cashBalance);
}
public void setBankBalance(int bankBalance) {
this.bankBalance = bankBalance;
- sendDelta(1, 1, bankBalance);
+ sendDelta(1, 0, bankBalance);
}
public void setMovementScale(double movementScale) {
@@ -682,8 +682,8 @@ public class CreatureObject extends TangibleObject {
public void createBaseline1(Player target, BaselineBuilder bb) {
super.createBaseline1(target, bb); // 0 variables
- bb.addInt(cashBalance); // 0
- bb.addInt(bankBalance); // 1
+ bb.addInt(bankBalance); // 0
+ bb.addInt(cashBalance); // 1
bb.addObject(baseAttributes); // Attributes player has without any gear on -- 2
bb.addObject(skills); // 3
diff --git a/src/services/chat/ChatManager.java b/src/services/chat/ChatManager.java
index 61a6224a3..672c2644d 100644
--- a/src/services/chat/ChatManager.java
+++ b/src/services/chat/ChatManager.java
@@ -65,12 +65,12 @@ import java.util.Locale;
public class ChatManager extends Manager {
- private ObjectDatabase mails;
+ private final ObjectDatabase mails;
+ private final ChatRoomService roomService;
private int maxMailId;
- private ChatRoomService roomService;
- public ChatManager() {
- roomService = new ChatRoomService();
+ public ChatManager(Galaxy g) {
+ roomService = new ChatRoomService(g);
mails = new CachedObjectDatabase<>("odb/mails.db");
maxMailId = 1;
@@ -227,10 +227,6 @@ public class ChatManager extends Manager {
}
}
- public void initializeGalaxyChannels(Galaxy galaxy) {
- roomService.createSystemChannels(galaxy.getName());
- }
-
/* Friends List */
private void handleRequestFriendList(Player player) {
diff --git a/src/services/chat/ChatRoomService.java b/src/services/chat/ChatRoomService.java
index e5e97cfa8..ea296a911 100644
--- a/src/services/chat/ChatRoomService.java
+++ b/src/services/chat/ChatRoomService.java
@@ -32,12 +32,14 @@ import intents.chat.ChatRoomUpdateIntent;
import intents.network.GalacticPacketIntent;
import network.packets.Packet;
import network.packets.swg.SWGPacket;
+import network.packets.swg.zone.chat.ChatAddModeratorToRoom;
import network.packets.swg.zone.chat.ChatBanAvatarFromRoom;
import network.packets.swg.zone.chat.ChatCreateRoom;
import network.packets.swg.zone.chat.ChatDestroyRoom;
import network.packets.swg.zone.chat.ChatEnterRoomById;
import network.packets.swg.zone.chat.ChatInviteAvatarToRoom;
import network.packets.swg.zone.chat.ChatKickAvatarFromRoom;
+import network.packets.swg.zone.chat.ChatOnAddModeratorToRoom;
import network.packets.swg.zone.chat.ChatOnBanAvatarFromRoom;
import network.packets.swg.zone.chat.ChatOnCreateRoom;
import network.packets.swg.zone.chat.ChatOnDestroyRoom;
@@ -46,17 +48,20 @@ import network.packets.swg.zone.chat.ChatOnInviteToRoom;
import network.packets.swg.zone.chat.ChatOnKickAvatarFromRoom;
import network.packets.swg.zone.chat.ChatOnLeaveRoom;
import network.packets.swg.zone.chat.ChatOnReceiveRoomInvitation;
+import network.packets.swg.zone.chat.ChatOnRemoveModeratorFromRoom;
import network.packets.swg.zone.chat.ChatOnSendRoomMessage;
import network.packets.swg.zone.chat.ChatOnUnbanAvatarFromRoom;
import network.packets.swg.zone.chat.ChatOnUninviteFromRoom;
import network.packets.swg.zone.chat.ChatQueryRoom;
import network.packets.swg.zone.chat.ChatQueryRoomResults;
import network.packets.swg.zone.chat.ChatRemoveAvatarFromRoom;
+import network.packets.swg.zone.chat.ChatRemoveModeratorFromRoom;
import network.packets.swg.zone.chat.ChatRequestRoomList;
import network.packets.swg.zone.chat.ChatSendToRoom;
import network.packets.swg.zone.chat.ChatUnbanAvatarFromRoom;
import network.packets.swg.zone.chat.ChatUninviteFromRoom;
import network.packets.swg.zone.insertion.ChatRoomList;
+import resources.Galaxy;
import resources.Terrain;
import resources.chat.ChatAvatar;
import resources.chat.ChatResult;
@@ -68,6 +73,8 @@ import resources.control.Service;
import resources.objects.player.PlayerObject;
import resources.player.AccessLevel;
import resources.player.Player;
+import resources.server_info.CachedObjectDatabase;
+import resources.server_info.ObjectDatabase;
import services.player.PlayerManager;
import java.util.ArrayList;
@@ -81,12 +88,16 @@ import java.util.concurrent.ConcurrentHashMap;
* @author Waverunner
*/
public class ChatRoomService extends Service {
- private int maxChatRoomId;
- private Map roomMap;
// Map to keep track of each player's recent message for a room to prevent duplicates from client
- private Map> messages;
+ private final Map> messages;
+ private final ObjectDatabase database;
+ private final Map roomMap;
+ private final Galaxy galaxy;
+ private int maxChatRoomId;
- public ChatRoomService() {
+ public ChatRoomService(Galaxy g) {
+ galaxy = g;
+ database = new CachedObjectDatabase<>("odb/chat_rooms.db");
roomMap = new ConcurrentHashMap<>();
messages = new ConcurrentHashMap<>();
maxChatRoomId = 1;
@@ -94,10 +105,17 @@ public class ChatRoomService extends Service {
@Override
public boolean initialize() {
- // TODO: Load up persistent channels
registerForIntent(ChatRoomUpdateIntent.TYPE);
registerForIntent(GalacticPacketIntent.TYPE);
+ database.load();
+ database.traverse((room) -> {
+ if (room.getId() >= maxChatRoomId)
+ maxChatRoomId++;
+ roomMap.put(room.getId(), room);
+ });
+
+ createSystemChannels(galaxy.getName());
return super.initialize();
}
@@ -162,6 +180,13 @@ public class ChatRoomService extends Service {
break;
case CHAT_UNBAN_AVATAR_FROM_ROOM:
if (p instanceof ChatUnbanAvatarFromRoom) handleChatUnbanAvatarFromRoom(player, (ChatUnbanAvatarFromRoom) p);
+ break;
+ case CHAT_ADD_MODERATOR_TO_ROOM:
+ if (p instanceof ChatAddModeratorToRoom) handleChatAddModeratorToRoom(player, (ChatAddModeratorToRoom) p);
+ break;
+ case CHAT_REMOVE_MODERATOR_FROM_ROOM:
+ if (p instanceof ChatRemoveModeratorFromRoom) handleChatRemoveModeratorFromRoom(player, (ChatRemoveModeratorFromRoom) p);
+ break;
default: break;
}
}
@@ -176,6 +201,79 @@ public class ChatRoomService extends Service {
/* Chat Rooms */
+ private void handleChatRemoveModeratorFromRoom(Player player, ChatRemoveModeratorFromRoom p) {
+ String path = p.getRoom();
+ ChatAvatar target = p.getAvatar();
+ int sequence = p.getSequence();
+
+ ChatRoom room = getRoom(path);
+ ChatAvatar sender = ChatAvatar.getFromPlayer(player);
+
+ if (room == null) {
+ player.sendPacket(new ChatOnRemoveModeratorFromRoom(target, sender, ChatResult.ROOM_INVALID_NAME.getCode(), path, sequence));
+ return;
+ }
+
+ if (!room.isModerated()) {
+ player.sendPacket(new ChatOnRemoveModeratorFromRoom(target, sender, ChatResult.CUSTOM_FAILURE.getCode(), path, sequence));
+ return;
+ }
+
+ if (!room.isModerator(sender)) {
+ player.sendPacket(new ChatOnRemoveModeratorFromRoom(target, sender, ChatResult.ROOM_AVATAR_NO_PERMISSION.getCode(), path, sequence));
+ return;
+ }
+
+ if (!room.getModerators().remove(target)) {
+ player.sendPacket(new ChatOnRemoveModeratorFromRoom(target, sender, ChatResult.TARGET_AVATAR_DOESNT_EXIST.getCode(), path, sequence));
+ return;
+ }
+
+ player.sendPacket(new ChatOnRemoveModeratorFromRoom(target, sender, ChatResult.SUCCESS.getCode(), path, sequence));
+ }
+
+ private void handleChatAddModeratorToRoom(Player player, ChatAddModeratorToRoom p) {
+ String path = p.getRoom();
+ ChatAvatar target = p.getAvatar();
+ int sequence = p.getSequence();
+
+ ChatRoom room = getRoom(path);
+ ChatAvatar sender = ChatAvatar.getFromPlayer(player);
+
+ if (room == null) {
+ player.sendPacket(new ChatOnAddModeratorToRoom(target, sender, ChatResult.ROOM_INVALID_NAME.getCode(), path, sequence));
+ return;
+ }
+
+ if (!room.isModerated()) {
+ player.sendPacket(new ChatOnAddModeratorToRoom(target, sender, ChatResult.CUSTOM_FAILURE.getCode(), path, sequence));
+ return;
+ }
+
+ if (!room.isModerator(sender)) {
+ player.sendPacket(new ChatOnAddModeratorToRoom(target, sender, ChatResult.ROOM_AVATAR_NO_PERMISSION.getCode(), path, sequence));
+ return;
+ }
+
+ Player targetPlayer = player.getPlayerManager().getPlayerByCreatureFirstName(target.getName());
+ if (targetPlayer == null) {
+ player.sendPacket(new ChatOnAddModeratorToRoom(target, sender, ChatResult.TARGET_AVATAR_DOESNT_EXIST.getCode(), path, sequence));
+ return;
+ }
+
+ // Remove from ban list
+ if (room.getBanned().remove(target)) {
+ room.sendPacketToMembers(player.getPlayerManager(), new ChatOnUnbanAvatarFromRoom(path, sender, target, ChatResult.SUCCESS.getCode(), 0));
+ }
+
+ if (!room.getModerators().add(target)) {
+ player.sendPacket(new ChatOnAddModeratorToRoom(target, sender, ChatResult.NONE.getCode(), path, sequence));
+ return;
+ }
+
+ player.sendPacket(new ChatOnAddModeratorToRoom(target, sender, ChatResult.SUCCESS.getCode(), path, sequence));
+ }
+
private void handleChatUnbanAvatarFromRoom(Player player, ChatUnbanAvatarFromRoom p) {
String path = p.getRoom();
ChatAvatar target = p.getAvatar();
@@ -269,11 +367,6 @@ public class ChatRoomService extends Service {
return;
}
- if (room.isMember(target)) {
- player.sendPacket(new ChatOnKickAvatarFromRoom(target, sender, ChatResult.NONE.getCode(), path));
- return;
- }
-
room.sendPacketToMembers(player.getPlayerManager(), new ChatOnKickAvatarFromRoom(target, sender, ChatResult.SUCCESS.getCode(), path));
}
@@ -290,7 +383,7 @@ public class ChatRoomService extends Service {
}
if (room.isPublic()) {
- player.sendPacket(new ChatOnUninviteFromRoom(path, sender, invitee, ChatResult.NONE.getCode(), p.getSequence()));
+ player.sendPacket(new ChatOnUninviteFromRoom(path, sender, invitee, ChatResult.CUSTOM_FAILURE.getCode(), p.getSequence()));
return;
}
@@ -318,7 +411,7 @@ public class ChatRoomService extends Service {
}
if (room.isPublic()) {
- player.sendPacket(new ChatOnInviteToRoom(path, sender, p.getAvatar(), ChatResult.NONE.getCode()));
+ player.sendPacket(new ChatOnInviteToRoom(path, sender, p.getAvatar(), ChatResult.CUSTOM_FAILURE.getCode()));
return;
}
@@ -368,8 +461,8 @@ public class ChatRoomService extends Service {
result = ChatResult.ROOM_ALREADY_EXISTS;
if (result == ChatResult.SUCCESS) {
- room = createRoom(ChatAvatar.getFromPlayer(player), p.isPublic(), path, title);
- room.setMuted(p.isModerated());
+ room = createRoom(ChatAvatar.getFromPlayer(player), p.isPublic(), path, title, true);
+ room.setModerated(p.isModerated());
}
player.sendPacket(new ChatOnCreateRoom(result.getCode(), room, p.getSequence()));
@@ -547,19 +640,24 @@ public class ChatRoomService extends Service {
public void leaveChatChannel(Player player, String path) {
for (ChatRoom chatRoom : roomMap.values()) {
- if (chatRoom.getPath().equals(path))
+ if (chatRoom.getPath().equals(path)) {
leaveChatChannel(player, chatRoom, 0);
+ break;
+ }
}
}
+
/**
- * Creates a new, non-persistent, chat room with the specified address path.
+ * Creates a new chat room with the specified address path. If the path's parent channel doesn't exist, then a new
+ * chat room is created with the same passed arguments.
* @param creator Room creator who will also become the owner of this room
* @param isPublic Determines if the room should be publicly displayed in the channel listing
* @param path Address for the channel (Ex: SWG.serverName.Imperial)
* @param title Descriptive name of the chat channel (Ex: Imperial chat for this galaxy)
+ * @param persist If true then this channel will be saved in an {@link ObjectDatabase}
* @return {@link ChatRoom}
*/
- public ChatRoom createRoom(ChatAvatar creator, boolean isPublic, String path, String title) {
+ public ChatRoom createRoom(ChatAvatar creator, boolean isPublic, String path, String title, boolean persist) {
if (path.isEmpty() || path.endsWith("."))
return null;
@@ -567,12 +665,15 @@ public class ChatRoomService extends Service {
if (!path.startsWith(base) || path.equals(base))
return null;
+ if (getRoom(path) != null)
+ return getRoom(path);
+
// All paths should have parents, lets validate to make sure they exist first. Create them if they don't.
int lastIndex = path.lastIndexOf(".");
if (lastIndex != -1) {
String parentPath = path.substring(0, lastIndex);
if (getRoom(parentPath) == null) {
- createRoom(creator, isPublic, parentPath, "");
+ createRoom(creator, isPublic, parentPath, "", persist);
}
}
@@ -588,9 +689,24 @@ public class ChatRoomService extends Service {
room.setTitle(title);
roomMap.put(id, room);
+
+ if (persist)
+ database.put(id, room);
return room;
}
+ /**
+ * Creates a new, non-persistent, chat room with the specified address path.
+ * @param creator Room creator who will also become the owner of this room
+ * @param isPublic Determines if the room should be publicly displayed in the channel listing
+ * @param path Address for the channel (Ex: SWG.serverName.Imperial)
+ * @param title Descriptive name of the chat channel (Ex: Imperial chat for this galaxy)
+ * @return {@link ChatRoom}
+ */
+ public ChatRoom createRoom(ChatAvatar creator, boolean isPublic, String path, String title) {
+ return createRoom(creator, isPublic, path, title, false);
+ }
+
public boolean notifyDestroyRoom(ChatAvatar destroyer, String roomPath, int sequence) {
ChatRoom room = getRoom(roomPath);
if (roomPath == null)
@@ -635,7 +751,7 @@ public class ChatRoomService extends Service {
String basePath = "SWG." + galaxy + ".";
DatatableData rooms = ServerFactory.getDatatable("chat/default_rooms.iff");
- rooms.handleRows((r) -> createRoom(systemAvatar, true, basePath + rooms.getCell(r, 0), (String) rooms.getCell(r, 1)));
+ rooms.handleRows((r) -> createRoom(systemAvatar, true, basePath + rooms.getCell(r, 0), (String) rooms.getCell(r, 1), true));
createPlanetChannels(systemAvatar, basePath);
@@ -652,9 +768,9 @@ public class ChatRoomService extends Service {
DatatableData planets = ServerFactory.getDatatable("chat/planets.iff");
planets.handleRows((r) -> {
String path = basePath + planets.getCell(r, 0) + ".";
- createRoom(systemAvatar, true, path + "Planet", "public chat for this planet, cannot create rooms here");
- createRoom(systemAvatar, true, path + "system", "system messages for this planet, cannot create rooms here");
- createRoom(systemAvatar, true, path + "Chat", "public chat for this planet, can create rooms here");
+ createRoom(systemAvatar, true, path + "Planet", "public chat for this planet, cannot create rooms here", true);
+ createRoom(systemAvatar, true, path + "system", "system messages for this planet, cannot create rooms here", true);
+ createRoom(systemAvatar, true, path + "Chat", "public chat for this planet, can create rooms here", true);
});
}
diff --git a/src/services/commands/CommandService.java b/src/services/commands/CommandService.java
index 95937b0cf..e1f2daa28 100644
--- a/src/services/commands/CommandService.java
+++ b/src/services/commands/CommandService.java
@@ -172,6 +172,8 @@ public class CommandService extends Service {
registerCallback("jumpServer", new JumpCmdCallback());
registerCallback("serverDestroyObject", new ServerDestroyObjectCmdCallback());
registerCallback("findFriend", new FindFriendCallback());
+ registerCallback("setPlayerAppearance", new PlayerAppearanceCallback());
+ registerCallback("revertPlayerAppearance", new RevertAppearanceCallback());
}
private void clearCommands() {
diff --git a/src/services/galaxy/GalacticManager.java b/src/services/galaxy/GalacticManager.java
index cdc454208..894839b6f 100644
--- a/src/services/galaxy/GalacticManager.java
+++ b/src/services/galaxy/GalacticManager.java
@@ -53,7 +53,7 @@ public class GalacticManager extends Manager {
objectManager = new ObjectManager();
playerManager = new PlayerManager();
gameManager = new GameManager();
- chatManager = new ChatManager();
+ chatManager = new ChatManager(g);
prevPacketIntent = null;
addChildService(objectManager);
@@ -65,7 +65,6 @@ public class GalacticManager extends Manager {
@Override
public boolean initialize() {
registerForIntent(InboundPacketIntent.TYPE);
- chatManager.initializeGalaxyChannels(galaxy);
return super.initialize();
}
diff --git a/src/services/network/NetworkClientManager.java b/src/services/network/NetworkClientManager.java
index 548ef21d1..00b773962 100644
--- a/src/services/network/NetworkClientManager.java
+++ b/src/services/network/NetworkClientManager.java
@@ -35,9 +35,13 @@ import java.net.InetAddress;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.LinkedList;
import java.util.List;
import java.util.Map;
+import java.util.Queue;
import java.util.Random;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
import network.NetworkClient;
import network.PacketReceiver;
@@ -57,15 +61,30 @@ public class NetworkClientManager extends Manager implements PacketReceiver {
private final Map > clients;
private final Map networkClients;
+ private final Queue receivedPackets;
+ private final ExecutorService packetProcessor;
private final Random crcGenerator;
private final PacketSender packetSender;
+ private final Runnable processPacketRunnable;
private long networkId;
public NetworkClientManager(PacketSender packetSender) {
this.packetSender = packetSender;
clients = new HashMap>();
networkClients = new HashMap();
+ receivedPackets = new LinkedList<>();
+ packetProcessor = Executors.newCachedThreadPool();
crcGenerator = new Random();
+ processPacketRunnable = new Runnable() {
+ public void run() {
+ synchronized (receivedPackets) {
+ ReceivedPacket recv = receivedPackets.poll();
+ if (recv == null)
+ return;
+ handlePacket(recv.getType(), recv.getPacket());
+ }
+ }
+ };
networkId = 0;
}
@@ -87,9 +106,12 @@ public class NetworkClientManager extends Manager implements PacketReceiver {
@Override
public void receivePacket(ServerType type, UDPPacket packet) {
- handlePacket(type, packet);
+ synchronized (receivedPackets) {
+ receivedPackets.add(new ReceivedPacket(type, packet));
+ }
+ packetProcessor.submit(processPacketRunnable);
}
-
+
@Override
public void onIntentReceived(Intent i) {
if (i instanceof OutboundPacketIntent) {
@@ -276,4 +298,22 @@ public class NetworkClientManager extends Manager implements PacketReceiver {
return false;
}
+ private static class ReceivedPacket {
+ private final ServerType type;
+ private final UDPPacket packet;
+
+ public ReceivedPacket(ServerType type, UDPPacket packet) {
+ this.type = type;
+ this.packet = packet;
+ }
+
+ public ServerType getType() {
+ return type;
+ }
+
+ public UDPPacket getPacket() {
+ return packet;
+ }
+ }
+
}
diff --git a/src/services/objects/ObjectManager.java b/src/services/objects/ObjectManager.java
index be4314258..94ff89a6d 100644
--- a/src/services/objects/ObjectManager.java
+++ b/src/services/objects/ObjectManager.java
@@ -205,7 +205,8 @@ public class ObjectManager extends Manager {
private void loadObject(SWGObject obj) {
obj.setOwner(null);
- if (!(obj instanceof CreatureObject) || ((CreatureObject) obj).getPlayerObject() == null)
+ // if player is not a player
+ if (!(obj instanceof CreatureObject && ((CreatureObject) obj).hasSlot("ghost")))
objectAwareness.add(obj);
if (obj instanceof CreatureObject && ((CreatureObject) obj).getPlayerObject() != null) {
if (!obj.hasSlot("bank"))
@@ -265,10 +266,14 @@ public class ObjectManager extends Manager {
case PE_DISAPPEAR:
p.getCreatureObject().clearAware();
objectAwareness.remove(p.getCreatureObject());
+ for (SWGObject obj : p.getCreatureObject().getObservers())
+ p.getCreatureObject().destroyObject(obj.getOwner());
break;
case PE_ZONE_IN:
p.getCreatureObject().clearAware();
objectAwareness.update(p.getCreatureObject());
+ if (p.getCreatureObject().getParent() == null)
+ p.getCreatureObject().createObject(p);
break;
default:
break;
diff --git a/src/services/player/ZoneManager.java b/src/services/player/ZoneManager.java
index d33b64eea..22e59a7ff 100644
--- a/src/services/player/ZoneManager.java
+++ b/src/services/player/ZoneManager.java
@@ -46,7 +46,6 @@ import network.packets.swg.zone.RequestGalaxyLoopTimes;
import network.packets.swg.zone.SetWaypointColor;
import network.packets.swg.zone.ShowBackpack;
import network.packets.swg.zone.ShowHelmet;
-import network.packets.swg.zone.UpdatePvpStatusMessage;
import network.packets.swg.zone.chat.ChatOnConnectAvatar;
import network.packets.swg.zone.chat.ChatSystemMessage;
import network.packets.swg.zone.chat.VoiceChatStatus;
@@ -136,8 +135,6 @@ public class ZoneManager extends Manager {
sendZonePackets(player, creature);
initPlayerBeforeZoneIn(player, creature, playerObj);
- if (creature.getParent() == null)
- creature.createObject(player);
System.out.printf("[%s] %s is zoning in%n", player.getUsername(), player.getCharacterName());
Log.i("ObjectManager", "Zoning in %s with character %s", player.getUsername(), player.getCharacterName());
sendCommitHistory(player);
@@ -189,7 +186,7 @@ public class ZoneManager extends Manager {
sendPacket(player, new ParametersMessage());
sendPacket(player, new ChatOnConnectAvatar());
sendPacket(player, new CmdStartScene(false, objId, race, l, time));
- sendPacket(player, new UpdatePvpStatusMessage(creature.getPvpType(), creature.getPvpFactionId(), creature.getObjectId()));
+ flushPackets();
}
private void initPlayerBeforeZoneIn(Player player, CreatureObject creatureObj, PlayerObject playerObj) {
diff --git a/src/utilities/Encoder.java b/src/utilities/Encoder.java
index d273624b1..d0c27aec2 100644
--- a/src/utilities/Encoder.java
+++ b/src/utilities/Encoder.java
@@ -40,7 +40,7 @@ public class Encoder {
}
public static byte[] encode(Object object, StringType strType) {
- if (strType != StringType.UNSPECIFIED) {
+ if (strType != StringType.UNSPECIFIED && object instanceof String) {
switch (strType) {
case ASCII: return encodeAscii((String) object);
case UNICODE: return encodeUnicode((String) object);
diff --git a/src/utilities/IntentFactory.java b/src/utilities/IntentFactory.java
new file mode 100644
index 000000000..f5ba6229d
--- /dev/null
+++ b/src/utilities/IntentFactory.java
@@ -0,0 +1,42 @@
+package utilities;
+
+import resources.encodables.player.Mail;
+import resources.objects.SWGObject;
+import resources.player.Player;
+import intents.chat.ChatBroadcastIntent;
+import intents.chat.ChatBroadcastIntent.BroadcastType;
+import intents.chat.PersistentMessageIntent;
+
+/**
+ * @author Mads
+ * This class is to be used exclusively in cases where using the intents directly isn't practical.
+ */
+public final class IntentFactory {
+
+ private void broadcast(String message, Player source, BroadcastType type) {
+ new ChatBroadcastIntent(message, source, source.getCreatureObject().getTerrain(), type).broadcast();
+ }
+
+ public void broadcastArea(String message, Player source) {
+ broadcast(message, source, BroadcastType.AREA);
+ }
+
+ public void broadcastGalaxy(String message, Player source) {
+ broadcast(message, source, BroadcastType.GALAXY);
+ }
+
+ public void broadcastPersonal(String message, Player source) {
+ broadcast(message, source, BroadcastType.PERSONAL);
+ }
+
+ public void broadcastPlanet(String message, Player source) {
+ broadcast(message, source, BroadcastType.PLANET);
+ }
+
+ public void sendMail(SWGObject receiver, String sender, String subject, String message) {
+ Mail mail = new Mail(sender, subject, message, receiver.getObjectId());
+
+ new PersistentMessageIntent(receiver, mail, receiver.getOwner().getGalaxyName()).broadcast();
+ }
+
+}
diff --git a/src/utilities/Scripts.java b/src/utilities/Scripts.java
index 409bd90e5..ff8859506 100644
--- a/src/utilities/Scripts.java
+++ b/src/utilities/Scripts.java
@@ -41,6 +41,10 @@ public class Scripts {
private static final ScriptEngine ENGINE = new ScriptEngineManager().getEngineByName("nashorn");
private static final Invocable INVOCABLE = (Invocable) ENGINE;
+ static {
+ ENGINE.put("intentFactory", new IntentFactory());
+ }
+
// Prevents instantiation.
private Scripts() {}