diff --git a/code/nel/include/nel/misc/sheet_id.h b/code/nel/include/nel/misc/sheet_id.h index dc5a1385b..856dbf330 100644 --- a/code/nel/include/nel/misc/sheet_id.h +++ b/code/nel/include/nel/misc/sheet_id.h @@ -58,19 +58,43 @@ public : */ explicit CSheetId( uint32 sheetRef = 0 ); + /** + * Constructor + */ + explicit CSheetId( int sheetRef ); + /** * Constructor */ explicit CSheetId( const std::string& sheetName ); + /** + * Operator= + */ + explicit CSheetId( const char *sheetName ); + /** * Constructor, uses defaultType as extension when sheetName * contains no file extension. */ explicit CSheetId( const std::string& sheetName, const std::string &defaultType ); + /** + * Constructor, uses defaultType as extension when sheetName + * contains no file extension. + */ + explicit CSheetId( const std::string& sheetName, const char *defaultType ); + + /** + * Constructor, uses defaultType as extension when sheetName + * contains no file extension. + */ + explicit CSheetId( const char *sheetName, const char *defaultType ); + // build from a string and returns true if the build succeed - bool buildSheetId(const std::string& sheetName); + bool buildSheetId(const char *sheetName, size_t sheetNameLen); + inline bool buildSheetId(const char *sheetName) { return buildSheetId(sheetName, strlen(sheetName)); } + inline bool buildSheetId(const std::string &sheetName) { return buildSheetId(sheetName.c_str(), sheetName.size()); } // build from a SubSheetId and a type void buildSheetId(uint32 shortId, uint32 type); @@ -93,17 +117,22 @@ public : /** * Return the **whole** sheet id (id+type) */ - uint32 asInt() const { return _Id.Id; } + inline uint32 asInt() const { return _Id.Id; } /** * Return the sheet type (sub part of the sheetid) */ - uint32 getSheetType() const { return _Id.IdInfos.Type; } + inline uint32 getSheetType() const { return _Id.IdInfos.Type; } /** * Return the sheet sub id (sub part of the sheetid) */ - uint32 getShortId() const { return _Id.IdInfos.Id; } + inline uint32 getShortId() const { return _Id.IdInfos.Id; } + + /** + * Operator bool + */ + inline operator bool() const { return _Id.Id; } /** * Operator= @@ -115,11 +144,21 @@ public : */ CSheetId& operator=( const std::string& sheetName ); + /** + * Operator= + */ + CSheetId& operator=( const char *sheetName ); + /** * Operator= */ CSheetId& operator=( uint32 sheetRef ); + /** + * Operator= + */ + CSheetId& operator=( int sheetRef ); + /** * Operator< */ @@ -218,9 +257,12 @@ private : } }; + typedef CStaticMap TSheetIdToNameMap; + typedef CStaticMap TSheetNameToIdMap; + static CChar _AllStrings; - static CStaticMap _SheetIdToName; - static CStaticMap _SheetNameToId; + static TSheetIdToNameMap _SheetIdToName; + static TSheetNameToIdMap _SheetNameToId; static std::vector _FileExtensions; static bool _Initialised; diff --git a/code/nel/include/nel/misc/string_common.h b/code/nel/include/nel/misc/string_common.h index bc506cf82..3fd46b835 100644 --- a/code/nel/include/nel/misc/string_common.h +++ b/code/nel/include/nel/misc/string_common.h @@ -275,6 +275,21 @@ inline bool startsWith(const char *str, const char *prefix) inline bool startsWith(const std::string &str, const char *prefix) { return startsWith(str.c_str(), prefix); } inline bool startsWith(const std::string &str, const std::string &prefix) { return startsWith(str.c_str(), prefix.c_str()); } +inline bool endsWith(const char *str, size_t strLen, const char *suffix, size_t suffixLen) +{ + if (strLen < suffixLen) + return false; + int minLen = strLen < suffixLen ? strLen : suffixLen; + for (int i = 1; i <= minLen; ++i) + if (str[strLen - i] != suffix[suffixLen - i]) + return false; + return true; +} + +inline bool endsWith(const char *str, const char *suffix) { return endsWith(str, strlen(str), suffix, strlen(suffix)); } +inline bool endsWith(const std::string &str, const char *suffix) { return endsWith(str.c_str(), str.size(), suffix, strlen(suffix)); } +inline bool endsWith(const std::string &str, const std::string &suffix) { return endsWith(str.c_str(), str.size(), suffix.c_str(), suffix.size()); } + // Convert local codepage to UTF-8 // On Windows, the local codepage is undetermined // On Linux, the local codepage is always UTF-8 (no-op) diff --git a/code/nel/include/nel/misc/string_mapper.h b/code/nel/include/nel/misc/string_mapper.h index aeaccf959..c2229e746 100644 --- a/code/nel/include/nel/misc/string_mapper.h +++ b/code/nel/include/nel/misc/string_mapper.h @@ -1,6 +1,9 @@ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // +// This source file has been modified by the following contributors: +// Copyright (C) 2019 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 @@ -65,7 +68,23 @@ class CStringMapper class CCharComp { public: - bool operator()(std::string *x, std::string *y) const +#ifdef NL_CPP14 + // https://www.fluentcpp.com/2017/06/09/search-set-another-type-key/ + + using is_transparent = void; + + bool operator()(const std::string *x, const char *y) const + { + return strcmp(x->c_str(), y) < 0; + } + + bool operator()(const char *x, const std::string *y) const + { + return strcmp(x, y->c_str()) < 0; + } +#endif + + bool operator()(const std::string *x, const std::string *y) const { return (*x) < (*y); } @@ -73,53 +92,70 @@ class CStringMapper class CAutoFastMutex { - CFastMutex *_Mutex; + CFastMutex *m_Mutex; + public: - CAutoFastMutex(CFastMutex *mtx) : _Mutex(mtx) {_Mutex->enter();} - ~CAutoFastMutex() {_Mutex->leave();} + CAutoFastMutex(CFastMutex *mtx) + : m_Mutex(mtx) + { + m_Mutex->enter(); + } + ~CAutoFastMutex() { m_Mutex->leave(); } }; // Local Data - std::set _StringTable; - std::string* _EmptyId; - CFastMutex _Mutex; // Must be thread-safe (Called by CPortal/CCluster, each of them called by CInstanceGroup) + typedef std::set TStringTable; + TStringTable m_StringTable; + std::string *m_EmptyId; + CFastMutex m_Mutex; // Must be thread-safe (Called by CPortal/CCluster, each of them called by CInstanceGroup) // The 'singleton' for static methods - static CStringMapper _GlobalMapper; + static CStringMapper s_GlobalMapper; // private constructor. CStringMapper(); public: - ~CStringMapper() { localClear(); + delete m_EmptyId; } /// Globaly map a string into a unique Id. ** This method IS Thread-Safe ** - static TStringId map(const std::string &str) { return _GlobalMapper.localMap(str); } + static TStringId map(const std::string &str) { return s_GlobalMapper.localMap(str); } + /// Globaly map a string into a unique Id. ** This method IS Thread-Safe ** + static TStringId map(const char *str) { return s_GlobalMapper.localMap(str); } /// Globaly unmap a string. ** This method IS Thread-Safe ** - static const std::string &unmap(const TStringId &stringId) { return _GlobalMapper.localUnmap(stringId); } + static const std::string &unmap(const TStringId &stringId) { return s_GlobalMapper.localUnmap(stringId); } /// Globaly helper to serial a string id. ** This method IS Thread-Safe ** - static void serialString(NLMISC::IStream &f, TStringId &id) {_GlobalMapper.localSerialString(f, id);} + static void serialString(NLMISC::IStream &f, TStringId &id) { s_GlobalMapper.localSerialString(f, id); } /// Return the global id for the empty string (helper function). NB: Works with every instance of CStringMapper - static TStringId emptyId() { return 0; } + static TStringId emptyId() { return NULL; } // ** This method IS Thread-Safe ** - static void clear() { _GlobalMapper.localClear(); } + static void clear() { s_GlobalMapper.localClear(); } /// Create a local mapper. You can dispose of it by deleting it. - static CStringMapper * createLocalMapper(); + static CStringMapper *createLocalMapper(); /// Localy map a string into a unique Id - TStringId localMap(const std::string &str); + TStringId localMap(const std::string &str); +#ifdef NL_CPP14 + /** + \brief Localy map a string into a unique Id. + Lookup in string mapper using `const char *` + to avoid an std::string allocation when using literals. + \author Jan BOON (Kaetemi) + \date 2019 + */ + TStringId localMap(const char *str); +#endif /// Localy unmap a string - const std::string &localUnmap(const TStringId &stringId) { return (stringId==0)?*_EmptyId:*((std::string*)stringId); } + const std::string &localUnmap(const TStringId &stringId) const { return (stringId == NULL) ? *m_EmptyId : *((const std::string *)stringId); } /// Localy helper to serial a string id - void localSerialString(NLMISC::IStream &f, TStringId &id); - - void localClear(); + void localSerialString(NLMISC::IStream &f, TStringId &id); + void localClear(); }; // linear from 0 (0 is empty string) (The TSStringId returned by CStaticStringMapper diff --git a/code/nel/include/nel/misc/types_nl.h b/code/nel/include/nel/misc/types_nl.h index d5a566d89..3797c1137 100644 --- a/code/nel/include/nel/misc/types_nl.h +++ b/code/nel/include/nel/misc/types_nl.h @@ -70,7 +70,13 @@ # endif # ifdef _MSC_VER # define NL_COMP_VC -# if _MSC_VER >= 1900 +# if _MSC_VER >= 1920 +# define NL_COMP_VC14 +# define NL_COMP_VC_VERSION 142 +# elif _MSC_VER >= 1910 +# define NL_COMP_VC14 +# define NL_COMP_VC_VERSION 141 +# elif _MSC_VER >= 1900 # define NL_COMP_VC14 # define NL_COMP_VC_VERSION 140 # elif _MSC_VER >= 1800 @@ -176,6 +182,16 @@ # define NL_NO_EXCEPTION_SPECS #endif +// https://docs.microsoft.com/en-us/cpp/overview/visual-cpp-language-conformance?view=vs-2019 +// https://gcc.gnu.org/projects/cxx-status.html +#if (defined(_MSC_VER) && (_MSC_VER >= 1910) && (!defined(_HAS_CXX17) || _HAS_CXX17)) || (defined(__GNUC__ ) && (__GNUC__ >= 8) && (__cplusplus >= 201703L)) +# define NL_CPP17 +#endif + +#if (defined(_MSC_VER) && (_MSC_VER >= 1900)) || (defined(__GNUC__ ) && (__GNUC__ >= 6) && (__cplusplus >= 201402L)) +# define NL_CPP14 +#endif + #if defined(NL_COMP_VC) && (NL_COMP_VC_VERSION >= 140) #define nlmove(v) std::move(v) #else diff --git a/code/nel/src/3d/zone_lighter.cpp b/code/nel/src/3d/zone_lighter.cpp index b17ab5f2d..570ba1075 100644 --- a/code/nel/src/3d/zone_lighter.cpp +++ b/code/nel/src/3d/zone_lighter.cpp @@ -2,7 +2,7 @@ // Copyright (C) 2010 Winch Gate Property Limited // // This source file has been modified by the following contributors: -// Copyright (C) 2013-2014 Jan BOON (Kaetemi) +// Copyright (C) 2013-2019 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 @@ -1179,36 +1179,43 @@ void CZoneLighter::light (CLandscape &landscape, CZone& output, uint zoneToLight // Set the thread state _LastPatchComputed.resize (_ProcessCount); - // Launch threads - uint process; - for (process=0; process<_ProcessCount; process++) + if (patchCount) { - // Last patch - uint lastPatch=firstPatch+patchCountByThread; - lastPatch %= patchCount; + // Launch threads + uint process; + for (process = 0; process < _ProcessCount; process++) + { + // Last patch + uint lastPatch = firstPatch + patchCountByThread; + lastPatch %= patchCount; - // Last patch computed - _LastPatchComputed[process] = firstPatch; + // Last patch computed + _LastPatchComputed[process] = firstPatch; - // Create a thread - CLightRunnable *runnable = new CLightRunnable (process, this, &description); - IThread *pThread=IThread::create (runnable); - runnable->Thread = pThread; + // Create a thread + CLightRunnable *runnable = new CLightRunnable(process, this, &description); + IThread *pThread = IThread::create(runnable); + runnable->Thread = pThread; - // New first patch - firstPatch=lastPatch; + // New first patch + firstPatch = lastPatch; - // Launch - pThread->start(); - } + // Launch + pThread->start(); + } - // Wait for others processes - while (_ProcessExited!=_ProcessCount) - { - nlSleep (1000); + // Wait for others processes + while (_ProcessExited != _ProcessCount) + { + nlSleep(1000); - // Call the progress callback - progress ("Lighting patches", (float)_NumberOfPatchComputed/(float)_PatchInfo.size()); + // Call the progress callback + progress("Lighting patches", (float)_NumberOfPatchComputed / (float)_PatchInfo.size()); + } + } + else + { + nlwarning("Empty zone"); } // Reset old thread mask @@ -1765,7 +1772,7 @@ void CZoneLighter::addTriangles (const CMeshBase &meshBase, const CMeshGeom &mes alphaTestThreshold)); } } - else + else if (iba.getFormat() == CIndexBuffer::Indices16) { const uint16* triIndex=(const uint16*)iba.getPtr (); uint numTri=primitive.getNumIndexes ()/3; @@ -1797,6 +1804,10 @@ void CZoneLighter::addTriangles (const CMeshBase &meshBase, const CMeshGeom &mes alphaTestThreshold)); } } + else + { + nlerror("Invalid index buffer format"); + } } } } @@ -1901,34 +1912,73 @@ void CZoneLighter::addTriangles (const CMeshBase &meshBase, const CMeshMRMGeom & // Dump triangles CIndexBufferRead iba; primitive.lock (iba); - const uint32* triIndex= (const uint32 *) iba.getPtr (); - uint numTri=primitive.getNumIndexes ()/3; - uint tri; - for (tri=0; tri CSheetId::_DevTypeNameToId; std::vector> CSheetId::_DevSheetIdToName; std::map CSheetId::_DevSheetNameToId; -const CSheetId CSheetId::Unknown(0); +const CSheetId CSheetId::Unknown((uint32)0); void CSheetId::cbFileChange(const std::string &filename) { @@ -74,7 +74,35 @@ CSheetId::CSheetId(uint32 sheetRef) // For now, all static CSheetId are 0 (eg: CSheetId::Unknown) if (sheetRef) { - CStaticMap::iterator it(_SheetIdToName.find(sheetRef)); + TSheetIdToNameMap::iterator it(_SheetIdToName.find(sheetRef)); + if (it != _SheetIdToName.end()) + { + _DebugSheetName = it->second.Ptr; + } + else + _DebugSheetName = NULL; + } + else + { + _DebugSheetName = NULL; + } +#endif +} + +//----------------------------------------------- +// CSheetId +// +//----------------------------------------------- +CSheetId::CSheetId(int sheetRef) +{ + _Id.Id = (uint32)sheetRef; + +#ifdef NL_DEBUG_SHEET_ID + // Yoyo: don't access the static map, because of order of static ctor call. + // For now, all static CSheetId are 0 (eg: CSheetId::Unknown) + if (sheetRef) + { + TSheetIdToNameMap::iterator it(_SheetIdToName.find(sheetRef)); if (it != _SheetIdToName.end()) { _DebugSheetName = it->second.Ptr; @@ -95,7 +123,7 @@ CSheetId::CSheetId(uint32 sheetRef) //----------------------------------------------- CSheetId::CSheetId(const string &sheetName) { - if (!buildSheetId(sheetName)) + if (!buildSheetId(sheetName.c_str(), sheetName.size())) { if (sheetName.empty()) nlwarning("SHEETID: Try to create an CSheetId with empty name. TODO: check why."); @@ -115,6 +143,25 @@ CSheetId::CSheetId(const string &sheetName) } // CSheetId // +//----------------------------------------------- +// CSheetId +// +//----------------------------------------------- +CSheetId::CSheetId(const char *sheetName) +{ + if (!buildSheetId(sheetName, strlen(sheetName))) + { + if (!sheetName[0]) + nlwarning("SHEETID: Try to create an CSheetId with empty name. TODO: check why."); + else + nlwarning("SHEETID: The sheet '%s' is not in sheet_id.bin, setting it to Unknown", sheetName); + *this = Unknown; + } + + // nldebug("LIST_SHEET_ID: %s (%s)", toString().c_str(), sheetName.c_str()); + +} // CSheetId // + CSheetId::CSheetId(const std::string &sheetName, const std::string &defaultType) { // Don't use this function without defaultType, use the one above. @@ -132,11 +179,47 @@ CSheetId::CSheetId(const std::string &sheetName, const std::string &defaultType) } } +static std::string s_Dot = "."; + +CSheetId::CSheetId(const std::string &sheetName, const char *defaultType) +{ + // Don't use this function without defaultType, use the one above. + nlassert(defaultType[0]); + + if (sheetName.rfind('.') == std::string::npos) + { + std::string withType = sheetName + s_Dot + defaultType; + *this = CSheetId(withType); + // nldebug("SHEETID: Constructing CSheetId from name '%s' without explicit type, defaulting as '%s' to '%s'", sheetName.c_str(), defaultType.c_str(), withType.c_str()); + } + else + { + *this = CSheetId(sheetName); + } +} + +CSheetId::CSheetId(const char *sheetName, const char *defaultType) +{ + // Don't use this function without defaultType, use the one above. + nlassert(defaultType[0]); + + if (!strchr(sheetName, '.')) + { + std::string withType = sheetName + s_Dot + defaultType; + *this = CSheetId(withType); + // nldebug("SHEETID: Constructing CSheetId from name '%s' without explicit type, defaulting as '%s' to '%s'", sheetName.c_str(), defaultType.c_str(), withType.c_str()); + } + else + { + *this = CSheetId(sheetName); + } +} + //----------------------------------------------- // Build // //----------------------------------------------- -bool CSheetId::buildSheetId(const std::string &sheetName) +bool CSheetId::buildSheetId(const char *sheetName, size_t sheetNameLen) { nlassert(_Initialised); @@ -184,14 +267,23 @@ bool CSheetId::buildSheetId(const std::string &sheetName) } // try looking up the sheet name in _SheetNameToId - CStaticMap::const_iterator itId; + TSheetNameToIdMap::const_iterator itId; CChar c; +#ifdef alloca +#pragma warning(push) +#pragma warning(disable : 6255) + c.Ptr = (char *)alloca(sheetNameLen + 1); +#pragma warning(pop) +#else c.Ptr = new char[sheetName.size() + 1]; - strcpy(c.Ptr, sheetName.c_str()); +#endif + strcpy(c.Ptr, sheetName); toLower(c.Ptr); itId = _SheetNameToId.find(c); - delete[] c.Ptr; +#ifndef alloca + delete[] c.Ptr; // Don't delete alloca +#endif if (itId != _SheetNameToId.end()) { _Id.Id = itId->second; @@ -203,11 +295,10 @@ bool CSheetId::buildSheetId(const std::string &sheetName) } // we failed to find the sheet name in the sheetname map so see if the string is numeric - if (sheetName.size() > 1 && sheetName[0] == '#') + if (sheetName[0] == '#' && sheetName[1]) { uint32 numericId; - NLMISC::fromString((const char *)(sheetName.c_str() + 1), numericId); - if (NLMISC::toString("#%u", numericId) == sheetName) + if (NLMISC::fromString((const char *)(sheetName + 1), numericId)) { _Id.Id = numericId; return true; @@ -316,7 +407,7 @@ void CSheetId::loadSheetId() { uint32 nSize = (uint32)_SheetIdToName.size(); _SheetNameToId.reserve(nSize); - CStaticMap::iterator itStr; + TSheetIdToNameMap::iterator itStr; for (itStr = _SheetIdToName.begin(); itStr != _SheetIdToName.end(); ++itStr) { // add entry to the inverse map @@ -428,7 +519,7 @@ CSheetId &CSheetId::operator=(const CSheetId &sheetId) CSheetId &CSheetId::operator=(const string &sheetName) { - if (!buildSheetId(sheetName)) + if (!buildSheetId(sheetName.c_str(), sheetName.size())) *this = Unknown; // nldebug("LIST_SHEET_ID: %s (%s)", toString().c_str(), sheetName.c_str()); @@ -437,6 +528,22 @@ CSheetId &CSheetId::operator=(const string &sheetName) } // operator= // +//----------------------------------------------- +// operator= +// +//----------------------------------------------- +CSheetId &CSheetId::operator=(const char *sheetName) +{ + + if (!buildSheetId(sheetName, strlen(sheetName))) + *this = Unknown; + + // nldebug("LIST_SHEET_ID: %s (%s)", toString().c_str(), sheetName); + + return *this; + +} // operator= // + //----------------------------------------------- // operator= // @@ -452,6 +559,21 @@ CSheetId &CSheetId::operator=(uint32 sheetRef) } // operator= // +//----------------------------------------------- +// operator= +// +//----------------------------------------------- +CSheetId &CSheetId::operator=(int sheetRef) +{ + if (!_Initialised) + init(false); + + _Id.Id = (uint32)sheetRef; + + return *this; + +} // operator= // + //----------------------------------------------- // operator< // @@ -499,7 +621,7 @@ string CSheetId::toString(bool ifNotFoundUseNumericId) const } } - CStaticMap::const_iterator itStr = _SheetIdToName.find(_Id.Id); + TSheetIdToNameMap::const_iterator itStr = _SheetIdToName.find(_Id.Id); if (itStr != _SheetIdToName.end()) { return string((*itStr).second.Ptr); @@ -528,7 +650,7 @@ void CSheetId::serial(NLMISC::IStream &f) f.serial(_Id.Id); #ifdef NL_DEBUG_SHEET_ID - CStaticMap::iterator it(_SheetIdToName.find(_Id.Id)); + TSheetIdToNameMap::iterator it(_SheetIdToName.find(_Id.Id)); if (it != _SheetIdToName.end()) _DebugSheetName = it->second.Ptr; else @@ -564,7 +686,7 @@ void CSheetId::display() if (!_Initialised) init(false); - CStaticMap::const_iterator itStr; + TSheetIdToNameMap::const_iterator itStr; for (itStr = _SheetIdToName.begin(); itStr != _SheetIdToName.end(); ++itStr) { //nlinfo("%d %s",(*itStr).first,(*itStr).second.c_str()); @@ -582,7 +704,7 @@ void CSheetId::display(uint32 type) if (!_Initialised) init(false); - CStaticMap::const_iterator itStr; + TSheetIdToNameMap::const_iterator itStr; for (itStr = _SheetIdToName.begin(); itStr != _SheetIdToName.end(); ++itStr) { // work out the type value for this entry in the map @@ -608,7 +730,7 @@ void CSheetId::buildIdVector(std::vector &result) if (!_Initialised) init(false); - CStaticMap::const_iterator itStr; + TSheetIdToNameMap::const_iterator itStr; for (itStr = _SheetIdToName.begin(); itStr != _SheetIdToName.end(); ++itStr) { result.push_back((CSheetId)(*itStr).first); @@ -626,7 +748,7 @@ void CSheetId::buildIdVector(std::vector &result, uint32 type) init(false); nlassert(type < (1 << (NL_SHEET_ID_TYPE_BITS))); - CStaticMap::const_iterator itStr; + TSheetIdToNameMap::const_iterator itStr; for (itStr = _SheetIdToName.begin(); itStr != _SheetIdToName.end(); ++itStr) { // work out the type value for this entry in the map @@ -652,7 +774,7 @@ void CSheetId::buildIdVector(std::vector &result, std::vector::const_iterator itStr; + TSheetIdToNameMap::const_iterator itStr; for (itStr = _SheetIdToName.begin(); itStr != _SheetIdToName.end(); ++itStr) { // work out the type value for this entry in the map @@ -737,7 +859,7 @@ void CSheetId::buildSheetId(uint32 shortId, uint32 type) _Id.IdInfos.Type = type; #ifdef NL_DEBUG_SHEET_ID - CStaticMap::iterator it(_SheetIdToName.find(_Id.Id)); + TSheetIdToNameMap::iterator it(_SheetIdToName.find(_Id.Id)); if (it != _SheetIdToName.end()) { _DebugSheetName = it->second.Ptr; diff --git a/code/nel/src/misc/string_mapper.cpp b/code/nel/src/misc/string_mapper.cpp index 39931efd2..8518afa4b 100644 --- a/code/nel/src/misc/string_mapper.cpp +++ b/code/nel/src/misc/string_mapper.cpp @@ -27,13 +27,12 @@ using namespace std; namespace NLMISC { -CStringMapper CStringMapper::_GlobalMapper; - +CStringMapper CStringMapper::s_GlobalMapper; // **************************************************************************** CStringMapper::CStringMapper() { - _EmptyId = new string(); + m_EmptyId = new string(); } // **************************************************************************** @@ -46,39 +45,54 @@ CStringMapper *CStringMapper::createLocalMapper() TStringId CStringMapper::localMap(const std::string &str) { if (str.empty()) - return 0; - - CAutoFastMutex automutex(&_Mutex); + return NULL; - string *pStr = new string; - *pStr = str; + CAutoFastMutex autoMutex(&m_Mutex); - std::set::iterator it = _StringTable.find(pStr); + TStringTable::const_iterator it = m_StringTable.find((const std::string *)&str); - if (it == _StringTable.end()) + if (it == m_StringTable.end()) { - _StringTable.insert(pStr); + string *pStr = new string(str); + m_StringTable.insert(pStr); + return pStr; } - else + return (TStringId)(*it); +} + +#ifdef NL_CPP14 +// **************************************************************************** +TStringId CStringMapper::localMap(const char *str) +{ + if (!str[0]) + return NULL; + + CAutoFastMutex autoMutex(&m_Mutex); + + TStringTable::const_iterator it = m_StringTable.find(str); + + if (it == m_StringTable.end()) { - delete pStr; - pStr = (*it); + string *pStr = new string(str); + m_StringTable.insert(pStr); + return pStr; } - return (TStringId)pStr; + return (TStringId)(*it); } +#endif // *************************************************************************** void CStringMapper::localSerialString(NLMISC::IStream &f, TStringId &id) { - std::string str; - if(f.isReading()) + std::string str; + if (f.isReading()) { f.serial(str); - id= localMap(str); + id = localMap(str); } else { - str= localUnmap(id); + str = localUnmap(id); f.serial(str); } } @@ -86,17 +100,16 @@ void CStringMapper::localSerialString(NLMISC::IStream &f, TStringId &id) // **************************************************************************** void CStringMapper::localClear() { - CAutoFastMutex automutex(&_Mutex); + CAutoFastMutex autoMutex(&m_Mutex); - std::set::iterator it = _StringTable.begin(); - while (it != _StringTable.end()) + TStringTable::iterator it = m_StringTable.begin(); + while (it != m_StringTable.end()) { - string *ptrTmp = (*it); + const std::string *ptrTmp = (*it); delete ptrTmp; it++; } - _StringTable.clear(); - delete _EmptyId; + m_StringTable.clear(); } // **************************************************************************** diff --git a/code/nel/tools/CMakeLists.txt b/code/nel/tools/CMakeLists.txt index 8734bf103..5297f34a4 100644 --- a/code/nel/tools/CMakeLists.txt +++ b/code/nel/tools/CMakeLists.txt @@ -17,6 +17,10 @@ IF(WITH_NEL_TOOLS) ADD_SUBDIRECTORY(pacs) ENDIF() + IF(WITH_LIGO) + ADD_SUBDIRECTORY(ligo) + ENDIF() + IF(WITH_LOGIC) ADD_SUBDIRECTORY(logic) ENDIF() diff --git a/code/nel/tools/ligo/CMakeLists.txt b/code/nel/tools/ligo/CMakeLists.txt new file mode 100644 index 000000000..9a7f24ebe --- /dev/null +++ b/code/nel/tools/ligo/CMakeLists.txt @@ -0,0 +1,6 @@ + +IF(WITH_LIGO) + IF(WITH_3D) + ADD_SUBDIRECTORY(unbuild_land) + ENDIF() +ENDIF() diff --git a/code/nel/tools/ligo/unbuild_land/CMakeLists.txt b/code/nel/tools/ligo/unbuild_land/CMakeLists.txt new file mode 100644 index 000000000..3e8c8fbdb --- /dev/null +++ b/code/nel/tools/ligo/unbuild_land/CMakeLists.txt @@ -0,0 +1,11 @@ +FILE(GLOB SRC *.cpp *.h *.rc) + +SOURCE_GROUP("" FILES ${SRC}) + +ADD_EXECUTABLE(unbuild_land ${SRC}) + +TARGET_LINK_LIBRARIES(unbuild_land nel3d nelmisc nelligo) +NL_DEFAULT_PROPS(unbuild_land "NeL, Tools, Ligo: Unbuild Land") +NL_ADD_RUNTIME_FLAGS(unbuild_land) + +INSTALL(TARGETS unbuild_land RUNTIME DESTINATION ${NL_BIN_PREFIX} COMPONENT toolsligo) diff --git a/code/nel/tools/ligo/unbuild_land/gold_pill.ico b/code/nel/tools/ligo/unbuild_land/gold_pill.ico new file mode 100644 index 000000000..618b67a5d Binary files /dev/null and b/code/nel/tools/ligo/unbuild_land/gold_pill.ico differ diff --git a/code/nel/tools/ligo/unbuild_land/main.rc b/code/nel/tools/ligo/unbuild_land/main.rc new file mode 100644 index 000000000..20feb7ec8 --- /dev/null +++ b/code/nel/tools/ligo/unbuild_land/main.rc @@ -0,0 +1,42 @@ +#include +#include "config.h" + +IDI_MAIN_ICON ICON DISCARDABLE "gold_pill.ico" + +#ifdef _DEBUG +#define NL_FILEEXT "_d" +#else +#define NL_FILEEXT "" +#endif + +VS_VERSION_INFO VERSIONINFO + FILEVERSION NL_VERSION_RC + PRODUCTVERSION NL_VERSION_RC + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +#ifdef _DEBUG + FILEFLAGS VS_FF_DEBUG +#else + FILEFLAGS 0x0L +#endif + FILEOS VOS_NT_WINDOWS32 + FILETYPE VFT_APP + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "CompanyName", AUTHOR + VALUE "FileDescription", "NeL Unbuild Land" + VALUE "FileVersion", NL_VERSION + VALUE "LegalCopyright", COPYRIGHT + VALUE "OriginalFilename", "unbuild_land" NL_FILEEXT ".exe" + VALUE "ProductName", "NeL Tools" + VALUE "ProductVersion", NL_PRODUCT_VERSION + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x9, 1200 + END +END diff --git a/code/nel/tools/ligo/unbuild_land/unbuild_land.cpp b/code/nel/tools/ligo/unbuild_land/unbuild_land.cpp new file mode 100644 index 000000000..37b3b4e79 --- /dev/null +++ b/code/nel/tools/ligo/unbuild_land/unbuild_land.cpp @@ -0,0 +1,500 @@ +// NeL - MMORPG Framework +// Copyright (C) 2019 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 . +// +// This utility is intended to rescue a lost .land file from existing +// runtime zones. It does not recover the heightmap. +// +// Author: Jan BOON (Kaetemi) + +// #include "../../3d/zone_lib/zone_utility.h" + +#include +#include +#include +#include +#include +#include +#include +//#include +#include +//#include +//#include +//#include +//#include +#include +#include +#include + +using namespace NL3D; +using namespace NLMISC; +using namespace NLLIGO; +using namespace std; + +namespace /* anonymous */ +{ + +sint32 s_ZoneMinX, s_ZoneMinY, s_ZoneMaxX, s_ZoneMaxY; +float s_CellSize = 160.0f; + +bool s_Height = false; + +std::string s_ZoneBricksDirIn; // UTF-8 path +std::string s_ZoneRuntimeDirIn; // UTF-8 path +std::string s_LandFileOut; // UTF-8 path + +CZoneRegion s_Land; + +bool saveLand() +{ + try + { + COFile fileOut; + if (fileOut.open(s_LandFileOut, false, true, false)) + { + COXml xml; + nlverify(xml.init(&fileOut)); + s_Land.serial(xml); + } + else + { + nlwarning("Can't open the land file for writing: %s", s_LandFileOut.c_str()); + return false; + } + } + catch (const Exception &e) + { + nlwarning("Error in writing land file: %s", e.what()); + return true; + } + return true; +} + +bool getXYFromZoneName(sint32 &x, sint32 &y, const string &zoneName) +{ + string xStr, yStr; + uint32 i = 0; + while (zoneName[i] != '_') + { + yStr += zoneName[i]; + ++i; + if (i == zoneName.size()) + goto Fail; + } + if (!NLMISC::fromString(yStr, y)) + goto Fail; + y = -y; + ++i; + while (i < zoneName.size()) + { + xStr += zoneName[i]; + ++i; + } + if (xStr.size() != 2) + goto Fail; + xStr = NLMISC::toUpper(xStr); + x = ((xStr[0] - 'A') * 26 + (xStr[1] - 'A')); + return true; +Fail: + x = -1; + y = -1; + return false; +} + +void centerVertices(std::vector &vertices) +{ + CVector avg = CVector(0.0f, 0.0f, 0.0f); + for (ptrdiff_t i = 0; i < vertices.size(); ++i) + avg += vertices[i]; + avg /= (float)vertices.size(); + nldebug("Average: %f, %f", avg.x, avg.y); + for (ptrdiff_t i = 0; i < vertices.size(); ++i) + vertices[i] -= avg; +} + +void offsetVertices(std::vector &vertices, int x, int y) +{ + CVector off = CVector((float)x * s_CellSize, (float)y * s_CellSize, 0.0f); + for (ptrdiff_t i = 0; i < vertices.size(); ++i) + vertices[i] -= off; +} + +float ratePoints(const std::vector &zone, const std::vector &ref, float xx, float xy, float yx, float yy) +{ + // Rudimentary distance rating of vertices (not very reliable, but good enough!) + + float md = 0.f; + // std::vector refcpy = ref; + std::vector usedref; + usedref.resize(ref.size(), false); + for (ptrdiff_t i = 0; i < zone.size(); ++i) + { + if (ref.size()) + { + int lowj = 0; + float lowv = (CVector(ref[0].x * xx + ref[0].y * xy, ref[0].x * yx + ref[0].y * yy, ref[0].z) - zone[i]).sqrnorm(); + for (ptrdiff_t j = 1; j < ref.size(); ++j) + { + float v = (CVector(ref[j].x * xx + ref[j].y * xy, ref[j].x * yx + ref[j].y * yy, ref[j].z) - zone[i]).sqrnorm(); + if (v < lowv) + { + lowj = j; + lowv = v; + } + } + md += sqrtf(lowv); + usedref[lowj] = true; + // keep it! - refcpy.erase(refcpy.begin() + lowj); + } + else + { + md += zone[i].norm(); + } + } +#if 0 + md = 0.f; + std::vector usedzone; + usedzone.resize(zone.size(), false); + for (ptrdiff_t j = 0; j < ref.size(); ++j) + { + if (usedref[j]) + { + if (zone.size()) + { + int lowi = 0; + float lowv = (CVector2f(ref[j].x * xx + ref[j].y * xy, ref[j].x * yx + ref[j].y * yy) - zone[0]).sqrnorm(); + for (ptrdiff_t i = 1; i < zone.size(); ++i) + { + float v = (CVector2f(ref[j].x * xx + ref[j].y * xy, ref[j].x * yx + ref[j].y * yy) - zone[i]).sqrnorm(); + if (v < lowv) + { + lowi = i; + lowv = v; + } + } + md += lowv; + usedzone[lowi] = true; + } + else + { + md += ref[j].norm(); + } + } + } + md = 0.f; + int nc = 0; + for (ptrdiff_t i = 0; i < zone.size(); ++i) + { + if (usedzone[i]) + { + if (ref.size()) + { + int lowj = 0; + float lowv = (CVector2f(ref[0].x * xx + ref[0].y * xy, ref[0].x * yx + ref[0].y * yy) - zone[i]).sqrnorm(); + for (ptrdiff_t j = 1; j < ref.size(); ++j) + { + float v = (CVector2f(ref[j].x * xx + ref[j].y * xy, ref[j].x * yx + ref[j].y * yy) - zone[i]).sqrnorm(); + if (v < lowv) + { + lowj = j; + lowv = v; + } + } + md += sqrtf(lowv); + usedref[lowj] = true; + // keep it! - refcpy.erase(refcpy.begin() + lowj); + } + else + { + md += zone[i].norm(); + } + } + else + { + ++nc; + // md += 1.0f; + // md += 0.01; + } + } + for (ptrdiff_t j = 0; j < ref.size(); ++j) + { + if (!usedref[j]) + { + // md += 1.0f; + // md += 0.01; + } + } + if (nc * 8 > zone.size()) + return md + 10000; +#endif + return md; +} + +void findBestBrick(std::string &brick, int &rotate, int &flip, float &es, std::vector &zoneVertices, const std::map> &brickVertices) +{ + float bestPoints = (float)(uint32)~0; + for (std::map>::const_iterator it = brickVertices.begin(), end = brickVertices.end(); it != end; ++it) + { + float rating; + rating = ratePoints(zoneVertices, it->second, 1.0, 0.0, 0.0, 1.0); + if (rating < bestPoints) + { + brick = it->first; + rotate = 0; + flip = 0; + bestPoints = rating; + } + rating = ratePoints(zoneVertices, it->second, 0.0, -1.0, 1.0, 0.0); + if (rating < bestPoints) + { + brick = it->first; + rotate = 1; + flip = 0; + bestPoints = rating; + } + rating = ratePoints(zoneVertices, it->second, -1.0, 0.0, 0.0, -1.0); + if (rating < bestPoints) + { + brick = it->first; + rotate = 2; + flip = 0; + bestPoints = rating; + } + rating = ratePoints(zoneVertices, it->second, 0.0, 1.0, -1.0, 0.0); + if (rating < bestPoints) + { + brick = it->first; + rotate = 3; + flip = 0; + } + rating = ratePoints(zoneVertices, it->second, -1.0, 0.0, 0.0, 1.0); + if (rating < bestPoints) + { + brick = it->first; + rotate = 0; + flip = 1; + bestPoints = rating; + } + rating = ratePoints(zoneVertices, it->second, 0.0, -1.0, -1.0, 0.0); + if (rating < bestPoints) + { + brick = it->first; + rotate = 1; + flip = 1; + bestPoints = rating; + } + rating = ratePoints(zoneVertices, it->second, 1.0, 0.0, 0.0, -1.0); + if (rating < bestPoints) + { + brick = it->first; + rotate = 2; + flip = 1; + bestPoints = rating; + } + rating = ratePoints(zoneVertices, it->second, 0.0, 1.0, 1.0, 0.0); + if (rating < bestPoints) + { + brick = it->first; + rotate = 3; + flip = 1; + bestPoints = rating; + } + } + es = bestPoints; +} + +bool unbuildLand() +{ + s_Land.resize(s_ZoneMinX, s_ZoneMaxX, s_ZoneMinY, s_ZoneMaxY); + + // float th = s_CellSize * 0.5f; + float th = (s_CellSize * 0.5f) - (s_CellSize * 0.2f * 0.5f); + + // Read in all the bricks + std::vector brickFiles; + CPath::getPathContent(s_ZoneBricksDirIn, false, false, true, brickFiles); + std::map> brickVertices; + for (std::vector::const_iterator it = brickFiles.begin(), end = brickFiles.end(); it != end; ++it) + { + if (CFile::getExtension(*it) != "zone") + continue; + + if (NLMISC::startsWith(CFile::getFilename(*it), "converted-")) // Not a real ligo + continue; + + // if (NLMISC::startsWith(CFile::getFilename(*it), "foret-moor")) // Not useful for r2_forest + // continue; + // if (NLMISC::startsWith(CFile::getFilename(*it), "goo-")) // Not useful for r2_forest + // continue; + // if (NLMISC::endsWith(CFile::getFilenameWithoutExtension(*it), "_zc")) // Not useful for r2_forest + // continue; + + nldebug("Load %s", CFile::getFilenameWithoutExtension(*it).c_str()); + + CIFile zoneFile(*it); + CZone zone; + zone.serial(zoneFile); + zoneFile.close(); + + // Retrieve patches and vertices + uint16 zoneId = zone.getZoneId(); + std::vector zonePatches; + std::vector zoneBorderVertices; + zone.retrieve(zonePatches, zoneBorderVertices); + + brickVertices[CFile::getFilenameWithoutExtension(*it)] = std::vector(); + std::vector &vec = brickVertices[CFile::getFilenameWithoutExtension(*it)]; + CVector off = CVector(s_CellSize * 0.5f, s_CellSize * 0.5f, 0.0f); + for (ptrdiff_t i = 0; i < zonePatches.size(); ++i) + { + for (ptrdiff_t j = 0; j < 4; ++j) + { + float rx = zonePatches[i].Patch.Vertices[j].x - off.x; + float ry = zonePatches[i].Patch.Vertices[j].y - off.y; + if (rx <= -th || rx >= th + || ry <= -th || ry >= th) + goto SkipA; + } + for (ptrdiff_t j = 0; j < 4; ++j) + { + float rx = zonePatches[i].Patch.Vertices[j].x - off.x; + float ry = zonePatches[i].Patch.Vertices[j].y - off.y; + vec.push_back(CVector(rx, ry, s_Height ? zonePatches[i].Patch.Vertices[j].z : 0.0f)); + } + SkipA:; + } + + // centerVertices(vec); + } + + std::vector runtimeFiles; + CPath::getPathContent(s_ZoneRuntimeDirIn, false, false, true, runtimeFiles); + for (std::vector::const_iterator it = runtimeFiles.begin(), end = runtimeFiles.end(); it != end; ++it) + { + if (CFile::getExtension(*it) != "zonel") + continue; + + int x, y; + std::string zoneName = CFile::getFilenameWithoutExtension(*it); + if (!getXYFromZoneName(x, y, zoneName)) + { + nlerrornoex("Bad zone name: %s", zoneName.c_str()); + continue; + } + + CIFile zoneFile(*it); + CZone zone; + zone.serial(zoneFile); + zoneFile.close(); + + // Retrieve patches and vertices + uint16 zoneId = zone.getZoneId(); + std::vector zonePatches; + std::vector zoneBorderVertices; + zone.retrieve(zonePatches, zoneBorderVertices); + + std::vector vec; + CVector off = CVector((float)x * s_CellSize, (float)y * s_CellSize, 0.0f) + CVector(s_CellSize * 0.5f, s_CellSize * 0.5f, 0.0f); + for (ptrdiff_t i = 0; i < zonePatches.size(); ++i) + { + for (ptrdiff_t j = 0; j < 4; ++j) + { + float rx = zonePatches[i].Patch.Vertices[j].x - off.x; + float ry = zonePatches[i].Patch.Vertices[j].y - off.y; + if (rx <= -th || rx >= th + || ry <= -th || ry >= th) + goto SkipB; + } + for (ptrdiff_t j = 0; j < 4; ++j) + { + float rx = zonePatches[i].Patch.Vertices[j].x - off.x; + float ry = zonePatches[i].Patch.Vertices[j].y - off.y; + vec.push_back(CVector(rx, ry, s_Height ? zonePatches[i].Patch.Vertices[j].z : 0.0f)); + } + SkipB:; + } + + // offsetVertices(vec, x, y); + // centerVertices(vec); + + std::string brick; + int rotate; + int flip; + float es; + findBestBrick(brick, rotate, flip, es, vec, brickVertices); + + nlinfo("Zone: %s, brick: %s, rotate: %i; flip: %i, error score: %f", zoneName.c_str(), brick.c_str(), rotate, flip, es); + + s_Land.setName(x, y, brick); + s_Land.setRot(x, y, rotate); + s_Land.setFlip(x, y, flip); + } + + return saveLand(); +} + +} /* anonymous namespace */ + +int main(int argc, char **argv) +{ + NLMISC::CApplicationContext myApplicationContext; + + NLMISC::CCmdArgs args; + + args.addAdditionalArg("land", "Output ligo land file"); + args.addAdditionalArg("zonebricks", "Input zone bricks directory"); + args.addAdditionalArg("zoneruntime", "Input runtime zone directory"); + args.addAdditionalArg("zonemin", "Zone boundary"); + args.addAdditionalArg("zonemax", "Zone boundary"); + args.addArg("", "cellsize", "meters", "Zone cell size"); + args.addArg("", "height", "", "Take Z coordinate into account"); + + if (!args.parse(argc, argv)) + { + return EXIT_FAILURE; + } + + s_LandFileOut = args.getAdditionalArg("land")[0]; + s_ZoneBricksDirIn = args.getAdditionalArg("zonebricks")[0]; + s_ZoneRuntimeDirIn = args.getAdditionalArg("zoneruntime")[0]; + + sint32 zoneMinX, zoneMinY; + sint32 zoneMaxX, zoneMaxY; + if (!getXYFromZoneName(zoneMinX, zoneMinY, args.getAdditionalArg("zonemin")[0]) + || !getXYFromZoneName(zoneMaxX, zoneMaxY, args.getAdditionalArg("zonemax")[0])) + { + goto Fail; + } + s_ZoneMinX = min(zoneMinX, zoneMaxX); + s_ZoneMaxX = max(zoneMinX, zoneMaxX); + s_ZoneMinY = min(zoneMinY, zoneMaxY); + s_ZoneMaxY = max(zoneMinY, zoneMaxY); + + s_Height = args.haveLongArg("height"); + + if (args.haveLongArg("cellsize")) + { + if (!NLMISC::fromString(args.getLongArg("cellsize")[0], s_CellSize)) + goto Fail; + } + + if (!unbuildLand()) + return EXIT_FAILURE; + + return EXIT_SUCCESS; +Fail: + args.displayHelp(); + return EXIT_FAILURE; +} diff --git a/code/ryzom/client/src/login.cpp b/code/ryzom/client/src/login.cpp index ae678ead3..c9c1fdeaf 100644 --- a/code/ryzom/client/src/login.cpp +++ b/code/ryzom/client/src/login.cpp @@ -867,7 +867,7 @@ void initAutoLogin() void initAltLogin() { // Check the alt param - if (!LoginCustomParameters.empty()) + if (!LoginCustomParameters.empty() && LoginCustomParameters != "&dbg=1") { // don't use login and password for alternate login string res = checkLogin("", "", ClientApp, LoginCustomParameters); diff --git a/code/ryzom/tools/leveldesign/mp_generator/main.cpp b/code/ryzom/tools/leveldesign/mp_generator/main.cpp index 267f6a4ab..150807f5c 100644 --- a/code/ryzom/tools/leveldesign/mp_generator/main.cpp +++ b/code/ryzom/tools/leveldesign/mp_generator/main.cpp @@ -307,6 +307,11 @@ bool endsWith( const CSString& s, const CSString& substring ) return (s.right( (uint)substring.size() ) == substring); } +bool endsWith( const CSString& s, const char *substring ) +{ + return endsWith(s, CSString(substring)); +} + // Generate item names void GenerateItemNames( const CSString& nomMP, char eco, int level, bool mission, bool creature, CSString& outStr )