// 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 NL_CDB_GROUP_H #define NL_CDB_GROUP_H #include "nel/misc/entity_id.h" #include "player_manager/cdb_synchronised.h" #include #include "game_item_manager/guild_inv.h" class CCharacter; class IDataProvider; typedef NLMISC::CEntityId CCDBRecipient; /** * Database group. * * A group type is identified by a TCDBBank enum. * One recipient CAN'T belong to several groups of the same bank (ex: one player can belong * to 0 or 1 guild). * * What are the main advantages of using a CCDBGroup instead of duplicating changes * on several character's databases? * - Less user code. * - The data are shared, and the change trackers are shared as well (less memory needed). * - The delta buffer is built only once per tick (less CPU). * - The delta buffer is sent in one message to a FS (less network traffic). * - The number of bits used to locate properties is lower, as there is one tree per bank (less * network traffic). * * How to use the database system? * Here is a tutorial, it explains how CCDBGroup is used in the EGS. * * A. Put a CCDBSynchronised database in the character class. * Put a CCDBGroup in each group class (eg. in a guild class). * Init them with the corresponding banks. * * B. At each game cycle, here is the using process: * * 1. To populate a CCDBGroup, use addRecipient()/removeRecipient(). addRecipient() will send to it all * modifications in the group database since the beginning. removeRecipient() will ask the client to * reset the corresponding data, so that a new addRecipient() would work (the delta values need be * done with 0 as the reference value). * * 2. Your code sets some properties using Database.setProp(), either database of a particular character * or the database in a CCDBGroup (in database.xml, the branch banks must have been set likewise). * * 3. Now you want to build a delta buffer for all characters, including modifications for groups and * particular characters. * Call sendDeltas() on each CCDBGroup object. You may provide maxBitSize to limit the space used by * these groups. You need not call writeDelta() on the Database object in a CCDBGroup. A message will * be emitted to all front-ends, to send the changes to all the recipients of the group. * * 4. Call writeDelta() on the CCDBSynchronised database of every character. * You should provide maxBitSize to limit the size of the message. * The recommended available size should be provided by the network emitting system (front-end service). * Push the outbox bitmemstream of every character into an output message. You should differenciate the * initial message with other updates so that the client can react differently (it will not call any * observers for the initial message). Note: you can know the "not sent yet" flag in CCDBSynchronized * database, using setAsSent()/notSentYet(). Send the message. * * \author Olivier Cado * \author Nevrax France * \date 2004 */ class CCDBGroup { public: /// Flags for sendDeltas enum { SendDeltasToRecipients = 0, ///< If specified, send the deltas to the group's recipent list SendDeltasToAll = 1, ///< If specified, send the deltas to everyong (broadcast), ignores the recipent list }; /// Init (the singleton of CCDBStructBanks must have been initialized before) void init( TCDBBank bank ) { Database.init( bank, true ); } /** * Add a recipient. * - recipient must be ready for writing (e.g. at state 1 of above tutorial), because it will * be filled immediately with the modifications that occured before its arrival. * //Obsolete: * //- recipient must neither move in memory nor be removed between calls of addRecipient() and * //removeRecipient(). Beware with vectors and reallocation. */ void addRecipient( const CCDBRecipient& recipient ); /// Remove a recipient void removeRecipient( const CCDBRecipient& recipient ); /// Use Database to set properties CCDBSynchronised Database; /// Write and send the delta to all recipients, if there's something to write. Set maxBitSize to ~0 for no limit. /// @param[in] sendFlags A combination of Flags (see enum above) indicating how the deltas are to be sent void sendDeltas( uint32 maxBitSize, IDataProvider& dataProvider, uint8 sendFlags); /// Simpler version /// @param[in] sendFlags A combination of Flags (see enum above) indicating how the deltas are to be sent void sendDeltas( uint32 maxBitSize, uint8 sendFlags) { CFakeDataProvider dp; sendDeltas( maxBitSize, dp, sendFlags ); } private: typedef std::set< CCDBRecipient > CRecipientList; /// Recipients CRecipientList _Recipients; /// New recipients since the latest sendDeltas() std::vector< CCDBRecipient > _NewRecipients; }; #endif // NL_CDB_GROUP_H /* End of cdb_group.h */