diff --git a/scripts/commands/generic/addFriend.py b/scripts/commands/generic/addFriend.py
index 485e1ee0a..140dec685 100644
--- a/scripts/commands/generic/addFriend.py
+++ b/scripts/commands/generic/addFriend.py
@@ -1,29 +1,15 @@
from intents.chat import ChatAvatarRequestIntent
-from intents.chat import ChatBroadcastIntent
-from resources.encodables import ProsePackage
-from intents.chat.ChatAvatarRequestIntent.RequestType import TARGET_STATUS
-import sys
+from intents.chat.ChatAvatarRequestIntent.RequestType import FRIEND_ADD_TARGET
def execute(galacticManager, player, target, args):
ghost = player.getPlayerObject()
- if ghost is None:
+ if ghost is None or args is None:
return
- name = str(args.split(" ")[0])
- name.lower()
+ name = str(args.split(" ")[0]).lower()
- # TODO: Check ignore list for name -- return message @cmnty:friend_fail_is_ignored TT name if ignored
-
- if ghost.getFriendsList().contains(name):
- ChatBroadcastIntent(player, ProsePackage("@cmnty:friend_duplicate", "TT", name)).broadcast()
+ if not name:
return
- if galacticManager.getPlayerManager().playerExists(name) is False:
- ChatBroadcastIntent(player, ProsePackage("@cmnty:friend_duplicate", "TT", name)).broadcast()
- return
-
- ghost.addFriend(name)
- ChatBroadcastIntent(player, ProsePackage("@cmnty:friend_added", "TT", name)).broadcast()
-
- ChatAvatarRequestIntent(player, name, TARGET_STATUS).broadcast()
+ ChatAvatarRequestIntent(player, name, FRIEND_ADD_TARGET).broadcast()
return
diff --git a/scripts/commands/generic/getFriendList.py b/scripts/commands/generic/getFriendList.py
new file mode 100644
index 000000000..c75dd1c4b
--- /dev/null
+++ b/scripts/commands/generic/getFriendList.py
@@ -0,0 +1,7 @@
+from intents.chat import ChatAvatarRequestIntent
+from intents.chat.ChatAvatarRequestIntent.RequestType import FRIEND_LIST
+
+
+def execute(galacticManager, player, target, args):
+ ChatAvatarRequestIntent(player, None, FRIEND_LIST).broadcast()
+ return
diff --git a/scripts/commands/generic/removeFriend.py b/scripts/commands/generic/removeFriend.py
index 4ff98acf1..6871aacd4 100644
--- a/scripts/commands/generic/removeFriend.py
+++ b/scripts/commands/generic/removeFriend.py
@@ -1,20 +1,22 @@
from intents.chat import ChatBroadcastIntent
from resources.encodables import ProsePackage
-import sys
+from intents.chat import ChatAvatarRequestIntent
+from intents.chat.ChatAvatarRequestIntent.RequestType import FRIEND_REMOVE_TARGET
def execute(galacticManager, player, target, args):
ghost = player.getPlayerObject()
- if ghost is None:
+ if ghost is None or not args:
return
- name = str(args.split(" ")[0])
- name.lower()
+ name = str(args.split(" ")[0]).lower()
+
+ if not name:
+ return
if ghost.getFriendsList().contains(name) is False:
ChatBroadcastIntent(player, ProsePackage("@cmnty:friend_not_found", "TT", name)).broadcast()
return
- ghost.removeFriend(name)
- ChatBroadcastIntent(player, ProsePackage("@cmnty:friend_removed", "TT", name)).broadcast()
+ ChatAvatarRequestIntent(player, name, FRIEND_REMOVE_TARGET).broadcast()
return
diff --git a/src/intents/chat/ChatAvatarRequestIntent.java b/src/intents/chat/ChatAvatarRequestIntent.java
index 8243cbb2a..2ed8d4538 100644
--- a/src/intents/chat/ChatAvatarRequestIntent.java
+++ b/src/intents/chat/ChatAvatarRequestIntent.java
@@ -60,7 +60,10 @@ public class ChatAvatarRequestIntent extends Intent{
}
public enum RequestType {
+ FRIEND_LIST,
TARGET_STATUS,
+ FRIEND_ADD_TARGET,
+ FRIEND_REMOVE_TARGET,
IGNORE_ADD_TARGET,
IGNORE_REMOVE_TARGET
}
diff --git a/src/intents/chat/ChatBroadcastIntent.java b/src/intents/chat/ChatBroadcastIntent.java
index 16dc9043a..86afae761 100644
--- a/src/intents/chat/ChatBroadcastIntent.java
+++ b/src/intents/chat/ChatBroadcastIntent.java
@@ -53,11 +53,12 @@ public class ChatBroadcastIntent extends Intent {
this(null, receiver, null, BroadcastType.PERSONAL);
this.prose = prose;
}
-
public ChatBroadcastIntent(String message, BroadcastType type) {
this(message, null, null, type);
}
-
+ public ChatBroadcastIntent(Player receiver, String message) {
+ this(message, receiver, null, BroadcastType.PERSONAL);
+ }
public ChatBroadcastIntent(String message) {
this(message, null, null, BroadcastType.GALAXY);
}
diff --git a/src/network/packets/Packet.java b/src/network/packets/Packet.java
index 3f37d3571..af0742e69 100644
--- a/src/network/packets/Packet.java
+++ b/src/network/packets/Packet.java
@@ -34,8 +34,8 @@ import java.nio.charset.Charset;
public class Packet {
- public static Charset ascii = Charset.forName("UTF-8");
- public static Charset unicode = Charset.forName("UTF-16LE");
+ public static final Charset ascii = Charset.forName("UTF-8");
+ public static final Charset unicode = Charset.forName("UTF-16LE");
private InetAddress address;
private ByteBuffer data;
private int port = 0;
@@ -125,9 +125,9 @@ public class Packet {
addShort(bb, b.length);
bb.put(b);
}
-
+
public static boolean getBoolean(ByteBuffer bb) {
- return getByte(bb) == 1 ? true : false;
+ return getByte(bb) == 1;
}
public static String getAscii(ByteBuffer bb) {
@@ -149,7 +149,7 @@ public class Packet {
bb.get(str);
return new String(str, unicode);
}
-
+
public static byte getByte(ByteBuffer bb) {
return bb.get();
}
diff --git a/src/network/packets/swg/zone/ServerWeatherMessage.java b/src/network/packets/swg/zone/ServerWeatherMessage.java
index 812eb4f3d..238a57f22 100644
--- a/src/network/packets/swg/zone/ServerWeatherMessage.java
+++ b/src/network/packets/swg/zone/ServerWeatherMessage.java
@@ -24,15 +24,12 @@ public class ServerWeatherMessage extends SWGPacket {
type = WeatherType.CLEAR;
break;
case 1:
- type = WeatherType.CLOUDY;
- break;
- case 2:
type = WeatherType.LIGHT;
break;
- case 3:
+ case 2:
type = WeatherType.MEDIUM;
break;
- case 4:
+ case 3:
type = WeatherType.HEAVY;
break;
}
diff --git a/src/network/packets/swg/zone/chat/ChatOnAddFriend.java b/src/network/packets/swg/zone/chat/ChatOnAddFriend.java
new file mode 100644
index 000000000..f3dbf6020
--- /dev/null
+++ b/src/network/packets/swg/zone/chat/ChatOnAddFriend.java
@@ -0,0 +1,50 @@
+/*******************************************************************************
+ * 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 ChatOnAddFriend extends SWGPacket {
+ public static final int CRC = 0x2B2A0D94;
+
+ public ChatOnAddFriend() {}
+
+ @Override
+ public ByteBuffer encode() {
+ ByteBuffer bb = ByteBuffer.allocate(14);
+ addShort(bb, 3);
+ addInt(bb, CRC);
+ addLong(bb, 0);
+ return bb;
+ }
+}
diff --git a/src/network/packets/swg/zone/chat/ChatOnChangeFriendStatus.java b/src/network/packets/swg/zone/chat/ChatOnChangeFriendStatus.java
new file mode 100644
index 000000000..148618bca
--- /dev/null
+++ b/src/network/packets/swg/zone/chat/ChatOnChangeFriendStatus.java
@@ -0,0 +1,66 @@
+/*******************************************************************************
+ * Copyright (c) 2015 /// Project SWG /// www.projectswg.com
+ *
+ * ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on
+ * July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies.
+ * Our goal is to create an emulator which will provide a server for players to
+ * continue playing a game similar to the one they used to play. We are basing
+ * it on the final publish of the game prior to end-game events.
+ *
+ * This file is part of Holocore.
+ *
+ * --------------------------------------------------------------------------------
+ *
+ * Holocore is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * Holocore is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with Holocore. If not, see
+ ******************************************************************************/
+
+package network.packets.swg.zone.chat;
+
+import network.packets.swg.SWGPacket;
+
+import java.nio.ByteBuffer;
+
+/**
+ * @author Waverunner
+ */
+public class ChatOnChangeFriendStatus extends SWGPacket {
+ public static final int CRC = 0x54336726;
+
+ private String galaxy;
+ private String friendName;
+ private boolean remove;
+ private long playerID;
+
+ public ChatOnChangeFriendStatus(long playerID, String galaxy, String friendName, boolean remove) {
+ this.playerID = playerID;
+ this.galaxy = galaxy;
+ this.friendName = friendName;
+ this.remove = remove;
+ }
+
+ @Override
+ public ByteBuffer encode() {
+ ByteBuffer bb = ByteBuffer.allocate(32 + galaxy.length() + friendName.length());
+ addShort(bb, ((short) 0x06));
+ addInt(bb, CRC);
+ addLong(bb, playerID);
+ addAscii(bb, "SWG");
+ addAscii(bb, galaxy);
+ addAscii(bb, friendName);
+ addInt(bb, 0);
+ addInt(bb, (remove ? 1 : 0));
+ addByte(bb, 0);
+ return bb;
+ }
+}
diff --git a/src/network/packets/swg/zone/chat/ChatOnGetFriendsList.java b/src/network/packets/swg/zone/chat/ChatOnGetFriendsList.java
new file mode 100644
index 000000000..7460eb40f
--- /dev/null
+++ b/src/network/packets/swg/zone/chat/ChatOnGetFriendsList.java
@@ -0,0 +1,73 @@
+/*******************************************************************************
+ * 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;
+import java.util.List;
+
+/**
+ * @author Waverunner
+ */
+public class ChatOnGetFriendsList extends SWGPacket {
+ public static final int CRC = 0xE97AB594;
+
+ private List friends;
+ private String galaxy;
+ private long objectId;
+
+ public ChatOnGetFriendsList(long objectId, String galaxy, List friends) {
+ this.objectId = objectId;
+ this.galaxy = galaxy;
+ this.friends = friends;
+ }
+
+ @Override
+ public ByteBuffer encode() {
+ int additional = galaxy.length() + 9;
+ int length = 0;
+ for (String friend : friends) {
+ length += friend.length() + additional;
+ }
+
+ ByteBuffer bb = ByteBuffer.allocate(18 + length);
+ addShort(bb, 3);
+ addInt(bb, CRC);
+ addLong(bb, objectId);
+
+ addInt(bb, friends.size());
+ for (String friend : friends) {
+ addAscii(bb, "SWG");
+ addAscii(bb, galaxy);
+ addAscii(bb, friend);
+ }
+
+ return bb;
+ }
+}
diff --git a/src/network/packets/swg/zone/chat/ChatOnSendPersistentMessage.java b/src/network/packets/swg/zone/chat/ChatOnSendPersistentMessage.java
index 198c14733..55863ba5c 100644
--- a/src/network/packets/swg/zone/chat/ChatOnSendPersistentMessage.java
+++ b/src/network/packets/swg/zone/chat/ChatOnSendPersistentMessage.java
@@ -28,27 +28,29 @@
package network.packets.swg.zone.chat;
import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
import network.packets.swg.SWGPacket;
+import services.chat.ChatResult;
public class ChatOnSendPersistentMessage extends SWGPacket {
public static final int CRC = 0x94E7A7AE;
- private int errorCode;
+ private ChatResult result;
private int count;
- public ChatOnSendPersistentMessage(int errorCode, int count) {
- this.errorCode = errorCode;
+ public ChatOnSendPersistentMessage(ChatResult result, int count) {
+ this.result = result;
this.count = count;
}
@Override
public ByteBuffer encode() {
- ByteBuffer data = ByteBuffer.allocate(20);
+ ByteBuffer data = ByteBuffer.allocate(14);
addShort(data, 3);
- addInt(data, errorCode);
+ addInt(data, CRC);
+ addInt(data, result.getCode());
addInt(data, count);
return data;
}
-
}
diff --git a/src/network/packets/swg/zone/chat/ChatPersistentMessageToClient.java b/src/network/packets/swg/zone/chat/ChatPersistentMessageToClient.java
index 841757038..2b69d1d50 100644
--- a/src/network/packets/swg/zone/chat/ChatPersistentMessageToClient.java
+++ b/src/network/packets/swg/zone/chat/ChatPersistentMessageToClient.java
@@ -28,334 +28,44 @@
package network.packets.swg.zone.chat;
import java.nio.ByteBuffer;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
+import java.nio.ByteOrder;
-import resources.Terrain;
-import resources.network.BaselineBuilder.Encodable;
+import resources.encodables.player.Mail;
import network.packets.swg.SWGPacket;
public class ChatPersistentMessageToClient extends SWGPacket {
public static final int CRC = 0x08485E17;
- private String senderName;
+ private Mail mail;
private String galaxy;
- private int mailId;
private boolean header;
- private String subject;
- private String message;
- private List waypointAttachments;
- private List proseAttachments;
- private byte status;
- private int timestamp;
-
- public ChatPersistentMessageToClient(boolean header, String sender, String galaxy, int mailId, String subject, String message, int timestamp, byte status) {
- waypointAttachments = new ArrayList();
- proseAttachments = new ArrayList();
- this.senderName = sender;
+
+ public ChatPersistentMessageToClient(Mail mail, String galaxy, boolean header) {
+ this.mail = mail;
this.galaxy = galaxy;
- this.mailId = mailId;
this.header = header;
- this.subject = subject;
- this.message = message;
- this.status = status;
- this.timestamp = timestamp;
}
-
- public ChatPersistentMessageToClient(Encodable mailEncodable) {
-
- }
- public ChatPersistentMessageToClient(ByteBuffer data) {
- decode(data);
- }
-
- public void decode(ByteBuffer data) {
- if (!super.decode(data, CRC))
- return;
- senderName = getAscii(data);
- getAscii(data); // SWG
- galaxy = getAscii(data);
- mailId = getInt(data);
- header = getBoolean(data);
-
- if (header) {
- getInt(data); // 0?
- subject = getUnicode(data);
- getInt(data);
- } else {
- message = getUnicode(data);
- subject = getUnicode(data);
- int size = getInt(data) * 2;
- int start = data.position();
- do {
- getShort(data); // 0?
- byte type = getByte(data);
- getInt(data); // Integer version of the type, it seems
- if (type == 4)
- waypointAttachments.add(WaypointAttachment.deserialize(data));
- else if (type == 1)
- proseAttachments.add(ProseAttachment.deserialize(data));
- else {
- System.err.println("Invalid type supplied in ChatPersistentMessageToClient.decode");
- break;
- }
- } while (data.position() - start < size);
- }
- status = getByte(data);
- timestamp = getInt(data);
- }
-
+
+ @Override
public ByteBuffer encode() {
- int extraSize = 0;
- if (header) {
- extraSize += 12 + subject.length()*2;
- } else {
- extraSize += 12 + message.length()*2 + subject.length()*2;
- for (WaypointAttachment waypoint : waypointAttachments)
- extraSize += 7 + waypoint.getSerializableSize();
- for (ProseAttachment prose : proseAttachments)
- extraSize += 7 + prose.getSerializableSize();
- }
- ByteBuffer data = ByteBuffer.allocate(25 + extraSize + galaxy.length() + senderName.length());
- addShort(data, 2);
- addInt( data, CRC);
- addAscii(data, senderName);
- addAscii(data, "SWG");
- addAscii(data, galaxy);
- addInt(data, mailId);
- addBoolean(data, header);
-
- if (header) {
- addInt(data, 0); // message (empty as 1 is sending only the header to the client)
- addUnicode(data, subject);
- addInt(data, 0);
- } else {
- addUnicode(data, message);
- addUnicode(data, subject);
- addInt(data, 0); // TODO: Mail Attachments
- /*for (WaypointAttachment waypoint : waypointAttachments) {
- addShort(data, 0);
- addByte(data, 4);
- addInt(data, 0xFFFFFFFD);
- waypoint.serialize(data);
- }
- for (ProseAttachment prose : proseAttachments) {
- addShort(data, 0);
- addByte(data, 1);
- addInt(data, 0xFFFFFFFF);
- prose.serialize(data);
- }*/
- }
- addByte(data, status);
- addInt(data, timestamp);
- return data;
+ byte[] data = (header ? mail.encodeHeader() : mail.encode());
+
+ ByteBuffer bb = ByteBuffer.allocate(25 + galaxy.length() + data.length + (mail.getSender().length() * 2)).order(ByteOrder.LITTLE_ENDIAN);
+ addShort(bb, 2);
+ addInt(bb, CRC);
+
+ addAscii(bb, mail.getSender());
+ addAscii(bb, "SWG");
+ addAscii(bb, galaxy);
+ addInt(bb, mail.getId());
+ addBoolean(bb, header);
+
+ bb.put(data);
+
+ addByte(bb, mail.getStatus());
+ addInt(bb, mail.getTimestamp());
+ return bb;
}
-
- public void setSenderName(String senderName) {
- this.senderName = senderName;
- }
-
- public void setGalaxy(String galaxy) {
- this.galaxy = galaxy;
- }
-
- public void setMailId(int mailId) {
- this.mailId = mailId;
- }
-
- public void setHeader(boolean header) {
- this.header = header;
- }
-
- public void setSubject(String subject) {
- this.subject = subject;
- }
-
- public void setMessage(String message) {
- this.message = message;
- }
-
- public void addWaypoint(WaypointAttachment waypoint) {
- waypointAttachments.add(waypoint);
- }
-
- public void addAllWaypoints(Collection waypoints) {
- waypointAttachments.addAll(waypoints);
- }
-
- public void addProse(ProseAttachment prose) {
- proseAttachments.add(prose);
- }
-
- public void addAllProses(Collection proses) {
- proseAttachments.addAll(proses);
- }
-
- public void setStatus(byte status) {
- this.status = status;
- }
-
- public void setTimestamp(int timestamp) {
- this.timestamp = timestamp;
- }
-
- public static class WaypointAttachment {
- private float x;
- private float y;
- private float z;
- private Terrain planet;
- private String attachmentName;
- private long cellId;
- private byte color;
- private boolean active;
-
- public float getX() { return x; }
- public float getY() { return y; }
- public float getZ() { return z; }
- public Terrain getPlanet() { return planet; }
- public String getAttachmentName() { return attachmentName; }
- public long getCellId() { return cellId; }
- public byte getColor() { return color; }
- public boolean isActive() { return active; }
-
- public void setX(float x) { this.x = x; }
- public void setY(float y) { this.y = y; }
- public void setZ(float z) { this.z = z; }
- public void setPlanet(Terrain p) { this.planet = p; }
- public void setAttachmentName(String name) { this.attachmentName = name; }
- public void setCellId(long id) { this.cellId = id; }
- public void setColor(byte c) { this.color = c; }
- public void setActive(boolean active) { this.active = active; }
-
- private final int getSerializableSize() {
- return 43 + attachmentName.length()*2;
- }
-
- private static final WaypointAttachment deserialize(ByteBuffer data) {
- WaypointAttachment waypoint = new WaypointAttachment();
- getInt(data); // 0?
- waypoint.setX(getFloat(data));
- waypoint.setY(getFloat(data));
- waypoint.setZ(getFloat(data));
- getLong(data); // 0?
- waypoint.setPlanet(Terrain.getTerrainFromCrc(getInt(data)));
- waypoint.setAttachmentName(getUnicode(data));
- waypoint.setCellId(getLong(data));
- waypoint.setColor(getByte(data));
- waypoint.setActive(getBoolean(data));
- getByte(data); // 0?
- return waypoint;
- }
-
- public final void serialize(ByteBuffer data) {
- addInt (data, 0);
- addFloat (data, getX());
- addFloat (data, getY());
- addFloat (data, getZ());
- addLong (data, 0);
- addInt (data, planet.getCrc());
- addUnicode(data, attachmentName);
- addLong (data, cellId);
- addByte (data, color);
- addBoolean(data, active);
- addByte (data, 0);
- }
- }
-
- public static class ProseAttachment {
- private String stf;
- private ProseSegment tu;
- private ProseSegment tt;
- private ProseSegment to;
- private int diInt;
- private float dfFloat;
-
- public String getSTF() { return stf; }
- public ProseSegment getTu() { return tu; }
- public ProseSegment getTt() { return tt; }
- public ProseSegment getTo() { return to; }
- public int getDiInteger() { return diInt; }
- public float getDfFloat() { return dfFloat; }
-
- public void setSTF(String stf) { this.stf = stf; }
- public void setTu(ProseSegment tu) { this.tu = tu; }
- public void setTt(ProseSegment tt) { this.tt = tt; }
- public void setTo(ProseSegment to) { this.to = to; }
- public void setDiInteger(int di) { this.diInt = di; }
- public void setDfFloat(float df) { this.dfFloat = df; }
-
- private final int getSerializableSize() {
- return 10 + stf.length() + tu.getSerializableSize() + tt.getSerializableSize() + to.getSerializableSize();
- }
-
- private static final ProseAttachment deserialize(ByteBuffer data) {
- ProseAttachment prose = new ProseAttachment();
- prose.setSTF(getAscii(data));
- prose.setTu(ProseSegment.deserialize(data));
- prose.setTt(ProseSegment.deserialize(data));
- prose.setTo(ProseSegment.deserialize(data));
- prose.setDiInteger(getInt(data));
- prose.setDfFloat(getFloat(data));
- return prose;
- }
-
- public final void serialize(ByteBuffer data) {
- addAscii(data, stf);
- tu.serialize(data);
- tt.serialize(data);
- to.serialize(data);
- addInt(data, diInt);
- addFloat(data, dfFloat);
- }
-
- public static class ProseSegment {
- private long objectId;
- private String stf;
- private String customString;
-
- public long getObjectId() { return objectId; }
- public String getSTF() { return stf; }
- public String getCustomString() { return customString; }
-
- public void setObjectId(long id) { this.objectId = id; }
- public void setSTF(String stf) { this.stf = stf; }
- public void setCustomString(String custom) { this.customString = custom; }
-
- private final int getSerializableSize() {
- return 14 + stf.length() + customString.length()*2;
- }
-
- private static final ProseSegment deserialize(ByteBuffer data) {
- ProseSegment segment = new ProseSegment();
- segment.setObjectId(getLong(data));
- segment.setSTF(getAscii(data));
- segment.setCustomString(getUnicode(data));
- return segment;
- }
-
- private final void serialize(ByteBuffer data) {
- addLong(data, objectId);
- addAscii(data, stf);
- addUnicode(data, customString);
- }
- }
- }
- /*
- * ASCII Stf
- * LONG TuObjectId
- * ASCII TuStf
- * UNICODE TuCustomString
- * LONG TtObjectId
- * ASCII TtStf
- * UNICODE TtCustomString
- * LONG ToObjectId
- * ASCII ToStf
- * UNICODE ToCustomString
- * INT DiInteger
- * FLOAT DfFloat
- * BYTE 0
- */
-
+
}
diff --git a/src/network/packets/swg/zone/chat/ChatPersistentMessageToServer.java b/src/network/packets/swg/zone/chat/ChatPersistentMessageToServer.java
index 93e41524d..c5287e046 100644
--- a/src/network/packets/swg/zone/chat/ChatPersistentMessageToServer.java
+++ b/src/network/packets/swg/zone/chat/ChatPersistentMessageToServer.java
@@ -28,14 +28,16 @@
package network.packets.swg.zone.chat;
import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
import network.packets.swg.SWGPacket;
+import resources.encodables.OutOfBandPackage;
public class ChatPersistentMessageToServer extends SWGPacket {
public static final int CRC = 0x25A29FA6;
private String message;
- private String outOfBand;
+ private OutOfBandPackage outOfBandPackage;
private int counter;
private String subject;
private String galaxy;
@@ -43,9 +45,8 @@ public class ChatPersistentMessageToServer extends SWGPacket {
public ChatPersistentMessageToServer() {
message = "";
- outOfBand = "";
+ outOfBandPackage = new OutOfBandPackage();
subject = "";
-
galaxy = "";
recipient = "";
}
@@ -55,10 +56,9 @@ public class ChatPersistentMessageToServer extends SWGPacket {
if (!super.decode(data, CRC))
return;
message = getUnicode(data);
- outOfBand = getUnicode(data);
+ outOfBandPackage.decode(data);
counter = getInt(data);
subject = getUnicode(data);
-
getAscii(data); // "SWG"
galaxy = getAscii(data);
recipient = getAscii(data);
@@ -66,10 +66,11 @@ public class ChatPersistentMessageToServer extends SWGPacket {
@Override
public ByteBuffer encode() {
- int dataLength = 31 + message.length()*2+outOfBand.length()*2+subject.length()*2+galaxy.length()+recipient.length();
+ byte[] oob = outOfBandPackage.encode();
+ int dataLength = 31 + message.length()*2+oob.length+subject.length()*2+galaxy.length()+recipient.length();
ByteBuffer data = ByteBuffer.allocate(dataLength);
addUnicode(data, message);
- addUnicode(data, outOfBand);
+ data.put(oob);
addInt(data, counter);
addUnicode(data, subject);
addAscii(data, "SWG");
@@ -82,8 +83,8 @@ public class ChatPersistentMessageToServer extends SWGPacket {
return message;
}
- public String getOutOfBand() {
- return outOfBand;
+ public OutOfBandPackage getOutOfBandPackage() {
+ return outOfBandPackage;
}
public int getCounter() {
@@ -106,8 +107,8 @@ public class ChatPersistentMessageToServer extends SWGPacket {
this.message = message;
}
- public void setOutOfBand(String outOfBand) {
- this.outOfBand = outOfBand;
+ public void setOutOfBandPackage(OutOfBandPackage outOfBandPackage) {
+ this.outOfBandPackage = outOfBandPackage;
}
public void setCounter(int counter) {
diff --git a/src/network/packets/swg/zone/chat/ChatSystemMessage.java b/src/network/packets/swg/zone/chat/ChatSystemMessage.java
index 3d6107d8f..c5b096d7d 100644
--- a/src/network/packets/swg/zone/chat/ChatSystemMessage.java
+++ b/src/network/packets/swg/zone/chat/ChatSystemMessage.java
@@ -29,7 +29,7 @@ package network.packets.swg.zone.chat;
import java.nio.ByteBuffer;
-import resources.encodables.OutOfBand;
+import resources.encodables.OutOfBandPackage;
import network.packets.swg.SWGPacket;
public class ChatSystemMessage extends SWGPacket {
@@ -37,7 +37,7 @@ public class ChatSystemMessage extends SWGPacket {
public static final int CRC = 0x6D2A6413;
private int type = 0;
private String message = "";
- private OutOfBand oob;
+ private OutOfBandPackage oob;
public ChatSystemMessage() {
@@ -48,7 +48,7 @@ public class ChatSystemMessage extends SWGPacket {
this.message = message;
}
- public ChatSystemMessage(int type, OutOfBand oob) {
+ public ChatSystemMessage(int type, OutOfBandPackage oob) {
this.type = type;
this.oob = oob;
}
@@ -57,7 +57,7 @@ public class ChatSystemMessage extends SWGPacket {
this(type.ordinal(), message);
}
- public ChatSystemMessage(SystemChatType type, OutOfBand oob) {
+ public ChatSystemMessage(SystemChatType type, OutOfBandPackage oob) {
this(type.ordinal(), oob);
}
diff --git a/src/network/packets/swg/zone/object_controller/ObjectMenuResponse.java b/src/network/packets/swg/zone/object_controller/ObjectMenuResponse.java
index a3c342d37..7e1d67849 100644
--- a/src/network/packets/swg/zone/object_controller/ObjectMenuResponse.java
+++ b/src/network/packets/swg/zone/object_controller/ObjectMenuResponse.java
@@ -56,7 +56,7 @@ public class ObjectMenuResponse extends ObjectController {
public ObjectMenuResponse(ByteBuffer data) {
super(CRC);
- options = new ArrayList();
+ options = new ArrayList<>();
decode(data);
}
@@ -72,6 +72,7 @@ public class ObjectMenuResponse extends ObjectController {
option.setId(getShort(data));
option.setOptionType(getByte(data));
option.setText(getUnicode(data));
+ options.add(option);
}
counter = getByte(data);
}
diff --git a/src/resources/Terrain.java b/src/resources/Terrain.java
index b0ab3bdc0..38469cb39 100644
--- a/src/resources/Terrain.java
+++ b/src/resources/Terrain.java
@@ -123,8 +123,8 @@ public enum Terrain {
Terrain(String file) {
this.file = file;
- this.crc = CRC.getCrc(file);
this.name = file.substring(8, file.length() - 4);
+ this.crc = CRC.getCrc(name);
}
public String getFile() { return file; }
diff --git a/src/resources/WeatherType.java b/src/resources/WeatherType.java
index e68f1405a..63b65e187 100644
--- a/src/resources/WeatherType.java
+++ b/src/resources/WeatherType.java
@@ -1,19 +1,30 @@
package resources;
+/**
+ * Make sure that the chances for each weather type add up to 1.0 (100%).
+ * @author Ziggy
+ *
+ */
public enum WeatherType {
- CLEAR(0),
- CLOUDY(1),
- LIGHT(2),
- MEDIUM(3),
- HEAVY(4);
+ CLEAR(0, .60f), // 60% chance
+ LIGHT(1, .20f), // 20% chance
+ MEDIUM(2, .15f), // 15% chance
+ HEAVY(3, .05f); // 5% chance
private int value;
+ private float chance;
- WeatherType(int value) {
+ WeatherType(int value, float chance) {
this.value = value;
+ this.chance = chance;
}
public int getValue() {
return value;
}
+
+ public float getChance() {
+ return chance;
+ }
+
}
diff --git a/src/resources/collections/SWGList.java b/src/resources/collections/SWGList.java
index bfcd0124c..e66fee37f 100644
--- a/src/resources/collections/SWGList.java
+++ b/src/resources/collections/SWGList.java
@@ -231,7 +231,24 @@ public class SWGList extends AbstractList implements Encodable {
// Clear the queue since the delta has been sent to observers through the builder
clearDeltaQueue();
}
-
+
+ public void sendRefreshedListData(SWGObject target) {
+ clearDeltaQueue();
+ updateCount = 0;
+
+ ByteBuffer bb = ByteBuffer.allocate(11 + dataSize).order(ByteOrder.LITTLE_ENDIAN);
+ bb.putInt(data.size() + 1);
+ bb.putInt(updateCount += data.size() + 1);
+ bb.put((byte) 3);
+ bb.putShort((short) data.size());
+ for (byte[] bytes : data) {
+ bb.put(bytes);
+ }
+
+ DeltaBuilder builder = new DeltaBuilder(target, baseline, view, updateType, bb.array());
+ builder.send();
+ }
+
public void clearDeltaQueue() {
deltas.clear();
deltaSize = 0;
@@ -271,6 +288,10 @@ public class SWGList extends AbstractList implements Encodable {
data.add(encodedData);
}
+ createIndexedDelta(encodedData, index, update);
+ }
+
+ private void createIndexedDelta(byte[] encodedData, int index, byte update) {
ByteBuffer buffer = ByteBuffer.allocate(encodedData.length + 2).order(ByteOrder.LITTLE_ENDIAN);
buffer.putShort((short) index);
buffer.put(encodedData);
diff --git a/src/resources/commands/callbacks/FindFriendCallback.java b/src/resources/commands/callbacks/FindFriendCallback.java
new file mode 100644
index 000000000..5782acaf0
--- /dev/null
+++ b/src/resources/commands/callbacks/FindFriendCallback.java
@@ -0,0 +1,97 @@
+/*******************************************************************************
+ * Copyright (c) 2015 /// Project SWG /// www.projectswg.com
+ *
+ * ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on
+ * July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies.
+ * Our goal is to create an emulator which will provide a server for players to
+ * continue playing a game similar to the one they used to play. We are basing
+ * it on the final publish of the game prior to end-game events.
+ *
+ * This file is part of Holocore.
+ *
+ * --------------------------------------------------------------------------------
+ *
+ * Holocore is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * Holocore is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with Holocore. If not, see
+ ******************************************************************************/
+
+package resources.commands.callbacks;
+
+import intents.chat.ChatBroadcastIntent;
+import resources.Location;
+import resources.commands.ICmdCallback;
+import resources.encodables.ProsePackage;
+import resources.objects.SWGObject;
+import resources.objects.player.PlayerObject;
+import resources.objects.waypoint.WaypointObject;
+import resources.player.Player;
+import resources.player.PlayerState;
+import services.galaxy.GalacticManager;
+
+import java.util.Map;
+
+/**
+ * @author Waverunner
+ */
+public class FindFriendCallback implements ICmdCallback {
+ @Override
+ public void execute(GalacticManager galacticManager, Player player, SWGObject target, String args) {
+ PlayerObject ghost = player.getPlayerObject();
+
+ if (ghost == null || args.isEmpty())
+ return;
+
+ String friendName = args.split(" ")[0].toLowerCase();
+
+ if (!ghost.getFriendsList().contains(friendName)) {
+ new ChatBroadcastIntent(player, "@ui_cmnty:friend_location_failed_noname").broadcast();
+ return;
+ }
+
+ Player friend = galacticManager.getPlayerManager().getPlayerByCreatureFirstName(friendName);
+ if (friend == null || friend.getPlayerState() != PlayerState.ZONED_IN) {
+ new ChatBroadcastIntent(player, new ProsePackage("@ui_cmnty:friend_location_failed", "TU", friendName)).broadcast();
+ return;
+ }
+
+ PlayerObject friendGhost = friend.getPlayerObject();
+ if (friendGhost == null || !friendGhost.getFriendsList().contains(player.getCharacterName().split(" ")[0].toLowerCase())) {
+ new ChatBroadcastIntent(player, new ProsePackage("@ui_cmnty:friend_location_failed", "TU", friendName)).broadcast();
+ return;
+ }
+
+ Location location = friend.getCreatureObject().getLocation();
+
+ WaypointObject waypoint = null;
+ for (Map.Entry entry : ghost.getWaypoints().entrySet()) {
+ WaypointObject waypointEntry = entry.getValue();
+ if (waypointEntry == null || !waypointEntry.getName().equals(friendName))
+ continue;
+
+ waypoint = waypointEntry;
+ break;
+ }
+
+ if (waypoint == null) {
+ waypoint = (WaypointObject) galacticManager.getObjectManager().createObject("object/waypoint/shared_waypoint.iff", location, false);
+ waypoint.setColor(WaypointObject.WaypointColor.PURPLE);
+ waypoint.setName(friendName);
+ ghost.addWaypoint(waypoint);
+ new ChatBroadcastIntent(player, new ProsePackage("@ui_cmnty:friend_location_create_new_wp", "TU", friendName)).broadcast();
+ } else {
+ waypoint.setLocation(location);
+ ghost.updateWaypoint(waypoint);
+ new ChatBroadcastIntent(player, new ProsePackage("@ui_cmnty:friend_location", "TU", friendName)).broadcast();
+ }
+ }
+}
diff --git a/src/resources/commands/callbacks/WaypointCmdCallback.java b/src/resources/commands/callbacks/WaypointCmdCallback.java
index 81a687ac4..b34753d8d 100644
--- a/src/resources/commands/callbacks/WaypointCmdCallback.java
+++ b/src/resources/commands/callbacks/WaypointCmdCallback.java
@@ -27,6 +27,7 @@
***********************************************************************************/
package resources.commands.callbacks;
+import intents.chat.ChatBroadcastIntent;
import resources.Location;
import resources.Terrain;
import resources.commands.ICmdCallback;
@@ -45,61 +46,144 @@ public class WaypointCmdCallback implements ICmdCallback {
PlayerObject ghost = player.getPlayerObject();
if (ghost == null)
return;
-
- String[] cmdArgs = args.split(" ");
- if (cmdArgs.length > 6)
- cmdArgs = args.split(" ", 6);
- WaypointColor color = null;
+ String[] cmdArgs = args.split(" ");
+
+ WaypointColor color = WaypointColor.BLUE;
Terrain terrain = null;
String name = null;
- float x = -1;
- float y = -1;
+ float x = Float.NaN;
+ float z = Float.NaN;
+
+ // Validate parameters, format for proper command arguments as it's split at whitespace
+ for (int i = 0; i < cmdArgs.length; i++) {
+ switch(i) {
+ // This could be either for just a named waypoint at current spot (1 param) or a planet arg (6 param)
+ case 0:
+ if (Terrain.getTerrainFromName(cmdArgs[0]) != null) {
+ // Terrain's name could also be part of the waypoint name, check to see if next few args are coords
+ try {
+ if (cmdArgs.length > 2) {
+ x = Float.parseFloat(cmdArgs[1]);
+ if (cmdArgs.length >= 3) {
+ z = Float.parseFloat(cmdArgs[2]); // Just to be sure.. Maybe someone wanted some numbers in the name.
+ if (cmdArgs.length != 6)
+ cmdArgs = args.split(" ", 6);
+ }
+ }
+ } catch (NumberFormatException e) {
+ // This is just a named waypoint.
+ cmdArgs = new String[]{args};
+ }
+ } else {
+ // This is just a named waypoint.
+ cmdArgs = new String[]{args};
+ }
+ break;
+ // This could be either for a name (3 param) or a z coordinate (6 param)
+ case 3:
+ try {
+ z = Float.parseFloat(cmdArgs[3]);
+ // Ensure 100% this is a 6 argument command as the first param MUST be the planet name
+ if (Terrain.getTerrainFromName(cmdArgs[0]) != null)
+ if (cmdArgs.length != 6)
+ cmdArgs = args.split(" ", 6);
+ else cmdArgs = args.split(" ", 4);
+ } catch (NumberFormatException e) {
+ // This is intended for a name, should be 4 params
+ cmdArgs = args.split(" ", 4);
+ }
+ break;
+ default: break;
+ }
+ }
+
+ // Was there an error message saying the format was wrong?
switch(cmdArgs.length) {
+ case 1: // name
+ name = cmdArgs[0];
+ break;
case 2: // x y
x = floatValue(cmdArgs[0]);
- if (x == -1)
- return;
- y = floatValue(cmdArgs[1]);
+ if (Float.isNaN(x))
+ break;
+ z = floatValue(cmdArgs[1]);
break;
- case 4: // x z y name
+ case 3: // x y z
x = floatValue(cmdArgs[0]);
- if (x == -1)
- return;
- //z = floatValue(cmdArgs[1]);
- y = floatValue(cmdArgs[2]);
+ if (Float.isNaN(x))
+ break;
+ //y = floatValue(cmdArgs[1]);
+ z = floatValue(cmdArgs[2]);
+ break;
+ case 4: // x y z name
+ x = floatValue(cmdArgs[0]);
+ if (Float.isNaN(x))
+ break;
+ //y = floatValue(cmdArgs[1]);
+ z = floatValue(cmdArgs[2]);
+ if (Float.isNaN(z))
+ break;
name = cmdArgs[3];
break;
- case 6: // planet x z y color name
+ case 6: // planet x y z color name
terrain = Terrain.getTerrainFromName(cmdArgs[0]);
if (terrain == null)
- return;
+ break;
x = floatValue(cmdArgs[1]);
- if (x == -1)
- return;
- //z = floatValue(cmdArgs[2]);
- y = floatValue(cmdArgs[3]);
- color = colorValue(cmdArgs[4]);
+ if (Float.isNaN(x))
+ break;
+ //y = floatValue(cmdArgs[2]);
+ z = floatValue(cmdArgs[3]);
+ if (Float.isNaN(z))
+ break;
+ color = WaypointColor.fromString(cmdArgs[4]);
name = cmdArgs[5];
break;
- default:
- break;
+ default:
+ // Not a valid format for /waypoint command
+ return;
+ }
+
+ Location location = new Location(player.getCreatureObject().getLocation());
+
+ if (!Float.isNaN(x))
+ location.setX(x);
+
+ if (!Float.isNaN(z))
+ location.setZ(z);
+
+ boolean differentPlanetMessage = false;
+ if (terrain != null) {
+ if (terrain != location.getTerrain()) {
+ location.setTerrain(terrain);
+ differentPlanetMessage = true;
+ }
+ }
+
+ if (name == null)
+ name = "Waypoint";
+
+ WaypointObject waypoint = createWaypoint(galacticManager.getObjectManager(), color, name, location);
+ ghost.addWaypoint(waypoint);
+
+ if (differentPlanetMessage) {
+ new ChatBroadcastIntent(player, "Waypoint: New waypoint \""+ name + "\" created for location "
+ + terrain.getName() + " (" + String.format("%.0f", location.getX()) + ", "
+ + String.format("%.0f", location.getY()) + ", "+ String.format("%.0f", location.getZ()) + ")").broadcast();
+ } else {
+ new ChatBroadcastIntent(player, "Waypoint: New waypoint \""+ name + "\" created for location ("
+ + String.format("%.0f", location.getX()) + ", "+ String.format("%.0f", location.getY())
+ + ", "+ String.format("%.0f", location.getZ()) + ")").broadcast();
}
- WaypointObject waypoint = createWaypoint(galacticManager.getObjectManager(), terrain, color, name, x, y, player.getCreatureObject().getLocation());
- ghost.addWaypoint(waypoint);
-
}
- private WaypointObject createWaypoint(ObjectManager objManager, Terrain terrain, WaypointColor color, String name, float x, float y, Location loc) {
- WaypointObject waypoint = (WaypointObject) objManager.createObject("object/waypoint/shared_waypoint.iff", false);
-
- waypoint.setLocation(new Location((x != -1 ? x : loc.getX()), 0, (y != -1 ? y : loc.getZ()), (terrain != null ? terrain : loc.getTerrain())));
- if (color != null)
- waypoint.setColor(color);
-
- waypoint.setName(name == null ? "New Waypoint" : name);
-
+ private WaypointObject createWaypoint(ObjectManager objManager, WaypointColor color, String name, Location location) {
+ WaypointObject waypoint = (WaypointObject) objManager.createObject("object/waypoint/shared_waypoint.iff", location, false);
+ waypoint.setColor(color);
+ waypoint.setName(name);
+ // TODO: Check if the location collides with a building, and if it does then set the proper cellId
return waypoint;
}
@@ -107,19 +191,7 @@ public class WaypointCmdCallback implements ICmdCallback {
try {
return Float.parseFloat(str);
} catch (NumberFormatException | NullPointerException e) {
- return (float) -1;
- }
- }
-
- private WaypointColor colorValue(String str) {
- switch (str) {
- case "blue": return WaypointColor.BLUE;
- case "green": return WaypointColor.GREEN;
- case "yellow": return WaypointColor.YELLOW;
- case "white": return WaypointColor.WHITE;
- case "orange": return WaypointColor.ORANGE;
- case "purple": return WaypointColor.PURPLE;
- default: return WaypointColor.BLUE;
+ return Float.NaN;
}
}
}
diff --git a/src/resources/containers/ContainerPermissions.java b/src/resources/containers/ContainerPermissions.java
index 6c0edb3a4..b411cc595 100644
--- a/src/resources/containers/ContainerPermissions.java
+++ b/src/resources/containers/ContainerPermissions.java
@@ -40,8 +40,8 @@ import java.util.*;
public abstract class ContainerPermissions implements Serializable {
private static final long serialVersionUID = 1L;
- public static WorldPermissions WORLD = new WorldPermissions();
- public static InventoryPermissions INVENTORY = new InventoryPermissions();
+ public static final WorldPermissions WORLD = new WorldPermissions();
+ public static final InventoryPermissions INVENTORY = new InventoryPermissions();
private Map permissionGroups;
private List joinedGroups;
@@ -160,7 +160,8 @@ public abstract class ContainerPermissions implements Serializable {
}
public static int valueOf(EnumSet bitmaskSet) {
- return valueOf(bitmaskSet);
+ Permission[] permissions = bitmaskSet.toArray(new Permission[0]);
+ return valueOf(permissions);
}
public static int valueOf(Permission... permissions) {
diff --git a/src/resources/encodables/OutOfBand.java b/src/resources/encodables/OutOfBandPackage.java
similarity index 52%
rename from src/resources/encodables/OutOfBand.java
rename to src/resources/encodables/OutOfBandPackage.java
index 2b86bf558..83962a2a5 100644
--- a/src/resources/encodables/OutOfBand.java
+++ b/src/resources/encodables/OutOfBandPackage.java
@@ -29,53 +29,121 @@ package resources.encodables;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
import resources.network.BaselineBuilder.Encodable;
+import resources.objects.waypoint.WaypointObject;
-public class OutOfBand implements Encodable {
- // Multiple ProsePackages, need to find an example of it in a packet. Also note that OutOfBand's did not have just ProsePackages.
-
+public class OutOfBandPackage implements Encodable {
private static final long serialVersionUID = 1L;
- private ProsePackage prose;
- private Type type;
+ private List packages;
+ private transient List data;
+ private transient int dataSize;
- public OutOfBand(ProsePackage prose) {
- this.prose = prose;
- this.type = Type.PROSE_PACKAGE;
+ public OutOfBandPackage() {
+ packages = new ArrayList<>(5);
}
-
- public static OutOfBand ProsePackage(Object ... objects) {
- return new OutOfBand(new ProsePackage(objects));
+
+ public OutOfBandPackage(OutOfBandData outOfBandData) {
+ this();
+ packages.add(outOfBandData);
}
-
- public static OutOfBand ProsePackage(Object stf, String key, Object prose) {
- return new OutOfBand(new ProsePackage(stf, key, prose));
+
+ public static OutOfBandPackage createWithProse(Object stf, String key, Object prose) {
+ return new OutOfBandPackage(new ProsePackage(stf, key, prose));
}
-
+
@Override
public byte[] encode() {
- byte[] encodedProse = prose.encode();
+ if (packages.size() == 0)
+ return new byte[4];
- ByteBuffer bb = ByteBuffer.allocate(11 + encodedProse.length).order(ByteOrder.LITTLE_ENDIAN);
+ if (data == null) {
+ data = new LinkedList<>();
- bb.putInt((7 + encodedProse.length) / 2);
- bb.putShort((short) 0); // ?? -- seen as 0 and 1
- bb.put((byte) type.ordinal());
- bb.putInt(-1); // ??
- bb.put(encodedProse);
+ for (OutOfBandData outOfBandData : packages) {
+ byte[] bytes = outOfBandData.encodeOutOfBandData();
+ dataSize += bytes.length;
+ data.add(bytes);
+ }
+ }
+
+ ByteBuffer bb = ByteBuffer.allocate(4 + dataSize).order(ByteOrder.LITTLE_ENDIAN);
+
+ bb.putInt(dataSize / 2);
+
+ for (byte[] bytes : data) {
+ bb.put(bytes);
+ }
return bb.array();
}
+ public void decode(ByteBuffer data) {
+ int size = data.getInt() * 2;
+
+ for (int read = 0; read < size; read+= 3) {
+ boolean addedByte = data.getShort() > 0; // ?? Seen as 1
+
+ Type type = Type.valueOf(data.get());
+ switch(type) {
+ case PROSE_PACKAGE:
+ ProsePackage prose = new ProsePackage();
+ read += prose.decodeOutOfBandData(data);
+ packages.add(prose);
+ break;
+ case WAYPOINT:
+ WaypointObject waypoint = new WaypointObject(-1);
+ read += waypoint.decodeOutOfBandData(data);
+ packages.add(waypoint);
+ break;
+ default:
+ System.err.println("Tried to decode an unsupported OutOfBandData Type: " + type);
+ break;
+ }
+
+ if (addedByte) {
+ data.get();
+ read+= 1;
+ }
+ }
+ }
+
public enum Type {
- OBJECT,
- PROSE_PACKAGE,
- UNKNOWN,
- AUCTION_TOKEN,
- WAYPOINT,
- STRING_ID,
- STRING,
- UNKNOWN_2
+ NONE(-1),
+ OBJECT(0),
+ PROSE_PACKAGE(1),
+ UNKNOWN(2),
+ AUCTION_TOKEN(3),
+ WAYPOINT(4),
+ STRING_ID(5),
+ STRING(6),
+ UNKNOWN_2(7);
+
+ byte type;
+
+ Type(int type) {
+ this.type = (byte) type;
+ }
+
+ public byte getType() {
+ return type;
+ }
+
+ public static Type valueOf(byte typeByte) {
+ for (Type type : Type.values()) {
+ if (type.getType() == typeByte)
+ return type;
+ }
+ return Type.NONE;
+ }
+ }
+
+ public interface OutOfBandData extends Encodable {
+ byte[] encodeOutOfBandData();
+ int decodeOutOfBandData(ByteBuffer data);
}
}
diff --git a/src/resources/encodables/ProsePackage.java b/src/resources/encodables/ProsePackage.java
index 388c33b27..898d5b873 100644
--- a/src/resources/encodables/ProsePackage.java
+++ b/src/resources/encodables/ProsePackage.java
@@ -34,10 +34,10 @@ import java.nio.charset.Charset;
import resources.network.BaselineBuilder.Encodable;
-public class ProsePackage implements Encodable {
+public class ProsePackage implements OutOfBandPackage.OutOfBandData {
private static final long serialVersionUID = 1L;
- private Stf base;
+ private Stf base = new Stf("", "");
private Prose actor = new Prose();
private Prose target = new Prose();
@@ -50,6 +50,8 @@ public class ProsePackage implements Encodable {
private boolean grammarFlag = false;
+ public ProsePackage() {}
+
/**
* Creates a new ProsePackage that contains only 1 parameter for the specified STF object
*
@@ -191,10 +193,10 @@ public class ProsePackage implements Encodable {
byte[] targetData = target.encode();
byte[] otherData = other.encode();
- int size = 9 + stringData.length + actorData.length + targetData.length + otherData.length;
-
- ByteBuffer bb = ByteBuffer.allocate(size).order(ByteOrder.LITTLE_ENDIAN);
-
+ ByteBuffer bb = ByteBuffer.allocate(16 + stringData.length + actorData.length + targetData.length + otherData.length).order(ByteOrder.LITTLE_ENDIAN);
+ bb.putShort((short) 0); // ??
+ bb.put(OutOfBandPackage.Type.PROSE_PACKAGE.getType());
+ bb.putInt(-1); // ??
bb.put(stringData);
bb.put(actorData);
bb.put(targetData);
@@ -208,6 +210,17 @@ public class ProsePackage implements Encodable {
return bb.array();
}
+
+ @Override
+ public byte[] encodeOutOfBandData() {
+ return encode();
+ }
+
+ @Override
+ public int decodeOutOfBandData(ByteBuffer data) {
+ return 0;
+ }
+
@Override
public String toString() {
return "[ProsePackage] " + base.toString() + " Actor=" + actor.toString()
diff --git a/src/resources/encodables/player/Mail.java b/src/resources/encodables/player/Mail.java
index 8557b32ef..4766fa67f 100644
--- a/src/resources/encodables/player/Mail.java
+++ b/src/resources/encodables/player/Mail.java
@@ -27,7 +27,12 @@
***********************************************************************************/
package resources.encodables.player;
+import resources.encodables.OutOfBandPackage;
import resources.network.BaselineBuilder.Encodable;
+import utilities.Encoder;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
public class Mail implements Encodable {
private static final long serialVersionUID = 1L;
@@ -37,9 +42,9 @@ public class Mail implements Encodable {
private long receiverId;
private String subject;
private String message;
+ private OutOfBandPackage outOfBandPackage;
private byte status;
private int timestamp;
- // TODO: Waypoint attachments
public static final byte NEW = 0x4E;
public static final byte READ = 0x52;
@@ -52,12 +57,6 @@ public class Mail implements Encodable {
this.receiverId = receiverId;
this.status = NEW;
}
-
- @Override
- public byte [] encode() {
- // TODO Auto-generated method stub
- return new byte[0];
- }
public int getId() {
return id;
@@ -98,4 +97,26 @@ public class Mail implements Encodable {
public void setTimestamp(int timestamp) {
this.timestamp = timestamp;
}
+
+ public void setOutOfBandPackage(OutOfBandPackage outOfBandPackage) {
+ this.outOfBandPackage = outOfBandPackage;
+ }
+
+ @Override
+ public byte[] encode() {
+ byte[] oob = outOfBandPackage.encode();
+ ByteBuffer bb = ByteBuffer.allocate(8 + (message.length() * 2) + (subject.length() * 2) + oob.length).order(ByteOrder.LITTLE_ENDIAN);
+ bb.put(Encoder.encodeUnicode(message));
+ bb.put(Encoder.encodeUnicode(subject));
+ bb.put(oob);
+ return bb.array();
+ }
+
+ public byte[] encodeHeader() {
+ ByteBuffer bb = ByteBuffer.allocate(12 + subject.length() * 2).order(ByteOrder.LITTLE_ENDIAN);
+ bb.putInt(0);
+ bb.put(Encoder.encodeUnicode(subject));
+ bb.putInt(0);
+ return bb.array();
+ }
}
diff --git a/src/resources/network/BaselineBuilder.java b/src/resources/network/BaselineBuilder.java
index 992218d6c..e412e32bf 100644
--- a/src/resources/network/BaselineBuilder.java
+++ b/src/resources/network/BaselineBuilder.java
@@ -163,7 +163,7 @@ public class BaselineBuilder {
}
public interface Encodable extends Serializable {
- public byte [] encode();
+ byte [] encode();
}
}
diff --git a/src/resources/objects/SWGObject.java b/src/resources/objects/SWGObject.java
index fa05aef2b..e2f84deaf 100644
--- a/src/resources/objects/SWGObject.java
+++ b/src/resources/objects/SWGObject.java
@@ -493,7 +493,7 @@ public abstract class SWGObject implements Serializable, Comparable {
if (volume == null)
return 0;
try {
- return Integer.valueOf(volume.toString());
+ return Integer.parseInt(volume.toString());
} catch (NumberFormatException e) {
return 0;
}
diff --git a/src/resources/objects/waypoint/WaypointObject.java b/src/resources/objects/waypoint/WaypointObject.java
index c8fd7dc72..3afd881cc 100644
--- a/src/resources/objects/waypoint/WaypointObject.java
+++ b/src/resources/objects/waypoint/WaypointObject.java
@@ -30,18 +30,22 @@ package resources.objects.waypoint;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
+import network.packets.Packet;
import network.packets.swg.zone.baselines.Baseline.BaselineType;
+import resources.Location;
+import resources.Terrain;
import resources.common.CRC;
+import resources.encodables.OutOfBandPackage;
import resources.network.BaselineBuilder.Encodable;
import resources.objects.intangible.IntangibleObject;
import resources.player.Player;
import utilities.Encoder;
-public class WaypointObject extends IntangibleObject implements Encodable {
+public class WaypointObject extends IntangibleObject implements OutOfBandPackage.OutOfBandData {
private static final long serialVersionUID = 1L;
- private int cellNumber;
+ private long cellId;
private String name = "New Waypoint";
private WaypointColor color = WaypointColor.BLUE;
private boolean active = true;
@@ -50,89 +54,136 @@ public class WaypointObject extends IntangibleObject implements Encodable {
super(objectId, BaselineType.WAYP);
}
-
- public int getCellNumber() {
- return cellNumber;
- }
-
-
- public void setCellNumber(int cellNumber) {
- this.cellNumber = cellNumber;
- }
-
public String getName() {
return name;
}
-
public void setName(String name) {
this.name = name;
}
-
public WaypointColor getColor() {
return color;
}
-
public void setColor(WaypointColor color) {
this.color = color;
}
-
public boolean isActive() {
return active;
}
-
+
public void setActive(boolean active) {
this.active = active;
}
+ public long getCellId() {
+ return cellId;
+ }
+
+ public void setCellId(long cellId) {
+ this.cellId = cellId;
+ }
+
public void createObject(Player target) {
// NOTE: Client is never sent a WAYP baseline in NGE, WaypointObject's just go inside the Waypoint List in PLAY.
}
@Override
public byte[] encode() {
+ Location loc = getLocation();
ByteBuffer bb = ByteBuffer.allocate(42 + name.length() * 2).order(ByteOrder.LITTLE_ENDIAN);
- bb.putInt(cellNumber);
- bb.putFloat((float) getLocation().getX());
- bb.putFloat((float) 0);
- bb.putFloat((float) getLocation().getZ());
- bb.putLong(0); // Network id, used for clusters
- bb.putInt(CRC.getCrc(getLocation().getTerrain().getName()));
+ bb.putInt(0);
+ bb.putFloat((float) loc.getX());
+ bb.putFloat((float) loc.getY());
+ bb.putFloat((float) loc.getZ());
+ bb.putLong(cellId);
+ bb.putInt(CRC.getCrc(loc.getTerrain().getName()));
bb.put(Encoder.encodeUnicode(name));
bb.putLong(getObjectId());
bb.put((byte) color.getValue());
bb.put((byte) (active ? 1 : 0));
return bb.array();
}
-
+
+ @Override
+ public byte[] encodeOutOfBandData() {
+ byte[] encoded = encode();
+ ByteBuffer bb = ByteBuffer.allocate(encoded.length + 8).order(ByteOrder.LITTLE_ENDIAN);
+ bb.putShort((short) 1); // ??
+ bb.put(OutOfBandPackage.Type.WAYPOINT.getType());
+ bb.putInt(-3); // ??
+ bb.put(encoded);
+ bb.put((byte) 0);
+ return bb.array();
+ }
+
+ @Override
+ public int decodeOutOfBandData(ByteBuffer data) {
+ data.getInt(); // -3
+ data.getInt();
+ setLocation(data.getFloat(), data.getFloat(), data.getFloat());
+ cellId = data.getLong();
+ getLocation().setTerrain(Terrain.getTerrainFromCrc(data.getInt()));
+ name = Packet.getUnicode(data);
+ data.getLong();
+ color = WaypointColor.valueOf(data.get());
+ active = Packet.getBoolean(data);
+ return 46 + name.length() * 2;
+ }
+
@Override
public boolean equals(Object o) {
if (!super.equals(o))
return false;
if (o instanceof WaypointObject) {
WaypointObject wp = (WaypointObject) o;
- return wp.name.equals(name) && wp.cellNumber == cellNumber && wp.color == color && wp.active == active;
+ return wp.name.equals(name) && wp.cellId == cellId && wp.color == color && wp.active == active;
}
return false;
}
@Override
public int hashCode() {
- return ((super.hashCode() * 7 + name.hashCode()) * 13 + color.getValue()) * 17 + cellNumber;
+ return ((super.hashCode() * 7 + name.hashCode()) * 13 + color.getValue()) * 17 + (int) cellId;
}
-
+
+ @Override
+ public String toString() {
+ return "[WaypointObject] " + getLocation() + " Name: " + name + " Color: " + color + " Active: " + active;
+ }
+
public enum WaypointColor{
BLUE(1), GREEN(2), ORANGE(3), YELLOW(4), PURPLE(5), WHITE(6), MULTICOLOR(7);
private int i;
- private WaypointColor(int i) {
+ WaypointColor(int i) {
this.i = i;
}
public int getValue() { return i; }
+
+ public static WaypointColor valueOf(int colorId) {
+ for (WaypointColor color : WaypointColor.values()) {
+ if (color.getValue() == colorId)
+ return color;
+ }
+ return WaypointColor.BLUE;
+ }
+
+ public static WaypointColor fromString(String string) {
+ switch(string) {
+ case "blue": return WaypointColor.BLUE;
+ case "green": return WaypointColor.GREEN;
+ case "orange": return WaypointColor.ORANGE;
+ case "yellow": return WaypointColor.YELLOW;
+ case "purple": return WaypointColor.PURPLE;
+ case "white": return WaypointColor.WHITE;
+ case "multicolor": return WaypointColor.MULTICOLOR;
+ default: return WaypointColor.BLUE;
+ }
+ }
}
}
diff --git a/src/resources/objects/weapon/WeaponObject.java b/src/resources/objects/weapon/WeaponObject.java
index 88f6c78a7..c29691483 100644
--- a/src/resources/objects/weapon/WeaponObject.java
+++ b/src/resources/objects/weapon/WeaponObject.java
@@ -133,7 +133,7 @@ public class WeaponObject extends TangibleObject implements Encodable{
byte[] data3 = bb.buildAsBaselinePacket();
bb = new BaselineBuilder(this, BaselineType.WEAO, 6);
- createBaseline6(null, bb);
+ createBaseline6(null, bb); // TODO: This needs to have a target otherwise null pointer will be thrown, new encode function in encodable?
byte[] data6 = bb.buildAsBaselinePacket();
byte[] ret = new byte[data3.length + data6.length];
diff --git a/src/services/chat/ChatResult.java b/src/services/chat/ChatResult.java
new file mode 100644
index 000000000..700d294d9
--- /dev/null
+++ b/src/services/chat/ChatResult.java
@@ -0,0 +1,48 @@
+/*******************************************************************************
+ * 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 services.chat;
+
+/**
+ * @author Waverunner
+ */
+public enum ChatResult {
+ NONE(-1),
+ SUCCESS(0),
+ TARGET_AVATAR_DOESNT_EXIST(4),
+ IGNORED(23);
+
+
+ private final int code;
+ ChatResult(int code) {
+ this.code = code;
+ }
+
+ public int getCode() {
+ return code;
+ }
+}
diff --git a/src/services/chat/ChatService.java b/src/services/chat/ChatService.java
index 5983d25f3..3d662d15e 100644
--- a/src/services/chat/ChatService.java
+++ b/src/services/chat/ChatService.java
@@ -34,6 +34,7 @@ import intents.chat.ChatBroadcastIntent;
import intents.chat.PersistentMessageIntent;
import intents.chat.SpatialChatIntent;
import intents.network.GalacticPacketIntent;
+import intents.player.ZonePlayerSwapIntent;
import intents.server.ServerStatusIntent;
import network.packets.Packet;
import network.packets.swg.SWGPacket;
@@ -42,6 +43,9 @@ import network.packets.swg.zone.chat.ChatDeletePersistentMessage;
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.ChatOnGetFriendsList;
import network.packets.swg.zone.chat.ChatOnSendInstantMessage;
import network.packets.swg.zone.chat.ChatOnSendPersistentMessage;
import network.packets.swg.zone.chat.ChatPersistentMessageToClient;
@@ -51,9 +55,10 @@ import network.packets.swg.zone.chat.ChatSystemMessage;
import network.packets.swg.zone.chat.ChatSystemMessage.SystemChatType;
import network.packets.swg.zone.object_controller.SpatialChat;
import resources.Terrain;
+import resources.collections.SWGList;
import resources.control.Intent;
import resources.control.Service;
-import resources.encodables.OutOfBand;
+import resources.encodables.OutOfBandPackage;
import resources.encodables.ProsePackage;
import resources.encodables.player.Mail;
import resources.objects.SWGObject;
@@ -76,7 +81,7 @@ public class ChatService extends Service {
private int maxMailId;
public ChatService() {
- mails = new CachedObjectDatabase("odb/mails.db");
+ mails = new CachedObjectDatabase<>("odb/mails.db");
maxMailId = 1;
}
@@ -89,6 +94,7 @@ public class ChatService extends Service {
registerForIntent(ChatBroadcastIntent.TYPE);
registerForIntent(ServerStatusIntent.TYPE);
registerForIntent(ChatAvatarRequestIntent.TYPE);
+ registerForIntent(ZonePlayerSwapIntent.TYPE);
mails.load();
mails.traverse(new Traverser() {
@Override
@@ -174,10 +180,13 @@ public class ChatService extends Service {
private void handlePlayerEventIntent(PlayerEventIntent intent) {
switch (intent.getEvent()) {
case PE_FIRST_ZONE:
- sendPersistentMessageHeaders(intent.getPlayer(), intent.getGalaxy());
- updateChatAvatarStatus(intent.getPlayer(), intent.getGalaxy(), true);
+ Player player = intent.getPlayer();
+ sendPersistentMessageHeaders(player, intent.getGalaxy());
+ updateChatAvatarStatus(player, intent.getGalaxy(), true);
break;
case PE_LOGGED_OUT:
+ if (intent.getPlayer() == null || intent.getPlayer().getCreatureObject() == null)
+ return;
updateChatAvatarStatus(intent.getPlayer(), intent.getGalaxy(), false);
break;
default:
@@ -197,7 +206,7 @@ public class ChatService extends Service {
broadcastGalaxyMessage(i.getMessage());
break;
case PERSONAL:
- broadcastPersonalMessage(i.getProse(), i.getBroadcaster());
+ broadcastPersonalMessage(i.getProse(), i.getBroadcaster(), i.getMessage());
break;
}
}
@@ -211,9 +220,76 @@ public class ChatService extends Service {
break;
case IGNORE_ADD_TARGET:
break;
+ case FRIEND_ADD_TARGET:
+ handleAddFriend(i.getPlayer(), i.getTarget());
+ break;
+ case FRIEND_REMOVE_TARGET:
+ handleRemoveFriend(i.getPlayer(), i.getTarget());
+ break;
+ case FRIEND_LIST:
+ handleRequestFriendList(i.getPlayer());
+ break;
}
}
+ private void handleRequestFriendList(Player player) {
+ PlayerObject ghost = player.getPlayerObject();
+ if (ghost == null)
+ return;
+
+ SWGList friends = (SWGList) ghost.getFriendsList();
+ player.sendPacket(new ChatOnGetFriendsList(player.getCreatureObject().getObjectId(), player.getGalaxyName(), friends));
+
+ friends.sendRefreshedListData(ghost);
+ }
+
+ private void handleRemoveFriend(Player player, String target) {
+ PlayerObject ghost = player.getPlayerObject();
+ if (ghost == null)
+ return;
+
+ ChatOnChangeFriendStatus friendStatus = new ChatOnChangeFriendStatus(
+ player.getCreatureObject().getObjectId(), player.getGalaxyName(), target, true);
+
+ player.sendPacket(friendStatus);
+
+ ghost.removeFriend(target);
+
+ new ChatBroadcastIntent(player, new ProsePackage("@cmnty:friend_removed", "TT", target)).broadcast();
+ }
+
+ private void handleAddFriend(Player player, String target) {
+ if (target.equalsIgnoreCase(player.getCharacterName().split(" ")[0]))
+ return;
+
+ PlayerObject ghost = player.getPlayerObject();
+ if (ghost == null)
+ return;
+
+ if (ghost.getFriendsList().contains(target)) {
+ new ChatBroadcastIntent(player, new ProsePackage("@cmnty:friend_duplicate", "TT", target)).broadcast();
+ return;
+ }
+
+ if (!player.getPlayerManager().playerExists(target)) {
+ new ChatBroadcastIntent(player, new ProsePackage("@cmnty:friend_not_found", "TT", target)).broadcast();
+ return;
+ }
+
+ ChatOnChangeFriendStatus friendStatus = new ChatOnChangeFriendStatus(
+ player.getCreatureObject().getObjectId(), player.getGalaxyName(), target, false);
+
+ player.sendPacket(new ChatOnAddFriend(), friendStatus);
+
+ Player targetPlayer = player.getPlayerManager().getPlayerByCreatureFirstName(target);
+ if (targetPlayer != null && targetPlayer.getPlayerState() == PlayerState.ZONED_IN)
+ player.sendPacket(new ChatFriendsListUpdate(player.getGalaxyName(), target, true));
+
+ ghost.addFriend(target);
+
+ new ChatBroadcastIntent(player, new ProsePackage("@cmnty:friend_added", "TT", target)).broadcast();
+ }
+
private void handleChatRoomListRequest(Player player, ChatRequestRoomList request) {
}
@@ -262,17 +338,20 @@ public class ChatService extends Service {
Player recipient = playerMgr.getPlayerByCreatureFirstName(recipientStr);
long recId = (recipient == null ? playerMgr.getCharacterIdByName(request.getRecipient()) : recipient.getCreatureObject().getObjectId());
- int errorCode = 0;
+ ChatResult result = ChatResult.SUCCESS;
if (recId == 0)
- errorCode = 4;
-
- sender.sendPacket(new ChatOnSendPersistentMessage(errorCode, request.getCounter()));
-
+ result = ChatResult.TARGET_AVATAR_DOESNT_EXIST;
+
+ sender.sendPacket(new ChatOnSendPersistentMessage(result, request.getCounter()));
+
+ if (result != ChatResult.SUCCESS)
+ return;
+
Mail mail = new Mail(sender.getCharacterName(), request.getSubject(), request.getMessage(), recId);
mail.setId(maxMailId++);
mail.setTimestamp((int) (new Date().getTime() / 1000));
-
+ mail.setOutOfBandPackage(request.getOutOfBandPackage());
mails.put(mail.getId(), mail);
if (recipient != null)
@@ -319,11 +398,10 @@ public class ChatService extends Service {
if (online) {
PlayerObject playerObject = player.getPlayerObject();
- if (playerObject == null || playerObject.getFriendsList().size() <= 0)
- return;
-
- for (String friend : playerObject.getFriendsList()) {
- sendTargetAvatarStatus(player, friend);
+ if (playerObject != null && playerObject.getFriendsList().size() <= 0) {
+ for (String friend : playerObject.getFriendsList()) {
+ sendTargetAvatarStatus(player, friend);
+ }
}
}
@@ -339,9 +417,7 @@ public class ChatService extends Service {
return false;
List friends = playerObject.getFriendsList();
- if (friends.contains(update.getFriendName()))
- return true;
- return false;
+ return friends.contains(update.getFriendName());
}
}, update);
}
@@ -378,16 +454,18 @@ public class ChatService extends Service {
new NotifyPlayersPacketIntent(packet).broadcast();
}
- private void broadcastPersonalMessage(ProsePackage prose, Player player) {
- OutOfBand pckg = new OutOfBand(prose);
- player.sendPacket(new ChatSystemMessage(SystemChatType.SCREEN_AND_CHAT, pckg));
+ private void broadcastPersonalMessage(ProsePackage prose, Player player, String message) {
+ if (prose != null)
+ player.sendPacket(new ChatSystemMessage(SystemChatType.SCREEN_AND_CHAT, new OutOfBandPackage(prose)));
+ else
+ player.sendPacket(new ChatSystemMessage(SystemChatType.SCREEN_AND_CHAT, message));
}
private void sendPersistentMessageHeaders(Player player, String galaxy) {
if (player == null || player.getCreatureObject() == null)
return;
- final List playersMail = new LinkedList();
+ final List playersMail = new LinkedList<>();
final long receiverId = player.getCreatureObject().getObjectId();
mails.traverse(new Traverser() {
@@ -410,10 +488,10 @@ public class ChatService extends Service {
switch (requestType) {
case FULL_MESSAGE:
- packet = new ChatPersistentMessageToClient(false, mail.getSender(), galaxy, mail.getId(), mail.getSubject(), mail.getMessage(), mail.getTimestamp(), mail.getStatus());
+ packet = new ChatPersistentMessageToClient(mail, galaxy, false);
break;
case HEADER_ONLY:
- packet = new ChatPersistentMessageToClient(true, mail.getSender(), galaxy, mail.getId(), mail.getSubject(), "", mail.getTimestamp(), mail.getStatus());
+ packet = new ChatPersistentMessageToClient(mail, galaxy, true);
break;
}
@@ -426,6 +504,6 @@ public class ChatService extends Service {
private enum MailFlagType {
FULL_MESSAGE,
- HEADER_ONLY;
+ HEADER_ONLY
}
}
diff --git a/src/services/commands/CommandService.java b/src/services/commands/CommandService.java
index 4e11eb70c..de225a83b 100644
--- a/src/services/commands/CommandService.java
+++ b/src/services/commands/CommandService.java
@@ -171,6 +171,7 @@ public class CommandService extends Service {
registerCallback("kneel", new KneelCmdCallback());
registerCallback("jumpServer", new JumpCmdCallback());
registerCallback("serverDestroyObject", new ServerDestroyObjectCmdCallback());
+ registerCallback("findFriend", new FindFriendCallback());
}
private void clearCommands() {
diff --git a/src/services/galaxy/GameManager.java b/src/services/galaxy/GameManager.java
index f1d141088..90a6c6fa1 100644
--- a/src/services/galaxy/GameManager.java
+++ b/src/services/galaxy/GameManager.java
@@ -30,7 +30,6 @@ package services.galaxy;
import resources.control.Manager;
import services.chat.ChatService;
import services.commands.CommandService;
-import services.player.WeatherService;
import services.sui.SuiService;
public class GameManager extends Manager {
diff --git a/src/services/player/WeatherService.java b/src/services/galaxy/WeatherService.java
similarity index 87%
rename from src/services/player/WeatherService.java
rename to src/services/galaxy/WeatherService.java
index c2fa01d1a..8bf2b019b 100644
--- a/src/services/player/WeatherService.java
+++ b/src/services/galaxy/WeatherService.java
@@ -1,4 +1,4 @@
-package services.player;
+package services.galaxy;
import java.util.HashMap;
import java.util.Map;
@@ -28,7 +28,7 @@ public final class WeatherService extends Service {
private final Random random;
public WeatherService() {
- cycleDuration = 900; // Ziggy: 15 minutes, 900 seconds
+ cycleDuration = 600; // Ziggy: 10 minutes, 600 seconds
terrains = Terrain.values();
executor = Executors.newScheduledThreadPool(terrains.length);
weatherForTerrain = new HashMap<>();
@@ -44,6 +44,7 @@ public final class WeatherService extends Service {
executor.scheduleAtFixedRate(
new WeatherChanger(t), 0,
cycleDuration, TimeUnit.SECONDS);
+
}
registerForIntent(PlayerEventIntent.TYPE);
@@ -90,14 +91,21 @@ public final class WeatherService extends Service {
swm.setType(type);
swm.setCloudVectorX(random.nextFloat()); // randomised
- swm.setCloudVectorZ(0); // Ziggy: Always 0, clouds don't move up/down
- swm.setCloudVectorY(random.nextFloat()); // randomised
+ swm.setCloudVectorZ(random.nextFloat()); // randomised
+ swm.setCloudVectorY(0); // Ziggy: Always 0, clouds don't move up/down
return swm;
}
private WeatherType randomWeather() {
- return weatherTypes[random.nextInt(weatherTypes.length)];
+ WeatherType weather = WeatherType.CLEAR;
+ float roll = random.nextFloat();
+
+ for(WeatherType candidate : weatherTypes)
+ if(roll <= candidate.getChance())
+ weather = candidate;
+
+ return weather;
}
private class WeatherChanger implements Runnable {
diff --git a/src/utilities/namegen/SWGNameGenerator.java b/src/utilities/namegen/SWGNameGenerator.java
index d455f20cb..b1d46ff90 100644
--- a/src/utilities/namegen/SWGNameGenerator.java
+++ b/src/utilities/namegen/SWGNameGenerator.java
@@ -27,6 +27,9 @@
***********************************************************************************/
package utilities.namegen;
+import resources.Race;
+import resources.zone.NameFilter;
+
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
@@ -35,9 +38,6 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import resources.Race;
-import resources.zone.NameFilter;
-
public class SWGNameGenerator {
private Map ruleMap = new HashMap<>();
@@ -158,29 +158,35 @@ public class SWGNameGenerator {
}
private String getNameByRule(RaceNameRule rule) {
- String name = "";
+ StringBuffer buffer = new StringBuffer("");
String instructions = getRandomInstruction(rule);
int l = instructions.length();
for (int i = 0; i < l; i++) {
char x = instructions.charAt(0);
- switch (x) {
- case 'v': name += removeExcessDuplications(rule.getVowels(), name, getRandomElementFrom(rule.getVowels()));
- break;
- case 'c': name += removeExcessDuplications(rule.getStartConsonants(), name, getRandomElementFrom(rule.getStartConsonants()));
- break;
- case 'd': name += removeExcessDuplications(rule.getEndConsonants(), name, getRandomElementFrom(rule.getEndConsonants()));
- break;
- case '/': name += "'";
- break;
+ switch (x) {
+ case 'v':
+ buffer.append(removeExcessDuplications(rule.getVowels(), buffer.toString(), getRandomElementFrom(rule.getVowels())));
+ break;
+ case 'c':
+ buffer.append(removeExcessDuplications(rule.getStartConsonants(), buffer.toString(), getRandomElementFrom(rule.getStartConsonants())));
+ break;
+ case 'd':
+ buffer.append(removeExcessDuplications(rule.getEndConsonants(), buffer.toString(), getRandomElementFrom(rule.getEndConsonants())));
+ break;
+ case '/':
+ buffer.append("'");
+ break;
+ default:
+ break;
}
instructions = instructions.substring(1);
}
- if (name.isEmpty())
+ if (buffer.length() == 0)
return getNameByRule(rule);
- return name;
+ return buffer.toString();
}
private String getRandomInstruction(RaceNameRule rule) {
@@ -251,6 +257,7 @@ public class SWGNameGenerator {
case "Instructions":
rule.addInstruction(line);
break;
+ default: break;
}
}
}
diff --git a/test/resources/TestWeatherType.java b/test/resources/TestWeatherType.java
new file mode 100644
index 000000000..b47c81b87
--- /dev/null
+++ b/test/resources/TestWeatherType.java
@@ -0,0 +1,24 @@
+package resources;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+
+public class TestWeatherType {
+
+ /**
+ * Tests if the chance of each weather type sum up to 100%
+ */
+ @Test
+ public void verifyChances() {
+ float expected = 1;
+ float actual = 0;
+
+ for(WeatherType type : WeatherType.values())
+ actual += type.getChance();
+
+ assertEquals(expected, actual, 0);
+
+ }
+
+}