mirror of
https://port.numenaute.org/aleajactaest/khanat-code-old.git
synced 2024-11-28 01:36:36 +00:00
1425 lines
40 KiB
C++
1425 lines
40 KiB
C++
|
||
#include "stdpch.h"
|
||
#include "string_manager.h"
|
||
#include "input_output_service.h"
|
||
#include "nel/misc/i18n.h"
|
||
#include "nel/misc/path.h"
|
||
#include "nel/misc/file.h"
|
||
#include "nel/net/unified_network.h"
|
||
#include "nel/net/service.h"
|
||
#include "nel/misc/bit_mem_stream.h"
|
||
#include "nel/misc/diff_tool.h"
|
||
#include "game_share/ryzom_mirror_properties.h"
|
||
#include "game_share/backup_service_interface.h"
|
||
#include "nel/georges/u_form_elm.h"
|
||
#include "nel/georges/load_form.h"
|
||
#include "server_share/r2_variables.h"
|
||
#include <time.h>
|
||
|
||
//---------------------------------------------------------------------------------------
|
||
// Stuff used for management of log messages
|
||
|
||
//static bool VerboseLog=false;
|
||
|
||
|
||
//bool DebugReplacementParameter = false;
|
||
//NLMISC_VARIABLE(bool, DebugReplacementParameter, "Debug missing replacement parameter.");
|
||
NLMISC::CVariable<bool> DebugReplacementParameter("ios","DebugReplacementParameter", "Insert error debugging information in generated text", false, 0, true);
|
||
NLMISC::CVariable<bool> VerboseStringManager("ios","VerboseStringManager", "Turn on or off or check the state of verbose string manager logging", false, 0, true);
|
||
NLMISC::CVariable<bool> VerboseStringManagerParser("ios","VerboseStringManagerParser", "Turn on or off or check the state of verbose string manager logging when parsing files", false, 0, true);
|
||
NLMISC::CVariable<std::string> StringManagerCacheDirectory("ios","StringManagerCacheDirectory", "Directory to read/write string cache file (default (empty) is service SaveFilesDirectory)", "", 0, true);
|
||
|
||
#define LOG if (!VerboseStringManager) {} else nlinfo
|
||
#define LOGPARSE if (!VerboseStringManagerParser) {} else nlinfo
|
||
|
||
|
||
// Instantiate the string manager.
|
||
CStringManager Instance;
|
||
CStringManager *SM = &Instance;
|
||
CIosLocalSender IosLocalSender;
|
||
|
||
using namespace STRING_MANAGER;
|
||
using namespace NLMISC;
|
||
using namespace NLNET;
|
||
using namespace std;
|
||
|
||
const ucstring nl("\r\n");
|
||
|
||
|
||
std::string CStringManager::_LanguageCode[NB_LANGUAGES] =
|
||
{
|
||
"wk", // Work
|
||
"en", // english
|
||
"de",
|
||
"fr",
|
||
"ru",
|
||
|
||
/* ace: currently, we only want english, i remove other language to remove warning during IOS launch
|
||
"fr", // french
|
||
"zh", // traditionnal chinese
|
||
"zh-CN" // simplified chinese
|
||
*/
|
||
};
|
||
|
||
/*
|
||
ucstring CStringManager::getEntityDisplayName(const NLMISC::CEntityId &eid)
|
||
{
|
||
ucstring ret;
|
||
NLMISC::CSheetId sid = SM->getSheetId(eid);
|
||
if (sid != NLMISC::CSheetId::Unknown)
|
||
{
|
||
// TSheetInfoContainer::iterator it(_SheetInfo.find(sid));
|
||
|
||
if (it != _SheetInfo.end())
|
||
ret = it->second.DisplayName;
|
||
}
|
||
|
||
// not found.
|
||
if (ret.empty())
|
||
ret = ucstring(eid.toString());
|
||
|
||
return ret;
|
||
}
|
||
*/
|
||
|
||
|
||
|
||
|
||
|
||
uint32 CStringManager::CEntityWords::getStringId(const std::string &rowName, const std::string columnName) const
|
||
{
|
||
std::map<std::string, uint32>::const_iterator colIt(_ColumnInfo.find(columnName));
|
||
if (colIt != _ColumnInfo.end())
|
||
{
|
||
std::map<std::string, uint32>::const_iterator rowIt(_RowInfo.find(rowName));
|
||
if (rowIt != _RowInfo.end())
|
||
{
|
||
return _Data[rowIt->second*_NbColums + colIt->second];
|
||
}
|
||
}
|
||
// not found, return rowName.columnName.
|
||
if (DebugReplacementParameter)
|
||
return SM->storeString(ucstring(std::string("<")+rowName+"."+columnName+">"));
|
||
else
|
||
{
|
||
ucstring s;
|
||
s += ucchar(8);
|
||
return SM->storeString(s);
|
||
}
|
||
}
|
||
|
||
|
||
|
||
CStringManager::CStringManager()
|
||
{
|
||
_TestOnly = false;
|
||
_CacheLoaded = false;
|
||
_Mapper = NLMISC::CStringMapper::createLocalMapper();
|
||
_DefaultSetPhraseLanguage = NB_LANGUAGES;
|
||
// init the game share string manager pointer.
|
||
// GameShareSM = this;
|
||
}
|
||
|
||
|
||
void CStringManager::loadCache()
|
||
{
|
||
if (_CacheLoaded)
|
||
{
|
||
return;
|
||
}
|
||
nlassert(_StringIdx.empty());
|
||
nlassert(_StringBase.empty());
|
||
|
||
// std::string filename("data_shard/ios.string_cache");
|
||
// _CacheFilename = NLMISC::CPath::lookup(filename, false, false);
|
||
// if (!_CacheFilename.empty())
|
||
|
||
std::string cacheDirectory = ((StringManagerCacheDirectory.get() == "") ? Bsi.getLocalPath() : StringManagerCacheDirectory.get());
|
||
_CacheFilename = CPath::standardizePath(cacheDirectory) + "ios.string_cache";
|
||
if (CFile::fileExists(_CacheFilename))
|
||
{
|
||
nlinfo("Reading string cache...");
|
||
// ok, load the cache data
|
||
NLMISC::CIFile file(_CacheFilename);
|
||
file.serial(_CacheTimestamp);
|
||
|
||
uint32 start = CTime::getSecondsSince1970();
|
||
uint32 t1 = start;
|
||
|
||
while (!file.eof())
|
||
{
|
||
uint32 id;
|
||
ucstring str;
|
||
|
||
file.serial(id);
|
||
file.serial(str);
|
||
|
||
// nldebug("Loaded from cache [%u][%s]", id, str.toString().c_str());
|
||
// create a new entry
|
||
std::pair<TMappedUStringContainer::iterator, bool> ret;
|
||
ret = _StringIdx.insert(std::make_pair(str, id));
|
||
// nlassert(ret.second);
|
||
if (!ret.second)
|
||
{
|
||
TMappedUStringContainer::iterator it = _StringIdx.find(str);
|
||
nlassert(it != _StringIdx.end());
|
||
nlwarning("String cache : string [%s][%u] already in the string map with id [%u] !", str.c_str(), id, it->second);
|
||
if (id != it->second)
|
||
{
|
||
nlwarning(" !!! ID diff : string cache invalide.");
|
||
}
|
||
}
|
||
// if (_StringBase.size() <= id)
|
||
// {
|
||
// _StringBase.reserve(_StringBase.size()*2);
|
||
// }
|
||
// _StringBase.resize(id+1);
|
||
// _StringBase[id] = str;
|
||
while (_StringBase.size() <= id)
|
||
_StringBase.push_back(string());
|
||
_StringBase[id] = str;
|
||
|
||
// some logging
|
||
uint32 now = CTime::getSecondsSince1970();
|
||
if ((now - t1) > 10)
|
||
{
|
||
// more than 10 s... log where we are
|
||
double progress = 100*(file.getPos()/double(file.getFileSize()));
|
||
|
||
nlinfo(" %6.2f%% read", progress);
|
||
|
||
t1 = now;
|
||
}
|
||
}
|
||
uint32 now = CTime::getSecondsSince1970();
|
||
nlinfo("Done, %u strings read in %u seconds.", _StringBase.size(), now-start);
|
||
}
|
||
else
|
||
{
|
||
// create a new cache
|
||
if (!CFile::isExists(cacheDirectory))
|
||
CFile::createDirectoryTree(cacheDirectory);
|
||
|
||
_CacheTimestamp = CTime::getSecondsSince1970();
|
||
NLMISC::COFile file(_CacheFilename);
|
||
file.serial(_CacheTimestamp);
|
||
}
|
||
|
||
_CacheLoaded = true;
|
||
}
|
||
|
||
void CStringManager::clearCache(NLMISC::CLog *log)
|
||
{
|
||
if (_CacheFilename.empty())
|
||
{
|
||
log->displayNL("Clear cache requested but no cache file name available!");
|
||
return;
|
||
}
|
||
|
||
log->displayNL("Clearing cache file and reloading string files...");
|
||
CFile::deleteFile(_CacheFilename);
|
||
_StringIdx.clear();
|
||
_StringBase.clear();
|
||
_CacheLoaded = false;
|
||
// this will clear all loaded string, then reinit the string manager
|
||
reload(log);
|
||
|
||
// warn all the client that they must dropout there cache file
|
||
}
|
||
|
||
|
||
|
||
|
||
// load the values using the george sheet
|
||
void CStringManager::TSheetInfo::readGeorges (const NLMISC::CSmartPtr<NLGEORGES::UForm> &form, const NLMISC::CSheetId &sheetId)
|
||
{
|
||
if (form)
|
||
{
|
||
SheetName = sheetId.toString();
|
||
|
||
std::string ext = NLMISC::CSheetId::fileExtensionFromType(sheetId.getSheetType());
|
||
|
||
SheetName = SheetName.substr(0, SheetName.find(ext));
|
||
// remove ending '.'
|
||
if (!SheetName.empty() && *SheetName.rbegin() == '.')
|
||
SheetName.resize(SheetName.size()-1);
|
||
|
||
std::string gender;
|
||
|
||
if (sheetId.getSheetType() == NLMISC::CSheetId::typeFromFileExtension("creature"))
|
||
{
|
||
form->getRootNode ().getValueByName (gender, "Basics.Gender");
|
||
Gender = GSGENDER::EGender(atoi(gender.c_str()));
|
||
|
||
form->getRootNode ().getValueByName (Race, "Basics.Race");
|
||
|
||
// form->getRootNode ().getValueByName (DisplayName, "Basics.First Name");
|
||
// std::string s;
|
||
// form->getRootNode ().getValueByName (s, "Basics.CharacterName");
|
||
// if (!DisplayName.empty())
|
||
// DisplayName+=' ';
|
||
// DisplayName+=s;
|
||
|
||
form->getRootNode ().getValueByName (Profile, "Basics.Profile");
|
||
form->getRootNode ().getValueByName (ChatProfile, "Basics.ChatProfile");
|
||
}
|
||
else if (sheetId.getSheetType() == NLMISC::CSheetId::typeFromFileExtension("race_stats"))
|
||
{
|
||
form->getRootNode ().getValueByName (Race, "Race");
|
||
}
|
||
/* else if (sheetId.getType() == NLMISC::CSheetId::typeFromFileExtension("sitem"))
|
||
{
|
||
// read any item specific data
|
||
}
|
||
*/ else
|
||
{
|
||
nlwarning("CStringManager::TEntityInfo : Do not know the type of the sheet '%s'.", sheetId.toString().c_str());
|
||
return;
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
|
||
|
||
const CStringManager::CEntityWords &CStringManager::getEntityWords(TLanguages lang, STRING_MANAGER::TParamType type) const
|
||
{
|
||
nlassert(lang < NB_LANGUAGES);
|
||
nlassert(type < STRING_MANAGER::NB_PARAM_TYPES ||type == STRING_MANAGER::self);
|
||
|
||
return _AllEntityWords[lang][type];
|
||
}
|
||
|
||
|
||
bool CStringManager::CClause::eval(CStringManager::TLanguages lang, const CCharacterInfos *charInfo, const CPhrase *phrase)
|
||
{
|
||
bool ret = false;
|
||
|
||
// if no condition, it's true !
|
||
if (Conditions.empty())
|
||
return true;
|
||
|
||
for (uint i=0; !ret && i<Conditions.size(); ++i)
|
||
{
|
||
|
||
std::vector<TCondition> &andedCond = Conditions[i];
|
||
bool temp = true;
|
||
|
||
for (uint j=0; temp && j<andedCond.size(); ++j)
|
||
{
|
||
const CParameterTraits *param = phrase->Params[andedCond[j].ParamIndex];
|
||
temp &= param->eval(lang,charInfo ,andedCond[j]);
|
||
}
|
||
|
||
ret |= temp;
|
||
}
|
||
|
||
return ret;
|
||
}
|
||
|
||
NLMISC::CSheetId CStringManager::getSheetId(const NLMISC::CEntityId &entityId)
|
||
{
|
||
TDataSetRow entityIndex = TheDataset.getDataSetRow( entityId );
|
||
|
||
if (!entityIndex.isValid())
|
||
return NLMISC::CSheetId::Unknown;
|
||
|
||
CMirrorPropValueBase<TYPE_SHEET> sheetId( TheDataset, entityIndex, DSPropertySHEET );
|
||
return NLMISC::CSheetId( sheetId );
|
||
}
|
||
|
||
NLMISC::CSheetId CStringManager::getSheetServerId(const NLMISC::CEntityId &entityId)
|
||
{
|
||
TDataSetRow entityIndex = TheDataset.getDataSetRow( entityId );
|
||
|
||
if (!entityIndex.isValid())
|
||
return NLMISC::CSheetId::Unknown;
|
||
|
||
CMirrorPropValueBase<uint32> sheetServerId( TheDataset, entityIndex, DSPropertySHEET_SERVER );
|
||
return NLMISC::CSheetId( sheetServerId );
|
||
}
|
||
|
||
|
||
const CStringManager::TSheetInfo &CStringManager::getSheetInfo(const NLMISC::CSheetId &sheetId)
|
||
{
|
||
TSheetInfoContainer::iterator it(_SheetInfo.find(sheetId));
|
||
if (it != _SheetInfo.end())
|
||
return it->second;
|
||
|
||
static TSheetInfo unknown;
|
||
// nlwarning("Unknown sheetId : %s", sheetId.toString().c_str());
|
||
return unknown;
|
||
}
|
||
|
||
|
||
|
||
void CStringManager::buildMissingPhraseStream(CCharacterInfos * charInfo, uint32 seqNum, NLMISC::CBitMemStream & bmsOut, const std::string &phraseName)
|
||
{
|
||
// store a string for this error message.
|
||
uint32 id = storeString(ucstring("<missing:")+phraseName+">");
|
||
// now, build the message for the client.
|
||
GenericXmlMsgHeaderMngr.pushNameToStream( "STRING_MANAGER:PHRASE_SEND", bmsOut);
|
||
bmsOut.serial(seqNum);
|
||
bmsOut.serial(id);
|
||
|
||
LOG("Sending phrase [%s] content", phraseName.c_str());
|
||
}
|
||
|
||
bool CStringManager::buildPhraseStream( CCharacterInfos * charInfo, uint32 seqNum, NLNET::CMessage & message, bool debug, CStringManager::TLanguages lang, NLMISC::CBitMemStream & bmsOut)
|
||
{
|
||
// uint32 seqNum;
|
||
std::string phraseName;
|
||
message.serial(phraseName);
|
||
LOG("Receiving phrase %u as '%s'", seqNum, phraseName.c_str() );
|
||
|
||
if (phraseName.empty())
|
||
{
|
||
nlwarning("buildPhraseStream: phrase name is empty !");
|
||
return false;
|
||
}
|
||
|
||
// ok, try to find this phrase
|
||
bool found = false;
|
||
TPhrasesContainer::iterator it(_AllPhrases[lang].find(phraseName));
|
||
if (it != _AllPhrases[lang].end())
|
||
found = true;
|
||
|
||
// if not found try to get the working text
|
||
if (!found && lang != english)
|
||
{
|
||
it = _AllPhrases[english].find(phraseName);
|
||
if (it != _AllPhrases[english].end())
|
||
found = true;
|
||
}
|
||
|
||
// if still not found try to get the work text
|
||
if (!found && lang != work)
|
||
{
|
||
it = _AllPhrases[work].find(phraseName);
|
||
if (it != _AllPhrases[work].end())
|
||
{
|
||
found = true;
|
||
|
||
// every phrases should be at least translated in english
|
||
nlwarning("CStringManager::buildPhraseStream the phrase [%s] has not been translated in english!", phraseName.c_str());
|
||
}
|
||
}
|
||
|
||
if (!found)
|
||
{
|
||
nlwarning("CStringManager::buildPhraseStream the phrase [%s] is unknown in %s, in english and in work", phraseName.c_str(), _LanguageCode[lang].c_str());
|
||
|
||
buildMissingPhraseStream(charInfo, seqNum, bmsOut, phraseName);
|
||
return true;
|
||
}
|
||
|
||
// ok, we have the phrase, we can parse the parameter from the message
|
||
CPhrase &phrase = it->second;
|
||
// std::vector<TStringParam> params;
|
||
// params.resize(phrase.Params.size());
|
||
uint i;
|
||
|
||
try
|
||
{
|
||
bool result = true;
|
||
for (i=1; i<phrase.Params.size(); ++i)
|
||
{
|
||
result &= phrase.Params[i]->extractFromMessage(message, debug);
|
||
}
|
||
|
||
if (!result)
|
||
nlwarning("Format error extracting parameters in phrase %s, result string could be erroneous !",phrase.Name.c_str() );
|
||
}
|
||
catch(...)
|
||
{
|
||
nlwarning("Exception while extracting parameters in phrase %s, result string could be erroneous !",phrase.Name.c_str() );
|
||
|
||
// init the rest with default values
|
||
for (; i<phrase.Params.size(); ++i)
|
||
{
|
||
phrase.Params[i]->setDefaultValue();
|
||
}
|
||
// return;
|
||
}
|
||
|
||
// update the self parameter with dest eid.
|
||
if ( charInfo )
|
||
phrase.Params[0]->EId = charInfo->EntityId;
|
||
else
|
||
phrase.Params[0]->EId = CEntityId::Unknown;
|
||
|
||
|
||
// ok, we have the phrase and a list of typed param, we can search for the good clause.
|
||
found = false;
|
||
for (i=0; i<phrase.Clauses.size(); ++i)
|
||
{
|
||
// if the first clause as no condition, consider it as a fallback clause.
|
||
if (i==0 && phrase.Clauses[i].Conditions.empty())
|
||
{
|
||
// skip it, it will be used only for fallback when no clause match
|
||
continue;
|
||
}
|
||
if (phrase.Clauses[i].eval(lang,charInfo, &phrase))
|
||
{
|
||
found = true;
|
||
break;
|
||
}
|
||
}
|
||
if (!found)
|
||
{
|
||
// force the use of the first clause.
|
||
// NB : this is a 'best effort' fallback. Either the first clause has
|
||
// no condition, so it is designed to be the fallback one, or
|
||
// the first clause has some condition not valid, but we use it.
|
||
i=0;
|
||
}
|
||
|
||
CClause &clause = phrase.Clauses[i];
|
||
|
||
// now, build the message for the client.
|
||
GenericXmlMsgHeaderMngr.pushNameToStream( "STRING_MANAGER:PHRASE_SEND", bmsOut);
|
||
bmsOut.serial(seqNum);
|
||
bmsOut.serial(clause.ClientStringId);
|
||
|
||
// for each replacement parameter in order...
|
||
for (i=0; i<clause.Replacements.size(); ++i)
|
||
{
|
||
TReplacement &rep = clause.Replacements[i];
|
||
CParameterTraits *param = phrase.Params[clause.Replacements[i].ParamIndex];
|
||
|
||
param->fillBitMemStream(charInfo,lang, rep, bmsOut);
|
||
}
|
||
LOG("Sending phrase [%s] content", phraseName.c_str());
|
||
return true;
|
||
|
||
}
|
||
|
||
void CStringManager::receiveUserPhrase(NLNET::CMessage &message, bool debug)
|
||
{
|
||
// extract the parameters
|
||
uint32 userId;
|
||
uint32 seqNum;
|
||
message.serial( userId );
|
||
message.serial(seqNum);
|
||
LOG("Receiving a phrase for user id %d", userId);
|
||
|
||
// get the user language
|
||
TUserLanguagesContainer::const_iterator itUser = _UsersLanguages.find( userId );
|
||
if ( itUser == _UsersLanguages.end() )
|
||
{
|
||
// just extract the phrase name for more info in the warning
|
||
std::string phraseName;
|
||
message.serial(phraseName);
|
||
|
||
nlwarning("CStringManager::receiveUserPhrase '%s', unknown user %u", phraseName.c_str(), userId);
|
||
return;
|
||
}
|
||
// built the stream to be sent to the client
|
||
NLMISC::CBitMemStream bmsOut;
|
||
if ( buildPhraseStream( NULL, seqNum, message, debug, (*itUser).second.Language, bmsOut ) )
|
||
{
|
||
CMessage msgout( "IMPULSION_UID" );
|
||
msgout.serial( userId );
|
||
msgout.serialBufferWithSize((uint8*)bmsOut.buffer(), bmsOut.length());
|
||
NLNET::CUnifiedNetwork::getInstance()->send( (*itUser).second.FrontEndId, msgout );
|
||
nldebug( "IOSSM: Sent IMPULSION_UID to %hu (PHRASE_SEND)", (*itUser).second.FrontEndId.get() );
|
||
}
|
||
}
|
||
|
||
void CStringManager::receivePhrase(NLNET::CMessage &message, bool debug, const std::string &serviceName)
|
||
{
|
||
// extract the parameters
|
||
// NLMISC::CEntityId dest;
|
||
TDataSetRow dest;
|
||
uint32 seqNum;
|
||
message.serial( dest );
|
||
LOG("Receiving a phrase for char %s:%x",
|
||
TheDataset.getEntityId(dest).toString().c_str(),
|
||
dest.getIndex() );
|
||
|
||
message.serial(seqNum);
|
||
|
||
CEntityId destId = TheDataset.getEntityId(dest);
|
||
// retrieve the dest player infos.
|
||
CCharacterInfos *charInfo = IOS->getCharInfos(destId);
|
||
if (charInfo == 0)
|
||
{
|
||
nlwarning("CStringManager::receivePhrase unknown eid %s:%x",
|
||
TheDataset.getEntityId(dest).toString().c_str(),
|
||
dest.getIndex());
|
||
return;
|
||
}
|
||
|
||
if (destId.getType() == RYZOMID::npc || destId.getType() == RYZOMID::creature)
|
||
{
|
||
// read the phrase name
|
||
std::string phraseName;
|
||
message.serial(phraseName);
|
||
|
||
nlwarning("Service '%s' is trying to send phrase '%s' to a AIS entity !",
|
||
serviceName.c_str(),
|
||
phraseName.c_str());
|
||
return;
|
||
|
||
}
|
||
|
||
// built the stream to be sent to the client
|
||
NLMISC::CBitMemStream bmsOut;
|
||
if ( buildPhraseStream( charInfo, seqNum, message, debug, charInfo->Language, bmsOut ) )
|
||
{
|
||
NLNET::CMessage msgout( "IMPULS_CH_ID" );
|
||
NLMISC::CEntityId destId = charInfo->EntityId;
|
||
uint8 channel = 1;
|
||
msgout.serial( destId );
|
||
msgout.serial( channel );
|
||
|
||
msgout.serialBufferWithSize((uint8*)bmsOut.buffer(), bmsOut.length());
|
||
NLNET::CUnifiedNetwork::getInstance()->send(TServiceId(charInfo->EntityId.getDynamicId()), msgout);
|
||
}
|
||
}
|
||
|
||
void CStringManager::broadcastSystemMessage(NLNET::CMessage &message, bool debug)
|
||
{
|
||
TDataSetRow client;
|
||
vector<CEntityId> temp;
|
||
set<CEntityId> excluded;
|
||
CChatGroup::TGroupType audience = CChatGroup::nbChatMode;
|
||
uint32 seqNum;
|
||
|
||
message.serial(client);
|
||
message.serialCont(temp);
|
||
excluded.insert(temp.begin(), temp.end());
|
||
message.serialEnum(audience);
|
||
message.serial(seqNum);
|
||
|
||
if (!IOS->getChatManager().checkClient(client))
|
||
{
|
||
nlwarning("broadcastSystemMessage : can't find client %s:%x in chat client",
|
||
TheDataset.getEntityId(client).toString().c_str(),
|
||
client.getIndex());
|
||
return;
|
||
}
|
||
|
||
try
|
||
{
|
||
// can thow CChatManager::EChatClient exception
|
||
CChatClient &chatClient = IOS->getChatManager().getClient(client);
|
||
|
||
TGroupId groupId;
|
||
|
||
switch (audience)
|
||
{
|
||
case CChatGroup::say:
|
||
// force an update of the say audience
|
||
chatClient.getSayAudience(true);
|
||
groupId = chatClient.getSayAudienceId();
|
||
break;
|
||
case CChatGroup::team:
|
||
groupId = chatClient.getTeamChatGroup();
|
||
break;
|
||
case CChatGroup::guild:
|
||
groupId = chatClient.getGuildChatGroup();
|
||
break;
|
||
case CChatGroup::shout:
|
||
// force an update of the shout audience
|
||
chatClient.getShoutAudience(true);
|
||
groupId = chatClient.getShoutAudienceId();
|
||
break;
|
||
default:
|
||
nlwarning("broadcastSystemMessage : unsupported chat mode '%s' for broadcast", CChatGroup::groupTypeToString(audience).c_str());
|
||
return;
|
||
}
|
||
|
||
// can throw EChatGroup
|
||
CChatGroup &chatGroup = IOS->getChatManager().getGroup(groupId);
|
||
|
||
// generate a unique string seq number
|
||
seqNum = STRING_MANAGER::pickStringSerialNumber();
|
||
|
||
// and send to all the client in audience.
|
||
CChatGroup::TMemberCont::iterator first(chatGroup.Members.begin()), last(chatGroup.Members.end());
|
||
for (; first != last; ++first)
|
||
{
|
||
TDataSetRow dsr = *first;
|
||
|
||
// send to all client except the sender
|
||
if (dsr != client)
|
||
{
|
||
CEntityId eid = TheDataset.getEntityId(dsr);
|
||
|
||
if (excluded.find(eid) != excluded.end())
|
||
continue;
|
||
|
||
CCharacterInfos *charInfo = IOS->getCharInfos(eid);
|
||
if (charInfo == NULL)
|
||
continue;
|
||
|
||
// copy the message
|
||
CMessage msg;
|
||
msg.assignFromSubMessage(message);
|
||
// built the stream to be sent to the client
|
||
NLMISC::CBitMemStream bmsOut;
|
||
if ( buildPhraseStream( charInfo, seqNum, msg, debug, charInfo->Language, bmsOut ) )
|
||
{
|
||
NLNET::CMessage msgout( "IMPULS_CH_ID" );
|
||
NLMISC::CEntityId destId = charInfo->EntityId;
|
||
uint8 channel = 1;
|
||
msgout.serial( destId );
|
||
msgout.serial( channel );
|
||
|
||
msgout.serialBufferWithSize((uint8*)bmsOut.buffer(), bmsOut.length());
|
||
NLNET::CUnifiedNetwork::getInstance()->send(TServiceId(charInfo->EntityId.getDynamicId()), msgout);
|
||
|
||
|
||
// inform the client to display the dyn string in system info
|
||
{
|
||
CMessage msgout( "IMPULSION_ID" );
|
||
msgout.serial( const_cast<CEntityId&> (eid) );
|
||
CBitMemStream bms;
|
||
if ( ! GenericXmlMsgHeaderMngr.pushNameToStream( "STRING:DYN_STRING", bms) )
|
||
{
|
||
nlwarning("<sendDynamicSystemMessage> Msg name CHAT:DYN_STRING not found");
|
||
}
|
||
else
|
||
{
|
||
bms.serial( seqNum );
|
||
msgout.serialBufferWithSize((uint8*)bms.buffer(), bms.length());
|
||
CUnifiedNetwork::getInstance()->send( TServiceId(eid.getDynamicId()), msgout );
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
catch(CChatManager::EChatClient e)
|
||
{
|
||
nlwarning("%s", e.what());
|
||
}
|
||
catch(...)
|
||
{
|
||
}
|
||
}
|
||
|
||
//void CStringManager::requestString(const NLMISC::CEntityId &client, uint32 stringId)
|
||
//{
|
||
// ucstring str = getString(stringId);
|
||
//
|
||
// CCharacterInfos *charInfo = IOS->getCharInfos(client);
|
||
// if (charInfo == 0)
|
||
// {
|
||
// if (IsRingShard.get())
|
||
// {
|
||
// // In ring shard, it is possible that the client autologin and
|
||
// // autochoose the character rapidly, and if a string need to be resolved
|
||
// // to d<>splay the char summary, it is possible client receive the
|
||
// // dynamic string from IOS after the EGS has passed the frontend in
|
||
// // entityId mode.
|
||
// // So, the IOS receive a stringId request with a Eid not registered yet.
|
||
// // Look in the user table, if we have the user, use the UID version
|
||
// uint32 userId = client.getShortId()>>4;
|
||
// TUserLanguagesContainer::const_iterator itUser = _UsersLanguages.find( userId );
|
||
// if ( itUser != _UsersLanguages.end() )
|
||
// {
|
||
// requestString(userId, stringId);
|
||
// return;
|
||
// }
|
||
// }
|
||
// nlwarning("requestString : Client with eid %s is unknown (requesting string %u as [%s])",
|
||
// client.toString().c_str(),
|
||
// stringId,
|
||
// str.toString().c_str());
|
||
// return;
|
||
// }
|
||
//
|
||
//
|
||
// LOG("Sending string %u as [%s] to client %s", stringId, str.toString().c_str(), client.toString().c_str());
|
||
//
|
||
// // build the response message
|
||
// NLMISC::CBitMemStream bmsOut;
|
||
// GenericXmlMsgHeaderMngr.pushNameToStream( "STRING_MANAGER:STRING_RESP", bmsOut);
|
||
// bmsOut.serial(stringId);
|
||
// // Send in utf8 format to save bandwith
|
||
// string strUtf8= str.toUtf8();
|
||
// bmsOut.serial(strUtf8);
|
||
//
|
||
// // send the message to Front End
|
||
// NLNET::CMessage msgout( "IMPULS_CH_ID" );
|
||
// NLMISC::CEntityId destId = client;
|
||
// uint8 channel = 1;
|
||
// msgout.serial( destId );
|
||
// msgout.serial( channel );
|
||
//
|
||
// msgout.serialBufferWithSize((uint8*)bmsOut.buffer(), bmsOut.length());
|
||
// NLNET::CUnifiedNetwork::getInstance()->send(TServiceId(charInfo->EntityId.getDynamicId()), msgout);
|
||
//}
|
||
|
||
void CStringManager::requestString(uint32 userId, uint32 stringId)
|
||
{
|
||
TServiceId frontendId;
|
||
TUserLanguagesContainer::const_iterator itUser = _UsersLanguages.find( userId );
|
||
if ( itUser == _UsersLanguages.end() )
|
||
{
|
||
// no user language, try to find a character
|
||
breakable
|
||
{
|
||
const CInputOutputService::TIdToInfos &chars = IOS->getCharInfosCont();
|
||
CInputOutputService::TIdToInfos::const_iterator it(chars.lower_bound(CEntityId(RYZOMID::player, userId<<4)));
|
||
if (it != chars.end())
|
||
{
|
||
CEntityId eid = it->first;
|
||
|
||
if (eid.getShortId()>>4 == userId)
|
||
{
|
||
// we found a character for this user, use it
|
||
frontendId = TServiceId(eid.getDynamicId());
|
||
|
||
break;
|
||
}
|
||
}
|
||
|
||
// if we are here, we did not found a character for this user
|
||
nlwarning("<CStringManager requestString> Invalid user id %u",userId);
|
||
return;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
// we know the user
|
||
frontendId = itUser->second.FrontEndId;
|
||
}
|
||
|
||
ucstring str = getString(stringId);
|
||
LOG("Sending string %u as [%s] to user %u", stringId, str.toString().c_str(), userId);
|
||
// build the response message
|
||
NLMISC::CBitMemStream bmsOut;
|
||
GenericXmlMsgHeaderMngr.pushNameToStream( "STRING_MANAGER:STRING_RESP", bmsOut);
|
||
bmsOut.serial(stringId);
|
||
// Send in utf8 format to save bandwidth
|
||
string strUtf8= str.toUtf8();
|
||
bmsOut.serial(strUtf8);
|
||
|
||
// send the message to Front End
|
||
CMessage msgout( "IMPULSION_UID" );
|
||
msgout.serial( userId );
|
||
msgout.serialBufferWithSize((uint8*)bmsOut.buffer(), bmsOut.length());
|
||
NLNET::CUnifiedNetwork::getInstance()->send( frontendId, msgout );
|
||
nldebug( "IOSSM: Sent IMPULSION_UID to %hu (STRING_RESP)", frontendId.get() );
|
||
}
|
||
|
||
|
||
void CStringManager::reload(NLMISC::CLog *log)
|
||
{
|
||
uint i;
|
||
for(i=0; i<NB_LANGUAGES; ++i)
|
||
{
|
||
uint j;
|
||
|
||
// need to manualy delete param object.
|
||
while (!_AllPhrases[i].empty())
|
||
{
|
||
CPhrase &phrase = _AllPhrases[i]. begin()->second;
|
||
|
||
while (!phrase.Params.empty())
|
||
{
|
||
delete phrase.Params.back();
|
||
phrase.Params.pop_back();
|
||
}
|
||
|
||
_AllPhrases[i].erase(_AllPhrases[i].begin());
|
||
}
|
||
_AllPhrases[i].clear();
|
||
|
||
for (j=0; j<STRING_MANAGER::NB_PARAM_TYPES; ++j)
|
||
{
|
||
CEntityWords &ew = _AllEntityWords[i][j];
|
||
|
||
ew._ColumnInfo.clear();
|
||
ew._NbColums = 0;
|
||
ew._RowInfo.clear();
|
||
delete [] ew._Data;
|
||
}
|
||
}
|
||
|
||
init(log);
|
||
}
|
||
|
||
|
||
|
||
|
||
CStringManager::TLanguages CStringManager::checkLanguageCode(const std::string &languageCode)
|
||
{
|
||
for (uint i=0; i<NB_LANGUAGES; ++i)
|
||
{
|
||
if (_LanguageCode[i] == languageCode)
|
||
return TLanguages(i);
|
||
}
|
||
|
||
nlwarning("Unrecognized language code %s, default to english", languageCode.c_str());
|
||
// default to english.
|
||
return english;
|
||
}
|
||
|
||
const std::string &CStringManager::getLanguageCodeString(TLanguages language)
|
||
{
|
||
if (language < NB_LANGUAGES)
|
||
return _LanguageCode[language];
|
||
|
||
nlwarning("Language number %u is out of range, returning english", language);
|
||
nlassert(english < NB_LANGUAGES); // just to avoid oopsie
|
||
return _LanguageCode[english];
|
||
}
|
||
|
||
|
||
|
||
uint32 CStringManager::storeString(const ucstring &str)
|
||
{
|
||
// TMappedUStringContainer _StringIdx;
|
||
// TUStringContainer _StringBase;
|
||
|
||
TMappedUStringContainer::iterator it(_StringIdx.find(str));
|
||
if (it != _StringIdx.end())
|
||
{
|
||
// the string already in base, just return the index.
|
||
return it->second;
|
||
}
|
||
else
|
||
{
|
||
// create a new entry
|
||
std::pair<TMappedUStringContainer::iterator, bool> ret;
|
||
ret = _StringIdx.insert(std::make_pair(str, (uint32)_StringBase.size()));
|
||
nlassert(ret.second);
|
||
_StringBase.push_back(str);
|
||
|
||
if (!_TestOnly)
|
||
{
|
||
// add the string in the cache file
|
||
NLMISC::COFile file(_CacheFilename, true);
|
||
LOGPARSE("Writing to cache [%u][%s]", ret.first->second, ret.first->first.toString().c_str());
|
||
file.serial(ret.first->second);
|
||
ucstring temp = ret.first->first;
|
||
file.serial(temp);
|
||
}
|
||
|
||
return ret.first->second;
|
||
}
|
||
}
|
||
|
||
const ucstring &CStringManager::getString(uint32 stringId)
|
||
{
|
||
if (stringId < _StringBase.size())
|
||
return _StringBase[stringId];
|
||
else
|
||
return _StringBase.front();
|
||
}
|
||
|
||
|
||
|
||
uint32 CStringManager::translateShortName(uint32 shortNameIndex)
|
||
{
|
||
// No bot name translation on ring shards
|
||
if (IsRingShard)
|
||
return shortNameIndex;
|
||
|
||
std::map<uint32, uint32>::iterator it(_BotNameTranslation.find(shortNameIndex));
|
||
|
||
if (it != _BotNameTranslation.end())
|
||
{
|
||
if (it->second != 0)
|
||
// yeaa, we found a translation with a non empty short name
|
||
return it->second;
|
||
else
|
||
// the translated name is empty, ignore the translated name
|
||
return shortNameIndex;
|
||
}
|
||
else
|
||
// no translation, return the same index.
|
||
return shortNameIndex;
|
||
|
||
return 0;
|
||
}
|
||
|
||
uint32 CStringManager::translateShortName(const ucstring &shortName)
|
||
{
|
||
//
|
||
return translateShortName(storeString(shortName));
|
||
}
|
||
|
||
uint32 CStringManager::translateTitle(const std::string &title, TLanguages language)
|
||
{
|
||
const std::string colName("name");
|
||
const CStringManager::CEntityWords &ew = getEntityWords(language, STRING_MANAGER::title);
|
||
std::string rowName = NLMISC::strlwr(title);
|
||
uint32 stringId;
|
||
stringId = ew.getStringId(rowName, colName);
|
||
|
||
return stringId;
|
||
}
|
||
|
||
uint32 CStringManager::translateEventFaction(uint32 eventFactionId)
|
||
{
|
||
if (VerboseStringManager)
|
||
nlinfo("Event faction translation asked for : '%s' (%u)", getString(eventFactionId).toString().c_str(), eventFactionId);
|
||
|
||
if (eventFactionId == 0)
|
||
return 0;
|
||
|
||
std::map<uint32, uint32>::iterator it = _EventFactionTranslation.find(eventFactionId);
|
||
if (it != _EventFactionTranslation.end())
|
||
{
|
||
if (VerboseStringManager)
|
||
nlinfo("Found event faction translation : '%s' (%u)", getString(it->second).toString().c_str(), it->second);
|
||
|
||
return it->second;
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
uint32 CStringManager::translateEventFaction(const ucstring &eventFaction)
|
||
{
|
||
if (eventFaction.empty())
|
||
return 0;
|
||
|
||
return translateEventFaction(storeString(eventFaction));
|
||
}
|
||
|
||
/*
|
||
* Send the requested string
|
||
*/
|
||
void CStringManager::sendString( uint32 nameIndex, TServiceId serviceId )
|
||
{
|
||
CMessage msgout( "RECV_STRING" );
|
||
msgout.serial( nameIndex );
|
||
const ucstring& ucs = getString( nameIndex );
|
||
msgout.serial( const_cast<ucstring&>(ucs) );
|
||
CUnifiedNetwork::getInstance()->send( serviceId, msgout ); // reply => not via mirror
|
||
}
|
||
|
||
|
||
/*
|
||
* Send the names of all online entities
|
||
*/
|
||
void CStringManager::retrieveEntityNames( TServiceId serviceId )
|
||
{
|
||
vector< pair<TDataSetRow,string> > names;
|
||
TEntityIdToEntityIndexMap::const_iterator itEntityIndex;
|
||
for( itEntityIndex = TheDataset.entityBegin(); itEntityIndex != TheDataset.entityEnd(); ++itEntityIndex )
|
||
{
|
||
TDataSetRow entityIndex = TheDataset.getCurrentDataSetRow( GET_ENTITY_INDEX(itEntityIndex) );
|
||
if ( entityIndex.isValid() )
|
||
{
|
||
CMirrorPropValueRO<TYPE_NAME_STRING_ID> nameIndex( TheDataset, entityIndex, DSPropertyNAME_STRING_ID );
|
||
if ( nameIndex() != 0 )
|
||
{
|
||
names.push_back( make_pair( entityIndex, getString(nameIndex).toString() ) );
|
||
}
|
||
}
|
||
}
|
||
NLNET::CMessage msgout( "ENTITY_NAMES" );
|
||
uint32 len = (uint32)names.size();
|
||
msgout.serial( len );
|
||
vector< pair<TDataSetRow,string> >::const_iterator itn;
|
||
for ( itn=names.begin(); itn!=names.end(); ++itn )
|
||
{
|
||
msgout.serial( const_cast<TDataSetRow&>((*itn).first) );
|
||
msgout.serial( const_cast<string&>((*itn).second) );
|
||
}
|
||
NLNET::CUnifiedNetwork::getInstance()->send( serviceId, msgout );
|
||
nldebug( "IOSSM: Sent %u names to service %hu", names.size(), serviceId.get() );
|
||
}
|
||
|
||
void CStringManager::updateUserLanguage( uint32 userId, TServiceId frontEndId, const std::string & lang )
|
||
{
|
||
CStringManager::TLanguages language = checkLanguageCode( lang );
|
||
SUserLanguageEntry entry( frontEndId, language );
|
||
TUserLanguagesContainer::iterator it = _UsersLanguages.find(userId);
|
||
if (it == _UsersLanguages.end())
|
||
{
|
||
_UsersLanguages.insert(make_pair(userId, entry));
|
||
}
|
||
else
|
||
{
|
||
it->second.FrontEndId = frontEndId;
|
||
it->second.Language = language;
|
||
}
|
||
|
||
// TODO : send cache time stamp to client.
|
||
nldebug ("IOSSM: updateUserLanguage : set userId %u to front end %u using language code '%s'",
|
||
userId,
|
||
frontEndId.get(),
|
||
SM->getLanguageCodeString(language).c_str());
|
||
|
||
// send back the cache time stamp info
|
||
uint32 timestamp = SM->getCacheTimestamp();
|
||
|
||
// now, build the message for the client.
|
||
NLMISC::CBitMemStream bmsOut;
|
||
GenericXmlMsgHeaderMngr.pushNameToStream( "STRING_MANAGER:RELOAD_CACHE", bmsOut);
|
||
bmsOut.serial(timestamp);
|
||
|
||
// send the message to Front End
|
||
NLNET::CMessage msgout( "IMPULSION_UID" );
|
||
msgout.serial(userId);
|
||
|
||
msgout.serialBufferWithSize((uint8*)bmsOut.buffer(), bmsOut.length());
|
||
try
|
||
{
|
||
CUnifiedNetwork::getInstance()->send( frontEndId, msgout);
|
||
}
|
||
catch( Exception& e )
|
||
{
|
||
nlwarning( "CStringManager::updateUserLanguage : Error : %s", e.what() );
|
||
}
|
||
}
|
||
|
||
/*
|
||
* Replace a phrase in default language(s) (message handler)
|
||
*/
|
||
void CStringManager::setPhrase(NLNET::CMessage &message)
|
||
{
|
||
std::string phraseName;
|
||
ucstring phraseContent;
|
||
try
|
||
{
|
||
message.serial(phraseName);
|
||
message.serial(phraseContent);
|
||
}
|
||
catch( Exception& e )
|
||
{
|
||
nlwarning("<setPhrase> %s",e.what());
|
||
return;
|
||
}
|
||
setPhrase(phraseName, phraseContent);
|
||
}
|
||
|
||
/*
|
||
* Replace a phrase in default language(s)
|
||
*/
|
||
void CStringManager::setPhrase(std::string const& phraseName, ucstring const& phraseContent)
|
||
{
|
||
if (_DefaultSetPhraseLanguage==NB_LANGUAGES)
|
||
for (int i=0; i<NB_LANGUAGES; ++i)
|
||
setPhrase(phraseName, phraseContent, (TLanguages)i);
|
||
else
|
||
setPhrase(phraseName, phraseContent, _DefaultSetPhraseLanguage);
|
||
}
|
||
|
||
|
||
/// Store a set of user named item associated with an AIInstance
|
||
void CStringManager::storeItemNamesForAIInstance(uint32 aiInstance, const std::vector < R2::TCharMappedInfo > &itemInfos)
|
||
{
|
||
// first, parse all the container to remove any previously user item with this aiInstance
|
||
TRingUserItemInfos::iterator first(_RingUserItemInfos.begin()), last(_RingUserItemInfos.end());
|
||
// for each item having one or more translation...
|
||
for (; first != last; ++first)
|
||
{
|
||
std::vector<TRingUserItemInfo> &items = first->second;
|
||
// for each translation of this item...
|
||
for (uint i=0; i<items.size(); ++i)
|
||
{
|
||
if (items[i].AIInstance == aiInstance)
|
||
{
|
||
// remove this one
|
||
items.erase(items.begin() + i);
|
||
--i;
|
||
|
||
// NB : item with 0 translation are keept in the table because
|
||
// the set of user item in the ring is closed and limited.
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
// insert the new items definition
|
||
for (uint i=0; i<itemInfos.size(); ++i)
|
||
{
|
||
const R2::TCharMappedInfo &itemInfo = itemInfos[i];
|
||
|
||
TRingUserItemInfo ruii;
|
||
ruii.AIInstance = aiInstance;
|
||
ruii.ItemNameId = storeString(itemInfo.getName());
|
||
_RingUserItemInfos[itemInfo.getItemSheet()].push_back(ruii);
|
||
}
|
||
}
|
||
|
||
|
||
/*
|
||
NLMISC_COMMAND(verboseStringManager,"Turn on or off or check the state of verbose string manager logging","")
|
||
{
|
||
if(args.size()>1)
|
||
return false;
|
||
|
||
if(args.size()==1)
|
||
{
|
||
if(args[0]==string("on")||args[0]==string("ON")||args[0]==string("true")||args[0]==string("TRUE")||args[0]==string("1"))
|
||
VerboseLog=true;
|
||
|
||
if(args[0]==string("off")||args[0]==string("OFF")||args[0]==string("false")||args[0]==string("FALSE")||args[0]==string("0"))
|
||
VerboseLog=false;
|
||
}
|
||
|
||
nlinfo("VerboseLogging is %s",VerboseLog?"ON":"OFF");
|
||
return true;
|
||
}
|
||
*/
|
||
|
||
NLMISC_CATEGORISED_COMMAND(stringmanager, loadPhraseFile, "Merge a phrase file into string manager","<language code> <directory>[/file]")
|
||
{
|
||
if (args.size() != 2)
|
||
return false;
|
||
|
||
std::string lang = args[0];
|
||
std::string file = args[1];
|
||
|
||
CStringManager::TLanguages language = SM->checkLanguageCode(lang);
|
||
|
||
if (SM->getLanguageCodeString(language) != lang)
|
||
{
|
||
log.displayNL("Failed, language '%s' is not a valid language", lang.c_str());
|
||
return false;
|
||
}
|
||
|
||
if (!CFile::fileExists(file))
|
||
{
|
||
if (!CFile::isDirectory(file))
|
||
{
|
||
log.displayNL("Failed, path '%s' is not a valid file nor directory", file.c_str());
|
||
return false;
|
||
}
|
||
|
||
file = CPath::standardizePath(file)+"phrase_"+lang+".txt";
|
||
|
||
if (!CFile::fileExists(file))
|
||
{
|
||
log.displayNL("Failed to locate default phrase file '%s'", file.c_str());
|
||
return false;
|
||
}
|
||
}
|
||
|
||
SM->loadPhraseFile(file, language, "", &log);
|
||
|
||
return true;
|
||
}
|
||
|
||
NLMISC_CATEGORISED_COMMAND(stringmanager, mergeWordFile, "Merge a word file into string manager","<language code> <word type> <directory>[/file]")
|
||
{
|
||
if (args.size() != 3)
|
||
return false;
|
||
|
||
std::string lang = args[0];
|
||
std::string word = toLower(args[1]);
|
||
std::string file = args[2];
|
||
|
||
// get language
|
||
CStringManager::TLanguages language = SM->checkLanguageCode(lang);
|
||
if (SM->getLanguageCodeString(language) != lang)
|
||
{
|
||
log.displayNL("Failed, language '%s' is not a valid language", lang.c_str());
|
||
return false;
|
||
}
|
||
|
||
// get word type
|
||
CStringManager::TParameterTraitList typeNames = CStringManager::CParameterTraits::getParameterTraitsNames();
|
||
STRING_MANAGER::TParamType wordType;
|
||
uint i;
|
||
for (i=0; i<typeNames.size(); ++i)
|
||
{
|
||
if (toLower(typeNames[i].second) == word)
|
||
{
|
||
wordType = typeNames[i].first;
|
||
break;
|
||
}
|
||
}
|
||
if (i == typeNames.size())
|
||
{
|
||
log.displayNL("Failed, word type '%s' is not valid", word.c_str());
|
||
return false;
|
||
}
|
||
|
||
//
|
||
if (!CFile::fileExists(file))
|
||
{
|
||
if (!CFile::isDirectory(file))
|
||
{
|
||
log.displayNL("Failed, path '%s' is not a valid file nor directory", file.c_str());
|
||
return false;
|
||
}
|
||
|
||
file = CPath::standardizePath(file)+word+"_words_"+lang+".txt";
|
||
|
||
if (!CFile::fileExists(file))
|
||
{
|
||
log.displayNL("Failed to locate default word file '%s'", file.c_str());
|
||
return false;
|
||
}
|
||
}
|
||
|
||
bool oldMode = SM->ReadTranslationWork;
|
||
// We don't want diff with work file now
|
||
SM->ReadTranslationWork = false;
|
||
SM->mergeEntityWordsFile(file, language, wordType);
|
||
SM->ReadTranslationWork = oldMode;
|
||
|
||
return true;
|
||
}
|
||
|
||
NLMISC_CATEGORISED_COMMAND(stringmanager, displayEntityWords, "display entity words for a language and type","<language code> <word type> [wordwildcard]")
|
||
{
|
||
if (args.size() < 2 || args.size() > 3)
|
||
return false;
|
||
|
||
std::string lang = args[0];
|
||
std::string word = toLower(args[1]);
|
||
std::string wc;
|
||
|
||
if (args.size() == 3)
|
||
wc = args[2];
|
||
|
||
// get language
|
||
CStringManager::TLanguages language = SM->checkLanguageCode(lang);
|
||
if (SM->getLanguageCodeString(language) != lang)
|
||
{
|
||
log.displayNL("Failed, language '%s' is not a valid language", lang.c_str());
|
||
return false;
|
||
}
|
||
|
||
// get word type
|
||
CStringManager::TParameterTraitList typeNames = CStringManager::CParameterTraits::getParameterTraitsNames();
|
||
STRING_MANAGER::TParamType wordType;
|
||
uint i;
|
||
for (i=0; i<typeNames.size(); ++i)
|
||
{
|
||
if (toLower(typeNames[i].second) == word)
|
||
{
|
||
wordType = typeNames[i].first;
|
||
break;
|
||
}
|
||
}
|
||
if (i == typeNames.size())
|
||
{
|
||
log.displayNL("Failed, word type '%s' is not valid", word.c_str());
|
||
return false;
|
||
}
|
||
|
||
SM->displayEntityWords(language, wordType, wc, &log);
|
||
return true;
|
||
}
|
||
|
||
NLMISC_CATEGORISED_COMMAND(stringmanager, setEntityWord, "set a word value","<language code>.<word type>.<word>.<determinant> <value>")
|
||
{
|
||
if (args.size() < 2 || args.size() > 5)
|
||
return false;
|
||
|
||
std::string path = args[0];
|
||
uint wi = 1;
|
||
|
||
while (wi < args.size()-1)
|
||
path += "."+args[wi++];
|
||
|
||
ucstring word(args[wi]);
|
||
|
||
// get language
|
||
SM->setEntityWord(path, word);
|
||
return true;
|
||
}
|
||
|
||
|
||
NLMISC_CATEGORISED_COMMAND(stringmanager, loadBotNames, "load a bot names file","[bot names file] [reset bot names (0|1)]")
|
||
{
|
||
if (args.size() > 2)
|
||
return false;
|
||
|
||
std::string filename = "bot_names.txt";
|
||
bool resetBotnames = false;
|
||
|
||
if (args.size() > 0)
|
||
filename = args[0];
|
||
|
||
if (args.size() > 1)
|
||
resetBotnames = (atoi(args[1].c_str()) != 0);
|
||
|
||
SM->loadBotNames(filename, resetBotnames, &log);
|
||
return true;
|
||
}
|
||
|
||
NLMISC_CATEGORISED_COMMAND(stringmanager, setBotName, "set a bot name","<bot name (utf8)> <translation (utf8)>")
|
||
{
|
||
if (args.size() != 2)
|
||
return false;
|
||
|
||
ucstring botname, translation;
|
||
|
||
botname.fromUtf8(args[0]);
|
||
translation.fromUtf8(args[1]);
|
||
|
||
SM->setBotName(botname, translation);
|
||
return true;
|
||
}
|
||
|
||
NLMISC_CATEGORISED_COMMAND(stringmanager, readStringManagerRepository, "parse a whole repository with phrases and words (language is optional, none will load rep for all languages)","<directory> [language code]")
|
||
{
|
||
if (args.size() < 1 || args.size() > 2)
|
||
return false;
|
||
|
||
string path = args[0];
|
||
|
||
if (args.size() == 2)
|
||
{
|
||
string lang = args[1];
|
||
|
||
CStringManager::TLanguages language = SM->checkLanguageCode(lang);
|
||
if (SM->getLanguageCodeString(language) != lang)
|
||
{
|
||
log.displayNL("Failed, language '%s' is not a valid language", lang.c_str());
|
||
return false;
|
||
}
|
||
|
||
log.displayNL("Reading text repository '%s' for language '%s'",
|
||
path.c_str(),
|
||
lang.c_str());
|
||
SM->readRepository(path, language, &log);
|
||
}
|
||
else
|
||
{
|
||
log.displayNL("Reading text repository '%s' for all language",
|
||
path.c_str());
|
||
uint i;
|
||
for (i=1; i<CStringManager::NB_LANGUAGES; ++i)
|
||
{
|
||
SM->readRepository(path, (CStringManager::TLanguages)i, &log);
|
||
}
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
|
||
NLMISC_CATEGORISED_COMMAND(stringmanager, defaultSetPhraseLanguage, "Selects the language overriden by AIS messages","<language code>")
|
||
{
|
||
if (args.size() < 0 || args.size() > 1)
|
||
return false;
|
||
|
||
if (args.size()!=0)
|
||
{
|
||
CStringManager::TLanguages language = CStringManager::english;
|
||
if (args[0]=="all")
|
||
{
|
||
language = CStringManager::NB_LANGUAGES;
|
||
}
|
||
else
|
||
{
|
||
language = SM->checkLanguageCode(args[0]);
|
||
}
|
||
SM->setDefaultSetPhraseLanguage(language);
|
||
}
|
||
CStringManager::TLanguages language = SM->getDefaultSetPhraseLanguage();
|
||
std::string languageCode;
|
||
if (language==CStringManager::NB_LANGUAGES)
|
||
languageCode = "all";
|
||
else
|
||
languageCode = SM->getLanguageCodeString(language);
|
||
log.displayNL("Language overriden by AIS messages is %s", languageCode.c_str());
|
||
return true;
|
||
}
|
||
|
||
|