// Ryzom - MMORPG Framework // Copyright (C) 2010-2017 Winch Gate Property Limited // // This source file has been modified by the following contributors: // Copyright (C) 2020 Jan BOON (Kaetemi) // // 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 . #ifndef STRING_MANAGER_CLIENT_H #define STRING_MANAGER_CLIENT_H #include "nel/misc/static_map.h" #include "nel/misc/ucstring.h" #include "nel/misc/bit_mem_stream.h" #include "nel/misc/i18n.h" #include "nel/misc/sheet_id.h" #include "nel/misc/diff_tool.h" #include "game_share/brick_families.h" #include "game_share/skills.h" namespace STRING_MANAGER { class IStringWaiterRemover; class IStringWaitCallback; class CStringManagerClient { friend class IStringWaiterRemover; friend class IStringWaitCallback; public: // Singleton pattern implementation static CStringManagerClient *instance(); static bool hasInstance() { return _Instance; } static void release(bool mustReleaseStaticArrays); /** Prepare the string manager to use a persistent string cache. * There is one cache file for each language and for each encountered shard. */ void initCache(const std::string &shardId, const std::string &languageCode); /** Clear the current string table and load the content of the cache file. * This method is called after receiving the impulse RELOAD_CACHE from * IOS. * If the received timestamp and the file timestamp differ, the file cache * is reseted. */ void loadCache(uint32 timestamp); bool isCacheLoaded() {return _CacheLoaded;}; // Force the cache to be saved void flushStringCache(); bool getString(uint32 stringId, std::string &result); void waitString(uint32 stringId, const IStringWaiterRemover *premover, std::string *result); void waitString(uint32 stringId, IStringWaitCallback *pcallback); bool getDynString(uint32 dynStringId, std::string &result); void waitDynString(uint32 stringId, const IStringWaiterRemover *premover, std::string *result); void waitDynString(uint32 stringId, IStringWaitCallback *pcallback); void receiveString(uint32 stringId, const std::string &str); void receiveDynString(NLMISC::CBitMemStream &bms); void releaseDynString(uint32 stringId); // Yoyo: Append to the I18N some words (skills, bricks...) static void initI18NSpecialWords(const std::string &languageCode); static void specialWordsMemoryCompress(); // Yoyo: Replace the Brick Name with Filled stats (CSBrickManager work). No-Op if not found static void replaceSBrickName(NLMISC::CSheetId id, const std::string &name, const std::string &desc, const std::string &desc2); static void replaceDynString(const std::string &name, const std::string &text); // Get the Localized Name of the Places. static const char *getPlaceLocalizedName(const std::string &placeNameID); // Get the Localized Name of the faction (for the fame) static const char *getFactionLocalizedName(const std::string &factionNameID); // Get the Localized Name of the Skill. static const char *getSkillLocalizedName(SKILLS::ESkills e); // Get the Localized Name of the Item. static const char *getItemLocalizedName(NLMISC::CSheetId id); // Get the Localized Name of the Creature. static const char *getCreatureLocalizedName(NLMISC::CSheetId id); // Get the Localized Name of the SBrick. static const char *getSBrickLocalizedName(NLMISC::CSheetId id); // Get the Localized Name of the SPhrase. static const char *getSPhraseLocalizedName(NLMISC::CSheetId id); // Get the Localized Description of the Skill. static const char *getSkillLocalizedDescription(SKILLS::ESkills e); // Get the Localized Descriptionof the Item. static const char *getItemLocalizedDescription(NLMISC::CSheetId id); // Get the Localized Description of the SBrick. static const char *getSBrickLocalizedDescription(NLMISC::CSheetId id); // Get the Localized Composition Description of the SBrick. static const char *getSBrickLocalizedCompositionDescription(NLMISC::CSheetId id); // Get the Localized Description of the SPhrase. static const char *getSPhraseLocalizedDescription(NLMISC::CSheetId id); // Get the Localized Title name static const char *getTitleLocalizedName(const std::string &titleId, bool women); static const char *getLocalizedName(const std::string &text); static std::vector getTitleInfos(const std::string &titleId, bool women); // Get the Localized name of a classification type static const char *getClassificationTypeLocalizedName(EGSPD::CClassificationType::TClassificationType type); // Outpost name static const char *getOutpostLocalizedName(NLMISC::CSheetId id); // Outpost description static const char *getOutpostLocalizedDescription(NLMISC::CSheetId id); // Outpost building name static const char *getOutpostBuildingLocalizedName(NLMISC::CSheetId id); // Outpost building description static const char *getOutpostBuildingLocalizedDescription(NLMISC::CSheetId id); // Squad name static const char *getSquadLocalizedName(NLMISC::CSheetId id); // Squad description static const char *getSquadLocalizedDescription(NLMISC::CSheetId id); private: // constructor. CStringManagerClient(); // destructor. ~CStringManagerClient(); /// A string waiter is destoyed, remove any waiting string reference from it. void removeStringWaiter(const IStringWaiterRemover *remover); /// A string wait callback is destoyed, remove any waiting string reference from it. void removeStringWaiter(const IStringWaitCallback *callback); enum TParamType { string_id, integer, time, money, dyn_string_id, sheet_id }; struct TParamValue { TParamType Type; std::string::size_type ReplacementPoint; union { uint32 StringId; sint32 Integer; uint32 Time; uint64 Money; uint32 DynStringId; }; }; struct TDynStringInfo { enum TStatus { received, serialized, complete }; TStatus Status; NLMISC::CBitMemStream Message; uint32 StringId; std::vector Params; std::string String; }; enum { EmptyStringId= 0, EmptyDynStringId= 0xffffffff }; struct TStringWaiter { /// Pointer to the utf-8 string to fill std::string *Result; /// Pointer to the remover that contains this string reference const IStringWaiterRemover *Remover; }; bool buildDynString(TDynStringInfo &dynInfo); /// Container for simple strings typedef CHashMap TStringsContainer; /// Container for dyn strings typedef CHashMap TDynStringsContainer; /// Container of string reference waiting for value. typedef CHashMultiMap TStringWaitersContainer; /// Container of string reference to string callback object. typedef CHashMultiMap TStringCallbacksContainer; TStringsContainer _ReceivedStrings; CHashSet _WaitingStrings; TDynStringsContainer _ReceivedDynStrings; TDynStringsContainer _WaitingDynStrings; /// String waiting the string value from the server. TStringWaitersContainer _StringsWaiters; // String waiting the dyn string value from the server. TStringWaitersContainer _DynStringsWaiters; // Callback for string value from the server TStringCallbacksContainer _StringsCallbacks; // Callback for dyn string value from the server TStringCallbacksContainer _DynStringsCallbacks; // Return value for waiting string.. static std::string _WaitString; // Singleton pattern implementation static CStringManagerClient *_Instance; //@{ //\name Cache management /// Flag for cache management initialisation done. bool _CacheInited; /// Shard id is used to identify the cache file to use. std::string _ShardId; /// Language code is used to identify the cache file to use. std::string _LanguageCode; /// Timestamp (unix date) of the corrently loaded cache file. uint32 _Timestamp; /// Fullpath name of the current cache file. std::string _CacheFilename; /// Flag to incate that the cache is loaded. bool _CacheLoaded; /// Waiting string to be saved in cache struct CCacheString { uint32 StringId; std::string String; }; std::vector _CacheStringToSave; //@} // SpecialItems. class CItem { public: // The Name of the item std::string Name; // The Women Name of the item std::string WomenName; // Description of the item std::string Desc; // Optional Second description (For SBrick composition for example) std::string Desc2; void serial(NLMISC::IStream &f) { sint ver = f.serialVersion(2); if (ver >= 2) { f.serial(Name); f.serial(WomenName); f.serial(Desc); f.serial(Desc2); } else { nlassert(f.isReading()); ucstring name; // Old UTF-16 serial ucstring womenName; // Old UTF-16 serial ucstring desc; // Old UTF-16 serial ucstring desc2; // Old UTF-16 serial f.serial(name); if (ver >= 1) f.serial(womenName); f.serial(desc); f.serial(desc2); Name = name.toUtf8(); WomenName = womenName.toUtf8(); Desc = desc.toUtf8(); Desc2 = desc2.toUtf8(); } } }; static bool _SpecItem_MemoryCompressed; static std::map _SpecItem_TempMap; static std::vector _TitleWords; static std::map _DynStrings; static char *_SpecItem_Labels; static char *_SpecItem_NameDesc; struct CItemLight { const char *Label; const char *Name; const char *WomenName; const char *Desc; const char *Desc2; }; struct CItemLightComp { bool operator()(const CItemLight &x, const CItemLight &y) const { return strcmp(x.Label, y.Label) < 0; } }; static std::vector _SpecItems; static const char *getSpecialWord(const std::string &label, bool women = false); static const char *getSpecialDesc(const std::string &label); static const char *getSpecialDesc2(const std::string &label); // Check Files for the Packed string. class CFileCheck { public: uint32 ReferenceDate; uint32 AdditionDate; CFileCheck() { ReferenceDate= 0; AdditionDate= 0; } bool operator==(const CFileCheck &o) const { return ReferenceDate==o.ReferenceDate && AdditionDate==o.AdditionDate; } void serial(NLMISC::IStream &f) { f.serialVersion(0); f.serial(ReferenceDate); f.serial(AdditionDate); } }; // The Header for the Packed String Client class CPackHeader { public: // The language code used std::string LanguageCode; // The Modification Dates of each word files std::vector FileChecks; // If must rebuild the packed version for any reason. uint32 PackedVersion; void serial(NLMISC::IStream &f) { f.serialCheck(NELID("_RTS")); f.serialCheck(NELID("KCAP")); f.serialVersion(0); f.serial(PackedVersion); f.serial(LanguageCode); f.serialCont(FileChecks); } }; // return true if OK (same). static bool checkWordFileDates(std::vector &fileChecks, const std::vector &fileNames, const std::string &languageCode); }; /** Class that want to register to wait for string * need to derive from this class. */ class IStringWaiterRemover { public: virtual ~IStringWaiterRemover() { // signal the string manager that this waiter is destroyed if (CStringManagerClient::hasInstance()) CStringManagerClient::instance()->removeStringWaiter(this); } }; /** Implement this class if you want to wait for * string to be delivered. */ class IStringWaitCallback { public: /// Overide this method to receive callback for string. virtual void onStringAvailable(uint /* stringId */, const std::string &/* value */) {} /// Overide this method to receive callback for dynamic string. virtual void onDynStringAvailable(uint /* stringId */, const std::string &/* value */) {} virtual ~IStringWaitCallback() { // signal the string manager that this waiter is destroyed if (CStringManagerClient::hasInstance()) CStringManagerClient::instance()->removeStringWaiter(this); } }; /** A proxy file loader for CI18N * The implementation will check if there is any * new content in the translation/work directory of ryzom * then overwrite the value found in data/gamedev/language */ class CLoadProxy : public NLMISC::CI18N::ILoadProxy, public TStringDiff::IDiffCallback { void loadStringFile(const std::string &filename, ucstring &text); // TODO: UTF-8 (serial) void onEquivalent(uint addIndex, uint refIndex, TStringDiffContext &context); void onAdd(uint addIndex, uint refIndex, TStringDiffContext &context); void onRemove(uint addIndex, uint refIndex, TStringDiffContext &context); void onChanged(uint addIndex, uint refIndex, TStringDiffContext &context); void onSwap(uint newIndex, uint refIndex, TStringDiffContext &context); }; } // namespace STRING_MANAGER #endif //STRING_MANAGER_CLIENT_H