393 lines
9.8 KiB
C++
393 lines
9.8 KiB
C++
|
// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
|
||
|
// 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 <http://www.gnu.org/licenses/>.
|
||
|
|
||
|
|
||
|
|
||
|
#include "stdpch.h"
|
||
|
|
||
|
//
|
||
|
// Includes
|
||
|
//
|
||
|
|
||
|
#include <string>
|
||
|
#include <queue>
|
||
|
|
||
|
#include <nel/misc/types_nl.h>
|
||
|
#include <nel/misc/debug.h>
|
||
|
|
||
|
#include <nel/net/udp_sock.h>
|
||
|
|
||
|
#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<NB_VISUAL_PROPERTIES; ++i)
|
||
|
_VolatileActions[i] = NULL;
|
||
|
}
|
||
|
|
||
|
|
||
|
CActionFactory::~CActionFactory()
|
||
|
{
|
||
|
uint nbDeleted = 0;
|
||
|
for ( std::vector<TActionStore>::iterator iv=RegisteredAction.begin(); iv!=RegisteredAction.end(); ++iv )
|
||
|
{
|
||
|
TActionStore& actionStore = (*iv);
|
||
|
for ( std::vector<CAction*>::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<TActionStore>::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<CAction*>()));
|
||
|
|
||
|
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<CAction*>(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 <CAction *>& 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; i<NB_VISUAL_PROPERTIES; ++i)
|
||
|
_VolatileActions[i] = (CActionSint64*)createByPropIndex( 0, i );
|
||
|
|
||
|
_VolatilePosition = (CActionPosition*)(createByPropIndex( 0, PROPERTY_POSITION ));
|
||
|
}
|
||
|
|
||
|
void CActionFactory::releaseVolatileProperties()
|
||
|
{
|
||
|
for (uint i=PROPERTY_ORIENTATION; i<NB_VISUAL_PROPERTIES; ++i)
|
||
|
{
|
||
|
CAction* action = _VolatileActions[i];
|
||
|
remove(action);
|
||
|
_VolatileActions[i] = NULL;
|
||
|
}
|
||
|
|
||
|
CAction* action = _VolatilePosition;
|
||
|
remove(action);
|
||
|
_VolatilePosition = NULL;
|
||
|
}
|
||
|
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
NLMISC_COMMAND( displayActionVectors, "Display the size of action vector in factory", "" )
|
||
|
{
|
||
|
uint nbActionsInStore = CLFECOMMON::CActionFactory::getInstance()->getNbActionsInStore();
|
||
|
log.displayNL( "%u actions in factory store", nbActionsInStore );
|
||
|
return true;
|
||
|
}
|
||
|
|