diff --git a/code/nel/include/nel/misc/cdb.h b/code/nel/include/nel/misc/cdb.h index dc95e51e9..d23986b0c 100644 --- a/code/nel/include/nel/misc/cdb.h +++ b/code/nel/include/nel/misc/cdb.h @@ -33,6 +33,7 @@ class IProgressCallback; class CBitMemStream; class CCDBNodeLeaf; class CCDBNodeBranch; +class CCDBBankHandler; ///global bool, must be set to true if we want to display database modification. See displayDBModifs in commands.cpp extern bool VerboseDatabase; @@ -197,7 +198,7 @@ public : * Build the structure of the database from a file * \param f is the stream */ - virtual void init( xmlNodePtr node, IProgressCallback &progressCallBack, bool mapBanks=false ) = 0; + virtual void init( xmlNodePtr node, IProgressCallback &progressCallBack, bool mapBanks=false, CCDBBankHandler *bankHandler = NULL ) = 0; /** * Save a backup of the database diff --git a/code/nel/include/nel/misc/cdb_bank_handler.h b/code/nel/include/nel/misc/cdb_bank_handler.h new file mode 100644 index 000000000..560a81b46 --- /dev/null +++ b/code/nel/include/nel/misc/cdb_bank_handler.h @@ -0,0 +1,79 @@ +// Ryzom - MMORPG Framework +// Copyright (C) 2010 Winch Gate Property Limited +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +#ifndef CDB_BANK_HANDLER +#define CDB_BANK_HANDLER + +#include +#include "nel/misc/types_nl.h" + +namespace NLMISC{ + +class CCDBBankHandler{ +public: + CCDBBankHandler( uint maxbanks ); + + ~CCDBBankHandler(){} + + uint getUIDForBank( uint bank ) const; + + uint getBankForUID( uint uid ) const{ return _UnifiedIndexToBank[ uid ]; } + + uint getLastUnifiedIndex() const{ return _CDBLastUnifiedIndex; } + + uint getFirstLevelIdBits( uint bank ) const{ return _FirstLevelIdBitsByBank[ bank ]; } + + std::string getBankName( uint bank ) const{ return _CDBBankNames[ bank ]; } + + uint getBankByName( const std::string &name ) const; + + void mapNodeByBank( const std::string &bankName ); + + void fillBankNames( const char **strings, uint size ); + + void resetNodeBankMapping(){ _UnifiedIndexToBank.clear(); } + + void reset(); + + uint getUnifiedIndexToBankSize() const{ return _UnifiedIndexToBank.size(); } + + void calcIdBitsByBank(); + + uint getServerToClientUIDMapping( uint bank, uint index ) const{ return _CDBBankToUnifiedIndexMapping[ bank ][ index ]; } + +private: + /// Mapping from server database index to client database index (first-level nodes) + std::vector< std::vector< uint > > _CDBBankToUnifiedIndexMapping; + + /// Mapping from client database index to bank IDs (first-level nodes) + std::vector< uint > _UnifiedIndexToBank; + + /// Last index mapped + uint _CDBLastUnifiedIndex; + + /// Number of bits for first-level branches, by bank + std::vector< uint > _FirstLevelIdBitsByBank; + + /// Names of the CDB banks + std::vector< std::string > _CDBBankNames; + + uint maxBanks; +}; + +} + +#endif + diff --git a/code/nel/include/nel/misc/cdb_branch.h b/code/nel/include/nel/misc/cdb_branch.h index 7d7187aa1..632d6e9a3 100644 --- a/code/nel/include/nel/misc/cdb_branch.h +++ b/code/nel/include/nel/misc/cdb_branch.h @@ -23,11 +23,6 @@ namespace NLMISC{ -enum{ - CDB_BANKS_MAX = 3, - CDB_BANK_INVALID -}; - /** * Database Node which contains a set of properties * \author Stephane Coutelas @@ -56,7 +51,7 @@ public: * Build the structure of the database from a file * \param f is the stream */ - void init( xmlNodePtr node, class IProgressCallback &progressCallBack, bool mapBanks=false ); + void init( xmlNodePtr node, class IProgressCallback &progressCallBack, bool mapBanks=false, CCDBBankHandler *bankHandler = NULL ); /** * Add a new sub node @@ -105,7 +100,7 @@ public: void write( CTextId& id, FILE * f); /// Update the database from the delta, but map the first level with the bank mapping (see _CDBBankToUnifiedIndexMapping) - void readAndMapDelta( TGameCycle gc, CBitMemStream& s, uint bank ); + void readAndMapDelta( TGameCycle gc, CBitMemStream& s, uint bank, CCDBBankHandler *bankHandler ); /// Update the database from a stream coming from the FE void readDelta( TGameCycle gc, CBitMemStream & f ); @@ -130,15 +125,12 @@ public: /// Clear the node and his children void clear(); - /// Reset the data corresponding to the bank (works only on top level node) - void resetBank( TGameCycle gc, uint bank) + void resetNode( TGameCycle gc, uint node ) { - //nlassert( getParent() == NULL ); - for ( uint i=0; i!=_Nodes.size(); ++i ) - { - if ( _UnifiedIndexToBank[i] == bank ) - _Nodes[i]->resetData(gc); - } + if( node > _Nodes.size() ) + return; + + _Nodes[ node ]->resetData( gc ); } /// Reset all leaf data from this point @@ -237,15 +229,9 @@ public: /// Find a subnode at this level ICDBNode * find (const std::string &nodeName); - /// Main init - static void resetNodeBankMapping() { _UnifiedIndexToBank.clear(); } - // reset all static mappings static void reset(); - /// Internal use only - static void mapNodeByBank( ICDBNode *node, const std::string& bankStr, bool clientOnly, uint nodeIndex ); - protected: @@ -328,18 +314,6 @@ protected: static CDBBranchObsInfo *_CurrNotifiedObs; static CDBBranchObsInfo *_NextNotifiedObs; - /// Mapping from server database index to client database index (first-level nodes) - static std::vector _CDBBankToUnifiedIndexMapping [CDB_BANKS_MAX]; - - // Mapping from client database index to TCDBBank (first-level nodes) - static std::vector _UnifiedIndexToBank; - - /// Last index mapped - static uint _CDBLastUnifiedIndex; - - /// Number of bits for first-level branches, by bank - static uint _FirstLevelIdBitsByBank [CDB_BANKS_MAX]; - /// called by clear void removeAllBranchObserver(); void removeBranchInfoIt(TObsList::iterator it); diff --git a/code/nel/include/nel/misc/cdb_leaf.h b/code/nel/include/nel/misc/cdb_leaf.h index fed2b908d..566394d97 100644 --- a/code/nel/include/nel/misc/cdb_leaf.h +++ b/code/nel/include/nel/misc/cdb_leaf.h @@ -101,7 +101,7 @@ public: * Build the structure of the database from a file * \param f is the stream */ - void init( xmlNodePtr node, IProgressCallback &progressCallBack, bool mapBanks=false ); + void init( xmlNodePtr node, IProgressCallback &progressCallBack, bool mapBanks=false, CCDBBankHandler *bankHandler = NULL ); /** * Get a node diff --git a/code/nel/src/misc/cdb_bank_handler.cpp b/code/nel/src/misc/cdb_bank_handler.cpp new file mode 100644 index 000000000..f090ece4c --- /dev/null +++ b/code/nel/src/misc/cdb_bank_handler.cpp @@ -0,0 +1,96 @@ +// Ryzom - MMORPG Framework +// Copyright (C) 2010 Winch Gate Property Limited +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +#include "nel/misc/cdb_bank_handler.h" + +namespace NLMISC{ + CCDBBankHandler::CCDBBankHandler(uint maxbanks) : +_CDBBankToUnifiedIndexMapping( maxbanks, std::vector< uint >() ), +_FirstLevelIdBitsByBank( maxbanks ) + { + std::fill( _FirstLevelIdBitsByBank.begin(), _FirstLevelIdBitsByBank.end(), 0 ); + maxBanks = maxbanks; + } + + uint CCDBBankHandler::getUIDForBank( uint bank ) const + { + uint uid = static_cast< uint >( -1 ); + + for( uint i = 0; i < _UnifiedIndexToBank.size(); i++ ) + if( _UnifiedIndexToBank[ i ] == bank ) + return i; + + return uid; + } + + uint CCDBBankHandler::getBankByName( const std::string &name ) const + { + uint b = static_cast< uint >( -1 ); + + for( uint i = 0; i < _CDBBankNames.size(); i++ ) + if( _CDBBankNames[ i ].compare( name ) == 0 ) + return i; + + return b; + } + + void CCDBBankHandler::mapNodeByBank( const std::string &bankName ) + { + uint b = getBankByName( bankName ); + // no such bank + if( b == static_cast< uint >( -1 ) ) + return; + + _CDBBankToUnifiedIndexMapping[ b ].push_back( _CDBLastUnifiedIndex ); + ++_CDBLastUnifiedIndex; + _UnifiedIndexToBank.push_back( b ); + } + + void CCDBBankHandler::fillBankNames( const char **strings, uint size ) + { + _CDBBankNames.clear(); + + for( uint i = 0; i < size; i++ ) + _CDBBankNames.push_back( std::string( strings[ i ] ) ); + } + + void CCDBBankHandler::reset() + { + for( std::vector< std::vector< uint > >::iterator itr =_CDBBankToUnifiedIndexMapping.begin(); + itr != _CDBBankToUnifiedIndexMapping.end(); ++itr ) + itr->clear(); + + _UnifiedIndexToBank.clear(); + _CDBLastUnifiedIndex = 0; + } + + void CCDBBankHandler::calcIdBitsByBank() + { + for( uint bank = 0; bank != maxBanks; bank++ ) + { + uint nbNodesOfBank = static_cast< uint >( _CDBBankToUnifiedIndexMapping[ bank ].size() ); + uint idb = 0; + + if ( nbNodesOfBank > 0 ) + for ( idb = 1; nbNodesOfBank > unsigned( 1 << idb ) ; idb++ ) + ; + + _FirstLevelIdBitsByBank[ bank ] = idb; + } + } +} + + diff --git a/code/nel/src/misc/cdb_branch.cpp b/code/nel/src/misc/cdb_branch.cpp index 45bef670a..738c66b2f 100644 --- a/code/nel/src/misc/cdb_branch.cpp +++ b/code/nel/src/misc/cdb_branch.cpp @@ -44,6 +44,7 @@ using namespace std; #include "nel/misc/progress_callback.h" #include "nel/misc/bit_mem_stream.h" #include "nel/misc/bit_set.h" +#include "nel/misc/cdb_bank_handler.h" #include //#include @@ -70,30 +71,11 @@ CCDBNodeBranch::CDBBranchObsInfo *CCDBNodeBranch::_NextNotifiedObs = NULL; // uint CCDBNodeBranch::_CurrNotifiedObsList = 0; -// Mapping from server database index to client database index (first-level nodes) -vector CCDBNodeBranch::_CDBBankToUnifiedIndexMapping [CDB_BANKS_MAX]; - -// Mapping from client database index to TCDBBank (first-level nodes) -vector CCDBNodeBranch::_UnifiedIndexToBank; - -// Last index mapped -uint CCDBNodeBranch::_CDBLastUnifiedIndex = 0; - -// Number of bits for first-level branches, by bank -uint CCDBNodeBranch::_FirstLevelIdBitsByBank [CDB_BANKS_MAX]; - -extern const char *CDBBankNames[CDB_BANK_INVALID+1]; - std::vector< CCDBNodeBranch::IBranchObserverCallFlushObserver* > CCDBNodeBranch::flushObservers; // reset all static data void CCDBNodeBranch::reset() { - for ( uint b=0; bmapNodeByBank( bankName ); //nldebug( "CDB: Mapping %s for %s (node %u)", newName.c_str(), bankName.c_str(), nodes.size()-1 ); } else @@ -161,7 +118,7 @@ static /*inline*/ void addNode( ICDBNode *newNode, std::string newName, CCDBNode } } -void CCDBNodeBranch::init( xmlNodePtr node, IProgressCallback &progressCallBack, bool mapBanks ) +void CCDBNodeBranch::init( xmlNodePtr node, IProgressCallback &progressCallBack, bool mapBanks, CCDBBankHandler *bankHandler ) { xmlNodePtr child; @@ -200,7 +157,7 @@ void CCDBNodeBranch::init( xmlNodePtr node, IProgressCallback &progressCallBack, // nlinfo("+ %s%d",name,i); string newName = string(name.getDatas())+toString(i); - addNode( new CCDBNodeBranch(newName), newName, this, _Nodes, _NodesByName, child, sBank, sAtom=="1", sClientonly=="1", progressCallBack, mapBanks ); + addNode( new CCDBNodeBranch(newName), newName, this, _Nodes, _NodesByName, child, sBank, sAtom=="1", sClientonly=="1", progressCallBack, mapBanks, bankHandler ); // nlinfo("-"); // Progress bar @@ -212,7 +169,7 @@ void CCDBNodeBranch::init( xmlNodePtr node, IProgressCallback &progressCallBack, // dealing with a single entry // nlinfo("+ %s",name); string newName = string(name.getDatas()); - addNode( new CCDBNodeBranch(newName), newName, this, _Nodes, _NodesByName, child, sBank, sAtom=="1", sClientonly=="1", progressCallBack, mapBanks ); + addNode( new CCDBNodeBranch(newName), newName, this, _Nodes, _NodesByName, child, sBank, sAtom=="1", sClientonly=="1", progressCallBack, mapBanks, bankHandler ); // nlinfo("-"); } @@ -249,7 +206,7 @@ void CCDBNodeBranch::init( xmlNodePtr node, IProgressCallback &progressCallBack, // nlinfo(" %s%d",name,i); string newName = string(name.getDatas())+toString(i); - addNode( new CCDBNodeLeaf(newName), newName, this, _Nodes, _NodesByName, child, sBank, false, false, progressCallBack, mapBanks ); + addNode( new CCDBNodeLeaf(newName), newName, this, _Nodes, _NodesByName, child, sBank, false, false, progressCallBack, mapBanks, bankHandler ); // Progress bar progressCallBack.popCropedValues (); @@ -259,7 +216,7 @@ void CCDBNodeBranch::init( xmlNodePtr node, IProgressCallback &progressCallBack, { // nlinfo(" %s",name); string newName = string(name.getDatas()); - addNode( new CCDBNodeLeaf(newName), newName, this, _Nodes, _NodesByName, child, sBank, false, false, progressCallBack, mapBanks ); + addNode( new CCDBNodeLeaf(newName), newName, this, _Nodes, _NodesByName, child, sBank, false, false, progressCallBack, mapBanks, bankHandler ); } // Progress bar @@ -269,18 +226,11 @@ void CCDBNodeBranch::init( xmlNodePtr node, IProgressCallback &progressCallBack, // count number of bits required to store the id if ( (mapBanks) && (getParent() == NULL) ) - { - nlassertex( _UnifiedIndexToBank.size() == countNode, ("Mapped: %u Nodes: %u", _UnifiedIndexToBank.size(), countNode) ); - + { + nlassert( bankHandler != NULL ); + nlassertex( bankHandler->getUnifiedIndexToBankSize() == countNode, ("Mapped: %u Nodes: %u", bankHandler->getUnifiedIndexToBankSize(), countNode) ); + bankHandler->calcIdBitsByBank(); _IdBits = 0; - for ( uint b=0; b!=CDB_BANKS_MAX; ++b ) - { - uint nbNodesOfBank = (uint)_CDBBankToUnifiedIndexMapping[b].size(); - uint idb = 0; - if ( nbNodesOfBank > 0 ) - for ( idb=1; nbNodesOfBank > unsigned(1<getFirstLevelIdBits( bank ) ); // Translate bank index -> unified index - idx = _CDBBankToUnifiedIndexMapping[bank][idx]; + idx = bankHandler->getServerToClientUIDMapping( bank, idx ); if (idx >= _Nodes.size()) { throw Exception ("idx %d > _Nodes.size() %d ", idx, _Nodes.size()); diff --git a/code/nel/src/misc/cdb_leaf.cpp b/code/nel/src/misc/cdb_leaf.cpp index 96a4b4428..992699627 100644 --- a/code/nel/src/misc/cdb_leaf.cpp +++ b/code/nel/src/misc/cdb_leaf.cpp @@ -41,7 +41,7 @@ namespace NLMISC{ //----------------------------------------------- // init //----------------------------------------------- -void CCDBNodeLeaf::init( xmlNodePtr node, IProgressCallback &/* progressCallBack */, bool /* mapBanks */ ) +void CCDBNodeLeaf::init( xmlNodePtr node, IProgressCallback &/* progressCallBack */, bool /* mapBanks */, CCDBBankHandler * /* bankHandler */ ) { CXMLAutoPtr type((const char*)xmlGetProp (node, (xmlChar*)"type")); nlassert((const char *) type != NULL); diff --git a/code/ryzom/client/src/cdb_synchronised.cpp b/code/ryzom/client/src/cdb_synchronised.cpp index caf487b81..2379d34a4 100644 --- a/code/ryzom/client/src/cdb_synchronised.cpp +++ b/code/ryzom/client/src/cdb_synchronised.cpp @@ -40,6 +40,8 @@ #include +#include "../../common/src/game_share/ryzom_database_banks.h" + //////////////// // Namespaces // @@ -56,11 +58,11 @@ uint32 NbDatabaseChanges = 0; // CCDBSynchronised // //----------------------------------------------- -CCDBSynchronised::CCDBSynchronised() : _Database(0), _InitInProgress(true), _InitDeltaReceived(0) +CCDBSynchronised::CCDBSynchronised() : _Database(0), _InitInProgress(true), _InitDeltaReceived(0), bankHandler( NB_CDB_BANKS ) { } - +extern const char *CDBBankNames[INVALID_CDB_BANK+1]; //----------------------------------------------- // init @@ -78,9 +80,10 @@ void CCDBSynchronised::init( const string &fileName, NLMISC::IProgressCallback & read.init (file); //Parse the parser output!!! - CCDBNodeBranch::resetNodeBankMapping(); // in case the game is restarted from start + bankHandler.resetNodeBankMapping(); // in case the game is restarted from start + bankHandler.fillBankNames( CDBBankNames, INVALID_CDB_BANK + 1 ); _Database = new CCDBNodeBranch("SERVER"); - _Database->init( read.getRootNode (), progressCallBack, true ); + _Database->init( read.getRootNode (), progressCallBack, true, &bankHandler ); } } catch (const Exception &e) @@ -193,7 +196,7 @@ void CCDBSynchronised::readDelta( NLMISC::TGameCycle gc, CBitMemStream& s, uint for( uint i=0; i!=propertyCount; ++i ) { - _Database->readAndMapDelta( gc, s, bank ); + _Database->readAndMapDelta( gc, s, bank, &bankHandler ); } /*// Read "client only" property changes @@ -307,6 +310,7 @@ void CCDBSynchronised::clear() // clear CCDBNodeBranch static data CCDBNodeBranch::reset(); + bankHandler.reset(); } @@ -320,6 +324,9 @@ void CCDBSynchronised::writeInitInProgressIntoUIDB() } +void CCDBSynchronised::resetBank( uint gc, uint bank ){ + _Database->resetNode( gc, bankHandler.getUIDForBank( bank ) ); +} #ifdef TRACE_READ_DELTA #undef TRACE_READ_DELTA diff --git a/code/ryzom/client/src/cdb_synchronised.h b/code/ryzom/client/src/cdb_synchronised.h index d65dc1523..b9d11e5b6 100644 --- a/code/ryzom/client/src/cdb_synchronised.h +++ b/code/ryzom/client/src/cdb_synchronised.h @@ -22,6 +22,7 @@ #include "nel/misc/cdb.h" #include "nel/misc/cdb_branch.h" +#include "nel/misc/cdb_bank_handler.h" /** * Class to manage a database of properties @@ -144,6 +145,8 @@ public: } } + void resetBank( uint gc, uint bank ); + private: friend void impulseDatabaseInitPlayer( NLMISC::CBitMemStream &impulse ); @@ -153,6 +156,8 @@ private: bool allInitPacketReceived() const { return _InitDeltaReceived == 2; } // Classic database + inventory void writeInitInProgressIntoUIDB(); + + NLMISC::CCDBBankHandler bankHandler; }; diff --git a/code/ryzom/client/src/net_manager.cpp b/code/ryzom/client/src/net_manager.cpp index ec8705202..8116ccaea 100644 --- a/code/ryzom/client/src/net_manager.cpp +++ b/code/ryzom/client/src/net_manager.cpp @@ -141,9 +141,7 @@ extern bool CharNameValid; bool IsInRingSession = false; TSessionId HighestMainlandSessionId; // highest in the position stack -namespace NLMISC{ extern const char *CDBBankNames[INVALID_CDB_BANK+1]; -} void cbImpulsionGatewayOpen(NLMISC::CBitMemStream &bms); void cbImpulsionGatewayMessage(NLMISC::CBitMemStream &bms); @@ -222,7 +220,7 @@ void impulseDatabaseUpdateBank(NLMISC::CBitMemStream &impulse) } catch (const Exception &e) { - BOMB( NLMISC::toString( "Problem while decoding a DB_GROUP:UPDATE_BANK %s msg, skipped: %s", NLMISC::CDBBankNames[bank], e.what() ), return ); + BOMB( NLMISC::toString( "Problem while decoding a DB_GROUP:UPDATE_BANK %s msg, skipped: %s", CDBBankNames[bank], e.what() ), return ); } } @@ -242,7 +240,7 @@ void impulseDatabaseInitBank(NLMISC::CBitMemStream &impulse) // read delta IngameDbMngr.readDelta( serverTick, impulse, (TCDBBank)bank ); - nldebug( "CDB: DB_GROUP:INIT_BANK %s", NLMISC::CDBBankNames[bank] ); + nldebug( "CDB: DB_GROUP:INIT_BANK %s", CDBBankNames[bank] ); // read guild inventory update if ( bank == CDBGuild ) @@ -252,7 +250,7 @@ void impulseDatabaseInitBank(NLMISC::CBitMemStream &impulse) } catch (const Exception &e) { - BOMB( NLMISC::toString( "Problem while decoding a DB_GROUP:INIT_BANK %s msg, skipped: %s", NLMISC::CDBBankNames[bank], e.what() ), return ); + BOMB( NLMISC::toString( "Problem while decoding a DB_GROUP:INIT_BANK %s msg, skipped: %s", CDBBankNames[bank], e.what() ), return ); } } @@ -271,12 +269,12 @@ void impulseDatabaseResetBank(NLMISC::CBitMemStream &impulse) impulse.serial( bank, nbits ); // reset the bank - IngameDbMngr.getNodePtr()->resetBank( serverTick, (TCDBBank)bank ); - nldebug( "CDB: DB_GROUP:RESET_BANK %s", NLMISC::CDBBankNames[bank] ); + IngameDbMngr.resetBank( serverTick, bank ); + nldebug( "CDB: DB_GROUP:RESET_BANK %s", CDBBankNames[bank] ); } catch (const Exception &e) { - BOMB( NLMISC::toString( "Problem while decoding a DB_GROUP:RESET_BANK %s msg, skipped: %s", NLMISC::CDBBankNames[bank], e.what() ), return ); + BOMB( NLMISC::toString( "Problem while decoding a DB_GROUP:RESET_BANK %s msg, skipped: %s", CDBBankNames[bank], e.what() ), return ); } } diff --git a/code/ryzom/common/src/game_share/ryzom_database_banks.cpp b/code/ryzom/common/src/game_share/ryzom_database_banks.cpp index cffa4e138..46fddd789 100644 --- a/code/ryzom/common/src/game_share/ryzom_database_banks.cpp +++ b/code/ryzom/common/src/game_share/ryzom_database_banks.cpp @@ -17,9 +17,7 @@ #include "stdpch.h" #include "ryzom_database_banks.h" -namespace NLMISC{ const char *CDBBankNames[INVALID_CDB_BANK+1] = { "PLR", "GUILD", /* "CONTINENT", */ "OUTPOST", /* "GLOBAL", */ "", "INVALID" }; -} // leave not static else this workaround don't work