Changed ChatService to a manager and moved chat room functionality to ChatRoomService under ChatManager

NotifyPlayersPacketIntent can now accept a list of networkId's to notify players with a packet
This commit is contained in:
Waverunner
2015-07-10 10:40:38 -04:00
parent 3816802551
commit 271cb87f9e
6 changed files with 581 additions and 391 deletions
+20 -3
View File
@@ -32,19 +32,35 @@ import resources.Terrain;
import resources.control.Intent;
import resources.player.Player;
import java.util.List;
public class NotifyPlayersPacketIntent extends Intent {
public static final String TYPE = "GalaxyWidePacketIntent";
private Packet packet;
private Terrain terrain;
private List<Long> networkIds;
private ConditionalNotify condition;
public NotifyPlayersPacketIntent(Packet packet, Terrain terrain, ConditionalNotify condition) {
public NotifyPlayersPacketIntent(Packet packet, Terrain terrain, ConditionalNotify condition, List<Long> networkIds) {
super(TYPE);
this.packet = packet;
this.terrain = terrain;
this.condition = condition;
this.networkIds = networkIds;
}
public NotifyPlayersPacketIntent(Packet packet, Terrain terrain, ConditionalNotify condition) {
this(packet, terrain, condition, null);
}
public NotifyPlayersPacketIntent(Packet packet, ConditionalNotify condition, List<Long> networkIds) {
this(packet, null, condition, networkIds);
}
public NotifyPlayersPacketIntent(Packet packet, List<Long> networkIds) {
this(packet, null, null, networkIds);
}
public NotifyPlayersPacketIntent(Packet packet, Terrain terrain) {
@@ -52,12 +68,13 @@ public class NotifyPlayersPacketIntent extends Intent {
}
public NotifyPlayersPacketIntent(Packet p) {
this(p, null, null);
this(p, null, null, null);
}
public Packet getPacket() { return packet; }
public Terrain getTerrain() { return terrain; }
public ConditionalNotify getCondition() { return condition; }
public List<Long> getNetworkIds() { return networkIds; }
public interface ConditionalNotify {
boolean meetsCondition(Player player);
@@ -50,6 +50,7 @@ import resources.chat.ChatResult;
import resources.chat.ChatRoom;
import resources.collections.SWGList;
import resources.control.Intent;
import resources.control.Manager;
import resources.control.Service;
import resources.encodables.OutOfBandPackage;
import resources.encodables.ProsePackage;
@@ -74,26 +75,18 @@ import java.util.Locale;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class ChatService extends Service {
public class ChatManager extends Manager {
// Array of only the valid terrains in relation to zones able to use planetary-based chat
private static final List<Terrain> terrains = Arrays.asList(
Terrain.CORELLIA, Terrain.DANTOOINE, Terrain.DATHOMIR, Terrain.ENDOR, Terrain.KASHYYYK, Terrain.LOK,
Terrain.MUSTAFAR, Terrain.NABOO, Terrain.RORI, Terrain.TATOOINE, Terrain.TALUS, Terrain.YAVIN4
);
private ObjectDatabase<Mail> mails;
private int maxMailId;
private int maxChatRoomId;
private Map<Integer, ChatRoom> roomMap;
// Map to keep track of each player's recent message for a room to prevent duplicates from client
private Map<Long, Map<Integer, Integer>> messages;
private ChatRoomService roomService;
public ChatService() {
roomMap = new HashMap<>();
public ChatManager() {
roomService = new ChatRoomService();
mails = new CachedObjectDatabase<>("odb/mails.db");
maxMailId = 1;
maxChatRoomId = 1;
messages = new ConcurrentHashMap<>();
addChildService(roomService);
}
@Override
@@ -106,14 +99,11 @@ public class ChatService extends Service {
registerForIntent(ServerStatusIntent.TYPE);
registerForIntent(ChatAvatarRequestIntent.TYPE);
registerForIntent(ZonePlayerSwapIntent.TYPE);
registerForIntent(ChatRoomUpdateIntent.TYPE);
mails.load();
mails.traverse(new Traverser<Mail>() {
@Override
public void process(Mail mail) {
if (mail.getId() >= maxMailId)
maxMailId = mail.getId() + 1;
}
mails.traverse(mail -> {
if (mail.getId() >= maxMailId)
maxMailId = mail.getId() + 1;
});
return super.initialize();
}
@@ -150,17 +140,6 @@ public class ChatService extends Service {
if (i instanceof ChatAvatarRequestIntent)
handleChatAvatarStatusRequestIntent((ChatAvatarRequestIntent) i);
break;
case ChatRoomUpdateIntent.TYPE:
if (i instanceof ChatRoomUpdateIntent)
handleChatRoomUpdateIntent((ChatRoomUpdateIntent) i);
break;
}
}
private void handleChatRoomUpdateIntent(ChatRoomUpdateIntent i) {
switch(i.getUpdateType()) {
case CREATE: createRoom(i.getAvatar(), i.isPublic(), i.getPath(), i.getTitle());
default: break;
}
}
@@ -176,35 +155,6 @@ public class ChatService extends Service {
private void processSwgPacket(PlayerManager pm, Player player, String galaxyName, SWGPacket p) {
switch (p.getPacketType()) {
/* Chat Rooms */
case CHAT_QUERY_ROOM:
if (p instanceof ChatQueryRoom)
handleChatQueryRoom(player, (ChatQueryRoom) p);
break;
case CHAT_ENTER_ROOM_BY_ID:
if (!(p instanceof ChatEnterRoomById))
return;
{
ChatEnterRoomById enterRoomById = (ChatEnterRoomById) p;
enterChatChannel(player, enterRoomById.getRoomId(), enterRoomById.getSequence());
}
break;
case CHAT_REMOVE_AVATAR_FROM_ROOM:
if (p instanceof ChatRemoveAvatarFromRoom)
leaveChatChannel(player, ((ChatRemoveAvatarFromRoom) p).getPath());
break;
case CHAT_SEND_TO_ROOM:
if (p instanceof ChatSendToRoom)
handleChatSendToRoom(player, (ChatSendToRoom) p);
break;
case CHAT_REQUEST_ROOM_LIST:
if (p instanceof ChatRequestRoomList)
handleChatRoomListRequest(player);
break;
case CHAT_CREATE_ROOM:
if (p instanceof ChatCreateRoom)
handleChatCreateRoom(player, (ChatCreateRoom) p);
break;
/* Mails */
case CHAT_PERSISTENT_MESSAGE_TO_SERVER:
if (p instanceof ChatPersistentMessageToServer)
@@ -235,12 +185,13 @@ public class ChatService extends Service {
switch (intent.getEvent()) {
case PE_ZONE_IN:
switchPlanetaryChatChannels(player);
roomService.enterPlanetaryChatChannels(player);
break;
case PE_FIRST_ZONE:
sendPersistentMessageHeaders(player, intent.getGalaxy());
updateChatAvatarStatus(player, intent.getGalaxy(), true);
enterJoinedChatChannels(player);
if (player.getPlayerObject() != null)
roomService.enterChatChannels(player, player.getPlayerObject().getJoinedChannels());
break;
case PE_LOGGED_OUT:
if (player.getCreatureObject() == null)
@@ -289,313 +240,8 @@ public class ChatService extends Service {
}
}
/* Chat Rooms */
private void handleChatCreateRoom(Player player, ChatCreateRoom p) {
String path = p.getRoomName();
String title = p.getRoomTitle();
ChatRoom room = getRoom(path);
ChatResult result = ChatResult.SUCCESS;
if (room != null)
result = ChatResult.ROOM_ALREADY_EXISTS;
if (result == ChatResult.SUCCESS) {
room = createRoom(ChatAvatar.getFromPlayer(player), p.isPublic(), path, title);
room.setMuted(p.isModerated());
}
player.sendPacket(new ChatOnCreateRoom(result.getCode(), room, p.getSequence()));
}
private void handleChatSendToRoom(Player player, ChatSendToRoom p) {
ChatResult result = ChatResult.SUCCESS;
ChatRoom room = getRoom(p.getRoomId());
if (room == null)
result = ChatResult.ROOM_INVALID_ID;
if (result != ChatResult.SUCCESS) {
player.sendPacket(new ChatOnSendRoomMessage(result.getCode(), p.getSequence()));
return;
}
if (!incrementMessageCounter(player.getNetworkId(), room.getId(), p.getSequence()))
return;
ChatAvatar avatar = ChatAvatar.getFromPlayer(player);
result = room.canSendMessage(avatar);
// TODO: Check length of messages -- Result 16 is used for too long message
player.sendPacket(new ChatOnSendRoomMessage(result.getCode(), p.getSequence()));
if (result == ChatResult.SUCCESS)
room.sendMessage(avatar, p.getMessage(), p.getOutOfBandPackage(), player.getPlayerManager());
}
private void handleChatQueryRoom(Player player, ChatQueryRoom p) {
ChatRoom room = getRoom(p.getRoomPath()); // No result code is sent for queries
if (room == null)
return;
player.sendPacket(new ChatQueryRoomResults(room, p.getSequence()));
}
private void handleChatRoomListRequest(Player player) {
ChatAvatar avatar = ChatAvatar.getFromPlayer(player);
List<ChatRoom> rooms = new ArrayList<>();
for (ChatRoom chatRoom : roomMap.values()) {
if (!chatRoom.isPublic() && !chatRoom.getInvited().contains(avatar) && !chatRoom.getOwner().equals(avatar))
continue;
rooms.add(chatRoom);
}
ChatRoomList response = new ChatRoomList(rooms);
player.sendPacket(response);
}
private void sendOnEnteredChatRoom(Player player, ChatAvatar avatar, ChatResult result, int id, int sequence) {
ChatOnEnteredRoom onEnteredRoom = new ChatOnEnteredRoom(avatar, id, sequence);
onEnteredRoom.setResult(result.getCode());
player.sendPacket(onEnteredRoom);
}
private void enterJoinedChatChannels(Player player) {
PlayerObject ghost = player.getPlayerObject();
if (ghost == null)
return;
for (String s : ghost.getJoinedChannels()) {
enterChatChannel(player, s);
}
}
private void switchPlanetaryChatChannels(Player player) {
PlayerObject ghost = player.getPlayerObject();
if (ghost == null)
return;
// Leave old zone-only chat channels
String planetEndPath = ".Planet";
for (String channel : ghost.getJoinedChannels()) {
if (channel.endsWith(planetEndPath)) {
leaveChatChannel(player, channel);
} else {
// Better way of doing this?
String[] split = channel.split("\\.");
if (split.length == 3 && split[2].equals("system"))
leaveChatChannel(player, channel);
}
}
Terrain terrain = player.getCreatureObject().getLocation().getTerrain();
// Enter the new zone-only chat channels
if (!terrains.contains(terrain))
return;
String planetPath = "SWG." + player.getGalaxyName() + "." + terrain.getNameCapitalized() + ".";
enterChatChannel(player, planetPath + "Planet");
enterChatChannel(player, planetPath + "system");
}
/**
* Attempts to join the specified chat channel
* @param player Player joining the chat channel
* @param room Chat room to enter
*/
public void enterChatChannel(Player player, ChatRoom room, int sequence) {
ChatAvatar avatar = ChatAvatar.getFromPlayer(player);
PlayerObject ghost = player.getPlayerObject();
if (ghost == null) {
sendOnEnteredChatRoom(player, avatar, ChatResult.NONE, room.getId(), sequence);
return;
}
ChatResult result = room.canJoinRoom(avatar);
if (result != ChatResult.SUCCESS && player.getAccessLevel() != AccessLevel.PLAYER) {
sendOnEnteredChatRoom(player, avatar, result, room.getId(), sequence);
return;
}
// TODO: Check if player is appropriate faction for the room (Rebel and imperial chat rooms)
// Server-based list so we can join chat channels automatically
ghost.addJoinedChannel(room.getPath());
// Re-send the player the room list with just this room as it could have been private/hidden
// This also "refreshes" the client, not sending this will cause a Chat channel unavailable message.
ChatRoomList roomList = new ChatRoomList(room);
player.sendPacket(roomList);
// Notify players of success, it's ChatResult.SUCCESS at this point
player.sendPacket(new ChatOnEnteredRoom(avatar, result.getCode(), room.getId(), sequence));
PlayerManager manager = player.getPlayerManager();
// Notify everyone that a player entered the room
room.sendPacketToMembers(manager, new ChatOnEnteredRoom(avatar, result.getCode(), room.getId(), 0));
room.getMembers().add(avatar);
}
public void enterChatChannel(Player player, int id, int sequence) {
ChatRoom room = getRoom(id);
if (room == null) {
sendOnEnteredChatRoom(player, ChatAvatar.getFromPlayer(player), ChatResult.NONE, id, sequence);
return;
}
enterChatChannel(player, room, sequence);
}
public void enterChatChannel(Player player, String path) {
for (ChatRoom room : roomMap.values()) {
if (room.getPath().equals(path)) {
enterChatChannel(player, room, 0);
return;
}
}
System.err.println("Tried to join a room with a path that does not exist: " + path);
}
public void leaveChatChannel(Player player, ChatRoom room, int sequence) {
ChatAvatar avatar = ChatAvatar.getFromPlayer(player);
PlayerObject ghost = player.getPlayerObject();
if (ghost == null)
return; // ChatOnLeaveRoom doesn't do anything other than for a ChatResult.SUCCESS, so no need to send a fail
if (!room.getMembers().remove(avatar) && !ghost.removeJoinedChannel(room.getPath()))
return;
player.sendPacket(new ChatOnLeaveRoom(avatar, ChatResult.SUCCESS.getCode(), room.getId(), sequence));
room.sendPacketToMembers(player.getPlayerManager(), new ChatOnLeaveRoom(avatar, ChatResult.SUCCESS.getCode(), room.getId(), 0));
}
public void leaveChatChannel(Player player, String path) {
for (ChatRoom chatRoom : roomMap.values()) {
if (chatRoom.getPath().equals(path))
leaveChatChannel(player, chatRoom, 0);
}
}
/**
* Creates a new, non-persistent, chat room with the specified address path.
* @param creator Room creator who will also become the owner of this room
* @param isPublic Determines if the room should be publicly displayed in the channel listing
* @param path Address for the channel (Ex: SWG.serverName.Imperial)
* @param title Descriptive name of the chat channel (Ex: Imperial chat for this galaxy)
* @return {@link ChatRoom}
*/
public ChatRoom createRoom(ChatAvatar creator, boolean isPublic, String path, String title) {
if (path.isEmpty() || path.endsWith("."))
return null;
String base = "SWG." + creator.getGalaxy();
if (!path.startsWith(base) || path.equals(base))
return null;
// All paths should have parents, lets validate to make sure they exist first. Create them if they don't.
int lastIndex = path.lastIndexOf(".");
if (lastIndex != -1) {
String parentPath = path.substring(0, lastIndex);
if (getRoom(parentPath) == null) {
createRoom(creator, isPublic, parentPath, "");
}
}
ChatRoom room = new ChatRoom();
int id = maxChatRoomId;
maxChatRoomId++;
room.setId(id);
room.setOwner(creator);
room.setCreator(creator);
room.setIsPublic(isPublic);
room.setPath(path);
room.setTitle(title);
roomMap.put(id, room);
return room;
}
private void createSystemChannels(String galaxy) {
ChatAvatar systemAvatar = ChatAvatar.getSystemAvatar(galaxy);
// TODO: Move these to a Server Data File?
String basePath = "SWG." + galaxy + ".";
createRoom(systemAvatar, true, basePath + "Galaxy", "public chat for the whole galaxy, cannot create rooms here");
createRoom(systemAvatar, true, basePath + "system", "system messages for this galaxy");
createRoom(systemAvatar, true, basePath + "Chat", "public chat for this galaxy, can create rooms here");
createRoom(systemAvatar, true, basePath + "Imperial", "Imperial chat for this galaxy");
createRoom(systemAvatar, true, basePath + "ImperialWarRoom", "Imperial war room chat for this galaxy");
createRoom(systemAvatar, true, basePath + "Rebel", "Rebel chat for this galaxy");
createRoom(systemAvatar, true, basePath + "RebelWarRoom", "Rebel war room chat for this galaxy");
createRoom(systemAvatar, true, basePath + "BountyHunter", "Bounty Hunter chat for this galaxy");
createRoom(systemAvatar, true, basePath + "Commando", "Commando chat for this galaxy");
createRoom(systemAvatar, true, basePath + "Entertainer", "Entertainer chat for this galaxy");
createRoom(systemAvatar, true, basePath + "ForceSensitive", "Force Sensitive chat for this galaxy");
createRoom(systemAvatar, true, basePath + "Medic", "Medic chat for this galaxy");
createRoom(systemAvatar, true, basePath + "Officer", "Officer chat for this galaxy");
createRoom(systemAvatar, true, basePath + "Pilot", "Pilot chat for this galaxy");
createRoom(systemAvatar, true, basePath + "Politician", "Politician chat for this galaxy");
createRoom(systemAvatar, true, basePath + "Smuggler", "Smuggler chat for this galaxy");
createRoom(systemAvatar, true, basePath + "Spy", "Spy chat for this galaxy");
createRoom(systemAvatar, true, basePath + "Trader", "Trader chat for this galaxy");
createRoom(systemAvatar, true, basePath + "BeastMastery", "Beast Mastery chat for this galaxy");
createRoom(systemAvatar, true, basePath + "Auction", "Auction chat for this galaxy");
createPlanetChannels(systemAvatar, basePath);
}
private void createPlanetChannels(ChatAvatar systemAvatar, String basePath) {
for (Terrain terrain : terrains) {
String path = basePath + terrain.getNameCapitalized() + ".";
createRoom(systemAvatar, true, path + "Planet", "public chat for this planet, cannot create rooms here");
createRoom(systemAvatar, true, path + "system", "system messages for this planet, cannot create rooms here");
createRoom(systemAvatar, true, path + "Chat", "public chat for this planet, can create rooms here");
}
}
private boolean incrementMessageCounter(long networkId, int roomId, int messageId) {
if (networkId == -1) // System ChatAvatar uses -1 for networkId
return true;
Map<Integer, Integer> messageHistory = messages.get(networkId);
if (messageHistory != null) {
if (messageHistory.containsKey(roomId) && messageHistory.get(roomId) == messageId)
return false;
} else {
messageHistory = new HashMap<>();
messages.put(networkId, messageHistory);
}
messageHistory.put(roomId, messageId);
return true;
}
public void initializeGalaxyChannels(Galaxy galaxy) {
createSystemChannels(galaxy.getName());
// TODO: Load up persistent channels
/** Channel Notes
* Group channels: created by System
* - SWG.serverName.group.GroupObjectId.GroupChat title = GroupId
* Guild channels: created by System
* - SWG.serverName.guild.GuildId.GuildChat title = GuildId
* City channels: created by System
* - SWG.serverName.city.CityId.CityChat title = CityId
*/
}
public ChatRoom getRoom(String path) {
for (ChatRoom room : roomMap.values()) {
if (room.getPath().equals(path))
return room;
}
return null;
}
public ChatRoom getRoom(int roomId) {
return roomMap.get(roomId);
roomService.createSystemChannels(galaxy.getName());
}
/* Friends List */
+458
View File
@@ -0,0 +1,458 @@
/*******************************************************************************
* 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 <http://www.gnu.org/licenses/>
******************************************************************************/
package services.chat;
import intents.chat.ChatRoomUpdateIntent;
import intents.network.GalacticPacketIntent;
import network.packets.Packet;
import network.packets.swg.SWGPacket;
import network.packets.swg.zone.chat.ChatCreateRoom;
import network.packets.swg.zone.chat.ChatEnterRoomById;
import network.packets.swg.zone.chat.ChatOnCreateRoom;
import network.packets.swg.zone.chat.ChatOnEnteredRoom;
import network.packets.swg.zone.chat.ChatOnLeaveRoom;
import network.packets.swg.zone.chat.ChatOnSendRoomMessage;
import network.packets.swg.zone.chat.ChatQueryRoom;
import network.packets.swg.zone.chat.ChatQueryRoomResults;
import network.packets.swg.zone.chat.ChatRemoveAvatarFromRoom;
import network.packets.swg.zone.chat.ChatRequestRoomList;
import network.packets.swg.zone.chat.ChatSendToRoom;
import network.packets.swg.zone.insertion.ChatRoomList;
import resources.Terrain;
import resources.chat.ChatAvatar;
import resources.chat.ChatResult;
import resources.chat.ChatRoom;
import resources.control.Intent;
import resources.control.Service;
import resources.objects.player.PlayerObject;
import resources.player.AccessLevel;
import resources.player.Player;
import services.player.PlayerManager;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* @author Waverunner
*/
public class ChatRoomService extends Service {
// Array of only the valid terrains in relation to zones able to use planetary-based chat
private static final List<Terrain> terrains = Arrays.asList(
Terrain.CORELLIA, Terrain.DANTOOINE, Terrain.DATHOMIR, Terrain.ENDOR, Terrain.KASHYYYK, Terrain.LOK,
Terrain.MUSTAFAR, Terrain.NABOO, Terrain.RORI, Terrain.TATOOINE, Terrain.TALUS, Terrain.YAVIN4
);
private int maxChatRoomId;
private Map<Integer, ChatRoom> roomMap;
// Map to keep track of each player's recent message for a room to prevent duplicates from client
private Map<Long, Map<Integer, Integer>> messages;
public ChatRoomService() {
roomMap = new ConcurrentHashMap<>();
messages = new ConcurrentHashMap<>();
maxChatRoomId = 1;
}
@Override
public boolean initialize() {
// TODO: Load up persistent channels
registerForIntent(ChatRoomUpdateIntent.TYPE);
registerForIntent(GalacticPacketIntent.TYPE);
return super.initialize();
}
@Override
public void onIntentReceived(Intent i) {
switch(i.getType()) {
case ChatRoomUpdateIntent.TYPE:
processChatRoomUpdateIntent((ChatRoomUpdateIntent) i);
break;
case GalacticPacketIntent.TYPE:
processPacket((GalacticPacketIntent) i);
break;
}
}
private void processPacket(GalacticPacketIntent intent) {
Player player = intent.getPlayerManager().getPlayerFromNetworkId(intent.getNetworkId());
if (player == null)
return;
Packet p = intent.getPacket();
if (p instanceof SWGPacket)
processSwgPacket(player, (SWGPacket) p);
}
private void processSwgPacket(Player player, SWGPacket p) {
switch (p.getPacketType()) {
case CHAT_QUERY_ROOM:
if (p instanceof ChatQueryRoom) handleChatQueryRoom(player, (ChatQueryRoom) p);
break;
case CHAT_ENTER_ROOM_BY_ID: {
if (!(p instanceof ChatEnterRoomById)) return;
ChatEnterRoomById enterRoomById = (ChatEnterRoomById) p;
enterChatChannel(player, enterRoomById.getRoomId(), enterRoomById.getSequence());
break; }
case CHAT_REMOVE_AVATAR_FROM_ROOM:
if (p instanceof ChatRemoveAvatarFromRoom)
leaveChatChannel(player, ((ChatRemoveAvatarFromRoom) p).getPath());
break;
case CHAT_SEND_TO_ROOM:
if (p instanceof ChatSendToRoom) handleChatSendToRoom(player, (ChatSendToRoom) p);
break;
case CHAT_REQUEST_ROOM_LIST:
if (p instanceof ChatRequestRoomList)
handleChatRoomListRequest(player);
break;
case CHAT_CREATE_ROOM:
if (p instanceof ChatCreateRoom) handleChatCreateRoom(player, (ChatCreateRoom) p);
break;
}
}
private void processChatRoomUpdateIntent(ChatRoomUpdateIntent i) {
switch(i.getUpdateType()) {
case CREATE: createRoom(i.getAvatar(), i.isPublic(), i.getPath(), i.getTitle()); break;
default: break;
}
}
/* Chat Rooms */
private void handleChatCreateRoom(Player player, ChatCreateRoom p) {
String path = p.getRoomName();
String title = p.getRoomTitle();
ChatRoom room = getRoom(path);
ChatResult result = ChatResult.SUCCESS;
if (room != null)
result = ChatResult.ROOM_ALREADY_EXISTS;
if (result == ChatResult.SUCCESS) {
room = createRoom(ChatAvatar.getFromPlayer(player), p.isPublic(), path, title);
room.setMuted(p.isModerated());
}
player.sendPacket(new ChatOnCreateRoom(result.getCode(), room, p.getSequence()));
}
private void handleChatSendToRoom(Player player, ChatSendToRoom p) {
ChatResult result = ChatResult.SUCCESS;
ChatRoom room = getRoom(p.getRoomId());
if (room == null)
result = ChatResult.ROOM_INVALID_ID;
if (result != ChatResult.SUCCESS) {
player.sendPacket(new ChatOnSendRoomMessage(result.getCode(), p.getSequence()));
return;
}
if (!incrementMessageCounter(player.getNetworkId(), room.getId(), p.getSequence()))
return;
ChatAvatar avatar = ChatAvatar.getFromPlayer(player);
result = room.canSendMessage(avatar);
// TODO: Check length of messages -- Result 16 is used for too long message
player.sendPacket(new ChatOnSendRoomMessage(result.getCode(), p.getSequence()));
if (result == ChatResult.SUCCESS)
room.sendMessage(avatar, p.getMessage(), p.getOutOfBandPackage(), player.getPlayerManager());
}
private void handleChatQueryRoom(Player player, ChatQueryRoom p) {
ChatRoom room = getRoom(p.getRoomPath()); // No result code is sent for queries
if (room == null)
return;
player.sendPacket(new ChatQueryRoomResults(room, p.getSequence()));
}
private void handleChatRoomListRequest(Player player) {
ChatAvatar avatar = ChatAvatar.getFromPlayer(player);
List<ChatRoom> rooms = new ArrayList<>();
for (ChatRoom chatRoom : roomMap.values()) {
if (!chatRoom.isPublic() && !chatRoom.getInvited().contains(avatar) && !chatRoom.getOwner().equals(avatar))
continue;
rooms.add(chatRoom);
}
ChatRoomList response = new ChatRoomList(rooms);
player.sendPacket(response);
}
private void sendOnEnteredChatRoom(Player player, ChatAvatar avatar, ChatResult result, int id, int sequence) {
ChatOnEnteredRoom onEnteredRoom = new ChatOnEnteredRoom(avatar, id, sequence);
onEnteredRoom.setResult(result.getCode());
player.sendPacket(onEnteredRoom);
}
public void enterChatChannels(Player player, List<String> channels) {
for (String s : channels) {
enterChatChannel(player, s);
}
}
public void enterPlanetaryChatChannels(Player player) {
PlayerObject ghost = player.getPlayerObject();
if (ghost == null)
return;
// Leave old zone-only chat channels
String planetEndPath = ".Planet";
for (String channel : ghost.getJoinedChannels()) {
if (channel.endsWith(planetEndPath)) {
leaveChatChannel(player, channel);
} else {
// Better way of doing this?
String[] split = channel.split("\\.");
if (split.length == 3 && split[2].equals("system"))
leaveChatChannel(player, channel);
}
}
Terrain terrain = player.getCreatureObject().getLocation().getTerrain();
// Enter the new zone-only chat channels
if (!terrains.contains(terrain))
return;
String planetPath = "SWG." + player.getGalaxyName() + "." + terrain.getNameCapitalized() + ".";
enterChatChannel(player, planetPath + "Planet");
enterChatChannel(player, planetPath + "system");
}
/**
* Attempts to join the specified chat channel
* @param player Player joining the chat channel
* @param room Chat room to enter
*/
public void enterChatChannel(Player player, ChatRoom room, int sequence) {
ChatAvatar avatar = ChatAvatar.getFromPlayer(player);
PlayerObject ghost = player.getPlayerObject();
if (ghost == null) {
sendOnEnteredChatRoom(player, avatar, ChatResult.NONE, room.getId(), sequence);
return;
}
ChatResult result = room.canJoinRoom(avatar);
if (result != ChatResult.SUCCESS && player.getAccessLevel() != AccessLevel.PLAYER) {
sendOnEnteredChatRoom(player, avatar, result, room.getId(), sequence);
return;
}
// TODO: Check if player is appropriate faction for the room (Rebel and imperial chat rooms)
// Server-based list so we can join chat channels automatically
ghost.addJoinedChannel(room.getPath());
// Re-send the player the room list with just this room as it could have been private/hidden
// This also "refreshes" the client, not sending this will cause a Chat channel unavailable message.
ChatRoomList roomList = new ChatRoomList(room);
player.sendPacket(roomList);
// Notify players of success, it's ChatResult.SUCCESS at this point
player.sendPacket(new ChatOnEnteredRoom(avatar, result.getCode(), room.getId(), sequence));
PlayerManager manager = player.getPlayerManager();
// Notify everyone that a player entered the room
room.sendPacketToMembers(manager, new ChatOnEnteredRoom(avatar, result.getCode(), room.getId(), 0));
room.getMembers().add(avatar);
}
public void enterChatChannel(Player player, int id, int sequence) {
ChatRoom room = getRoom(id);
if (room == null) {
sendOnEnteredChatRoom(player, ChatAvatar.getFromPlayer(player), ChatResult.NONE, id, sequence);
return;
}
enterChatChannel(player, room, sequence);
}
public void enterChatChannel(Player player, String path) {
for (ChatRoom room : roomMap.values()) {
if (room.getPath().equals(path)) {
enterChatChannel(player, room, 0);
return;
}
}
System.err.println("Tried to join a room with a path that does not exist: " + path);
}
public void leaveChatChannel(Player player, ChatRoom room, int sequence) {
ChatAvatar avatar = ChatAvatar.getFromPlayer(player);
PlayerObject ghost = player.getPlayerObject();
if (ghost == null)
return; // ChatOnLeaveRoom doesn't do anything other than for a ChatResult.SUCCESS, so no need to send a fail
if (!room.getMembers().remove(avatar) && !ghost.removeJoinedChannel(room.getPath()))
return;
player.sendPacket(new ChatOnLeaveRoom(avatar, ChatResult.SUCCESS.getCode(), room.getId(), sequence));
room.sendPacketToMembers(player.getPlayerManager(), new ChatOnLeaveRoom(avatar, ChatResult.SUCCESS.getCode(), room.getId(), 0));
}
public void leaveChatChannel(Player player, String path) {
for (ChatRoom chatRoom : roomMap.values()) {
if (chatRoom.getPath().equals(path))
leaveChatChannel(player, chatRoom, 0);
}
}
/**
* Creates a new, non-persistent, chat room with the specified address path.
* @param creator Room creator who will also become the owner of this room
* @param isPublic Determines if the room should be publicly displayed in the channel listing
* @param path Address for the channel (Ex: SWG.serverName.Imperial)
* @param title Descriptive name of the chat channel (Ex: Imperial chat for this galaxy)
* @return {@link ChatRoom}
*/
public ChatRoom createRoom(ChatAvatar creator, boolean isPublic, String path, String title) {
if (path.isEmpty() || path.endsWith("."))
return null;
String base = "SWG." + creator.getGalaxy();
if (!path.startsWith(base) || path.equals(base))
return null;
// All paths should have parents, lets validate to make sure they exist first. Create them if they don't.
int lastIndex = path.lastIndexOf(".");
if (lastIndex != -1) {
String parentPath = path.substring(0, lastIndex);
if (getRoom(parentPath) == null) {
createRoom(creator, isPublic, parentPath, "");
}
}
ChatRoom room = new ChatRoom();
int id = maxChatRoomId;
maxChatRoomId++;
room.setId(id);
room.setOwner(creator);
room.setCreator(creator);
room.setIsPublic(isPublic);
room.setPath(path);
room.setTitle(title);
roomMap.put(id, room);
return room;
}
public boolean destroyRoom(ChatRoom room) {
// Remove existing, online, members from the room
// Remove room from map and database
// Remove roompath from joinedChannels list if player tried to join an invalid room
return false;
}
public void createSystemChannels(String galaxy) {
/** Channel Notes
* Group channels: created by System
* - SWG.serverName.group.GroupObjectId.GroupChat title = GroupId
* Guild channels: created by System
* - SWG.serverName.guild.GuildId.GuildChat title = GuildId
* City channels: created by System
* - SWG.serverName.city.CityId.CityChat title = CityId
*/
ChatAvatar systemAvatar = ChatAvatar.getSystemAvatar(galaxy);
// TODO: Move to server datatable file (SDF): Room (s) | Title (s) | Private (b)
String basePath = "SWG." + galaxy + ".";
createRoom(systemAvatar, true, basePath + "Galaxy", "public chat for the whole galaxy, cannot create rooms here");
createRoom(systemAvatar, true, basePath + "system", "system messages for this galaxy");
createRoom(systemAvatar, true, basePath + "Chat", "public chat for this galaxy, can create rooms here");
createRoom(systemAvatar, true, basePath + "Imperial", "Imperial chat for this galaxy");
createRoom(systemAvatar, true, basePath + "ImperialWarRoom", "Imperial war room chat for this galaxy");
createRoom(systemAvatar, true, basePath + "Rebel", "Rebel chat for this galaxy");
createRoom(systemAvatar, true, basePath + "RebelWarRoom", "Rebel war room chat for this galaxy");
createRoom(systemAvatar, true, basePath + "BountyHunter", "Bounty Hunter chat for this galaxy");
createRoom(systemAvatar, true, basePath + "Commando", "Commando chat for this galaxy");
createRoom(systemAvatar, true, basePath + "Entertainer", "Entertainer chat for this galaxy");
createRoom(systemAvatar, true, basePath + "ForceSensitive", "Force Sensitive chat for this galaxy");
createRoom(systemAvatar, true, basePath + "Medic", "Medic chat for this galaxy");
createRoom(systemAvatar, true, basePath + "Officer", "Officer chat for this galaxy");
createRoom(systemAvatar, true, basePath + "Pilot", "Pilot chat for this galaxy");
createRoom(systemAvatar, true, basePath + "Politician", "Politician chat for this galaxy");
createRoom(systemAvatar, true, basePath + "Smuggler", "Smuggler chat for this galaxy");
createRoom(systemAvatar, true, basePath + "Spy", "Spy chat for this galaxy");
createRoom(systemAvatar, true, basePath + "Trader", "Trader chat for this galaxy");
createRoom(systemAvatar, true, basePath + "BeastMastery", "Beast Mastery chat for this galaxy");
createRoom(systemAvatar, true, basePath + "Auction", "Auction chat for this galaxy");
createPlanetChannels(systemAvatar, basePath);
}
private void createPlanetChannels(ChatAvatar systemAvatar, String basePath) {
// TODO: Move planets to a server datatable file (SDF): Planet (s)
for (Terrain terrain : terrains) {
String path = basePath + terrain.getNameCapitalized() + ".";
createRoom(systemAvatar, true, path + "Planet", "public chat for this planet, cannot create rooms here");
createRoom(systemAvatar, true, path + "system", "system messages for this planet, cannot create rooms here");
createRoom(systemAvatar, true, path + "Chat", "public chat for this planet, can create rooms here");
}
}
private boolean incrementMessageCounter(long networkId, int roomId, int messageId) {
if (networkId == -1) // System ChatAvatar uses -1 for networkId
return true;
Map<Integer, Integer> messageHistory = messages.get(networkId);
if (messageHistory != null) {
if (messageHistory.containsKey(roomId) && messageHistory.get(roomId) == messageId)
return false;
} else {
messageHistory = new HashMap<>();
messages.put(networkId, messageHistory);
}
messageHistory.put(roomId, messageId);
return true;
}
public ChatRoom getRoom(String path) {
for (ChatRoom room : roomMap.values()) {
if (room.getPath().equals(path))
return room;
}
return null;
}
public ChatRoom getRoom(int roomId) {
return roomMap.get(roomId);
}
}
+5 -5
View File
@@ -33,7 +33,7 @@ import intents.network.InboundPacketIntent;
import resources.Galaxy;
import resources.control.Intent;
import resources.control.Manager;
import services.chat.ChatService;
import services.chat.ChatManager;
import services.objects.ObjectManager;
import services.player.PlayerManager;
@@ -44,7 +44,7 @@ public class GalacticManager extends Manager {
private ObjectManager objectManager;
private PlayerManager playerManager;
private GameManager gameManager;
private ChatService chatService;
private ChatManager chatManager;
private Intent prevPacketIntent;
private Galaxy galaxy;
@@ -53,19 +53,19 @@ public class GalacticManager extends Manager {
objectManager = new ObjectManager();
playerManager = new PlayerManager();
gameManager = new GameManager();
chatService = new ChatService();
chatManager = new ChatManager();
prevPacketIntent = null;
addChildService(objectManager);
addChildService(playerManager);
addChildService(gameManager);
addChildService(chatService);
addChildService(chatManager);
}
@Override
public boolean initialize() {
registerForIntent(InboundPacketIntent.TYPE);
chatService.initializeGalaxyChannels(galaxy);
chatManager.initializeGalaxyChannels(galaxy);
return super.initialize();
}
-1
View File
@@ -28,7 +28,6 @@
package services.galaxy;
import resources.control.Manager;
import services.chat.ChatService;
import services.commands.CommandService;
import services.sui.SuiService;
+83 -13
View File
@@ -31,6 +31,7 @@ import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
@@ -149,7 +150,61 @@ public class PlayerManager extends Manager {
}
}
}
public void notifyPlayers(NotifyPlayersPacketIntent.ConditionalNotify conditional, Packet... packets) {
if (conditional == null) {
notifyPlayers(packets);
return;
}
synchronized (players) {
for (Player player : players.values()) {
if (conditional.meetsCondition(player)) {
player.sendPacket(packets);
}
}
}
}
public void notifyPlayers(List<Long> networkIds, NotifyPlayersPacketIntent.ConditionalNotify conditionalNotify, Packet... packets) {
if (conditionalNotify == null) {
notifyPlayers(networkIds, packets);
return;
}
synchronized (players) {
networkIds.forEach(id -> {
Player p = players.get(id);
if (p != null && p.getCreatureObject() != null && conditionalNotify.meetsCondition(p))
p.sendPacket(packets);
});
}
}
public void notifyPlayers(List<Long> networkIds, Packet... packets) {
synchronized (players) {
networkIds.forEach(id -> {
Player p = players.get(id);
if (p != null && p.getCreatureObject() != null)
p.sendPacket(packets);
});
}
}
public void notifyPlayersAtPlanet(NotifyPlayersPacketIntent.ConditionalNotify conditional, Terrain terrain, Packet... packets) {
if (conditional == null) {
notifyPlayersAtPlanet(terrain, packets);
return;
}
synchronized(players) {
for (Player p : players.values()) {
if (p != null && p.getCreatureObject() != null && p.getCreatureObject().getLocation().getTerrain() == terrain && conditional.meetsCondition(p))
p.sendPacket(packets);
}
}
}
public void notifyPlayersAtPlanet(Terrain terrain, Packet... packets) {
synchronized(players) {
for (Player p : players.values()) {
@@ -159,13 +214,28 @@ 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 void notifyPlayersAtPlanet(List<Long> networkIds, NotifyPlayersPacketIntent.ConditionalNotify conditional, Terrain terrain, Packet... packets) {
if(conditional == null) {
notifyPlayersAtPlanet(networkIds, terrain, packets);
return;
}
synchronized(players) {
networkIds.forEach(id -> {
Player p = players.get(id);
if (p != null && p.getCreatureObject() != null && p.getCreatureObject().getLocation().getTerrain() == terrain && conditional.meetsCondition(p))
p.sendPacket(packets);
});
}
}
public void notifyPlayersAtPlanet(List<Long> networkIds, Terrain terrain, Packet... packets) {
synchronized(players) {
networkIds.forEach(id -> {
Player p = players.get(id);
if (p != null && p.getCreatureObject() != null && p.getCreatureObject().getLocation().getTerrain() == terrain)
p.sendPacket(packets);
});
}
}
@@ -260,12 +330,12 @@ public class PlayerManager extends Manager {
}
private void onNotifyPlayersPacketIntent(NotifyPlayersPacketIntent nppi) {
if (nppi.getCondition() != null) {
notifyPlayersWithCondition(nppi.getCondition(), nppi.getPacket());
} else if (nppi.getTerrain() != null) {
notifyPlayersAtPlanet(nppi.getTerrain(), nppi.getPacket());
if (nppi.getNetworkIds() != null) {
if (nppi.getTerrain() != null) notifyPlayersAtPlanet(nppi.getNetworkIds(), nppi.getCondition(), nppi.getTerrain(), nppi.getPacket());
else notifyPlayers(nppi.getNetworkIds(), nppi.getCondition(), nppi.getPacket());
} else {
notifyPlayers(nppi.getPacket());
if (nppi.getTerrain() != null) notifyPlayersAtPlanet(nppi.getCondition(), nppi.getTerrain(), nppi.getPacket());
else notifyPlayers(nppi.getCondition(), nppi.getPacket());
}
}
}