From 799d13b5d5bec31e51c73e386ac68db4fd9bb926 Mon Sep 17 00:00:00 2001 From: Waverunner Date: Thu, 18 Jun 2015 10:09:31 -0400 Subject: [PATCH 01/17] Added /findfriend --- src/intents/chat/ChatBroadcastIntent.java | 5 +- .../callbacks/FindFriendCallback.java | 95 +++++++++++++++++++ src/services/commands/CommandService.java | 1 + 3 files changed, 99 insertions(+), 2 deletions(-) create mode 100644 src/resources/commands/callbacks/FindFriendCallback.java 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/resources/commands/callbacks/FindFriendCallback.java b/src/resources/commands/callbacks/FindFriendCallback.java new file mode 100644 index 000000000..661d9889e --- /dev/null +++ b/src/resources/commands/callbacks/FindFriendCallback.java @@ -0,0 +1,95 @@ +/******************************************************************************* + * 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); + ghost.addWaypoint(waypoint); + } else { + waypoint.setLocation(location); + ghost.updateWaypoint(waypoint); + } + + new ChatBroadcastIntent(player, new ProsePackage("@ui_cmnty:friend_location", "TU", friendName)).broadcast(); + } +} 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() { From 1f77856284c48ed1441395902f88518664acc8c3 Mon Sep 17 00:00:00 2001 From: Ziggeh Date: Thu, 18 Jun 2015 17:36:15 +0200 Subject: [PATCH 02/17] Moved WeatherService into the galaxy package --- src/services/{player => galaxy}/WeatherService.java | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/services/{player => galaxy}/WeatherService.java (100%) diff --git a/src/services/player/WeatherService.java b/src/services/galaxy/WeatherService.java similarity index 100% rename from src/services/player/WeatherService.java rename to src/services/galaxy/WeatherService.java From 7bf4a3aca4f1972bf0743708675e796532afb7e0 Mon Sep 17 00:00:00 2001 From: Ziggeh Date: Thu, 18 Jun 2015 17:39:34 +0200 Subject: [PATCH 03/17] Each WeatherType now specify their chance of being picked --- .../swg/zone/ServerWeatherMessage.java | 7 ++---- src/resources/WeatherType.java | 23 ++++++++++++++----- src/services/galaxy/GameManager.java | 1 - 3 files changed, 19 insertions(+), 12 deletions(-) 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/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/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 { From aae012a81e561894bad49d516d7afdeead014183 Mon Sep 17 00:00:00 2001 From: Ziggeh Date: Thu, 18 Jun 2015 17:45:07 +0200 Subject: [PATCH 04/17] Added a unit test for WeatherType --- test/resources/TestWeatherType.java | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 test/resources/TestWeatherType.java 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); + + } + +} From c6c9704b4b82e6d4f881e30d6482d5cda1bf6ec3 Mon Sep 17 00:00:00 2001 From: Ziggeh Date: Thu, 18 Jun 2015 17:47:48 +0200 Subject: [PATCH 05/17] Weather now updates more frequently and is less prone to being "bad" --- src/services/galaxy/WeatherService.java | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/services/galaxy/WeatherService.java b/src/services/galaxy/WeatherService.java index c2fa01d1a..8bf2b019b 100644 --- a/src/services/galaxy/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 { From bd6a18bd9d59db07dd3e38f7ffd3a54d1bb16a0d Mon Sep 17 00:00:00 2001 From: Waverunner Date: Thu, 18 Jun 2015 14:48:32 -0400 Subject: [PATCH 06/17] Fixed friends list causing issues when adding other players and relogging --- scripts/commands/generic/addFriend.py | 10 +-- src/intents/chat/ChatAvatarRequestIntent.java | 2 + .../swg/zone/chat/ChatOnAddFriend.java | 50 ++++++++++++++ .../zone/chat/ChatOnChangeFriendStatus.java | 66 +++++++++++++++++++ src/services/chat/ChatService.java | 34 ++++++++-- 5 files changed, 151 insertions(+), 11 deletions(-) create mode 100644 src/network/packets/swg/zone/chat/ChatOnAddFriend.java create mode 100644 src/network/packets/swg/zone/chat/ChatOnChangeFriendStatus.java diff --git a/scripts/commands/generic/addFriend.py b/scripts/commands/generic/addFriend.py index 485e1ee0a..18bc2fce8 100644 --- a/scripts/commands/generic/addFriend.py +++ b/scripts/commands/generic/addFriend.py @@ -1,8 +1,7 @@ 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() @@ -19,11 +18,8 @@ def execute(galacticManager, player, target, args): return if galacticManager.getPlayerManager().playerExists(name) is False: - ChatBroadcastIntent(player, ProsePackage("@cmnty:friend_duplicate", "TT", name)).broadcast() + ChatBroadcastIntent(player, ProsePackage("@cmnty:friend_not_found", "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/src/intents/chat/ChatAvatarRequestIntent.java b/src/intents/chat/ChatAvatarRequestIntent.java index 8243cbb2a..9a8fcef56 100644 --- a/src/intents/chat/ChatAvatarRequestIntent.java +++ b/src/intents/chat/ChatAvatarRequestIntent.java @@ -61,6 +61,8 @@ public class ChatAvatarRequestIntent extends Intent{ public enum RequestType { TARGET_STATUS, + FRIEND_ADD_TARGET, + FRIEND_REMOVE_TARGET, IGNORE_ADD_TARGET, IGNORE_REMOVE_TARGET } 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..389268479 --- /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 { + private 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/services/chat/ChatService.java b/src/services/chat/ChatService.java index 3b3264146..ddbae3bab 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,8 @@ 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.ChatOnSendInstantMessage; import network.packets.swg.zone.chat.ChatOnSendPersistentMessage; import network.packets.swg.zone.chat.ChatPersistentMessageToClient; @@ -89,6 +92,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 @@ -197,7 +201,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 +215,29 @@ public class ChatService extends Service { break; case IGNORE_ADD_TARGET: break; + case FRIEND_ADD_TARGET: + handleAddFriend(i.getPlayer(), i.getTarget()); + break; } } + private void handleAddFriend(Player player, String target) { + PlayerObject ghost = player.getPlayerObject(); + if (ghost == null) + return; + + ChatOnChangeFriendStatus friendStatus = new ChatOnChangeFriendStatus( + player.getCreatureObject().getObjectId(), player.getGalaxyName(), target, false); + + player.sendPacket(new ChatOnAddFriend(), friendStatus); + + ghost.addFriend(target); + + new ChatBroadcastIntent(player, new ProsePackage("@cmnty:friend_added", "TT", target)).broadcast(); + + sendTargetAvatarStatus(player, target); + } + private void handleChatRoomListRequest(Player player, ChatRequestRoomList request) { } @@ -378,9 +402,11 @@ 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 OutOfBand(prose))); + else + player.sendPacket(new ChatSystemMessage(SystemChatType.SCREEN_AND_CHAT, message)); } private void sendPersistentMessageHeaders(Player player, String galaxy) { From de5d7ba3c7478e8000d9f4bb5968dd7f0517e27e Mon Sep 17 00:00:00 2001 From: Waverunner Date: Thu, 18 Jun 2015 15:19:46 -0400 Subject: [PATCH 07/17] FindFriend waypoints are set to the appropriate name, color, and displays appropriate messages for being newly created or updated Waypoints can be created at -1, 0, -1 --- src/network/packets/swg/zone/chat/ChatOnAddFriend.java | 2 +- src/resources/commands/callbacks/FindFriendCallback.java | 6 ++++-- src/resources/commands/callbacks/WaypointCmdCallback.java | 6 +++--- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/network/packets/swg/zone/chat/ChatOnAddFriend.java b/src/network/packets/swg/zone/chat/ChatOnAddFriend.java index 389268479..f3dbf6020 100644 --- a/src/network/packets/swg/zone/chat/ChatOnAddFriend.java +++ b/src/network/packets/swg/zone/chat/ChatOnAddFriend.java @@ -35,7 +35,7 @@ import java.nio.ByteBuffer; * @author Waverunner */ public class ChatOnAddFriend extends SWGPacket { - private static final int CRC = 0x2B2A0D94; + public static final int CRC = 0x2B2A0D94; public ChatOnAddFriend() {} diff --git a/src/resources/commands/callbacks/FindFriendCallback.java b/src/resources/commands/callbacks/FindFriendCallback.java index 661d9889e..5782acaf0 100644 --- a/src/resources/commands/callbacks/FindFriendCallback.java +++ b/src/resources/commands/callbacks/FindFriendCallback.java @@ -84,12 +84,14 @@ public class FindFriendCallback implements ICmdCallback { 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(); } - - 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..7b96bb2ce 100644 --- a/src/resources/commands/callbacks/WaypointCmdCallback.java +++ b/src/resources/commands/callbacks/WaypointCmdCallback.java @@ -53,8 +53,8 @@ public class WaypointCmdCallback implements ICmdCallback { WaypointColor color = null; Terrain terrain = null; String name = null; - float x = -1; - float y = -1; + float x = Float.MAX_VALUE; + float y = Float.MAX_VALUE; switch(cmdArgs.length) { case 2: // x y @@ -94,7 +94,7 @@ public class WaypointCmdCallback implements ICmdCallback { 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()))); + waypoint.setLocation(new Location((x != Float.MAX_VALUE ? x : loc.getX()), 0, (y != Float.MAX_VALUE ? y : loc.getZ()), (terrain != null ? terrain : loc.getTerrain()))); if (color != null) waypoint.setColor(color); From 1ea6818c5c2cbbff96939d91c16bf72847b10108 Mon Sep 17 00:00:00 2001 From: Waverunner Date: Fri, 19 Jun 2015 12:37:12 -0400 Subject: [PATCH 08/17] Fixed friends displaying in friends list from old characters Fixed removeFriend command not properly lowercasing Fixed variety of issues with the community window not refreshing friends list properly Fixed empty "does not exist" messages for friends list Fixed bug allowing you to add yourself to your friends list --- scripts/commands/generic/addFriend.py | 16 +--- scripts/commands/generic/getFriendList.py | 7 ++ scripts/commands/generic/removeFriend.py | 14 ++-- src/intents/chat/ChatAvatarRequestIntent.java | 1 + .../swg/zone/chat/ChatOnGetFriendsList.java | 73 +++++++++++++++++++ src/resources/collections/SWGList.java | 23 +++++- src/services/chat/ChatService.java | 65 ++++++++++++++--- 7 files changed, 170 insertions(+), 29 deletions(-) create mode 100644 scripts/commands/generic/getFriendList.py create mode 100644 src/network/packets/swg/zone/chat/ChatOnGetFriendsList.java diff --git a/scripts/commands/generic/addFriend.py b/scripts/commands/generic/addFriend.py index 18bc2fce8..140dec685 100644 --- a/scripts/commands/generic/addFriend.py +++ b/scripts/commands/generic/addFriend.py @@ -1,24 +1,14 @@ from intents.chat import ChatAvatarRequestIntent -from intents.chat import ChatBroadcastIntent -from resources.encodables import ProsePackage 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() - return - - if galacticManager.getPlayerManager().playerExists(name) is False: - ChatBroadcastIntent(player, ProsePackage("@cmnty:friend_not_found", "TT", name)).broadcast() + if not name: return ChatAvatarRequestIntent(player, name, FRIEND_ADD_TARGET).broadcast() 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 9a8fcef56..2ed8d4538 100644 --- a/src/intents/chat/ChatAvatarRequestIntent.java +++ b/src/intents/chat/ChatAvatarRequestIntent.java @@ -60,6 +60,7 @@ public class ChatAvatarRequestIntent extends Intent{ } public enum RequestType { + FRIEND_LIST, TARGET_STATUS, FRIEND_ADD_TARGET, FRIEND_REMOVE_TARGET, 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/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/services/chat/ChatService.java b/src/services/chat/ChatService.java index ddbae3bab..331e15069 100644 --- a/src/services/chat/ChatService.java +++ b/src/services/chat/ChatService.java @@ -45,6 +45,7 @@ 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; @@ -54,6 +55,7 @@ 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; @@ -79,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; } @@ -218,24 +220,71 @@ public class ChatService extends Service { 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 handleAddFriend(Player player, String target) { + 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(); - - sendTargetAvatarStatus(player, target); } private void handleChatRoomListRequest(Player player, ChatRequestRoomList request) { @@ -363,9 +412,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); } @@ -413,7 +460,7 @@ public class ChatService extends Service { 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() { @@ -452,6 +499,6 @@ public class ChatService extends Service { private enum MailFlagType { FULL_MESSAGE, - HEADER_ONLY; + HEADER_ONLY } } From e1db970154a59d38e02658d90f1fade2bc14c9e1 Mon Sep 17 00:00:00 2001 From: Waverunner Date: Fri, 19 Jun 2015 13:14:59 -0400 Subject: [PATCH 09/17] Changed ChatService to use PE_ZONE_IN instead of PE_FIRST_ZONE --- src/services/chat/ChatService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/services/chat/ChatService.java b/src/services/chat/ChatService.java index 331e15069..7552bc706 100644 --- a/src/services/chat/ChatService.java +++ b/src/services/chat/ChatService.java @@ -179,7 +179,7 @@ public class ChatService extends Service { private void handlePlayerEventIntent(PlayerEventIntent intent) { switch (intent.getEvent()) { - case PE_FIRST_ZONE: + case PE_ZONE_IN: sendPersistentMessageHeaders(intent.getPlayer(), intent.getGalaxy()); updateChatAvatarStatus(intent.getPlayer(), intent.getGalaxy(), true); break; From 754bd804ffd7de89bbd853ce6c5afa1daa93cef8 Mon Sep 17 00:00:00 2001 From: Waverunner Date: Fri, 19 Jun 2015 14:39:04 -0400 Subject: [PATCH 10/17] Fixed online notification status not showing for players that are relogging --- src/services/chat/ChatService.java | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/services/chat/ChatService.java b/src/services/chat/ChatService.java index 7552bc706..e980d55cd 100644 --- a/src/services/chat/ChatService.java +++ b/src/services/chat/ChatService.java @@ -179,11 +179,14 @@ public class ChatService extends Service { private void handlePlayerEventIntent(PlayerEventIntent intent) { switch (intent.getEvent()) { - case PE_ZONE_IN: - sendPersistentMessageHeaders(intent.getPlayer(), intent.getGalaxy()); - updateChatAvatarStatus(intent.getPlayer(), intent.getGalaxy(), true); + case PE_FIRST_ZONE: + 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: @@ -392,11 +395,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); + } } } From 2ff79ceef89f9831dbcdf29baf8b6cacca2e3a55 Mon Sep 17 00:00:00 2001 From: Waverunner Date: Fri, 19 Jun 2015 16:55:24 -0400 Subject: [PATCH 11/17] Changed SWGNameGenerator to use StringBuffer for name generation and fixed some small issues in other classes --- src/network/packets/Packet.java | 4 +- .../object_controller/ObjectMenuResponse.java | 3 +- .../containers/ContainerPermissions.java | 7 ++-- src/resources/objects/SWGObject.java | 2 +- .../objects/weapon/WeaponObject.java | 2 +- src/utilities/namegen/SWGNameGenerator.java | 37 +++++++++++-------- 6 files changed, 32 insertions(+), 23 deletions(-) diff --git a/src/network/packets/Packet.java b/src/network/packets/Packet.java index 3f37d3571..23d3ceebb 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; 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/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/objects/SWGObject.java b/src/resources/objects/SWGObject.java index 96fe94d23..ef4b2876c 100644 --- a/src/resources/objects/SWGObject.java +++ b/src/resources/objects/SWGObject.java @@ -478,7 +478,7 @@ public abstract class SWGObject implements Serializable, Comparable { } public int getMaxContainerSize() { - return Integer.valueOf(templateAttributes.get("containerVolumeLimit").toString()); + return Integer.parseInt(templateAttributes.get("containerVolumeLimit").toString()); } public void setBuildout(boolean buildout) { 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/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; } } } From c17396951d424c713c787b7a4a3204c8b1be473c Mon Sep 17 00:00:00 2001 From: Waverunner Date: Fri, 19 Jun 2015 21:13:52 -0400 Subject: [PATCH 12/17] Added Waypoint attachments for Mails and renamed OutOfBand to OutOfBandPackage as well as added a decoding method with a new interface --- src/network/packets/Packet.java | 8 +- .../chat/ChatOnSendPersistentMessage.java | 14 +- .../chat/ChatPersistentMessageToClient.java | 342 ++---------------- .../chat/ChatPersistentMessageToServer.java | 23 +- .../swg/zone/chat/ChatSystemMessage.java | 8 +- src/resources/Terrain.java | 2 +- .../{OutOfBand.java => OutOfBandPackage.java} | 128 +++++-- src/resources/encodables/ProsePackage.java | 23 +- src/resources/encodables/player/Mail.java | 35 +- src/resources/network/BaselineBuilder.java | 2 +- .../objects/waypoint/WaypointObject.java | 62 +++- src/services/chat/ChatResult.java | 48 +++ src/services/chat/ChatService.java | 23 +- 13 files changed, 315 insertions(+), 403 deletions(-) rename src/resources/encodables/{OutOfBand.java => OutOfBandPackage.java} (52%) create mode 100644 src/services/chat/ChatResult.java diff --git a/src/network/packets/Packet.java b/src/network/packets/Packet.java index 23d3ceebb..de6effe6e 100644 --- a/src/network/packets/Packet.java +++ b/src/network/packets/Packet.java @@ -123,11 +123,11 @@ public class Packet { public static void addArray(ByteBuffer bb, byte [] b) { addShort(bb, b.length); - bb.put(b); + bb.order(ByteOrder.LITTLE_ENDIAN).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/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..ebdd82951 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.order(ByteOrder.LITTLE_ENDIAN).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/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/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..820a6d246 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(); + + 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..b8d53b3cf 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,12 @@ public class ProsePackage implements Encodable { byte[] targetData = target.encode(); byte[] otherData = other.encode(); - int size = 9 + stringData.length + actorData.length + targetData.length + otherData.length; + int size = 14 + stringData.length + actorData.length + targetData.length + otherData.length; ByteBuffer bb = ByteBuffer.allocate(size).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 +212,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/waypoint/WaypointObject.java b/src/resources/objects/waypoint/WaypointObject.java index c8fd7dc72..944281dfd 100644 --- a/src/resources/objects/waypoint/WaypointObject.java +++ b/src/resources/objects/waypoint/WaypointObject.java @@ -30,14 +30,18 @@ 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; @@ -94,20 +98,47 @@ public class WaypointObject extends IntangibleObject implements Encodable { @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.putFloat((float) loc.getX()); + bb.putFloat((float) loc.getY()); + bb.putFloat((float) loc.getZ()); + bb.putLong(0); + 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()); + 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)) @@ -123,16 +154,29 @@ public class WaypointObject extends IntangibleObject implements Encodable { public int hashCode() { return ((super.hashCode() * 7 + name.hashCode()) * 13 + color.getValue()) * 17 + cellNumber; } - + + @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; + } } } 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 e980d55cd..fe84f8833 100644 --- a/src/services/chat/ChatService.java +++ b/src/services/chat/ChatService.java @@ -58,7 +58,7 @@ 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; @@ -338,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) @@ -453,7 +456,7 @@ public class ChatService extends Service { private void broadcastPersonalMessage(ProsePackage prose, Player player, String message) { if (prose != null) - player.sendPacket(new ChatSystemMessage(SystemChatType.SCREEN_AND_CHAT, new OutOfBand(prose))); + player.sendPacket(new ChatSystemMessage(SystemChatType.SCREEN_AND_CHAT, new OutOfBandPackage(prose))); else player.sendPacket(new ChatSystemMessage(SystemChatType.SCREEN_AND_CHAT, message)); } @@ -485,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; } From 788494617a6401e61119d11c8ae0f795a7d15b6e Mon Sep 17 00:00:00 2001 From: Waverunner Date: Sat, 20 Jun 2015 00:35:46 -0400 Subject: [PATCH 13/17] Fixed waypoint command parameters, all variations of it should work. --- .../callbacks/WaypointCmdCallback.java | 154 ++++++++++++------ .../objects/waypoint/WaypointObject.java | 13 ++ 2 files changed, 117 insertions(+), 50 deletions(-) diff --git a/src/resources/commands/callbacks/WaypointCmdCallback.java b/src/resources/commands/callbacks/WaypointCmdCallback.java index 7b96bb2ce..822636612 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,126 @@ 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 = Float.MAX_VALUE; - float y = Float.MAX_VALUE; - + 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 { + x = Float.parseFloat(cmdArgs[1]); + if (cmdArgs.length >= 3) // Just to be sure.. Maybe someone wanted some numbers in the name. + z = Float.parseFloat(cmdArgs[2]); + } 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) + 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; + } + } + 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; // TODO: fail message + z = floatValue(cmdArgs[1]); break; - case 4: // x z y name + case 4: // x y z name x = floatValue(cmdArgs[0]); - if (x == -1) - return; - //z = floatValue(cmdArgs[1]); - y = floatValue(cmdArgs[2]); + if (Float.isNaN(x)) + break; // TODO: fail message + //y = floatValue(cmdArgs[1]); + z = floatValue(cmdArgs[2]); + if (Float.isNaN(z)) + break; // TODO: Fail message 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: break; + } + + 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 != Float.MAX_VALUE ? x : loc.getX()), 0, (y != Float.MAX_VALUE ? 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); return waypoint; } @@ -107,19 +173,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/objects/waypoint/WaypointObject.java b/src/resources/objects/waypoint/WaypointObject.java index 944281dfd..8ef8abaa8 100644 --- a/src/resources/objects/waypoint/WaypointObject.java +++ b/src/resources/objects/waypoint/WaypointObject.java @@ -178,5 +178,18 @@ public class WaypointObject extends IntangibleObject implements OutOfBandPackage } 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; + } + } } } From 6893f47ded3dc08a8e0147bae0e4b87cfb53330d Mon Sep 17 00:00:00 2001 From: Waverunner Date: Sat, 20 Jun 2015 00:53:27 -0400 Subject: [PATCH 14/17] Added x y z only command variation to /waypoint --- .../commands/callbacks/WaypointCmdCallback.java | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/resources/commands/callbacks/WaypointCmdCallback.java b/src/resources/commands/callbacks/WaypointCmdCallback.java index 822636612..6f999943d 100644 --- a/src/resources/commands/callbacks/WaypointCmdCallback.java +++ b/src/resources/commands/callbacks/WaypointCmdCallback.java @@ -92,6 +92,8 @@ public class WaypointCmdCallback implements ICmdCallback { } } + // Was there an error message saying the format was wrong? + switch(cmdArgs.length) { case 1: // name name = cmdArgs[0]; @@ -99,17 +101,24 @@ public class WaypointCmdCallback implements ICmdCallback { case 2: // x y x = floatValue(cmdArgs[0]); if (Float.isNaN(x)) - break; // TODO: fail message + break; + z = floatValue(cmdArgs[1]); + break; + case 3: // x y z + x = floatValue(cmdArgs[0]); + if (Float.isNaN(x)) + break; + //y = floatValue(cmdArgs[2]); z = floatValue(cmdArgs[1]); break; case 4: // x y z name x = floatValue(cmdArgs[0]); if (Float.isNaN(x)) - break; // TODO: fail message + break; //y = floatValue(cmdArgs[1]); z = floatValue(cmdArgs[2]); if (Float.isNaN(z)) - break; // TODO: Fail message + break; name = cmdArgs[3]; break; case 6: // planet x y z color name From d5fa8ab342a7a409926ad482af7994a00ef99401 Mon Sep 17 00:00:00 2001 From: Waverunner Date: Sat, 20 Jun 2015 00:56:41 -0400 Subject: [PATCH 15/17] Minor change to prior commit --- src/resources/commands/callbacks/WaypointCmdCallback.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/resources/commands/callbacks/WaypointCmdCallback.java b/src/resources/commands/callbacks/WaypointCmdCallback.java index 6f999943d..6bbe7a330 100644 --- a/src/resources/commands/callbacks/WaypointCmdCallback.java +++ b/src/resources/commands/callbacks/WaypointCmdCallback.java @@ -108,8 +108,8 @@ public class WaypointCmdCallback implements ICmdCallback { x = floatValue(cmdArgs[0]); if (Float.isNaN(x)) break; - //y = floatValue(cmdArgs[2]); - z = floatValue(cmdArgs[1]); + //y = floatValue(cmdArgs[1]); + z = floatValue(cmdArgs[2]); break; case 4: // x y z name x = floatValue(cmdArgs[0]); From 29f1d73b675c536ed653af7bef78aedc87485708 Mon Sep 17 00:00:00 2001 From: Waverunner Date: Sat, 20 Jun 2015 09:08:05 -0400 Subject: [PATCH 16/17] Fixed ProsePackage buffer overflows and removed system messages on waypoint creation. --- src/network/packets/Packet.java | 2 +- .../zone/chat/ChatPersistentMessageToServer.java | 2 +- .../commands/callbacks/WaypointCmdCallback.java | 15 +++------------ src/resources/encodables/ProsePackage.java | 4 +--- 4 files changed, 6 insertions(+), 17 deletions(-) diff --git a/src/network/packets/Packet.java b/src/network/packets/Packet.java index de6effe6e..af0742e69 100644 --- a/src/network/packets/Packet.java +++ b/src/network/packets/Packet.java @@ -123,7 +123,7 @@ public class Packet { public static void addArray(ByteBuffer bb, byte [] b) { addShort(bb, b.length); - bb.order(ByteOrder.LITTLE_ENDIAN).put(b); + bb.put(b); } public static boolean getBoolean(ByteBuffer bb) { diff --git a/src/network/packets/swg/zone/chat/ChatPersistentMessageToServer.java b/src/network/packets/swg/zone/chat/ChatPersistentMessageToServer.java index ebdd82951..c5287e046 100644 --- a/src/network/packets/swg/zone/chat/ChatPersistentMessageToServer.java +++ b/src/network/packets/swg/zone/chat/ChatPersistentMessageToServer.java @@ -70,7 +70,7 @@ public class ChatPersistentMessageToServer extends SWGPacket { int dataLength = 31 + message.length()*2+oob.length+subject.length()*2+galaxy.length()+recipient.length(); ByteBuffer data = ByteBuffer.allocate(dataLength); addUnicode(data, message); - data.order(ByteOrder.LITTLE_ENDIAN).put(oob); + data.put(oob); addInt(data, counter); addUnicode(data, subject); addAscii(data, "SWG"); diff --git a/src/resources/commands/callbacks/WaypointCmdCallback.java b/src/resources/commands/callbacks/WaypointCmdCallback.java index 6bbe7a330..a3304c1ed 100644 --- a/src/resources/commands/callbacks/WaypointCmdCallback.java +++ b/src/resources/commands/callbacks/WaypointCmdCallback.java @@ -146,29 +146,20 @@ public class WaypointCmdCallback implements ICmdCallback { 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"; + if (Float.isNaN(x) || Float.isNaN(z)) + return; + 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(); - } } private WaypointObject createWaypoint(ObjectManager objManager, WaypointColor color, String name, Location location) { diff --git a/src/resources/encodables/ProsePackage.java b/src/resources/encodables/ProsePackage.java index b8d53b3cf..898d5b873 100644 --- a/src/resources/encodables/ProsePackage.java +++ b/src/resources/encodables/ProsePackage.java @@ -193,9 +193,7 @@ public class ProsePackage implements OutOfBandPackage.OutOfBandData { byte[] targetData = target.encode(); byte[] otherData = other.encode(); - int size = 14 + 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); // ?? From 6366c0b2082be5a9df57ce67e7aa9231ec570e50 Mon Sep 17 00:00:00 2001 From: Waverunner Date: Sat, 20 Jun 2015 10:09:07 -0400 Subject: [PATCH 17/17] Fixed multiple attachments not decoding properly for OutOfBandPackage's and fixed WaypointCmdCallback exceptions on certain cases Added cellId to WaypointObject --- .../callbacks/WaypointCmdCallback.java | 34 +++++++++++++----- .../encodables/OutOfBandPackage.java | 2 +- .../objects/waypoint/WaypointObject.java | 36 ++++++++----------- 3 files changed, 42 insertions(+), 30 deletions(-) diff --git a/src/resources/commands/callbacks/WaypointCmdCallback.java b/src/resources/commands/callbacks/WaypointCmdCallback.java index a3304c1ed..b34753d8d 100644 --- a/src/resources/commands/callbacks/WaypointCmdCallback.java +++ b/src/resources/commands/callbacks/WaypointCmdCallback.java @@ -63,9 +63,14 @@ public class WaypointCmdCallback implements ICmdCallback { 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 { - x = Float.parseFloat(cmdArgs[1]); - if (cmdArgs.length >= 3) // Just to be sure.. Maybe someone wanted some numbers in the name. - z = Float.parseFloat(cmdArgs[2]); + 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}; @@ -81,7 +86,8 @@ public class WaypointCmdCallback implements ICmdCallback { 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) - cmdArgs = args.split(" ", 6); + 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 @@ -135,7 +141,9 @@ public class WaypointCmdCallback implements ICmdCallback { 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()); @@ -146,26 +154,36 @@ public class WaypointCmdCallback implements ICmdCallback { 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"; - if (Float.isNaN(x) || Float.isNaN(z)) - return; - 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(); + } } 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; } diff --git a/src/resources/encodables/OutOfBandPackage.java b/src/resources/encodables/OutOfBandPackage.java index 820a6d246..83962a2a5 100644 --- a/src/resources/encodables/OutOfBandPackage.java +++ b/src/resources/encodables/OutOfBandPackage.java @@ -83,7 +83,7 @@ public class OutOfBandPackage implements Encodable { } public void decode(ByteBuffer data) { - int size = data.getInt(); + int size = data.getInt() * 2; for (int read = 0; read < size; read+= 3) { boolean addedByte = data.getShort() > 0; // ?? Seen as 1 diff --git a/src/resources/objects/waypoint/WaypointObject.java b/src/resources/objects/waypoint/WaypointObject.java index 8ef8abaa8..3afd881cc 100644 --- a/src/resources/objects/waypoint/WaypointObject.java +++ b/src/resources/objects/waypoint/WaypointObject.java @@ -45,7 +45,7 @@ public class WaypointObject extends IntangibleObject implements OutOfBandPackage 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; @@ -54,44 +54,38 @@ public class WaypointObject extends IntangibleObject implements OutOfBandPackage 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. } @@ -100,11 +94,11 @@ public class WaypointObject extends IntangibleObject implements OutOfBandPackage public byte[] encode() { Location loc = getLocation(); ByteBuffer bb = ByteBuffer.allocate(42 + name.length() * 2).order(ByteOrder.LITTLE_ENDIAN); - bb.putInt(cellNumber); + bb.putInt(0); bb.putFloat((float) loc.getX()); bb.putFloat((float) loc.getY()); bb.putFloat((float) loc.getZ()); - bb.putLong(0); + bb.putLong(cellId); bb.putInt(CRC.getCrc(loc.getTerrain().getName())); bb.put(Encoder.encodeUnicode(name)); bb.putLong(getObjectId()); @@ -130,7 +124,7 @@ public class WaypointObject extends IntangibleObject implements OutOfBandPackage data.getInt(); // -3 data.getInt(); setLocation(data.getFloat(), data.getFloat(), data.getFloat()); - data.getLong(); + cellId = data.getLong(); getLocation().setTerrain(Terrain.getTerrainFromCrc(data.getInt())); name = Packet.getUnicode(data); data.getLong(); @@ -145,14 +139,14 @@ public class WaypointObject extends IntangibleObject implements OutOfBandPackage 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