Files
src-1.2/engine/server/application/ChatServer/src/shared/ChatInterface.cpp
T

3198 lines
112 KiB
C++
Executable File

// ChatInterface.cpp
// Copyright 2000-02, Sony Online Entertainment Inc., all rights reserved.
// Author: Justin Randall
//-----------------------------------------------------------------------
#include "FirstChatServer.h"
#include "ChatAPI/ChatAvatar.h"
#include "ChatInterface.h"
#include "ChatAPI/ChatFriendStatus.h"
#include "ChatAPI/ChatIgnoreStatus.h"
#include "ChatAPI/ChatRoom.h"
#include "ChatAPI/PersistentMessage.h"
#include "ChatAPI/ChatEnum.h"
#include "ChatServer.h"
#include "ChatServerAvatarOwner.h"
#include "ConfigChatServer.h"
#include "ConnectionServerConnection.h"
#include "GameServerConnection.h"
#include "sharedDebug/Profiler.h"
#include "sharedFoundation/Clock.h"
#include "sharedFoundation/NetworkIdArchive.h"
#include "sharedLog/Log.h"
#include "sharedNetwork/Service.h"
#include "sharedNetworkMessages/ChatFriendsListUpdate.h"
#include "sharedNetworkMessages/ChatInstantMessageToClient.h"
#include "sharedNetworkMessages/ChatOnAddFriend.h"
#include "sharedNetworkMessages/ChatOnAddModeratorToRoom.h"
#include "sharedNetworkMessages/ChatOnBanAvatarFromRoom.h"
#include "sharedNetworkMessages/ChatOnChangeFriendStatus.h"
#include "sharedNetworkMessages/ChatOnChangeIgnoreStatus.h"
#include "sharedNetworkMessages/ChatOnConnectAvatar.h"
#include "sharedNetworkMessages/ChatOnCreateRoom.h"
#include "sharedNetworkMessages/ChatOnDeleteAllPersistentMessages.h"
#include "sharedNetworkMessages/ChatOnDestroyRoom.h"
#include "sharedNetworkMessages/ChatOnEnteredRoom.h"
#include "sharedNetworkMessages/ChatOnGetFriendsList.h"
#include "sharedNetworkMessages/ChatOnGetIgnoreList.h"
#include "sharedNetworkMessages/ChatOnInviteToRoom.h"
#include "sharedNetworkMessages/ChatOnKickAvatarFromRoom.h"
#include "sharedNetworkMessages/ChatOnLeaveRoom.h"
#include "sharedNetworkMessages/ChatOnReceiveRoomInvitation.h"
#include "sharedNetworkMessages/ChatOnRemoveModeratorFromRoom.h"
#include "sharedNetworkMessages/ChatOnSendInstantMessage.h"
#include "sharedNetworkMessages/ChatOnSendPersistentMessage.h"
#include "sharedNetworkMessages/ChatOnSendRoomInvitation.h"
#include "sharedNetworkMessages/ChatOnSendRoomMessage.h"
#include "sharedNetworkMessages/ChatOnUnbanAvatarFromRoom.h"
#include "sharedNetworkMessages/ChatOnUninviteFromRoom.h"
#include "sharedNetworkMessages/ChatQueryRoomResults.h"
#include "sharedNetworkMessages/ChatPersistentMessageToClient.h"
#include "sharedNetworkMessages/ChatQueryRoomResults.h"
#include "sharedNetworkMessages/ChatRoomData.h"
#include "sharedNetworkMessages/ChatRoomList.h"
#include "sharedNetworkMessages/ChatRoomMessage.h"
#include "sharedNetworkMessages/ChatSystemMessage.h"
#include "sharedNetworkMessages/GenericValueTypeMessage.h"
#include "StringId.h"
#include "unicodeArchive/UnicodeArchive.h"
#include "UnicodeUtils.h"
#include <cstdio>
using namespace ChatSystem;
//----------------------------------------------------------------------
namespace ChatInterfaceNamespace
{
char convertPmStatus (const int value)
{
if (value == ChatSystem::PERSISTENT_NEW)
return 'N';
else if (value == ChatSystem::PERSISTENT_UNREAD)
return 'U';
else if (value == ChatSystem::PERSISTENT_READ)
return 'R';
else if (value == ChatSystem::PERSISTENT_TRASH)
return 'T';
else if (value == ChatSystem::PERSISTENT_DELETED)
return 'D';
return 0;
}
// Control log output for chat room related methods
bool const s_enableChatRoomLogs = false;
static int s_intervalToSendHeadersToClientSeconds;
static int s_maxHeadersToSendToClientPerInterval;
// to prevent sending duplicate room chat message
std::unordered_map<unsigned, std::pair<unsigned, unsigned> > s_mostRecentRoomChatMessage;
}
using namespace ChatInterfaceNamespace;
//----------------------------------------------------------------------
//----------------------------------------------------------------------
void splitRoomName(std::string roomName, Unicode::String &name, Unicode::String &address)
{
if (roomName.find("SOE") != 0)
{
roomName = "SOE." + roomName;
}
size_t pos = roomName.find(".");
while (pos != std::string::npos)
{
roomName[pos] = '+';
pos = roomName.find(".");
}
pos = roomName.rfind("+");
if (pos != std::string::npos)
{
address = Unicode::narrowToWide(roomName.substr(0, pos));
name = Unicode::narrowToWide(roomName.substr(pos+1));
}
/*char *tmp = roomName.c_str();
char *loc = tmp;
int numPlus = 0;
while (*loc != 0)
{
if (*loc == '+')
{
numPlus++;
}
if (numPlus == 3)
{
//i.e SOE.SWG.bria
*loc = 0;
address = Unicode::narrowToWide(std::string(tmp));
name = Unicode::narrowToWide(std::string(loc+1));
}
++loc;
*/
}
//-----------------------------------------------------------------------
void makeAvatarId(const ChatUnicodeString &name, const ChatUnicodeString &addr, ChatAvatarId &id)
{
std::string address = Unicode::wideToNarrow(Unicode::String(addr.string_data, addr.string_length));
if ((address.find("SOE") == 0) && (address.length() > 4))
{
address = address.substr(4);
}
else
{
DEBUG_WARNING(true, ("makeAvatarId() received an invalid address"));
}
char text[1024];
snprintf(text, sizeof(text), "%s", address.c_str());
char *loc = strstr(text, "+");
if (loc)
{
*loc = 0;
id.gameCode = text;
id.cluster = (loc+1);
id.name = Unicode::wideToNarrow(Unicode::String(name.string_data, name.string_length));
//tmp, due to a bug in the backend.
if (id.gameCode == "PS")
{
id.gameCode = "SWG";
}
}
}
//-----------------------------------------------------------------------
void makeAvatarId(const ChatAvatar & avatar, ChatAvatarId & id)
{
makeAvatarId(avatar.getName(), avatar.getAddress(), id);
}
//-----------------------------------------------------------------------
void makeRoomName(const ChatUnicodeString &roomAddress, std::string &name)
{
std::string narrowRoomAddress = Unicode::wideToNarrow(Unicode::String(roomAddress.string_data,roomAddress.string_length));
if ((narrowRoomAddress.find("SOE") == 0) && (narrowRoomAddress.length() > 4))
{
narrowRoomAddress = narrowRoomAddress.substr(4);
}
name = narrowRoomAddress;
size_t pos = name.find("+");
while (pos != std::string::npos)
{
name[pos] = '.';
pos = name.find("+");
}
}
//-----------------------------------------------------------------------
void makeRoomName(const ChatRoom *room, std::string &name)
{
name.clear();
if (room)
{
makeRoomName(room->getAddress(), name);
}
}
//-----------------------------------------------------------------------
void makeRoomName(const RoomSummary *room, std::string &name)
{
name.clear();
if (room)
{
makeRoomName(room->getRoomAddress(), name);
}
}
//-----------------------------------------------------------------------
void makeRoomData(const ChatRoom & room, ChatRoomData & roomData)
{
NOT_NULL(&room);
roomData.id = room.getRoomID();
if (room.getRoomAttributes() & ROOMATTR_PRIVATE)
{
roomData.roomType = CHAT_ROOM_PRIVATE;
}
else
{
roomData.roomType = CHAT_ROOM_PUBLIC;
}
if (room.getRoomAttributes() & ROOMATTR_MODERATED)
{
roomData.moderated = 1;
}
makeRoomName(&room, roomData.path);
makeAvatarId(room.getCreatorName(), room.getCreatorAddress(), roomData.owner);
makeAvatarId(room.getCreatorName(), room.getCreatorAddress(), roomData.creator);
roomData.title = Unicode::String(room.getRoomTopic().string_data, room.getRoomTopic().string_length);
roomData.moderators.clear();
ModeratorIterator m = room.getFirstModerator();
for(; !m.outOfBounds(); ++m)
{
ChatAvatarId id;
makeAvatarId(*(*m), id);
roomData.moderators.push_back(id);
}
roomData.invitees.clear();
InviteIterator i = room.getFirstInvited();
for(; !i.outOfBounds(); ++i)
{
ChatAvatarId id;
makeAvatarId(*(*i), id);
roomData.invitees.push_back(id);
}
}
//-----------------------------------------------------------------------
ChatInterface::ChatInterface( const std::string & strGameCode,
const std::string & strGatewayServerIP,
const unsigned short sGatewayServerPort,
const std::string & registrarHost,
const unsigned short registrarPort) :
ChatAPI(registrarHost.c_str(), registrarPort, strGatewayServerIP.c_str(), sGatewayServerPort),
avatarMap(),
pendingAvatars(),
pendingRoomQueries(),
roomQueriesThisFrame(0),
roomList(),
deferredChatMessages(),
queuedHeaders(),
trackingRequestGetAnyAvatarForDestroy()
{
ChatServer::fileLog(true, "ChatInterface", "connecting to API (gameCode=%s, gatewayServer=%s:%d registrar=%s:%d", strGameCode.c_str(), strGatewayServerIP.c_str(), sGatewayServerPort, registrarHost.c_str(), registrarPort);
UNREF(strGameCode);
s_intervalToSendHeadersToClientSeconds = ConfigChatServer::getIntervalToSendHeadersToClientSeconds();
s_maxHeadersToSendToClientPerInterval = ConfigChatServer::getMaxHeadersToSendToClientPerInterval();
}
//-----------------------------------------------------------------------
ChatInterface::~ChatInterface()
{
for (std::map<ChatAvatarId, std::pair<unsigned long, std::deque<const ChatPersistentMessageToClient *> > >::const_iterator iter = queuedHeaders.begin(); iter != queuedHeaders.end(); ++iter)
{
for (std::deque<const ChatPersistentMessageToClient *>::const_iterator iter2 = iter->second.second.begin(); iter2 != iter->second.second.end(); ++iter2)
delete *iter2;
}
queuedHeaders.clear();
}
//-----------------------------------------------------------------------
void ChatInterface::OnConnect()
{
ChatServer::fileLog(true, "ChatInterface", "OnConnect() ChatAPI has established connection to the ChatServer backend and is ready to accept requests. Connecting SYSTEM avatar.");
ConnectPlayer(10, "SYSTEM", NetworkId::cms_invalid);
}
//-----------------------------------------------------------------------
void ChatInterface::OnDisconnect()
{
ChatServer::fileLog(true, "ChatInterface", "OnDisconnect() ChatAPI has lost connection to the ChatServer backend. This may be followed by an OnFailoverBegin command if the connection is re-established and failover mode is initiated.");
}
//-----------------------------------------------------------------------
void ChatInterface::OnFailoverBegin()
{
ChatServer::fileLog(true, "ChatInterface", "OnFailoverBegin() ChatAPI has restored connection to the ChatServer backend and is attempting failover to restore validity of its state. It is retaining its queued requests for server submission upon OnFailoverComplete.");
}
//-----------------------------------------------------------------------
void ChatInterface::OnFailoverComplete()
{
ChatServer::fileLog(true, "ChatInterface", "OnFailoverComplete() ChatAPI has restored its connection to the ChatServer backend and restored its state. It is submitting the queued requests and ready to accept new requests.");
}
//-----------------------------------------------------------------------
void ChatInterface::OnGetRoom(unsigned track, unsigned result, const ChatRoom *room, void *user)
{
ChatServer::fileLog(s_enableChatRoomLogs, "ChatInterface", "OnGetRoom() track(%u) result(%u) room(%s)", track, result, ChatServer::getChatRoomNameNarrow(room).c_str());
PROFILER_AUTO_BLOCK_DEFINE("ChatInterface - OnGetRoom");
if (result != CHATRESULT_SUCCESS || !room)
{
return;
}
std::string roomName;
if (room)
makeRoomName(room, roomName);
//printf("!!!!!!!!!!!!got room %s\n", roomName.c_str());
if (strstr(roomName.c_str(), "group") == NULL)
{
ChatServer::putSystemAvatarInRoom(roomName);
}
std::string lowerRoomName = toLower(roomName);
unsigned sequence = (unsigned)user;
std::unordered_map<std::string, ChatServerRoomOwner>::iterator f = roomList.find(lowerRoomName);
if (f != roomList.end() && room)
{
(*f).second.updateRoomData(room);
}
else
{
if (room)
{
ChatServerRoomOwner * o = new ChatServerRoomOwner(room);
IGNORE_RETURN(roomList.insert(std::make_pair(lowerRoomName, *o)));
delete o;
}
}
ChatServerRoomOwner *owner = NULL;
if (room)
owner = getRoomOwner(room->getRoomID());
if (owner)
{
ChatAvatarId av;
std::vector<ChatAvatarId> avatars;
if(room)
{
for(AvatarIterator a = room->getFirstAvatar(); !a.outOfBounds(); ++a)
{
makeAvatarId(*(*a), av);
avatars.push_back(av);
}
std::vector<ChatAvatarId> moderators;
for(ModeratorIterator m = room->getFirstModerator(); !m.outOfBounds(); ++m)
{
makeAvatarId(*(*m), av);
moderators.push_back(av);
}
std::vector<ChatAvatarId> invitees;
for(InviteIterator i = room->getFirstInvited(); !i.outOfBounds(); ++i)
{
makeAvatarId(*(*i), av);
invitees.push_back(av);
}
std::vector<ChatAvatarId> banned;
for(BanIterator b = room->getFirstBanned(); !b.outOfBounds(); ++b)
{
makeAvatarId(*(*b), av);
banned.push_back(av);
}
ChatQueryRoomResults results(sequence, owner->getRoomData(), avatars, moderators, invitees, banned);
ChatServer::sendResponseForTrackId(track, results);
}
}
}
//-----------------------------------------------------------------------
void ChatInterface::queryRoom(const NetworkId & id, ConnectionServerConnection * connection, const unsigned int sequence, const std::string & roomName)
{
UNREF(connection);
ChatServer::fileLog(s_enableChatRoomLogs, "ChatInterface", "queryRoom() id(%s) connection(%s) sequence(%u) roomName(%s)", id.getValueString().c_str(), ChatServer::getConnectionAddress(connection).c_str(), sequence, roomName.c_str());
std::string tmpName = "SOE+" + roomName;
size_t pos = tmpName.find(".");
while (pos != std::string::npos)
{
tmpName[pos] = '+';
pos = tmpName.find(".");
}
Unicode::String wideName = Unicode::narrowToWide(tmpName);
unsigned track = RequestGetRoom(ChatUnicodeString(wideName.data(), wideName.size()), (void *)sequence);
ChatServer::instance().pendingRequests[track] = id;
}
//-----------------------------------------------------------------------
const ChatServerRoomOwner * ChatInterface::getRoomByName(const std::string & roomName) const
{
ChatServer::fileLog(s_enableChatRoomLogs, "ChatInterface", "getRoomByName() roomName(%s)", roomName.c_str());
std::string lowerRoomName = toLower(roomName);
const ChatServerRoomOwner * result = 0;
std::unordered_map<std::string, ChatServerRoomOwner>::const_iterator f = roomList.find(lowerRoomName);
if(f != roomList.end())
{
result = &(*f).second;
}
return result;
}
//-----------------------------------------------------------------------
void ChatInterface::deferChatMessageFor(const NetworkId & id, const Archive::ByteStream & bs)
{
ChatServer::fileLog(false, "ChatInterface", "deferChatMessageFor() id(%s)", id.getValueString().c_str());
std::vector<Archive::ByteStream> & v = deferredChatMessages[id];
v.push_back(bs);
}
//-----------------------------------------------------------------------
void ChatInterface::sendMessageToAvatar(const ChatAvatarId & avatar, const GameNetworkMessage & message)
{
ChatServer::fileLog(false, "ChatInterface", "sendMessageToAvatar() avatar(%s) message(%s)", avatar.getFullName().c_str(), message.getCmdName().c_str());
ChatServerAvatarOwner * to = 0;
std::map<ChatAvatarId, ChatServerAvatarOwner *>::const_iterator f = avatarMap.find(avatar);
if(f != avatarMap.end())
to = (*f).second;
if(to)
{
ConnectionServerConnection * connection = to->getPlayerConnection();
if(connection)
{
const NetworkId & id = to->getNetworkId();
if(id != NetworkId::cms_invalid)
{
connection->sendToClient(id, message);
}
}
}
}
//-----------------------------------------------------------------------
void ChatInterface::sendMessageToAvatar(const ChatAvatar & avatar, const GameNetworkMessage & message)
{
ChatServer::fileLog(false, "ChatInterface", "sendMessageToAvatar() avatar(%s) message(%s)", ChatServer::getFullChatAvatarName(&avatar).c_str(), message.getCmdName().c_str());
ChatServerAvatarOwner * to = getAvatarOwner(&avatar);
if(! to)
{
ChatAvatarId id;
makeAvatarId(avatar, id);
std::map<ChatAvatarId, ChatServerAvatarOwner *>::const_iterator f = avatarMap.find(id);
if(f != avatarMap.end())
{
to = (*f).second;
}
}
if(to)
{
ConnectionServerConnection * connection = to->getPlayerConnection();
if(connection)
{
const NetworkId & id = to->getNetworkId();
if(id != NetworkId::cms_invalid)
{
connection->sendToClient(id, message);
}
}
}
}
//-----------------------------------------------------------------------
void ChatInterface::sendMessageToAllAvatars(const GameNetworkMessage & message)
{
ChatServer::fileLog(false, "ChatInterface", "sendMessageToAllAvatars() message(%s)", message.getCmdName().c_str());
ChatServer::sendToAllConnectionServers(message);
/*
//send to all connected avatars
std::map<ChatAvatarId, ChatServerAvatarOwner *>::const_iterator f = avatarMap.begin();
while (f != avatarMap.end())
{
ChatServerAvatarOwner *to = (*f).second;
if(to)
{
ConnectionServerConnection * connection = to->getPlayerConnection();
if(connection)
{
const NetworkId & id = to->getNetworkId();
if(id != NetworkId::cms_invalid)
{
connection->sendToClient(id, message);
}
}
}
++f;
}
//send to all pending avatars
std::unordered_map<std::string, NetworkId>::iterator p = pendingAvatars.begin();
while (p != pendingAvatars.end())
{
ConnectionServerConnection * connection =
ChatServer::getConnectionForCharacter((*p).second);
if(connection)
{
const NetworkId & id = (*p).second;
if(id != NetworkId::cms_invalid)
{
connection->sendToClient(id, message);
}
}
++p;
}
*/
}
//-----------------------------------------------------------------------
std::string ChatInterface::getChatName(const NetworkId &id)
{
ChatServer::fileLog(false, "ChatInterface", "getChatName() id(%s)", id.getValueString().c_str());
std::unordered_map<std::string, NetworkId>::iterator i;
for (i = pendingAvatars.begin(); i != pendingAvatars.end(); ++i)
{
if (id == (*i).second)
{
return (*i).first;
}
}
static std::string tmp("somebody");
return tmp;
}
//-----------------------------------------------------------------------
bool ChatInterface::sendMessageToPendingAvatar(const ChatAvatarId &id, const GameNetworkMessage &message)
{
ChatServer::fileLog(false, "ChatInterface", "sendMessageToPendingAvatar() id(%s) message(%s)", id.getFullName().c_str(), message.getCmdName().c_str());
std::unordered_map<std::string, NetworkId>::iterator f = pendingAvatars.find(id.name);
if (f != pendingAvatars.end())
{
ConnectionServerConnection * connection =
ChatServer::getConnectionForCharacter((*f).second);
if (connection)
{
const NetworkId & id = (*f).second;
if(id != NetworkId::cms_invalid)
{
connection->sendToClient(id, message);
return true;
}
}
}
return false;
}
//-----------------------------------------------------------------------
const std::unordered_map<std::string, ChatServerRoomOwner> & ChatInterface::getRoomList() const
{
return roomList;
}
//-----------------------------------------------------------------------
void ChatInterface::updateRooms()
{
std::unordered_map<std::string, ChatServerRoomOwner>::const_iterator i;
for(i = roomList.begin(); i != roomList.end(); ++i)
{
ChatServerRoomOwner & roomOwner = const_cast<ChatServerRoomOwner &>((*i).second);
const ChatRoom *room = roomOwner.getRoom();
if (room)
{
roomOwner.updateRoomData(room);
/*
AvatarIterator i = room->getFirstAvatar();
if (!i.outOfBounds())
{
++i;
}
if (i.outOfBounds() && (!(room->getRoomAttributes() & ROOMATTR_PERSISTENT)))
{
ChatServer::removeSystemAvatarFromRoom(room);
roomOwner.flagForDelete();
}*/
}
}
}
//-----------------------------------------------------------------------
void ChatInterface::requestRoomList(const NetworkId & id, ConnectionServerConnection * connection)
{
ChatServer::fileLog(s_enableChatRoomLogs, "ChatInterface", "requestRoomList() id(%s) connection(%s)", id.getValueString().c_str(), ChatServer::getConnectionAddress(connection).c_str());
if (roomQueriesThisFrame >= ConfigChatServer::getMaxRoomQueriesPerFrame())
{
// printf("%Ld requested room query, but we've had too many queries this frame. Queuing it\n", id.getValue());
pendingRoomQueries.insert(id);
return;
}
++roomQueriesThisFrame;
std::unordered_map<std::string, ChatServerRoomOwner>::const_iterator i;
std::vector<ChatRoomData> rooms;
const ChatAvatar * target = ChatServer::getAvatarByNetworkId(id);
ChatAvatarId requestingAvatar;
if(target)
{
makeAvatarId(*target, requestingAvatar);
for(i = roomList.begin(); i != roomList.end(); ++i)
{
ChatServerRoomOwner & roomOwner = const_cast<ChatServerRoomOwner &>((*i).second);
const ChatRoomData & roomData = roomOwner.getRoomData();
if(
roomData.roomType == CHAT_ROOM_PUBLIC || //lint !e641 enum to int
roomData.creator == requestingAvatar
)
{
rooms.push_back(roomData);
}
else
{
std::vector<ChatAvatarId>::const_iterator j;
for(j = roomData.invitees.begin(); j != roomData.invitees.end(); ++j)
{
if (requestingAvatar == (*j))
{
rooms.push_back(roomData);
break;
}
}
}
}
}
ChatRoomList r(rooms);
ChatServer::fileLog(s_enableChatRoomLogs, "ChatInterface", "requestRoomList() sending room list of %u rooms to (%s)", r.getRoomData().size(), id.getValueString().c_str());
if (connection)
connection->sendToClient(id, r);
}
//-----------------------------------------------------------------------
std::string makeCanonicalName(const std::string &characterName)
{
/*
static const std::string dot(".");
std::string retVal;
char *str = strdup(characterName.c_str());
char *tmp = strtok(str, ".");
if (tmp)
{
retVal = toUpper(tmp);
}
tmp = strtok(NULL, ".");
if (tmp)
{
retVal += (dot + tmp);
}
tmp = strtok(NULL, ".");
if (tmp)
{
retVal += (dot + tmp);
}
printf("canonicalized(%s -> %s)\n", characterName.c_str(), retVal.c_str());
free(str);
return retVal;
*/
if (characterName == "SYSTEM")
{
return characterName;
}
else
{
return toLower(characterName);
}
}
//-----------------------------------------------------------------------
struct ConnectPlayerInfo
{
Unicode::String name;
Unicode::String address;
unsigned int suid;
};
struct QueuedLoginInfo
{
std::string name;
NetworkId id;
unsigned int suid;
};
static std::vector<QueuedLoginInfo *> queuedLogins;
//-----------------------------------------------------------------------
void ChatInterface::ConnectPlayer(unsigned int suid, const std::string & characterName, const NetworkId & networkId)
{
ChatServer::fileLog(false, "ChatInterface", "ConnectPlayer() suid(%u) characterName(%s) networkId(%s)", suid, characterName.c_str(), networkId.getValueString().c_str());
unsigned int loginFlowControlRate = ConfigChatServer::getLoginFlowControlRate();
if (loginFlowControlRate && pendingAvatars.size() > loginFlowControlRate)
{
QueuedLoginInfo *info = new QueuedLoginInfo;
info->name = characterName;
info->id = networkId;
info->suid = suid;
queuedLogins.push_back(info);
// printf("Queuing login of avatar (%s)\n", characterName.c_str());
return;
}
static const std::string game("SOE+SWG");
IGNORE_RETURN(pendingAvatars.insert(std::make_pair(characterName, networkId)));
Unicode::String name = Unicode::narrowToWide(characterName);
Unicode::String address = Unicode::narrowToWide(game + "+" + ConfigChatServer::getClusterName());
//Unicode::String address = Unicode::narrowToWide("SOE+SWG+Test Server");
ConnectPlayerInfo *info = new ConnectPlayerInfo;
info->name = name;
info->address = address;
info->suid = suid;
IGNORE_RETURN(RequestLoginAvatar(suid, ChatUnicodeString(name.data(), name.size()), ChatUnicodeString(address.data(), address.size()), (void *)info));
}
//-----------------------------------------------------------------------
void ChatInterface::DestroyAvatar(const std::string & characterName)
{
std::string const avatarName(Unicode::toLower(characterName));
std::string const avatarNameNormalized(avatarName, 0, avatarName.find(' '));
ChatAvatarId const avatar("SWG", ConfigChatServer::getClusterName(), avatarNameNormalized);
// track how many times we have called RequestGetAnyAvatar() for this particular DestroyAvatar
// operation, so that we can stop if we somehow get stuck in an infinite loop
unsigned const trackID = RequestGetAnyAvatar(ChatUnicodeString(avatar.getName()), ChatUnicodeString(avatar.getAPIAddress()), NULL);
trackingRequestGetAnyAvatarForDestroy[trackID] = std::make_pair(std::make_pair(ChatUnicodeString(avatar.getName()), ChatUnicodeString(avatar.getAPIAddress())), 1);
}
//-----------------------------------------------------------------------
void ChatInterface::checkQueuedLogins()
{
roomQueriesThisFrame = 0;
unsigned int loginFlowControlRate = ConfigChatServer::getLoginFlowControlRate();
if (!loginFlowControlRate)
{
return;
}
if (queuedLogins.size() > 0)
{
while (queuedLogins.size() > 0 && pendingAvatars.size() < loginFlowControlRate)
{
std::vector<QueuedLoginInfo *>::iterator i = queuedLogins.begin();
QueuedLoginInfo *info = (*i);
ConnectPlayer(info->suid, info->name, info->id);
// printf("Servicing queued login of avatar (%s)\n", info->name.c_str());
delete info;
queuedLogins.erase(i);
}
}
while (roomQueriesThisFrame < ConfigChatServer::getMaxRoomQueriesPerFrame() &&
!pendingRoomQueries.empty())
{
std::set<NetworkId>::iterator i = pendingRoomQueries.begin();
// printf("Servicing queued room query for %Ld.\n", (*i).getValue());
ConnectionServerConnection * c = ChatServer::getConnectionForCharacter((*i));
if (c)
{
requestRoomList((*i), c);
}
pendingRoomQueries.erase(i);
}
}
//-----------------------------------------------------------------------
void ChatInterface::sendQueuedHeadersToClient()
{
const unsigned long currentTime = Clock::timeSeconds();
const unsigned long queuedHeadersSendTime = currentTime + static_cast<unsigned long>(s_intervalToSendHeadersToClientSeconds);
int numberHeadersSent = 0;
const ChatPersistentMessageToClient * header = NULL;
for (std::map<ChatAvatarId, std::pair<unsigned long, std::deque<const ChatPersistentMessageToClient *> > >::iterator iter = queuedHeaders.begin(); iter != queuedHeaders.end();)
{
if (iter->second.first < currentTime)
{
numberHeadersSent = 0;
while ((!iter->second.second.empty()) && (numberHeadersSent < s_maxHeadersToSendToClientPerInterval))
{
header = iter->second.second.front();
iter->second.second.pop_front();
sendMessageToAvatar(iter->first, *header);
++numberHeadersSent;
delete header;
}
iter->second.first = queuedHeadersSendTime;
}
if (iter->second.second.empty())
{
queuedHeaders.erase(iter++);
}
else
{
++iter;
}
}
}
//-----------------------------------------------------------------------
void ChatInterface::clearQueuedHeadersForAvatar(const ChatAvatarId & avatarId)
{
std::map<ChatAvatarId, std::pair<unsigned long, std::deque<const ChatPersistentMessageToClient *> > >::iterator iter = queuedHeaders.find(avatarId);
if (iter != queuedHeaders.end())
{
for (std::deque<const ChatPersistentMessageToClient *>::const_iterator iter2 = iter->second.second.begin(); iter2 != iter->second.second.end(); ++iter2)
delete *iter2;
queuedHeaders.erase(iter);
}
}
//-----------------------------------------------------------------------
void ChatInterface::addQueuedHeaderForAvatar(const ChatAvatarId & avatarId, const ChatPersistentMessageToClient * header, unsigned long sendTime)
{
if (header == NULL)
return;
std::pair<unsigned long, std::deque<const ChatPersistentMessageToClient *> > & queuedHeader = queuedHeaders[avatarId];
queuedHeader.first = sendTime;
queuedHeader.second.push_back(header);
}
//-----------------------------------------------------------------------
ChatServerAvatarOwner *ChatInterface::getAvatarOwner(const ChatAvatar *avatar)
{
if (avatar)
{
ChatAvatarId id;
makeAvatarId(*avatar, id);
std::map<ChatAvatarId, ChatServerAvatarOwner *>::iterator f = avatarMap.find(id);
if (f != avatarMap.end())
{
return (*f).second;
}
}
return NULL;
}
//-----------------------------------------------------------------------
// Response to RequestAddModerator(...)
void ChatInterface::OnAddModerator(unsigned track, unsigned result, const ChatAvatar *srcAvatar, const ChatRoom *destRoom, void *user)
{
ChatServer::fileLog(s_enableChatRoomLogs, "ChatInterface", "OnAddModerator() track(%u) result(%u) srcAvatar(%s) destRoom(%s)", track, result, ChatServer::getFullChatAvatarName(srcAvatar).c_str(), ChatServer::getChatRoomNameNarrow(destRoom).c_str());
PROFILER_AUTO_BLOCK_DEFINE("ChatInterface - OnAddModerator");
AvatarIdSequencePair *pair = (AvatarIdSequencePair *)user;
unsigned sequence = 0;
ChatAvatarId destId;
if (pair)
{
destId = pair->avatar;
sequence = pair->sequence;
delete pair;
pair = NULL;
}
ChatAvatarId srcId;
if (srcAvatar)
{
makeAvatarId(*srcAvatar, srcId);
}
std::string roomName;
if (destRoom)
{
makeRoomName(destRoom, roomName);
}
// Tell the player making the request whether it was successful
ChatOnAddModeratorToRoom msg(result, sequence, destId, srcId, roomName);
NetworkId responseNetworkId = ChatServer::sendResponseForTrackId(track, msg);
// If we had a success, tell everyone else in the room about it
if (result == CHATRESULT_SUCCESS)
{
if (destRoom)
{
ChatAvatarId responseId;
{
ChatAvatar const * const responseAvatar = ChatServer::getAvatarByNetworkId( responseNetworkId );
if (responseAvatar)
{
makeAvatarId(*responseAvatar, responseId);
}
}
AvatarIterator i = destRoom->getFirstAvatar();
for(; !i.outOfBounds(); ++i)
{
ChatAvatarId id;
makeAvatarId(*(*i), id);
// We already sent a response to the avatar that made the request
if (id != responseId)
{
sendMessageToAvatar(id, msg);
}
}
}
}
}
//-----------------------------------------------------------------------
// OnReceiveAddModeratorRoom
// Called when srcAvatar has granted destAvatar moderator privileges in
// destRoom and this API has avatars that are in destRoom.
void ChatInterface::OnReceiveAddModeratorRoom(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, const ChatRoom *destRoom)
{
ChatServer::fileLog(s_enableChatRoomLogs, "ChatInterface", "OnReceiveAddModeratorRoom() srcAvatar(%s) destAvatar(%s) destRoom(%s)", ChatServer::getFullChatAvatarName(srcAvatar).c_str(), ChatServer::getFullChatAvatarName(destAvatar).c_str(), ChatServer::getChatRoomNameNarrow(destRoom).c_str());
PROFILER_AUTO_BLOCK_DEFINE("ChatInterface - OnReceiveAddModeratorRoom");
if (destRoom)
{
std::string roomName;
makeRoomName(destRoom, roomName);
// Update info about the room
std::unordered_map<std::string, ChatServerRoomOwner>::iterator f = roomList.find(toLower(roomName));
if(f != roomList.end())
(*f).second.updateRoomData(destRoom);
// See who created the room
ChatAvatarId creatorAvatarId;
makeAvatarId(destRoom->getCreatorName(), destRoom->getCreatorAddress(), creatorAvatarId);
// Clients don't want to know who belongs to the system created rooms
// NOTE: The name for the system avatar should be the same for all clusters
if (!Unicode::caseInsensitiveCompare(creatorAvatarId.getName(), ChatServer::getSystemAvatarId().getName()))
{
ChatServer::fileLog(false, "ChatInterface", "OnReceiveAddModeratorRoom() updating clients with member info for chatRoom(%s)", ChatServer::getChatRoomNameNarrow(destRoom).c_str());
// Tell all the avatars in the room the new member info
updateRoomForThisChatAPI(destRoom, destAvatar);
}
}
}
//-----------------------------------------------------------------------
// OnReceiveAddModeratorAvatar
// Called when srcAvatar has granted destAvatar moderator privileges in
// the room described by roomName and roomAddress, and destAvatar
// is on this API.
void ChatInterface::OnReceiveAddModeratorAvatar(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, const ChatUnicodeString &roomName, const ChatUnicodeString &roomAddress)
{
ChatServer::fileLog(s_enableChatRoomLogs, "ChatInterface", "OnReceiveAddModeratorAvatar() srcAvatar(%s) destAvatar(%s) roomName(%s) roomAddress(%s)", ChatServer::getFullChatAvatarName(srcAvatar).c_str(), ChatServer::getFullChatAvatarName(destAvatar).c_str(), ChatServer::toNarrowString(roomName).c_str(), ChatServer::toNarrowString(roomAddress).c_str());
}
//-----------------------------------------------------------------------
// Response to RequestRemoveModerator(...)
void ChatInterface::OnRemoveModerator(unsigned track, unsigned result, const ChatAvatar *srcAvatar, const ChatRoom *destRoom, void *user)
{
ChatServer::fileLog(s_enableChatRoomLogs, "ChatInterface", "OnRemoveModerator() track(%u) result(%u) srcAvatar(%s) destRoom(%s)", track, result, ChatServer::getFullChatAvatarName(srcAvatar).c_str(), ChatServer::getChatRoomNameNarrow(destRoom).c_str());
PROFILER_AUTO_BLOCK_DEFINE("ChatInterface - OnRemoveModerator");
AvatarIdSequencePair *pair = (AvatarIdSequencePair *)user;
unsigned sequence = 0;
ChatAvatarId destId;
if (pair)
{
destId = pair->avatar;
sequence = pair->sequence;
delete pair;
pair = NULL;
}
ChatAvatarId srcId;
if (srcAvatar)
{
makeAvatarId(*srcAvatar, srcId);
}
std::string roomName;
if (destRoom)
{
makeRoomName(destRoom, roomName);
}
// Tell the player making the request whether it was successful
ChatOnRemoveModeratorFromRoom msg(result, sequence, destId, srcId, roomName);
NetworkId responseNetworkId = ChatServer::sendResponseForTrackId(track, msg);
// If we had a success, tell everyone else in the room about it
if (result == CHATRESULT_SUCCESS)
{
if (destRoom)
{
ChatAvatarId responseId;
{
ChatAvatar const * const responseAvatar = ChatServer::getAvatarByNetworkId( responseNetworkId );
if (responseAvatar)
{
makeAvatarId(*responseAvatar, responseId);
}
}
AvatarIterator i = destRoom->getFirstAvatar();
for(; !i.outOfBounds(); ++i)
{
ChatAvatarId id;
makeAvatarId(*(*i), id);
// We already sent a response to the avatar that made the request
if (id != responseId)
{
sendMessageToAvatar(id, msg);
}
}
}
}
}
//-----------------------------------------------------------------------
// OnReceiveRemoveModeratorRoom
// Called when srcAvatar has removed destAvatar moderator privileges in
// destRoom and this API has avatars that are in destRoom.
void ChatInterface::OnReceiveRemoveModeratorRoom(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, const ChatRoom *destRoom)
{
ChatServer::fileLog(s_enableChatRoomLogs, "ChatInterface", "OnReceiveRemoveModeratorRoom() srcAvatar(%s) destAvatar(%s) destRoom(%s)", ChatServer::getFullChatAvatarName(srcAvatar).c_str(), ChatServer::getFullChatAvatarName(destAvatar).c_str(), ChatServer::getChatRoomNameNarrow(destRoom).c_str());
PROFILER_AUTO_BLOCK_DEFINE("ChatInterface - OnReceiveRemoveModeratorRoom");
if (destRoom)
{
std::string roomName;
makeRoomName(destRoom, roomName);
// Update info about the room
std::unordered_map<std::string, ChatServerRoomOwner>::iterator f = roomList.find(toLower(roomName));
if(f != roomList.end())
(*f).second.updateRoomData(destRoom);
// See who created the room
ChatAvatarId creatorAvatarId;
makeAvatarId(destRoom->getCreatorName(), destRoom->getCreatorAddress(), creatorAvatarId);
// Clients don't want to know who belongs to the system created rooms
// NOTE: The name for the system avatar should be the same for all clusters
if (!Unicode::caseInsensitiveCompare(creatorAvatarId.getName(), ChatServer::getSystemAvatarId().getName()))
{
ChatServer::fileLog(s_enableChatRoomLogs, "ChatInterface", "OnReceiveRemoveModeratorRoom() updating clients with member info for chatRoom(%s)", ChatServer::getChatRoomNameNarrow(destRoom).c_str());
// Tell all the avatars in the room the new member info
updateRoomForThisChatAPI(destRoom, 0);
}
}
}
//-----------------------------------------------------------------------
// OnReceiveRemoveModeratorAvatar
// Called when srcAvatar has removed destAvatar moderator privileges from
// the room described by roomName and roomAddress, and destAvatar is on
// this API.
void ChatInterface::OnReceiveRemoveModeratorAvatar(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, const ChatUnicodeString &roomName, const ChatUnicodeString &roomAddress)
{
ChatServer::fileLog(s_enableChatRoomLogs, "ChatInterface", "OnReceiveRemoveModeratorAvatar() srcAvatar(%s) destAvatar(%s) roomName(%s) roomAddress(%s)", ChatServer::getFullChatAvatarName(srcAvatar).c_str(), ChatServer::getFullChatAvatarName(destAvatar).c_str(), ChatServer::toNarrowString(roomName).c_str(), ChatServer::toNarrowString(roomAddress).c_str());
}
//-----------------------------------------------------------------------
void ChatInterface::OnAddFriend(unsigned track, unsigned result, const ChatAvatar *srcAvatar, const ChatUnicodeString &destName, const ChatUnicodeString &destAddress, void *user)
{
ChatServer::fileLog(false, "ChatInterface", "OnAddFriend() track(%u) result(%u) srcAvatar(%s) destName(%s) destAddress(%s)", track, result, ChatServer::getFullChatAvatarName(srcAvatar).c_str(), ChatServer::toNarrowString(destName).c_str(), ChatServer::toNarrowString(destAddress).c_str());
PROFILER_AUTO_BLOCK_DEFINE("ChatInterface - OnAddFriend");
UNREF(user);
if(result == CHATRESULT_SUCCESS) //lint !e641 Converting enum 'ChatResult' to int // jrandall that's what the API exposes
{
// send message to client!
ChatAvatarId d;
makeAvatarId(destName, destAddress, d);
ChatOnAddFriend chat(0, result); //lint !e713 Loss of precision (arg. no. 2) (unsigned int to int)
IGNORE_RETURN(ChatServer::sendResponseForTrackId(track, chat));
}
else
{
ChatOnAddFriend failed(0, result); //lint !e713 Loss of precision (arg. no. 2) (unsigned int to int)
IGNORE_RETURN(ChatServer::sendResponseForTrackId(track, failed));
}
//game server support
ChatAvatarId d;
makeAvatarId(destName, destAddress, d);
ChatServerAvatarOwner * mo = NULL;
if (srcAvatar)
mo = getAvatarOwner(srcAvatar);
if(mo)
{
ChatOnChangeFriendStatus update(0, mo->getNetworkId(), d, true, result);
ConnectionServerConnection * mc = mo->getPlayerConnection();
if(mc)
{
mc->sendToClient(mo->getNetworkId(), update);
}
}
}
//-----------------------------------------------------------------------
void ChatInterface::OnRemoveFriend(unsigned track, unsigned result, const ChatAvatar *srcAvatar, const ChatUnicodeString &destName, const ChatUnicodeString &destAddress, void *user)
{
ChatServer::fileLog(false, "ChatInterface", "OnRemoveFriend() track(%u) result(%u) srcAvatar(%s) destName(%s) destAddress(%s)", track, result, ChatServer::getFullChatAvatarName(srcAvatar).c_str(), ChatServer::toNarrowString(destName).c_str(), ChatServer::toNarrowString(destAddress).c_str());
PROFILER_AUTO_BLOCK_DEFINE("ChatInterface - OnRemoveFriend");
UNREF(user);
UNREF(track);
// send message to client!
ChatAvatarId d;
makeAvatarId(destName, destAddress, d);
ChatServerAvatarOwner * mo = NULL;
if (srcAvatar)
mo = getAvatarOwner(srcAvatar);
if(mo)
{
ChatOnChangeFriendStatus update(0, mo->getNetworkId(), d, false, result);
ConnectionServerConnection * mc = mo->getPlayerConnection();
if(mc)
{
mc->sendToClient(mo->getNetworkId(), update);
}
}
}
//-----------------------------------------------------------------------
void ChatInterface::OnIgnoreStatus(unsigned track, unsigned result, const ChatAvatar *srcAvatar, unsigned listLength, const ChatIgnoreStatus *ignoreList, void *user)
{
ChatServer::fileLog(false, "ChatInterface", "OnIgnoreStatus() track(%u) result(%u) srcAvatar(%s) listLength(%u)", track, result, ChatServer::getFullChatAvatarName(srcAvatar).c_str(), listLength);
PROFILER_AUTO_BLOCK_DEFINE("ChatInterface - OnIgnoreStatus");
UNREF(user);
UNREF(result);
// REPORT_LOG(true, ("OnIgnoreStatus(%u)\n", result));
if (track != 0 && result == CHATRESULT_SUCCESS)
{
std::vector<ChatAvatarId> idList;
if (ignoreList)
{
for (unsigned i = 0; i < listLength; ++i)
{
ChatAvatarId id;
makeAvatarId(ignoreList[i].getName(), ignoreList[i].getAddress(), id);
idList.push_back(id);
}
}
ChatServerAvatarOwner * mo = NULL;
if (srcAvatar)
mo = getAvatarOwner(srcAvatar);
if(mo)
{
ChatOnGetIgnoreList msg(mo->getNetworkId(), idList);
ConnectionServerConnection * mc = mo->getPlayerConnection();
if(mc)
{
mc->sendToClient(mo->getNetworkId(), msg);
}
}
}
}
//-----------------------------------------------------------------------
void ChatInterface::OnFriendStatus(unsigned track, unsigned result, const ChatAvatar *srcAvatar, unsigned listLength, const ChatFriendStatus *friendList, void *user)
{
ChatServer::fileLog(false, "ChatInterface", "OnFriendStatus() track(%u) result(%u) srcAvatar(%s) listLength(%u)", track, result, ChatServer::getFullChatAvatarName(srcAvatar).c_str(), listLength);
PROFILER_AUTO_BLOCK_DEFINE("ChatInterface - OnFriendStatus");
UNREF(user);
UNREF(result);
if (track != 0 && result == CHATRESULT_SUCCESS)
{
std::vector<ChatAvatarId> idList;
if (friendList)
{
for (unsigned i = 0; i < listLength; ++i)
{
ChatAvatarId id;
makeAvatarId(friendList[i].getName(), friendList[i].getAddress(), id);
idList.push_back(id);
}
}
ChatServerAvatarOwner * mo = NULL;
if (srcAvatar)
mo = getAvatarOwner(srcAvatar);
if(mo)
{
ChatOnGetFriendsList msg(mo->getNetworkId(), idList);
ConnectionServerConnection * mc = mo->getPlayerConnection();
if(mc)
{
mc->sendToClient(mo->getNetworkId(), msg);
}
}
}
}
//-----------------------------------------------------------------------
void ChatInterface::OnReceiveFriendLogin(const ChatAvatar *srcAvatar, const ChatUnicodeString &srcAddress, const ChatAvatar *destAvatar)
{
ChatServer::fileLog(false, "ChatInterface", "OnReceiveFriendLogin() srcAvatar(%s) srcAddress(%s) destAvatar(%s)", ChatServer::getFullChatAvatarName(srcAvatar).c_str(), ChatServer::toNarrowString(srcAddress).c_str(), ChatServer::getFullChatAvatarName(destAvatar).c_str());
PROFILER_AUTO_BLOCK_DEFINE("ChatInterface - OnReceiveFriendLogin");
UNREF(srcAddress);
ChatServerAvatarOwner * owner = NULL;
if (destAvatar)
owner = getAvatarOwner(destAvatar);
if(owner)
{
ConnectionServerConnection * connection = owner->getPlayerConnection();
if(connection)
{
const NetworkId & id = owner->getNetworkId();
if((id != NetworkId::cms_invalid) && (srcAvatar))
{
ChatAvatarId d;
makeAvatarId(*srcAvatar, d);
ChatFriendsListUpdate update(d, true);
connection->sendToClient(id, update);
}
}
}
}
//-----------------------------------------------------------------------
void ChatInterface::OnReceiveFriendLogout(const ChatAvatar *srcAvatar, const ChatUnicodeString &srcAddress, const ChatAvatar *destAvatar)
{
ChatServer::fileLog(false, "ChatInterface", "OnReceiveFriendLogout() srcAvatar(%s) srcAddress(%s) destAvatar(%s)", ChatServer::getFullChatAvatarName(srcAvatar).c_str(), ChatServer::toNarrowString(srcAddress).c_str(), ChatServer::getFullChatAvatarName(destAvatar).c_str());
PROFILER_AUTO_BLOCK_DEFINE("ChatInterface - OnReceiveFriendLogout");
UNREF(srcAddress);
ChatServerAvatarOwner * owner = NULL;
if (destAvatar)
owner = getAvatarOwner(destAvatar);
if(owner)
{
ConnectionServerConnection * connection = owner->getPlayerConnection();
if(connection)
{
const NetworkId & id = owner->getNetworkId();
if((id != NetworkId::cms_invalid) && (srcAvatar))
{
ChatAvatarId d;
makeAvatarId(*srcAvatar, d);
ChatFriendsListUpdate update(d, false);
connection->sendToClient(id, update);
}
}
}
}
//-----------------------------------------------------------------------
void ChatInterface::OnAddIgnore(unsigned track, unsigned result, const ChatAvatar *srcAvatar, const ChatUnicodeString &destName, const ChatUnicodeString &destAddress, void *user)
{
ChatServer::fileLog(false, "ChatInterface", "OnAddIgnore() track(%u) result(%u) srcAvatar(%s) destName(%s) destAddress(%s)", track, result, ChatServer::getFullChatAvatarName(srcAvatar).c_str(), ChatServer::toNarrowString(destName).c_str(), ChatServer::toNarrowString(destAddress).c_str());
PROFILER_AUTO_BLOCK_DEFINE("ChatInterface - OnAddIgnore");
UNREF(user);
if(srcAvatar)
{
//game server support
ChatAvatarId d;
makeAvatarId(destName, destAddress, d);
ChatAvatarId r;
makeAvatarId(*srcAvatar, r);
ChatServerAvatarOwner * mo = getAvatarOwner(srcAvatar);
if(mo)
{
ChatOnChangeIgnoreStatus update(0, mo->getNetworkId(), d, true, result);
ConnectionServerConnection * mc = mo->getPlayerConnection();
if(mc)
{
mc->sendToClient(mo->getNetworkId(), update);
}
}
}
}
//-----------------------------------------------------------------------
void ChatInterface::OnRemoveIgnore(unsigned track, unsigned result, const ChatAvatar *srcAvatar, const ChatUnicodeString &destName, const ChatUnicodeString &destAddress, void *user)
{
ChatServer::fileLog(false, "ChatInterface", "OnRemoveIgnore() track(%u) result(%u) srcAvatar(%s) destName(%s) destAddress(%s)", track, result, ChatServer::getFullChatAvatarName(srcAvatar).c_str(), ChatServer::toNarrowString(destName).c_str(), ChatServer::toNarrowString(destAddress).c_str());
PROFILER_AUTO_BLOCK_DEFINE("ChatInterface - OnRemoveIgnore");
UNREF(user);
//game server support
ChatAvatarId d;
makeAvatarId(destName, destAddress, d);
ChatServerAvatarOwner * mo = NULL;
if (srcAvatar)
mo = getAvatarOwner(srcAvatar);
if(mo)
{
ChatOnChangeIgnoreStatus update(0, mo->getNetworkId(), d, false, result);
ConnectionServerConnection * mc = mo->getPlayerConnection();
if(mc)
{
mc->sendToClient(mo->getNetworkId(), update);
}
}
}
//-----------------------------------------------------------------------
void ChatInterface::OnLoginAvatar(unsigned track, unsigned result, const ChatAvatar *newAvatar, void *user)
{
ChatServer::fileLog(false, "ChatInterface", "OnLoginAvatar() track(%u) result(%u) newAvatar(%s)", track, result, ChatServer::getFullChatAvatarName(newAvatar).c_str());
PROFILER_AUTO_BLOCK_DEFINE("ChatInterface - OnLoginAvatar");
static unsigned lastTrack = 12345678;
if (track == lastTrack)
{
DEBUG_WARNING(true, ("Received duplicate track"));
return;
}
lastTrack = track;
if (newAvatar)
s_mostRecentRoomChatMessage.erase(newAvatar->getAvatarID());
// login to destroy chat avatar
std::map<unsigned, std::pair<std::pair<ChatUnicodeString, ChatUnicodeString>, int> >::const_iterator iterFind = trackingRequestGetAnyAvatarForDestroy.find(track);
if (iterFind != trackingRequestGetAnyAvatarForDestroy.end())
{
if ((result == CHATRESULT_SUCCESS) && newAvatar)
{
// destroy chat avatar
unsigned const trackID = RequestDestroyAvatar(newAvatar, NULL);
trackingRequestGetAnyAvatarForDestroy[trackID] = iterFind->second;
}
trackingRequestGetAnyAvatarForDestroy.erase(track);
return;
}
ConnectPlayerInfo *info = (ConnectPlayerInfo *)user;
if (info)
{
if (result == 1) //timeout
{
// printf("!!!!!!!!!!avatar login timed out, trying again\n");
ConnectPlayerInfo *info2 = new ConnectPlayerInfo;
info2->name = info->name;
info2->address = info->address;
info2->suid = info->suid;
IGNORE_RETURN(RequestLoginAvatar(info->suid, ChatUnicodeString(info->name.data(), info->name.size()), ChatUnicodeString(info->address.data(), info->address.size()), (void *)info2));
delete info;
return;
}
}
// ChatAvatarId foobar;
// if (newAvatar)
// {
// makeAvatarId(*newAvatar, foobar);
// }
// printf("OnLoginAvatar(%u) for %s.%s.%s\n", result, foobar.gameCode.c_str(), foobar.cluster.c_str(), foobar.name.c_str());
//DEBUG_WARNING(result != CHATRESULT_SUCCESS, ("Chat Connect avatar %s.%s.%s failed! : %s\n", avatar.GetGameCode().c_str(), avatar.GetGameServerName().c_str(), avatar.GetCharacterName().c_str(), getChatResultCodeName(resultCode).c_str())); //lint !e641 converting enum to int
// is this the special system avatar?
if (result != CHATRESULT_SUCCESS)
{
ChatAvatarId failedAvatarId;
makeAvatarId(ChatUnicodeString(info->name.data(), info->name.size()), ChatUnicodeString(info->address.data(), info->address.size()), failedAvatarId);
std::unordered_map<std::string, NetworkId>::iterator f = pendingAvatars.find(failedAvatarId.name);
if (f != pendingAvatars.end())
{
pendingAvatars.erase(f);
}
DEBUG_WARNING(result != CHATRESULT_SUCCESS, ("Chat Connect avatar failed for %s.%s.%s! : %u\n", failedAvatarId.gameCode.c_str(),failedAvatarId.cluster.c_str(), failedAvatarId.name.c_str(), result)); //lint !e641 converting enum to int
delete info;
return;
}
delete info;
ChatAvatarId id;
if (newAvatar)
makeAvatarId(*newAvatar, id);
if(id == ChatServer::getSystemAvatarId())
{
//REPORT_LOG(true, ("\"System avatar\" load confirmed\n"));
if (newAvatar)
{
ChatServer::fileLog(true, "ChatInterface", "OnLoginAvatar() ChatAPI SYSTEM avatar connected with name=(%s), address=(%s), server=(%s), gateway=(%s), loginLocation=(%s)",
Unicode::wideToNarrow(Unicode::String(newAvatar->getName().string_data, newAvatar->getName().string_length)).c_str(),
Unicode::wideToNarrow(Unicode::String(newAvatar->getAddress().string_data, newAvatar->getAddress().string_length)).c_str(),
Unicode::wideToNarrow(Unicode::String(newAvatar->getServer().string_data, newAvatar->getServer().string_length)).c_str(),
Unicode::wideToNarrow(Unicode::String(newAvatar->getGateway().string_data, newAvatar->getGateway().string_length)).c_str(),
Unicode::wideToNarrow(Unicode::String(newAvatar->getLoginLocation().string_data, newAvatar->getLoginLocation().string_length)).c_str());
ChatServer::setOwnerSystem(newAvatar);
static Unicode::String wideSWG = Unicode::narrowToWide("SOE+SWG");
static Unicode::String wideFilter = Unicode::narrowToWide("");
static ChatUnicodeString swgNode(wideSWG.data(), wideSWG.size());
static ChatUnicodeString filter(wideFilter.data(), wideFilter.size());
IGNORE_RETURN(RequestGetRoomSummaries(swgNode, filter, NULL));
}
}
else
{
// look up a connection for this avatar
std::unordered_map<std::string, NetworkId>::iterator f = pendingAvatars.find(id.name);
if(f != pendingAvatars.end())
{
GenericValueTypeMessage<NetworkId> const avatarConnectedMessage("ChatAvatarConnected", (*f).second);
ChatServer::broadcastToGameServers(avatarConnectedMessage);
ConnectionServerConnection * c = ChatServer::getConnectionForCharacter((*f).second);
if(c && newAvatar)
{
ChatServerAvatarOwner * owner = new ChatServerAvatarOwner(c, (*f).second);
ChatAvatarId avId;
makeAvatarId(*newAvatar, avId);
avatarMap[avId] = owner;
if(ChatServer::isGod(f->second))
{
RequestSetAvatarAttributes(newAvatar, AVATARATTR_GM, NULL);
}
else
{
RequestSetAvatarAttributes(newAvatar, 0, NULL);
}
ChatServer::chatConnectedAvatar((*f).second, *newAvatar);
// flush chat messages pending for this avatar
std::unordered_map<NetworkId, std::vector<Archive::ByteStream>, NetworkId::Hash >::iterator df = deferredChatMessages.find((*f).second);
if(df != deferredChatMessages.end())
{
std::vector<Archive::ByteStream> & v = (*df).second;
std::vector<Archive::ByteStream>::const_iterator i;
for(i = v.begin(); i != v.end(); ++i)
{
const_cast<ConnectionServerConnection *>(c)->onReceive((*i));
}
deferredChatMessages.erase(df);
}
//ChatServer::getFriendsList(id);
clearQueuedHeadersForAvatar(avId);
IGNORE_RETURN(RequestGetPersistentHeaders(newAvatar, NULL));
//REPORT_LOG(true, ("Connection to chat system for %s.%s.%s confirmed\n", avatar.GetGameCode().c_str(), avatar.GetGameServerName().c_str(), avatar.GetCharacterName().c_str()));
}//lint !e429 Custodial pointer 'owner' has not been freed or returned // jrandall avatar owns it
pendingAvatars.erase(f);
}
else
{
// no way to route messages to avatar, they disconnected between
// the time they connected to the connection server and the time
// this message arrived from the chat backend.
if (newAvatar)
IGNORE_RETURN(RequestLogoutAvatar(newAvatar, NULL));
}
}
ChatOnConnectAvatar const connect;
sendMessageToAvatar(id, connect);
// make my owner object
}
//-----------------------------------------------------------------------
void ChatInterface::OnCreateRoom(unsigned track,unsigned result, const ChatRoom *newRoom, void *user)
{
ChatServer::fileLog(s_enableChatRoomLogs, "ChatInterface", "OnCreateRoom() track(%u) result(%u) newRoom(%s)", track, result, ChatServer::getChatRoomNameNarrow(newRoom).c_str());
PROFILER_AUTO_BLOCK_DEFINE("ChatInterface - OnCreateRoom");
UNREF(user);
unsigned sequence = (unsigned)user;
static Unicode::String wideSWG = Unicode::narrowToWide("SOE+SWG");
static Unicode::String wideFilter = Unicode::narrowToWide("");
static ChatUnicodeString swgNode(wideSWG.data(), wideSWG.size());
static ChatUnicodeString filter(wideFilter.data(), wideFilter.size());
//printf("!!!!Calling GetRoomSummaries from OnCreateRoom\n");
//IGNORE_RETURN(RequestGetRoomSummaries(swgNode, filter, NULL));
ChatRoomData roomData;
if((result == CHATRESULT_SUCCESS) && (newRoom)) //lint !e641 enum to int
{
ChatServerRoomOwner * o = new ChatServerRoomOwner(newRoom);
roomData = o->getRoomData();
//Unicode::String wideRoomName(newRoom->getRoomName().string_data, newRoom->getRoomName().string_length);
std::string roomName;
makeRoomName(newRoom, roomName);
if (strstr(roomName.c_str(), "group") == NULL)
{
ChatServer::putSystemAvatarInRoom(roomName);
}
std::string lowerRoomName = toLower(roomName);
IGNORE_RETURN(roomList.insert(std::make_pair(lowerRoomName, *o)));
//REPORT_LOG(true, ("OnCreateRoom(%s) confirmed\n", roomData.path.c_str()));
delete o;
ChatServer::onCreateRoomSuccess(lowerRoomName, newRoom->getRoomID());
} //lint !e429 Pointer 'o' not freed or returned: Set in SetRoomOwnerPtr
ChatOnCreateRoom const c(sequence, result, roomData);
IGNORE_RETURN(ChatServer::sendResponseForTrackId(track, c));
Connection * const connection = safe_cast<Connection *>(ChatServer::getGameServerConnection(sequence));
if (connection)
{
static Archive::ByteStream a;
a.clear();
c.pack(a);
connection->send(a, true);
}
}
//-----------------------------------------------------------------------
void ChatInterface::OnGetRoomSummaries(unsigned track, unsigned result, unsigned numFoundRooms, RoomSummary *foundRooms, void *user)
{
ChatServer::fileLog(s_enableChatRoomLogs, "ChatInterface", "OnGetRoomSummaries() track(%u) result(%u) numFoundRooms(%u)", track, result, numFoundRooms);
PROFILER_AUTO_BLOCK_DEFINE("ChatInterface - OnGetRoomSummaries");
UNREF(track);
UNREF(result);
UNREF(user);
if (foundRooms)
{
for (unsigned i = 0; i < numFoundRooms; ++i)
{
std::string roomName;
makeRoomName(&(foundRooms[i]), roomName);
std::string lowerRoomName = toLower(roomName);
std::unordered_map<std::string, ChatServerRoomOwner>::const_iterator f = roomList.find(lowerRoomName);
if(f == roomList.end())
{
RequestGetRoom(foundRooms[i].getRoomAddress(), NULL);
//ChatServerRoomOwner * o = new ChatServerRoomOwner((*i));
//(*i)->SetRoomOwnerPtr(o);
//IGNORE_RETURN(roomList.insert(std::make_pair(lowerRoomName, *o)));
//printf("insert %s, roomList size = %u\n", lowerRoomName.c_str(), roomList.size());
} //lint !e429 pointer not freed or returned, it is set as ownerPtr
}
}
}
//-----------------------------------------------------------------------
const ChatServerRoomOwner *ChatInterface::getRoomOwner(const std::string & roomName)
{
std::string lowerName = toLower(roomName);
std::unordered_map<std::string, ChatServerRoomOwner>::const_iterator f = roomList.find(lowerName);
if(f != roomList.end())
{
return &((*f).second);
}
return NULL;
}
//-----------------------------------------------------------------------
ChatServerRoomOwner *ChatInterface::getRoomOwner(unsigned roomId)
{
std::unordered_map<std::string, ChatServerRoomOwner>::iterator f = roomList.begin();
while (f != roomList.end())
{
if ((*f).second.getRoomData().id == roomId)
{
return &((*f).second);
}
++f;
}
return NULL;
}
//-----------------------------------------------------------------------
void ChatInterface::OnReceiveDestroyRoom(const ChatAvatar *srcAvatar, const ChatRoom *destRoom)
{
ChatServer::fileLog(s_enableChatRoomLogs, "ChatInterface", "OnReceiveDestroyRoom() srcAvatar(%s) destRoom(%s)", ChatServer::getFullChatAvatarName(srcAvatar).c_str(), ChatServer::getChatRoomNameNarrow(destRoom).c_str());
PROFILER_AUTO_BLOCK_DEFINE("ChatInterface - OnReceiveDestroyRoom");
ChatAvatarId destroyer;
if (srcAvatar)
makeAvatarId(*srcAvatar, destroyer);
if (destRoom)
{
const ChatOnDestroyRoom c(0, 0, destRoom->getRoomID(), destroyer);
AvatarIterator i = destRoom->getFirstAvatar();
/*for(; !i.outOfBounds(); ++i)
{
sendMessageToAvatar(*(*i), c);
}*/
sendMessageToAllAvatars(c);
std::string roomName;
makeRoomName(destRoom, roomName);
std::string lowerName = toLower(roomName);
std::unordered_map<std::string, ChatServerRoomOwner>::iterator f = roomList.find(lowerName);
if(f != roomList.end())
{
roomList.erase(f);
}
}
}
//-----------------------------------------------------------------------
void ChatInterface::OnDestroyRoom(unsigned track, unsigned result, void *user)
{
ChatServer::fileLog(s_enableChatRoomLogs, "ChatInterface", "OnDestroyRoom() track(%u) result(%u)", track, result);
PROFILER_AUTO_BLOCK_DEFINE("ChatInterface - OnDestroyRoom");
static Unicode::String wideSWG = Unicode::narrowToWide("SOE+SWG");
static Unicode::String wideFilter = Unicode::narrowToWide("");
static ChatUnicodeString swgNode(wideSWG.data(), wideSWG.size());
static ChatUnicodeString filter(wideFilter.data(), wideFilter.size());
//IGNORE_RETURN(RequestGetRoomSummaries(swgNode, filter, NULL));
ChatAvatarId destroyer;
RoomOwnerSequencePair *pair = (RoomOwnerSequencePair *)user;
const ChatServerRoomOwner * owner = NULL;
unsigned sequence = 0;
if (pair)
{
owner = pair->roomOwner;
sequence = pair->sequence;
delete pair;
pair = 0;
}
if (owner)
{
const ChatOnDestroyRoom c(sequence, result, owner->getRoomData().id, destroyer);
NetworkId responseNetworkId = ChatServer::sendResponseForTrackId(track, c);
if (result == CHATRESULT_SUCCESS)
{
std::string lowerName = toLower(owner->getRoomData().path);
std::unordered_map<std::string, ChatServerRoomOwner>::iterator f = roomList.find(lowerName);
if(f != roomList.end())
{
roomList.erase(f);
}
}
}
}
//-----------------------------------------------------------------------
void ChatInterface::OnLogoutAvatar(unsigned track, unsigned result, const ChatAvatar *oldAvatar, void *user)
{
ChatServer::fileLog(false, "ChatInterface", "OnLogoutAvatar() track(%u) result(%u) oldAvatar(%s)", track, result, ChatServer::getFullChatAvatarName(oldAvatar).c_str());
PROFILER_AUTO_BLOCK_DEFINE("ChatInterface - OnLogoutAvatar");
UNREF(user);
UNREF(result);
UNREF(track);
if (!oldAvatar)
{
return;
}
s_mostRecentRoomChatMessage.erase(oldAvatar->getAvatarID());
/*ChatAvatarId id;
makeAvatarId(*oldAvatar, id);
std::map<ChatAvatarId, ChatServerAvatarOwner *>::iterator f = avatarMap.find(id);
if(f != avatarMap.end())
{*/
ChatServer::disconnectAvatar(*oldAvatar);
//}
ChatAvatarId id;
makeAvatarId(*oldAvatar, id);
clearQueuedHeadersForAvatar(id);
}
//-----------------------------------------------------------------------
void ChatInterface::OnDestroyAvatar(unsigned track, unsigned result, const ChatAvatar *oldAvatar, void *user)
{
UNREF(user);
std::map<unsigned, std::pair<std::pair<ChatUnicodeString, ChatUnicodeString>, int> >::const_iterator iterFind = trackingRequestGetAnyAvatarForDestroy.find(track);
if (iterFind != trackingRequestGetAnyAvatarForDestroy.end())
{
if ((result == CHATRESULT_SUCCESS) && oldAvatar)
{
// stop if it looks like we're in an infinite loop
if (iterFind->second.second <= 25)
{
unsigned const trackID = RequestGetAnyAvatar(iterFind->second.first.first, iterFind->second.first.second, NULL);
trackingRequestGetAnyAvatarForDestroy[trackID] = std::make_pair(iterFind->second.first, (iterFind->second.second + 1));
}
}
trackingRequestGetAnyAvatarForDestroy.erase(track);
}
}
//-----------------------------------------------------------------------
void ChatInterface::OnGetAnyAvatar(unsigned track, unsigned result, const ChatAvatar *foundAvatar, bool loggedIn, void *user)
{
UNREF(user);
std::map<unsigned, std::pair<std::pair<ChatUnicodeString, ChatUnicodeString>, int> >::const_iterator iterFind = trackingRequestGetAnyAvatarForDestroy.find(track);
if (iterFind != trackingRequestGetAnyAvatarForDestroy.end())
{
if ((result == CHATRESULT_SUCCESS) && foundAvatar)
{
// can only destroy the avatar if he is logged in
if (loggedIn)
{
unsigned const trackID = RequestDestroyAvatar(foundAvatar, NULL);
trackingRequestGetAnyAvatarForDestroy[trackID] = iterFind->second;
}
// log in the chat avatar so we can destroy him
else
{
unsigned const trackID = RequestLoginAvatar(foundAvatar->getUserID(), foundAvatar->getName(), foundAvatar->getAddress(), NULL);
trackingRequestGetAnyAvatarForDestroy[trackID] = iterFind->second;
}
}
trackingRequestGetAnyAvatarForDestroy.erase(track);
}
}
//-----------------------------------------------------------------------
void ChatInterface::OnReceiveForcedLogout(const ChatAvatar *oldAvatar)
{
ChatServer::fileLog(false, "ChatInterface", "OnReceiveForcedLogout() oldAvatar(%s)", ChatServer::getFullChatAvatarName(oldAvatar).c_str());
PROFILER_AUTO_BLOCK_DEFINE("ChatInterface - OnReceiveForcedLogout");
if (oldAvatar == NULL)
{
DEBUG_WARNING(true, ("We received an OnReceiveForcedLogout with a success result code but NULL data. This is an error that the API should never give."));
return;
}
ChatAvatarId id;
makeAvatarId(*oldAvatar, id);
std::map<ChatAvatarId, ChatServerAvatarOwner *>::iterator f = avatarMap.find(id);
if(f != avatarMap.end())
{
ChatServer::disconnectAvatar(*oldAvatar);
}
else
{
DEBUG_WARNING(true, ("We received a forced logout for an avatar who is awaiting login. Usually this will happen on slow boxes when you log out and back in quickly, exploiting a race condition in the backend. No harm should come from this."));
}
}
//-----------------------------------------------------------------------
// Response to RequestEnterRoom(...)
void ChatInterface::OnEnterRoom(unsigned track, unsigned result, const ChatAvatar *srcAvatar, const ChatRoom *destRoom, void *user)
{
ChatServer::fileLog(s_enableChatRoomLogs, "ChatInterface", "OnEnterRoom() track(%u) result(%u) srcAvatar(%s) destRoom(%s)", track, result, ChatServer::getFullChatAvatarName(srcAvatar).c_str(), ChatServer::getChatRoomNameNarrow(destRoom).c_str());
PROFILER_AUTO_BLOCK_DEFINE("ChatInterface - OnEnterRoom");
if (result == CHATRESULT_SUCCESS && (srcAvatar == NULL || destRoom == NULL))
{
DEBUG_WARNING(true, ("We received an OnEnterRoom with a success result code but NULL data. This is an error that the API should never give."));
return;
}
unsigned sequence = (unsigned)user;
ChatAvatarId srcId;
if (srcAvatar)
{
makeAvatarId(*srcAvatar, srcId);
}
unsigned roomId = 0;
if (destRoom)
{
roomId = destRoom->getRoomID();
}
// If we had a success, we need to tell the client about the room
// so that they have the information to process entering the room
if (result == CHATRESULT_SUCCESS)
{
// Send the room data for the room the avatar has entered
// since the room may be private and may be unknown to the player
if (destRoom)
{
ChatServerRoomOwner *roomOwner = getRoomOwner(destRoom->getRoomID());
if (roomOwner)
{
std::vector<ChatRoomData> rooms;
ChatRoomData data = roomOwner->getRoomData();
rooms.push_back(data);
ChatRoomList r(rooms);
ChatServer::fileLog(s_enableChatRoomLogs, "ChatInterface", "OnEnterRoom() sending room list of %u rooms to (%s)", r.getRoomData().size(), ChatServer::getFullChatAvatarName(srcAvatar).c_str());
sendMessageToAvatar(srcId, r);
}
}
}
// Tell the client that made the request the results
ChatOnEnteredRoom const msg(sequence, result, roomId, srcId);
NetworkId responseNetworkId = ChatServer::sendResponseForTrackId(track, msg);
// If we had a success, tell everyone else in the room about it
if (result == CHATRESULT_SUCCESS)
{
// Tell the client that entered the room if they did not make the request
ChatServerAvatarOwner * const owner = getAvatarOwner(srcAvatar);
if (owner && (owner->getNetworkId() != responseNetworkId))
{
sendMessageToAvatar(srcId, msg);
}
if (destRoom)
{
std::string roomName;
makeRoomName(destRoom, roomName);
// Let everyone in the room know the client entered the room
if (roomName.find(".system") == roomName.npos)
{
ChatAvatarId responseId;
{
ChatAvatar const * const responseAvatar = ChatServer::getAvatarByNetworkId( responseNetworkId );
if (responseAvatar)
{
makeAvatarId(*responseAvatar, responseId);
}
}
AvatarIterator i = destRoom->getFirstAvatar();
for(; !i.outOfBounds(); ++i)
{
ChatAvatarId id;
makeAvatarId(*(*i), id);
// We already sent a response to the avatar that made the request
if ((id != responseId) && (id != srcId))
{
sendMessageToAvatar(id, msg);
}
}
}
}
}
}
//-----------------------------------------------------------------------
// OnReceiveEnterRoom
// Called when srcAvatar has entered destRoom and this API has avatars
// that are in destRoom. If srcAvatar is on this API and no others from
// this API are in the room, this is not called.
void ChatInterface::OnReceiveEnterRoom(const ChatAvatar *srcAvatar, const ChatRoom *destRoom)
{
ChatServer::fileLog(s_enableChatRoomLogs, "ChatInterface", "OnReceiveEnterRoom() srcAvatar(%s) destRoom(%s)", ChatServer::getFullChatAvatarName(srcAvatar).c_str(), ChatServer::getChatRoomNameNarrow(destRoom).c_str());
PROFILER_AUTO_BLOCK_DEFINE("ChatInterface - OnReceiveEnterRoom");
if (destRoom)
{
std::string roomName;
makeRoomName(destRoom, roomName);
// Update info about the room
std::unordered_map<std::string, ChatServerRoomOwner>::iterator f = roomList.find(toLower(roomName));
if(f != roomList.end())
(*f).second.updateRoomData(destRoom);
// See who created the room
ChatAvatarId creatorAvatarId;
makeAvatarId(destRoom->getCreatorName(), destRoom->getCreatorAddress(), creatorAvatarId);
// Clients don't want to know who belongs to the system created rooms
// NOTE: The name for the system avatar should be the same for all clusters
if (!Unicode::caseInsensitiveCompare(creatorAvatarId.getName(), ChatServer::getSystemAvatarId().getName()))
{
ChatServer::fileLog(s_enableChatRoomLogs, "ChatInterface", "OnReceiveEnterRoom() updating clients with member info for chatRoom(%s)", ChatServer::getChatRoomNameNarrow(destRoom).c_str());
// Tell all the avatars in the room the new member info
updateRoomForThisChatAPI(destRoom, srcAvatar);
}
}
}
//-----------------------------------------------------------------------
// The OnReceive___() callbacks for chat rooms get called for every
// Chat API that has avatars in the room. So limit updates to the
// avatars that are located on this Chat API.
void ChatInterface::updateRoomForThisChatAPI(const ChatRoom *room, const ChatAvatar *additionalAvatar)
{
ChatServer::fileLog(s_enableChatRoomLogs, "ChatInterface", "updateRoomForThisChatAPI() room(%s)", ChatServer::getChatRoomNameNarrow(room).c_str());
PROFILER_AUTO_BLOCK_DEFINE("ChatInterface - updateRoomForThisChatAPI");
if (room)
{
ChatServerRoomOwner *owner = getRoomOwner(room->getRoomID());
if (owner)
{
owner->updateRoomData(room);
ChatAvatarId av;
std::vector<ChatAvatarId> avatars;
for(AvatarIterator a = room->getFirstAvatar(); !a.outOfBounds(); ++a)
{
makeAvatarId(*(*a), av);
avatars.push_back(av);
}
std::vector<ChatAvatarId> moderators;
for(ModeratorIterator m = room->getFirstModerator(); !m.outOfBounds(); ++m)
{
makeAvatarId(*(*m), av);
moderators.push_back(av);
}
std::vector<ChatAvatarId> invitees;
for(InviteIterator i = room->getFirstInvited(); !i.outOfBounds(); ++i)
{
makeAvatarId(*(*i), av);
invitees.push_back(av);
}
std::vector<ChatAvatarId> banned;
for(BanIterator b = room->getFirstBanned(); !b.outOfBounds(); ++b)
{
makeAvatarId(*(*b), av);
banned.push_back(av);
}
ChatAvatarId additionalAvatarId;
if (additionalAvatar)
{
makeAvatarId(*additionalAvatar, additionalAvatarId);
}
// We only want to update the additional avatar once
bool wasAdditionalAvatarUpdated = false;
ChatQueryRoomResults results(0, owner->getRoomData(), avatars, moderators, invitees, banned);
for(AvatarIterator avs = room->getFirstAvatar(); !avs.outOfBounds(); ++avs)
{
makeAvatarId(*(*avs), av);
// Only send to avatars for this Chat API
if (av.cluster == ChatServer::getSystemAvatarId().cluster)
{
ChatServer::fileLog(s_enableChatRoomLogs, "ChatInterface", "updateRoomForThisChatAPI() sending room members (%u avatars, %u moderators, %u invitees, %u banned) to (%s)",
avatars.size(), moderators.size(), invitees.size(), banned.size(), av.getFullName().c_str());
sendMessageToAvatar(av, results);
if (additionalAvatar && (av == additionalAvatarId))
{
wasAdditionalAvatarUpdated = true;
}
}
}
if (additionalAvatar && !wasAdditionalAvatarUpdated)
{
ChatServer::fileLog(s_enableChatRoomLogs, "ChatInterface", "updateRoomForThisChatAPI() sending room members (%u avatars, %u moderators, %u invitees, %u banned) to (%s)",
avatars.size(), moderators.size(), invitees.size(), banned.size(), additionalAvatarId.getFullName().c_str());
sendMessageToAvatar(additionalAvatarId, results);
}
}
}
}
//-----------------------------------------------------------------------
// Response to RequestAddBan(...)
void ChatInterface::OnAddBan(unsigned track, unsigned result, const ChatAvatar *srcAvatar, const ChatRoom *destRoom, void *user)
{
ChatServer::fileLog(s_enableChatRoomLogs, "ChatInterface", "OnAddBan() track(%u) result(%u) srcAvatar(%s) destRoom(%s)", track, result, ChatServer::getFullChatAvatarName(srcAvatar).c_str(), ChatServer::getChatRoomNameNarrow(destRoom).c_str());
PROFILER_AUTO_BLOCK_DEFINE("ChatInterface - OnAddBan");
if (result == CHATRESULT_SUCCESS && (srcAvatar == NULL || destRoom == NULL))
{
DEBUG_WARNING(true, ("We received an OnAddBan with a success result code but NULL data. This is an error that the API should never give."));
return;
}
AvatarIdSequencePair *pair = (AvatarIdSequencePair *)user;
unsigned sequence = 0;
ChatAvatarId destId;
if (pair)
{
destId = pair->avatar;
sequence = pair->sequence;
delete pair;
pair = NULL;
}
ChatAvatarId srcId;
if (srcAvatar)
{
makeAvatarId(*srcAvatar, srcId);
}
std::string roomName;
if (destRoom)
{
makeRoomName(destRoom, roomName);
}
// Tell the player making the request whether the ban was successful
ChatOnBanAvatarFromRoom const msg(sequence, result, roomName, srcId, destId);
NetworkId responseNetworkId = ChatServer::sendResponseForTrackId(track, msg);
// If we had a success, tell everyone else in the room about it
if (result == CHATRESULT_SUCCESS)
{
if (destRoom)
{
ChatAvatarId responseId;
{
ChatAvatar const * const responseAvatar = ChatServer::getAvatarByNetworkId( responseNetworkId );
if (responseAvatar)
{
makeAvatarId(*responseAvatar, responseId);
}
}
AvatarIterator i = destRoom->getFirstAvatar();
for(; !i.outOfBounds(); ++i)
{
ChatAvatarId id;
makeAvatarId(*(*i), id);
// We already sent a response to the avatar that made the request
if (id != responseId)
{
sendMessageToAvatar(id, msg);
}
}
}
}
}
//-----------------------------------------------------------------------
// OnReceiveAddBanRoom
// Called when srcAvatar has banned destAvatar from destRoom and this
// API has avatars that are in destRoom.
void ChatInterface::OnReceiveAddBanRoom(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, const ChatRoom *destRoom)
{
ChatServer::fileLog(s_enableChatRoomLogs, "ChatInterface", "OnReceiveAddBanRoom() srcAvatar(%s) destAvatar(%s) destRoom(%s)", ChatServer::getFullChatAvatarName(srcAvatar).c_str(), ChatServer::getFullChatAvatarName(destAvatar).c_str(), ChatServer::getChatRoomNameNarrow(destRoom).c_str());
// NOTE: Do not put anything in this callback that uses destAvatar.
// Currently there is a bug where the address and name are not set correctly in destAvatar.
PROFILER_AUTO_BLOCK_DEFINE("ChatInterface - OnReceiveAddBanRoom");
if (destRoom)
{
std::string roomName;
makeRoomName(destRoom, roomName);
// Update info about the room
std::unordered_map<std::string, ChatServerRoomOwner>::iterator f = roomList.find(toLower(roomName));
if(f != roomList.end())
(*f).second.updateRoomData(destRoom);
// See who created the room
ChatAvatarId creatorAvatarId;
makeAvatarId(destRoom->getCreatorName(), destRoom->getCreatorAddress(), creatorAvatarId);
// Clients don't want to know who belongs to the system created rooms
// NOTE: The name for the system avatar should be the same for all clusters
if (!Unicode::caseInsensitiveCompare(creatorAvatarId.getName(), ChatServer::getSystemAvatarId().getName()))
{
ChatServer::fileLog(s_enableChatRoomLogs, "ChatInterface", "OnReceiveAddBanRoom() updating clients with member info for chatRoom(%s)", ChatServer::getChatRoomNameNarrow(destRoom).c_str());
// Tell all the avatars in the room the new member info
updateRoomForThisChatAPI(destRoom, destAvatar);
}
}
}
//-----------------------------------------------------------------------
// OnReceiveAddBanAvatar
// Called when srcAvatar has banned destAvatar from the room described by
// roomName and roomAddress, and destAvatar is on this API.
void ChatInterface::OnReceiveAddBanAvatar(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, const ChatUnicodeString &roomName, const ChatUnicodeString &roomAddress)
{
ChatServer::fileLog(s_enableChatRoomLogs, "ChatInterface", "OnReceiveAddBanAvatar() srcAvatar(%s) destAvatar(%s) roomName(%s) roomAddress(%s)", ChatServer::getFullChatAvatarName(srcAvatar).c_str(), ChatServer::getFullChatAvatarName(destAvatar).c_str(), ChatServer::toNarrowString(roomName).c_str(), ChatServer::toNarrowString(roomAddress).c_str());
}
//-----------------------------------------------------------------------
// Response to RequestRemoveBan(...)
void ChatInterface::OnRemoveBan(unsigned track, unsigned result, const ChatAvatar *srcAvatar, const ChatRoom *destRoom, void *user)
{
ChatServer::fileLog(s_enableChatRoomLogs, "ChatInterface", "OnRemoveBan() track(%u) result(%u) srcAvatar(%s) destRoom(%s)", track, result, ChatServer::getFullChatAvatarName(srcAvatar).c_str(), ChatServer::getChatRoomNameNarrow(destRoom).c_str());
PROFILER_AUTO_BLOCK_DEFINE("ChatInterface - OnRemoveBan");
if (result == CHATRESULT_SUCCESS && (srcAvatar == NULL || destRoom == NULL))
{
DEBUG_WARNING(true, ("We received an OnRemoveBan with a success result code but NULL data. This is an error that the API should never give."));
return;
}
AvatarIdSequencePair *pair = (AvatarIdSequencePair *)user;
unsigned sequence = 0;
ChatAvatarId destId;
if (pair)
{
destId = pair->avatar;
sequence = pair->sequence;
delete pair;
pair = NULL;
}
ChatAvatarId srcId;
if (srcAvatar)
{
makeAvatarId(*srcAvatar, srcId);
}
std::string roomName;
if (destRoom)
{
makeRoomName(destRoom, roomName);
}
// Tell the player making the request whether the ban was successful
ChatOnUnbanAvatarFromRoom const msg(sequence, result, roomName, srcId, destId);
NetworkId responseNetworkId = ChatServer::sendResponseForTrackId(track, msg);
// If we had a success, tell everyone else in the room about it
if (result == CHATRESULT_SUCCESS)
{
if (destRoom)
{
ChatAvatarId responseId;
{
ChatAvatar const * const responseAvatar = ChatServer::getAvatarByNetworkId( responseNetworkId );
if (responseAvatar)
{
makeAvatarId(*responseAvatar, responseId);
}
}
AvatarIterator i = destRoom->getFirstAvatar();
for(; !i.outOfBounds(); ++i)
{
ChatAvatarId id;
makeAvatarId(*(*i), id);
// We already sent a response to the avatar that made the request
if (id != responseId)
{
sendMessageToAvatar(id, msg);
}
}
}
}
}
//-----------------------------------------------------------------------
// OnReceiveRemoveBanRoom
// Called when srcAvatar has removed the ban on destAvatar from
// destRoom and this API has avatars that are in destRoom.
void ChatInterface::OnReceiveRemoveBanRoom(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, const ChatRoom *destRoom)
{
ChatServer::fileLog(s_enableChatRoomLogs, "ChatInterface", "OnReceiveRemoveBanRoom() srcAvatar(%s) destAvatar(%s) destRoom(%s)", ChatServer::getFullChatAvatarName(srcAvatar).c_str(), ChatServer::getFullChatAvatarName(destAvatar).c_str(), ChatServer::getChatRoomNameNarrow(destRoom).c_str());
PROFILER_AUTO_BLOCK_DEFINE("ChatInterface - OnReceiveRemoveBanRoom");
if (destRoom)
{
std::string roomName;
makeRoomName(destRoom, roomName);
// Update info about the room
std::unordered_map<std::string, ChatServerRoomOwner>::iterator f = roomList.find(toLower(roomName));
if(f != roomList.end())
(*f).second.updateRoomData(destRoom);
// See who created the room
ChatAvatarId creatorAvatarId;
makeAvatarId(destRoom->getCreatorName(), destRoom->getCreatorAddress(), creatorAvatarId);
// Clients don't want to know who belongs to the system created rooms
// NOTE: The name for the system avatar should be the same for all clusters
if (!Unicode::caseInsensitiveCompare(creatorAvatarId.getName(), ChatServer::getSystemAvatarId().getName()))
{
ChatServer::fileLog(s_enableChatRoomLogs, "ChatInterface", "OnReceiveRemoveBanRoom() updating clients with member info for chatRoom(%s)", ChatServer::getChatRoomNameNarrow(destRoom).c_str());
// Tell all the avatars in the room the new member info
updateRoomForThisChatAPI(destRoom, destAvatar);
}
}
}
//-----------------------------------------------------------------------
// OnReceiveRemoveBanAvatar
// Called when srcAvatar has removed the ban on destAvatar from
// the room described by roomName and roomAddress, and destAvatar is on
// this API.
void ChatInterface::OnReceiveRemoveBanAvatar(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, const ChatUnicodeString &roomName, const ChatUnicodeString &roomAddress)
{
ChatServer::fileLog(s_enableChatRoomLogs, "ChatInterface", "OnReceiveRemoveBanAvatar() srcAvatar(%s) destAvatar(%s) roomName(%s) roomAddress(%s)", ChatServer::getFullChatAvatarName(srcAvatar).c_str(), ChatServer::getFullChatAvatarName(destAvatar).c_str(), ChatServer::toNarrowString(roomName).c_str(), ChatServer::toNarrowString(roomAddress).c_str());
}
//-----------------------------------------------------------------------
// Response to RequestAddInvite(...)
void ChatInterface::OnAddInvite(unsigned track, unsigned result, const ChatAvatar *srcAvatar, const ChatRoom *destRoom, void *user)
{
ChatServer::fileLog(s_enableChatRoomLogs, "ChatInterface", "OnAddInvite() track(%u) result(%u) srcAvatar(%s) destRoom(%s)", track, result, ChatServer::getFullChatAvatarName(srcAvatar).c_str(), ChatServer::getChatRoomNameNarrow(destRoom).c_str());
PROFILER_AUTO_BLOCK_DEFINE("ChatInterface - OnAddInvite");
if (result == CHATRESULT_SUCCESS && (srcAvatar == NULL || destRoom == NULL))
{
DEBUG_WARNING(true, ("We received an OnAddInvite with a success result code but NULL data. This is an error that the API should never give."));
return;
}
AvatarIdSequencePair *pair = (AvatarIdSequencePair *)user;
unsigned sequence = 0;
ChatAvatarId destId;
if (pair)
{
destId = pair->avatar;
sequence = pair->sequence;
delete pair;
pair = NULL;
}
ChatAvatarId srcId;
if (srcAvatar)
{
makeAvatarId(*srcAvatar, srcId);
}
std::string roomName;
if (destRoom)
{
makeRoomName(destRoom, roomName);
}
// Tell the player making the request whether the invite was successful
ChatOnInviteToRoom const msg(result, roomName, srcId, destId);
NetworkId responseNetworkId = ChatServer::sendResponseForTrackId(track, msg);
if (result == CHATRESULT_SUCCESS)
{
if (destRoom)
{
// Calling this on a room will cause the API to cache the room
// and to receive room updates for the room.
RequestGetRoom(destRoom->getAddress(), NULL);
// Send the room data for the room the avatar was invited to join
// since the room may be private and may be unknown to the player
ChatServerRoomOwner const * const roomOwner = getRoomOwner(destRoom->getRoomID());
if (roomOwner)
{
std::vector<ChatRoomData> rooms;
ChatRoomData data = roomOwner->getRoomData();
rooms.push_back(data);
ChatRoomList const r(rooms);
ChatServer::fileLog(s_enableChatRoomLogs, "ChatInterface", "OnAddInvite() sending room list of %u rooms to (%s)", r.getRoomData().size(), destId.getFullName().c_str());
sendMessageToAvatar(destId, r);
}
}
// Tell the invited person about the invitation
ChatOnReceiveRoomInvitation const chat(roomName, srcId);
sendMessageToAvatar(destId, chat);
}
}
//-----------------------------------------------------------------------
// OnReceiveAddInviteRoom
// Called when srcAvatar has invited destAvatar to destRoom and this
// API has avatars that are in this room.
void ChatInterface::OnReceiveAddInviteRoom(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, const ChatRoom *destRoom)
{
ChatServer::fileLog(s_enableChatRoomLogs, "ChatInterface", "OnReceiveAddInviteRoom() srcAvatar(%s) destAvatar(%s) destRoom(%s)", ChatServer::getFullChatAvatarName(srcAvatar).c_str(), ChatServer::getFullChatAvatarName(destAvatar).c_str(), ChatServer::getChatRoomNameNarrow(destRoom).c_str());
PROFILER_AUTO_BLOCK_DEFINE("ChatInterface - OnReceiveAddInviteRoom");
if (destRoom)
{
std::string roomName;
makeRoomName(destRoom, roomName);
// Update info about the room
std::unordered_map<std::string, ChatServerRoomOwner>::iterator f = roomList.find(toLower(roomName));
if(f != roomList.end())
(*f).second.updateRoomData(destRoom);
// See who created the room
ChatAvatarId creatorAvatarId;
makeAvatarId(destRoom->getCreatorName(), destRoom->getCreatorAddress(), creatorAvatarId);
// Clients don't want to know who belongs to the system created rooms
// NOTE: The name for the system avatar should be the same for all clusters
if (!Unicode::caseInsensitiveCompare(creatorAvatarId.getName(), ChatServer::getSystemAvatarId().getName()))
{
ChatServer::fileLog(s_enableChatRoomLogs, "ChatInterface", "OnReceiveAddInviteRoom() updating clients with member info for chatRoom(%s)", ChatServer::getChatRoomNameNarrow(destRoom).c_str());
// Tell all the avatars in the room the new member info
updateRoomForThisChatAPI(destRoom, 0);
}
}
}
//-----------------------------------------------------------------------
// OnReceiveAddInviteAvatar
// Called when srcAvatar has invited destAvatar to the room described
// by roomName and roomAddress, and destAvatar is on this API.
void ChatInterface::OnReceiveAddInviteAvatar(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, const ChatUnicodeString &roomName, const ChatUnicodeString &roomAddress)
{
ChatServer::fileLog(s_enableChatRoomLogs, "ChatInterface", "OnReceiveAddInviteAvatar() srcAvatar(%s) destAvatar(%s) roomName(%s) roomAddress(%s)", ChatServer::getFullChatAvatarName(srcAvatar).c_str(), ChatServer::getFullChatAvatarName(destAvatar).c_str(), ChatServer::toNarrowString(roomName).c_str(), ChatServer::toNarrowString(roomAddress).c_str());
}
//-----------------------------------------------------------------------
// Response to RequestRemoveInvite(...)
void ChatInterface::OnRemoveInvite(unsigned track, unsigned result, const ChatAvatar *srcAvatar, const ChatRoom *destRoom, void *user)
{
ChatServer::fileLog(s_enableChatRoomLogs, "ChatInterface", "OnRemoveInvite() track(%u) result(%u) srcAvatar(%s) destRoom(%s)", track, result, ChatServer::getFullChatAvatarName(srcAvatar).c_str(), ChatServer::getChatRoomNameNarrow(destRoom).c_str());
PROFILER_AUTO_BLOCK_DEFINE("ChatInterface - OnRemoveInvite");
if (result == CHATRESULT_SUCCESS && (srcAvatar == NULL || destRoom == NULL))
{
DEBUG_WARNING(true, ("We received an OnRemoveInvite with a success result code but NULL data. This is an error that the API should never give."));
return;
}
AvatarIdSequencePair *pair = (AvatarIdSequencePair *)user;
unsigned sequence = 0;
ChatAvatarId inviteeId;
if (pair)
{
inviteeId = pair->avatar;
sequence = pair->sequence;
delete pair;
pair = NULL;
}
std::string roomName;
if (destRoom)
{
makeRoomName(destRoom, roomName);
}
ChatAvatarId invitorId;
if (srcAvatar)
{
makeAvatarId(*srcAvatar, invitorId);
}
//if the sequence is 0, the message initiated from the game server. Don't
//bother telling the client that something failed when they didn't even
//ask to do it.
if (sequence != 0)
{
ChatOnUninviteFromRoom const msg(sequence, result, roomName, invitorId, inviteeId);
IGNORE_RETURN(ChatServer::sendResponseForTrackId(track, msg));
}
else
{
// We still need to somehow remove the pending request from the queue
IGNORE_RETURN(ChatServer::getAvatarIdForTrackId(track));
}
}
//-----------------------------------------------------------------------
// OnReceiveRemoveInviteRoom
// Called when srcAvatar has uninvited destAvatar from destRoom and
// this API has avatars that are in this room.
void ChatInterface::OnReceiveRemoveInviteRoom(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, const ChatRoom *destRoom)
{
ChatServer::fileLog(s_enableChatRoomLogs, "ChatInterface", "OnReceiveRemoveInviteRoom() srcAvatar(%s) destAvatar(%s) chatRoom(%s)", ChatServer::getFullChatAvatarName(srcAvatar).c_str(), ChatServer::getFullChatAvatarName(destAvatar).c_str(), ChatServer::getChatRoomNameNarrow(destRoom).c_str());
PROFILER_AUTO_BLOCK_DEFINE("ChatInterface - OnReceiveRemoveInviteRoom");
if (destRoom)
{
std::string roomName;
makeRoomName(destRoom, roomName);
// Update info about the room
std::unordered_map<std::string, ChatServerRoomOwner>::iterator f = roomList.find(toLower(roomName));
if(f != roomList.end())
(*f).second.updateRoomData(destRoom);
// See who created the room
ChatAvatarId creatorAvatarId;
makeAvatarId(destRoom->getCreatorName(), destRoom->getCreatorAddress(), creatorAvatarId);
// Clients don't want to know who belongs to the system created rooms
// NOTE: The name for the system avatar should be the same for all clusters
if (!Unicode::caseInsensitiveCompare(creatorAvatarId.getName(), ChatServer::getSystemAvatarId().getName()))
{
ChatServer::fileLog(s_enableChatRoomLogs, "ChatInterface", "OnReceiveRemoveInviteRoom() updating clients with member info for chatRoom(%s)", ChatServer::getChatRoomNameNarrow(destRoom).c_str());
// Tell all the avatars in the room the new member info
updateRoomForThisChatAPI(destRoom, 0);
}
}
}
//-----------------------------------------------------------------------
// OnReceiveRemoveInviteAvatar
// Called when srcAvatar has uninvited destAvatar from the room
// described by roomName and roomAddress, and destAvatar is on
// this API.
void ChatInterface::OnReceiveRemoveInviteAvatar(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, const ChatUnicodeString &roomName, const ChatUnicodeString &roomAddress)
{
ChatServer::fileLog(s_enableChatRoomLogs, "ChatInterface", "OnReceiveRemoveInviteAvatar() srcAvatar(%s) destAvatar(%s) roomName(%s) roomAddress(%s)", ChatServer::getFullChatAvatarName(srcAvatar).c_str(), ChatServer::getFullChatAvatarName(destAvatar).c_str(), ChatServer::toNarrowString(roomName).c_str(), ChatServer::toNarrowString(roomAddress).c_str());
}
//-----------------------------------------------------------------------
// Response to RequestLeaveRoom(...)
void ChatInterface::OnLeaveRoom(unsigned track, unsigned result, const ChatAvatar *srcAvatar, const ChatRoom *destRoom, void *user)
{
ChatServer::fileLog(s_enableChatRoomLogs, "ChatInterface", "OnLeaveRoom() track(%u) result(%u) srcAvatar(%s) destRoom(%s)", track, result, ChatServer::getFullChatAvatarName(srcAvatar).c_str(), ChatServer::getChatRoomNameNarrow(destRoom).c_str());
PROFILER_AUTO_BLOCK_DEFINE("ChatInterface - OnLeaveRoom");
if (result == CHATRESULT_SUCCESS && (srcAvatar == NULL || destRoom == NULL))
{
DEBUG_WARNING(true, ("We received an OnLeaveRoom with a success result code but NULL data. This is an error that the API should never give."));
return;
}
unsigned sequence = (unsigned)user;
ChatAvatarId id;
if (srcAvatar)
{
makeAvatarId(*srcAvatar, id);
}
unsigned roomId = 0;
if (destRoom)
{
roomId = destRoom->getRoomID();
}
// Tell the person requesting to leave the success of the request
ChatOnLeaveRoom const msg(sequence, result, roomId, id);
IGNORE_RETURN(ChatServer::sendResponseForTrackId(track, msg));
// We'll tell everyone else in the room about it in OnReceiveLeaveRoom()
}
//-----------------------------------------------------------------------
// OnReceiveLeaveRoom
// Called when srcAvatar has left destRoom and this API has avatars
// that are in destRoom.
void ChatInterface::OnReceiveLeaveRoom(const ChatAvatar *srcAvatar, const ChatRoom *destRoom)
{
ChatServer::fileLog(s_enableChatRoomLogs, "ChatInterface", "OnReceiveLeaveRoom() srcAvatar(%s) destRoom(%s)", ChatServer::getFullChatAvatarName(srcAvatar).c_str(), ChatServer::getChatRoomNameNarrow(destRoom).c_str());
PROFILER_AUTO_BLOCK_DEFINE("ChatInterface - OnReceiveLeaveRoom");
if (destRoom)
{
std::string roomName;
makeRoomName(destRoom, roomName);
// Update info about the room
std::unordered_map<std::string, ChatServerRoomOwner>::iterator const f = roomList.find(toLower(roomName));
if(f != roomList.end())
(*f).second.updateRoomData(destRoom);
// See who created the room
ChatAvatarId creatorAvatarId;
makeAvatarId(destRoom->getCreatorName(), destRoom->getCreatorAddress(), creatorAvatarId);
// Clients don't want to know who belongs to the system created rooms
// NOTE: The name for the system avatar should be the same for all clusters
if (!Unicode::caseInsensitiveCompare(creatorAvatarId.getName(), ChatServer::getSystemAvatarId().getName()))
{
ChatServer::fileLog(s_enableChatRoomLogs, "ChatInterface", "OnReceiveLeaveRoom() updating clients with member info for chatRoom(%s)", ChatServer::getChatRoomNameNarrow(destRoom).c_str());
// Tell all the avatars in the room the new member info
updateRoomForThisChatAPI(destRoom, srcAvatar);
}
// If we didn't send the updated room information, then just send the
// message to everyone in the room that the person has left the room
else if ((f != roomList.end()) && srcAvatar)
{
ChatAvatarId srcAvatarId;
makeAvatarId(*srcAvatar, srcAvatarId);
ChatOnLeaveRoom const msg(0, CHATRESULT_SUCCESS, destRoom->getRoomID(), srcAvatarId);
AvatarIterator i = destRoom->getFirstAvatar();
for(; !i.outOfBounds(); ++i)
{
ChatAvatarId id;
makeAvatarId(*(*i), id);
sendMessageToAvatar(id, msg);
}
}
}
}
//-----------------------------------------------------------------------
// Response to RequestKickAvatar(...)
void ChatInterface::OnKickAvatar(unsigned track, unsigned result, const ChatAvatar *srcAvatar, const ChatRoom *destRoom, void *user)
{
ChatServer::fileLog(s_enableChatRoomLogs, "ChatInterface", "OnKickAvatar() track(%u) result(%u) srcAvatar(%s) destRoom(%s)", track, result, ChatServer::getFullChatAvatarName(srcAvatar).c_str(), ChatServer::getChatRoomNameNarrow(destRoom).c_str());
PROFILER_AUTO_BLOCK_DEFINE("ChatInterface - OnKickAvatar");
AvatarIdSequencePair *pair = (AvatarIdSequencePair *)user;
unsigned sequence = 0;
ChatAvatarId kickedId;
if (pair)
{
kickedId = pair->avatar;
sequence = pair->sequence;
delete pair;
pair = NULL;
}
std::string roomName;
if (destRoom)
{
makeRoomName(destRoom, roomName);
}
ChatAvatarId srcId;
if (srcAvatar)
{
makeAvatarId(*srcAvatar, srcId);
}
// Tell the person making the kick request whether it was successful
ChatOnKickAvatarFromRoom const msg(result, kickedId, srcId, roomName);
NetworkId responseNetworkId = ChatServer::sendResponseForTrackId(track, msg);
// If we had a success, tell everyone else in the room about it
if (result == CHATRESULT_SUCCESS)
{
if (destRoom)
{
ChatAvatarId responseId;
{
ChatAvatar const * const responseAvatar = ChatServer::getAvatarByNetworkId( responseNetworkId );
if (responseAvatar)
{
makeAvatarId(*responseAvatar, responseId);
}
}
AvatarIterator i = destRoom->getFirstAvatar();
for(; !i.outOfBounds(); ++i)
{
ChatAvatarId id;
makeAvatarId(*(*i), id);
// We already sent a response to the avatar that made the request
if (id != responseId)
{
sendMessageToAvatar(id, msg);
}
}
}
}
}
//-----------------------------------------------------------------------
// OnReceiveKickRoom
// Called when destAvatar has been kicked by srcAvatar from destRoom
// and this API has avatars that are in destRoom.
void ChatInterface::OnReceiveKickRoom(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, const ChatRoom *destRoom)
{
ChatServer::fileLog(s_enableChatRoomLogs, "ChatInterface", "OnReceiveKickRoom() srcAvatar(%s) destAvatar(%s) chatRoom(%s)", ChatServer::getFullChatAvatarName(srcAvatar).c_str(), ChatServer::getFullChatAvatarName(destAvatar).c_str(), ChatServer::getChatRoomNameNarrow(destRoom).c_str());
PROFILER_AUTO_BLOCK_DEFINE("ChatInterface - OnReceiveKickRoom");
if (destRoom)
{
std::string roomName;
makeRoomName(destRoom, roomName);
// Update info about the room
std::unordered_map<std::string, ChatServerRoomOwner>::iterator f = roomList.find(toLower(roomName));
if(f != roomList.end())
(*f).second.updateRoomData(destRoom);
// See who created the room
ChatAvatarId creatorAvatarId;
makeAvatarId(destRoom->getCreatorName(), destRoom->getCreatorAddress(), creatorAvatarId);
// Clients don't want to know who belongs to the system created rooms
// NOTE: The name for the system avatar should be the same for all clusters
if (!Unicode::caseInsensitiveCompare(creatorAvatarId.getName(), ChatServer::getSystemAvatarId().getName()))
{
ChatServer::fileLog(s_enableChatRoomLogs, "ChatInterface", "OnReceiveKickRoom() updating clients with member info for chatRoom(%s)", ChatServer::getChatRoomNameNarrow(destRoom).c_str());
// Tell all the avatars in the room the new member info
updateRoomForThisChatAPI(destRoom, destAvatar);
}
}
}
//-----------------------------------------------------------------------
// OnReceiveKickAvatar
// Called when destAvatar has been kicked by srcAvatar from the room
// described by roomName and roomAddress, and destAvatar is on
// this API.
void ChatInterface::OnReceiveKickAvatar(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, const ChatUnicodeString &roomName, const ChatUnicodeString &roomAddress)
{
ChatServer::fileLog(s_enableChatRoomLogs, "ChatInterface", "OnReceiveKickAvatar() srcAvatar(%s) destAvatar(%s) roomName(%s) roomAddress(%s)", ChatServer::getFullChatAvatarName(srcAvatar).c_str(), ChatServer::getFullChatAvatarName(destAvatar).c_str(), ChatServer::toNarrowString(roomName).c_str(), ChatServer::toNarrowString(roomAddress).c_str());
}
//-----------------------------------------------------------------------
void ChatInterface::OnGetPersistentMessage(unsigned track, unsigned result, ChatAvatar *destAvatar, const PersistentHeader *header, const ChatUnicodeString &msg, const ChatUnicodeString &oob, void *user)
{
ChatServer::fileLog(false, "ChatInterface", "OnGetPersistentMessage() track(%u) result(%u) destAvatar(%s)", track, result, ChatServer::getFullChatAvatarName(destAvatar).c_str());
PROFILER_AUTO_BLOCK_DEFINE("ChatInterface - OnGetPersistentMessage");
if (result == CHATRESULT_SUCCESS && (destAvatar == NULL))
{
DEBUG_WARNING(true, ("We received an OnGetPersistentMessage with a success result code but NULL data. This is an error that the API should never give."));
return;
}
UNREF(user);
UNREF(track);
if (!destAvatar || !header)
{
return;
}
if(result == CHATRESULT_SUCCESS) //lint !e641 Converting enum 'ChatResult' to int // jrandall That's what is passed to this method by the ChatAPI
{
ChatAvatarId fromId;
fromId.name = Unicode::wideToNarrow(Unicode::String(header->getFromName().string_data, header->getFromName().string_length));
std::string tmpAddress = Unicode::wideToNarrow(Unicode::String(header->getFromAddress().string_data, header->getFromAddress().string_length));
char *str = (char *)tmpAddress.c_str();
char *loc = strstr(str, ".");
if (loc)
{
*loc = 0;
fromId.gameCode = str;
fromId.cluster = loc+1;
}
Unicode::String subject = (Unicode::String(header->getSubject().string_data, header->getSubject().string_length));
//printf("PM from OnGetPersistentMessage\n");
const ChatPersistentMessageToClient m(
header->getMessageID(),
convertPmStatus (header->getStatus()),
fromId.gameCode,
fromId.cluster,
fromId.name,
subject,
Unicode::String(msg.string_data, msg.string_length),
Unicode::String(oob.string_data, oob.string_length),
header->getSentTime()
);
ChatAvatarId toId;
makeAvatarId(*destAvatar, toId);
sendMessageToAvatar(toId, m);
}
}
//-----------------------------------------------------------------------
void ChatInterface::OnGetPersistentHeaders(unsigned track, unsigned result, ChatAvatar *destAvatar, unsigned listLength, const PersistentHeader *list, void *user)
{
ChatServer::fileLog(false, "ChatInterface", "OnGetPersistentHeaders() track(%u) result(%u) destAvatar(%s)", track, result, ChatServer::getFullChatAvatarName(destAvatar).c_str(), listLength);
PROFILER_AUTO_BLOCK_DEFINE("ChatInterface - OnGetPersistentHeaders");
if (result == CHATRESULT_SUCCESS && (destAvatar == NULL))
{
DEBUG_WARNING(true, ("We received an OnGetPersistentHeaders with a success result code but NULL data. This is an error that the API should never give."));
return;
}
UNREF(track);
UNREF(user);
if(result == CHATRESULT_SUCCESS) //lint !e641 Converting enum 'ChatResult' to int // jrandall That's what is passed to this method by the ChatAPI
{
if (!destAvatar || !list)
{
return;
}
ChatAvatarId toAvatar;
makeAvatarId(*destAvatar, toAvatar);
LOG("CustomerService", ("Login:retrieved %u persistent message headers for %s", listLength, toAvatar.getFullName().c_str()));
clearQueuedHeadersForAvatar(toAvatar);
int numberHeadersSent = 0;
const unsigned long queuedHeadersSendTime = Clock::timeSeconds() + static_cast<unsigned long>(s_intervalToSendHeadersToClientSeconds);
for(unsigned i = 0; i < listLength; ++i)
{
ChatAvatarId fromId;
makeAvatarId(list[i].getFromName(), list[i].getFromAddress(), fromId);
Unicode::String subject(list[i].getSubject().string_data, list[i].getSubject().string_length);
//printf("PM from OnGetPersistentHeaders\n");
if (numberHeadersSent < s_maxHeadersToSendToClientPerInterval)
{
const ChatPersistentMessageToClient m(
list[i].getMessageID(),
convertPmStatus (list[i].getStatus()),
fromId.gameCode,
fromId.cluster,
fromId.name,
subject,
list[i].getSentTime());
sendMessageToAvatar(toAvatar, m);
++numberHeadersSent;
}
else
{
const ChatPersistentMessageToClient * m = new ChatPersistentMessageToClient(
list[i].getMessageID(),
convertPmStatus (list[i].getStatus()),
fromId.gameCode,
fromId.cluster,
fromId.name,
subject,
list[i].getSentTime());
addQueuedHeaderForAvatar(toAvatar, m, queuedHeadersSendTime);
}
}
}
}
//-----------------------------------------------------------------------
void ChatInterface::OnReceivePersistentMessage(const ChatAvatar *destAvatar, const PersistentHeader *header)
{
ChatServer::fileLog(false, "ChatInterface", "OnReceivePersistentMessage() destAvatar(%s)", ChatServer::getFullChatAvatarName(destAvatar).c_str());
PROFILER_AUTO_BLOCK_DEFINE("ChatInterface - OnReceivePersistentMessage");
if (destAvatar == NULL)
{
DEBUG_WARNING(true, ("We received an OnREceivePersistentMessage with a success result code but NULL data. This is an error that the API should never give."));
return;
}
if (!header)
{
return;
}
ChatAvatarId toAvatar;
makeAvatarId(*destAvatar, toAvatar);
ChatAvatarId fromId;
makeAvatarId(header->getFromName(), header->getFromAddress(), fromId);
Unicode::String subject(header->getSubject().string_data, header->getSubject().string_length);
//printf("PM from OnReceivePersistentMessage\n");
const ChatPersistentMessageToClient m(
header->getMessageID(),
convertPmStatus (header->getStatus()),
fromId.gameCode,
fromId.cluster,
fromId.name,
subject,
header->getSentTime());
sendMessageToAvatar(toAvatar, m);
}
//-----------------------------------------------------------------------
void ChatInterface::OnSendRoomMessage(unsigned track, unsigned result, const ChatAvatar *srcAvatar, const ChatRoom *destRoom, void *user)
{
ChatServer::fileLog(false, "ChatInterface", "OnSendRoomMessage() track(%u) result(%u) srcAvatar(%s) destRoom(%s)", track, result, ChatServer::getFullChatAvatarName(srcAvatar).c_str(), ChatServer::getChatRoomNameNarrow(destRoom).c_str());
PROFILER_AUTO_BLOCK_DEFINE("ChatInterface - OnSendRoomMessage");
if (result == CHATRESULT_SUCCESS && (srcAvatar == NULL || destRoom == NULL))
{
DEBUG_WARNING(true, ("We received an OnsendRoomMessage with a success result code but NULL data. This is an error that the API should never give."));
return;
}
UNREF(srcAvatar);
UNREF(destRoom);
unsigned sequence = (unsigned)user;
ChatOnSendRoomMessage chat(sequence, result);
IGNORE_RETURN(ChatServer::sendResponseForTrackId(track, chat));
}
//-----------------------------------------------------------------------
void ChatInterface::OnReceiveRoomMessage(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, const ChatRoom *destRoom, const ChatUnicodeString &msg, const ChatUnicodeString &oob, unsigned messageID)
{
ChatServer::fileLog(false, "ChatInterface", "OnReceiveRoomMessage() srcAvatar(%s) destAvatar(%s) destRoom(%s) messageID(%u)", ChatServer::getFullChatAvatarName(srcAvatar).c_str(), ChatServer::getFullChatAvatarName(destAvatar).c_str(), ChatServer::getChatRoomNameNarrow(destRoom).c_str(), messageID);
PROFILER_AUTO_BLOCK_DEFINE("ChatInterface - OnReceiveRoomMessage");
if(! srcAvatar || ! destAvatar || ! destRoom)
{
DEBUG_WARNING(true, ("We received an OnREceiveRoomMessage with a success result code but NULL data. This is an error that the API should never give."));
return;
}
// check to prevent sending duplicate room chat message
{
unsigned const destAvatarId = destAvatar->getAvatarID();
unsigned const destRoomId = destRoom->getRoomID();
std::unordered_map<unsigned, std::pair<unsigned, unsigned> >::iterator const iterFind = s_mostRecentRoomChatMessage.find(destAvatarId);
if (iterFind != s_mostRecentRoomChatMessage.end())
{
if ((iterFind->second.first == destRoomId) && (iterFind->second.second == messageID))
return;
iterFind->second.first = destRoomId;
iterFind->second.second = messageID;
}
else
{
s_mostRecentRoomChatMessage.insert(std::make_pair(destAvatarId, std::make_pair(destRoomId, messageID)));
}
}
ChatAvatarId fromId;
makeAvatarId(*srcAvatar, fromId);
GameNetworkMessage * gnm = 0;
Unicode::String ustrMessage(msg.string_data, msg.string_length);
Unicode::String outOfBand(oob.string_data, oob.string_length);
ChatSystemMessage chat(ChatSystemMessage::BROADCAST, ustrMessage, outOfBand); //lint !e641 enum to int
ChatRoomMessage m(destRoom->getRoomID(), fromId, ustrMessage, outOfBand);
if(fromId == ChatServer::getSystemAvatarId())
{
gnm = &chat;
}
else
{
gnm = &m;
}
ChatAvatarId toId;
makeAvatarId(*destAvatar, toId);
sendMessageToAvatar(toId, *gnm);
// don't log planet-wide chat
const std::string chatRoomName = toLower(ChatServer::getChatRoomNameNarrow(destRoom));
if(chatRoomName != "auction" && chatRoomName != "planet")
{
Unicode::String const wideTo(Unicode::narrowToWide(toId.getFullName()));
Unicode::String const wideFrom(Unicode::narrowToWide(fromId.getFullName()));
ChatServer::instance().logChatMessage(wideTo, wideFrom, Unicode::emptyString, ChatServer::toUnicodeString(msg), ChatServer::getChatRoomName(destRoom));
}
}
//-----------------------------------------------------------------------
void ChatInterface::OnSendInstantMessage(unsigned track, unsigned result, const ChatAvatar *srcAvatar, void *user)
{
ChatServer::fileLog(false, "ChatInterface", "OnSendInstantMessage() track(%u) result(%u) srcAvatar(%s)", track, result, ChatServer::getFullChatAvatarName(srcAvatar).c_str());
PROFILER_AUTO_BLOCK_DEFINE("ChatInterface - OnSendInstantMessage");
if (result == CHATRESULT_SUCCESS && (srcAvatar == NULL))
{
DEBUG_WARNING(true, ("We received an OnSendInstantMessage with a success result code but NULL data. This is an error that the API should never give."));
return;
}
UNREF(srcAvatar);
unsigned sequence = (unsigned)user;
ChatOnSendInstantMessage chat(sequence, result);
IGNORE_RETURN(ChatServer::sendResponseForTrackId(track, chat));
}
//-----------------------------------------------------------------------
void ChatInterface::OnReceiveInstantMessage(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, const ChatUnicodeString &msg, const ChatUnicodeString &oob)
{
ChatServer::fileLog(false, "ChatInterface", "OnReceiveInstantMessage() srcAvatar(%s) destAvatar(%s)", ChatServer::getFullChatAvatarName(srcAvatar).c_str(), ChatServer::getFullChatAvatarName(destAvatar).c_str());
PROFILER_AUTO_BLOCK_DEFINE("ChatInterface - OnReceiveInstantMessage");
if ((srcAvatar == NULL || destAvatar == NULL))
{
DEBUG_WARNING(true, ("We received an OnReceiveInstantMessage with a success result code but NULL data. This is an error that the API should never give."));
return;
}
ChatAvatarId fromId;
makeAvatarId(*srcAvatar, fromId);
ChatAvatarId toId;
makeAvatarId(*destAvatar, toId);
if(fromId == ChatServer::getSystemAvatarId())
{
ChatSystemMessage chat(
ChatSystemMessage::PERSONAL,
Unicode::String(msg.string_data, msg.string_length),
Unicode::String(oob.string_data, oob.string_length)); //lint !e641 enum to int
sendMessageToAvatar(toId, chat);
}
else
{
ChatInstantMessageToClient chat(fromId, Unicode::String(msg.string_data, msg.string_length),
Unicode::String(oob.string_data, oob.string_length));
sendMessageToAvatar(toId, chat);
Unicode::String const wideTo(Unicode::narrowToWide(toId.getFullName()));
Unicode::String const wideFrom(Unicode::narrowToWide(fromId.getFullName()));
ChatServer::instance().logChatMessage(wideTo, wideFrom, wideTo, ChatServer::toUnicodeString(msg), ChatServer::getChannelTell());
ChatServer::instance().logChatMessage(wideFrom, wideFrom, wideTo, ChatServer::toUnicodeString(msg), ChatServer::getChannelTell());
}
}
//-----------------------------------------------------------------------
void ChatInterface::OnSendPersistentMessage(unsigned track, unsigned result, const ChatAvatar *srcAvatar, void *user)
{
ChatServer::fileLog(false, "ChatInterface", "OnSendPersistentMessage() track(%u) result(%u) srcAvatar(%s)", track, result, ChatServer::getFullChatAvatarName(srcAvatar).c_str());
PROFILER_AUTO_BLOCK_DEFINE("ChatInterface - OnSendPersistentMessage");
if (result == CHATRESULT_SUCCESS && (srcAvatar == NULL))
{
DEBUG_WARNING(true, ("We received an OnSendPersistentMessage with a success result code but NULL data. This is an error that the API should never give."));
return;
}
unsigned sequence = (unsigned)user;
UNREF(srcAvatar);
ChatOnSendPersistentMessage chat(sequence, result);
IGNORE_RETURN(ChatServer::sendResponseForTrackId(track, chat));
}
//-----------------------------------------------------------------------
const NetworkId & ChatInterface::getNetworkIdByAvatarId(const ChatAvatarId &id)
{
std::map<ChatAvatarId, ChatServerAvatarOwner *>::iterator f = avatarMap.find(id);
if(f != avatarMap.end())
{
ChatServerAvatarOwner * o = (*f).second;
if (o)
{
return o->getNetworkId();
}
}
else
{
//tmp hack because of the tolower thing
ChatAvatarId lowerId = id;
lowerId.name = toLower(id.name);
f = avatarMap.find(lowerId);
if(f != avatarMap.end())
{
ChatServerAvatarOwner * o = (*f).second;
if (o)
{
return o->getNetworkId();
}
}
}
static NetworkId badId;
return badId;
}
//-----------------------------------------------------------------------
void ChatInterface::disconnectPlayer (const ChatAvatarId & id)
{
ChatServer::fileLog(false, "ChatInterface", "disconnectPlayer() id(%s)", id.getFullName().c_str());
std::map<ChatAvatarId, ChatServerAvatarOwner *>::iterator f = avatarMap.find(id);
if(f != avatarMap.end())
{
ChatServerAvatarOwner * o = (*f).second;
delete o;
avatarMap.erase(f);
}
}
//-----------------------------------------------------------------------
void ChatInterface::OnUpdatePersistentMessages(unsigned track, unsigned result, const ChatAvatar *targetAvatar, void *user)
{
UNREF(track);
// Get the target chat avatar id
ChatAvatarId targetChatAvatarId;
if (targetAvatar != NULL)
{
makeAvatarId(*targetAvatar, targetChatAvatarId);
}
// Get the source chat avatar id
ChatAvatarId sourceChatAvatarId;
NetworkId const *tmpNetworkId = reinterpret_cast<NetworkId const *>(user);
if (tmpNetworkId != NULL)
{
ChatAvatar const *sourceAvatar = ChatServer::getAvatarByNetworkId(*tmpNetworkId);
if (sourceAvatar != NULL)
{
makeAvatarId(*sourceAvatar, sourceChatAvatarId);
}
delete tmpNetworkId;
tmpNetworkId = NULL;
}
ChatServer::fileLog(false, "ChatInterface", "OnUpdatePersistentMessage() track(%u) result(%u) sourceAvatar(%s) targetAvatar(%s)", track, result, sourceChatAvatarId.getFullName().c_str(), targetChatAvatarId.getFullName().c_str());
// Send a response to the person (source) who issued this message
if ( !targetChatAvatarId.getFullName().empty()
&& !sourceChatAvatarId.getFullName().empty())
{
std::string const &targetName = targetChatAvatarId.name;
bool const success = (result == CHATRESULT_SUCCESS);
ChatOnDeleteAllPersistentMessages msg(targetName, success);
sendMessageToAvatar(sourceChatAvatarId, msg);
}
else
{
ChatServer::fileLog(false, "ChatInterface", "OnUpdatePersistentMessage() Unable to resolve source(%s) and target(%s).", sourceChatAvatarId.getFullName().c_str(), targetChatAvatarId.getFullName().c_str());
}
}
//-----------------------------------------------------------------------
void ChatInterface::OnReceiveUnregisterRoomReady(const ChatRoom *destRoom)
{
UNREF(destRoom);
// Overloading default so we don't get a warning messsage
}
//-----------------------------------------------------------------------
void ChatInterface::OnTransferAvatar(unsigned track, unsigned result, unsigned oldUserID, unsigned newUserID, const ChatUnicodeString &oldName, const ChatUnicodeString &newName, const ChatUnicodeString &oldAddress, const ChatUnicodeString &newAddress, void *user)
{
UNREF(user);
LOG("CustomerService", ("CharacterTransfer: Received OnTransferAvatar(%d, %d, %d, %d, %s, %s, %s, %s)", track, result, oldUserID, newUserID, oldName.c_str(), newName.c_str(), oldAddress.c_str(), newAddress.c_str()));
LOG("CustomerService", ("Player: Received OnTransferAvatar(%d, %d, %d, %d, %s, %s, %s, %s)", track, result, oldUserID, newUserID, oldName.c_str(), newName.c_str(), oldAddress.c_str(), newAddress.c_str()));
// if the chat avatar rename was successful, tell each game server that has
// a connected character that has the chat avatar on his friends list or ignore
// list to refresh the friends list and ignore list to update the friends list
// and ignore list with the new chat avatar name
if ((result == CHATRESULT_SUCCESS) && (oldAddress == newAddress) && (oldName != newName))
{
ChatAvatarId const dummyAvatar("SWG", ConfigChatServer::getClusterName(), "dummy");
if (oldAddress == dummyAvatar.getAPIAddress())
{
GenericValueTypeMessage<std::pair<std::string, std::string> > const chatAvatarRenamed("ChatAvatarRenamed", std::make_pair(std::string(oldName.c_str()), std::string(newName.c_str())));
ChatServer::broadcastToGameServers(chatAvatarRenamed);
}
}
}
//-----------------------------------------------------------------------