khanat-opennel-code/code/ryzom/server/src/general_utilities_service/ec_channel.cpp
2017-03-15 20:43:10 +01:00

404 lines
12 KiB
C++

// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
// Copyright (C) 2010 Winch Gate Property Limited
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//-----------------------------------------------------------------------------
// includes
//-----------------------------------------------------------------------------
// game share
#include "game_share/utils.h"
// local
#include "ec_channel.h"
//-----------------------------------------------------------------------------
// namespaces
//-----------------------------------------------------------------------------
using namespace std;
using namespace NLMISC;
using namespace GUS;
//-----------------------------------------------------------------------------
// EC namespace
//-----------------------------------------------------------------------------
namespace EC
{
//-----------------------------------------------------------------------------
// methods CUserGroup
//-----------------------------------------------------------------------------
CUserGroup::CUserGroup(IChannel* parent)
{
_Parent= parent;
}
NLMISC::CSString CUserGroup::processCommand(const NLMISC::CSString& command)
{
CSString result;
CVectorSString tokens;
command.splitWords(tokens);
// if command is empty then just display the user group
if (tokens.empty())
{
return CSString().join(_CharacterIds,' ');
}
// there must be an even number of tokens
if (tokens.size()&1)
return "Bad command syntax (odd token count found): "+command;
// perform a syntax check and giveup if hte syntax is bad
for (uint32 i=0;i<tokens.size();i+=2)
{
if (tokens[i]!="+" && tokens[i]!="-")
return "Bad command syntax (expected '+' or '-' but found '"+tokens[i]+"'): "+command;
if (!tokens[i+1].isValidKeyword())
return "Bad command syntax (expected character naem but found '"+tokens[i]+"'): "+command;
}
// perform adds and removals
for (uint32 i=0;i+1<tokens.size();i+=2)
{
CSString& sign= tokens[i];
CSString& name= tokens[i+1];
nldebug("EC: Treating channel operation: '%s' %s",sign.c_str(),name.c_str());
if (sign=="+")
{
// look to see whether name already exists in this user group
TCharacterIds::iterator it= _CharacterIds.begin();
while (it!=_CharacterIds.end() && (*it)!=name) ++it;
// if name found then we're done so skip forwards
if (it!=_CharacterIds.end())
continue;
// add to this user group
_CharacterIds.push_back(name);
// tell container to add named character to chat list
nldebug("EC: Telling chat channel to add user: %s",name.c_str());
_Parent->_chatAdd(name);
// add a segment to the result string
result+=(result.empty()?"+":" +")+name;
}
else if (sign=="-")
{
// look to see whether name exists in this user group
TCharacterIds::iterator it= _CharacterIds.begin();
while (it!=_CharacterIds.end() && (*it)!=name) ++it;
// if name not found then we're done so skip forwards
if (it==_CharacterIds.end())
continue;
// remove from this user group
(*it)=_CharacterIds.back();
_CharacterIds.pop_back();
// tell container to remove named character from chat list
nldebug("EC: Telling chat channel to remove user: %s",name.c_str());
_Parent->_chatRemove(name);
// add a segment to the result string
result+=(result.empty()?"-":" -")+name;
}
else
{
nlerror("This can never happen because we performed a previous test to ensure that all 'signs' are valid before doing this");
}
}
return result;
}
bool CUserGroup::contains(const TCharacterId& id) const
{
for (uint32 i=_CharacterIds.size();i--;)
if (_CharacterIds[i]==id)
return true;
return false;
}
//-----------------------------------------------------------------------------
// methods IChannel
//-----------------------------------------------------------------------------
IChannel::IChannel(const NLMISC::CSString& name): _Members(this), _Officers(this), _Archs(this)
{
_Chat= CChatManager::getInstance()->createChatChannel(name);
_Chat->setChatCallback(this);
}
IChannel::~IChannel()
{
_Chat->closeChannel();
}
const NLMISC::CSString& IChannel::getChannelName() const
{
return _Chat->getChannelName();
}
const NLMISC::CSString& IChannel::getChannelTitle() const
{
return _Chat->getChannelTitle();
}
void IChannel::setChannelTitle(const NLMISC::CSString& title)
{
_Chat->setChannelTitle(title);
}
void IChannel::addMember(const TCharacterId& id)
{
setRank(id,MEMBER);
}
void IChannel::addOfficer(const TCharacterId& id)
{
setRank(id,OFFICER);
}
void IChannel::addArch(const TCharacterId& id)
{
setRank(id,ARCH);
}
CUserGroup& IChannel::getMembers()
{
return _Members;
}
CUserGroup& IChannel::getOfficers()
{
return _Officers;
}
CUserGroup& IChannel::getArchs()
{
return _Archs;
}
void IChannel::removeUser(const TCharacterId& id)
{
getMembers().processCommand("-"+id);
getOfficers().processCommand("-"+id);
getArchs().processCommand("-"+id);
}
const TChannelRank IChannel::getRank(const TCharacterId& id)
{
if (_Archs.contains(id)) return ARCH;
if (_Officers.contains(id)) return OFFICER;
if (_Members.contains(id)) return MEMBER;
return NO_RANK;
}
void IChannel::setRank(const TCharacterId& id,const TChannelRank& rank)
{
const TChannelRank& oldRank= getRank(id);
// if there's nothing to do then there's nothing to do!
if (oldRank==rank)
return;
// the old rank and new rank differ so start by removing from the old ranking list
switch(oldRank)
{
case MEMBER: getMembers().processCommand("-"+id); break;
case OFFICER: getOfficers().processCommand("-"+id); break;
case ARCH: getArchs().processCommand("-"+id); break;
default: break;
};
// add the client to one of the user groups or ignore him if the new rank
switch(rank)
{
case MEMBER: getMembers().processCommand("+"+id); break;
case OFFICER: getOfficers().processCommand("+"+id); break;
case ARCH: getArchs().processCommand("+"+id); break;
default: break;
};
// perform additions or removals to/from chat provoked by the rank change
_chatUpdate();
}
void IChannel::displayMembers()
{
InfoLog->displayNL("Members: %s",getMembers().processCommand("").c_str());
}
void IChannel::displayOfficers()
{
InfoLog->displayNL("Officers: %s",getOfficers().processCommand("").c_str());
}
void IChannel::displayArchs()
{
InfoLog->displayNL("Archs: %s",getArchs().processCommand("").c_str());
}
void IChannel::displayAllUsers()
{
displayMembers();
displayOfficers();
displayArchs();
}
void IChannel::sendMessage(GUS::TClientId clientId,const NLMISC::CSString& speaker,const NLMISC::CSString& txt)
{
getChannel().sendMessage(clientId,speaker,txt);
}
void IChannel::broadcastMessage(const NLMISC::CSString& speaker,const NLMISC::CSString& txt)
{
getChannel().broadcastMessage(speaker,txt);
}
CChatChannel& IChannel::getChannel()
{
nlassert(_Chat!=NULL);
return *_Chat;
}
void IChannel::receiveMessage(GUS::TClientId clientId,const ucstring& txt)
{
// call the cbChatText callback
TCharacterId id= CClientManager::getInstance()->getCharacterName(clientId);
cbChatText(getRank(id),id,clientId,txt.toUtf8());
// perform additions or removals to/from chat provoked by processing of the received message
_chatUpdate();
}
void IChannel::clientReadyInChannel(CChatChannel *chatChannel, GUS::TClientId clientId)
{
BOMB_IF(_Chat!=chatChannel,"Unexpected receipt of clientReadyInChannel callback for wrong chat channel",return);
// call the cbAddUser callback
TCharacterId id= CClientManager::getInstance()->getCharacterName(clientId);
cbAddUser(getRank(id),id,clientId);
}
bool IChannel::isClientAllowedInChatChannel(GUS::TClientId clientId, CChatChannel *chatChannel)
{
BOMB_IF(_Chat!=chatChannel,"Unexpected receipt of isClientAllowedInChatChannel callback for wrong chat channel",return false);
TCharacterId id= CClientManager::getInstance()->getCharacterName(clientId);
return _Members.contains(id) || _Officers.contains(id) || _Archs.contains(id);
}
void IChannel::_chatAdd(const TCharacterId& name)
{
// either add to the container's adds list or remove from its removes list
if (_ChatRemoves.find(name)==_ChatRemoves.end())
{
// add name to the container channel's 'adds' list
_ChatAdds.insert(name);
nldebug("EC: Adding user to 'add' list: %s",name.c_str());
}
else
{
// remove name from the container channel's 'removes' list
_ChatRemoves.erase(name);
nldebug("EC: Removing user from 'remove' list: %s",name.c_str());
}
}
void IChannel::_chatRemove(const TCharacterId& name)
{
// either add to the container's removes list or remove from its adds list
if (_ChatAdds.find(name)==_ChatAdds.end())
{
// add name to the container channel's 'removes' list
_ChatRemoves.insert(name);
nldebug("EC: Adding user to 'remove' list: %s",name.c_str());
}
else
{
// remove name from the container channel's 'adds' list
_ChatAdds.erase(name);
nldebug("EC: Removing user from 'add' list: %s",name.c_str());
}
}
void IChannel::_chatUpdate()
{
// if nothing to do then give up
if (_ChatRemoves.empty() && _ChatAdds.empty())
return;
// remove players in the ChatRemoves set from the chat channel
if (!_ChatRemoves.empty())
{
nldebug("EC: Treating chat removes for channel: %s (%d removes)",getChannelTitle().c_str(),_ChatRemoves.size());
CSString removes;
for (TUntreatedUserSet::iterator it= _ChatRemoves.begin();it!=_ChatRemoves.end();++it)
{
// try to get the client id from the id, treating the id as a character name
TClientId clientId= CClientManager::getInstance()->getClientId(*it);
nldebug("EC: - Adding Client: %s(%d)",(*it).c_str(),clientId.getIndex());
// if we don't have a handle on the player then we're all done as they can't be logged in
if (clientId== BadTClientId)
continue;
// remove the player from the current chat group
_Chat->removeClient(clientId);
// call the cbRemoveUser callback
TCharacterId id= CClientManager::getInstance()->getCharacterName(clientId);
cbRemoveUser(getRank(id),id,clientId);
// add a block to the log string
removes+= (removes.empty()?"":" ")+ (*it);
}
nlinfo("EC: update chat: remove %d: online: %s",_ChatRemoves.size(),removes.c_str());
_ChatRemoves.clear();
}
// add players in the ChatAdds set to the chat channel
if (!_ChatAdds.empty())
{
nldebug("EC: Treating chat adds for channel: %s (%d adds)",getChannelTitle().c_str(),_ChatAdds.size());
CSString adds;
for (TUntreatedUserSet::iterator it= _ChatAdds.begin();it!=_ChatAdds.end();++it)
{
// try to get the client id from the id, treating the id as a character name
TClientId clientId= CClientManager::getInstance()->getClientId(*it);
nldebug("EC: - Removing Client: %s(%d)",(*it).c_str(),clientId.getIndex());
// if we don't have a handle on the player then we're all done as they can't be logged in
if (clientId== BadTClientId)
continue;
// add the client to the chat channel
_Chat->addClient(clientId);
// add a block to the log string
adds+= (adds.empty()?"":" ")+ (*it);
}
nlinfo("EC: update chat: add %d: online: %s",_ChatAdds.size(),adds.c_str());
_ChatAdds.clear();
}
}
}