// Ryzom - MMORPG Framework
// 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 .
#include "stdpch.h"
#include "chat_client.h"
#include "input_output_service.h"
using namespace std;
using namespace NLMISC;
using namespace NLNET;
CVariable VerboseChat("ios","VerboseChat", "Set verbosity for chat debugging", false, 0, true);
extern CVariable VerboseChatManagement;
//-----------------------------------------------
// CChatClient
//
//-----------------------------------------------
CChatClient::CChatClient( const TDataSetRow& index )
//: _SayAudience(CChatGroup::say, ""),
// _ShoutAudience(CChatGroup::shout, "")
{
_DataSetIndex = index;
_Id = TheDataset.getEntityId(index);
// create fake groupe id for say and sout audience
_SayAudienceId = CEntityId(RYZOMID::chatGroup, _Id.getShortId()|(uint64(1)<<(CEntityId::ID_SIZE-1)));
_ShoutAudienceId = CEntityId(RYZOMID::chatGroup, _Id.getShortId()|(uint64(1)<<(CEntityId::ID_SIZE-2)));
// register the client chat groups
CChatManager &cm = IOS->getChatManager();
cm.addGroup(_SayAudienceId, CChatGroup::say, "");
cm.addGroup(_ShoutAudienceId, CChatGroup::shout, "");
_Muted = false;
_ChatMode = CChatGroup::say;
_SayLastAudienceUpdateTime = CTime::getLocalTime();
_ShoutLastAudienceUpdateTime = _SayLastAudienceUpdateTime;
_AudienceUpdatePeriod = 1000;
_DynChatChan = 0;
} // CChatClient //
CChatClient::~CChatClient()
{
CChatManager &cm = IOS->getChatManager();
cm.removeGroup(_SayAudienceId);
cm.removeGroup(_ShoutAudienceId);
}
void CChatClient::setChatMode( CChatGroup::TGroupType mode, TChanID dynChatChan)
{
_ChatMode = mode;
_DynChatChan = dynChatChan;
}
/*
// store chat group subscribe
void CChatClient::subscribeInChatGroup(CChatGroup::TGroupType type, TGroupId groupId)
{
CChatGroup::TGroupType type = groupId.getType();
_AllChatGroups.
}
// store chat group unsubscribe
void CChatClient::unsubscribeInChatGroup(CChatGroup::TGroupType type, TGroupId groupId);
{
}
*/
//-----------------------------------------------
// mute
//
//-----------------------------------------------
void CChatClient::mute( sint32 delay )
{
if( _Muted )
{
_Muted = false;
}
else
{
_Muted = true;
_MuteStartTime = CTime::getLocalTime();
_MuteDelay = delay;
}
} // mute //
//-----------------------------------------------
// isMuted
//
//-----------------------------------------------
bool CChatClient::isMuted()
{
if( !_Muted )
{
return false;
}
else
{
if( _MuteDelay != -1 )
{
TTime time = CTime::getLocalTime();
if( time > _MuteStartTime + _MuteDelay * 60 * 1000 )
{
_Muted = false;
return false;
}
}
return true;
}
} // isMuted //
//-----------------------------------------------
// ignore :
//
//-----------------------------------------------
void CChatClient::setIgnoreStatus( const NLMISC::CEntityId &id, bool ignored)
{
TIgnoreListCont::iterator itIgnore = _IgnoreList.find(id);
if (ignored)
{
if( itIgnore == _IgnoreList.end() )
{
_IgnoreList.insert( id );
}
}
else
{
if( itIgnore != _IgnoreList.end() )
{
_IgnoreList.erase( itIgnore );
}
}
} // ignore //
//-----------------------------------------------
// isInIgnoreList :
//
//-----------------------------------------------
bool CChatClient::isInIgnoreList( const NLMISC::CEntityId &id )
{
TIgnoreListCont::const_iterator itIgnore = _IgnoreList.find(id);
if( itIgnore != _IgnoreList.end() )
{
return true;
}
else
{
return false;
}
} // isInIgnoreList //
//-----------------------------------------------
// isInIgnoreList :
//
//-----------------------------------------------
bool CChatClient::isInIgnoreList( const TDataSetRow &id )
{
const NLMISC::CEntityId &ei = IOS->DataSet->getEntityId(id);
if (ei == NLMISC::CEntityId::Unknown) return false;
return isInIgnoreList(ei);
}
//-----------------------------------------------
// setIgnoreList
//
//-----------------------------------------------
void CChatClient::setIgnoreList(const std::vector &ignoreList)
{
TIgnoreListCont ignoreListCont(ignoreList.begin(), ignoreList.end());
_IgnoreList.swap(ignoreListCont);
}
//-----------------------------------------------
// filter :
//
//-----------------------------------------------
void CChatClient::filter( TFilter filterId )
{
set::iterator itF = _Filters.find( filterId );
if( itF != _Filters.end() )
{
_Filters.insert( filterId );
}
else
{
_Filters.erase( itF );
}
} // addGameplayFilter //
//-----------------------------------------------
// getAudience :
//
//-----------------------------------------------
CChatGroup& CChatClient::getAudience()
{
CChatManager &cm = IOS->getChatManager();
if(_ChatMode == CChatGroup::shout)
return cm.getGroup(_ShoutAudienceId);
else
return cm.getGroup(_SayAudienceId);
} // getAudience //
//-----------------------------------------------
// getSayAudience :
//
//-----------------------------------------------
CChatGroup& CChatClient::getSayAudience( bool update )
{
CChatManager &cm = IOS->getChatManager();
if( update )
{
updateAudience( _SayAudienceId, MaxDistSay, _SayLastAudienceUpdateTime );
}
return cm.getGroup(_SayAudienceId);
} // getSayAudience //
//-----------------------------------------------
// getShoutAudience :
//
//-----------------------------------------------
CChatGroup& CChatClient::getShoutAudience( bool update )
{
CChatManager &cm = IOS->getChatManager();
if( update )
{
updateAudience( _ShoutAudienceId, MaxDistShout, _ShoutLastAudienceUpdateTime );
}
return cm.getGroup(_ShoutAudienceId);
} // getShoutAudience //
//-----------------------------------------------
// updateAudience :
//
//-----------------------------------------------
void CChatClient::updateAudience()
{
switch( _ChatMode )
{
case CChatGroup::say :
{
updateAudience( _SayAudienceId, MaxDistSay, _SayLastAudienceUpdateTime );
}
break;
case CChatGroup::shout :
{
updateAudience( _ShoutAudienceId, MaxDistShout, _ShoutLastAudienceUpdateTime );
}
break;
default:
{
return;
}
}
} // updateAudience //
//-----------------------------------------------
// updateAudience :
//
//-----------------------------------------------
void CChatClient::updateAudience( CEntityId &audienceId, sint maxDist, TTime& lastAudienceUpdateTime )
{
// get the cell and coordinates of the player
CMirrorPropValueRO instanceId( TheDataset, _DataSetIndex, DSPropertyAI_INSTANCE );
CMirrorPropValueRO cell( TheDataset, _DataSetIndex, DSPropertyCELL );
sint32 cellS = (sint32)(cell());
CChatManager &cm = IOS->getChatManager();
CChatGroup &audience = cm.getGroup(audienceId);
// test if player is in an 'elevator' cell
if( cellS == -1 )
{
while (!audience.Members.empty())
cm.removeFromGroup(audienceId, *audience.Members.begin());
}
else
{
// if time has come to update player's audience
TTime currentTime = CTime::getLocalTime();
if( currentTime - lastAudienceUpdateTime > _AudienceUpdatePeriod )
{
// Browse all the entities!
TEntityIdToEntityIndexMap::const_iterator itEntityIndex;
for( itEntityIndex = TheDataset.entityBegin(); itEntityIndex != TheDataset.entityEnd(); ++itEntityIndex )
{
TDataSetRow entityIndex = TheDataset.getCurrentDataSetRow( GET_ENTITY_INDEX(itEntityIndex) );
const CEntityId& entityId = (*itEntityIndex).first;
if (entityIndex.isValid())
{
if ( entityId.getType() == RYZOMID::player )
{
bool isInAudience = false;
CMirrorPropValueRO charInstanceId( TheDataset, entityIndex, DSPropertyAI_INSTANCE);
// first of all, check the instance id
if (instanceId == charInstanceId)
{
CMirrorPropValueRO charCell( TheDataset, entityIndex, DSPropertyCELL );
// if the player is NOT in an appartment
if( cellS > 0 )
{
uint16 senderCellX = (uint16)(cell>>16);
uint16 senderCellY = (uint16)(cell&0xffff);
uint16 charCellX = (uint16)(charCell>>16);
uint16 charCellY = (uint16)(charCell&0xffff);
sint32 distX = (sint32)(charCellX) - (sint32)(senderCellX);
sint32 distY = (sint32)(charCellY) - (sint32)(senderCellY);
// nldebug(" dist : x=%d y=%d ",distX,distY);
// if the player is close enough
if( abs(distX)<=maxDist && abs(distY)<=maxDist )
{
isInAudience = true;
}
}
// if the player is in an apartment
else
{
// if both players are in the same apartment
if( charCell == cellS )
{
isInAudience = true;
}
}
}
CChatClient &cc = cm.getClient(entityIndex);
// add or remove char from player's audience
if( isInAudience )
{
// we add him in the audience
CChatGroup::TMemberCont::iterator itA = audience.Members.find( entityIndex );
if( itA == audience.Members.end() )
{
cm.addToGroup(audienceId, entityIndex);
/* cc.subscribeInChatGroup(groupId);
audience.Members.insert( entityIndex );
if (VerboseChat)
nldebug("CChatClient::updateAudience : adding player %x in the audience of %x",
entityIndex.getIndex(),
_DataSetIndex.getIndex());
*/ }
}
else
{
// we remove him from the audience(if necessary)
CChatGroup::TMemberCont::iterator itA = audience.Members.find( entityIndex );
if( itA != audience.Members.end() )
{
cm.removeFromGroup(audienceId, entityIndex);
/* audience.Members.erase( itA );
if (VerboseChat)
nldebug("CChatClient::updateAudience : removing player %x from the audience of %x",
entityIndex.getIndex(),
_DataSetIndex.getIndex());
*/ }
}
}
}
}
}
lastAudienceUpdateTime = currentTime;
}
} // updateAudience //
//-----------------------------------------------
// knowString :
//
//-----------------------------------------------
bool CChatClient::knowString( uint32 index )
{
if( index >= _KnownStrings.size() )
{
_KnownStrings.resize( index+1, false );
}
if( _KnownStrings[index] == false )
{
_KnownStrings[index] = true;
return false;
}
else
{
return true;
}
} // knowString //
void CChatClient::subscribeInChatGroup(TGroupId groupId)
{
if (VerboseChatManagement)
{
nldebug("IOSCC: subscribeInChatGroup : client %s:%x subscribe in chat group %s",
TheDataset.getEntityId(_DataSetIndex).toString().c_str(),
_DataSetIndex.getIndex(),
groupId.toString().c_str());
}
TSubscribedGroupCont::iterator it(_SubscribedGroups.find(groupId));
if (it == _SubscribedGroups.end())
{
_SubscribedGroups.insert(groupId);
}
else
{
nlwarning("CChatClient::subscribeInChatGroup : error : client %s:%x has alrady subscribed to group %s",
TheDataset.getEntityId(_DataSetIndex).toString().c_str(),
_DataSetIndex.getIndex(),
groupId.toString().c_str());
}
}
void CChatClient::unsubscribeInChatGroup(TGroupId groupId)
{
if (VerboseChatManagement)
{
nldebug("IOSCC: unsubscribeInChatGroup : client %s:%x unsubscribe from chat group %s",
TheDataset.getEntityId(_DataSetIndex).toString().c_str(),
_DataSetIndex.getIndex(),
groupId.toString().c_str());
}
TSubscribedGroupCont::iterator it(_SubscribedGroups.find(groupId));
if (it != _SubscribedGroups.end())
{
_SubscribedGroups.erase(it);
}
else
{
nlwarning("CChatClient::unsubscribeInChatGroup : error : client %s:%x has not subscribed to group %s",
TheDataset.getEntityId(_DataSetIndex).toString().c_str(),
_DataSetIndex.getIndex(),
groupId.toString().c_str());
}
}
void CChatClient::unsubscribeAllChatGroup()
{
CChatManager &cm = IOS->getChatManager();
while (!_SubscribedGroups.empty())
{
TGroupId gid = *(_SubscribedGroups.begin());
cm.removeFromGroup(gid, _DataSetIndex);
if (_SubscribedGroups.find(gid) != _SubscribedGroups.end())
{
nlwarning("CChatClient::unsubscribeAllChatGroup : force unsubscrib from group %s", gid.toString().c_str());
_SubscribedGroups.erase(gid);
}
}
}