1387 lines
41 KiB
C++
1387 lines
41 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/>.
|
|
|
|
#include "stdpch.h"
|
|
|
|
#include "nel/net/service.h"
|
|
#include "nel/net/message.h"
|
|
#include "nel/misc/file.h"
|
|
#include "nel/misc/path.h"
|
|
#include "nel/misc/o_xml.h"
|
|
#include "nel/misc/i_xml.h"
|
|
#include "nel/misc/algo.h"
|
|
#include "nel/misc/sstring.h"
|
|
#include "nel/misc/random.h"
|
|
|
|
#include "game_share/backup_service_interface.h"
|
|
#include "game_share/utils.h"
|
|
|
|
#include "name_manager.h"
|
|
#include "database_mapping.h"
|
|
|
|
using namespace std;
|
|
using namespace NLMISC;
|
|
using namespace NLNET;
|
|
using namespace MSW;
|
|
using namespace CHARSYNC;
|
|
|
|
CVariable<bool> NameManagerCheckOnStatup("name_mgr", "NameManagerCheckOnStatup", "If true name manager will do a complete check on character name and rename any invalid one", true, 0, true );
|
|
|
|
NLMISC::CRandom RandomGenerator;
|
|
|
|
|
|
const char *GUILD_NAME_FILE = "guild_names.txt";
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
bool CNameManager::assignName(uint32 charId, const ucstring & ucName, uint32 homeSessionId, bool skipTest)
|
|
{
|
|
// if (eId == NLMISC::CEntityId::Unknown)
|
|
// return false;
|
|
|
|
|
|
const TCharSlot charSlot( charId );
|
|
const uint32 playerId = charSlot.UserId;
|
|
const uint8 charIndex = charSlot.CharIndex;
|
|
|
|
// check that name is usable
|
|
if (!skipTest && isNameUsable( ucName, playerId, charIndex, homeSessionId ) != TCharacterNameResult::cnr_ok)
|
|
return false;
|
|
|
|
// assign name and save
|
|
const string name = toLower( ucName.toUtf8() );
|
|
|
|
|
|
// remove any temporary reserve for this name
|
|
_TemporaryReservedNames.erase(name);
|
|
|
|
TFullName fullname(name, homeSessionId);
|
|
|
|
const TCharSlot *owner = _Names.getB(fullname);
|
|
if (owner != NULL && *owner == charSlot)
|
|
// association already exist, nothing more to do
|
|
return true;
|
|
else if (owner != NULL)
|
|
{
|
|
// we need to remove this assoc
|
|
_Names.removeWithA(fullname);
|
|
_ReleasedNames.insert((owner->UserId<<4)+owner->CharIndex);
|
|
}
|
|
|
|
if (_Names.getBToAMap().find(charSlot) != _Names.getBToAMap().end())
|
|
{
|
|
// the character is associated to another name
|
|
_Names.removeWithB(charSlot);
|
|
}
|
|
|
|
// insert the new association
|
|
_Names.add(fullname, charSlot);
|
|
_ChangedNames.insert(charId);
|
|
|
|
// saveCharacterNames();
|
|
|
|
nlinfo("NAMEMGR: assigned name '%s' to char %u", name.c_str(), charId );
|
|
|
|
return true;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void CNameManager::liberateName(uint32 charId, const ucstring & ucName)
|
|
{
|
|
const TCharSlot charSlot( charId );
|
|
const string name = toLower( ucName.toUtf8() );
|
|
|
|
// remove the name from the reservation if it belong to the specified user
|
|
{
|
|
TTempReservedNames::iterator it(_TemporaryReservedNames.find(name));
|
|
if (it != _TemporaryReservedNames.end() && it->second.UserId == (charId >> 4))
|
|
{
|
|
_TemporaryReservedNames.erase(it);
|
|
}
|
|
}
|
|
|
|
const TFullName *fullname = _Names.getA(charId);
|
|
if (fullname == NULL || fullname->Name != ucName.toUtf8())
|
|
{
|
|
nlwarning("NAMEMGR: char %u is trying to liberate a name he does not own: '%s'", charId, name.c_str() );
|
|
return;
|
|
}
|
|
|
|
_Names.removeWithB( charSlot );
|
|
_ReleasedNames.insert(charId);
|
|
// saveCharacterNames();
|
|
nlinfo("NAMEMGR: char %u liberated his name '%s'", charId, name.c_str() );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// liberate any name associated to a character
|
|
void CNameManager::liberateName(uint32 charId)
|
|
{
|
|
const TCharSlot charSlot( charId );
|
|
|
|
TNamesIndex::TBToAMap::const_iterator it = _Names.getBToAMap().find( charSlot );
|
|
if ( it == _Names.getBToAMap().end() )
|
|
return;
|
|
|
|
nlinfo("NAMEMGR: char %u liberated his name '%s'", charId, it->second.Name.c_str() );
|
|
// ok, association found, remove it
|
|
_Names.removeWithB(charSlot);
|
|
_ReleasedNames.insert(charId);
|
|
|
|
// saveCharacterNames();
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//void CNameManager::checkCharacterSlot(uint32 charId, const ucstring & ucName)
|
|
//{
|
|
//// if (eId == CEntityId::Unknown)
|
|
//// return;
|
|
//
|
|
// const TCharSlot charSlot( charId );
|
|
// const TName name = toLower( ucName.toUtf8() );
|
|
//
|
|
// // verify that name is assigned to the character
|
|
// {
|
|
// TNamesIndex::TAToBMap::const_iterator it = _Names.getAToBMap().find( name );
|
|
// if ( it != _Names.getAToBMap().end() )
|
|
// {
|
|
// if( it->second != charSlot )
|
|
// {
|
|
// nlwarning("NAMEMGR: char %u has name '%s', but this name is assigned to another character", charId, name.c_str() );
|
|
// renameCharacter(charId);
|
|
// }
|
|
// }
|
|
// else
|
|
// {
|
|
// nlwarning("NAMEMGR: char %u has name '%s', but this name is not assigned", charId, name.c_str() );
|
|
// assignName(charId, ucName);
|
|
// }
|
|
// }
|
|
//
|
|
// // if this slot is not duplicated, just return
|
|
// TDuplicatedSlots::iterator it = _DuplicatedSlots.find( charSlot );
|
|
// if ( it == _DuplicatedSlots.end() )
|
|
// return;
|
|
//
|
|
// const std::set<TName> & dupNames = (*it).second;
|
|
//
|
|
// // erase other names associated to the same slot
|
|
// std::set<TName>::const_iterator itDupName;
|
|
// for (itDupName = dupNames.begin(); itDupName != dupNames.end(); ++itDupName)
|
|
// {
|
|
// const TName & dupName = (*itDupName);
|
|
// if (dupName != name)
|
|
// {
|
|
// const TCharSlot *cs = _Names.getB(dupName);
|
|
// if (cs != NULL)
|
|
// {
|
|
// _ReleasedNames.insert((cs->UserId<<4)+cs->CharIndex);
|
|
// }
|
|
// _Names.removeWithA( dupName );
|
|
// }
|
|
// }
|
|
//
|
|
// // save changes
|
|
// saveCharacterNames();
|
|
//
|
|
// // slot has been fixed
|
|
// _DuplicatedSlots.erase( it );
|
|
//
|
|
// nlinfo("NAMEMGR: fixed character slot: userId=%u, slot=%u, name='%s'", charSlot.UserId, charSlot.CharIndex, name.c_str() );
|
|
//
|
|
// if ( !_DuplicatedSlots.empty() )
|
|
// nlinfo("NAMEMGR: there still are %u duplicated character slots", _DuplicatedSlots.size() );
|
|
//}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
ucstring CNameManager::renameCharacter(uint32 charId, uint32 homeSessionId)
|
|
{
|
|
const ucstring ucDefaultName = generateDefaultName(charId, homeSessionId);
|
|
nlverify(assignName(charId, ucDefaultName, homeSessionId, true));
|
|
|
|
return ucDefaultName;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
ucstring CNameManager::generateDefaultName(uint32 charId, uint32 homeSessionId)
|
|
{
|
|
const TCharSlot charSlot(charId);
|
|
|
|
string defaultName;
|
|
string randomLetters(5, 'a');
|
|
|
|
uint count = 0;
|
|
while (1)
|
|
{
|
|
for (uint i = 0; i < randomLetters.size(); i++)
|
|
{
|
|
randomLetters[i] = 'a' + (char)RandomGenerator.rand(uint16('z'-'a'));
|
|
}
|
|
defaultName = "Default" + randomLetters;
|
|
|
|
if ( isNameUsable(defaultName, charSlot.UserId, charSlot.CharIndex, homeSessionId) == TCharacterNameResult::cnr_ok)
|
|
break;
|
|
|
|
// anti freeze
|
|
if (++count > 100)
|
|
break;
|
|
}
|
|
|
|
return defaultName;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
ucstring CNameManager::generateDefaultGuildName(uint32 guildId)
|
|
{
|
|
string defaultName;
|
|
string randomLetters(5, 'a');
|
|
|
|
uint count = 0;
|
|
while (1)
|
|
{
|
|
for (uint i = 0; i < randomLetters.size(); i++)
|
|
{
|
|
randomLetters[i] = 'a' + (char)RandomGenerator.rand(uint16('z'-'a'));
|
|
}
|
|
defaultName = "DefaultGuild" + randomLetters;
|
|
|
|
if ( isGuildNameUsable(defaultName, guildId) == TCharacterNameResult::cnr_ok)
|
|
break;
|
|
|
|
// anti freeze
|
|
if (++count > 100)
|
|
break;
|
|
}
|
|
|
|
return defaultName;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
/** This methods implemented by CCommandHandler is used by the
|
|
* command registry to retrieve the name of the object instance.
|
|
*/
|
|
const std::string &CNameManager::getCommandHandlerName() const
|
|
{
|
|
const static string name = "nameManager";
|
|
return name;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
CHARSYNC::TCharacterNameResult CNameManager::isNameUsable(const ucstring & ucNameIn, uint32 userId, uint8 charIndex, uint32 homeSessionId)
|
|
{
|
|
// WARNING: if you change validity checks here,
|
|
// please also change them in CEntityIdTranslator::isValidEntityName() (nel/misc/eid_translator.cpp)
|
|
|
|
// if the name contains a shard specification, remove it first
|
|
ucstring ucName;
|
|
ucstring::size_type pos = ucNameIn.find('(');
|
|
if (pos != ucstring::npos)
|
|
{
|
|
//only keep the simple name for the test
|
|
ucName = ucNameIn.substr(0, pos);
|
|
}
|
|
else
|
|
{
|
|
// test the whole input name
|
|
ucName = ucNameIn;
|
|
}
|
|
|
|
|
|
// perform a first validity check on the name length
|
|
if (ucName.size() < 3)
|
|
{
|
|
nldebug("VALID_NAME::CNameManager::isNameUsable name '%s' rejected because is too short", ucName.toString().c_str());
|
|
return TCharacterNameResult::cnr_invalid_name;
|
|
}
|
|
|
|
// perform a first validity check on the name length
|
|
if (ucName.size() > 15)
|
|
{
|
|
nldebug("VALID_NAME::CNameManager::isNameUsable name '%s' rejected because is too long", ucName.toString().c_str());
|
|
return TCharacterNameResult::cnr_invalid_name;
|
|
}
|
|
|
|
// make sure the name is only composed of valid characters
|
|
for (uint32 i = 0; i < ucName.size(); ++i)
|
|
{
|
|
if ( (ucName[i] < (uint16)'A' || ucName[i] > (uint16)'Z') && (ucName[i] < (uint16)'a' || ucName[i] > (uint16)'z') )
|
|
{
|
|
nldebug("VALID_NAME::CNameManager::isNameUsable name '%s' rejected because it contains invalid character", ucName.toString().c_str());
|
|
return TCharacterNameResult::cnr_invalid_name;
|
|
}
|
|
}
|
|
|
|
// it's now safe to convert the name to 8 bit lower case
|
|
const string name = toLower( ucName.toUtf8() );
|
|
|
|
// make sure the name isn't forbidden
|
|
for (uint32 i = 0; i < _ForbiddenNames.size(); ++i)
|
|
{
|
|
if ( NLMISC::testWildCard( name, _ForbiddenNames[i] ) )
|
|
{
|
|
nldebug("VALID_NAME::CNameManager::isNameUsable name '%s' rejected because it contains the forbidden string '%s'",
|
|
ucName.toString().c_str(),
|
|
_ForbiddenNames[i].c_str());
|
|
return TCharacterNameResult::cnr_invalid_name;
|
|
}
|
|
}
|
|
|
|
// make sure the name isn't reserved
|
|
TReservedNames::iterator rit = _ReservedNames.find( name );
|
|
if ( rit != _ReservedNames.end() )
|
|
{
|
|
if ( (*rit).second != userId )
|
|
{
|
|
nldebug("VALID_NAME::CNameManager::isNameUsable name '%s' rejected because it's reserved", ucName.toString().c_str());
|
|
return TCharacterNameResult::cnr_already_exist;
|
|
}
|
|
}
|
|
|
|
// make sure the name isn't temporary reserved
|
|
{
|
|
TTempReservedNames::iterator rit = _TemporaryReservedNames.find( name );
|
|
if ( rit != _TemporaryReservedNames.end() )
|
|
{
|
|
if ( rit->second.UserId != userId && rit->second.UserId == homeSessionId)
|
|
{
|
|
nldebug("VALID_NAME::CNameManager::isNameUsable name '%s' rejected because it's temporary reserved", ucName.toString().c_str());
|
|
return TCharacterNameResult::cnr_already_exist;
|
|
}
|
|
}
|
|
}
|
|
|
|
TFullName fullname(name, homeSessionId);
|
|
// make sure the name isn't used by another character
|
|
TNamesIndex::TAToBMap::const_iterator it = _Names.getAToBMap().find( fullname );
|
|
if ( it != _Names.getAToBMap().end())
|
|
{
|
|
if( it->second.UserId != userId || it->second.CharIndex != charIndex )
|
|
{
|
|
nldebug("VALID_NAME::CNameManager::isNameUsable name '%s' rejected because it's already used", ucName.toString().c_str());
|
|
return TCharacterNameResult::cnr_already_exist;
|
|
}
|
|
}
|
|
|
|
// make sure the name is not used by a guild
|
|
{
|
|
TGuildNames::iterator it = _GuildNames.find(name);
|
|
if (it != _GuildNames.end())
|
|
{
|
|
nldebug("VALID_NAME::CNameManager::isNameUsable name '%s' rejected because it's a guild name", ucName.toString().c_str());
|
|
return TCharacterNameResult::cnr_already_exist;
|
|
}
|
|
}
|
|
|
|
// the name is valid, insert it in the temporary reserve
|
|
|
|
TTemporaryReservedNameInfo trni;
|
|
trni.UserId = userId;
|
|
trni.ReserveDate = CTime::getSecondsSince1970();
|
|
trni.HomeSessionId = homeSessionId;
|
|
_TemporaryReservedNames.insert(make_pair(name, trni));
|
|
|
|
nldebug("VALID_NAME::CNameManager::isNameUsable name '%s' accepted", ucName.toString().c_str());
|
|
|
|
return TCharacterNameResult::cnr_ok;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
TCharacterNameResult CNameManager::isGuildNameUsable(const ucstring & ucName, uint32 guildId)
|
|
{
|
|
// perform a first validity check on the name length
|
|
if (ucName.size() < 3)
|
|
return TCharacterNameResult::cnr_invalid_name;
|
|
|
|
// perform a first validity check on the name length
|
|
if (ucName.size() > 50)
|
|
return TCharacterNameResult::cnr_invalid_name;
|
|
|
|
// make sure the name is only composed of valid characters
|
|
bool prevBlank = false;
|
|
for (uint i = 0; i < ucName.size(); i++)
|
|
{
|
|
if ( ucName[i] == ucchar(' ') )
|
|
{
|
|
if ( prevBlank )
|
|
{
|
|
return TCharacterNameResult::cnr_invalid_name;
|
|
}
|
|
prevBlank = true;
|
|
}
|
|
else
|
|
{
|
|
prevBlank = false;
|
|
if (!isalpha (ucName[i]))
|
|
{
|
|
return TCharacterNameResult::cnr_invalid_name;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// it's now safe to convert the name to 8 bit lower case
|
|
const string name = toLower( ucName.toUtf8() );
|
|
|
|
// make sure the name isn't forbidden
|
|
for (uint32 i = 0; i < _ForbiddenNames.size(); ++i)
|
|
{
|
|
if ( NLMISC::testWildCard( name, _ForbiddenNames[i] ) )
|
|
return TCharacterNameResult::cnr_invalid_name;
|
|
}
|
|
|
|
// make sure the name isn't reserved
|
|
TReservedNames::iterator rit = _ReservedNames.find( name );
|
|
if ( rit != _ReservedNames.end() )
|
|
{
|
|
return TCharacterNameResult::cnr_already_exist;
|
|
}
|
|
|
|
// make sure the name isn't temporary reserved
|
|
{
|
|
TTempReservedNames::iterator rit = _TemporaryReservedNames.find( name );
|
|
if ( rit != _TemporaryReservedNames.end() )
|
|
{
|
|
return TCharacterNameResult::cnr_already_exist;
|
|
}
|
|
}
|
|
|
|
// make sure the name isn't used by a character
|
|
TNamesIndex::TAToBMap::const_iterator it = _Names.getAToBMap().lower_bound( TFullName(name, 0) );
|
|
if ( it != _Names.getAToBMap().end() && it->first.Name == name)
|
|
{
|
|
return TCharacterNameResult::cnr_already_exist;
|
|
}
|
|
|
|
// make sure the name is not used by another guild
|
|
{
|
|
TGuildNames::iterator it = _GuildNames.find(name);
|
|
if (it != _GuildNames.end() && it->second.GuildId != guildId)
|
|
return TCharacterNameResult::cnr_already_exist;
|
|
}
|
|
|
|
// the name is valid
|
|
return TCharacterNameResult::cnr_ok;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void CNameManager::registerLoadedGuildNames(uint32 shardId, const std::map<uint32, ucstring> &guilds, vector<uint32> &renamedGuildIds)
|
|
{
|
|
bool saveFile = false;
|
|
|
|
std::map<uint32, ucstring>::const_iterator first(guilds.begin()), last(guilds.end());
|
|
|
|
for (; first != last; ++first)
|
|
{
|
|
uint32 guildId = first->first;
|
|
const ucstring &guildName = first->second;
|
|
|
|
// check the name
|
|
if (isGuildNameUsable(guildName, guildId) == TCharacterNameResult::cnr_ok)
|
|
{
|
|
// convert the name into the standard utf8 low case version
|
|
string name = toLower(guildName.toUtf8());
|
|
// ok, the name is correct, check if it already exist
|
|
TGuildNames::iterator it(_GuildNames.find(name));
|
|
if (it == _GuildNames.end())
|
|
{
|
|
// this is a new name
|
|
_GuildNames.insert(make_pair(name, TGuildSlot(shardId, guildId)));
|
|
_GuildIndex.insert(make_pair(guildId, name));
|
|
saveFile = true;
|
|
}
|
|
else
|
|
{
|
|
BOMB_IF(it->second.GuildId != guildId, "Guild "<<guildId<<" is just loaded by shard "<<shardId<<" but name already in use by guild "<<it->second.GuildId, continue);
|
|
BOMB_IF(it->second.ShardId != shardId, "Guild "<<guildId<<" is just loaded by shard "<<shardId<<" but already registered by shard "<<it->second.ShardId, continue);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// we need to rename the guild
|
|
ucstring newName = generateDefaultGuildName(guildId);
|
|
|
|
nlinfo("NM:registerLoadedGuildNames : Guild %u has a conflicting name '%s', renamed to '%s'",
|
|
guildId,
|
|
guildName.toUtf8().c_str(),
|
|
newName.toUtf8().c_str());
|
|
|
|
// save it in the container
|
|
std::string name = toLower(newName.toUtf8());
|
|
_GuildNames.insert(make_pair(name, TGuildSlot(shardId, guildId)));
|
|
_GuildIndex.insert(make_pair(guildId, name));
|
|
|
|
saveFile = true;
|
|
|
|
// put it in the renamed guild list return vector
|
|
renamedGuildIds.push_back(guildId);
|
|
}
|
|
}
|
|
|
|
if (saveFile)
|
|
{
|
|
saveGuildNames();
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
bool CNameManager::assignGuildName(uint32 shardId, uint32 guildId, const ucstring &guildName)
|
|
{
|
|
bool ret;
|
|
if (isGuildNameUsable(guildName, guildId) != TCharacterNameResult::cnr_ok)
|
|
{
|
|
// oups, bad name, we need to generate a new valid name
|
|
ucstring newName = generateDefaultGuildName(guildId);
|
|
|
|
string name = toLower(newName.toUtf8());
|
|
_GuildNames.insert(make_pair(name, TGuildSlot(shardId, guildId)));
|
|
_GuildIndex.insert(make_pair(guildId, name));
|
|
|
|
ret = false;
|
|
}
|
|
else
|
|
{
|
|
// ok, the name is correct, do a simple insertion
|
|
string name = toLower(guildName.toUtf8());
|
|
_GuildNames.insert(make_pair(name, TGuildSlot(shardId, guildId)));
|
|
_GuildIndex.insert(make_pair(guildId, name));
|
|
|
|
ret = true;
|
|
}
|
|
|
|
// save the file
|
|
saveGuildNames();
|
|
|
|
return ret;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void CNameManager::releaseGuildName(uint32 shardId, uint32 guildId)
|
|
{
|
|
TGuildIndex::iterator it(_GuildIndex.find(guildId));
|
|
if (it == _GuildIndex.end())
|
|
{
|
|
nlwarning("CNameManager::releaseGuildName : no guild %s registered in name manager", guildId);
|
|
return;
|
|
}
|
|
|
|
// erase the name entry
|
|
_GuildNames.erase(it->second);
|
|
// erase the index entry
|
|
_GuildIndex.erase(it);
|
|
|
|
// save the file
|
|
saveGuildNames();
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//void CNameManager::saveCharacterNames()
|
|
//{
|
|
// // save the character names
|
|
// {
|
|
// string fileName = "character_names.txt";
|
|
//
|
|
// CSString s;
|
|
// nlinfo("NAMEMGR::save: building file content: %s",fileName.c_str());
|
|
// for (TNamesIndex::TAToBMap::const_iterator it=_Names.getAToBMap().begin(); it!=_Names.getAToBMap().end(); ++it)
|
|
// {
|
|
// s << it->first.Name << " " << it->second.UserId << " " << it->second.CharIndex << " " << it->first.HomeSessionId << "\n";
|
|
// }
|
|
//
|
|
// if( s.empty() )
|
|
// return;
|
|
//
|
|
// nlinfo("NAMEMGR::save: send message to BS");
|
|
//
|
|
// CBackupMsgSaveFile msg( fileName, CBackupMsgSaveFile::SaveFile, BsiGlobal );
|
|
// msg.DataMsg.serialBuffer((uint8*)s.c_str(), s.size());
|
|
// BsiGlobal.sendFile(msg);
|
|
// }
|
|
//
|
|
// // save account names
|
|
// {
|
|
// string fileName = "account_names.txt";
|
|
//
|
|
// string s;
|
|
// nlinfo("NAMEMGR::save: building file content: %s",fileName.c_str());
|
|
// for (TAccountNames::iterator it=_AccountNames.begin();it!=_AccountNames.end();++it)
|
|
// {
|
|
// s+=NLMISC::toString("%s %i\n",(*it).second.c_str(),(*it).first);
|
|
// }
|
|
//
|
|
// if( s.empty() )
|
|
// return;
|
|
//
|
|
// nlinfo("NAMEMGR::save: send message to BS");
|
|
//
|
|
// CBackupMsgSaveFile msg( fileName, CBackupMsgSaveFile::SaveFile, BsiGlobal );
|
|
// msg.DataMsg.serialBuffer((uint8*)s.c_str(), s.size());
|
|
// BsiGlobal.sendFile(msg);
|
|
// }
|
|
//}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void CNameManager::saveGuildNames()
|
|
{
|
|
// save the guild names
|
|
{
|
|
string fileName = GUILD_NAME_FILE;
|
|
|
|
string s;
|
|
nlinfo("NAMEMGR::save: building file content: %s",fileName.c_str());
|
|
for (TGuildNames::const_iterator it=_GuildNames.begin(); it!=_GuildNames.end(); ++it)
|
|
{
|
|
s+=NLMISC::toString("%s %i %i\n", it->first.c_str(), it->second.ShardId, it->second.GuildId);
|
|
}
|
|
|
|
if( s.empty() )
|
|
return;
|
|
|
|
nlinfo("NAMEMGR::save: send message to BS");
|
|
|
|
CBackupMsgSaveFile msg( fileName, CBackupMsgSaveFile::SaveFile, Bsi );
|
|
msg.DataMsg.serialBuffer((uint8*)s.c_str(), (uint)s.size());
|
|
Bsi.sendFile(msg);
|
|
}
|
|
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
void CNameManager::loadAllNames()
|
|
{
|
|
bool result;
|
|
|
|
// load account names
|
|
result=loadAccountNamesFromDatabase();
|
|
if (result==false)
|
|
result=loadAccountNamesFromTxt();
|
|
if (result==false)
|
|
nlinfo("NAMEMGR::load: Failed to load account names from txt file");
|
|
|
|
// load character names
|
|
result=loadCharacterNamesFromDatabase();
|
|
if (result==false)
|
|
result=loadCharacterNamesFromTxt();
|
|
// if (result==false)
|
|
// result=loadCharacterNamesFromXML();
|
|
if (result==false)
|
|
nlinfo("NAMEMGR::load: Failed to load character names from txt file");
|
|
|
|
// load character names
|
|
result=loadGuildsNamesFromTxt();
|
|
if (result==false)
|
|
nlinfo("NAMEMGR::load: Failed to load guilds names from txt file");
|
|
|
|
// load forbidden names
|
|
result=loadForbiddenNames();
|
|
if (result==false)
|
|
nlwarning("NAMEMGR::load: Failed to load forbidden name file");
|
|
|
|
// load reserved names
|
|
result=loadReservedNames("reserved_names.xml");
|
|
if (result==false)
|
|
nlwarning("NAMEMGR::load: Failed to load reserved player name file");
|
|
|
|
// load dev and gm names
|
|
result=loadReservedNames("dev_gm_names.xml");
|
|
if (result==false)
|
|
nlwarning("NAMEMGR::load: Failed to load reserved dev and gm name file");
|
|
|
|
nlinfo("NameManager : checking %u loaded names...", _Names.getAToBMap().size());
|
|
|
|
// revalidate all character names
|
|
TNamesIndex::TAToBMap::const_iterator first(_Names.getAToBMap().begin()), last(_Names.getAToBMap().end());
|
|
for (uint i=0; first != last; ++i)
|
|
{
|
|
TNamesIndex::TAToBMap::const_iterator next(first);
|
|
++next;
|
|
|
|
const TFullName &fullName = first->first;
|
|
const TCharSlot &charSlot = first->second;
|
|
if (isNameUsable(fullName.Name, charSlot.UserId, charSlot.CharIndex, fullName.HomeSessionId) != CHARSYNC::TCharacterNameResult::cnr_ok)
|
|
{
|
|
nlinfo("NameManager : renaming invalid character name '%s' for char %u", fullName.Name.c_str(), charSlot.getCharId());
|
|
|
|
// get the shard id
|
|
uint32 charId = charSlot.getCharId();
|
|
// the name is invalid !
|
|
ucstring newName = renameCharacter(charSlot.getCharId(), fullName.HomeSessionId);
|
|
// do not access the fullName and charSlot var from now
|
|
|
|
RSMGR::CCharacterPtr character = RSMGR::CCharacter::load(*_Database, charId, __FILE__, __LINE__);
|
|
if (character != NULL)
|
|
{
|
|
character->setCharName(newName.toUtf8());
|
|
character->update(*_Database);
|
|
}
|
|
}
|
|
|
|
first = next;
|
|
|
|
if (i%1000 == 0)
|
|
{
|
|
nldebug("NameManager : checking name advance %u/%u", i, _Names.getAToBMap().size());
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
bool CNameManager::loadAccountNamesFromTxt()
|
|
{
|
|
FILE* f;
|
|
string fileName;
|
|
|
|
// open the file
|
|
fileName = BsiGlobal.getLocalPath() + "account_names.txt";
|
|
f=fopen(fileName.c_str(),"rb");
|
|
if (f == NULL)
|
|
{
|
|
nlwarning("Failed to open file for reading: %s", fileName.c_str() );
|
|
return false;
|
|
}
|
|
|
|
CSString input;
|
|
|
|
// read the file content into a buffer
|
|
uint32 size=NLMISC::CFile::getFileSize(f);
|
|
input.resize(size);
|
|
uint32 readSize= (uint32)fread(&input[0],1,size,f);
|
|
fclose(f);
|
|
BOMB_IF(readSize!=size,"Failed to read file content for file: "+fileName,return false);
|
|
|
|
// scan the content
|
|
while (!input.empty())
|
|
{
|
|
CSString line=input.firstLine(true);
|
|
if (line.strip().empty())
|
|
continue;
|
|
DROP_IF (line.countWords()!=2,"Invalid line found in account names file: "+line,continue);
|
|
DROP_IF (line.word(1).atoi()==0,"Invalid user id in account names file line: "+line,continue);
|
|
_AccountNames[line.word(1).atoi()]=line.word(0);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
bool CNameManager::loadAccountNamesFromDatabase()
|
|
{
|
|
if (_Database == NULL)
|
|
return false;
|
|
|
|
// request the database to extract the complete list of account names
|
|
CSString query;
|
|
query << "SELECT user_id, user_name FROM ring_users";
|
|
BOMB_IF(!_Database->query(query), "Failed to load account names from the database", return false);
|
|
|
|
auto_ptr<CUseResult> result = _Database->useResult();
|
|
|
|
while (result->fetchRow())
|
|
{
|
|
uint32 userId;
|
|
string accountName;
|
|
result->getField(0, userId);
|
|
result->getField(1, accountName);
|
|
|
|
_AccountNames[userId]=accountName;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//bool CNameManager::loadAccountNamesFromXML()
|
|
//{
|
|
// CIFile f;
|
|
// string fileName;
|
|
//
|
|
// fileName = BsiGlobal.getLocalPath() + "account_names.xml";
|
|
// if( !f.open( fileName ) )
|
|
// return false;
|
|
//
|
|
// nlinfo("NAMEMGR: Loading file: %s",fileName.c_str());
|
|
//
|
|
// CIXml input;
|
|
// if(!input.init( f ))
|
|
// {
|
|
// nlwarning("NAMEMGR:loadAccountNamesFromXML Can't init xml input for file %s", fileName.c_str());
|
|
// return false;
|
|
// }
|
|
// input.serialCont( _AccountNames );
|
|
// f.close();
|
|
//
|
|
// return true;
|
|
//}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//bool CNameManager::loadAccountNamesFromEIDTranslator()
|
|
//{
|
|
// nlinfo("NAMEMGR: Build account names from EIDTranslator");
|
|
//
|
|
// try
|
|
// {
|
|
// CEntityIdTranslator::getInstance()->load(BsiGlobal.getLocalPath() + "eid_translation.data", IService::getInstance()->ConfigFile.getVar("InvalidEntityNamesFilename").asString());
|
|
// }
|
|
// catch(const Exception &)
|
|
// {
|
|
// // if we can't load the file, we force a check coherency
|
|
// nlwarning("Can't load the eid_translation.data");
|
|
// return false;
|
|
// }
|
|
//
|
|
// for( map<CEntityId, CEntityIdTranslator::CEntity>::const_iterator it = CEntityIdTranslator::getInstance()->getRegisteredEntities().begin(); it != CEntityIdTranslator::getInstance()->getRegisteredEntities().end(); ++it )
|
|
// {
|
|
// _AccountNames[(*it).second.UId]= (*it).second.UserName;
|
|
// }
|
|
// saveCharacterNames();
|
|
//
|
|
// return true;
|
|
//}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
bool CNameManager::loadCharacterNamesFromTxt()
|
|
{
|
|
FILE* f;
|
|
string fileName;
|
|
|
|
// open the file
|
|
fileName = BsiGlobal.getLocalPath() + "character_names.txt";
|
|
f=fopen(fileName.c_str(),"rb");
|
|
if (f == NULL)
|
|
{
|
|
nlwarning("Failed to open file for reading: %s", fileName.c_str() );
|
|
return false;
|
|
}
|
|
|
|
CSString input;
|
|
|
|
// read the file content into a buffer
|
|
uint32 size=NLMISC::CFile::getFileSize(f);
|
|
input.resize(size);
|
|
uint32 readSize= (uint32)fread(&input[0],1,size,f);
|
|
fclose(f);
|
|
BOMB_IF(readSize!=size,"Failed to read file content for file: "+fileName,return false);
|
|
|
|
_Names.clear();
|
|
_DuplicatedSlots.clear();
|
|
typedef map<TCharSlot, TName> TCharSlotToName;
|
|
TCharSlotToName charSlotToName;
|
|
|
|
vector<string> lines;
|
|
NLMISC::explode(string(input), string("\n"), lines, true);
|
|
|
|
// scan the content
|
|
// while (!input.empty())
|
|
|
|
// bool mustSaveFile = false;
|
|
for (uint i=0; i<lines.size(); ++i)
|
|
{
|
|
if (i > 0 && (i%100 == 0))
|
|
nldebug("Loading character names : %u/%u (%.2f%%)", i, lines.size(), float(i)/float(lines.size())*100.0f);
|
|
// CSString line=input.firstLine(true);
|
|
CSString line = lines[i];
|
|
vector<string> words;
|
|
NLMISC::explode(string(line), string(" "), words, true);
|
|
|
|
if (words.empty())
|
|
continue;
|
|
// if (line.strip().empty())
|
|
// continue;
|
|
// BOMB_IF (line.countWords()!=3,"Invalid line found in character names file: "+line,continue);
|
|
BOMB_IF (words.size()!=3 && words.size()!=4,"Invalid line found in character names file: "+line,continue);
|
|
|
|
sint i1, i2;
|
|
NLMISC::fromString(words[1], i1);
|
|
NLMISC::fromString(words[2], i2);
|
|
|
|
BOMB_IF (i1==0,"Invalid user id in character names file line: "+line,continue);
|
|
BOMB_IF (i2>15 || (i2==0 && words[2] != "0"),"Invalid slot id in character names file line: "+line,continue);
|
|
|
|
sint sessionId =0;
|
|
if (words.size() > 3)
|
|
NLMISC::fromString(words[3], sessionId);
|
|
|
|
const TName name = words[0];
|
|
const TCharSlot charSlot = TCharSlot(i1, i2);
|
|
TFullName fullname(name, sessionId);
|
|
|
|
// Check the name is usable, otherwise skip (to resolve corrupted names)
|
|
if ( isNameUsable( ucstring(name), charSlot.UserId, charSlot.CharIndex, sessionId ) != TCharacterNameResult::cnr_ok)
|
|
{
|
|
nlwarning( "Invalid character name '%s' for user %u char slot %u in %s, will be reset to default", name.c_str(), charSlot.UserId, (uint)charSlot.CharIndex, fileName.c_str() );
|
|
// mustSaveFile = true;
|
|
continue;
|
|
}
|
|
|
|
if (_Names.getAToBMap().find(fullname) != _Names.getAToBMap().end())
|
|
_Names.removeWithA(fullname);
|
|
if (_Names.getBToAMap().find(charSlot) != _Names.getBToAMap().end())
|
|
_Names.removeWithB(charSlot);
|
|
|
|
_Names.add(fullname, charSlot);
|
|
// TNames::const_iterator it = _Names.find( name );
|
|
// nlassert(it != _Names.end());
|
|
|
|
// check duplicated character slots
|
|
TCharSlotToName::iterator itSlot = charSlotToName.find( charSlot );
|
|
if ( itSlot != charSlotToName.end() )
|
|
{
|
|
_DuplicatedSlots[charSlot].insert( (*itSlot).second );
|
|
_DuplicatedSlots[charSlot].insert( name );
|
|
}
|
|
else
|
|
{
|
|
charSlotToName[charSlot] = name;
|
|
}
|
|
|
|
// // update the EID translator
|
|
// uint64 lid = ( (*it).second.UserId<<4 ) | (*it).second.CharId;
|
|
// CEntityId id( RYZOMID::player, lid );
|
|
// id.setDynamicId( 0 );
|
|
// id.setCreatorId( 0 );
|
|
//
|
|
// if (CEntityIdTranslator::getInstance()->isEntityRegistered(id))
|
|
// CEntityIdTranslator::getInstance()->unregisterEntity( id );
|
|
// CEntityIdTranslator::getInstance()->registerEntity( id, capitalize( (*it).first ), (*it).second.CharId, (*it).second.UserId, _AccountNames[(*it).second.UserId] );
|
|
}
|
|
|
|
if ( !_DuplicatedSlots.empty() )
|
|
{
|
|
nlwarning("NAMEMGR: file '%s' contains %u duplicated character slots", fileName.c_str(), _DuplicatedSlots.size() );
|
|
}
|
|
|
|
// if ( mustSaveFile )
|
|
// {
|
|
// saveCharacterNames();
|
|
// }
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
bool CNameManager::loadCharacterNamesFromDatabase()
|
|
{
|
|
if (_Database == NULL)
|
|
return false;
|
|
|
|
_Names.clear();
|
|
|
|
// request the database to extract the complete list of character names
|
|
CSString query;
|
|
query << "SELECT char_id, char_name, home_mainland_session_id FROM characters";
|
|
BOMB_IF(!_Database->query(query), "Failed to load character names from the database", return false);
|
|
|
|
auto_ptr<CUseResult> result = _Database->useResult();
|
|
|
|
while (result->fetchRow())
|
|
{
|
|
uint32 charId;
|
|
string charName;
|
|
uint32 sessionNum;
|
|
result->getField(0, charId);
|
|
result->getField(1, charName);
|
|
result->getField(2, sessionNum);
|
|
|
|
// uint32 userId = charId >> 4;
|
|
// uint8 charSlot = uint8(charId & 0xf);
|
|
|
|
_Names.add(TFullName(charName, sessionNum), TCharSlot(charId));
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//bool CNameManager::loadCharacterNamesFromXML()
|
|
//{
|
|
// CIFile f;
|
|
// string fileName;
|
|
//
|
|
// // load the character names and insert them into the eid translator
|
|
// fileName = BsiGlobal.getLocalPath() + "character_names.xml";
|
|
// if( !f.open( fileName ) )
|
|
// return false;
|
|
//
|
|
// nlinfo("NAMEMGR: Loading file: %s",fileName.c_str());
|
|
// CIXml input;
|
|
// if(!input.init( f ))
|
|
// {
|
|
// nlwarning("<NAMEMGR::loadCharacterNamesFromXML>Can't init xml input for file %s", fileName.c_str());
|
|
// return false;
|
|
// }
|
|
// TNames namesToCheckAndAdd;
|
|
// input.serialCont( namesToCheckAndAdd );
|
|
// f.close();
|
|
//
|
|
// _DuplicatedSlots.clear();
|
|
// map<TCharSlot,TName> charSlotToName;
|
|
//
|
|
// // update the EID translator
|
|
// bool mustSaveFile = false;
|
|
// for( TNames::iterator it = namesToCheckAndAdd.begin(); it != namesToCheckAndAdd.end(); ++it )
|
|
// {
|
|
// const TName & name = (*it).first;
|
|
// const TCharSlot charSlot = TCharSlot( (*it).second.UserId, (*it).second.CharIndex );
|
|
//
|
|
// // Check the name is usable, otherwise skip (to resolve corrupted names)
|
|
// if ( isNameUsable( ucstring(name), charSlot.UserId, charSlot.CharIndex ) != TCharacterNameResult::cnr_ok)
|
|
// {
|
|
// nlwarning( "Invalid character name '%s' for user %u char slot %u in %s, will be reset to default", name.c_str(), charSlot.UserId, (uint)charSlot.CharIndex, fileName.c_str() );
|
|
// mustSaveFile = true;
|
|
// continue;
|
|
// }
|
|
//
|
|
// if (_Names.getAToBMap().find(it->first) != _Names.getAToBMap().end())
|
|
// _Names.removeWithA(it->first);
|
|
// if (_Names.getBToAMap().find(it->second) != _Names.getBToAMap().end())
|
|
// _Names.removeWithB(it->second);
|
|
//
|
|
// _Names.add( it->first, it->second );
|
|
//
|
|
// // check duplicated character slots
|
|
// map<TCharSlot,TName>::iterator itSlot = charSlotToName.find( charSlot );
|
|
// if ( itSlot != charSlotToName.end() )
|
|
// {
|
|
// _DuplicatedSlots[charSlot].insert( (*itSlot).second );
|
|
// _DuplicatedSlots[charSlot].insert( name );
|
|
// }
|
|
// else
|
|
// {
|
|
// charSlotToName[charSlot] = name;
|
|
// }
|
|
//
|
|
//// uint64 lid = ( (*it).second.UserId<<4 ) | (*it).second.CharId;
|
|
//// CEntityId id( RYZOMID::player, lid );
|
|
//// id.setDynamicId( 0 );
|
|
//// id.setCreatorId( 0 );
|
|
////
|
|
//// if (CEntityIdTranslator::getInstance()->isEntityRegistered(id))
|
|
//// CEntityIdTranslator::getInstance()->unregisterEntity( id );
|
|
//// CEntityIdTranslator::getInstance()->registerEntity( id, capitalize( name ), (*it).second.CharId, (*it).second.UserId, _AccountNames[(*it).second.UserId] );
|
|
// }
|
|
//
|
|
// if ( !_DuplicatedSlots.empty() )
|
|
// {
|
|
// nlwarning("NAMEMGR: file '%s' contains %u duplicated character slots", fileName.c_str(), _DuplicatedSlots.size() );
|
|
// }
|
|
//
|
|
// if ( mustSaveFile )
|
|
// {
|
|
// saveCharacterNames();
|
|
// }
|
|
//
|
|
// return true;
|
|
//}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
bool CNameManager::loadGuildsNamesFromTxt()
|
|
{
|
|
FILE* f;
|
|
string fileName;
|
|
|
|
// open the file
|
|
fileName = Bsi.getLocalPath() + GUILD_NAME_FILE;
|
|
f=fopen(fileName.c_str(),"rb");
|
|
if (f == NULL)
|
|
{
|
|
nlinfo("Failed to open file for reading: %s", fileName.c_str() );
|
|
return false;
|
|
}
|
|
|
|
CSString input;
|
|
|
|
// read the file content into a buffer
|
|
uint32 size=NLMISC::CFile::getFileSize(f);
|
|
input.resize(size);
|
|
uint32 readSize= (uint32)fread(&input[0],1,size,f);
|
|
fclose(f);
|
|
BOMB_IF(readSize!=size,"Failed to read file content for file: "+fileName,return false);
|
|
|
|
_GuildNames.clear();
|
|
_GuildIndex.clear();
|
|
typedef map<TGuildSlot, TName> TGuildSlotToName;
|
|
TGuildSlotToName guildSlotToName;
|
|
|
|
vector<string> lines;
|
|
NLMISC::explode(string(input), string("\n"), lines, true);
|
|
|
|
// scan the content
|
|
// while (!input.empty())
|
|
|
|
// bool mustSaveFile = false;
|
|
for (uint i=0; i<lines.size(); ++i)
|
|
{
|
|
if (i > 0 && (i%100 == 0))
|
|
nldebug("Loading guild names : %u/%u (%.2f%%)", i+1, lines.size(), float(i+1)/float(lines.size())*100.0f);
|
|
CSString line = lines[i];
|
|
vector<string> words;
|
|
NLMISC::explode(string(line), string(" "), words, true);
|
|
|
|
if (words.empty())
|
|
continue;
|
|
// merge the first words until we have only 3 words
|
|
while (words.size() > 3)
|
|
{
|
|
words[0] += words[1];
|
|
words.erase(words.begin()+1);
|
|
}
|
|
BOMB_IF (words.size()!=3,"Invalid line "<<i+1<<" found in guild names file : '"<<line<<"'", continue);
|
|
|
|
sint i1, i2;
|
|
NLMISC::fromString(words[1], i1);
|
|
NLMISC::fromString(words[2], i2);
|
|
|
|
BOMB_IF (i1==0, "Invalid shardId in guild names file line "<<i+1<<" : '"<<line<<"'", continue);
|
|
BOMB_IF (i2==0, "Invalid guildId in guild names file line "<<i+1<<" : '"<<line<<"'", continue);
|
|
TName name = words[0];
|
|
const TGuildSlot guildSlot = TGuildSlot(i1, i2);
|
|
|
|
// Check the name is usable, i.e valid regarding guild name rules AND not already used
|
|
if ( isGuildNameUsable( ucstring(name), guildSlot.GuildId) != TCharacterNameResult::cnr_ok)
|
|
{
|
|
nlwarning( "Invalid guild name '%s' for guild %u on from shard %u will be reset to default", name.c_str(), guildSlot.GuildId, guildSlot.ShardId);
|
|
|
|
name = toLower(generateDefaultGuildName(guildSlot.GuildId).toUtf8());
|
|
}
|
|
|
|
_GuildNames.insert(make_pair(name, guildSlot));
|
|
_GuildIndex.insert(make_pair(guildSlot.GuildId, name));
|
|
}
|
|
|
|
// if (mustSaveFile)
|
|
// {
|
|
// saveGuildNames();
|
|
// }
|
|
return true;
|
|
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
bool CNameManager::loadForbiddenNames()
|
|
{
|
|
string fileName;
|
|
|
|
// read the invalid entity name list
|
|
fileName = IService::getInstance()->WriteFilesDirectory.toString() + "invalid_entity_names.txt";
|
|
FILE *fp = fopen (fileName.c_str(), "r");
|
|
if (fp == NULL)
|
|
return false;
|
|
|
|
nlinfo("NAMEMGR: Loading file: %s",fileName.c_str());
|
|
while (true)
|
|
{
|
|
char str[512];
|
|
fgets(str, 511, fp);
|
|
if(feof(fp))
|
|
break;
|
|
if (strlen(str) > 0)
|
|
{
|
|
str[strlen(str)-1] = '\0';
|
|
toLower( str );
|
|
_ForbiddenNames.push_back(string());
|
|
_ForbiddenNames.back() = str;
|
|
}
|
|
}
|
|
fclose (fp);
|
|
|
|
return true;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
bool CNameManager::loadReservedNames(const char* fileNameWithoutPath)
|
|
{
|
|
CIFile f;
|
|
string fileName;
|
|
|
|
// read the reserved name list
|
|
fileName = IService::getInstance()->WriteFilesDirectory.toString() + fileNameWithoutPath;
|
|
if( !f.open( fileName ) )
|
|
return false;
|
|
|
|
nlinfo("NAMEMGR: Loading file: %s",fileName.c_str());
|
|
CIXml input;
|
|
if(!input.init( f ))
|
|
{
|
|
nlwarning("<NAMEMGR::loadReservedNames>Can't init xml input for file %s", fileName.c_str());
|
|
return false;
|
|
}
|
|
TReservedNames reservedName;
|
|
input.serialCont( reservedName );
|
|
f.close();
|
|
|
|
for( TReservedNames::iterator it = reservedName.begin(); it != reservedName.end(); ++it )
|
|
{
|
|
_ReservedNames[ toLower( (*it).first ) ] = (*it).second;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
void CNameManager::update()
|
|
{
|
|
TTempReservedNames::iterator first(_TemporaryReservedNames.begin()), last(_TemporaryReservedNames.end());
|
|
|
|
uint32 now = CTime::getSecondsSince1970();
|
|
|
|
for (; first != last; ++first)
|
|
{
|
|
if (first->second.ReserveDate+TEMPORARY_RESERVED_NAME_EXPIRATION > now)
|
|
{
|
|
// this reservation has expired, release it
|
|
_TemporaryReservedNames.erase(first);
|
|
// next release at next update
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
const CNameManager::TName &CNameManager::getGuildName(uint32 guildId) const
|
|
{
|
|
TGuildIndex::const_iterator it(_GuildIndex.find(guildId));
|
|
|
|
if (it == _GuildIndex.end())
|
|
{
|
|
static string emptyString;
|
|
return emptyString;
|
|
}
|
|
else
|
|
return it->second;
|
|
}
|
|
|
|
|
|
uint32 CNameManager::findCharId(const std::string &charName, uint32 homeSessionId)
|
|
{
|
|
TFullName fullname(charName, homeSessionId);
|
|
|
|
TNamesIndex::TAToBMap::const_iterator it(_Names.getAToBMap().find(fullname));
|
|
|
|
if (it != _Names.getAToBMap().end())
|
|
{
|
|
return it->second.getCharId();
|
|
}
|
|
|
|
// not found
|
|
return 0;
|
|
}
|
|
|
|
/// Try to find a shard id from a name without session id, return 0 if 0 or more than one match.
|
|
uint32 CNameManager::findCharId(const std::string &charName)
|
|
{
|
|
TFullName fullname(charName, 0);
|
|
|
|
TNamesIndex::TAToBMap::const_iterator it(_Names.getAToBMap().upper_bound(fullname));
|
|
TNamesIndex::TAToBMap::const_iterator found(_Names.getAToBMap().end());
|
|
|
|
while (it->first.Name == charName)
|
|
{
|
|
if (found != _Names.getAToBMap().end())
|
|
{
|
|
// more than one match
|
|
return 0;
|
|
}
|
|
// first found
|
|
found = it;
|
|
}
|
|
|
|
if (it != _Names.getAToBMap().end())
|
|
{
|
|
// we found one
|
|
return it->second.getCharId();
|
|
}
|
|
|
|
// not found 0
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
NLMISC_CLASS_COMMAND_IMPL(CNameManager, dump)
|
|
{
|
|
if (args.size() == 1 && args[0] == "all")
|
|
{
|
|
// dump the complete name table (heavy !)
|
|
const TNamesIndex::TBToAMap &ba = _Names.getBToAMap();
|
|
|
|
log.displayNL("Dumping %u character names :", ba.size());
|
|
|
|
TNamesIndex::TBToAMap::const_iterator first(ba.begin()), last(ba.end());
|
|
for (; first != last; ++first)
|
|
{
|
|
const TCharSlot &charSlot = first->first;
|
|
const TFullName &fullName = first->second;
|
|
|
|
log.displayNL(" User %u, Slot %u (char_id %u) : Name '%s' on session %u",
|
|
charSlot.UserId,
|
|
charSlot.CharIndex,
|
|
charSlot.UserId*16+charSlot.CharIndex,
|
|
fullName.Name.c_str(),
|
|
fullName.HomeSessionId.asInt());
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
if (args.size() != 0)
|
|
return false;
|
|
|
|
log.displayNL("Dumping NameManager internal state :");
|
|
log.displayNL(" - %u character names", _Names.getAToBMap().size());
|
|
log.displayNL(" - %u account names", _AccountNames.size());
|
|
log.displayNL(" - %u guild names", _GuildNames.size());
|
|
log.displayNL(" - %u guild index", _GuildIndex.size());
|
|
log.displayNL(" - %u reserved names", _ReservedNames.size());
|
|
log.displayNL(" - %u forbidden names", _ForbiddenNames.size());
|
|
log.displayNL("End of dump");
|
|
|
|
return true;
|
|
}
|
|
|
|
NLMISC_CLASS_COMMAND_IMPL(CNameManager, releaseGuildNamesForShard)
|
|
{
|
|
if (args.size() != 1)
|
|
return false;
|
|
|
|
uint32 shardId = atoui(args[1].c_str());
|
|
|
|
vector<uint32> guildNameToRemove;
|
|
|
|
TGuildNames::iterator first(_GuildNames.begin()), last(_GuildNames.end());
|
|
for (; first != last; ++first)
|
|
{
|
|
if (first->second.ShardId == shardId)
|
|
guildNameToRemove.push_back(first->second.GuildId);
|
|
}
|
|
|
|
log.displayNL("Releasing %u guild name for shard %u", guildNameToRemove.size(), shardId);
|
|
|
|
for (uint i=0; i<guildNameToRemove.size(); ++i)
|
|
{
|
|
uint32 guildId = guildNameToRemove[i];
|
|
TGuildIndex::iterator it(_GuildIndex.find(guildId));
|
|
BOMB_IF(it == _GuildIndex.end(), "Error in guildname/index management", continue);
|
|
|
|
_GuildNames.erase(it->second);
|
|
_GuildIndex.erase(it);
|
|
}
|
|
|
|
return true;
|
|
}
|