From 045c1ddc10f3a69b7f8d4ec572ed3eed207b3b96 Mon Sep 17 00:00:00 2001 From: Ziggy Date: Fri, 31 Jul 2015 07:42:50 +0200 Subject: [PATCH 01/25] SWGMap is now compatible with non-String value types --- src/resources/collections/SWGMap.java | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/resources/collections/SWGMap.java b/src/resources/collections/SWGMap.java index 1c9275075..a1f18bfb4 100644 --- a/src/resources/collections/SWGMap.java +++ b/src/resources/collections/SWGMap.java @@ -251,8 +251,15 @@ public class SWGMap extends AbstractMap implements Encodable, Serial private void addData(Object key, Object value, byte update) { byte[] encodedKey = Encoder.encode(key, strType); - byte[] encodedValue = Encoder.encode(value, strType); - byte[] encodedData = new byte[encodedKey.length + encodedValue.length]; + byte[] encodedValue; + byte[] encodedData; + + if(value instanceof String) + encodedValue = Encoder.encode(value, strType); + else + encodedValue = Encoder.encode(value); + + encodedData = new byte[encodedKey.length + encodedValue.length]; System.arraycopy(encodedKey, 0, encodedData, 0, encodedKey.length); System.arraycopy(encodedValue, 0, encodedData, encodedKey.length, encodedValue.length); From e62b3632a6c2416b82f11e5d6ea8f377c9d5d71e Mon Sep 17 00:00:00 2001 From: Waverunner Date: Sat, 1 Aug 2015 09:12:20 -0400 Subject: [PATCH 02/25] Added moderators for custom chat channels that have enabled moderation --- src/network/PacketType.java | 2 + .../swg/zone/chat/ChatAddModeratorToRoom.java | 76 +++++++++++++++ .../zone/chat/ChatOnAddModeratorToRoom.java | 78 +++++++++++++++ .../chat/ChatOnRemoveModeratorFromRoom.java | 78 +++++++++++++++ .../chat/ChatRemoveModeratorFromRoom.java | 76 +++++++++++++++ src/resources/chat/ChatResult.java | 2 +- src/resources/chat/ChatRoom.java | 20 ++-- src/services/chat/ChatRoomService.java | 95 +++++++++++++++++-- 8 files changed, 408 insertions(+), 19 deletions(-) create mode 100644 src/network/packets/swg/zone/chat/ChatAddModeratorToRoom.java create mode 100644 src/network/packets/swg/zone/chat/ChatOnAddModeratorToRoom.java create mode 100644 src/network/packets/swg/zone/chat/ChatOnRemoveModeratorFromRoom.java create mode 100644 src/network/packets/swg/zone/chat/ChatRemoveModeratorFromRoom.java diff --git a/src/network/PacketType.java b/src/network/PacketType.java index 1fef585c6..657c64edd 100644 --- a/src/network/PacketType.java +++ b/src/network/PacketType.java @@ -138,6 +138,8 @@ public enum PacketType { CHAT_KICK_AVATAR_FROM_ROOM (ChatKickAvatarFromRoom.CRC, ChatKickAvatarFromRoom.class), CHAT_BAN_AVATAR_FROM_ROOM (ChatBanAvatarFromRoom.CRC, ChatBanAvatarFromRoom.class), CHAT_UNBAN_AVATAR_FROM_ROOM (ChatUnbanAvatarFromRoom.CRC, ChatUnbanAvatarFromRoom.class), + CHAT_ADD_MODERATOR_TO_ROOM (ChatAddModeratorToRoom.CRC, ChatAddModeratorToRoom.class), + CHAT_REMOVE_MODERATOR_FROM_ROOM (ChatRemoveModeratorFromRoom.CRC, ChatRemoveModeratorFromRoom.class), CON_GENERIC_MESSAGE (ConGenericMessage.CRC, ConGenericMessage.class), VOICE_CHAT_STATUS (VoiceChatStatus.CRC, VoiceChatStatus.class), diff --git a/src/network/packets/swg/zone/chat/ChatAddModeratorToRoom.java b/src/network/packets/swg/zone/chat/ChatAddModeratorToRoom.java new file mode 100644 index 000000000..cecc2b43a --- /dev/null +++ b/src/network/packets/swg/zone/chat/ChatAddModeratorToRoom.java @@ -0,0 +1,76 @@ +/******************************************************************************* + * Copyright (c) 2015 /// Project SWG /// www.projectswg.com + * + * ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on + * July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. + * Our goal is to create an emulator which will provide a server for players to + * continue playing a game similar to the one they used to play. We are basing + * it on the final publish of the game prior to end-game events. + * + * This file is part of Holocore. + * + * -------------------------------------------------------------------------------- + * + * Holocore is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * Holocore is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Holocore. If not, see + ******************************************************************************/ + +package network.packets.swg.zone.chat; + +import network.packets.swg.SWGPacket; +import resources.chat.ChatAvatar; + +import java.nio.ByteBuffer; + +/** + * @author Waverunner + */ +public class ChatAddModeratorToRoom extends SWGPacket { + public static final int CRC = getCrc("ChatAddModeratorToRoom"); + + private ChatAvatar avatar; + private String room; + private int sequence; + + @Override + public void decode(ByteBuffer data) { + if (!super.decode(data, CRC)) + return; + avatar = getEncodable(data, ChatAvatar.class); + room = getAscii(data); + sequence = getInt(data); + } + + @Override + public ByteBuffer encode() { + ByteBuffer bb = ByteBuffer.allocate(12 + room.length() + avatar.encode().length); + addShort(bb, 4); + addInt(bb, CRC); + addEncodable(bb, avatar); + addAscii(bb, room); + addInt(bb, sequence); + return bb; + } + + public ChatAvatar getAvatar() { + return avatar; + } + + public String getRoom() { + return room; + } + + public int getSequence() { + return sequence; + } +} diff --git a/src/network/packets/swg/zone/chat/ChatOnAddModeratorToRoom.java b/src/network/packets/swg/zone/chat/ChatOnAddModeratorToRoom.java new file mode 100644 index 000000000..620c7cfff --- /dev/null +++ b/src/network/packets/swg/zone/chat/ChatOnAddModeratorToRoom.java @@ -0,0 +1,78 @@ +/******************************************************************************* + * Copyright (c) 2015 /// Project SWG /// www.projectswg.com + * + * ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on + * July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. + * Our goal is to create an emulator which will provide a server for players to + * continue playing a game similar to the one they used to play. We are basing + * it on the final publish of the game prior to end-game events. + * + * This file is part of Holocore. + * + * -------------------------------------------------------------------------------- + * + * Holocore is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * Holocore is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Holocore. If not, see + ******************************************************************************/ + +package network.packets.swg.zone.chat; + +import network.packets.swg.SWGPacket; +import resources.chat.ChatAvatar; + +import java.nio.ByteBuffer; + +/** + * @author Waverunner + */ +public class ChatOnAddModeratorToRoom extends SWGPacket { + public static final int CRC = getCrc("ChatOnAddModeratorToRoom"); + + private ChatAvatar target; + private ChatAvatar moderator; + private int result; + private String room; + private int sequence; + + public ChatOnAddModeratorToRoom(ChatAvatar target, ChatAvatar moderator, int result, String room, int sequence) { + this.target = target; + this.moderator = moderator; + this.result = result; + this.room = room; + this.sequence = sequence; + } + + @Override + public void decode(ByteBuffer data) { + if (!super.decode(data, CRC)) + return; + target = getEncodable(data, ChatAvatar.class); + moderator = getEncodable(data, ChatAvatar.class); + result = getInt(data); + room = getAscii(data); + sequence = getInt(data); + } + + @Override + public ByteBuffer encode() { + ByteBuffer bb = ByteBuffer.allocate(16 + target.encode().length + moderator.encode().length + room.length()); + addShort(bb, 1); + addInt(bb, CRC); + addEncodable(bb, target); + addEncodable(bb, moderator); + addInt(bb, result); + addAscii(bb, room); + addInt(bb, sequence); + return bb; + } +} diff --git a/src/network/packets/swg/zone/chat/ChatOnRemoveModeratorFromRoom.java b/src/network/packets/swg/zone/chat/ChatOnRemoveModeratorFromRoom.java new file mode 100644 index 000000000..5d559b9ab --- /dev/null +++ b/src/network/packets/swg/zone/chat/ChatOnRemoveModeratorFromRoom.java @@ -0,0 +1,78 @@ +/******************************************************************************* + * Copyright (c) 2015 /// Project SWG /// www.projectswg.com + * + * ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on + * July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. + * Our goal is to create an emulator which will provide a server for players to + * continue playing a game similar to the one they used to play. We are basing + * it on the final publish of the game prior to end-game events. + * + * This file is part of Holocore. + * + * -------------------------------------------------------------------------------- + * + * Holocore is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * Holocore is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Holocore. If not, see + ******************************************************************************/ + +package network.packets.swg.zone.chat; + +import network.packets.swg.SWGPacket; +import resources.chat.ChatAvatar; + +import java.nio.ByteBuffer; + +/** + * @author Waverunner + */ +public class ChatOnRemoveModeratorFromRoom extends SWGPacket { + public static final int CRC = getCrc("ChatOnRemoveModeratorFromRoom"); + + private ChatAvatar target; + private ChatAvatar moderator; + private int result; + private String room; + private int sequence; + + public ChatOnRemoveModeratorFromRoom(ChatAvatar target, ChatAvatar moderator, int result, String room, int sequence) { + this.target = target; + this.moderator = moderator; + this.result = result; + this.room = room; + this.sequence = sequence; + } + + @Override + public void decode(ByteBuffer data) { + if (!super.decode(data, CRC)) + return; + target = getEncodable(data, ChatAvatar.class); + moderator = getEncodable(data, ChatAvatar.class); + result = getInt(data); + room = getAscii(data); + sequence = getInt(data); + } + + @Override + public ByteBuffer encode() { + ByteBuffer bb = ByteBuffer.allocate(16 + target.encode().length + moderator.encode().length + room.length()); + addShort(bb, 1); + addInt(bb, CRC); + addEncodable(bb, target); + addEncodable(bb, moderator); + addInt(bb, result); + addAscii(bb, room); + addInt(bb, sequence); + return bb; + } +} diff --git a/src/network/packets/swg/zone/chat/ChatRemoveModeratorFromRoom.java b/src/network/packets/swg/zone/chat/ChatRemoveModeratorFromRoom.java new file mode 100644 index 000000000..25204eb32 --- /dev/null +++ b/src/network/packets/swg/zone/chat/ChatRemoveModeratorFromRoom.java @@ -0,0 +1,76 @@ +/******************************************************************************* + * Copyright (c) 2015 /// Project SWG /// www.projectswg.com + * + * ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on + * July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. + * Our goal is to create an emulator which will provide a server for players to + * continue playing a game similar to the one they used to play. We are basing + * it on the final publish of the game prior to end-game events. + * + * This file is part of Holocore. + * + * -------------------------------------------------------------------------------- + * + * Holocore is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * Holocore is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Holocore. If not, see + ******************************************************************************/ + +package network.packets.swg.zone.chat; + +import network.packets.swg.SWGPacket; +import resources.chat.ChatAvatar; + +import java.nio.ByteBuffer; + +/** + * @author Waverunner + */ +public class ChatRemoveModeratorFromRoom extends SWGPacket { + public static final int CRC = getCrc("ChatRemoveModeratorFromRoom"); + + private ChatAvatar avatar; + private String room; + private int sequence; + + @Override + public void decode(ByteBuffer data) { + if (!super.decode(data, CRC)) + return; + avatar = getEncodable(data, ChatAvatar.class); + room = getAscii(data); + sequence = getInt(data); + } + + @Override + public ByteBuffer encode() { + ByteBuffer bb = ByteBuffer.allocate(12 + room.length() + avatar.encode().length); + addShort(bb, 4); + addInt(bb, CRC); + addEncodable(bb, avatar); + addAscii(bb, room); + addInt(bb, sequence); + return bb; + } + + public ChatAvatar getAvatar() { + return avatar; + } + + public String getRoom() { + return room; + } + + public int getSequence() { + return sequence; + } +} diff --git a/src/resources/chat/ChatResult.java b/src/resources/chat/ChatResult.java index 764dfaede..fa237e24e 100644 --- a/src/resources/chat/ChatResult.java +++ b/src/resources/chat/ChatResult.java @@ -36,7 +36,7 @@ public enum ChatResult { TARGET_AVATAR_DOESNT_EXIST(4), ROOM_INVALID_ID(5), ROOM_INVALID_NAME(6), - ROOM_NOT_MODERATOR(9), + CUSTOM_FAILURE(9), ROOM_AVATAR_BANNED(12), ROOM_PRIVATE(13), ROOM_AVATAR_NO_PERMISSION(16), diff --git a/src/resources/chat/ChatRoom.java b/src/resources/chat/ChatRoom.java index 948d3ce33..27908bf34 100644 --- a/src/resources/chat/ChatRoom.java +++ b/src/resources/chat/ChatRoom.java @@ -54,7 +54,7 @@ public class ChatRoom implements Encodable, Serializable { private String title; private List moderators; private List invited; - private boolean muted; // No one but moderators can talk + private boolean moderated; // No one but moderators can talk private List banned; // Members are only actually apart of a room when they're "in the room", so we don't need to save this info // as each player will automatically re-join the room based on their joined channels list @@ -129,12 +129,12 @@ public class ChatRoom implements Encodable, Serializable { return invited; } - public boolean isMuted() { - return muted; + public boolean isModerated() { + return moderated; } - public void setMuted(boolean muted) { - this.muted = muted; + public void setModerated(boolean moderated) { + this.moderated = moderated; } public List getMembers() { @@ -173,8 +173,8 @@ public class ChatRoom implements Encodable, Serializable { if (banned.contains(avatar)) return ChatResult.ROOM_AVATAR_BANNED; - if (muted && !moderators.contains(avatar)) - return ChatResult.ROOM_NOT_MODERATOR; + if (moderated && !moderators.contains(avatar)) + return ChatResult.CUSTOM_FAILURE; return ChatResult.SUCCESS; } @@ -210,7 +210,7 @@ public class ChatRoom implements Encodable, Serializable { public void decode(ByteBuffer data) { id = Packet.getInt(data); type = Packet.getInt(data); - muted = Packet.getBoolean(data); + moderated = Packet.getBoolean(data); path = Packet.getAscii(data); owner = Packet.getEncodable(data, ChatAvatar.class); creator = Packet.getEncodable(data, ChatAvatar.class); @@ -237,7 +237,7 @@ public class ChatRoom implements Encodable, Serializable { ByteBuffer bb = ByteBuffer.allocate(23 + path.length() + (title.length() * 2) + avatarIdSize); Packet.addInt(bb, id); Packet.addInt(bb, type); - Packet.addBoolean(bb, muted); + Packet.addBoolean(bb, moderated); Packet.addAscii(bb, path); Packet.addEncodable(bb, owner); Packet.addEncodable(bb, creator); @@ -254,6 +254,6 @@ public class ChatRoom implements Encodable, Serializable { @Override public String toString() { return "ChatRoom[id=" + id + ", type=" + type + ", path='" + path + "', title='" + title + '\'' + - ", creator=" + creator + ", muted=" + muted + ", isPublic=" + isPublic() + "]"; + ", creator=" + creator + ", moderated=" + moderated + ", isPublic=" + isPublic() + "]"; } } diff --git a/src/services/chat/ChatRoomService.java b/src/services/chat/ChatRoomService.java index e5e97cfa8..e46964dba 100644 --- a/src/services/chat/ChatRoomService.java +++ b/src/services/chat/ChatRoomService.java @@ -32,12 +32,14 @@ import intents.chat.ChatRoomUpdateIntent; import intents.network.GalacticPacketIntent; import network.packets.Packet; import network.packets.swg.SWGPacket; +import network.packets.swg.zone.chat.ChatAddModeratorToRoom; import network.packets.swg.zone.chat.ChatBanAvatarFromRoom; import network.packets.swg.zone.chat.ChatCreateRoom; import network.packets.swg.zone.chat.ChatDestroyRoom; import network.packets.swg.zone.chat.ChatEnterRoomById; import network.packets.swg.zone.chat.ChatInviteAvatarToRoom; import network.packets.swg.zone.chat.ChatKickAvatarFromRoom; +import network.packets.swg.zone.chat.ChatOnAddModeratorToRoom; import network.packets.swg.zone.chat.ChatOnBanAvatarFromRoom; import network.packets.swg.zone.chat.ChatOnCreateRoom; import network.packets.swg.zone.chat.ChatOnDestroyRoom; @@ -46,12 +48,14 @@ import network.packets.swg.zone.chat.ChatOnInviteToRoom; import network.packets.swg.zone.chat.ChatOnKickAvatarFromRoom; import network.packets.swg.zone.chat.ChatOnLeaveRoom; import network.packets.swg.zone.chat.ChatOnReceiveRoomInvitation; +import network.packets.swg.zone.chat.ChatOnRemoveModeratorFromRoom; import network.packets.swg.zone.chat.ChatOnSendRoomMessage; import network.packets.swg.zone.chat.ChatOnUnbanAvatarFromRoom; import network.packets.swg.zone.chat.ChatOnUninviteFromRoom; import network.packets.swg.zone.chat.ChatQueryRoom; import network.packets.swg.zone.chat.ChatQueryRoomResults; import network.packets.swg.zone.chat.ChatRemoveAvatarFromRoom; +import network.packets.swg.zone.chat.ChatRemoveModeratorFromRoom; import network.packets.swg.zone.chat.ChatRequestRoomList; import network.packets.swg.zone.chat.ChatSendToRoom; import network.packets.swg.zone.chat.ChatUnbanAvatarFromRoom; @@ -162,6 +166,13 @@ public class ChatRoomService extends Service { break; case CHAT_UNBAN_AVATAR_FROM_ROOM: if (p instanceof ChatUnbanAvatarFromRoom) handleChatUnbanAvatarFromRoom(player, (ChatUnbanAvatarFromRoom) p); + break; + case CHAT_ADD_MODERATOR_TO_ROOM: + if (p instanceof ChatAddModeratorToRoom) handleChatAddModeratorToRoom(player, (ChatAddModeratorToRoom) p); + break; + case CHAT_REMOVE_MODERATOR_FROM_ROOM: + if (p instanceof ChatRemoveModeratorFromRoom) handleChatRemoveModeratorFromRoom(player, (ChatRemoveModeratorFromRoom) p); + break; default: break; } } @@ -176,6 +187,79 @@ public class ChatRoomService extends Service { /* Chat Rooms */ + private void handleChatRemoveModeratorFromRoom(Player player, ChatRemoveModeratorFromRoom p) { + String path = p.getRoom(); + ChatAvatar target = p.getAvatar(); + int sequence = p.getSequence(); + + ChatRoom room = getRoom(path); + ChatAvatar sender = ChatAvatar.getFromPlayer(player); + + if (room == null) { + player.sendPacket(new ChatOnRemoveModeratorFromRoom(target, sender, ChatResult.ROOM_INVALID_NAME.getCode(), path, sequence)); + return; + } + + if (!room.isModerated()) { + player.sendPacket(new ChatOnRemoveModeratorFromRoom(target, sender, ChatResult.CUSTOM_FAILURE.getCode(), path, sequence)); + return; + } + + if (!room.isModerator(sender)) { + player.sendPacket(new ChatOnRemoveModeratorFromRoom(target, sender, ChatResult.ROOM_AVATAR_NO_PERMISSION.getCode(), path, sequence)); + return; + } + + if (!room.getModerators().remove(target)) { + player.sendPacket(new ChatOnRemoveModeratorFromRoom(target, sender, ChatResult.TARGET_AVATAR_DOESNT_EXIST.getCode(), path, sequence)); + return; + } + + player.sendPacket(new ChatOnRemoveModeratorFromRoom(target, sender, ChatResult.SUCCESS.getCode(), path, sequence)); + } + + private void handleChatAddModeratorToRoom(Player player, ChatAddModeratorToRoom p) { + String path = p.getRoom(); + ChatAvatar target = p.getAvatar(); + int sequence = p.getSequence(); + + ChatRoom room = getRoom(path); + ChatAvatar sender = ChatAvatar.getFromPlayer(player); + + if (room == null) { + player.sendPacket(new ChatOnAddModeratorToRoom(target, sender, ChatResult.ROOM_INVALID_NAME.getCode(), path, sequence)); + return; + } + + if (!room.isModerated()) { + player.sendPacket(new ChatOnAddModeratorToRoom(target, sender, ChatResult.CUSTOM_FAILURE.getCode(), path, sequence)); + return; + } + + if (!room.isModerator(sender)) { + player.sendPacket(new ChatOnAddModeratorToRoom(target, sender, ChatResult.ROOM_AVATAR_NO_PERMISSION.getCode(), path, sequence)); + return; + } + + Player targetPlayer = player.getPlayerManager().getPlayerByCreatureFirstName(target.getName()); + if (targetPlayer == null) { + player.sendPacket(new ChatOnAddModeratorToRoom(target, sender, ChatResult.TARGET_AVATAR_DOESNT_EXIST.getCode(), path, sequence)); + return; + } + + // Remove from ban list + if (room.getBanned().remove(target)) { + room.sendPacketToMembers(player.getPlayerManager(), new ChatOnUnbanAvatarFromRoom(path, sender, target, ChatResult.SUCCESS.getCode(), 0)); + } + + if (!room.getModerators().add(target)) { + player.sendPacket(new ChatOnAddModeratorToRoom(target, sender, ChatResult.NONE.getCode(), path, sequence)); + return; + } + + player.sendPacket(new ChatOnAddModeratorToRoom(target, sender, ChatResult.SUCCESS.getCode(), path, sequence)); + } + private void handleChatUnbanAvatarFromRoom(Player player, ChatUnbanAvatarFromRoom p) { String path = p.getRoom(); ChatAvatar target = p.getAvatar(); @@ -269,11 +353,6 @@ public class ChatRoomService extends Service { return; } - if (room.isMember(target)) { - player.sendPacket(new ChatOnKickAvatarFromRoom(target, sender, ChatResult.NONE.getCode(), path)); - return; - } - room.sendPacketToMembers(player.getPlayerManager(), new ChatOnKickAvatarFromRoom(target, sender, ChatResult.SUCCESS.getCode(), path)); } @@ -290,7 +369,7 @@ public class ChatRoomService extends Service { } if (room.isPublic()) { - player.sendPacket(new ChatOnUninviteFromRoom(path, sender, invitee, ChatResult.NONE.getCode(), p.getSequence())); + player.sendPacket(new ChatOnUninviteFromRoom(path, sender, invitee, ChatResult.CUSTOM_FAILURE.getCode(), p.getSequence())); return; } @@ -318,7 +397,7 @@ public class ChatRoomService extends Service { } if (room.isPublic()) { - player.sendPacket(new ChatOnInviteToRoom(path, sender, p.getAvatar(), ChatResult.NONE.getCode())); + player.sendPacket(new ChatOnInviteToRoom(path, sender, p.getAvatar(), ChatResult.CUSTOM_FAILURE.getCode())); return; } @@ -369,7 +448,7 @@ public class ChatRoomService extends Service { if (result == ChatResult.SUCCESS) { room = createRoom(ChatAvatar.getFromPlayer(player), p.isPublic(), path, title); - room.setMuted(p.isModerated()); + room.setModerated(p.isModerated()); } player.sendPacket(new ChatOnCreateRoom(result.getCode(), room, p.getSequence())); From 08d938d4349132cd84df975990984a342fd6c872 Mon Sep 17 00:00:00 2001 From: Obique PSWG Date: Sat, 1 Aug 2015 11:46:33 -0500 Subject: [PATCH 03/25] Fixed issue where sometimes the server won't let you zone in --- src/services/player/ZoneManager.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/services/player/ZoneManager.java b/src/services/player/ZoneManager.java index d33b64eea..a0e5ce16f 100644 --- a/src/services/player/ZoneManager.java +++ b/src/services/player/ZoneManager.java @@ -190,6 +190,7 @@ public class ZoneManager extends Manager { sendPacket(player, new ChatOnConnectAvatar()); sendPacket(player, new CmdStartScene(false, objId, race, l, time)); sendPacket(player, new UpdatePvpStatusMessage(creature.getPvpType(), creature.getPvpFactionId(), creature.getObjectId())); + flushPackets(); } private void initPlayerBeforeZoneIn(Player player, CreatureObject creatureObj, PlayerObject playerObj) { From 4e9d83702d6b7770ae387fefe92d23ac874e3ed9 Mon Sep 17 00:00:00 2001 From: Obique PSWG Date: Sat, 1 Aug 2015 12:40:07 -0500 Subject: [PATCH 04/25] Removed memory logging from ProjectSWG --- src/main/ProjectSWG.java | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/src/main/ProjectSWG.java b/src/main/ProjectSWG.java index e0ae16ea3..2510a3b07 100644 --- a/src/main/ProjectSWG.java +++ b/src/main/ProjectSWG.java @@ -31,13 +31,10 @@ import intents.server.ServerStatusIntent; import resources.Galaxy.GalaxyStatus; import resources.control.IntentManager; import resources.control.ServerStatus; -import resources.server_info.Log; import services.CoreManager; public class ProjectSWG { - private static final String [] ENDINGS = {"B", "KB", "MB", "GB"}; - private static ProjectSWG server; private final Thread mainThread; private CoreManager manager; @@ -135,7 +132,6 @@ public class ProjectSWG { private void loop() { setStatus((manager.getGalaxyStatus() == GalaxyStatus.UP) ? ServerStatus.OPEN : ServerStatus.LOCKED); - long iter = 0; while (!shutdownRequested && !manager.isShutdownRequested() && manager.isOperational()) { manager.flushPackets(); // Sends any packets that weren't sent try { @@ -143,25 +139,9 @@ public class ProjectSWG { } catch (InterruptedException e) { throw new CoreException("Main Thread Interrupted."); } - iter++; - if (iter % 20 == 0) { - final Runtime r = Runtime.getRuntime(); - Log.i("ProjectSWG", "Memory Consumption: %s", getMemory((r.totalMemory()-r.freeMemory()))); - } } } - private String getMemory(long bytes) { - double val = bytes; - int iters = 0; - while (val >= 1024) { - val /= 1024; - iters++; - } - val = ((int) (val * 1E5)) / 1E5; - return val + ENDINGS[iters]; - } - private void stop() { if (manager == null || status == ServerStatus.OFFLINE) return; From bc0b07e412b8aec92c434e75672ff149d2ccd5f9 Mon Sep 17 00:00:00 2001 From: Obique PSWG Date: Sat, 1 Aug 2015 12:47:23 -0500 Subject: [PATCH 05/25] Added some ack/ooo logging to outbound network handler --- src/network/OutboundNetworkHandler.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/network/OutboundNetworkHandler.java b/src/network/OutboundNetworkHandler.java index 97788d1d3..68044617c 100644 --- a/src/network/OutboundNetworkHandler.java +++ b/src/network/OutboundNetworkHandler.java @@ -32,6 +32,7 @@ import java.util.LinkedList; import java.util.Queue; import resources.SortedLinkedList; +import resources.server_info.Log; import network.encryption.Encryption; import network.packets.Packet; import network.packets.soe.DataChannelA; @@ -82,6 +83,7 @@ public class OutboundNetworkHandler { else break; } + Log.d("OutboundNetworkHandler", "Ack: %d Remaining: %d", sequence, sequenced.size()); } } @@ -95,6 +97,7 @@ public class OutboundNetworkHandler { else break; } + Log.d("OutboundNetworkHandler", "Out Of Order: %d", sequence); } } From 0cc6d9d226fc30d9895928bc7f2a643c51a72714 Mon Sep 17 00:00:00 2001 From: Obique PSWG Date: Sat, 1 Aug 2015 16:40:02 -0500 Subject: [PATCH 06/25] Removed ack/ooo logging from previous commit --- src/network/OutboundNetworkHandler.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/network/OutboundNetworkHandler.java b/src/network/OutboundNetworkHandler.java index 68044617c..97788d1d3 100644 --- a/src/network/OutboundNetworkHandler.java +++ b/src/network/OutboundNetworkHandler.java @@ -32,7 +32,6 @@ import java.util.LinkedList; import java.util.Queue; import resources.SortedLinkedList; -import resources.server_info.Log; import network.encryption.Encryption; import network.packets.Packet; import network.packets.soe.DataChannelA; @@ -83,7 +82,6 @@ public class OutboundNetworkHandler { else break; } - Log.d("OutboundNetworkHandler", "Ack: %d Remaining: %d", sequence, sequenced.size()); } } @@ -97,7 +95,6 @@ public class OutboundNetworkHandler { else break; } - Log.d("OutboundNetworkHandler", "Out Of Order: %d", sequence); } } From 9f1e8ef1972d23867bc1b3fb790d1cea5fe58022 Mon Sep 17 00:00:00 2001 From: Obique PSWG Date: Sat, 1 Aug 2015 16:40:25 -0500 Subject: [PATCH 07/25] Added a catch to make sure encryption will not throw anything to cause a crash --- src/network/encryption/Encryption.java | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/network/encryption/Encryption.java b/src/network/encryption/Encryption.java index 73fe79230..22a1774b5 100644 --- a/src/network/encryption/Encryption.java +++ b/src/network/encryption/Encryption.java @@ -39,11 +39,21 @@ public class Encryption { } public static byte [] encode(byte [] input, int crc) { - return assembleMessage(input, crc); + try { + return assembleMessage(input, crc); + } catch (Throwable t) { + t.printStackTrace(); + return new byte[0]; + } } public static byte [] decode(byte [] input, int crc) { - return disassemble(input, crc); + try { + return disassemble(input, crc); + } catch (Throwable t) { + t.printStackTrace(); + return new byte[0]; + } } private static byte [] disassemble(byte [] data, int crcSeed) { From cf81b4a2bdd5ff3789ce14388684dab67f1ef69e Mon Sep 17 00:00:00 2001 From: Obique PSWG Date: Sat, 1 Aug 2015 16:41:24 -0500 Subject: [PATCH 08/25] Put the packet processing in a separate thread to make the UDPServer respond to new packets faster --- .../network/NetworkClientManager.java | 44 ++++++++++++++++++- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/src/services/network/NetworkClientManager.java b/src/services/network/NetworkClientManager.java index 548ef21d1..00b773962 100644 --- a/src/services/network/NetworkClientManager.java +++ b/src/services/network/NetworkClientManager.java @@ -35,9 +35,13 @@ import java.net.InetAddress; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.HashMap; +import java.util.LinkedList; import java.util.List; import java.util.Map; +import java.util.Queue; import java.util.Random; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; import network.NetworkClient; import network.PacketReceiver; @@ -57,15 +61,30 @@ public class NetworkClientManager extends Manager implements PacketReceiver { private final Map > clients; private final Map networkClients; + private final Queue receivedPackets; + private final ExecutorService packetProcessor; private final Random crcGenerator; private final PacketSender packetSender; + private final Runnable processPacketRunnable; private long networkId; public NetworkClientManager(PacketSender packetSender) { this.packetSender = packetSender; clients = new HashMap>(); networkClients = new HashMap(); + receivedPackets = new LinkedList<>(); + packetProcessor = Executors.newCachedThreadPool(); crcGenerator = new Random(); + processPacketRunnable = new Runnable() { + public void run() { + synchronized (receivedPackets) { + ReceivedPacket recv = receivedPackets.poll(); + if (recv == null) + return; + handlePacket(recv.getType(), recv.getPacket()); + } + } + }; networkId = 0; } @@ -87,9 +106,12 @@ public class NetworkClientManager extends Manager implements PacketReceiver { @Override public void receivePacket(ServerType type, UDPPacket packet) { - handlePacket(type, packet); + synchronized (receivedPackets) { + receivedPackets.add(new ReceivedPacket(type, packet)); + } + packetProcessor.submit(processPacketRunnable); } - + @Override public void onIntentReceived(Intent i) { if (i instanceof OutboundPacketIntent) { @@ -276,4 +298,22 @@ public class NetworkClientManager extends Manager implements PacketReceiver { return false; } + private static class ReceivedPacket { + private final ServerType type; + private final UDPPacket packet; + + public ReceivedPacket(ServerType type, UDPPacket packet) { + this.type = type; + this.packet = packet; + } + + public ServerType getType() { + return type; + } + + public UDPPacket getPacket() { + return packet; + } + } + } From 3cf6d1a848671fe6b42d9a2ac59a34ad74fd06f8 Mon Sep 17 00:00:00 2001 From: Obique PSWG Date: Sun, 2 Aug 2015 01:14:48 -0500 Subject: [PATCH 09/25] Optimized OutboundNetworkHandler to not re-encrypt old OOO data --- src/network/OutboundNetworkHandler.java | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/network/OutboundNetworkHandler.java b/src/network/OutboundNetworkHandler.java index 97788d1d3..70ca0bf2a 100644 --- a/src/network/OutboundNetworkHandler.java +++ b/src/network/OutboundNetworkHandler.java @@ -91,7 +91,7 @@ public class OutboundNetworkHandler { while (it.hasNext()) { SequencedPacket sp = it.next(); if (sp.getSequence() <= sequence) - pushAssembledEncrypted(sp.getPacket()); + pushAssembledUnencrypted(sp.getPacket()); // Pre-encrypted before putting into list else break; } @@ -110,11 +110,12 @@ public class OutboundNetworkHandler { } } - private void pushAssembledEncrypted(byte [] data) { + private byte [] pushAssembledEncrypted(byte [] data) { data = Encryption.encode(data, crc); synchronized (assembleQueue) { assembleQueue.add(data); } + return data; } private void pushAssembledUnencrypted(byte [] data) { @@ -164,8 +165,8 @@ public class OutboundNetworkHandler { int lastSeq = updateSequencesMulti((short)(sendSequence+count), m); for (Fragmented f : Fragmented.encode(m.encode(), sendSequence)) { byte [] encoded = f.encode().array(); - pushSequencedPacket(f.getSequence(), encoded); - pushAssembledEncrypted(encoded); + byte [] encrypted = pushAssembledEncrypted(encoded); + pushSequencedPacket(f.getSequence(), encrypted); } sendSequence = (short) (lastSeq + 1); return count; @@ -183,16 +184,16 @@ public class OutboundNetworkHandler { int lastSeq = updateSequenceData((short)(sendSequence+count), d); for (Fragmented f : Fragmented.encode(d.encode(), sendSequence)) { byte [] encoded = f.encode().array(); - pushSequencedPacket(f.getSequence(), encoded); - pushAssembledEncrypted(encoded); + byte [] encrypted = pushAssembledEncrypted(encoded); + pushSequencedPacket(f.getSequence(), encrypted); } sendSequence = (short) lastSeq; return count; } else { d.setSequence(sendSequence++); byte [] encoded = d.encode().array(); - pushSequencedPacket(d.getSequence(), encoded); - pushAssembledEncrypted(encoded); + byte [] encrypted = pushAssembledEncrypted(encoded); + pushSequencedPacket(d.getSequence(), encrypted); return 1; } } From 7daa5aa80a3bd3af8b7d6a2e69d3551fb8b18085 Mon Sep 17 00:00:00 2001 From: Obique PSWG Date: Sun, 2 Aug 2015 01:40:39 -0500 Subject: [PATCH 10/25] Fixed memory leak by cleaning up the compressed data after compressing --- src/network/encryption/Encryption.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/network/encryption/Encryption.java b/src/network/encryption/Encryption.java index 22a1774b5..21c48b0b4 100644 --- a/src/network/encryption/Encryption.java +++ b/src/network/encryption/Encryption.java @@ -103,6 +103,7 @@ public class Encryption { compressor.setInput(data, 2, data.length - 2); compressor.finish(); int length = compressor.deflate(result); + compressor.end(); if (length < data.length) { ByteBuffer bb = ByteBuffer.allocate(length+3); bb.put(data[0]).put(data[1]); From 27dc019cc1b3c1f6704c7757831ae5f29963e69a Mon Sep 17 00:00:00 2001 From: Obique PSWG Date: Sun, 2 Aug 2015 02:40:32 -0500 Subject: [PATCH 11/25] Removed UpdatePvpStatus message from zone in, should be sent with CREO baselines --- src/services/player/ZoneManager.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/services/player/ZoneManager.java b/src/services/player/ZoneManager.java index a0e5ce16f..d85fb911f 100644 --- a/src/services/player/ZoneManager.java +++ b/src/services/player/ZoneManager.java @@ -189,7 +189,6 @@ public class ZoneManager extends Manager { sendPacket(player, new ParametersMessage()); sendPacket(player, new ChatOnConnectAvatar()); sendPacket(player, new CmdStartScene(false, objId, race, l, time)); - sendPacket(player, new UpdatePvpStatusMessage(creature.getPvpType(), creature.getPvpFactionId(), creature.getObjectId())); flushPackets(); } From 74f1ac66f4163c98d658e32667231cd872735287 Mon Sep 17 00:00:00 2001 From: Obique PSWG Date: Sun, 2 Aug 2015 02:45:17 -0500 Subject: [PATCH 12/25] Moved player creature creation from ZoneManager to ObjectManager upon every zone --- src/services/objects/ObjectManager.java | 2 ++ src/services/player/ZoneManager.java | 2 -- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/services/objects/ObjectManager.java b/src/services/objects/ObjectManager.java index 6d1bd2196..a15ff7ccd 100644 --- a/src/services/objects/ObjectManager.java +++ b/src/services/objects/ObjectManager.java @@ -260,6 +260,8 @@ public class ObjectManager extends Manager { case PE_ZONE_IN: p.getCreatureObject().clearAware(); objectAwareness.update(p.getCreatureObject()); + if (p.getCreatureObject().getParent() == null) + p.getCreatureObject().createObject(p); break; default: break; diff --git a/src/services/player/ZoneManager.java b/src/services/player/ZoneManager.java index d85fb911f..99d6c66e2 100644 --- a/src/services/player/ZoneManager.java +++ b/src/services/player/ZoneManager.java @@ -136,8 +136,6 @@ public class ZoneManager extends Manager { sendZonePackets(player, creature); initPlayerBeforeZoneIn(player, creature, playerObj); - if (creature.getParent() == null) - creature.createObject(player); System.out.printf("[%s] %s is zoning in%n", player.getUsername(), player.getCharacterName()); Log.i("ObjectManager", "Zoning in %s with character %s", player.getUsername(), player.getCharacterName()); sendCommitHistory(player); From 04c486bb8b0b257e02799b30778d2eb98a762857 Mon Sep 17 00:00:00 2001 From: Obique PSWG Date: Sun, 2 Aug 2015 11:00:13 -0500 Subject: [PATCH 13/25] Fixed Encryption to always clean up the compression objects --- src/network/encryption/Encryption.java | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/network/encryption/Encryption.java b/src/network/encryption/Encryption.java index 21c48b0b4..7c7334b96 100644 --- a/src/network/encryption/Encryption.java +++ b/src/network/encryption/Encryption.java @@ -102,8 +102,12 @@ public class Encryption { Deflater compressor = new Deflater(); compressor.setInput(data, 2, data.length - 2); compressor.finish(); - int length = compressor.deflate(result); - compressor.end(); + int length = 0; + try { + length = compressor.deflate(result); + } finally { + compressor.end(); + } if (length < data.length) { ByteBuffer bb = ByteBuffer.allocate(length+3); bb.put(data[0]).put(data[1]); @@ -143,11 +147,12 @@ public class Encryption { try { int length = decompressor.inflate(result); - decompressor.end(); return length; } catch (DataFormatException e) { System.err.println("Failed to decompress packet. "+e.getClass().getSimpleName()+" Message: " + e.getMessage()); return -1; + } finally { + decompressor.end(); } } From 26faf2777162e13da7ac7dc06c2fc64d5b78af8c Mon Sep 17 00:00:00 2001 From: Obique PSWG Date: Sun, 2 Aug 2015 11:23:58 -0500 Subject: [PATCH 14/25] Fixed warning in imports --- src/services/player/ZoneManager.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/services/player/ZoneManager.java b/src/services/player/ZoneManager.java index 99d6c66e2..22e59a7ff 100644 --- a/src/services/player/ZoneManager.java +++ b/src/services/player/ZoneManager.java @@ -46,7 +46,6 @@ import network.packets.swg.zone.RequestGalaxyLoopTimes; import network.packets.swg.zone.SetWaypointColor; import network.packets.swg.zone.ShowBackpack; import network.packets.swg.zone.ShowHelmet; -import network.packets.swg.zone.UpdatePvpStatusMessage; import network.packets.swg.zone.chat.ChatOnConnectAvatar; import network.packets.swg.zone.chat.ChatSystemMessage; import network.packets.swg.zone.chat.VoiceChatStatus; From 97906a004ccfb8ab9086e6f84d51d94e56fe35e0 Mon Sep 17 00:00:00 2001 From: Obique PSWG Date: Sun, 2 Aug 2015 14:29:20 -0500 Subject: [PATCH 15/25] Now cleans up some lists and queues in the outbound network handler upon reset --- src/network/OutboundNetworkHandler.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/network/OutboundNetworkHandler.java b/src/network/OutboundNetworkHandler.java index 70ca0bf2a..31bbf1759 100644 --- a/src/network/OutboundNetworkHandler.java +++ b/src/network/OutboundNetworkHandler.java @@ -56,6 +56,8 @@ public class OutboundNetworkHandler { } public synchronized void reset() { + sequenced.clear(); + assembleQueue.clear(); sendSequence = 0; crc = 0; } From 8e8148c863b4bd3e5537f04f7d49b5060a0486ca Mon Sep 17 00:00:00 2001 From: Ziggy Date: Sun, 2 Aug 2015 22:26:37 +0200 Subject: [PATCH 16/25] Revert "SWGMap is now compatible with non-String value types" This reverts commit 045c1ddc10f3a69b7f8d4ec572ed3eed207b3b96. --- src/resources/collections/SWGMap.java | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/resources/collections/SWGMap.java b/src/resources/collections/SWGMap.java index a1f18bfb4..1c9275075 100644 --- a/src/resources/collections/SWGMap.java +++ b/src/resources/collections/SWGMap.java @@ -251,15 +251,8 @@ public class SWGMap extends AbstractMap implements Encodable, Serial private void addData(Object key, Object value, byte update) { byte[] encodedKey = Encoder.encode(key, strType); - byte[] encodedValue; - byte[] encodedData; - - if(value instanceof String) - encodedValue = Encoder.encode(value, strType); - else - encodedValue = Encoder.encode(value); - - encodedData = new byte[encodedKey.length + encodedValue.length]; + byte[] encodedValue = Encoder.encode(value, strType); + byte[] encodedData = new byte[encodedKey.length + encodedValue.length]; System.arraycopy(encodedKey, 0, encodedData, 0, encodedKey.length); System.arraycopy(encodedValue, 0, encodedData, encodedKey.length, encodedValue.length); From 91a36ad42de6cfe53def3bf24c3e5170fa8f9af6 Mon Sep 17 00:00:00 2001 From: Ziggy Date: Sun, 2 Aug 2015 22:29:25 +0200 Subject: [PATCH 17/25] Added an instanceof check to Encoder.encode() to prevent unintended behaviour with various classes --- src/utilities/Encoder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utilities/Encoder.java b/src/utilities/Encoder.java index d273624b1..d0c27aec2 100644 --- a/src/utilities/Encoder.java +++ b/src/utilities/Encoder.java @@ -40,7 +40,7 @@ public class Encoder { } public static byte[] encode(Object object, StringType strType) { - if (strType != StringType.UNSPECIFIED) { + if (strType != StringType.UNSPECIFIED && object instanceof String) { switch (strType) { case ASCII: return encodeAscii((String) object); case UNICODE: return encodeUnicode((String) object); From 61d55c9da329cfec98b7ee731713bd495161fda3 Mon Sep 17 00:00:00 2001 From: Ziggy Date: Sun, 2 Aug 2015 23:56:00 +0200 Subject: [PATCH 18/25] Implemented setPlayerAppearance and revertPlayerAppearance --- .../callbacks/PlayerAppearanceCallback.java | 22 +++++++++++++++++++ .../callbacks/RevertAppearanceCallback.java | 22 +++++++++++++++++++ src/services/commands/CommandService.java | 2 ++ 3 files changed, 46 insertions(+) create mode 100644 src/resources/commands/callbacks/PlayerAppearanceCallback.java create mode 100644 src/resources/commands/callbacks/RevertAppearanceCallback.java diff --git a/src/resources/commands/callbacks/PlayerAppearanceCallback.java b/src/resources/commands/callbacks/PlayerAppearanceCallback.java new file mode 100644 index 000000000..54a835272 --- /dev/null +++ b/src/resources/commands/callbacks/PlayerAppearanceCallback.java @@ -0,0 +1,22 @@ +package resources.commands.callbacks; + +import resources.commands.ICmdCallback; +import resources.objects.SWGObject; +import resources.objects.creature.CreatureObject; +import resources.player.Player; +import services.galaxy.GalacticManager; + +public class PlayerAppearanceCallback implements ICmdCallback { + + @Override + public void execute(GalacticManager galacticManager, Player player, + SWGObject target, String args) { + if(target instanceof CreatureObject) { + CreatureObject creatureTarget = (CreatureObject) target; + + creatureTarget.setCostume(args); + } + + } + +} diff --git a/src/resources/commands/callbacks/RevertAppearanceCallback.java b/src/resources/commands/callbacks/RevertAppearanceCallback.java new file mode 100644 index 000000000..bfa5e498d --- /dev/null +++ b/src/resources/commands/callbacks/RevertAppearanceCallback.java @@ -0,0 +1,22 @@ +package resources.commands.callbacks; + +import resources.commands.ICmdCallback; +import resources.objects.SWGObject; +import resources.objects.creature.CreatureObject; +import resources.player.Player; +import services.galaxy.GalacticManager; + +public class RevertAppearanceCallback implements ICmdCallback { + + @Override + public void execute(GalacticManager galacticManager, Player player, + SWGObject target, String args) { + if(target instanceof CreatureObject) { + CreatureObject creatureTarget = (CreatureObject) target; + + creatureTarget.setCostume(""); + } + + } + +} diff --git a/src/services/commands/CommandService.java b/src/services/commands/CommandService.java index 95937b0cf..e1f2daa28 100644 --- a/src/services/commands/CommandService.java +++ b/src/services/commands/CommandService.java @@ -172,6 +172,8 @@ public class CommandService extends Service { registerCallback("jumpServer", new JumpCmdCallback()); registerCallback("serverDestroyObject", new ServerDestroyObjectCmdCallback()); registerCallback("findFriend", new FindFriendCallback()); + registerCallback("setPlayerAppearance", new PlayerAppearanceCallback()); + registerCallback("revertPlayerAppearance", new RevertAppearanceCallback()); } private void clearCommands() { From 7fbffa8b634951db33d8af9772412a1abf771544 Mon Sep 17 00:00:00 2001 From: Waverunner Date: Sun, 2 Aug 2015 18:30:49 -0400 Subject: [PATCH 19/25] Added chat room persistence --- src/services/chat/ChatRoomService.java | 53 +++++++++++++++++++++----- 1 file changed, 43 insertions(+), 10 deletions(-) diff --git a/src/services/chat/ChatRoomService.java b/src/services/chat/ChatRoomService.java index e46964dba..1a73e5157 100644 --- a/src/services/chat/ChatRoomService.java +++ b/src/services/chat/ChatRoomService.java @@ -72,6 +72,8 @@ import resources.control.Service; import resources.objects.player.PlayerObject; import resources.player.AccessLevel; import resources.player.Player; +import resources.server_info.CachedObjectDatabase; +import resources.server_info.ObjectDatabase; import services.player.PlayerManager; import java.util.ArrayList; @@ -89,16 +91,24 @@ public class ChatRoomService extends Service { private Map roomMap; // Map to keep track of each player's recent message for a room to prevent duplicates from client private Map> messages; + private ObjectDatabase database; public ChatRoomService() { + database = new CachedObjectDatabase<>("odb/chat_rooms.db"); roomMap = new ConcurrentHashMap<>(); messages = new ConcurrentHashMap<>(); maxChatRoomId = 1; + + database.load(); + database.traverse((room) -> { + if (room.getId() >= maxChatRoomId) + maxChatRoomId++; + roomMap.put(room.getId(), room); + }); } @Override public boolean initialize() { - // TODO: Load up persistent channels registerForIntent(ChatRoomUpdateIntent.TYPE); registerForIntent(GalacticPacketIntent.TYPE); @@ -447,7 +457,7 @@ public class ChatRoomService extends Service { result = ChatResult.ROOM_ALREADY_EXISTS; if (result == ChatResult.SUCCESS) { - room = createRoom(ChatAvatar.getFromPlayer(player), p.isPublic(), path, title); + room = createRoom(ChatAvatar.getFromPlayer(player), p.isPublic(), path, title, true); room.setModerated(p.isModerated()); } @@ -626,19 +636,24 @@ public class ChatRoomService extends Service { public void leaveChatChannel(Player player, String path) { for (ChatRoom chatRoom : roomMap.values()) { - if (chatRoom.getPath().equals(path)) + if (chatRoom.getPath().equals(path)) { leaveChatChannel(player, chatRoom, 0); + break; + } } } + /** - * Creates a new, non-persistent, chat room with the specified address path. + * Creates a new chat room with the specified address path. If the path's parent channel doesn't exist, then a new + * chat room is created with the same passed arguments. * @param creator Room creator who will also become the owner of this room * @param isPublic Determines if the room should be publicly displayed in the channel listing * @param path Address for the channel (Ex: SWG.serverName.Imperial) * @param title Descriptive name of the chat channel (Ex: Imperial chat for this galaxy) + * @param persist If true then this channel will be saved in an {@link ObjectDatabase} * @return {@link ChatRoom} */ - public ChatRoom createRoom(ChatAvatar creator, boolean isPublic, String path, String title) { + public ChatRoom createRoom(ChatAvatar creator, boolean isPublic, String path, String title, boolean persist) { if (path.isEmpty() || path.endsWith(".")) return null; @@ -646,12 +661,15 @@ public class ChatRoomService extends Service { if (!path.startsWith(base) || path.equals(base)) return null; + if (getRoom(path) != null) + return getRoom(path); + // All paths should have parents, lets validate to make sure they exist first. Create them if they don't. int lastIndex = path.lastIndexOf("."); if (lastIndex != -1) { String parentPath = path.substring(0, lastIndex); if (getRoom(parentPath) == null) { - createRoom(creator, isPublic, parentPath, ""); + createRoom(creator, isPublic, parentPath, "", persist); } } @@ -667,9 +685,24 @@ public class ChatRoomService extends Service { room.setTitle(title); roomMap.put(id, room); + + if (persist) + database.put(id, room); return room; } + /** + * Creates a new, non-persistent, chat room with the specified address path. + * @param creator Room creator who will also become the owner of this room + * @param isPublic Determines if the room should be publicly displayed in the channel listing + * @param path Address for the channel (Ex: SWG.serverName.Imperial) + * @param title Descriptive name of the chat channel (Ex: Imperial chat for this galaxy) + * @return {@link ChatRoom} + */ + public ChatRoom createRoom(ChatAvatar creator, boolean isPublic, String path, String title) { + return createRoom(creator, isPublic, path, title, false); + } + public boolean notifyDestroyRoom(ChatAvatar destroyer, String roomPath, int sequence) { ChatRoom room = getRoom(roomPath); if (roomPath == null) @@ -714,7 +747,7 @@ public class ChatRoomService extends Service { String basePath = "SWG." + galaxy + "."; DatatableData rooms = ServerFactory.getDatatable("chat/default_rooms.iff"); - rooms.handleRows((r) -> createRoom(systemAvatar, true, basePath + rooms.getCell(r, 0), (String) rooms.getCell(r, 1))); + rooms.handleRows((r) -> createRoom(systemAvatar, true, basePath + rooms.getCell(r, 0), (String) rooms.getCell(r, 1), true)); createPlanetChannels(systemAvatar, basePath); @@ -731,9 +764,9 @@ public class ChatRoomService extends Service { DatatableData planets = ServerFactory.getDatatable("chat/planets.iff"); planets.handleRows((r) -> { String path = basePath + planets.getCell(r, 0) + "."; - createRoom(systemAvatar, true, path + "Planet", "public chat for this planet, cannot create rooms here"); - createRoom(systemAvatar, true, path + "system", "system messages for this planet, cannot create rooms here"); - createRoom(systemAvatar, true, path + "Chat", "public chat for this planet, can create rooms here"); + createRoom(systemAvatar, true, path + "Planet", "public chat for this planet, cannot create rooms here", true); + createRoom(systemAvatar, true, path + "system", "system messages for this planet, cannot create rooms here", true); + createRoom(systemAvatar, true, path + "Chat", "public chat for this planet, can create rooms here", true); }); } From 61e8d657830abd3216b807d32ee13fccf1b4515a Mon Sep 17 00:00:00 2001 From: Waverunner Date: Sun, 2 Aug 2015 18:53:41 -0400 Subject: [PATCH 20/25] Refactored default system channel creation to not require a public method --- src/services/chat/ChatManager.java | 12 ++++------ src/services/chat/ChatRoomService.java | 28 ++++++++++++++---------- src/services/galaxy/GalacticManager.java | 3 +-- 3 files changed, 21 insertions(+), 22 deletions(-) diff --git a/src/services/chat/ChatManager.java b/src/services/chat/ChatManager.java index 61a6224a3..672c2644d 100644 --- a/src/services/chat/ChatManager.java +++ b/src/services/chat/ChatManager.java @@ -65,12 +65,12 @@ import java.util.Locale; public class ChatManager extends Manager { - private ObjectDatabase mails; + private final ObjectDatabase mails; + private final ChatRoomService roomService; private int maxMailId; - private ChatRoomService roomService; - public ChatManager() { - roomService = new ChatRoomService(); + public ChatManager(Galaxy g) { + roomService = new ChatRoomService(g); mails = new CachedObjectDatabase<>("odb/mails.db"); maxMailId = 1; @@ -227,10 +227,6 @@ public class ChatManager extends Manager { } } - public void initializeGalaxyChannels(Galaxy galaxy) { - roomService.createSystemChannels(galaxy.getName()); - } - /* Friends List */ private void handleRequestFriendList(Player player) { diff --git a/src/services/chat/ChatRoomService.java b/src/services/chat/ChatRoomService.java index 1a73e5157..ea296a911 100644 --- a/src/services/chat/ChatRoomService.java +++ b/src/services/chat/ChatRoomService.java @@ -61,6 +61,7 @@ import network.packets.swg.zone.chat.ChatSendToRoom; import network.packets.swg.zone.chat.ChatUnbanAvatarFromRoom; import network.packets.swg.zone.chat.ChatUninviteFromRoom; import network.packets.swg.zone.insertion.ChatRoomList; +import resources.Galaxy; import resources.Terrain; import resources.chat.ChatAvatar; import resources.chat.ChatResult; @@ -87,24 +88,19 @@ import java.util.concurrent.ConcurrentHashMap; * @author Waverunner */ public class ChatRoomService extends Service { - private int maxChatRoomId; - private Map roomMap; // Map to keep track of each player's recent message for a room to prevent duplicates from client - private Map> messages; - private ObjectDatabase database; + private final Map> messages; + private final ObjectDatabase database; + private final Map roomMap; + private final Galaxy galaxy; + private int maxChatRoomId; - public ChatRoomService() { + public ChatRoomService(Galaxy g) { + galaxy = g; database = new CachedObjectDatabase<>("odb/chat_rooms.db"); roomMap = new ConcurrentHashMap<>(); messages = new ConcurrentHashMap<>(); maxChatRoomId = 1; - - database.load(); - database.traverse((room) -> { - if (room.getId() >= maxChatRoomId) - maxChatRoomId++; - roomMap.put(room.getId(), room); - }); } @Override @@ -112,6 +108,14 @@ public class ChatRoomService extends Service { registerForIntent(ChatRoomUpdateIntent.TYPE); registerForIntent(GalacticPacketIntent.TYPE); + database.load(); + database.traverse((room) -> { + if (room.getId() >= maxChatRoomId) + maxChatRoomId++; + roomMap.put(room.getId(), room); + }); + + createSystemChannels(galaxy.getName()); return super.initialize(); } diff --git a/src/services/galaxy/GalacticManager.java b/src/services/galaxy/GalacticManager.java index cdc454208..894839b6f 100644 --- a/src/services/galaxy/GalacticManager.java +++ b/src/services/galaxy/GalacticManager.java @@ -53,7 +53,7 @@ public class GalacticManager extends Manager { objectManager = new ObjectManager(); playerManager = new PlayerManager(); gameManager = new GameManager(); - chatManager = new ChatManager(); + chatManager = new ChatManager(g); prevPacketIntent = null; addChildService(objectManager); @@ -65,7 +65,6 @@ public class GalacticManager extends Manager { @Override public boolean initialize() { registerForIntent(InboundPacketIntent.TYPE); - chatManager.initializeGalaxyChannels(galaxy); return super.initialize(); } From c01a177c982356ebf77d9c9cbeb06929fb5992dd Mon Sep 17 00:00:00 2001 From: Obique PSWG Date: Sun, 2 Aug 2015 22:09:22 -0500 Subject: [PATCH 21/25] Fixed issue where players will still appear as spawned inside a building despite logging out --- src/resources/objects/SWGObject.java | 17 ++++++++++++----- src/services/objects/ObjectManager.java | 5 ++++- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/resources/objects/SWGObject.java b/src/resources/objects/SWGObject.java index a670e8163..afb39d04b 100644 --- a/src/resources/objects/SWGObject.java +++ b/src/resources/objects/SWGObject.java @@ -46,6 +46,7 @@ import resources.containers.DefaultPermissions; import resources.encodables.StringId; import resources.network.BaselineBuilder; import resources.network.DeltaBuilder; +import resources.objects.creature.CreatureObject; import resources.player.Player; import resources.player.PlayerState; import resources.server_info.Log; @@ -578,7 +579,7 @@ public abstract class SWGObject implements Serializable, Comparable { return (filledId != -1) ? filledId : -1; } - protected final void sendSceneCreateObject(Player target) { + private final void sendSceneCreateObject(Player target) { SceneCreateObjectByCrc create = new SceneCreateObjectByCrc(); create.setObjectId(objectId); create.setLocation(location); @@ -589,7 +590,7 @@ public abstract class SWGObject implements Serializable, Comparable { } - protected final void sendSceneDestroyObject(Player target) { + private final void sendSceneDestroyObject(Player target) { SceneDestroyObject destroy = new SceneDestroyObject(); destroy.setObjectId(objectId); target.sendPacket(destroy); @@ -607,6 +608,10 @@ public abstract class SWGObject implements Serializable, Comparable { target.sendPacket(new SceneEndBaselines(getObjectId())); } + public void destroyObject(Player target) { + sendSceneDestroyObject(target); + } + public void clearAware() { SWGObject [] objects; synchronized (objectsAware) { @@ -741,7 +746,7 @@ public abstract class SWGObject implements Serializable, Comparable { for (SWGObject swgObject : removed) { if (swgObject.getOwner() != null) { - sendSceneDestroyObject(swgObject.getOwner()); + destroyObject(swgObject.getOwner()); } } } @@ -766,7 +771,7 @@ public abstract class SWGObject implements Serializable, Comparable { if (objectsAware.remove(o)) { Player owner = o.getOwner(); if (owner != null) - sendSceneDestroyObject(owner); + destroyObject(owner); else destroyObjectObservers(o); } @@ -797,7 +802,7 @@ public abstract class SWGObject implements Serializable, Comparable { Set observers = new HashSet<>(); getChildrenObservers(observers, obj); for (SWGObject observer : observers) { - sendSceneDestroyObject(observer.getOwner()); + destroyObject(observer.getOwner()); } } @@ -854,6 +859,8 @@ public abstract class SWGObject implements Serializable, Comparable { // Now create the contained objects for (SWGObject containedObject : containedObjects.values()) { if (containedObject != null && !sentObjects.contains(containedObject)) { + if (containedObject instanceof CreatureObject && containedObject.hasSlot("ghost") && containedObject.getOwner() == null) + continue; // If it's a player, but that's logged out containedObject.createObject(target); } } diff --git a/src/services/objects/ObjectManager.java b/src/services/objects/ObjectManager.java index a15ff7ccd..ba007d4db 100644 --- a/src/services/objects/ObjectManager.java +++ b/src/services/objects/ObjectManager.java @@ -202,7 +202,8 @@ public class ObjectManager extends Manager { private void loadObject(SWGObject obj) { obj.setOwner(null); - if (!(obj instanceof CreatureObject) || ((CreatureObject) obj).getPlayerObject() == null) + // if player is not a player + if (!(obj instanceof CreatureObject && ((CreatureObject) obj).hasSlot("ghost"))) objectAwareness.add(obj); objectMap.put(obj.getObjectId(), obj); updateBuildoutParent(obj); @@ -256,6 +257,8 @@ public class ObjectManager extends Manager { case PE_DISAPPEAR: p.getCreatureObject().clearAware(); objectAwareness.remove(p.getCreatureObject()); + for (SWGObject obj : p.getCreatureObject().getObservers()) + p.getCreatureObject().destroyObject(obj.getOwner()); break; case PE_ZONE_IN: p.getCreatureObject().clearAware(); From 9346f93f036bc6dd2b781f9712814420ee840f25 Mon Sep 17 00:00:00 2001 From: Ziggy Date: Mon, 3 Aug 2015 05:09:40 +0200 Subject: [PATCH 22/25] Fixed misplaced CREO01 baseline variables and updated their respective deltas accordingly --- src/resources/objects/creature/CreatureObject.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/resources/objects/creature/CreatureObject.java b/src/resources/objects/creature/CreatureObject.java index 56498c884..a2f5eedb0 100644 --- a/src/resources/objects/creature/CreatureObject.java +++ b/src/resources/objects/creature/CreatureObject.java @@ -265,12 +265,12 @@ public class CreatureObject extends TangibleObject { public void setCashBalance(int cashBalance) { this.cashBalance = cashBalance; - sendDelta(1, 0, cashBalance); + sendDelta(1, 1, cashBalance); } public void setBankBalance(int bankBalance) { this.bankBalance = bankBalance; - sendDelta(1, 1, bankBalance); + sendDelta(1, 0, bankBalance); } public void setMovementScale(double movementScale) { @@ -682,8 +682,8 @@ public class CreatureObject extends TangibleObject { public void createBaseline1(Player target, BaselineBuilder bb) { super.createBaseline1(target, bb); // 0 variables - bb.addInt(cashBalance); // 0 - bb.addInt(bankBalance); // 1 + bb.addInt(bankBalance); // 0 + bb.addInt(cashBalance); // 1 bb.addObject(baseAttributes); // Attributes player has without any gear on -- 2 bb.addObject(skills); // 3 From b17c00059aff96873d9118bbad49f36b67e046b4 Mon Sep 17 00:00:00 2001 From: Obique PSWG Date: Sun, 2 Aug 2015 23:04:15 -0500 Subject: [PATCH 23/25] Fixed null pointer exception on chat room loading --- src/resources/chat/ChatRoom.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/resources/chat/ChatRoom.java b/src/resources/chat/ChatRoom.java index 27908bf34..63596a7e3 100644 --- a/src/resources/chat/ChatRoom.java +++ b/src/resources/chat/ChatRoom.java @@ -32,12 +32,16 @@ import network.packets.swg.SWGPacket; import network.packets.swg.zone.chat.ChatRoomMessage; import resources.encodables.Encodable; import resources.encodables.OutOfBandPackage; +import resources.objects.SWGObject; import resources.player.Player; import services.player.PlayerManager; +import java.io.IOException; +import java.io.ObjectInputStream; import java.io.Serializable; import java.nio.ByteBuffer; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; /** @@ -72,7 +76,12 @@ public class ChatRoom implements Encodable, Serializable { members = new ArrayList<>(); banned = new ArrayList<>(); } - + + private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException { + members = new ArrayList<>(); + ois.defaultReadObject(); + } + public int getId() { return id; } From ccc5c1bc208312cdfe852186cb8ecd35f06a62a4 Mon Sep 17 00:00:00 2001 From: Ziggy Date: Mon, 3 Aug 2015 06:04:48 +0200 Subject: [PATCH 24/25] Created an IntentFactory which currently supports common operations such as system messages and in-game mails --- src/utilities/IntentFactory.java | 42 ++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 src/utilities/IntentFactory.java diff --git a/src/utilities/IntentFactory.java b/src/utilities/IntentFactory.java new file mode 100644 index 000000000..f5ba6229d --- /dev/null +++ b/src/utilities/IntentFactory.java @@ -0,0 +1,42 @@ +package utilities; + +import resources.encodables.player.Mail; +import resources.objects.SWGObject; +import resources.player.Player; +import intents.chat.ChatBroadcastIntent; +import intents.chat.ChatBroadcastIntent.BroadcastType; +import intents.chat.PersistentMessageIntent; + +/** + * @author Mads + * This class is to be used exclusively in cases where using the intents directly isn't practical. + */ +public final class IntentFactory { + + private void broadcast(String message, Player source, BroadcastType type) { + new ChatBroadcastIntent(message, source, source.getCreatureObject().getTerrain(), type).broadcast(); + } + + public void broadcastArea(String message, Player source) { + broadcast(message, source, BroadcastType.AREA); + } + + public void broadcastGalaxy(String message, Player source) { + broadcast(message, source, BroadcastType.GALAXY); + } + + public void broadcastPersonal(String message, Player source) { + broadcast(message, source, BroadcastType.PERSONAL); + } + + public void broadcastPlanet(String message, Player source) { + broadcast(message, source, BroadcastType.PLANET); + } + + public void sendMail(SWGObject receiver, String sender, String subject, String message) { + Mail mail = new Mail(sender, subject, message, receiver.getObjectId()); + + new PersistentMessageIntent(receiver, mail, receiver.getOwner().getGalaxyName()).broadcast(); + } + +} From e3097069bcd415b02fd6ab4f27244b8299ba14d1 Mon Sep 17 00:00:00 2001 From: Ziggy Date: Mon, 3 Aug 2015 06:05:35 +0200 Subject: [PATCH 25/25] The IntentFactory can now be referenced in scripts without the need to import the class --- src/utilities/Scripts.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/utilities/Scripts.java b/src/utilities/Scripts.java index 409bd90e5..ff8859506 100644 --- a/src/utilities/Scripts.java +++ b/src/utilities/Scripts.java @@ -41,6 +41,10 @@ public class Scripts { private static final ScriptEngine ENGINE = new ScriptEngineManager().getEngineByName("nashorn"); private static final Invocable INVOCABLE = (Invocable) ENGINE; + static { + ENGINE.put("intentFactory", new IntentFactory()); + } + // Prevents instantiation. private Scripts() {}