Add infos into target window
[ryzomcore.git] / ryzom / server / src / entities_game_service / stat_db.cpp
blob4c8b490eb773ffa1f6c7a942b2d82d4c1b3ee875
1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
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.
8 //
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/>.
18 #include "stdpch.h"
19 #include "stat_db.h"
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"
32 using namespace std;
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 // ****************************************************************************
45 // Helpers
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);
59 if (guild == NULL)
60 return false;
62 guildName = guild->getName().toUtf8();
63 return true;
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();
71 ++it)
73 const CEntityId & playerId = (*it).first;
75 string playerName;
76 if (!getPlayerName(playerId, playerName))
78 #if FINAL_VERSION
79 nlwarning("SDB: cannot find the name of the player %s", playerId.toString().c_str());
80 #endif // FINAL_VERSION
81 continue;
84 namesMsg.PlayerNames[playerId] = playerName;
87 for ( map<EGSPD::TGuildId,sint32>::const_iterator it = tableLeafMsg.GuildValues.begin();
88 it != tableLeafMsg.GuildValues.end();
89 ++it)
91 const EGSPD::TGuildId & guildId = (*it).first;
93 string guildName;
94 if (!getGuildName(guildId, guildName))
96 #if FINAL_VERSION
97 nlwarning("SDB: cannot find the name of the guild %u", guildId);
98 #endif // FINAL_VERSION
99 continue;
102 namesMsg.GuildNames[guildId] = guildName;
106 // ****************************************************************************
107 // CStatDBBackupLeafCollector
108 // ****************************************************************************
110 // ****************************************************************************
111 void CStatDBBackupLeafCollector::loadLeaves(IStatDBNodePtr root)
113 nlassert(root != NULL);
115 clearLeaves();
116 _Root = root;
117 _Root->acceptVisitor(*this, "");
120 // ****************************************************************************
121 bool CStatDBBackupLeafCollector::popTableLeafPD(CStatDBTableLeafPD & tableLeafPD)
123 if (_Root == NULL)
124 return false;
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();
137 return true;
141 return false;
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)
208 _Log = &log;
210 if (_Settings.Recursive)
212 node->acceptVisitor(*this, currentPath);
214 else
216 displayOneNode(node, currentPath);
218 // if the node is a branch
219 CStatDBBranch * branch = dynamic_cast<CStatDBBranch *>(node.getPtr());
220 if (branch != NULL)
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);
228 return;
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());
239 if (branch != NULL)
241 visitBranch(branch, currentPath);
242 return;
245 CStatDBValueLeaf * valueLeaf = dynamic_cast<CStatDBValueLeaf *>(node.getPtr());
246 if (valueLeaf != NULL)
248 visitValueLeaf(valueLeaf, currentPath);
249 return;
252 CStatDBTableLeaf * tableLeaf = dynamic_cast<CStatDBTableLeaf *>(node.getPtr());
253 if (tableLeaf != NULL)
255 visitTableLeaf(tableLeaf, currentPath);
256 return;
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());
276 else
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();
291 ++it)
293 string playerName;
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();
304 ++it)
306 string guildName;
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 // ****************************************************************************
319 // CStatDB
320 // ****************************************************************************
322 // ****************************************************************************
323 CStatDB::CStatDB()
325 _Root = new CStatDBBranch;
326 _SDBIsLoaded = false;
327 _GuildsAreLoaded = false;
328 _MFSIsUp = false;
329 _MFSIsInitialized = false;
332 // ****************************************************************************
333 bool CStatDB::createValue(const std::string & path, sint32 val)
335 nlassert(_SDBIsLoaded);
337 IStatDBNodePtr node = _Root->getNode(path);
338 if (node != NULL)
339 return false;
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);
356 return res;
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)
366 return false;
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));
377 msgout.serial(val);
378 CUnifiedNetwork::getInstance()->send("MFS", msgout);
381 return true;
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)
391 return false;
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));
402 msgout.serial(val);
403 CUnifiedNetwork::getInstance()->send("MFS", msgout);
406 return true;
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)
416 return false;
418 val = valueLeaf->getValue();
419 return true;
422 // ****************************************************************************
423 bool CStatDB::createTable(const std::string & path)
425 nlassert(_SDBIsLoaded);
427 IStatDBNodePtr node = _Root->getNode(path);
428 if (node != NULL)
429 return false;
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);
443 if (node != NULL)
444 return false;
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);
466 return res;
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)
476 return false;
478 tableLeaf->playerAdd(playerId, val);
480 if (_MFSIsInitialized)
482 uint32 shardId = IService::getInstance()->getShardId();
483 string playerName;
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);
491 msgout.serial(val);
492 CUnifiedNetwork::getInstance()->send("MFS", msgout);
495 return true;
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)
505 return false;
507 tableLeaf->playerSet(playerId, val);
509 if (_MFSIsInitialized)
511 uint32 shardId = IService::getInstance()->getShardId();
512 string playerName;
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);
520 msgout.serial(val);
521 CUnifiedNetwork::getInstance()->send("MFS", msgout);
524 return true;
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)
534 return false;
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)
546 return false;
548 tableLeaf->guildAdd(guildId, val);
550 if (_MFSIsInitialized)
552 uint32 shardId = IService::getInstance()->getShardId();
553 string guildName;
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);
561 msgout.serial(val);
562 CUnifiedNetwork::getInstance()->send("MFS", msgout);
565 return true;
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)
575 return false;
577 tableLeaf->guildSet(guildId, val);
579 if (_MFSIsInitialized)
581 uint32 shardId = IService::getInstance()->getShardId();
582 string guildName;
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);
590 msgout.serial(val);
591 CUnifiedNetwork::getInstance()->send("MFS", msgout);
594 return true;
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)
604 return false;
606 return tableLeaf->guildGet(guildId, val);
609 // ****************************************************************************
610 class CStatDBBackupFileCleaner : private CStatDBNodeVisitor
612 public:
613 void submitRemovedNode(IStatDBNodePtr removedNode, const std::string & removedNodePath, bool keepBackupOfFiles)
615 _KeepBackupOfFiles = keepBackupOfFiles;
616 if (removedNode != NULL)
617 removedNode->acceptVisitor(*this, removedNodePath);
620 private:
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);
627 private:
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);
648 if (res)
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);
656 return res;
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, "");
697 if (nodes.empty())
698 return false;
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);
708 return true;
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;
727 pdr.clear();
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);
740 if (node == NULL)
742 bool res = _Root->setNode(valueLeafPD.Path, new CStatDBValueLeaf(valueLeafPD.Value));
743 if (!res)
745 nlwarning("value leaf '%s' cannot be created!", valueLeafPD.Path.c_str());
746 DEBUG_STOP;
749 else
751 nlwarning("leaf '%s' already exists!", valueLeafPD.Path.c_str());
752 DEBUG_STOP;
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;
790 pdr.clear();
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);
799 if (node == NULL)
801 bool res = _Root->setNode(tableLeafPD.Path, new CStatDBTableLeaf(tableLeafPD.PlayerValues, tableLeafPD.GuildValues));
802 if (!res)
804 nlwarning("table leaf '%s' cannot be created!", tableLeafPD.Path.c_str());
805 DEBUG_STOP;
808 else
810 nlwarning("leaf '%s' already exists!", tableLeafPD.Path.c_str());
811 DEBUG_STOP;
817 // ****************************************************************************
818 void CStatDB::load()
820 H_AUTO(CStatDB_load);
822 if (EGSLight)
824 _SDBIsLoaded = true;
825 return;
828 if (_SDBIsLoaded)
829 return;
831 nTotalLoaded = 0;
833 // // create SDB path
834 // {
835 // string sPath = Bsi.getLocalPath() + "sdb";
836 // if (!CFile::isExists(sPath))
837 // CFile::createDirectory(sPath);
838 // }
840 // load value leaves
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))
852 // {
853 // static CPersistentDataRecord pdr;
854 // pdr.clear();
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)
862 // {
863 // const CStatDBValueLeafPD & valueLeafPD = valueLeavesPD.ValueLeavesPD[i];
865 // IStatDBNodePtr node = _Root->getNode(valueLeafPD.Path);
866 // if (node == NULL)
867 // {
868 // bool res = _Root->setNode(valueLeafPD.Path, new CStatDBValueLeaf(valueLeafPD.Value));
869 // if (!res)
870 // {
871 // nlwarning("value leaf '%s' cannot be created!", valueLeafPD.Path.c_str());
872 // DEBUG_STOP;
873 // }
874 // }
875 // else
876 // {
877 // nlwarning("leaf '%s' already exists!", valueLeafPD.Path.c_str());
878 // DEBUG_STOP;
879 // }
880 // }
881 // }
884 // load table leaves
885 // string sdbSavePath = Bsi.getLocalPath() + "sdb";
888 // get the file list
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);
894 // load the files
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++)
901 // {
902 // const string & fileName = files[i];
904 // if ( CFile::getFilename(fileName).substr(0, 11) == "table_leaf_"
905 // && CFile::getExtension(fileName) == (XMLSave?"xml":"bin"))
906 // {
907 // H_AUTO(CStatDB_load_2);
909 // static CPersistentDataRecord pdr;
910 // pdr.clear();
911 // CStatDBTableLeafPD tableLeafPD;
913 // pdr.readFromFile(fileName);
914 // tableLeafPD.apply(pdr);
915 // nTotalLoaded += CFile::getFileSize(fileName);
917 // IStatDBNodePtr node = _Root->getNode(tableLeafPD.Path);
918 // if (node == NULL)
919 // {
920 // bool res = _Root->setNode(tableLeafPD.Path, new CStatDBTableLeaf(tableLeafPD.PlayerValues, tableLeafPD.GuildValues));
921 // if (!res)
922 // {
923 // nlwarning("table leaf '%s' cannot be created!", tableLeafPD.Path.c_str());
924 // DEBUG_STOP;
925 // }
926 // }
927 // else
928 // {
929 // nlwarning("leaf '%s' already exists!", tableLeafPD.Path.c_str());
930 // DEBUG_STOP;
931 // }
932 // }
933 // }
935 nlinfo("SDB: loaded %u bytes", nTotalLoaded);
937 _SDBIsLoaded = true;
938 if (canInitMFS())
939 initMFS();
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)
956 return;
958 uint32 shardId = IService::getInstance()->getShardId();
959 if ( shardId == DEFAULT_SHARD_ID )
961 #ifdef NL_OS_WINDOWS
962 nlwarning
963 #else
964 nlerror
965 #endif
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()
985 _MFSIsUp = true;
986 if (canInitMFS())
987 initMFS();
990 // ****************************************************************************
991 void CStatDB::cbMFServiceDown()
993 _MFSIsUp = false;
994 _MFSIsInitialized = false;
997 // ****************************************************************************
998 void CStatDB::cbGuildsLoaded()
1000 _GuildsAreLoaded = true;
1001 if (canInitMFS())
1002 initMFS();
1005 // ****************************************************************************
1006 void CStatDB::tickUpdate()
1008 H_AUTO(CStatDB_tickUpdate);
1010 if (!_SDBIsLoaded)
1011 return;
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)
1021 return;
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();
1033 else
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;
1065 pdr.clear();
1066 valueLeavesPD.store(pdr);
1068 CBackupMsgSaveFile msg( sFilePath, CBackupMsgSaveFile::SaveFile, Bsi );
1069 if (XMLSave)
1071 string s;
1072 pdr.toString(s);
1073 msg.DataMsg.serialBuffer((uint8*)&s[0], (uint)s.size());
1075 else
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;
1093 pdr.clear();
1094 tableLeafPD.store(pdr);
1096 CBackupMsgSaveFile msg( sFilePath, CBackupMsgSaveFile::SaveFile, Bsi );
1097 if (XMLSave)
1099 string s;
1100 pdr.toString(s);
1101 msg.DataMsg.serialBuffer((uint8*)&s[0], (uint)s.size());
1103 else
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 // ****************************************************************************
1116 // Commands
1117 // ****************************************************************************
1119 // ****************************************************************************
1120 NLMISC_COMMAND (sdbCreateValue, "create a value leaf in SDB", "<path> [<value>]")
1122 if (args.size() < 1 || args.size() > 2)
1123 return false;
1125 const string & path = args[0];
1126 sint32 val;
1127 if (args.size() < 2)
1128 val = 0;
1129 else
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)",
1135 path.c_str());
1138 return true;
1141 // ****************************************************************************
1142 NLMISC_COMMAND (sdbCreateTable, "create a table leaf in SDB", "<path>")
1144 if (args.size() != 1)
1145 return false;
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)",
1151 path.c_str());
1154 return true;
1157 // ****************************************************************************
1158 NLMISC_COMMAND (sdbRemoveNode, "remove a node from SDB", "<path>")
1160 if (args.size() != 1)
1161 return false;
1163 const string & path = args[0];
1164 if (!CStatDB::getInstance()->removeNode(path))
1166 log.displayNL("path '%s' not found", path.c_str());
1169 return true;
1172 // ****************************************************************************
1173 NLMISC_COMMAND (sdbValueSet, "set a value leaf in SDB", "<path> <value>")
1175 if (args.size() != 2)
1176 return false;
1178 const string & path = args[0];
1179 sint32 val;
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());
1187 return true;
1190 // ****************************************************************************
1191 NLMISC_COMMAND (sdbValueAdd, "add a value to a value leaf in SDB", "<path> <value>")
1193 if (args.size() != 2)
1194 return false;
1196 const string & path = args[0];
1197 sint32 val;
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());
1205 return true;
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)
1212 return false;
1214 const string & path = args[0];
1215 sint32 val;
1216 NLMISC::fromString(args[1], val);
1217 const string & targetType = args[2];
1219 if (targetType == "guild")
1221 CGuild * guild = CGuildManager::getInstance()->getGuildByName(args[3]);
1222 if (guild == NULL)
1224 log.displayNL("unknown guild: '%s'", args[3].c_str());
1225 return true;
1228 if (!CStatDB::getInstance()->tableGuildAdd(path, guild->getId(), val))
1230 log.displayNL("cannot find a table leaf at the path '%s'", path.c_str());
1233 else
1235 CEntityId playerId;
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());
1241 return true;
1244 if (!CEntityIdTranslator::getInstance()->isEntityRegistered(playerId))
1246 log.displayNL("player id %s is unknown", playerId.toString().c_str());
1247 return true;
1250 if (!CStatDB::getInstance()->tablePlayerAdd(path, playerId, val))
1252 log.displayNL("cannot find a table leaf at the path '%s'", path.c_str());
1256 return true;
1259 // ****************************************************************************
1260 NLMISC_COMMAND (sdbRemovePlayer, "remove a player from the whole SDB", "<player_id>")
1262 if (args.size() != 1)
1263 return false;
1265 CEntityId playerId;
1266 playerId.fromString(args[0].c_str());
1268 CStatDB::getInstance()->removePlayer(playerId);
1270 return true;
1273 // ****************************************************************************
1274 NLMISC_COMMAND (sdbRemoveGuild, "remove a guild from the whole SDB", "<guild_name>")
1276 if (args.size() != 1)
1277 return false;
1279 CGuild * guild = CGuildManager::getInstance()->getGuildByName(args[0]);
1280 if (guild == NULL)
1282 log.displayNL("unknown guild: '%s'", args[0].c_str());
1283 return true;
1286 CStatDB::getInstance()->removeGuild(guild->getId());
1288 return true;
1291 // ****************************************************************************
1292 NLMISC_COMMAND (sdbDisplayNodes, "display nodes of SDB", "<path> [<recursive>] [<display_values>] [<display_tables>]")
1294 if (args.size() < 1 || args.size() > 4)
1295 return false;
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());
1317 return true;
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)
1324 return false;
1326 CStatDB::getInstance()->saveAll();
1328 return true;
1332 #if !FINAL_VERSION
1334 extern NLMISC::CRandom RandomGenerator;
1335 // ****************************************************************************
1336 NLMISC_COMMAND (sdbInitEpisode2, "(debug) init fake database for Episode2 tests", "")
1338 // Episode II init
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)
1419 CEntityId playerId;
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));
1434 return true;
1437 #endif // !FINAL_VERSION