// Ryzom - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #include "stdmisc.h" //#define TRACE_READ_DELTA //#define TRACE_WRITE_DELTA //#define TRACE_SET_VALUE #define DELAYED_OBSERVERS ////////////// // Includes // ////////////// #include "nel/misc/cdb_leaf.h" #include "nel/misc/xml_auto_ptr.h" #include "nel/misc/bit_mem_stream.h" //#include //////////////// // Namespaces // //////////////// using namespace std; namespace NLMISC{ //----------------------------------------------- // init //----------------------------------------------- void CCDBNodeLeaf::init( xmlNodePtr node, IProgressCallback &/* progressCallBack */, bool /* mapBanks */, CCDBBankHandler * /* bankHandler */ ) { CXMLAutoPtr type((const char*)xmlGetProp (node, (xmlChar*)"type")); nlassert((const char *) type != NULL); // IF type is an INT with n bits [1,64]. if ((type.getDatas()[0] == 'I') || (type.getDatas()[0] == 'U')) { uint nbBit; fromString((const char *) (type.getDatas() + 1), nbBit); if(nbBit>=1 && nbBit<=64) _Type=(ICDBNode::EPropType)nbBit; else { nlwarning("CCDBNodeLeaf::init : property is an INT and should be between [1,64] but it is %d bit(s).", nbBit); _Type = ICDBNode::UNKNOWN; } } else if (type.getDatas()[0] == 'S') { uint nbBit; fromString((const char *) (type.getDatas() + 1), nbBit); if(nbBit>=1 && nbBit<=64) _Type = (ICDBNode::EPropType)(nbBit+64); else { nlwarning("CCDBNodeLeaf::init : property is an SINT and should be between [1,64] but it is %d bit(s).", nbBit); _Type = ICDBNode::UNKNOWN; } } // ELSE else { // IF it is a TEXT. if(!strcmp(type, "TEXT")) _Type = ICDBNode::TEXT; // ELSE type unknown. else { nlwarning("CCDBNodeLeaf::init : type '%s' is unknown.", type.getDatas()); _Type = ICDBNode::UNKNOWN; } } } // init // //----------------------------------------------- // getNode // //----------------------------------------------- ICDBNode * CCDBNodeLeaf::getNode( uint16 /* idx */ ) { return this; } // getNode // //----------------------------------------------- // getNode // //----------------------------------------------- ICDBNode * CCDBNodeLeaf::getNode (const CTextId& id, bool /* bCreate */) { if (_DBSM->localUnmap(_Name) == id.readNext()) { if (id.size() == id.getCurrentIndex()) return this; } return NULL; } // getNode // //----------------------------------------------- // write // //----------------------------------------------- void CCDBNodeLeaf::write( CTextId& id, FILE * f) { fprintf(f,"%" NL_I64 "d\t%s\n",_Property,id.toString().c_str()); } // write // //----------------------------------------------- // readDelta //----------------------------------------------- void CCDBNodeLeaf::readDelta(TGameCycle gc, CBitMemStream & f ) { // If the property Type is valid. if(_Type > UNKNOWN && _Type < Nb_Prop_Type) { // Read the Property Value according to the Property Type. uint64 recvd = 0; uint bits; if (_Type == TEXT) bits = 32; else if (_Type <= I64) bits = _Type; else bits = _Type - 64; f.serial(recvd, bits); // if the DB update is older than last DB update, abort (but after the read!!) if(gc<_LastChangeGC) return; // bkup _oldProperty _oldProperty = _Property; // setup new one _Property = (sint64)recvd; // if signed if (! ((_Type == TEXT) || (_Type <= I64))) { // extend bit sign sint64 mask = (((sint64)1)<> (bits-1))==1 ) { _Property |= ~mask; } } if ( verboseDatabase ) { nlinfo( "CDB: Read value (%u bits) %" NL_I64 "d", bits, _Property ); } // bkup the date of change _LastChangeGC= gc; notifyObservers(); } else nlwarning("CCDBNodeLeaf::readDelta : Property Type Unknown ('%d') -> not serialized.", (uint)_Type); }// readDelta // //----------------------------------------------- // resetData //----------------------------------------------- void CCDBNodeLeaf::resetData(TGameCycle gc, bool forceReset) { if(forceReset) { _LastChangeGC = 0; setValue64(0); } else if (gc>=_LastChangeGC) // apply only if happens after the DB change { _LastChangeGC = gc; setValue64(0); } // Same version but without observer notification: // if ((!forceReset) && (gc<_LastChangeGC)) // if !forceReset, apply only if happens after the DB change // return; // // if (forceReset) // gc = 0; // // _LastChangeGC = gc; // _oldProperty = _Property; // if (_Property != 0) // _Changed = true; // _Property = 0; } //----------------------------------------------- // getProp // //----------------------------------------------- sint64 CCDBNodeLeaf::getProp( CTextId& id ) { // assert that there are no lines left in the textid nlassert( id.getCurrentIndex() == id.size() ); // Return the property value. return getValue64(); } // getProp // //----------------------------------------------- // setProp // Set the value of a property (the update flag is set to true) // \param id is the text id of the property/grp // \param name is the name of the property // \param value is the value of the property // \return bool : 'false' if id is too long. //----------------------------------------------- bool CCDBNodeLeaf::setProp( CTextId& id, sint64 value ) { // assert that there are no lines left in the textid if(id.getCurrentIndex() != id.size()) return false; // Set the property value (and set "_Changed" flag with 'true'); CCDBNodeLeaf::setValue64(value); // Done return true; }// setProp // //----------------------------------------------- // setPropCheckGC //----------------------------------------------- bool CCDBNodeLeaf::setPropCheckGC(TGameCycle gc, sint64 value) { // Apply only if happens after the DB change if(gc>=_LastChangeGC) { // new recent date _LastChangeGC= gc; // Set the property value (and set "_Changed" flag with 'true'); CCDBNodeLeaf::setValue64(value); return true; } else return false; } //----------------------------------------------- // clear // //----------------------------------------------- void CCDBNodeLeaf::clear() { } // clear // //----------------------------------------------- //----------------------------------------------- void CCDBNodeLeaf::setValue64(sint64 prop) { if (_Property != prop) { if (!_Changed) { _Changed = true; } _oldProperty = _Property; _Property = prop; // notify observer notifyObservers(); } } void CCDBNodeLeaf::setValue32(sint32 prop) { sint64 newVal = (sint64)prop; setValue64(newVal); } void CCDBNodeLeaf::setValue16(sint16 prop) { sint64 newVal = (sint64)prop; setValue64(newVal); } void CCDBNodeLeaf::setValue8(sint8 prop) { sint64 newVal = (sint64)prop; setValue64(newVal); } void CCDBNodeLeaf::setValueBool(bool prop) { sint64 newVal = (sint64)prop; setValue64(newVal); } void CCDBNodeLeaf::setValueRGBA (const CRGBA &color) { sint64 newVal = (uint32)(color.R+(color.G<<8)+(color.B<<16)+(color.A<<24)); setValue64(newVal); } void CCDBNodeLeaf::display(const std::string &prefix) { nlinfo("%sL %s", prefix.c_str(), _DBSM->localUnmap(_Name).c_str()); } //----------------------------------------------- // addObserver // //----------------------------------------------- bool CCDBNodeLeaf::addObserver(IPropertyObserver* observer,CTextId& /* id */) { _Observers.push_back(observer); return true; } //----------------------------------------------- // removeObserver // //----------------------------------------------- bool CCDBNodeLeaf::removeObserver(IPropertyObserver* observer, CTextId& /* id */) { std::vector::iterator endIt = std::remove(_Observers.begin(), _Observers.end(), observer); if (endIt == _Observers.end()) return false; // no observer has been removed.. _Observers.erase(endIt, _Observers.end()); return true; } //----------------------------------------------- void CCDBNodeLeaf::notifyObservers() { std::vector obs = _Observers; // notify observer for (std::vector::const_iterator it = obs.begin(); it != obs.end(); it++) { (*it)->update(this); } // mark parent branchs if (_Parent) _Parent->onLeafChanged( _Name ); } #ifdef TRACE_READ_DELTA #undef TRACE_READ_DELTA #endif #ifdef TRACE_WRITE_DELTA #undef TRACE_WRITE_DELTA #endif #ifdef TRACE_SET_VALUE #undef TRACE_SET_VALUE #endif //############################################################################################# }