// 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;
}