// 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 RY_STAT_DB_TREE_H #define RY_STAT_DB_TREE_H #include "nel/misc/smart_ptr.h" #include "nel/misc/static_map.h" #include "nel/misc/entity_id.h" #include "nel/misc/log.h" #include "stat_db_common.h" #include "stat_db_tree_visitor.h" class IStatDBNode; typedef NLMISC::CSmartPtr IStatDBNodePtr; /** * Node structure of the statistical database, * this is the base for branches and leaves. * * A path is a string composed of keys separated with a '.' * A key is an alphanumeric string: [0-9A-Za-z_]* * Example of path: "branch1_name.branch2_name.leaf1" * * A path pattern can contain wildcard keys: * Wildcard key '*' means any key * * \author Matthieu 'Trap' Besson * \author Nevrax France * \date 2005 July */ class IStatDBNode : public NLMISC::CRefCount { public: struct CMatchingNode { std::string Path; IStatDBNodePtr Node; }; public: /// virtual dtor virtual ~IStatDBNode() {} /// add a node at the given path, it creates the path if necessary /// NOTE: if another node is already at the given path it is replaced virtual bool setNode(const std::string & path, IStatDBNodePtr node) = 0; /// get the node at the given path or NULL if the path does not exist virtual IStatDBNodePtr getNode(const std::string & path) = 0; /// get all nodes whose path matches the given pattern /// \param pathPattern : a path pattern /// \param matchingNodes : return the matching nodes /// \param currentPath : the current path /// WARNING: the vector 'matchingNodes' will not be cleared by this method before matching nodes are added virtual void getNodes(const std::string & pathPattern, std::vector & matchingNodes, const std::string & currentPath) = 0; /// remove and return the node at the given path virtual IStatDBNodePtr removeNode(const std::string & path) = 0; /// accept a visitor (visitor design pattern) /// \param currentPath : the path of this node virtual void acceptVisitor(CStatDBNodeVisitor & visitor, const std::string & currentPath) = 0; }; /** * Leaf structure of the statistical database. * * \author Matthieu 'Trap' Besson * \author Nevrax France * \date 2005 July */ class CStatDBLeaf : public IStatDBNode { public: virtual ~CStatDBLeaf() {} bool setNode(const std::string & /* path */, IStatDBNodePtr /* node */) { return false; } IStatDBNodePtr getNode(const std::string & /* path */) { return NULL; } void getNodes(const std::string & /* pathPattern */, std::vector & /* matchingNodes */, const std::string & /* currentPath */) {} IStatDBNodePtr removeNode(const std::string & /* path */) { return NULL; } virtual void acceptVisitor(CStatDBNodeVisitor & /* visitor */, const std::string & /* currentPath */) {} }; /** * Simple value leaf structure of the statistical database * * \author Matthieu 'Trap' Besson * \author Nevrax France * \date 2005 July */ class CStatDBValueLeaf : public CStatDBLeaf { public: /// ctor CStatDBValueLeaf(sint32 val = 0) : _Value(val) {} /// set value void setValue(sint32 val) { _Value = val; } /// get value sint32 getValue() { return _Value; } /// add value void addValue(sint32 val) { _Value += val; } void acceptVisitor(CStatDBNodeVisitor & visitor, const std::string & currentPath) { visitor.visitValueLeaf(this, currentPath); } private: sint32 _Value; }; /** * Leaf structure of the statistical database retaining info for players and guilds. * For the moment a table leaf removes entries with a value <= 0 (cf playerAdd() and guildAdd() methods). * It is typically made to store some positive scores, * but it may support both signed and unsigned scores in the future. * * \author Matthieu 'Trap' Besson * \author Nevrax France * \date 2005 July */ class CStatDBTableLeaf : public CStatDBLeaf { public: typedef std::map TPlayerValues; typedef std::map TGuildValues; public: /// ctor CStatDBTableLeaf() {} CStatDBTableLeaf(const TPlayerValues & playerValues, const TGuildValues & guildValues) : _PlayerValues(playerValues), _GuildValues(guildValues) { } /// add a value to a player /// NOTE: if the new value of the player is <= 0 the player entry is removed void playerAdd(NLMISC::CEntityId playerId, sint32 val); /// add a value to a guild /// NOTE: if the new value of the guild is <= 0 the guild entry is removed void guildAdd(EGSPD::TGuildId guildId, sint32 val); /// set a player value /// NOTE: if the new value of the player is <= 0 the player entry is removed void playerSet(NLMISC::CEntityId playerId, sint32 val); /// set a guild value /// NOTE: if the new value of the guild is <= 0 the guild entry is removed void guildSet(EGSPD::TGuildId guildId, sint32 val); /// get a value of a player bool playerGet(NLMISC::CEntityId playerId, sint32 & val) const; /// get a value of a guild bool guildGet(EGSPD::TGuildId guildId, sint32 & val) const; /// get player values const TPlayerValues & getPlayerValues() const { return _PlayerValues; } /// get guild values const TGuildValues & getGuildValues() const { return _GuildValues; } /// remove a player from the table void removePlayer(NLMISC::CEntityId playerId); /// remove a guild from the table void removeGuild(EGSPD::TGuildId guildId); void acceptVisitor(CStatDBNodeVisitor & visitor, const std::string & currentPath) { visitor.visitTableLeaf(this, currentPath); } private: TPlayerValues _PlayerValues; TGuildValues _GuildValues; }; /** * Branch structure of the statistical database. * We use a static map for branches because we will not add branches all days its a * 'created once read/write multiple' type of structure. * * \author Matthieu 'Trap' Besson * \author Nevrax France * \date 2005 July */ class CStatDBBranch : public IStatDBNode { public: bool setNode(const std::string & path, IStatDBNodePtr node); IStatDBNodePtr getNode(const std::string & path); void getNodes(const std::string & pathPattern, std::vector & matchingNodes, const std::string & currentPath); IStatDBNodePtr removeNode(const std::string & path); void acceptVisitor(CStatDBNodeVisitor & visitor, const std::string & currentPath); private: bool isValidToken(const std::string & token) const; void splitPath(const std::string & path, std::string & token, std::string & rest) const; private: typedef NLMISC::CStaticMap TChildren; TChildren _Children; }; /** * This class removes entities (players and guilds) through a SDB node * * \author Sebastien 'kxu' Guignot * \author Nevrax France * \date 2005 July */ class CStatDBEntitiesRemoval : private CStatDBNodeVisitor { public: /// queue a player to remove void addPlayerToRemove(NLMISC::CEntityId playerId); /// queue a guild to remove void addGuildToRemove(EGSPD::TGuildId guildId); /// process removal of players and guilds actually queued and flush them void processRemoval(IStatDBNodePtr root); private: void visitTableLeaf(CStatDBTableLeaf * tableLeaf, const std::string & path); private: std::vector _PlayersToRemove; std::vector _GuildsToRemove; }; #endif // RY_STAT_DB_TREE_H