diff --git a/scripts/commands/generic/planetChat.py b/scripts/commands/generic/planetChat.py
new file mode 100644
index 000000000..e25c9b15a
--- /dev/null
+++ b/scripts/commands/generic/planetChat.py
@@ -0,0 +1,3 @@
+
+def execute(galacticManager, player, target, args):
+ return
diff --git a/src/intents/chat/ChatRoomUpdateIntent.java b/src/intents/chat/ChatRoomUpdateIntent.java
new file mode 100644
index 000000000..e2093c877
--- /dev/null
+++ b/src/intents/chat/ChatRoomUpdateIntent.java
@@ -0,0 +1,111 @@
+/*******************************************************************************
+ * 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 intents.chat;
+
+import resources.chat.ChatAvatar;
+import resources.control.Intent;
+
+/**
+ * @author Waverunner
+ */
+public class ChatRoomUpdateIntent extends Intent {
+ public static final String TYPE = "ChatRoomIntent";
+
+ private String path;
+ private String title;
+ private String target;
+ private ChatAvatar avatar;
+ private String message;
+ private UpdateType updateType;
+ private boolean isPublic;
+
+ public ChatRoomUpdateIntent(String path, String title, String target, ChatAvatar avatar, String message, UpdateType updateType) {
+ super(TYPE);
+ this.path = path;
+ this.updateType = updateType;
+ this.avatar = avatar;
+
+ switch(updateType) {
+ case DESTROY: break;
+ case CREATE: this.title = title; break;
+ case SEND_MESSAGE: this.message = message; break;
+ default: this.target = target; break;
+ }
+ }
+
+ public ChatRoomUpdateIntent(ChatAvatar avatar, String path, String title, boolean isPublic) {
+ this(path, title, null, avatar, null, UpdateType.CREATE);
+ this.isPublic = isPublic;
+ }
+
+ public ChatRoomUpdateIntent(ChatAvatar avatar, String path, UpdateType updateType) {
+ this(path, null, null, avatar, null, updateType);
+ }
+
+ public String getPath() {
+ return path;
+ }
+
+ public String getTitle() {
+ return title;
+ }
+
+ public String getTarget() {
+ return target;
+ }
+
+ public ChatAvatar getAvatar() {
+ return avatar;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ public UpdateType getUpdateType() {
+ return updateType;
+ }
+
+ public boolean isPublic() {
+ return isPublic;
+ }
+
+ public enum UpdateType {
+ CREATE,
+ DESTROY,
+ JOIN,
+ LEAVE,
+ MODERATORS_ADD_TARGET,
+ MODERATORS_REMOVE_TARGET,
+ BANNED_ADD_TARGET,
+ BANNED_REMOVE_TARGET,
+ INVITED_ADD_TARGET,
+ INVITED_REMOVE_TARGET,
+ SEND_MESSAGE
+ }
+}
diff --git a/src/network/PacketType.java b/src/network/PacketType.java
index e4645342e..de5141510 100644
--- a/src/network/PacketType.java
+++ b/src/network/PacketType.java
@@ -121,9 +121,12 @@ public enum PacketType {
CHAT_PERSISTENT_MESSAGE_TO_SERVER (0x25A29FA6, ChatPersistentMessageToServer.class),
CHAT_DELETE_PERSISTENT_MESSAGE (0x8F251641, ChatDeletePersistentMessage.class),
CHAT_REQUEST_PERSISTENT_MESSAGE (0x07E3559F, ChatRequestPersistentMessage.class),
- CHAT_REQUEST_ROOM_LIST (0x4C3d2CfA, ChatRequestRoomList.class),
- CHAT_ROOM_LIST (0x70DEB197, ChatRoomList.class),
- CHAT_ROOM_MESSAGE (0xCD4CE444, ChatRoomMessage.class),
+ CHAT_REQUEST_ROOM_LIST (ChatRequestRoomList.CRC, ChatRequestRoomList.class),
+ CHAT_ENTER_ROOM_BY_ID (ChatEnterRoomById.CRC, ChatEnterRoomById.class),
+ CHAT_QUERY_ROOM (ChatQueryRoom.CRC, ChatQueryRoom.class),
+ CHAT_ROOM_LIST (ChatRoomList.CRC, ChatRoomList.class),
+ CHAT_ROOM_MESSAGE (ChatRoomMessage.CRC, ChatRoomMessage.class),
+ CHAT_SEND_TO_ROOM (ChatSendToRoom.CRC, ChatSendToRoom.class),
CHAT_SERVER_STATUS (0x7102B15F, ChatServerStatus.class),
CHAT_SYSTEM_MESSAGE (0x6D2A6413, ChatSystemMessage.class),
CON_GENERIC_MESSAGE (0x08C5FC76, ConGenericMessage.class),
diff --git a/src/network/packets/Packet.java b/src/network/packets/Packet.java
index af0742e69..b1cf7c78f 100644
--- a/src/network/packets/Packet.java
+++ b/src/network/packets/Packet.java
@@ -27,10 +27,13 @@
***********************************************************************************/
package network.packets;
+import resources.network.BaselineBuilder;
+
import java.net.InetAddress;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.charset.Charset;
+import java.util.List;
public class Packet {
@@ -72,7 +75,14 @@ public class Packet {
public int getOpcode() {
return opcode;
}
-
+
+ public static void addList(ByteBuffer bb, List extends BaselineBuilder.Encodable> list) {
+ addInt(bb, list.size());
+ for (BaselineBuilder.Encodable encodable : list) {
+ addData(bb, encodable.encode());
+ }
+ }
+
public static void addBoolean(ByteBuffer bb, boolean b) {
bb.put(b ? (byte)1 : (byte)0);
}
@@ -120,7 +130,11 @@ public class Packet {
public static void addByte(ByteBuffer bb, int b) {
bb.put((byte)b);
}
-
+
+ public static void addData(ByteBuffer bb, byte[] data) {
+ bb.put(data);
+ }
+
public static void addArray(ByteBuffer bb, byte [] b) {
addShort(bb, b.length);
bb.put(b);
diff --git a/src/network/packets/swg/SWGPacket.java b/src/network/packets/swg/SWGPacket.java
index 470b7d645..962e122e4 100644
--- a/src/network/packets/swg/SWGPacket.java
+++ b/src/network/packets/swg/SWGPacket.java
@@ -32,6 +32,7 @@ import java.nio.ByteBuffer;
import resources.Location;
import network.PacketType;
import network.packets.Packet;
+import resources.encodables.OutOfBandPackage;
public class SWGPacket extends Packet {
@@ -61,7 +62,7 @@ public class SWGPacket extends Packet {
l.setZ(getFloat(data));
return l;
}
-
+
public void setSWGOpcode(int opcode) {
this.opcode = opcode;
this.type = PacketType.fromCrc(opcode);
@@ -101,4 +102,10 @@ public class SWGPacket extends Packet {
public ByteBuffer getData() {
return data;
}
+
+ public static OutOfBandPackage getOutOfBand(ByteBuffer data) {
+ OutOfBandPackage outOfBandPackage = new OutOfBandPackage();
+ outOfBandPackage.decode(data);
+ return outOfBandPackage;
+ }
}
diff --git a/src/network/packets/swg/zone/chat/ChatEnterRoomById.java b/src/network/packets/swg/zone/chat/ChatEnterRoomById.java
new file mode 100644
index 000000000..54e6f253c
--- /dev/null
+++ b/src/network/packets/swg/zone/chat/ChatEnterRoomById.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 java.nio.ByteBuffer;
+
+/**
+ * @author Waverunner
+ */
+public class ChatEnterRoomById extends SWGPacket {
+ public static final int CRC = resources.common.CRC.getCrc("ChatEnterRoomById");
+
+ private int sequence;
+ private int roomId;
+ private String roomPath;
+
+ @Override
+ public void decode(ByteBuffer data) {
+ if (!super.decode(data, CRC))
+ return;
+
+ sequence = getInt(data);
+ roomId = getInt(data);
+ roomPath = getAscii(data);
+ System.out.println("ChatEnterRoomById: " + roomId + roomPath);
+ }
+
+ @Override
+ public ByteBuffer encode() {
+ ByteBuffer bb = ByteBuffer.allocate(10 + roomPath.length());
+ addShort(bb, 4);
+ addInt(bb, sequence);
+ addInt(bb, roomId);
+ addAscii(bb, roomPath);
+ return bb;
+ }
+
+ public int getSequence() {
+ return sequence;
+ }
+
+ public int getRoomId() {
+ return roomId;
+ }
+
+ public String getRoomPath() {
+ return roomPath;
+ }
+}
diff --git a/src/network/packets/swg/zone/chat/ChatOnConnectAvatar.java b/src/network/packets/swg/zone/chat/ChatOnConnectAvatar.java
index 99fc393c5..6a542e2f0 100644
--- a/src/network/packets/swg/zone/chat/ChatOnConnectAvatar.java
+++ b/src/network/packets/swg/zone/chat/ChatOnConnectAvatar.java
@@ -48,8 +48,7 @@ public class ChatOnConnectAvatar extends SWGPacket {
}
public void decode(ByteBuffer data) {
- if (!super.decode(data, CRC))
- return;
+ super.decode(data, CRC);
}
public ByteBuffer encode() {
diff --git a/src/network/packets/swg/zone/chat/ChatOnDestroyRoom.java b/src/network/packets/swg/zone/chat/ChatOnDestroyRoom.java
index 1f735def6..4b99fc002 100644
--- a/src/network/packets/swg/zone/chat/ChatOnDestroyRoom.java
+++ b/src/network/packets/swg/zone/chat/ChatOnDestroyRoom.java
@@ -30,27 +30,22 @@ package network.packets.swg.zone.chat;
import java.nio.ByteBuffer;
import network.packets.swg.SWGPacket;
+import resources.chat.ChatAvatar;
public class ChatOnDestroyRoom extends SWGPacket {
public static final int CRC = 0xE8EC5877;
-
- private String galaxy;
- private String owner;
- private boolean success;
+
+ private ChatAvatar owner;
+ private int result;
private int roomId;
- private int requestId;
-
- public ChatOnDestroyRoom() {
- this("", "", true, 0, 0);
- }
-
- public ChatOnDestroyRoom(String galaxy, String owner, boolean success, int roomId, int requestId) {
- this.galaxy = galaxy;
+ private int sequence;
+
+ public ChatOnDestroyRoom(ChatAvatar owner, int result, int roomId, int sequence) {
this.owner = owner;
- this.success = success;
+ this.result = result;
this.roomId = roomId;
- this.requestId = requestId;
+ this.sequence = sequence;
}
public ChatOnDestroyRoom(ByteBuffer data) {
@@ -60,24 +55,21 @@ public class ChatOnDestroyRoom extends SWGPacket {
public void decode(ByteBuffer data) {
if (!super.decode(data, CRC))
return;
- getAscii(data); // SWG
- galaxy = getAscii(data);
- owner = getAscii(data);
- success = getInt(data) == 0;
+ owner = new ChatAvatar();
+ owner.decode(data);
+ result = getInt(data);
roomId = getInt(data);
- requestId = getInt(data);
+ sequence = getInt(data);
}
public ByteBuffer encode() {
- ByteBuffer data = ByteBuffer.allocate(27 + galaxy.length() + owner.length());
+ ByteBuffer data = ByteBuffer.allocate(18 + owner.encode().length);
addShort(data, 5);
addInt (data, CRC);
- addAscii(data, "SWG");
- addAscii(data, galaxy);
- addAscii(data, owner);
- addInt (data, success ? 0 : 1);
+ data.put(owner.encode());
+ addInt (data, result);
addInt (data, roomId);
- addInt (data, requestId);
+ addInt (data, sequence);
return data;
}
diff --git a/src/network/packets/swg/zone/chat/ChatOnEnteredRoom.java b/src/network/packets/swg/zone/chat/ChatOnEnteredRoom.java
index ad3a43120..851902eba 100644
--- a/src/network/packets/swg/zone/chat/ChatOnEnteredRoom.java
+++ b/src/network/packets/swg/zone/chat/ChatOnEnteredRoom.java
@@ -30,76 +30,52 @@ package network.packets.swg.zone.chat;
import java.nio.ByteBuffer;
import network.packets.swg.SWGPacket;
+import resources.chat.ChatAvatar;
+import resources.chat.ChatResult;
public class ChatOnEnteredRoom extends SWGPacket {
public static final int CRC = 0xE69BDC0A;
-
- private String galaxy;
- private String character;
- private ChannelStatus status;
+
+ private ChatAvatar avatar;
+ private int result;
private int chatRoomId;
-
- public ChatOnEnteredRoom() {
- this("", "", ChannelStatus.SUCCESS, 0);
- }
-
- public ChatOnEnteredRoom(String galaxy, String character, ChannelStatus status, int chatRoomId) {
- this.galaxy = galaxy;
- this.character = character;
- this.status = status;
+ private int sequence;
+
+ public ChatOnEnteredRoom(ChatAvatar avatar, int chatRoomId, int sequence) {
+ this.avatar = avatar;
this.chatRoomId = chatRoomId;
+ this.sequence = sequence;
}
public ChatOnEnteredRoom(ByteBuffer data) {
decode(data);
}
-
+
public void decode(ByteBuffer data) {
if (!super.decode(data, CRC))
return;
- getAscii(data);
- galaxy = getAscii(data);
- character = getAscii(data);
- status = ChannelStatus.fromInteger(getInt(data));
+ avatar = new ChatAvatar();
+ avatar.decode(data);
+ result = getInt(data);
chatRoomId = getInt(data);
- getInt(data);
+ sequence = getInt(data);
}
public ByteBuffer encode() {
- ByteBuffer data = ByteBuffer.allocate(27 + galaxy.length() + character.length());
+ byte[] avatarData = avatar.encode();
+ ByteBuffer data = ByteBuffer.allocate(avatarData.length + 18);
addShort(data, 5);
addInt (data, CRC);
- addAscii(data, "SWG");
- addAscii(data, galaxy);
- addAscii(data, character);
- addInt (data, status.getBitmask());
+ data.put(avatarData);
+ addInt(data, result);
addInt (data, chatRoomId);
- addInt (data, 0);
+ addInt (data, sequence);
return data;
}
-
- public enum ChannelStatus {
- SUCCESS(0), // "You have joined the channel."
- NOT_INVITED(0x10), // "You cannot join '%TU (room name)' because you are not invted to the room."
- UNKNOWN(0x20); // "Chatroom '%TU (room name)' join failed for an unknown reason."
-
- private int bitmask;
-
- ChannelStatus(int bitmask) {
- this.bitmask = bitmask;
- }
- public int getBitmask() {
- return bitmask;
- }
- public static final ChannelStatus fromInteger(int i) {
- if (i == 0)
- return SUCCESS;
- if (i == 0x10)
- return NOT_INVITED;
- return UNKNOWN;
- }
- };
-
+
+ public void setResult(int result) {
+ this.result = result;
+ }
}
diff --git a/src/network/packets/swg/zone/chat/ChatOnLeaveRoom.java b/src/network/packets/swg/zone/chat/ChatOnLeaveRoom.java
index c971b4629..ee1dd7285 100644
--- a/src/network/packets/swg/zone/chat/ChatOnLeaveRoom.java
+++ b/src/network/packets/swg/zone/chat/ChatOnLeaveRoom.java
@@ -30,27 +30,22 @@ package network.packets.swg.zone.chat;
import java.nio.ByteBuffer;
import network.packets.swg.SWGPacket;
+import resources.chat.ChatAvatar;
public class ChatOnLeaveRoom extends SWGPacket {
public static final int CRC = 0x60B5098B;
- private String galaxyName;
- private String characterName;
- private int errorCode;
+ private ChatAvatar avatar;
+ private int result;
private int chatRoomId;
- private int requestId;
-
- public ChatOnLeaveRoom() {
- this("", "", 0, 0, 0);
- }
-
- public ChatOnLeaveRoom(String galaxy, String character, int errorCode, int chatRoomId, int requestId) {
- this.galaxyName = galaxy;
- this.characterName = character;
- this.errorCode = errorCode;
+ private int sequence;
+
+ public ChatOnLeaveRoom(ChatAvatar avatar, int errorCode, int chatRoomId, int sequence) {
+ this.avatar = avatar;
+ this.result = errorCode;
this.chatRoomId = chatRoomId;
- this.requestId = requestId;
+ this.sequence = sequence;
}
public ChatOnLeaveRoom(ByteBuffer data) {
@@ -60,24 +55,21 @@ public class ChatOnLeaveRoom extends SWGPacket {
public void decode(ByteBuffer data) {
if (!super.decode(data, CRC))
return;
- getAscii(data);
- galaxyName = getAscii(data);
- characterName = getAscii(data);
- errorCode = getInt(data);
+ avatar = new ChatAvatar();
+ avatar.decode(data);
+ result = getInt(data);
chatRoomId = getInt(data);
- requestId = getInt(data);
+ sequence = getInt(data);
}
public ByteBuffer encode() {
- ByteBuffer data = ByteBuffer.allocate(27+galaxyName.length()+characterName.length());
+ ByteBuffer data = ByteBuffer.allocate(18 + avatar.encode().length);
addShort(data, 2);
addInt( data, CRC);
- addAscii(data, "SWG");
- addAscii(data, galaxyName);
- addAscii(data, characterName);
- addInt (data, errorCode);
+ data.put(avatar.encode());
+ addInt(data, result);
addInt (data, chatRoomId);
- addInt (data, requestId);
+ addInt (data, sequence);
return data;
}
diff --git a/src/network/packets/swg/zone/chat/ChatOnReceiveRoomInvitation.java b/src/network/packets/swg/zone/chat/ChatOnReceiveRoomInvitation.java
index 7ee7ef5d1..e0d1fe26d 100644
--- a/src/network/packets/swg/zone/chat/ChatOnReceiveRoomInvitation.java
+++ b/src/network/packets/swg/zone/chat/ChatOnReceiveRoomInvitation.java
@@ -35,21 +35,14 @@ public class ChatOnReceiveRoomInvitation extends SWGPacket {
public static final int CRC = 0xC17EB06D;
- public ChatOnReceiveRoomInvitation() {
-
- }
-
- public ChatOnReceiveRoomInvitation(String command) {
-
- }
-
+ public ChatOnReceiveRoomInvitation() {}
+
public ChatOnReceiveRoomInvitation(ByteBuffer data) {
decode(data);
}
public void decode(ByteBuffer data) {
- if (!super.decode(data, CRC))
- return;
+ super.decode(data, CRC);
}
public ByteBuffer encode() {
diff --git a/src/network/packets/swg/zone/chat/ChatOnSendPersistentMessage.java b/src/network/packets/swg/zone/chat/ChatOnSendPersistentMessage.java
index 55863ba5c..daa903035 100644
--- a/src/network/packets/swg/zone/chat/ChatOnSendPersistentMessage.java
+++ b/src/network/packets/swg/zone/chat/ChatOnSendPersistentMessage.java
@@ -28,10 +28,9 @@
package network.packets.swg.zone.chat;
import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
import network.packets.swg.SWGPacket;
-import services.chat.ChatResult;
+import resources.chat.ChatResult;
public class ChatOnSendPersistentMessage extends SWGPacket {
public static final int CRC = 0x94E7A7AE;
diff --git a/src/network/packets/swg/zone/chat/ChatOnSendRoomMessage.java b/src/network/packets/swg/zone/chat/ChatOnSendRoomMessage.java
index b293c1503..419bf340b 100644
--- a/src/network/packets/swg/zone/chat/ChatOnSendRoomMessage.java
+++ b/src/network/packets/swg/zone/chat/ChatOnSendRoomMessage.java
@@ -32,34 +32,29 @@ import java.nio.ByteBuffer;
import network.packets.swg.SWGPacket;
public class ChatOnSendRoomMessage extends SWGPacket {
-
- public static final int CRC = 0xE7B61633;
- private int error = 0;
- private int messageId = 0;
-
- public ChatOnSendRoomMessage() {
-
- }
-
- public ChatOnSendRoomMessage(int error, int messageId) {
- this.error = error;
- this.messageId = messageId;
+ public static final int CRC = resources.common.CRC.getCrc("ChatOnSendRoomMessage");
+
+ private int result = 0;
+ private int sequence = 0;
+
+ public ChatOnSendRoomMessage(int result, int sequence) {
+ this.result = result;
+ this.sequence = sequence;
}
public void decode(ByteBuffer data) {
if (!super.decode(data, CRC))
return;
- error = getInt(data);
- messageId = getInt(data);
+ result = getInt(data);
+ sequence = getInt(data);
}
public ByteBuffer encode() {
- int length = 14;
- ByteBuffer data = ByteBuffer.allocate(length);
+ ByteBuffer data = ByteBuffer.allocate(14);
addShort(data, 3);
addInt( data, CRC);
- addInt( data, error);
- addInt( data, messageId);
+ addInt( data, result);
+ addInt( data, sequence);
return data;
}
}
diff --git a/src/network/packets/swg/zone/chat/ChatQueryRoom.java b/src/network/packets/swg/zone/chat/ChatQueryRoom.java
new file mode 100644
index 000000000..8fa63c24c
--- /dev/null
+++ b/src/network/packets/swg/zone/chat/ChatQueryRoom.java
@@ -0,0 +1,68 @@
+/*******************************************************************************
+ * 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 java.nio.ByteBuffer;
+
+/**
+ * @author Waverunner
+ */
+public class ChatQueryRoom extends SWGPacket {
+ public static final int CRC = resources.common.CRC.getCrc("ChatQueryRoom");
+
+ private int sequence;
+ private String roomPath;
+
+ @Override
+ public void decode(ByteBuffer data) {
+ if (!super.decode(data, CRC))
+ return;
+ sequence = getInt(data);
+ roomPath = getAscii(data);
+ }
+
+ @Override
+ public ByteBuffer encode() {
+ ByteBuffer bb = ByteBuffer.allocate(12 + roomPath.length());
+ addShort(bb, 3);
+ addInt(bb, CRC);
+ addInt(bb, sequence);
+ addAscii(bb, roomPath);
+ return bb;
+ }
+
+ public int getSequence() {
+ return sequence;
+ }
+
+ public String getRoomPath() {
+ return roomPath;
+ }
+}
diff --git a/src/network/packets/swg/zone/chat/ChatQueryRoomResults.java b/src/network/packets/swg/zone/chat/ChatQueryRoomResults.java
new file mode 100644
index 000000000..5fe4bb202
--- /dev/null
+++ b/src/network/packets/swg/zone/chat/ChatQueryRoomResults.java
@@ -0,0 +1,82 @@
+/*******************************************************************************
+ * 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 resources.chat.ChatRoom;
+import resources.network.BaselineBuilder;
+
+import java.nio.ByteBuffer;
+import java.util.List;
+
+/**
+ * @author Waverunner
+ */
+public class ChatQueryRoomResults extends SWGPacket {
+ public static final int CRC = resources.common.CRC.getCrc("ChatQueryRoomResults");
+
+ private ChatRoom room;
+ private int sequence;
+
+ public ChatQueryRoomResults(ChatRoom room, int sequence) {
+ this.room = room;
+ this.sequence = sequence;
+ }
+
+ @Override
+ public void decode(ByteBuffer data) {
+ super.decode(data, CRC);
+ }
+
+ @Override
+ public ByteBuffer encode() {
+ byte[] data = room.encode();
+ int size = data.length;
+
+ List members = room.getMembers();
+ List invited = room.getInvited();
+ List moderators = room.getModerators();
+ List banned = room.getBanned();
+
+ for (ChatAvatar avatar : members) { size += avatar.getSize(); }
+ for (ChatAvatar avatar : invited) { size += avatar.getSize(); }
+ for (ChatAvatar avatar : moderators) { size += avatar.getSize(); }
+ for (ChatAvatar avatar : banned) { size += avatar.getSize(); }
+
+ ByteBuffer bb = ByteBuffer.allocate(20 + size);
+ addList(bb, members);
+ addList(bb, invited);
+ addList(bb, moderators);
+ addList(bb, banned);
+ addInt(bb, sequence);
+ addData(bb, data);
+
+ return bb;
+ }
+}
diff --git a/src/network/packets/swg/zone/ChatRequestRoomList.java b/src/network/packets/swg/zone/chat/ChatRequestRoomList.java
similarity index 95%
rename from src/network/packets/swg/zone/ChatRequestRoomList.java
rename to src/network/packets/swg/zone/chat/ChatRequestRoomList.java
index 596192497..051c232fe 100644
--- a/src/network/packets/swg/zone/ChatRequestRoomList.java
+++ b/src/network/packets/swg/zone/chat/ChatRequestRoomList.java
@@ -25,7 +25,7 @@
* along with Holocore. If not, see . *
* *
***********************************************************************************/
-package network.packets.swg.zone;
+package network.packets.swg.zone.chat;
import java.nio.ByteBuffer;
@@ -35,13 +35,10 @@ public class ChatRequestRoomList extends SWGPacket {
public static final int CRC = 0x4C3D2CFA;
- public ChatRequestRoomList() {
-
- }
+ public ChatRequestRoomList() {}
public void decode(ByteBuffer data) {
- if (!super.decode(data, CRC))
- return;
+ super.decode(data, CRC);
}
public ByteBuffer encode() {
diff --git a/src/network/packets/swg/zone/chat/ChatRoomMessage.java b/src/network/packets/swg/zone/chat/ChatRoomMessage.java
index f81092c06..2bf864fd1 100644
--- a/src/network/packets/swg/zone/chat/ChatRoomMessage.java
+++ b/src/network/packets/swg/zone/chat/ChatRoomMessage.java
@@ -30,49 +30,43 @@ package network.packets.swg.zone.chat;
import java.nio.ByteBuffer;
import network.packets.swg.SWGPacket;
-import network.packets.swg.zone.insertion.ChatRoomList.ChatRoom.User;
+import resources.chat.ChatAvatar;
+import resources.encodables.OutOfBandPackage;
public class ChatRoomMessage extends SWGPacket {
-
- public static final int CRC = 0xCD4CE444;
- private User user = new User();
+ public static final int CRC = resources.common.CRC.getCrc("ChatRoomMessage");
+
+ private ChatAvatar avatar;
private int roomId = 0;
private String message = "";
-
- public ChatRoomMessage() {
-
- }
-
- public ChatRoomMessage(String game, String server, String name, int roomId, String message) {
- this.user.game = game;
- this.user.server = server;
- this.user.name = name;
+ private OutOfBandPackage outOfBandPackage;
+
+ public ChatRoomMessage(ChatAvatar avatar, int roomId, String message, OutOfBandPackage oob) {
+ this.avatar = avatar;
this.roomId = roomId;
this.message = message;
+ this.outOfBandPackage = oob;
}
public void decode(ByteBuffer data) {
if (!super.decode(data, CRC))
return;
- user.game = getAscii(data);
- user.server = getAscii(data);
- user.name = getAscii(data);
+ avatar.decode(data);
roomId = getInt(data);
message = getUnicode(data);
- getUnicode(data);
+ outOfBandPackage.decode(data);
}
public ByteBuffer encode() {
- int length = 24 + user.game.length() + user.server.length() + user.name.length() + message.length() * 2;
+ byte[] oob = outOfBandPackage.encode();
+ int length = 14 + avatar.encode().length + oob.length + message.length() * 2;
ByteBuffer data = ByteBuffer.allocate(length);
addShort( data, 5);
addInt( data, CRC);
- addAscii( data, user.game);
- addAscii( data, user.server);
- addAscii( data, user.name);
+ data.put(avatar.encode());
addInt( data, roomId);
addUnicode(data, message);
- addUnicode(data, "");
+ data.put(outOfBandPackage.encode());
return data;
}
}
diff --git a/src/network/packets/swg/zone/chat/ChatSendToRoom.java b/src/network/packets/swg/zone/chat/ChatSendToRoom.java
new file mode 100644
index 000000000..ed691d500
--- /dev/null
+++ b/src/network/packets/swg/zone/chat/ChatSendToRoom.java
@@ -0,0 +1,77 @@
+/*******************************************************************************
+ * 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.encodables.OutOfBandPackage;
+
+import java.nio.ByteBuffer;
+
+/**
+ * @author Waverunner
+ */
+public class ChatSendToRoom extends SWGPacket {
+ public static final int CRC = resources.common.CRC.getCrc("ChatSendToRoom");
+
+ private String message;
+ private OutOfBandPackage outOfBandPackage;
+ private int roomId;
+ private int sequence; // This seems to vary from room to room, client keeps track individually for each room?
+
+ @Override
+ public void decode(ByteBuffer data) {
+ if (!super.decode(data, CRC))
+ return;
+
+ message = getUnicode(data);
+ outOfBandPackage = getOutOfBand(data);
+ roomId = getInt(data);
+ sequence = getInt(data);
+ }
+
+ @Override
+ public ByteBuffer encode() {
+ return super.encode();
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ public OutOfBandPackage getOutOfBandPackage() {
+ return outOfBandPackage;
+ }
+
+ public int getRoomId() {
+ return roomId;
+ }
+
+ public int getSequence() {
+ return sequence;
+ }
+}
diff --git a/src/network/packets/swg/zone/insertion/ChatRoomList.java b/src/network/packets/swg/zone/insertion/ChatRoomList.java
index facb3ac74..2aa2caa4e 100644
--- a/src/network/packets/swg/zone/insertion/ChatRoomList.java
+++ b/src/network/packets/swg/zone/insertion/ChatRoomList.java
@@ -28,209 +28,47 @@
package network.packets.swg.zone.insertion;
import java.nio.ByteBuffer;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Vector;
+import java.util.Arrays;
+import java.util.Collection;
import network.packets.swg.SWGPacket;
-import network.packets.swg.zone.insertion.ChatRoomList.ChatRoom.User;
+import resources.chat.ChatRoom;
public class ChatRoomList extends SWGPacket {
-
- public static final int CRC = 0x70DEB197;
- private List chatrooms = new ArrayList();
-
- public ChatRoomList() {
-
+ public static final int CRC = resources.common.CRC.getCrc("ChatRoomList");
+
+ private Collection rooms;
+
+ public ChatRoomList(ChatRoom ... rooms) {
+ this.rooms = Arrays.asList(rooms);
}
-
- public ChatRoomList(ChatRoom room) {
- chatrooms.add(room);
+
+ public ChatRoomList(Collection rooms) {
+ this.rooms = rooms;
}
-
- public ChatRoomList(ChatRoom [] rooms) {
- for (ChatRoom r : rooms) {
- chatrooms.add(r);
- }
- }
-
- public void addChatRoom(ChatRoom r) {
- chatrooms.add(r);
- }
-
+
public void decode(ByteBuffer data) {
if (!super.decode(data, CRC))
return;
int chatroomCount = getInt(data);
for (int i = 0; i < chatroomCount; i++) {
ChatRoom room = new ChatRoom();
- room.setRoomId(getInt(data));
- room.setPrivateFlag(getInt(data));
- room.setModeratedFlag(getByte(data));
- room.setRoomPathName(getAscii(data));
- room.setGame(getAscii(data));
- room.setServer(getAscii(data));
- room.setOwner(getAscii(data));
- getAscii(data); // SWG
- getAscii(data); // galaxy
- room.setCreator(getAscii(data));
- room.setTitle(getUnicode(data));
- int moderatorCount = getInt(data);
- for (int m = 0; m < moderatorCount; m++) {
- User user = new User();
- user.setGame(getAscii(data));
- user.setServer(getAscii(data));
- user.setName(getAscii(data));
- room.addModerator(user);
- }
- int userCount = getInt(data);
- for (int u = 0; u < userCount; u++) {
- User user = new User();
- user.setGame(getAscii(data));
- user.setServer(getAscii(data));
- user.setName(getAscii(data));
- room.addUser(user);
- }
+ room.decode(data);
}
}
public ByteBuffer encode() {
int length = 10;
- for (ChatRoom r : chatrooms) {
- length += r.getSize();
+ for (ChatRoom r : rooms) {
+ length += r.encode().length;
}
ByteBuffer data = ByteBuffer.allocate(length);
addShort(data, 2);
addInt( data, CRC);
- addInt( data, chatrooms.size());
- for (ChatRoom r : chatrooms) {
- addInt(data, r.getRoomId());
- addInt(data, r.getPrivateFlag());
- addByte(data, r.getModeratedFlag());
- addAscii(data, r.getRoomPathName());
- addAscii(data, r.getGame());
- addAscii(data, r.getServer());
- addAscii(data, r.getOwner());
- addAscii(data, r.getCreator());
- addUnicode(data, r.getTitle());
- addInt(data, r.getModerators().size());
- for (User u : r.getModerators()) {
- addAscii(data, u.game);
- addAscii(data, u.server);
- addAscii(data, u.name);
- }
- addInt(data, r.getUsers().size());
- for (User u : r.getUsers()) {
- addAscii(data, u.game);
- addAscii(data, u.server);
- addAscii(data, u.name);
- }
+ addInt(data, rooms.size());
+ for (ChatRoom room : rooms) {
+ data.put(room.encode());
}
return data;
}
-
- public static class ChatRoom {
- private int roomId = 0;
- private int privateFlag = 0;
- private int moderatedFlag = 0;
- private String roomPathName = "";
- private String game = "";
- private String server = "";
- private String owner = "";
- private String creator = "";
- private String title = "";
- private Vector moderators = new Vector();
- private Vector users = new Vector();
-
- public ChatRoom() {
-
- }
-
- public ChatRoom(int roomId, int privateFlag, int moderatedFlag, String roomPathName, String game, String server, String owner, String creator, String title) {
- this.roomId = roomId;
- this.privateFlag = privateFlag;
- this.moderatedFlag = moderatedFlag;
- this.roomPathName = roomPathName;
- this.game = game;
- this.server = server;
- this.owner = owner;
- this.creator = creator;
- this.title = title;
- }
-
- public void addModerator(String game, String server, String name) {
- moderators.add(new User(game, server, name));
- }
-
- public void addUser(String game, String server, String name) {
- users.add(new User(game, server, name));
- }
-
- public int getSize() {
- int length = 31;
- length += roomPathName.length();
- length += game.length();
- length += server.length();
- length += owner.length();
- length += creator.length();
- length += title.length() * 2;
- for (User u : moderators) length += u.getSize();
- for (User u : users) length += u.getSize();
- return length;
- }
-
- public int getRoomId() { return roomId; }
- public int getPrivateFlag() { return privateFlag; }
- public int getModeratedFlag() { return moderatedFlag; }
- public String getRoomPathName() { return roomPathName; }
- public String getGame() { return game; }
- public String getServer() { return server; }
- public String getOwner() { return owner; }
- public String getCreator() { return creator; }
- public String getTitle() { return title; }
- public List getUsers() { return users; }
- public List getModerators() { return moderators; }
-
- public void setRoomId(int id) { this.roomId = id; }
- public void setPrivateFlag(int flag) { this.privateFlag = flag; }
- public void setModeratedFlag(int flag) { this.moderatedFlag = flag; }
- public void setRoomPathName(String path) { this.roomPathName = path; }
- public void setGame(String game) { this.game = game; }
- public void setServer(String server) { this.server = server; }
- public void setOwner(String owner) { this.owner = owner; }
- public void setCreator(String creator) { this.creator = creator; }
- public void setTitle(String title) { this.title = title; }
- public void setUsers(Vector users) { this.users = users; }
- public void setModerators(Vector moderators) { this.moderators = moderators; }
- public void addUser(User user) { this.users.add(user); }
- public void addModerator(User moderator) { this.moderators.add(moderator); }
-
- public static class User {
- public String game = "";
- public String server = "";
- public String name = "";
-
- public User() {
-
- }
-
- public User(String game, String server, String name) {
- this.game = game;
- this.server = server;
- this.name = name;
- }
-
- public int getSize() {
- return 6 + game.length() + server.length() + name.length();
- }
-
- public String getGame() { return game; }
- public String getServer() { return server; }
- public String getName() { return name; }
-
- public void setGame(String game) { this.game = game; }
- public void setServer(String server) { this.server = server; }
- public void setName(String name) { this.name = name; }
- }
- }
}
diff --git a/src/resources/chat/ChatAvatar.java b/src/resources/chat/ChatAvatar.java
new file mode 100644
index 000000000..bb7a7002c
--- /dev/null
+++ b/src/resources/chat/ChatAvatar.java
@@ -0,0 +1,149 @@
+/*******************************************************************************
+ * 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.chat;
+
+import network.packets.Packet;
+import resources.network.BaselineBuilder;
+import resources.objects.creature.CreatureObject;
+import resources.player.Player;
+
+import java.nio.ByteBuffer;
+
+/**
+ * @author Waverunner
+ */
+public class ChatAvatar implements BaselineBuilder.Encodable, BaselineBuilder.Decodable {
+ private long networkId;
+ private String name;
+ private String game = "SWG";
+ private String galaxy;
+
+ // Instances of the class will hardly ever change, so we can just pre-build the data.
+ private transient byte[] data;
+ private transient boolean modified;
+ private transient int size = 0;
+
+ public ChatAvatar() {
+ modified = true;
+ }
+
+ public ChatAvatar(long networkId, String name, String galaxy) {
+ this();
+ this.networkId = networkId;
+ this.name = name;
+ this.galaxy = galaxy;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ modified = true;
+ }
+
+ public String getGame() {
+ return game;
+ }
+
+ public void setGame(String game) {
+ this.game = game;
+ modified = true;
+ }
+
+ public String getGalaxy() {
+ return galaxy;
+ }
+
+ public void setGalaxy(String galaxy) {
+ this.galaxy = galaxy;
+ modified = true;
+ }
+
+ public long getNetworkId() {
+ return networkId;
+ }
+
+ public int getSize() {
+ if (size == 0)
+ size = 6 + game.length() + name.length() + galaxy.length();
+
+ return size;
+ }
+
+ @Override
+ public byte[] encode() {
+ if (!modified && data != null)
+ return data;
+
+ ByteBuffer buffer = ByteBuffer.allocate(getSize());
+ Packet.addAscii(buffer, game);
+ Packet.addAscii(buffer, galaxy);
+ Packet.addAscii(buffer, name);
+
+ data = buffer.array();
+ modified = false;
+
+ return data;
+ }
+
+ @Override
+ public void decode(ByteBuffer data) {
+
+ }
+
+ @Override
+ public String toString() {
+ return "ChatAvatar:" + getNetworkId() + "[" + getGame() + "." + getGalaxy() + "." + getName() + "]";
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null) return false;
+
+ if (getClass() != o.getClass())
+ return false;
+
+ return ((ChatAvatar) o).getNetworkId() == networkId;
+ }
+
+ @Override
+ public int hashCode() {
+ return (int) (networkId ^ (networkId >>> 32));
+ }
+
+ public static ChatAvatar getFromPlayer(Player player) {
+ return new ChatAvatar(player.getNetworkId(), player.getCharacterName().split(" ")[0].toLowerCase(), player.getGalaxyName());
+ }
+
+ public static ChatAvatar getSystemAvatar(String galaxy) {
+ return new ChatAvatar(-1, "system", galaxy);
+ }
+}
diff --git a/src/services/chat/ChatResult.java b/src/resources/chat/ChatResult.java
similarity index 74%
rename from src/services/chat/ChatResult.java
rename to src/resources/chat/ChatResult.java
index 700d294d9..65f4cd8d3 100644
--- a/src/services/chat/ChatResult.java
+++ b/src/resources/chat/ChatResult.java
@@ -25,16 +25,25 @@
* along with Holocore. If not, see
******************************************************************************/
-package services.chat;
+package resources.chat;
/**
* @author Waverunner
*/
public enum ChatResult {
- NONE(-1),
+ NONE(-1), // The client will just display an "unknown error code" if this is used.
SUCCESS(0),
TARGET_AVATAR_DOESNT_EXIST(4),
- IGNORED(23);
+ ROOM_INVALID_ID(5),
+ ROOM_INVALID_NAME(6),
+ ROOM_NOT_MODERATOR(9),
+ ROOM_AVATAR_BANNED(12),
+ ROOM_AVATAR_NOT_INVITED(16),
+ IGNORED(23),
+ ROOM_ALREADY_JOINED(36),
+ CHAT_SERVER_UNAVAILABLE(1000000),
+ ROOM_DIFFERENT_FACTION(1000001),
+ ROOM_NOT_GCW_DEFENDER_FACTION(1000005);
private final int code;
@@ -45,4 +54,12 @@ public enum ChatResult {
public int getCode() {
return code;
}
+
+ public static ChatResult fromInteger(int code) {
+ for (ChatResult result : ChatResult.values()) {
+ if (code == result.getCode())
+ return result;
+ }
+ return NONE;
+ }
}
diff --git a/src/resources/chat/ChatRoom.java b/src/resources/chat/ChatRoom.java
new file mode 100644
index 000000000..8a4ccf92a
--- /dev/null
+++ b/src/resources/chat/ChatRoom.java
@@ -0,0 +1,239 @@
+/*******************************************************************************
+ * 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.chat;
+
+import network.packets.Packet;
+import network.packets.swg.zone.chat.ChatRoomMessage;
+import resources.encodables.OutOfBandPackage;
+import resources.network.BaselineBuilder;
+import resources.player.Player;
+import services.player.PlayerManager;
+
+import java.io.Serializable;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author Waverunner
+ */
+public class ChatRoom implements Serializable, BaselineBuilder.Encodable, BaselineBuilder.Decodable {
+ private static final long serialVersionUID = 1L;
+
+ private int id;
+ private int type;
+ private String path;
+ private ChatAvatar owner;
+ private ChatAvatar creator;
+ private String title;
+ private List moderators;
+ private List invited;
+ private boolean muted; // No one but moderators can talk
+ private boolean isPublic;
+ 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
+ private transient List members;
+
+ // Large amount of data that's sent frequently, best if we can pre-encode everything and save it for later
+ private transient boolean modified = true;
+ private transient byte[] data;
+
+ public ChatRoom() {
+ moderators = new ArrayList<>();
+ invited = new ArrayList<>();
+ members = new ArrayList<>();
+ banned = new ArrayList<>();
+ }
+
+ public int getId() {
+ return id;
+ }
+
+ public void setId(int id) {
+ this.id = id;
+ }
+
+ public int getType() {
+ return type;
+ }
+
+ public void setType(int type) {
+ this.type = type;
+ }
+
+ public String getPath() {
+ return path;
+ }
+
+ public void setPath(String path) {
+ this.path = path;
+ }
+
+ public ChatAvatar getOwner() {
+ return owner;
+ }
+
+ public void setOwner(ChatAvatar owner) {
+ this.owner = owner;
+ }
+
+ public ChatAvatar getCreator() {
+ return creator;
+ }
+
+ public void setCreator(ChatAvatar creator) {
+ this.creator = creator;
+ }
+
+ public String getTitle() {
+ return title;
+ }
+
+ public void setTitle(String title) {
+ this.title = title;
+ }
+
+ public List getModerators() {
+ return moderators;
+ }
+
+ public List getInvited() {
+ return invited;
+ }
+
+ public boolean isMuted() {
+ return muted;
+ }
+
+ public void setMuted(boolean muted) {
+ this.muted = muted;
+ }
+
+ public List getMembers() {
+ return members;
+ }
+
+ public boolean isPublic() {
+ return isPublic;
+ }
+
+ public void setIsPublic(boolean isPublic) {
+ this.isPublic = isPublic;
+ }
+
+ public List getBanned() {
+ return banned;
+ }
+
+ public ChatResult canJoinRoom(ChatAvatar avatar) {
+ if (banned.contains(avatar))
+ return ChatResult.ROOM_AVATAR_BANNED;
+
+ if (members.contains(avatar))
+ return ChatResult.ROOM_ALREADY_JOINED;
+
+ if (isPublic || invited.contains(avatar))
+ return ChatResult.SUCCESS;
+
+ return ChatResult.ROOM_AVATAR_NOT_INVITED;
+ }
+
+ public ChatResult canSendMessage(ChatAvatar avatar) {
+ if (banned.contains(avatar))
+ return ChatResult.ROOM_AVATAR_BANNED;
+
+ if (muted && !moderators.contains(avatar))
+ return ChatResult.ROOM_NOT_MODERATOR;
+
+ return ChatResult.SUCCESS;
+ }
+
+ public void sendMessage(ChatAvatar sender, String message, OutOfBandPackage oob, PlayerManager playerManager) {
+ ChatRoomMessage chatRoomMessage = new ChatRoomMessage(sender, getId(), message, oob);
+
+ for (ChatAvatar avatar : members) {
+ Player player = playerManager.getPlayerFromNetworkId(avatar.getNetworkId());
+ if (player == null)
+ return;
+
+ player.sendPacket(chatRoomMessage);
+ }
+ }
+
+ @Override
+ public void decode(ByteBuffer data) {}
+
+ @Override
+ public byte[] encode() {
+ if (!modified && data != null)
+ return data;
+
+ int avatarIdSize = 0; // The encode method for ChatAvatar saves the encode result if the class was modified/null data
+ for (ChatAvatar moderator : moderators) {
+ avatarIdSize += moderator.encode().length;
+ }
+
+ for (ChatAvatar invitee : invited) {
+ avatarIdSize += invitee.encode().length;
+ }
+ avatarIdSize += owner.encode().length + creator.encode().length;
+
+ ByteBuffer bb = ByteBuffer.allocate(23 + path.length() + (title.length() * 2) + avatarIdSize).order(ByteOrder.LITTLE_ENDIAN);
+ bb.putInt(id);
+ bb.putInt(type);
+ bb.put(muted ? (byte) 1 : (byte) 0);
+ Packet.addAscii(bb, path);
+ bb.put(owner.encode());
+ bb.put(creator.encode());
+ Packet.addUnicode(bb, title);
+ bb.putInt(moderators.size());
+ for (ChatAvatar moderator : moderators) {
+ bb.put(moderator.encode());
+ }
+ bb.putInt(invited.size());
+ for (ChatAvatar invitee : invited) {
+ bb.put(invitee.encode());
+ }
+
+ data = bb.array();
+ modified = false;
+
+ return data;
+ }
+
+ @Override
+ public String toString() {
+ return "ChatRoom{" +
+ "id=" + id +
+ ", path='" + path + '\'' +
+ ", title='" + title + '\'' +
+ '}';
+ }
+}
diff --git a/src/resources/commands/callbacks/WaypointCmdCallback.java b/src/resources/commands/callbacks/WaypointCmdCallback.java
index b34753d8d..c7b087fda 100644
--- a/src/resources/commands/callbacks/WaypointCmdCallback.java
+++ b/src/resources/commands/callbacks/WaypointCmdCallback.java
@@ -162,7 +162,7 @@ public class WaypointCmdCallback implements ICmdCallback {
}
}
- if (name == null)
+ if (name == null || name.isEmpty())
name = "Waypoint";
WaypointObject waypoint = createWaypoint(galacticManager.getObjectManager(), color, name, location);
diff --git a/src/resources/network/BaselineBuilder.java b/src/resources/network/BaselineBuilder.java
index e412e32bf..2caa8f95f 100644
--- a/src/resources/network/BaselineBuilder.java
+++ b/src/resources/network/BaselineBuilder.java
@@ -165,5 +165,8 @@ public class BaselineBuilder {
public interface Encodable extends Serializable {
byte [] encode();
}
-
+
+ public interface Decodable {
+ void decode(ByteBuffer data);
+ }
}
diff --git a/src/resources/objects/player/PlayerObject.java b/src/resources/objects/player/PlayerObject.java
index 0cfed02b9..ae7a53e51 100644
--- a/src/resources/objects/player/PlayerObject.java
+++ b/src/resources/objects/player/PlayerObject.java
@@ -44,13 +44,16 @@ import resources.player.PlayerFlags;
import utilities.MathUtils;
import utilities.Encoder.StringType;
+import java.util.LinkedList;
import java.util.List;
public class PlayerObject extends IntangibleObject {
private static final long serialVersionUID = 1L;
- private String biography = "";
+ private String biography = "";
+ private List joinedChannels = new LinkedList<>();
+
// PLAY 03
private SWGBitSet flagsList = new SWGBitSet(BaselineType.PLAY, 3, 5);
private SWGBitSet profileFlags = new SWGBitSet(BaselineType.PLAY, 3, 6);
@@ -384,7 +387,11 @@ public class PlayerObject extends IntangibleObject {
flagsList.flip(flag.getFlag());
flagsList.sendDeltaMessage(this);
}
-
+
+ public List getJoinedChannels() {
+ return joinedChannels;
+ }
+
private int getProfessionIcon() {
switch (profession) {
case "entertainer_1a":
diff --git a/src/services/chat/ChatService.java b/src/services/chat/ChatService.java
index fe84f8833..1e000e28c 100644
--- a/src/services/chat/ChatService.java
+++ b/src/services/chat/ChatService.java
@@ -31,6 +31,7 @@ import intents.NotifyPlayersPacketIntent;
import intents.PlayerEventIntent;
import intents.chat.ChatAvatarRequestIntent;
import intents.chat.ChatBroadcastIntent;
+import intents.chat.ChatRoomUpdateIntent;
import intents.chat.PersistentMessageIntent;
import intents.chat.SpatialChatIntent;
import intents.network.GalacticPacketIntent;
@@ -38,23 +39,34 @@ import intents.player.ZonePlayerSwapIntent;
import intents.server.ServerStatusIntent;
import network.packets.Packet;
import network.packets.swg.SWGPacket;
-import network.packets.swg.zone.ChatRequestRoomList;
import network.packets.swg.zone.chat.ChatDeletePersistentMessage;
+import network.packets.swg.zone.chat.ChatEnterRoomById;
import network.packets.swg.zone.chat.ChatFriendsListUpdate;
import network.packets.swg.zone.chat.ChatInstantMessageToCharacter;
import network.packets.swg.zone.chat.ChatInstantMessageToClient;
import network.packets.swg.zone.chat.ChatOnAddFriend;
import network.packets.swg.zone.chat.ChatOnChangeFriendStatus;
+import network.packets.swg.zone.chat.ChatOnEnteredRoom;
import network.packets.swg.zone.chat.ChatOnGetFriendsList;
import network.packets.swg.zone.chat.ChatOnSendInstantMessage;
import network.packets.swg.zone.chat.ChatOnSendPersistentMessage;
+import network.packets.swg.zone.chat.ChatOnSendRoomMessage;
import network.packets.swg.zone.chat.ChatPersistentMessageToClient;
import network.packets.swg.zone.chat.ChatPersistentMessageToServer;
+import network.packets.swg.zone.chat.ChatQueryRoom;
+import network.packets.swg.zone.chat.ChatQueryRoomResults;
import network.packets.swg.zone.chat.ChatRequestPersistentMessage;
+import network.packets.swg.zone.chat.ChatRequestRoomList;
+import network.packets.swg.zone.chat.ChatSendToRoom;
import network.packets.swg.zone.chat.ChatSystemMessage;
import network.packets.swg.zone.chat.ChatSystemMessage.SystemChatType;
+import network.packets.swg.zone.insertion.ChatRoomList;
import network.packets.swg.zone.object_controller.SpatialChat;
+import resources.Galaxy;
import resources.Terrain;
+import resources.chat.ChatAvatar;
+import resources.chat.ChatResult;
+import resources.chat.ChatRoom;
import resources.collections.SWGList;
import resources.control.Intent;
import resources.control.Service;
@@ -63,6 +75,7 @@ import resources.encodables.ProsePackage;
import resources.encodables.player.Mail;
import resources.objects.SWGObject;
import resources.objects.player.PlayerObject;
+import resources.player.AccessLevel;
import resources.player.Player;
import resources.player.PlayerState;
import resources.server_info.CachedObjectDatabase;
@@ -71,18 +84,33 @@ import resources.server_info.ObjectDatabase.Traverser;
import services.player.PlayerManager;
import java.util.Date;
+import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
public class ChatService extends Service {
-
+
+ // Array of only the valid terrains in relation to zones able to use planetary-based chat
+ private static final Terrain[] terrains = new Terrain[] {
+ Terrain.CORELLIA, Terrain.DANTOOINE, Terrain.DATHOMIR, Terrain.ENDOR, Terrain.KASHYYYK, Terrain.LOK,
+ Terrain.MUSTAFAR, Terrain.NABOO, Terrain.RORI, Terrain.TATOOINE, Terrain.TALUS, Terrain.YAVIN4
+ };
private ObjectDatabase mails;
private int maxMailId;
-
+ 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;
+
public ChatService() {
+ roomMap = new HashMap<>();
mails = new CachedObjectDatabase<>("odb/mails.db");
maxMailId = 1;
+ maxChatRoomId = 1;
+ messages = new ConcurrentHashMap<>();
}
@Override
@@ -95,6 +123,7 @@ public class ChatService extends Service {
registerForIntent(ServerStatusIntent.TYPE);
registerForIntent(ChatAvatarRequestIntent.TYPE);
registerForIntent(ZonePlayerSwapIntent.TYPE);
+ registerForIntent(ChatRoomUpdateIntent.TYPE);
mails.load();
mails.traverse(new Traverser() {
@Override
@@ -138,6 +167,17 @@ public class ChatService extends Service {
if (i instanceof ChatAvatarRequestIntent)
handleChatAvatarStatusRequestIntent((ChatAvatarRequestIntent) i);
break;
+ case ChatRoomUpdateIntent.TYPE:
+ if (i instanceof ChatRoomUpdateIntent)
+ handleChatRoomUpdateIntent((ChatRoomUpdateIntent) i);
+ break;
+ }
+ }
+
+ private void handleChatRoomUpdateIntent(ChatRoomUpdateIntent i) {
+ switch(i.getUpdateType()) {
+ case CREATE: createRoom(i.getAvatar(), i.isPublic(), i.getPath(), i.getTitle());
+ default: break;
}
}
@@ -145,6 +185,7 @@ public class ChatService extends Service {
Player player = intent.getPlayerManager().getPlayerFromNetworkId(intent.getNetworkId());
if (player == null)
return;
+
Packet p = intent.getPacket();
if (p instanceof SWGPacket)
processSwgPacket(intent.getPlayerManager(), player, intent.getGalaxy().getName(), (SWGPacket) p);
@@ -152,9 +193,23 @@ public class ChatService extends Service {
private void processSwgPacket(PlayerManager pm, Player player, String galaxyName, SWGPacket p) {
switch (p.getPacketType()) {
+ case CHAT_QUERY_ROOM:
+ if (p instanceof ChatQueryRoom)
+ handleChatQueryRoom(player, (ChatQueryRoom) p);
+ break;
+ case CHAT_ENTER_ROOM_BY_ID:
+ if (p instanceof ChatEnterRoomById) {
+ ChatEnterRoomById enterRoomById = (ChatEnterRoomById) p;
+ enterChatChannel(player, enterRoomById.getRoomId(), enterRoomById.getSequence());
+ }
+ break;
+ case CHAT_SEND_TO_ROOM:
+ if (p instanceof ChatSendToRoom)
+ handleChatSendToRoom(player, (ChatSendToRoom) p);
+ break;
case CHAT_REQUEST_ROOM_LIST:
if (p instanceof ChatRequestRoomList)
- handleChatRoomListRequest(player, (ChatRequestRoomList) p);
+ handleChatRoomListRequest(player);
break;
case CHAT_INSTANT_MESSAGE_TO_CHARACTER:
if (p instanceof ChatInstantMessageToCharacter)
@@ -176,13 +231,19 @@ public class ChatService extends Service {
break;
}
}
-
+
private void handlePlayerEventIntent(PlayerEventIntent intent) {
switch (intent.getEvent()) {
+ case PE_ZONE_IN:
+ // TODO: Add players to proper planet chat room
+ break;
case PE_FIRST_ZONE:
Player player = intent.getPlayer();
sendPersistentMessageHeaders(player, intent.getGalaxy());
updateChatAvatarStatus(player, intent.getGalaxy(), true);
+ enterJoinedChatChannels(player);
+ enterChatChannel(intent.getPlayer(), "SWG.Localhost.Tatooine.Planet");
+ enterChatChannel(intent.getPlayer(), "SWG.Localhost.Tatooine.system");
break;
case PE_LOGGED_OUT:
if (intent.getPlayer() == null || intent.getPlayer().getCreatureObject() == null)
@@ -232,6 +293,265 @@ public class ChatService extends Service {
}
}
+ /* Chat Rooms */
+
+ private void handleChatSendToRoom(Player player, ChatSendToRoom p) {
+ ChatResult result = ChatResult.SUCCESS;
+
+ ChatRoom room = getRoom(p.getRoomId());
+ if (room == null)
+ result = ChatResult.ROOM_INVALID_ID;
+
+ if (result != ChatResult.SUCCESS) {
+ player.sendPacket(new ChatOnSendRoomMessage(result.getCode(), p.getSequence()));
+ return;
+ }
+
+ if (!incrementMessageCounter(player.getNetworkId(), room.getId(), p.getSequence()))
+ return;
+
+ ChatAvatar avatar = ChatAvatar.getFromPlayer(player);
+
+ result = room.canSendMessage(avatar);
+
+ // TODO: Check length of messages -- Result 16 is used for too long message
+
+ player.sendPacket(new ChatOnSendRoomMessage(result.getCode(), p.getSequence()));
+
+ if (result == ChatResult.SUCCESS)
+ room.sendMessage(avatar, p.getMessage(), p.getOutOfBandPackage(), player.getPlayerManager());
+ }
+
+ private void handleChatQueryRoom(Player player, ChatQueryRoom p) {
+ ChatRoom room = getRoom(p.getRoomPath()); // No result code is sent for queries
+ if (room == null)
+ return;
+
+ player.sendPacket(new ChatQueryRoomResults(room, p.getSequence()));
+ }
+
+ private void handleChatRoomListRequest(Player player) {
+ // TODO: Filter out private rooms
+ ChatRoomList response = new ChatRoomList(roomMap.values());
+ player.sendPacket(response);
+ }
+
+ private void sendOnEnteredChatRoom(Player player, ChatAvatar avatar, ChatResult result, int id, int sequence) {
+ ChatOnEnteredRoom onEnteredRoom = new ChatOnEnteredRoom(avatar, id, sequence);
+ onEnteredRoom.setResult(result.getCode());
+ player.sendPacket(onEnteredRoom);
+ }
+
+ private void enterJoinedChatChannels(Player player) {
+ if (player == null || player.getPlayerState() != PlayerState.ZONED_IN)
+ return;
+
+ PlayerObject ghost = player.getPlayerObject();
+ if (ghost == null)
+ return;
+
+ for (Integer id : ghost.getJoinedChannels()) {
+ enterChatChannel(player, id);
+ }
+ }
+
+ /**
+ * Attempts to join the specified chat channel
+ * @param player Player joining the chat channel
+ * @param room Chat room to enter
+ */
+ public void enterChatChannel(Player player, ChatRoom room, int sequence) {
+ ChatAvatar avatar = ChatAvatar.getFromPlayer(player);
+
+ PlayerObject ghost = player.getPlayerObject();
+ if (ghost == null) {
+ sendOnEnteredChatRoom(player, avatar, ChatResult.NONE, room.getId(), sequence);
+ return;
+ }
+
+ ChatResult result = room.canJoinRoom(avatar);
+ if (result != ChatResult.SUCCESS && player.getAccessLevel() != AccessLevel.PLAYER) {
+ sendOnEnteredChatRoom(player, avatar, result, room.getId(), sequence);
+ return;
+ }
+ // TODO: Check if player is appropriate faction for the room (Rebel and imperial chat rooms)
+
+ // Server-based list so we can join chat channels automatically
+ /* // TODO: Disabled until planet chat is automatically entered/removed from the list
+ List joinedChannels = ghost.getJoinedChannels();
+ if (!joinedChannels.contains(room.getId()))
+ joinedChannels.add(room.getId());*/
+
+ room.getMembers().add(avatar);
+
+ // Re-send the player the room list with just this room as it could have been private/hidden
+ // This also "refreshes" the client, not sending this will cause a Chat channel unavailable message.
+ ChatRoomList roomList = new ChatRoomList(room);
+ player.sendPacket(roomList);
+
+ // Notify players of success
+ ChatOnEnteredRoom onEnteredRoom = new ChatOnEnteredRoom(avatar, room.getId(), sequence);
+ onEnteredRoom.setResult(result.getCode()); // ChatResult.SUCCESS at this point
+ player.sendPacket(onEnteredRoom);
+
+ PlayerManager manager = player.getPlayerManager();
+ // Notify everyone that a player entered the room
+ for (ChatAvatar chatAvatar : room.getMembers()) {
+ if (chatAvatar.equals(avatar))
+ continue;
+
+ Player member = manager.getPlayerFromNetworkId(chatAvatar.getNetworkId());
+ if (member == null || member.getPlayerState() != PlayerState.ZONED_IN)
+ continue;
+ // TODO: Should sequence be set to 0 for other members?
+ member.sendPacket(onEnteredRoom);
+ }
+
+ System.out.println(avatar + " has entered room " + room);
+ }
+
+ public void enterChatChannel(Player player, int id, int sequence) {
+ ChatRoom room = getRoom(id);
+ if (room == null) {
+ sendOnEnteredChatRoom(player, ChatAvatar.getFromPlayer(player), ChatResult.NONE, id, sequence);
+ return;
+ }
+ enterChatChannel(player, room, sequence);
+ }
+
+ public void enterChatChannel(Player player, int id) {
+ enterChatChannel(player, id, 0);
+ }
+
+ public void enterChatChannel(Player player, String path) {
+ for (ChatRoom room : roomMap.values()) {
+ if (room.getPath().equals(path)) {
+ enterChatChannel(player, room, 0);
+ return;
+ }
+ }
+ System.out.println("Couldn't find room with path " + path);
+ }
+
+ /**
+ * 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) {
+ if (path.isEmpty() || path.endsWith("."))
+ return null;
+
+ String base = "SWG." + creator.getGalaxy();
+ if (!path.startsWith(base) || path.equals(base))
+ return null;
+
+ // 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, "");
+ }
+ }
+
+ ChatRoom room = new ChatRoom();
+ int id = maxChatRoomId;
+ maxChatRoomId++;
+
+ room.setId(id);
+ room.setOwner(creator);
+ room.setCreator(creator);
+ room.setIsPublic(isPublic);
+ room.setPath(path);
+ room.setTitle(title);
+
+ roomMap.put(id, room);
+ return room;
+ }
+
+ private void createSystemChannels(String galaxy) {
+ ChatAvatar systemAvatar = ChatAvatar.getSystemAvatar(galaxy);
+
+ String basePath = "SWG." + galaxy + ".";
+ createRoom(systemAvatar, true, basePath + "Galaxy", "public chat for the whole galaxy, cannot create rooms here");
+ createRoom(systemAvatar, true, basePath + "system", "system messages for this galaxy");
+ createRoom(systemAvatar, true, basePath + "Chat", "public chat for this galaxy, can create rooms here");
+ createRoom(systemAvatar, true, basePath + "Imperial", "Imperial chat for this galaxy");
+ createRoom(systemAvatar, true, basePath + "ImperialWarRoom", "Imperial war room chat for this galaxy");
+ createRoom(systemAvatar, true, basePath + "Rebel", "Rebel chat for this galaxy");
+ createRoom(systemAvatar, true, basePath + "RebelWarRoom", "Rebel war room chat for this galaxy");
+ createRoom(systemAvatar, true, basePath + "BountyHunter", "Bounty Hunter chat for this galaxy");
+ createRoom(systemAvatar, true, basePath + "Commando", "Commando chat for this galaxy");
+ createRoom(systemAvatar, true, basePath + "Entertainer", "Entertainer chat for this galaxy");
+ createRoom(systemAvatar, true, basePath + "ForceSensitive", "Force Sensitive chat for this galaxy");
+ createRoom(systemAvatar, true, basePath + "Medic", "Medic chat for this galaxy");
+ createRoom(systemAvatar, true, basePath + "Officer", "Officer chat for this galaxy");
+ createRoom(systemAvatar, true, basePath + "Pilot", "Pilot chat for this galaxy");
+ createRoom(systemAvatar, true, basePath + "Politician", "Politician chat for this galaxy");
+ createRoom(systemAvatar, true, basePath + "Smuggler", "Smuggler chat for this galaxy");
+ createRoom(systemAvatar, true, basePath + "Spy", "Spy chat for this galaxy");
+ createRoom(systemAvatar, true, basePath + "Trader", "Trader chat for this galaxy");
+ createRoom(systemAvatar, true, basePath + "BeastMastery", "Beast Mastery chat for this galaxy");
+ createRoom(systemAvatar, true, basePath + "Auction", "Auction chat for this galaxy");
+ createPlanetChannels(systemAvatar, basePath);
+ }
+
+ private void createPlanetChannels(ChatAvatar systemAvatar, String basePath) {
+ for (Terrain terrain : terrains) {
+ String path = basePath + Character.toUpperCase(terrain.getName().charAt(0)) + terrain.getName().substring(1) + ".";
+ 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");
+ }
+ }
+
+ private boolean incrementMessageCounter(long networkId, int roomId, int messageId) {
+ if (networkId == -1) // System ChatAvatar uses -1 for networkId
+ return true;
+
+ Map messageHistory = messages.get(networkId);
+ if (messageHistory != null) {
+ if (messageHistory.containsKey(roomId) && messageHistory.get(roomId) == messageId)
+ return false;
+ } else {
+ messageHistory = new HashMap<>();
+ messages.put(networkId, messageHistory);
+ }
+ messageHistory.put(roomId, messageId);
+ return true;
+ }
+
+ public void initializeGalaxyChannels(Galaxy galaxy) {
+ ChatAvatar systemAvatar = new ChatAvatar(-1, "System", galaxy.getName());
+ createSystemChannels(galaxy.getName());
+ /** Channel Notes
+ * Group channels: created by System
+ * - SWG.serverName.group.GroupObjectId.GroupChat title = GroupId
+ * Guild channels: created by System
+ * - SWG.serverName.guild.GuildId.GuildChat title = GuildId
+ * City channels: created by System
+ * - SWG.serverName.city.CityId.CityChat title = CityId
+ */
+ }
+
+ public ChatRoom getRoom(String path) {
+ for (ChatRoom room : roomMap.values()) {
+ if (room.getPath().equals(path))
+ return room;
+ }
+ return null;
+ }
+
+ public ChatRoom getRoom(int roomId) {
+ return roomMap.get(roomId);
+ }
+
+ /* Friends List */
+
private void handleRequestFriendList(Player player) {
PlayerObject ghost = player.getPlayerObject();
if (ghost == null)
@@ -290,10 +610,6 @@ public class ChatService extends Service {
new ChatBroadcastIntent(player, new ProsePackage("@cmnty:friend_added", "TT", target)).broadcast();
}
- private void handleChatRoomListRequest(Player player, ChatRequestRoomList request) {
-
- }
-
private void handleSpatialChat(SpatialChatIntent i) {
Player sender = i.getPlayer();
SWGObject actor = sender.getCreatureObject();
@@ -329,7 +645,9 @@ public class ChatService extends Service {
receiver.sendPacket(new ChatInstantMessageToClient(request.getGalaxy(), strSender, request.getMessage()));
}
-
+
+ /* Mails */
+
private void handleSendPersistentMessage(PlayerManager playerMgr, Player sender, String galaxy, ChatPersistentMessageToServer request) {
String recipientStr = request.getRecipient().toLowerCase(Locale.ENGLISH);
@@ -501,7 +819,7 @@ public class ChatService extends Service {
private void deletePersistentMessage(int mailId) {
mails.remove(mailId);
}
-
+
private enum MailFlagType {
FULL_MESSAGE,
HEADER_ONLY
diff --git a/src/services/galaxy/GalacticManager.java b/src/services/galaxy/GalacticManager.java
index 17689ef4b..ac78b52d0 100644
--- a/src/services/galaxy/GalacticManager.java
+++ b/src/services/galaxy/GalacticManager.java
@@ -33,6 +33,7 @@ import intents.network.InboundPacketIntent;
import resources.Galaxy;
import resources.control.Intent;
import resources.control.Manager;
+import services.chat.ChatService;
import services.objects.ObjectManager;
import services.player.PlayerManager;
@@ -43,6 +44,7 @@ public class GalacticManager extends Manager {
private ObjectManager objectManager;
private PlayerManager playerManager;
private GameManager gameManager;
+ private ChatService chatService;
private Intent prevPacketIntent;
private Galaxy galaxy;
@@ -51,16 +53,19 @@ public class GalacticManager extends Manager {
objectManager = new ObjectManager();
playerManager = new PlayerManager();
gameManager = new GameManager();
+ chatService = new ChatService();
prevPacketIntent = null;
addChildService(objectManager);
addChildService(playerManager);
addChildService(gameManager);
+ addChildService(chatService);
}
@Override
public boolean initialize() {
registerForIntent(InboundPacketIntent.TYPE);
+ chatService.initializeGalaxyChannels(galaxy);
return super.initialize();
}
diff --git a/src/services/galaxy/GameManager.java b/src/services/galaxy/GameManager.java
index 90a6c6fa1..5b29af5a7 100644
--- a/src/services/galaxy/GameManager.java
+++ b/src/services/galaxy/GameManager.java
@@ -33,21 +33,18 @@ import services.commands.CommandService;
import services.sui.SuiService;
public class GameManager extends Manager {
-
- private ChatService chatService;
+
private CommandService commandService;
private ConnectionService connectionService;
private SuiService suiService;
private WeatherService weatherService;
public GameManager() {
- chatService = new ChatService();
commandService = new CommandService();
connectionService = new ConnectionService();
suiService = new SuiService();
weatherService = new WeatherService();
-
- addChildService(chatService);
+
addChildService(commandService);
addChildService(connectionService);
addChildService(suiService);