// 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 "stdpch.h" // // Includes // #include #include #include #include #include #include "action_factory.h" // // Using // using namespace std; using namespace NLMISC; using namespace NLNET; namespace CLFECOMMON { // // Variables // CActionFactory *CActionFactory::Instance = NULL; // // Functions // CActionFactory::CActionFactory () { CActionSint64::init(); _VolatilePosition = NULL; uint i; for (i=0; i::iterator iv=RegisteredAction.begin(); iv!=RegisteredAction.end(); ++iv ) { TActionStore& actionStore = (*iv); for ( std::vector::iterator ias=actionStore.second.begin(); ias!=actionStore.second.end(); ++ias ) { delete (*ias); ++nbDeleted; } } //nldebug( "Deleted %u actions", nbDeleted ); } uint CActionFactory::getNbActionsInStore() { uint nb = 0; for ( std::vector::iterator iv=RegisteredAction.begin(); iv!=RegisteredAction.end(); ++iv ) { TActionStore& actionStore = (*iv); nb += actionStore.second.size(); } return nb; } uint CActionFactory::getNbActionsInStore(uint code) { return RegisteredAction[code].second.size(); } void CActionFactory::registerAction (uint32 code, CAction *(*creator)()) { /* CRegisteredAction::iterator it = RegisteredAction.find (code); if (it != RegisteredAction.end ()) { nlerror ("the code %u already registered in the CActionFactory", code); } RegisteredAction.insert (CRegisteredAction::value_type(code, creator)); */ if (RegisteredAction.size() > code && RegisteredAction[code].first != NULL) { nlerror ("The code %u already registered in the CActionFactory", code); } if (code >= 256) { nlerror ("Cannot register action code %d because it exceeds 255", code); } if (RegisteredAction.size() <= code) RegisteredAction.resize(code+1, make_pair((CAction *(*)())NULL, vector())); RegisteredAction[code].first = creator; } CAction *CActionFactory::create (TCLEntityId slot, TActionCode code) { if (RegisteredAction.size() <= code || RegisteredAction[code].first == NULL) { nlwarning ("CActionFactory::create() try to create an unknown action (%u)", code); return NULL; } else if (RegisteredAction[code].second.empty()) { // no action left in the store CAction *action = RegisteredAction[code].first (); // execute the factory function //nlinfo( "No action in store for code %u, creating action (total %u, total for code %u)", code, getNbActionsInStore(), getNbActionsInStore(action->Code) ); action->Code = code; action->PropertyCode = code; // default, set the property code to the action code (see create(TProperty,TPropIndex)) action->Slot = slot; action->reset(); return action; } else { // pop an action off the store CAction *action = RegisteredAction[code].second.back(); //nlinfo( "Found action in store for code %u (total %u, total for code %u)", code, getNbActionsInStore(), getNbActionsInStore(action->Code) ); RegisteredAction[code].second.pop_back(); action->reset(); action->Slot = slot; action->PropertyCode = code; return action; } } /* Create the action from a property code, fills property index and fill the internal propindex if needed * (it assumes the frontend and the client have the same mapping property/propindex). */ CAction *CActionFactory::createByPropIndex( TCLEntityId slot, TPropIndex propIndex ) { CAction *action; switch ( propIndex ) { case PROPERTY_POSITION: // same as propertyId { action = create( slot, ACTION_POSITION_CODE ); break; } default: { #ifdef NL_DEBUG nlassert( propIndex < NB_VISUAL_PROPERTIES ); #endif action = create( slot, ACTION_SINT64 ); ((CActionSint64*)action)->setNbBits( propIndex ); break; } } action->PropertyCode = propIndex; return action; } void CActionFactory::remove (CAction *&action) { if (action != NULL) { RegisteredAction[action->Code].second.push_back(action); //nlinfo( "Inserting action in store for code %u (total %u, total for code %u)", action->Code, getNbActionsInStore(), getNbActionsInStore(action->Code) ); action = NULL; } } void CActionFactory::remove (CActionImpulsion *&action) { if (action != NULL) { CAction* ptr = static_cast(action); remove(ptr); action = NULL; } } /* Pack an action to a bit stream. Set transmitTimestamp=true for server-->client, * false for client-->server. If true, set the current gamecycle. */ void CActionFactory::pack (CAction *action, NLMISC::CBitMemStream &message, NLMISC::TGameCycle /* currentCycle */ ) { //H_BEFORE(FactoryPack); //sint32 val = message.getPosInBit (); // if (action->Code < 4) { // short code (0 1 2 3) bool shortcode = true; uint32 code = action->Code; message.serialAndLog1 (shortcode); message.serialAndLog2 (code, 2); } else { bool shortcode = false; message.serialAndLog1 (shortcode); message.serialAndLog1 (action->Code); } action->pack (message); //H_AFTER(FactoryPack); //OLIV: nlassertex (message.getPosInBit () - val == (sint32)CActionFactory::getInstance()->size (action), ("CActionFactory::pack () : action %d packed %u bits, should be %u, size() is wrong", action->Code, message.getPosInBit () - val, CActionFactory::getInstance()->size (action))); // nlinfo ("ac:%p pack one action in message %d %hu %u %d", action, action->Code, (uint16)(action->CLEntityId), val, message.getPosInBit()-val); } /* Pack an action to a bit stream, for server-->client, actioncode < 4 only */ //void CActionFactory::packFast( CAction *action, NLMISC::CBitMemStream& message, NLMISC::TGameCycle currentCycle ) /* Unpack some actions from a bit stream. Set transmitTimestamp=true for server-->client, * false for client-->server. If true, set the current gamecycle. */ void CActionFactory::unpack (NLMISC::CBitMemStream &message, std::vector & actions, NLMISC::TGameCycle /* currentCycle */ ) { actions.clear (); static int n = 0; n++; while ((sint32)message.length() * 8 - message.getPosInBit () >= 8) { TActionCode code; bool shortcode; message.serial (shortcode); if (shortcode) { code = 0; uint32 val; message.serial (val, 2); code = (TActionCode) val; } else { message.serial (code); } CAction *action = create (INVALID_SLOT, code); //nlinfo ("m%d size: p:%d s:%d c:%d (actionsize: %d) slot:%hu", n, message.getPosInBit (), message.length() * 8, code, action->size(), (uint16)action->CLEntityId); if (action == NULL) { nlwarning ("Unpacking an action with unknown code, skip it (%u)", code); } else { action->unpack (message); actions.push_back (action); } } } /* Unpack an action from a bit stream. */ CAction *CActionFactory::unpack (NLMISC::CBitMemStream &message, NLMISC::TGameCycle /* currentCycle */ ) { CAction *action = NULL; if ((sint32)message.length() * 8 - message.getPosInBit () >= 8) { TActionCode code; bool shortcode; message.serial (shortcode); if (shortcode) { code = 0; uint32 val; message.serial (val, 2); code = (TActionCode) val; } else { message.serial (code); } action = create (INVALID_SLOT, (TActionCode)code); if (action == NULL) { nlwarning ("Unpacking an action with unknown code, skip it (%u)", code); } else { action->unpack (message); } } return action; } /* * Return the size IN BITS, not in bytes */ uint32 CActionFactory::size (CAction *action) { // If you change this size, please update IMPULSE_ACTION_HEADER_SIZE in the front-end /* * Warning: when calculating bit sizes, don't forget to multiply sizeof by 8 */ uint32 headerBitSize; // size of the code if (action->Code < 4) headerBitSize = 1 + 2; else headerBitSize = 1 + (sizeof (action->Code) * 8); return headerBitSize + action->size (); } void CActionFactory::initVolatileProperties() { for (uint i=PROPERTY_ORIENTATION; igetNbActionsInStore(); log.displayNL( "%u actions in factory store", nbActionsInStore ); return true; }