1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU Affero General Public License as
6 // published by the Free Software Foundation, either version 3 of the
7 // License, or (at your option) any later version.
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU Affero General Public License for more details.
14 // You should have received a copy of the GNU Affero General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
21 #include "nel/net/service.h"
23 #include "server_share/mail_forum_validator.h"
25 #include "player_manager/character.h"
26 #include "player_manager/player_manager.h"
27 #include "player_manager/player.h"
29 #include "guild_manager/guild_manager.h"
30 #include "guild_manager/guild.h"
33 using namespace NLMISC
;
34 using namespace NLNET
;
36 // ****************************************************************************
38 CStatDB
*CStatDB::_Instance
= NULL
;
40 CVariable
<uint32
> StatDBSavePeriod("egs", "StatDBSavePeriod","stat database save period in ticks", 6, 0, true);
42 extern CVariable
<bool> EGSLight
;
44 // ****************************************************************************
46 // ****************************************************************************
48 // ****************************************************************************
49 static bool getPlayerName(CEntityId playerId
, string
& playerName
)
51 playerName
= CEntityIdTranslator::getInstance()->getByEntity(playerId
).toUtf8();
52 return !playerName
.empty();
55 // ****************************************************************************
56 static bool getGuildName(EGSPD::TGuildId guildId
, string
& guildName
)
58 CGuild
* guild
= CGuildManager::getInstance()->getGuildFromId(guildId
);
62 guildName
= guild
->getName().toUtf8();
66 // ****************************************************************************
67 static void getNamesFromTable(const CStatDBTableLeafMsg
& tableLeafMsg
, CStatDBNamesMsg
& namesMsg
)
69 for ( map
<NLMISC::CEntityId
,sint32
>::const_iterator it
= tableLeafMsg
.PlayerValues
.begin();
70 it
!= tableLeafMsg
.PlayerValues
.end();
73 const CEntityId
& playerId
= (*it
).first
;
76 if (!getPlayerName(playerId
, playerName
))
79 nlwarning("SDB: cannot find the name of the player %s", playerId
.toString().c_str());
80 #endif // FINAL_VERSION
84 namesMsg
.PlayerNames
[playerId
] = playerName
;
87 for ( map
<EGSPD::TGuildId
,sint32
>::const_iterator it
= tableLeafMsg
.GuildValues
.begin();
88 it
!= tableLeafMsg
.GuildValues
.end();
91 const EGSPD::TGuildId
& guildId
= (*it
).first
;
94 if (!getGuildName(guildId
, guildName
))
97 nlwarning("SDB: cannot find the name of the guild %u", guildId
);
98 #endif // FINAL_VERSION
102 namesMsg
.GuildNames
[guildId
] = guildName
;
106 // ****************************************************************************
107 // CStatDBBackupLeafCollector
108 // ****************************************************************************
110 // ****************************************************************************
111 void CStatDBBackupLeafCollector::loadLeaves(IStatDBNodePtr root
)
113 nlassert(root
!= NULL
);
117 _Root
->acceptVisitor(*this, "");
120 // ****************************************************************************
121 bool CStatDBBackupLeafCollector::popTableLeafPD(CStatDBTableLeafPD
& tableLeafPD
)
126 while (!_TableLeafPaths
.empty())
128 string path
= _TableLeafPaths
.back();
129 _TableLeafPaths
.pop_back();
131 CStatDBTableLeaf
* tableLeaf
= dynamic_cast<CStatDBTableLeaf
*>(_Root
->getNode(path
).getPtr());
132 if (tableLeaf
!= NULL
)
134 tableLeafPD
.Path
= path
;
135 tableLeafPD
.PlayerValues
= tableLeaf
->getPlayerValues();
136 tableLeafPD
.GuildValues
= tableLeaf
->getGuildValues();
144 // ****************************************************************************
145 void CStatDBBackupLeafCollector::visitValueLeaf(CStatDBValueLeaf
* valueLeaf
, const std::string
& path
)
147 CStatDBValueLeafPD valueLeafPD
;
148 valueLeafPD
.Path
= path
;
149 valueLeafPD
.Value
= valueLeaf
->getValue();
151 _ValueLeavesPD
.ValueLeavesPD
.push_back(valueLeafPD
);
154 // ****************************************************************************
155 void CStatDBBackupLeafCollector::visitTableLeaf(CStatDBTableLeaf
* tableLeaf
, const std::string
& path
)
157 _TableLeafPaths
.push_back(path
);
160 // ****************************************************************************
161 // CStatDBMFSInitLeafCollector
162 // ****************************************************************************
164 // ****************************************************************************
165 void CStatDBMFSInitLeafCollector::loadLeaves(IStatDBNodePtr root
, CStatDBAllLeavesMsg
& allLeavesMsg
)
167 nlassert(root
!= NULL
);
169 _AllLeavesMsg
= &allLeavesMsg
;
170 _AllLeavesMsg
->ValueLeavesMsg
.clear();
171 _AllLeavesMsg
->TableLeavesMsg
.clear();
172 _AllLeavesMsg
->NamesMsg
.PlayerNames
.clear();
173 _AllLeavesMsg
->NamesMsg
.GuildNames
.clear();
175 root
->acceptVisitor(*this, "");
178 // ****************************************************************************
179 void CStatDBMFSInitLeafCollector::visitValueLeaf(CStatDBValueLeaf
* valueLeaf
, const std::string
& path
)
181 CStatDBValueLeafMsg valueLeafMsg
;
182 valueLeafMsg
.Path
= path
;
183 valueLeafMsg
.Value
= valueLeaf
->getValue();
185 _AllLeavesMsg
->ValueLeavesMsg
.push_back(valueLeafMsg
);
188 // ****************************************************************************
189 void CStatDBMFSInitLeafCollector::visitTableLeaf(CStatDBTableLeaf
* tableLeaf
, const std::string
& path
)
191 CStatDBTableLeafMsg tableLeafMsg
;
192 tableLeafMsg
.Path
= path
;
193 tableLeafMsg
.PlayerValues
= tableLeaf
->getPlayerValues();
194 tableLeafMsg
.GuildValues
= tableLeaf
->getGuildValues();
196 _AllLeavesMsg
->TableLeavesMsg
.push_back(tableLeafMsg
);
198 getNamesFromTable(tableLeafMsg
, _AllLeavesMsg
->NamesMsg
);
201 // ****************************************************************************
202 // CStatDBNodeDisplayer
203 // ****************************************************************************
205 // ****************************************************************************
206 void CStatDBNodeDisplayer::displayNode(IStatDBNodePtr node
, const std::string
& currentPath
, NLMISC::CLog
& log
)
210 if (_Settings
.Recursive
)
212 node
->acceptVisitor(*this, currentPath
);
216 displayOneNode(node
, currentPath
);
218 // if the node is a branch
219 CStatDBBranch
* branch
= dynamic_cast<CStatDBBranch
*>(node
.getPtr());
222 vector
<IStatDBNode::CMatchingNode
> children
;
223 branch
->getNodes("*", children
, currentPath
);
224 for (uint i
= 0; i
< children
.size(); i
++)
226 displayOneNode(children
[i
].Node
, children
[i
].Path
);
233 // ****************************************************************************
234 void CStatDBNodeDisplayer::displayOneNode(IStatDBNodePtr node
, const std::string
& currentPath
)
236 BOMB_IF(node
== NULL
, "node is NULL!", return);
238 CStatDBBranch
* branch
= dynamic_cast<CStatDBBranch
*>(node
.getPtr());
241 visitBranch(branch
, currentPath
);
245 CStatDBValueLeaf
* valueLeaf
= dynamic_cast<CStatDBValueLeaf
*>(node
.getPtr());
246 if (valueLeaf
!= NULL
)
248 visitValueLeaf(valueLeaf
, currentPath
);
252 CStatDBTableLeaf
* tableLeaf
= dynamic_cast<CStatDBTableLeaf
*>(node
.getPtr());
253 if (tableLeaf
!= NULL
)
255 visitTableLeaf(tableLeaf
, currentPath
);
260 // ****************************************************************************
261 void CStatDBNodeDisplayer::visitBranch(CStatDBBranch
* branch
, const std::string
& path
)
263 if (_Settings
.DisplayBranch
)
265 _Log
->displayNL("(B) %s", path
.c_str());
269 // ****************************************************************************
270 void CStatDBNodeDisplayer::visitValueLeaf(CStatDBValueLeaf
* valueLeaf
, const std::string
& path
)
272 if (_Settings
.DisplayValueLeaf
)
274 if (_Settings
.DisplayValueLeafContent
)
275 _Log
->displayNL("(V) %s = %d", path
.c_str(), valueLeaf
->getValue());
277 _Log
->displayNL("(V) %s", path
.c_str());
281 // ****************************************************************************
282 void CStatDBNodeDisplayer::visitTableLeaf(CStatDBTableLeaf
* tableLeaf
, const std::string
& path
)
284 if (_Settings
.DisplayTableLeaf
)
286 _Log
->displayNL("(T) %s", path
.c_str());
287 if (_Settings
.DisplayTableLeafContent
)
289 for ( map
<NLMISC::CEntityId
,sint32
>::const_iterator it
= tableLeaf
->getPlayerValues().begin();
290 it
!= tableLeaf
->getPlayerValues().end();
294 if (!getPlayerName((*it
).first
, playerName
))
296 playerName
= "[not found] " + (*it
).first
.toString();
299 _Log
->displayNL("\tplayer '%s' = %d", playerName
.c_str(), (*it
).second
);
302 for ( map
<EGSPD::TGuildId
,sint32
>::const_iterator it
= tableLeaf
->getGuildValues().begin();
303 it
!= tableLeaf
->getGuildValues().end();
307 if (!getGuildName((*it
).first
, guildName
))
309 guildName
= toString("[not found] %u", (*it
).first
);
312 _Log
->displayNL("\tguild '%s' = %d", guildName
.c_str(), (*it
).second
);
318 // ****************************************************************************
320 // ****************************************************************************
322 // ****************************************************************************
325 _Root
= new CStatDBBranch
;
326 _SDBIsLoaded
= false;
327 _GuildsAreLoaded
= false;
329 _MFSIsInitialized
= false;
332 // ****************************************************************************
333 bool CStatDB::createValue(const std::string
& path
, sint32 val
)
335 nlassert(_SDBIsLoaded
);
337 IStatDBNodePtr node
= _Root
->getNode(path
);
341 bool res
= _Root
->setNode(path
, new CStatDBValueLeaf(val
));
343 if (res
&& _MFSIsInitialized
)
345 uint32 shardId
= IService::getInstance()->getShardId();
346 CStatDBValueLeafMsg valueLeafMsg
;
347 valueLeafMsg
.Path
= path
;
348 valueLeafMsg
.Value
= val
;
350 CMessage
msgout("SDB:CREATE_VALUE");
351 msgout
.serial(shardId
);
352 msgout
.serial(valueLeafMsg
);
353 CUnifiedNetwork::getInstance()->send("MFS", msgout
);
359 // ****************************************************************************
360 bool CStatDB::valueSet(const std::string
& path
, sint32 val
)
362 nlassert(_SDBIsLoaded
);
364 CStatDBValueLeaf
* valueLeaf
= dynamic_cast<CStatDBValueLeaf
*>(_Root
->getNode(path
).getPtr());
365 if (valueLeaf
== NULL
)
368 valueLeaf
->setValue(val
);
370 if (_MFSIsInitialized
)
372 uint32 shardId
= IService::getInstance()->getShardId();
374 CMessage
msgout("SDB:VALUE_SET");
375 msgout
.serial(shardId
);
376 msgout
.serial(const_cast<string
&>(path
));
378 CUnifiedNetwork::getInstance()->send("MFS", msgout
);
384 // ****************************************************************************
385 bool CStatDB::valueAdd(const std::string
& path
, sint32 val
)
387 nlassert(_SDBIsLoaded
);
389 CStatDBValueLeaf
* valueLeaf
= dynamic_cast<CStatDBValueLeaf
*>(_Root
->getNode(path
).getPtr());
390 if (valueLeaf
== NULL
)
393 valueLeaf
->addValue(val
);
395 if (_MFSIsInitialized
)
397 uint32 shardId
= IService::getInstance()->getShardId();
399 CMessage
msgout("SDB:VALUE_ADD");
400 msgout
.serial(shardId
);
401 msgout
.serial(const_cast<string
&>(path
));
403 CUnifiedNetwork::getInstance()->send("MFS", msgout
);
409 // ****************************************************************************
410 bool CStatDB::valueGet(const std::string
& path
, sint32
& val
)
412 nlassert(_SDBIsLoaded
);
414 CStatDBValueLeaf
* valueLeaf
= dynamic_cast<CStatDBValueLeaf
*>(_Root
->getNode(path
).getPtr());
415 if (valueLeaf
== NULL
)
418 val
= valueLeaf
->getValue();
422 // ****************************************************************************
423 bool CStatDB::createTable(const std::string
& path
)
425 nlassert(_SDBIsLoaded
);
427 IStatDBNodePtr node
= _Root
->getNode(path
);
431 return createTable(path
, map
<NLMISC::CEntityId
,sint32
>(), map
<EGSPD::TGuildId
,sint32
>());
434 // ****************************************************************************
435 bool CStatDB::createTable(const std::string
& path
,
436 const std::map
<NLMISC::CEntityId
,sint32
> & playerValues
,
437 const std::map
<EGSPD::TGuildId
,sint32
> & guildValues
440 nlassert(_SDBIsLoaded
);
442 IStatDBNodePtr node
= _Root
->getNode(path
);
446 bool res
= _Root
->setNode(path
, new CStatDBTableLeaf(playerValues
, guildValues
));
448 if (res
&& _MFSIsInitialized
)
450 uint32 shardId
= IService::getInstance()->getShardId();
451 CStatDBTableLeafMsg tableLeafMsg
;
452 tableLeafMsg
.Path
= path
;
453 tableLeafMsg
.PlayerValues
= playerValues
;
454 tableLeafMsg
.GuildValues
= guildValues
;
456 CStatDBNamesMsg namesMsg
;
457 getNamesFromTable(tableLeafMsg
, namesMsg
);
459 CMessage
msgout("SDB:CREATE_TABLE");
460 msgout
.serial(shardId
);
461 msgout
.serial(tableLeafMsg
);
462 msgout
.serial(namesMsg
);
463 CUnifiedNetwork::getInstance()->send("MFS", msgout
);
469 // ****************************************************************************
470 bool CStatDB::tablePlayerAdd(const std::string
& path
, NLMISC::CEntityId playerId
, sint32 val
)
472 nlassert(_SDBIsLoaded
);
474 CStatDBTableLeaf
* tableLeaf
= dynamic_cast<CStatDBTableLeaf
*>(_Root
->getNode(path
).getPtr());
475 if (tableLeaf
== NULL
)
478 tableLeaf
->playerAdd(playerId
, val
);
480 if (_MFSIsInitialized
)
482 uint32 shardId
= IService::getInstance()->getShardId();
484 getPlayerName(playerId
, playerName
);
486 CMessage
msgout("SDB:TABLE_PLAYER_ADD");
487 msgout
.serial(shardId
);
488 msgout
.serial(const_cast<string
&>(path
));
489 msgout
.serial(playerId
);
490 msgout
.serial(playerName
);
492 CUnifiedNetwork::getInstance()->send("MFS", msgout
);
498 // ****************************************************************************
499 bool CStatDB::tablePlayerSet(const std::string
& path
, NLMISC::CEntityId playerId
, sint32 val
)
501 nlassert(_SDBIsLoaded
);
503 CStatDBTableLeaf
* tableLeaf
= dynamic_cast<CStatDBTableLeaf
*>(_Root
->getNode(path
).getPtr());
504 if (tableLeaf
== NULL
)
507 tableLeaf
->playerSet(playerId
, val
);
509 if (_MFSIsInitialized
)
511 uint32 shardId
= IService::getInstance()->getShardId();
513 getPlayerName(playerId
, playerName
);
515 CMessage
msgout("SDB:TABLE_PLAYER_SET");
516 msgout
.serial(shardId
);
517 msgout
.serial(const_cast<string
&>(path
));
518 msgout
.serial(playerId
);
519 msgout
.serial(playerName
);
521 CUnifiedNetwork::getInstance()->send("MFS", msgout
);
527 // ****************************************************************************
528 bool CStatDB::tablePlayerGet(const std::string
& path
, NLMISC::CEntityId playerId
, sint32
& val
)
530 nlassert(_SDBIsLoaded
);
532 CStatDBTableLeaf
* tableLeaf
= dynamic_cast<CStatDBTableLeaf
*>(_Root
->getNode(path
).getPtr());
533 if (tableLeaf
== NULL
)
536 return tableLeaf
->playerGet(playerId
, val
);
539 // ****************************************************************************
540 bool CStatDB::tableGuildAdd(const std::string
& path
, EGSPD::TGuildId guildId
, sint32 val
)
542 nlassert(_SDBIsLoaded
);
544 CStatDBTableLeaf
* tableLeaf
= dynamic_cast<CStatDBTableLeaf
*>(_Root
->getNode(path
).getPtr());
545 if (tableLeaf
== NULL
)
548 tableLeaf
->guildAdd(guildId
, val
);
550 if (_MFSIsInitialized
)
552 uint32 shardId
= IService::getInstance()->getShardId();
554 getGuildName(guildId
, guildName
);
556 CMessage
msgout("SDB:TABLE_GUILD_ADD");
557 msgout
.serial(shardId
);
558 msgout
.serial(const_cast<string
&>(path
));
559 msgout
.serial(guildId
);
560 msgout
.serial(guildName
);
562 CUnifiedNetwork::getInstance()->send("MFS", msgout
);
568 // ****************************************************************************
569 bool CStatDB::tableGuildSet(const std::string
& path
, EGSPD::TGuildId guildId
, sint32 val
)
571 nlassert(_SDBIsLoaded
);
573 CStatDBTableLeaf
* tableLeaf
= dynamic_cast<CStatDBTableLeaf
*>(_Root
->getNode(path
).getPtr());
574 if (tableLeaf
== NULL
)
577 tableLeaf
->guildSet(guildId
, val
);
579 if (_MFSIsInitialized
)
581 uint32 shardId
= IService::getInstance()->getShardId();
583 getGuildName(guildId
, guildName
);
585 CMessage
msgout("SDB:TABLE_GUILD_SET");
586 msgout
.serial(shardId
);
587 msgout
.serial(const_cast<string
&>(path
));
588 msgout
.serial(guildId
);
589 msgout
.serial(guildName
);
591 CUnifiedNetwork::getInstance()->send("MFS", msgout
);
597 // ****************************************************************************
598 bool CStatDB::tableGuildGet(const std::string
& path
, EGSPD::TGuildId guildId
, sint32
& val
)
600 nlassert(_SDBIsLoaded
);
602 CStatDBTableLeaf
* tableLeaf
= dynamic_cast<CStatDBTableLeaf
*>(_Root
->getNode(path
).getPtr());
603 if (tableLeaf
== NULL
)
606 return tableLeaf
->guildGet(guildId
, val
);
609 // ****************************************************************************
610 class CStatDBBackupFileCleaner
: private CStatDBNodeVisitor
613 void submitRemovedNode(IStatDBNodePtr removedNode
, const std::string
& removedNodePath
, bool keepBackupOfFiles
)
615 _KeepBackupOfFiles
= keepBackupOfFiles
;
616 if (removedNode
!= NULL
)
617 removedNode
->acceptVisitor(*this, removedNodePath
);
621 void visitTableLeaf(CStatDBTableLeaf
* tableLeaf
, const std::string
& path
)
623 string sFilePath
= toString("sdb/table_leaf_%s_pdr.%s", path
.c_str(), (XMLSave
?"xml":"bin"));
624 Bsi
.deleteFile(sFilePath
, _KeepBackupOfFiles
);
628 bool _KeepBackupOfFiles
;
631 bool CStatDB::removeNode(const std::string
& path
, bool keepBackupOfFiles
)
633 nlassert(_SDBIsLoaded
);
635 IStatDBNodePtr removedNode
= _Root
->removeNode(path
);
636 bool res
= (removedNode
!= NULL
);
638 if (res
&& _MFSIsInitialized
)
640 uint32 shardId
= IService::getInstance()->getShardId();
642 CMessage
msgout("SDB:REMOVE_NODE");
643 msgout
.serial(shardId
);
644 msgout
.serial(const_cast<string
&>(path
));
645 CUnifiedNetwork::getInstance()->send("MFS", msgout
);
650 // remove save files associated to the removed node if any
651 // only table leaves have their own save files
652 CStatDBBackupFileCleaner backupFileCleaner
;
653 backupFileCleaner
.submitRemovedNode(removedNode
, path
, keepBackupOfFiles
);
659 // ****************************************************************************
660 void CStatDB::removePlayer(NLMISC::CEntityId playerId
)
662 _EntitiesRemoval
.addPlayerToRemove(playerId
);
664 if (_MFSIsInitialized
)
666 uint32 shardId
= IService::getInstance()->getShardId();
668 CMessage
msgout("SDB:REMOVE_PLAYER");
669 msgout
.serial(shardId
);
670 msgout
.serial(playerId
);
671 CUnifiedNetwork::getInstance()->send("MFS", msgout
);
675 // ****************************************************************************
676 void CStatDB::removeGuild(EGSPD::TGuildId guildId
)
678 _EntitiesRemoval
.addGuildToRemove(guildId
);
680 if (_MFSIsInitialized
)
682 uint32 shardId
= IService::getInstance()->getShardId();
684 CMessage
msgout("SDB:REMOVE_GUILD");
685 msgout
.serial(shardId
);
686 msgout
.serial(guildId
);
687 CUnifiedNetwork::getInstance()->send("MFS", msgout
);
691 // ****************************************************************************
692 bool CStatDB::displayNodes(const std::string
& pathPattern
, NLMISC::CLog
& log
, const CStatDBNodeDisplayer::CSettings
& settings
)
694 vector
<IStatDBNode::CMatchingNode
> nodes
;
695 _Root
->getNodes(pathPattern
, nodes
, "");
700 CStatDBNodeDisplayer nodeDisplayer
;
701 nodeDisplayer
.setSettings(settings
);
703 for (uint i
= 0; i
< nodes
.size(); i
++)
705 nodeDisplayer
.displayNode(nodes
[i
].Node
, nodes
[i
].Path
, log
);
712 uint32 nTotalLoaded
= 0;
714 struct TValueLeaveFileCallback
: public IBackupFileReceiveCallback
716 virtual void callback(const CFileDescription
& fileDescription
, NLMISC::IStream
& dataStream
)
718 CStatDB::getInstance()->valueLeaveFileCallback(fileDescription
, dataStream
);
722 void CStatDB::valueLeaveFileCallback(const CFileDescription
& fileDescription
, NLMISC::IStream
& dataStream
)
724 if (!fileDescription
.FileName
.empty())
726 static CPersistentDataRecord pdr
;
728 CStatDBValueLeavesPD valueLeavesPD
;
730 pdr
.fromBuffer(dataStream
);
731 // pdr.readFromFile(sFilePath);
732 valueLeavesPD
.apply(pdr
);
733 nTotalLoaded
+= fileDescription
.FileSize
;
735 for (uint32 i
= 0; i
< valueLeavesPD
.ValueLeavesPD
.size(); ++i
)
737 const CStatDBValueLeafPD
& valueLeafPD
= valueLeavesPD
.ValueLeavesPD
[i
];
739 IStatDBNodePtr node
= _Root
->getNode(valueLeafPD
.Path
);
742 bool res
= _Root
->setNode(valueLeafPD
.Path
, new CStatDBValueLeaf(valueLeafPD
.Value
));
745 nlwarning("value leaf '%s' cannot be created!", valueLeafPD
.Path
.c_str());
751 nlwarning("leaf '%s' already exists!", valueLeafPD
.Path
.c_str());
758 vector
<string
> fileNames
;
760 struct TFileClassCallback
: public IBackupFileClassReceiveCallback
762 virtual void callback(const CFileDescriptionContainer
& fileList
)
764 for (uint i
=0; i
<fileList
.size(); ++i
)
766 fileNames
.push_back(fileList
[i
].FileName
);
772 struct TTableLeaveFileCallback
: public IBackupFileReceiveCallback
774 virtual void callback(const CFileDescription
& fileDescription
, NLMISC::IStream
& dataStream
)
776 CStatDB::getInstance()->tableLeaveFileCallback(fileDescription
, dataStream
);
780 void CStatDB::tableLeaveFileCallback(const CFileDescription
& fileDescription
, NLMISC::IStream
& dataStream
)
782 const string
& fileName
= CFile::getFilename(fileDescription
.FileName
);
784 if ( CFile::getFilename(fileName
).substr(0, 11) == "table_leaf_"
785 && CFile::getExtension(fileName
) == (XMLSave
?"xml":"bin"))
787 H_AUTO(CStatDB_load_2
);
789 static CPersistentDataRecord pdr
;
791 CStatDBTableLeafPD tableLeafPD
;
793 pdr
.fromBuffer(dataStream
);
794 // pdr.readFromFile(fileName);
795 tableLeafPD
.apply(pdr
);
796 nTotalLoaded
+= CFile::getFileSize(fileName
);
798 IStatDBNodePtr node
= _Root
->getNode(tableLeafPD
.Path
);
801 bool res
= _Root
->setNode(tableLeafPD
.Path
, new CStatDBTableLeaf(tableLeafPD
.PlayerValues
, tableLeafPD
.GuildValues
));
804 nlwarning("table leaf '%s' cannot be created!", tableLeafPD
.Path
.c_str());
810 nlwarning("leaf '%s' already exists!", tableLeafPD
.Path
.c_str());
817 // ****************************************************************************
820 H_AUTO(CStatDB_load
);
833 // // create SDB path
835 // string sPath = Bsi.getLocalPath() + "sdb";
836 // if (!CFile::isExists(sPath))
837 // CFile::createDirectory(sPath);
842 H_AUTO(CStatDB_load_1
);
844 // string sFilePath = Bsi.getLocalPath();
845 string sFilePath
= toString("sdb/value_leaves_pdr.%s", (XMLSave
?"xml":"bin"));
847 TValueLeaveFileCallback
*cb
= new TValueLeaveFileCallback
;
849 Bsi
.syncLoadFile(sFilePath
, cb
);
851 // if (CFile::isExists(sFilePath))
853 // static CPersistentDataRecord pdr;
855 // CStatDBValueLeavesPD valueLeavesPD;
857 // pdr.readFromFile(sFilePath);
858 // valueLeavesPD.apply(pdr);
859 // nTotalLoaded += CFile::getFileSize(sFilePath);
861 // for (uint32 i = 0; i < valueLeavesPD.ValueLeavesPD.size(); ++i)
863 // const CStatDBValueLeafPD & valueLeafPD = valueLeavesPD.ValueLeavesPD[i];
865 // IStatDBNodePtr node = _Root->getNode(valueLeafPD.Path);
868 // bool res = _Root->setNode(valueLeafPD.Path, new CStatDBValueLeaf(valueLeafPD.Value));
871 // nlwarning("value leaf '%s' cannot be created!", valueLeafPD.Path.c_str());
877 // nlwarning("leaf '%s' already exists!", valueLeafPD.Path.c_str());
885 // string sdbSavePath = Bsi.getLocalPath() + "sdb";
889 vector
<CBackupFileClass
> fileClasses(1);
890 fileClasses
[0].Patterns
.push_back(toString("table_leaf_*.%s", XMLSave
? "xml" : "bin"));
891 TFileClassCallback
*ccb
= new TFileClassCallback
;
892 Bsi
.syncLoadFileClass("sdb", fileClasses
, ccb
);
895 TTableLeaveFileCallback
*cb2
= new TTableLeaveFileCallback
;
896 Bsi
.syncLoadFiles(fileNames
, cb2
);
898 // std::vector<std::string> files;
899 // CPath::getPathContent(sdbSavePath, false, false, true, files);
900 // for (uint i = 0; i < files.size(); i++)
902 // const string & fileName = files[i];
904 // if ( CFile::getFilename(fileName).substr(0, 11) == "table_leaf_"
905 // && CFile::getExtension(fileName) == (XMLSave?"xml":"bin"))
907 // H_AUTO(CStatDB_load_2);
909 // static CPersistentDataRecord pdr;
911 // CStatDBTableLeafPD tableLeafPD;
913 // pdr.readFromFile(fileName);
914 // tableLeafPD.apply(pdr);
915 // nTotalLoaded += CFile::getFileSize(fileName);
917 // IStatDBNodePtr node = _Root->getNode(tableLeafPD.Path);
920 // bool res = _Root->setNode(tableLeafPD.Path, new CStatDBTableLeaf(tableLeafPD.PlayerValues, tableLeafPD.GuildValues));
923 // nlwarning("table leaf '%s' cannot be created!", tableLeafPD.Path.c_str());
929 // nlwarning("leaf '%s' already exists!", tableLeafPD.Path.c_str());
935 nlinfo("SDB: loaded %u bytes", nTotalLoaded
);
942 // ****************************************************************************
943 bool CStatDB::canInitMFS() const
945 return (_SDBIsLoaded
&& _GuildsAreLoaded
&& _MFSIsUp
);
948 // ****************************************************************************
949 void CStatDB::initMFS()
951 H_AUTO(CStatDB_initMFS
);
953 nlassert(canInitMFS());
955 if (_MFSIsInitialized
)
958 uint32 shardId
= IService::getInstance()->getShardId();
959 if ( shardId
== DEFAULT_SHARD_ID
)
966 ( "SDB: Sending default shard id (%u) to MFS", DEFAULT_SHARD_ID
);
968 CStatDBAllLeavesMsg allLeavesMsg
;
969 CStatDBMFSInitLeafCollector().loadLeaves(_Root
, allLeavesMsg
);
971 CMessage
msgout("SDB:INIT");
972 msgout
.serial(shardId
);
973 msgout
.serial(allLeavesMsg
);
975 nlinfo("SDB: initMFS: send %u bytes to MFS", msgout
.length());
977 CUnifiedNetwork::getInstance()->send("MFS", msgout
);
979 _MFSIsInitialized
= true;
982 // ****************************************************************************
983 void CStatDB::cbMFServiceUp()
990 // ****************************************************************************
991 void CStatDB::cbMFServiceDown()
994 _MFSIsInitialized
= false;
997 // ****************************************************************************
998 void CStatDB::cbGuildsLoaded()
1000 _GuildsAreLoaded
= true;
1005 // ****************************************************************************
1006 void CStatDB::tickUpdate()
1008 H_AUTO(CStatDB_tickUpdate
);
1013 // process players and guilds removal at every ticks
1015 H_AUTO(CStatDB_tickUpdate_1
);
1016 _EntitiesRemoval
.processRemoval(_Root
);
1019 // save SDB at every StatDBSavePeriod ticks
1020 if (CTickEventHandler::getGameCycle() % StatDBSavePeriod
.get() != 0)
1023 if (_BackupLeafCollector
.isEmpty())
1025 H_AUTO(CStatDB_tickUpdate_2
);
1026 _BackupLeafCollector
.loadLeaves(_Root
);
1028 // save value leaves file
1029 // even if there is no value leaf because a complete database erase must be saved
1030 saveValueLeaves(_BackupLeafCollector
.getValueLeavesPD());
1031 _BackupLeafCollector
.getValueLeavesPD().ValueLeavesPD
.clear();
1035 CStatDBTableLeafPD tableLeafPD
;
1036 if (_BackupLeafCollector
.popTableLeafPD(tableLeafPD
))
1038 H_AUTO(CStatDB_tickUpdate_4
);
1039 saveTableLeaf(tableLeafPD
);
1044 // ****************************************************************************
1045 void CStatDB::saveAll()
1047 _BackupLeafCollector
.loadLeaves(_Root
);
1049 saveValueLeaves(_BackupLeafCollector
.getValueLeavesPD());
1050 _BackupLeafCollector
.getValueLeavesPD().ValueLeavesPD
.clear();
1052 CStatDBTableLeafPD tableLeafPD
;
1053 while (_BackupLeafCollector
.popTableLeafPD(tableLeafPD
))
1055 saveTableLeaf(tableLeafPD
);
1059 // ****************************************************************************
1060 void CStatDB::saveValueLeaves(const CStatDBValueLeavesPD
& valueLeavesPD
)
1062 string sFilePath
= toString("sdb/value_leaves_pdr.%s", (XMLSave
?"xml":"bin"));
1064 static CPersistentDataRecordRyzomStore pdr
;
1066 valueLeavesPD
.store(pdr
);
1068 CBackupMsgSaveFile
msg( sFilePath
, CBackupMsgSaveFile::SaveFile
, Bsi
);
1073 msg
.DataMsg
.serialBuffer((uint8
*)&s
[0], (uint
)s
.size());
1077 uint size
= pdr
.totalDataSize();
1078 vector
<char> buffer(size
);
1079 pdr
.toBuffer(&buffer
[0], size
);
1080 msg
.DataMsg
.serialBuffer((uint8
*)&buffer
[0], size
);
1083 // nlinfo("saveValueLeaves send %u bytes to BS", msgout.length());
1084 Bsi
.sendFile( msg
);
1087 // ****************************************************************************
1088 void CStatDB::saveTableLeaf(const CStatDBTableLeafPD
& tableLeafPD
)
1090 string sFilePath
= toString("sdb/table_leaf_%s_pdr.%s", tableLeafPD
.Path
.c_str(), (XMLSave
?"xml":"bin"));
1092 static CPersistentDataRecordRyzomStore pdr
;
1094 tableLeafPD
.store(pdr
);
1096 CBackupMsgSaveFile
msg( sFilePath
, CBackupMsgSaveFile::SaveFile
, Bsi
);
1101 msg
.DataMsg
.serialBuffer((uint8
*)&s
[0], (uint
)s
.size());
1105 uint size
= pdr
.totalDataSize();
1106 vector
<char> buffer(size
);
1107 pdr
.toBuffer(&buffer
[0], size
);
1108 msg
.DataMsg
.serialBuffer((uint8
*)&buffer
[0], size
);
1111 // nlinfo("saveTableLeaf(%s) send %u bytes to BS", tableLeafPD.Path.c_str(), msgout.length());
1112 Bsi
.sendFile( msg
);
1115 // ****************************************************************************
1117 // ****************************************************************************
1119 // ****************************************************************************
1120 NLMISC_COMMAND (sdbCreateValue
, "create a value leaf in SDB", "<path> [<value>]")
1122 if (args
.size() < 1 || args
.size() > 2)
1125 const string
& path
= args
[0];
1127 if (args
.size() < 2)
1130 NLMISC::fromString(args
[1], val
);
1132 if (!CStatDB::getInstance()->createValue(path
, val
))
1134 log
.displayNL("cannot create a value leaf at the path '%s' (invalid path or already existing node)",
1141 // ****************************************************************************
1142 NLMISC_COMMAND (sdbCreateTable
, "create a table leaf in SDB", "<path>")
1144 if (args
.size() != 1)
1147 const string
& path
= args
[0];
1148 if (!CStatDB::getInstance()->createTable(path
))
1150 log
.displayNL("cannot create a table leaf at the path '%s' (invalid path or already existing node)",
1157 // ****************************************************************************
1158 NLMISC_COMMAND (sdbRemoveNode
, "remove a node from SDB", "<path>")
1160 if (args
.size() != 1)
1163 const string
& path
= args
[0];
1164 if (!CStatDB::getInstance()->removeNode(path
))
1166 log
.displayNL("path '%s' not found", path
.c_str());
1172 // ****************************************************************************
1173 NLMISC_COMMAND (sdbValueSet
, "set a value leaf in SDB", "<path> <value>")
1175 if (args
.size() != 2)
1178 const string
& path
= args
[0];
1180 NLMISC::fromString(args
[1], val
);
1182 if (!CStatDB::getInstance()->valueSet(path
, val
))
1184 log
.displayNL("cannot find a value leaf at the path '%s'", path
.c_str());
1190 // ****************************************************************************
1191 NLMISC_COMMAND (sdbValueAdd
, "add a value to a value leaf in SDB", "<path> <value>")
1193 if (args
.size() != 2)
1196 const string
& path
= args
[0];
1198 NLMISC::fromString(args
[1], val
);
1200 if (!CStatDB::getInstance()->valueAdd(path
, val
))
1202 log
.displayNL("cannot find a value leaf at the path '%s'", path
.c_str());
1208 // ****************************************************************************
1209 NLMISC_COMMAND (sdbTableAdd
, "add a value to a table leaf in SDB", "<path> <value> <target=player|guild> <player_id|guild_name>")
1211 if (args
.size() != 4)
1214 const string
& path
= args
[0];
1216 NLMISC::fromString(args
[1], val
);
1217 const string
& targetType
= args
[2];
1219 if (targetType
== "guild")
1221 CGuild
* guild
= CGuildManager::getInstance()->getGuildByName(args
[3]);
1224 log
.displayNL("unknown guild: '%s'", args
[3].c_str());
1228 if (!CStatDB::getInstance()->tableGuildAdd(path
, guild
->getId(), val
))
1230 log
.displayNL("cannot find a table leaf at the path '%s'", path
.c_str());
1236 playerId
.fromString(args
[3].c_str());
1238 if (playerId
.getType() != RYZOMID::player
)
1240 log
.displayNL("id %s is not a player id", playerId
.toString().c_str());
1244 if (!CEntityIdTranslator::getInstance()->isEntityRegistered(playerId
))
1246 log
.displayNL("player id %s is unknown", playerId
.toString().c_str());
1250 if (!CStatDB::getInstance()->tablePlayerAdd(path
, playerId
, val
))
1252 log
.displayNL("cannot find a table leaf at the path '%s'", path
.c_str());
1259 // ****************************************************************************
1260 NLMISC_COMMAND (sdbRemovePlayer
, "remove a player from the whole SDB", "<player_id>")
1262 if (args
.size() != 1)
1266 playerId
.fromString(args
[0].c_str());
1268 CStatDB::getInstance()->removePlayer(playerId
);
1273 // ****************************************************************************
1274 NLMISC_COMMAND (sdbRemoveGuild
, "remove a guild from the whole SDB", "<guild_name>")
1276 if (args
.size() != 1)
1279 CGuild
* guild
= CGuildManager::getInstance()->getGuildByName(args
[0]);
1282 log
.displayNL("unknown guild: '%s'", args
[0].c_str());
1286 CStatDB::getInstance()->removeGuild(guild
->getId());
1291 // ****************************************************************************
1292 NLMISC_COMMAND (sdbDisplayNodes
, "display nodes of SDB", "<path> [<recursive>] [<display_values>] [<display_tables>]")
1294 if (args
.size() < 1 || args
.size() > 4)
1297 const string
& pathPattern
= args
[0];
1299 CStatDBNodeDisplayer::CSettings settings
;
1301 if (args
.size() >= 2)
1302 settings
.Recursive
= (args
[1] == "1" || args
[1] == "true");
1304 if (args
.size() >= 3)
1305 settings
.DisplayValueLeafContent
= (args
[2] == "1" || args
[2] == "true");
1307 if (args
.size() >= 4)
1308 settings
.DisplayTableLeafContent
= (args
[3] == "1" || args
[3] == "true");
1310 settings
.DisplayBranch
= !settings
.Recursive
;
1312 if (!CStatDB::getInstance()->displayNodes(pathPattern
, log
, settings
))
1314 log
.displayNL("path '%s' not found", pathPattern
.c_str());
1320 // ****************************************************************************
1321 NLMISC_COMMAND (sdbSaveNow
, "save the whole SDB now (WARNING: it may stall the shard and flood the Backup Service)", "")
1323 if (args
.size() != 0)
1326 CStatDB::getInstance()->saveAll();
1334 extern NLMISC::CRandom RandomGenerator
;
1335 // ****************************************************************************
1336 NLMISC_COMMAND (sdbInitEpisode2
, "(debug) init fake database for Episode2 tests", "")
1339 // Leaf simple pour le harvest
1340 const char *peuple
[] = { "fyros", "matis", "tryker", "zorai" };
1341 uint peupleNB
= sizeof(peuple
)/sizeof(peuple
[0]);
1342 const char *faction
[] = { "kami", "karavan" };
1343 uint factionNB
= sizeof(faction
)/sizeof(faction
[0]);
1344 const char *mp
[] = { "carapace_a", "resine_a", "bois_a", "fibre_o","resine_o", "ecorce_o",
1345 "carapace_i", "resine_i", "boucle_i", "bois_i" };
1346 uint mpNB
= sizeof(mp
)/sizeof(mp
[0]);
1347 const char *mpByFaction
[] = { "seve", "amber" };
1348 uint mpByFactionNB
= sizeof(mpByFaction
)/sizeof(mpByFaction
[0]);
1350 for (uint i
= 0; i
< peupleNB
; ++i
)
1351 for (uint j
= 0; j
< factionNB
; ++j
)
1353 string sPath
= "storyline.episode2.";
1354 sPath
+= toString(peuple
[i
]) + ".";
1355 sPath
+= toString(faction
[j
]) + ".";
1356 for (uint k
= 0; k
< mpNB
; ++k
)
1358 string sTmpPath
= sPath
+ mp
[k
];
1359 CStatDB::getInstance()->createValue(sTmpPath
+toString(".qtemin"), RandomGenerator
.rand(500));
1360 CStatDB::getInstance()->createValue(sTmpPath
+toString(".qtemax"), RandomGenerator
.rand(500));
1362 CStatDB::getInstance()->createValue(sPath
+mpByFaction
[j
]+toString(".qtemin"), RandomGenerator
.rand(500));
1363 CStatDB::getInstance()->createValue(sPath
+mpByFaction
[j
]+toString(".qtemax"), RandomGenerator
.rand(500));
1366 // Leaf simple pour le craft
1367 const char *craft
[] = { "socle", "colonne", "comble", "muraille", "revetement", "ornement", "statue",
1368 "colonne_justice", "racine", "tronc", "fibre", "ecorce", "feuille", "fleur", "symbole", "noyau" };
1369 uint craftNB
= sizeof(craft
)/sizeof(craft
[0]);
1370 for (uint i
= 0; i
< peupleNB
; ++i
)
1372 for (uint j
= 0; j
< craftNB
; ++j
)
1374 string sPath
= "storyline.episode2.";
1375 sPath
+= toString(peuple
[i
]) + ".";
1376 sPath
+= toString(craft
[j
]);
1377 CStatDB::getInstance()->createValue(sPath
+toString(".qtemin"), RandomGenerator
.rand(500));
1378 CStatDB::getInstance()->createValue(sPath
+toString(".qtemax"), RandomGenerator
.rand(500));
1382 // Leaf simple pour les maxima
1383 const char *max_values
[] = { "socle_max", "colonne_max", "comble_max", "muraille_max", "revetement_max",
1384 "ornement_max", "statue_max", "colonne_justice_max", "racine_max", "tronc_max", "fibre_max",
1385 "ecorce_max", "feuille_max", "fleur_max", "symbole_max", "noyau_max" };
1386 uint max_valuesNB
= sizeof(max_values
)/sizeof(max_values
[0]);
1387 for (uint i
= 0; i
< peupleNB
; ++i
)
1389 for (uint j
= 0; j
< max_valuesNB
; ++j
)
1391 string sPath
= "storyline.episode2.";
1392 sPath
+= toString(peuple
[i
]) + ".";
1393 sPath
+= toString(max_values
[j
]);
1394 CStatDB::getInstance()->createValue(sPath
, 500 + RandomGenerator
.rand(500));
1398 // Tableaux de joueurs
1399 const char *action
[] = { "craft", "harvest", "kill" };
1400 uint actionNB
= sizeof(action
)/sizeof(action
[0]);
1401 const char *acte
[] = { "acte1", "acte2", "acte3" };
1402 uint acteNB
= sizeof(acte
)/sizeof(acte
[0]);
1403 for (uint i
= 0; i
< peupleNB
; ++i
)
1404 for (uint j
= 0; j
< factionNB
; ++j
)
1405 for (uint k
= 0; k
< actionNB
; ++k
)
1406 for (uint m
= 0; m
< acteNB
; ++m
)
1408 string sPath
= "storyline.episode2.";
1409 sPath
+= toString(peuple
[i
]) + ".";
1410 sPath
+= toString(faction
[j
]) + ".";
1411 sPath
+= toString(action
[k
]) + ".";
1412 sPath
+= toString(acte
[m
]);
1414 CStatDB::getInstance()->createTable(sPath
);
1416 uint nbjoueur
= 100+RandomGenerator
.rand(400);
1417 for (uint n
= 0; n
< nbjoueur
; ++n
)
1420 playerId
.setShortId(RandomGenerator
.rand(5000) << 4);
1421 playerId
.setType(RYZOMID::player
);
1422 CStatDB::getInstance()->tablePlayerAdd(sPath
, playerId
, 10 * RandomGenerator
.rand(5000));
1425 uint nbguild
= 250+RandomGenerator
.rand(250);
1426 for (uint n
= 0; n
< nbguild
; ++n
)
1429 EGSPD::TGuildId guildId
= uint32(RandomGenerator
.rand(20500));
1430 CStatDB::getInstance()->tableGuildAdd(sPath
, guildId
, 100 * RandomGenerator
.rand(10000));
1437 #endif // !FINAL_VERSION