2010-05-06 00:08:41 +00:00
// 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 ) ;
2010-05-13 20:45:24 +00:00
nb + = ( uint ) actionStore . second . size ( ) ;
2010-05-06 00:08:41 +00:00
}
return nb ;
}
uint CActionFactory : : getNbActionsInStore ( uint code )
{
2010-05-13 20:45:24 +00:00
return ( uint ) RegisteredAction [ code ] . second . size ( ) ;
2010-05-06 00:08:41 +00:00
}
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 ;
}