diff --git a/scripts/commands/generic/addFriend.py b/scripts/commands/generic/addFriend.py new file mode 100644 index 000000000..b60887a21 --- /dev/null +++ b/scripts/commands/generic/addFriend.py @@ -0,0 +1,29 @@ +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 + +def execute(galacticManager, player, target, args): + ghost = player.getPlayerObject() + if ghost is None: + return + + name = str(args.split(" ")[0]) + name.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() # Need to fix OOB packet crash + return + + if galacticManager.getPlayerManager().getPlayerByCreatureFirstName(name) is None: + #ChatBroadcastIntent(player, ProsePackage("@cmnty:friend_not_found", "TT", name)).broadcast() # Need to fix OOB packet crash + return + + ghost.addFriend(name) + #ChatBroadcastIntent(player, ProsePackage("@cmnty:friend_added", "TT", name)).broadcast() # Need to fix OOB packet crash + + ChatAvatarRequestIntent(player, name, TARGET_STATUS).broadcast() + return diff --git a/src/intents/NotifyPlayersPacketIntent.java b/src/intents/NotifyPlayersPacketIntent.java index 2854a8644..ce2674f42 100644 --- a/src/intents/NotifyPlayersPacketIntent.java +++ b/src/intents/NotifyPlayersPacketIntent.java @@ -30,6 +30,7 @@ package intents; import network.packets.Packet; import resources.Terrain; import resources.control.Intent; +import resources.player.Player; public class NotifyPlayersPacketIntent extends Intent { @@ -37,16 +38,28 @@ public class NotifyPlayersPacketIntent extends Intent { private Packet packet; private Terrain terrain; + private ConditionalNotify condition; - public NotifyPlayersPacketIntent(Packet packet, Terrain terrain) { + public NotifyPlayersPacketIntent(Packet packet, Terrain terrain, ConditionalNotify condition) { super(TYPE); this.packet = packet; this.terrain = terrain; + this.condition = condition; } + + public NotifyPlayersPacketIntent(Packet packet, Terrain terrain) { + this(packet, terrain, null); + } + public NotifyPlayersPacketIntent(Packet p) { - this(p, null); + this(p, null, null); } public Packet getPacket() { return packet; } public Terrain getTerrain() { return terrain; } + public ConditionalNotify getCondition() { return condition; } + + public interface ConditionalNotify { + boolean meetsCondition(Player player); + } } diff --git a/src/intents/chat/ChatAvatarRequestIntent.java b/src/intents/chat/ChatAvatarRequestIntent.java new file mode 100644 index 000000000..8243cbb2a --- /dev/null +++ b/src/intents/chat/ChatAvatarRequestIntent.java @@ -0,0 +1,67 @@ +/******************************************************************************* + * Copyright (c) 2015 /// Project SWG /// www.projectswg.com + * + * ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on + * July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. + * Our goal is to create an emulator which will provide a server for players to + * continue playing a game similar to the one they used to play. We are basing + * it on the final publish of the game prior to end-game events. + * + * This file is part of Holocore. + * + * -------------------------------------------------------------------------------- + * + * Holocore is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * Holocore is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Holocore. If not, see + ******************************************************************************/ + +package intents.chat; + +import resources.control.Intent; +import resources.player.Player; + +/** + * @author Waverunner + */ +public class ChatAvatarRequestIntent extends Intent{ + public static final String TYPE = "ChatAvatarRequestIntent"; + + private Player player; + private String target; + private RequestType requestType; + + public ChatAvatarRequestIntent(Player player, String target, RequestType requestType) { + super(TYPE); + this.player = player; + this.target = target; + this.requestType = requestType; + } + + public Player getPlayer() { + return player; + } + + public String getTarget() { + return target; + } + + public RequestType getRequestType() { + return requestType; + } + + public enum RequestType { + TARGET_STATUS, + IGNORE_ADD_TARGET, + IGNORE_REMOVE_TARGET + } +} diff --git a/src/network/PacketType.java b/src/network/PacketType.java index 823ca9e5c..e4645342e 100644 --- a/src/network/PacketType.java +++ b/src/network/PacketType.java @@ -46,12 +46,12 @@ import network.packets.swg.zone.server_ui.*; import network.packets.swg.zone.spatial.*; public enum PacketType { - + // Both SERVER_UNIX_EPOCH_TIME (0x24b73893, ServerUnixEpochTime.class), SERVER_ID (0x58c07f21, ServerId.class), SERVER_STRING (0x0e20d7e9, ServerString.class), - + // Login CLIENT_ID_MSG (0xd5899226, ClientIdMsg.class), ERROR_MESSAGE (0xb5abf91a, ErrorMessage.class), @@ -59,7 +59,7 @@ public enum PacketType { CLIENT_PERMISSIONS_MESSAGE (0xe00730e5, ClientPermissionsMessage.class), REQUEST_EXTENDED_CLUSTERS (0x8e33ed05, RequestExtendedClusters.class), OFFLINE_SERVERS_MESSAGE (0xF41A5265, OfflineServersMessage.class), - + // Post-Login LOGIN_CLIENT_ID (0x41131F96, LoginClientId.class), LOGIN_INCORRECT_CLIENT_ID (0x20E7E510, LoginIncorrectClientId.class), @@ -69,7 +69,7 @@ public enum PacketType { ENUMERATE_CHARACTER_ID (0x65ea4574, EnumerateCharacterId.class), STATION_ID_HAS_JEDI_SLOT (0xcc9fccf8, StationIdHasJediSlot.class), CHARACTER_CREATION_DISABLED (0xf4a15265, CharacterCreationDisabled.class), - + // Character Creation CLIENT_CREATE_CHARACTER (0xb97f3074, ClientCreateCharacter.class), CREATE_CHARACTER_SUCCESS (0x1db575cc, CreateCharacterSuccess.class), @@ -78,11 +78,11 @@ public enum PacketType { APPROVE_NAME_RESPONSE (0x9b2c6ba7, ClientVerifyAndLockNameResponse.class), RANDOM_NAME_REQUEST (0xd6d1b6d1, RandomNameRequest.class), RANDOM_NAME_RESPONSE (0xe85fb868, RandomNameResponse.class), - + // Character Deletion DELETE_CHARACTER_RESPONSE (0x8268989b, DeleteCharacterResponse.class), DELETE_CHARACTER_REQUEST (0xe87ad031, DeleteCharacterRequest.class), - + // Zone COMMAND_QUEUE_ENQUEUE (0x00000116, CommandQueueEnqueue.class), SELECT_CHARACTER (0xb5098d76, SelectCharacter.class), @@ -103,8 +103,8 @@ public enum PacketType { SET_WAYPOINT_COLOR (0x90C59FDE, SetWaypointColor.class), SHOW_BACKPACK (ShowBackpack.CRC, ShowBackpack.class), SHOW_HELMET (ShowHelmet.CRC, ShowHelmet.class), - SERVER_WEATHER_MESSAGE (ServerWeatherMessage.CRC, ServerWeatherMessage.class), - + SERVER_WEATHER_MESSAGE (ServerWeatherMessage.CRC, ServerWeatherMessage.class), + // Chat CHAT_FRIENDS_LIST_UPDATE (0x6CD2FCD8, ChatFriendsListUpdate.class), CHAT_IGNORE_LIST (0xF8C275B0, ChatIgnoreList.class), @@ -128,16 +128,16 @@ public enum PacketType { CHAT_SYSTEM_MESSAGE (0x6D2A6413, ChatSystemMessage.class), CON_GENERIC_MESSAGE (0x08C5FC76, ConGenericMessage.class), VOICE_CHAT_STATUS (0x9E601905, VoiceChatStatus.class), - + // Scene SCENE_END_BASELINES (0x2C436037, SceneEndBaselines.class), SCENE_CREATE_OBJECT_BY_CRC (0xFE89DDEA, SceneCreateObjectByCrc.class), - SCENE_DESTROY_OBJECT (0x4D45D504, SceneDestroyObject.class), + SCENE_DESTROY_OBJECT (0x4D45D504, SceneDestroyObject.class), UPDATE_CONTAINMENT_MESSAGE (0x56CBDE9E, UpdateContainmentMessage.class), UPDATE_CELL_PERMISSIONS_MESSAGE (0xF612499C, UpdateCellPermissionMessage.class), GET_MAP_LOCATIONS_MESSAGE (0x1A7AB839, GetMapLocationsMessage.class), GET_MAP_LOCATIONS_RESPONSE_MESSAGE (0x9F80464C, GetMapLocationsResponseMessage.class), - + // Spatial UPDATE_POSTURE_MESSAGE (0x0bde6b41, UpdatePostureMessage.class), UPDATE_TRANSFORMS_MESSAGE (0x1B24F808, UpdateTransformsMessage.class), @@ -147,17 +147,17 @@ public enum PacketType { ATTRIBUTE_LIST_MESSAGE (0xF3F12F2A, AttributeListMessage.class), STOP_CLIENT_EFFECT_OBJECT_BY_LABEL (0xAD6F6B26, StopClientEffectObjectByLabelMessage.class), OPENED_CONTAINER_MESSAGE (0x2E11E4AB, OpenedContainerMessage.class), - + // Combat UPDATE_PVP_STATUS_MESSAGE (0x08a1c126, UpdatePvpStatusMessage.class), GRANT_COMMAND_MESSAGE (0xE67E3875, GrantCommandMessage.class), - + // Server UI OBJECT_MENU_REQUEST (0x00000146, ObjectMenuRequest.class), OBJECT_MENU_RESPONSE (0x00000147, ObjectMenuResponse.class), SUI_CREATE_PAGE_MESSAGE (0xD44B7259, SuiCreatePageMessage.class), SUI_EVENT_NOTIFICATION (0x092D3564, SuiEventNotification.class), - + // Auction IS_VENDOR_OWNER_RESPONSE_MESSAGE (0xCE04173E, IsVendorOwnerResponseMessage.class), AUCTION_QUERY_HEADERS_MESSAGE (0x679E0D00, AuctionQueryHeadersMessage.class), @@ -168,36 +168,36 @@ public enum PacketType { AUCTION_QUERY_HEADERS_RESPONSE_MESSAGE (0xFA500E52, AuctionQueryHeadersResponseMessage.class), RETRIEVE_AUCTION_ITEM_MESSAGE (0x12B0D449, RetrieveAuctionItemMessage.class), RETRIEVE_AUCTION_ITEM_RESPONSE_MESSAGE (0x9499EF8C, RetrieveAuctionItemResponseMessage.class), - + UNKNOWN (0xFFFFFFFF, SWGPacket.class); - + private static final Map packetMap = new HashMap(); - + static { for (PacketType type : values()) { packetMap.put(type.crc, type); } } - + private int crc; private Class c; - + PacketType(int crc, Class c) { this.crc = crc; this.c = c; } - + public int getCrc() { return crc; } - + public static final PacketType fromCrc(int crc) { PacketType type = packetMap.get(crc); if (type == null) return UNKNOWN; return type; } - + public static final SWGPacket getForCrc(int crc) { PacketType type = packetMap.get(crc); if (type == null) @@ -210,5 +210,5 @@ public enum PacketType { } return null; } - + } diff --git a/src/network/packets/swg/zone/chat/ChatFriendsListUpdate.java b/src/network/packets/swg/zone/chat/ChatFriendsListUpdate.java index 1f90eaa73..efbe34d25 100644 --- a/src/network/packets/swg/zone/chat/ChatFriendsListUpdate.java +++ b/src/network/packets/swg/zone/chat/ChatFriendsListUpdate.java @@ -39,14 +39,14 @@ public class ChatFriendsListUpdate extends SWGPacket { private String friendName; private boolean online; - public ChatFriendsListUpdate() { - + public ChatFriendsListUpdate() {} + + public ChatFriendsListUpdate(String galaxy, String friendName, boolean online) { + this.galaxy = galaxy; + this.friendName = friendName; + this.online = online; } - - public ChatFriendsListUpdate(String command) { - - } - + public ChatFriendsListUpdate(ByteBuffer data) { decode(data); } @@ -61,7 +61,8 @@ public class ChatFriendsListUpdate extends SWGPacket { } public ByteBuffer encode() { - ByteBuffer data = ByteBuffer.allocate(6); + int stringLength = 9 + galaxy.length() + friendName.length(); + ByteBuffer data = ByteBuffer.allocate(stringLength + 7); addShort (data, 3); addInt (data, CRC); addAscii (data, "SWG"); @@ -71,4 +72,7 @@ public class ChatFriendsListUpdate extends SWGPacket { return data; } + public String getFriendName() { + return friendName; + } } diff --git a/src/resources/objects/player/PlayerObject.java b/src/resources/objects/player/PlayerObject.java index dc17b48c2..0cfed02b9 100644 --- a/src/resources/objects/player/PlayerObject.java +++ b/src/resources/objects/player/PlayerObject.java @@ -44,6 +44,8 @@ import resources.player.PlayerFlags; import utilities.MathUtils; import utilities.Encoder.StringType; +import java.util.List; + public class PlayerObject extends IntangibleObject { private static final long serialVersionUID = 1L; @@ -86,8 +88,8 @@ public class PlayerObject extends IntangibleObject { private long nearbyCraftStation = 0; private SWGList draftSchemList = new SWGList<>(BaselineType.PLAY, 9, 3); private int experimentPoints = 0; - private SWGList friendsList = new SWGList<>(BaselineType.PLAY, 9, 7); - private SWGList ignoreList = new SWGList<>(BaselineType.PLAY, 9, 8); + private SWGList friendsList = new SWGList<>(BaselineType.PLAY, 9, 7, StringType.ASCII); + private SWGList ignoreList = new SWGList<>(BaselineType.PLAY, 9, 8, StringType.ASCII); private int languageId = 0; private SWGList defenders = new SWGList<>(BaselineType.PLAY, 9, 17); // TODO: Change to set private int killMeter = 0; @@ -338,6 +340,24 @@ public class PlayerObject extends IntangibleObject { sendDelta(8, 6, activeQuest); } + public void removeFriend(String friend) { + synchronized (friendsList) { + friendsList.remove(friend); + } + friendsList.sendDeltaMessage(this); + } + + public void addFriend(String friend) { + synchronized (friendsList) { + friendsList.add(friend); + } + friendsList.sendDeltaMessage(this); + } + + public List getFriendsList() { + return this.friendsList; + } + public String getProfWheelPosition() { return profWheelPosition; } diff --git a/src/resources/player/Player.java b/src/resources/player/Player.java index 922f57f86..bb06a83cd 100644 --- a/src/resources/player/Player.java +++ b/src/resources/player/Player.java @@ -34,6 +34,7 @@ import resources.control.Service; import resources.objects.SWGObject; import resources.objects.creature.CreatureObject; import resources.objects.player.PlayerObject; +import services.player.PlayerManager; public class Player implements Serializable, Comparable { @@ -63,11 +64,15 @@ public class Player implements Serializable, Comparable { this.playerManager = playerManager; setNetworkId(networkId); } - + + public PlayerManager getPlayerManager() { + return (PlayerManager) playerManager; + } + public void setPlayerManager(Service playerManager) { this.playerManager = playerManager; } - + public void setNetworkId(long networkId) { this.networkId = networkId; } diff --git a/src/services/chat/ChatService.java b/src/services/chat/ChatService.java index 665fb168e..fc7e3011a 100644 --- a/src/services/chat/ChatService.java +++ b/src/services/chat/ChatService.java @@ -27,13 +27,9 @@ ***********************************************************************************/ package services.chat; -import java.util.Date; -import java.util.LinkedList; -import java.util.List; -import java.util.Locale; - import intents.NotifyPlayersPacketIntent; import intents.PlayerEventIntent; +import intents.chat.ChatAvatarRequestIntent; import intents.chat.ChatBroadcastIntent; import intents.chat.PersistentMessageIntent; import intents.chat.SpatialChatIntent; @@ -43,6 +39,7 @@ import network.packets.Packet; import network.packets.swg.SWGPacket; import network.packets.swg.zone.ChatRequestRoomList; import network.packets.swg.zone.chat.ChatDeletePersistentMessage; +import network.packets.swg.zone.chat.ChatFriendsListUpdate; import network.packets.swg.zone.chat.ChatInstantMessageToCharacter; import network.packets.swg.zone.chat.ChatInstantMessageToClient; import network.packets.swg.zone.chat.ChatOnSendInstantMessage; @@ -60,12 +57,19 @@ import resources.encodables.OutOfBand; import resources.encodables.ProsePackage; import resources.encodables.player.Mail; import resources.objects.SWGObject; +import resources.objects.player.PlayerObject; import resources.player.Player; +import resources.player.PlayerState; import resources.server_info.CachedObjectDatabase; import resources.server_info.ObjectDatabase; import resources.server_info.ObjectDatabase.Traverser; import services.player.PlayerManager; +import java.util.Date; +import java.util.LinkedList; +import java.util.List; +import java.util.Locale; + public class ChatService extends Service { private ObjectDatabase mails; @@ -84,6 +88,7 @@ public class ChatService extends Service { registerForIntent(PlayerEventIntent.TYPE); registerForIntent(ChatBroadcastIntent.TYPE); registerForIntent(ServerStatusIntent.TYPE); + registerForIntent(ChatAvatarRequestIntent.TYPE); mails.load(); mails.traverse(new Traverser() { @Override @@ -123,9 +128,13 @@ public class ChatService extends Service { if (i instanceof ChatBroadcastIntent) handleChatBroadcast((ChatBroadcastIntent) i); break; + case ChatAvatarRequestIntent.TYPE: + if (i instanceof ChatAvatarRequestIntent) + handleChatAvatarStatusRequestIntent((ChatAvatarRequestIntent) i); + break; } } - + private void processPacket(GalacticPacketIntent intent) { Player player = intent.getPlayerManager().getPlayerFromNetworkId(intent.getNetworkId()); if (player == null) @@ -164,34 +173,49 @@ public class ChatService extends Service { private void handlePlayerEventIntent(PlayerEventIntent intent) { switch (intent.getEvent()) { - case PE_ZONE_IN: + case PE_FIRST_ZONE: sendPersistentMessageHeaders(intent.getPlayer(), intent.getGalaxy()); + updateChatAvatarStatus(intent.getPlayer(), intent.getGalaxy(), true); + break; + case PE_LOGGED_OUT: + updateChatAvatarStatus(intent.getPlayer(), intent.getGalaxy(), false); break; - default: break; } } - + private void handleChatBroadcast(ChatBroadcastIntent i) { switch(i.getBroadcastType()) { case AREA: broadcastAreaMessage(i.getMessage(), i.getBroadcaster()); break; case PLANET: - broadcastGalaxyMessage(i.getMessage(), i.getTerrain()); // TODO: Planet specific system messages + broadcastPlanetMessage(i.getMessage(), i.getTerrain()); break; case GALAXY: - broadcastGalaxyMessage(i.getMessage(), i.getTerrain()); + broadcastGalaxyMessage(i.getMessage()); break; case PERSONAL: broadcastPersonalMessage(i.getProse(), i.getBroadcaster()); break; } } - - private void handleChatRoomListRequest(Player player, ChatRequestRoomList request) { - + + private void handleChatAvatarStatusRequestIntent(ChatAvatarRequestIntent i) { + switch (i.getRequestType()) { + case TARGET_STATUS: + sendTargetAvatarStatus(i.getPlayer(), i.getTarget()); + break; + case IGNORE_REMOVE_TARGET: + break; + case IGNORE_ADD_TARGET: + break; + } } - + + private void handleChatRoomListRequest(Player player, ChatRequestRoomList request) { + + } + private void handleSpatialChat(SpatialChatIntent i) { Player sender = i.getPlayer(); SWGObject actor = sender.getCreatureObject(); @@ -217,12 +241,12 @@ public class ChatService extends Service { Player receiver = playerMgr.getPlayerByCreatureFirstName(strReceiver); int errorCode = 0; // 0 = No issue, 4 = "strReceiver is not online" - if (receiver == null) + if (receiver == null || receiver.getPlayerState() != PlayerState.ZONED_IN) errorCode = 4; sender.sendPacket(new ChatOnSendInstantMessage(errorCode, request.getSequence())); - if (receiver == null) + if (errorCode == 4) return; receiver.sendPacket(new ChatInstantMessageToClient(request.getGalaxy(), strSender, request.getMessage())); @@ -284,17 +308,72 @@ public class ChatService extends Service { mail.setStatus(Mail.READ); sendPersistentMessage(player, mail, MailFlagType.FULL_MESSAGE, galaxy); } - + + private void updateChatAvatarStatus(Player player, String galaxy, boolean online) { + PlayerManager playerManager = player.getPlayerManager(); + String firstName = player.getCharacterName().toLowerCase(); + if (firstName.contains(" ")) + firstName = firstName.substring(0, firstName.indexOf(' ')); + + if (online) { + PlayerObject playerObject = player.getPlayerObject(); + if (playerObject == null || playerObject.getFriendsList().size() <= 0) + return; + + for (String friend : playerObject.getFriendsList()) { + sendTargetAvatarStatus(player, friend); + } + } + + final ChatFriendsListUpdate update = new ChatFriendsListUpdate(galaxy, firstName, online); + playerManager.notifyPlayersWithCondition(new NotifyPlayersPacketIntent.ConditionalNotify() { + @Override + public boolean meetsCondition(Player player) { + if (player.getPlayerState() != PlayerState.ZONED_IN) + return false; + + PlayerObject playerObject = player.getPlayerObject(); + if (playerObject == null || playerObject.getFriendsList().size() <= 0) + return false; + + List friends = playerObject.getFriendsList(); + if (friends.contains(update.getFriendName())) + return true; + return false; + } + }, update); + } + + private void sendTargetAvatarStatus(Player player, String target) { + PlayerObject object = player.getPlayerObject(); + if (object == null) + return; + + Player targetPlayer = player.getPlayerManager().getPlayerByCreatureFirstName(target); + + boolean online = true; + if (targetPlayer == null || targetPlayer.getPlayerState() != PlayerState.ZONED_IN) + online = false; + + ChatFriendsListUpdate update = new ChatFriendsListUpdate(player.getGalaxyName(), target, online); + player.sendPacket(update); + } + private void broadcastAreaMessage(String message, Player broadcaster) { ChatSystemMessage packet = new ChatSystemMessage(SystemChatType.SCREEN_AND_CHAT.ordinal(), message); broadcaster.sendPacket(packet); broadcaster.getCreatureObject().sendObservers(packet); } - - private void broadcastGalaxyMessage(String message, Terrain terrain) { + + private void broadcastPlanetMessage(String message, Terrain terrain) { ChatSystemMessage packet = new ChatSystemMessage(SystemChatType.SCREEN_AND_CHAT.ordinal(), message); - new NotifyPlayersPacketIntent(packet, terrain).broadcast(); + new NotifyPlayersPacketIntent(packet, terrain, null).broadcast(); + } + + private void broadcastGalaxyMessage(String message) { + ChatSystemMessage packet = new ChatSystemMessage(SystemChatType.SCREEN_AND_CHAT.ordinal(), message); + new NotifyPlayersPacketIntent(packet).broadcast(); } private void broadcastPersonalMessage(ProsePackage prose, Player player) { diff --git a/src/services/galaxy/ConnectionService.java b/src/services/galaxy/ConnectionService.java index 00e5a026c..defdd5aab 100644 --- a/src/services/galaxy/ConnectionService.java +++ b/src/services/galaxy/ConnectionService.java @@ -220,6 +220,7 @@ public class ConnectionService extends Service { disappearPlayers.add(new DisappearPlayer(System.nanoTime(), p)); } updateService.schedule(disappearRunnable, (long) DISAPPEAR_THRESHOLD, TimeUnit.MILLISECONDS); + new PlayerEventIntent(p, p.getGalaxyName(), PlayerEvent.PE_LOGGED_OUT).broadcast(); } } diff --git a/src/services/player/PlayerManager.java b/src/services/player/PlayerManager.java index 8c073a6b0..93aa13654 100644 --- a/src/services/player/PlayerManager.java +++ b/src/services/player/PlayerManager.java @@ -155,7 +155,17 @@ public class PlayerManager extends Manager { } } } - + + public void notifyPlayersWithCondition(NotifyPlayersPacketIntent.ConditionalNotify conditional, Packet... packets) { + synchronized (players) { + for (Player player : players.values()) { + if (conditional.meetsCondition(player)) { + player.sendPacket(packets); + } + } + } + } + public Player getPlayerFromNetworkId(long networkId) { synchronized (players) { return players.get(networkId); @@ -247,10 +257,12 @@ public class PlayerManager extends Manager { } private void onNotifyPlayersPacketIntent(NotifyPlayersPacketIntent nppi) { - if (nppi.getTerrain() != null) + if (nppi.getCondition() != null) { + notifyPlayersWithCondition(nppi.getCondition(), nppi.getPacket()); + } else if (nppi.getTerrain() != null) { notifyPlayersAtPlanet(nppi.getTerrain(), nppi.getPacket()); - else + } else { notifyPlayers(nppi.getPacket()); + } } - }