Merge pull request #78 from mapbase-source/feature/clientside-vscript

Proper client-side VScript control
This commit is contained in:
Blixibon 2021-01-23 14:21:41 -06:00 committed by GitHub
commit 4441911f92
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 718 additions and 103 deletions

View File

@ -281,6 +281,20 @@ BEGIN_DATADESC( C_ClientRagdoll )
END_DATADESC()
#ifdef MAPBASE_VSCRIPT
BEGIN_ENT_SCRIPTDESC( C_ClientRagdoll, C_BaseAnimating, "Client-side ragdolls" )
DEFINE_SCRIPTFUNC_NAMED( SUB_Remove, "FadeOut", "Fades out the ragdoll and removes it from the client." )
// TODO: Proper shared ragdoll funcs?
DEFINE_SCRIPTFUNC_NAMED( ScriptGetRagdollObject, "GetRagdollObject", "Gets the ragdoll object of the specified index." )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetRagdollObjectCount, "GetRagdollObjectCount", "Gets the number of ragdoll objects on this ragdoll." )
END_SCRIPTDESC();
ScriptHook_t C_BaseAnimating::g_Hook_OnClientRagdoll;
#endif
BEGIN_ENT_SCRIPTDESC( C_BaseAnimating, C_BaseEntity, "Animating models client-side" )
#ifdef MAPBASE_VSCRIPT
DEFINE_SCRIPTFUNC_NAMED( ScriptGetPoseParameter, "GetPoseParameter", "Get the specified pose parameter's value" )
@ -288,6 +302,14 @@ BEGIN_ENT_SCRIPTDESC( C_BaseAnimating, C_BaseEntity, "Animating models client-si
DEFINE_SCRIPTFUNC_NAMED( ScriptSetPoseParameter, "SetPoseParameter", "Set the specified pose parameter to the specified value" )
DEFINE_SCRIPTFUNC( IsSequenceFinished, "Ask whether the main sequence is done playing" )
#ifdef MAPBASE_VSCRIPT
DEFINE_SCRIPTFUNC( LookupAttachment, "Get the named attachement id" )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetAttachmentOrigin, "GetAttachmentOrigin", "Get the attachement id's origin vector" )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetAttachmentAngles, "GetAttachmentAngles", "Get the attachement id's angles as a p,y,r vector" )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetAttachmentMatrix, "GetAttachmentMatrix", "Get the attachement id's matrix transform" )
DEFINE_SCRIPTFUNC( LookupBone, "Get the named bone id" )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetBoneTransform, "GetBoneTransform", "Get the transform for the specified bone" )
DEFINE_SCRIPTFUNC( SetBodygroup, "Sets a bodygroup")
DEFINE_SCRIPTFUNC( GetBodygroup, "Gets a bodygroup" )
DEFINE_SCRIPTFUNC( GetBodygroupName, "Gets a bodygroup name" )
@ -302,7 +324,28 @@ BEGIN_ENT_SCRIPTDESC( C_BaseAnimating, C_BaseEntity, "Animating models client-si
DEFINE_SCRIPTFUNC( LookupActivity, "Gets the ID of the specified activity name" )
DEFINE_SCRIPTFUNC( GetSequenceName, "Gets the name of the specified sequence index" )
DEFINE_SCRIPTFUNC( GetSequenceActivityName, "Gets the activity name of the specified sequence index" )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetSequenceMoveDist, "GetSequenceMoveDist", "Gets the move distance of the specified sequence" )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetSequenceActivity, "GetSequenceActivity", "Gets the activity ID of the specified sequence index" )
DEFINE_SCRIPTFUNC_NAMED( ScriptSelectWeightedSequence, "SelectWeightedSequence", "Selects a sequence for the specified activity ID" )
DEFINE_SCRIPTFUNC( GetPlaybackRate, "" )
DEFINE_SCRIPTFUNC( SetPlaybackRate, "" )
DEFINE_SCRIPTFUNC( GetCycle, "" )
DEFINE_SCRIPTFUNC( SetCycle, "" )
DEFINE_SCRIPTFUNC( GetSkin, "Gets the model's skin" )
DEFINE_SCRIPTFUNC( SetSkin, "Sets the model's skin" )
DEFINE_SCRIPTFUNC( GetForceBone, "Gets the entity's force bone, which is used to determine which bone a ragdoll should apply its force to." )
DEFINE_SCRIPTFUNC( SetForceBone, "Sets the entity's force bone, which is used to determine which bone a ragdoll should apply its force to." )
DEFINE_SCRIPTFUNC( GetRagdollForce, "Gets the entity's ragdoll force, which is used to apply velocity to a ragdoll." )
DEFINE_SCRIPTFUNC( SetRagdollForce, "Sets the entity's ragdoll force, which is used to apply velocity to a ragdoll." )
DEFINE_SCRIPTFUNC_NAMED( ScriptBecomeRagdollOnClient, "BecomeRagdollOnClient", "" )
DEFINE_SCRIPTFUNC( IsRagdoll, "" )
BEGIN_SCRIPTHOOK( C_BaseAnimating::g_Hook_OnClientRagdoll, "OnClientRagdoll", FIELD_VOID, "Called when this entity turns into a client-side ragdoll." )
DEFINE_SCRIPTHOOK_PARAM( "ragdoll", FIELD_HSCRIPT )
END_SCRIPTHOOK()
#endif
END_SCRIPTDESC();
@ -666,6 +709,24 @@ void C_ClientRagdoll::Release( void )
BaseClass::Release();
}
#ifdef MAPBASE_VSCRIPT
HSCRIPT C_ClientRagdoll::ScriptGetRagdollObject( int iIndex )
{
if (iIndex < 0 || iIndex > m_pRagdoll->RagdollBoneCount())
{
Warning("%s GetRagdollObject: Index %i not valid (%i objects)\n", GetDebugName(), iIndex, m_pRagdoll->RagdollBoneCount());
return NULL;
}
return g_pScriptVM->RegisterInstance( m_pRagdoll->GetElement(iIndex) );
}
int C_ClientRagdoll::ScriptGetRagdollObjectCount()
{
return m_pRagdoll->RagdollBoneCount();
}
#endif
//-----------------------------------------------------------------------------
// Incremented each frame in InvalidateModelBones. Models compare this value to what it
// was last time they setup their bones to determine if they need to re-setup their bones.
@ -1429,6 +1490,61 @@ float C_BaseAnimating::ClampCycle( float flCycle, bool isLooping )
}
#ifdef MAPBASE_VSCRIPT
//-----------------------------------------------------------------------------
// Purpose: Returns the world location and world angles of an attachment to vscript caller
// Input : attachment name
// Output : location and angles
//-----------------------------------------------------------------------------
const Vector& C_BaseAnimating::ScriptGetAttachmentOrigin( int iAttachment )
{
static Vector absOrigin;
static QAngle qa;
C_BaseAnimating::GetAttachment( iAttachment, absOrigin, qa );
return absOrigin;
}
const Vector& C_BaseAnimating::ScriptGetAttachmentAngles( int iAttachment )
{
static Vector absOrigin;
static Vector absAngles;
static QAngle qa;
C_BaseAnimating::GetAttachment( iAttachment, absOrigin, qa );
absAngles.x = qa.x;
absAngles.y = qa.y;
absAngles.z = qa.z;
return absAngles;
}
HSCRIPT C_BaseAnimating::ScriptGetAttachmentMatrix( int iAttachment )
{
static matrix3x4_t matrix;
C_BaseAnimating::GetAttachment( iAttachment, matrix );
return g_pScriptVM->RegisterInstance( &matrix );
}
void C_BaseAnimating::ScriptGetBoneTransform( int iBone, HSCRIPT hTransform )
{
if (hTransform == NULL)
return;
GetBoneTransform( iBone, *HScriptToClass<matrix3x4_t>( hTransform ) );
}
HSCRIPT C_BaseAnimating::ScriptBecomeRagdollOnClient()
{
C_BaseAnimating *pRagdoll = BecomeRagdollOnClient();
if (!pRagdoll)
return NULL;
return pRagdoll->GetScriptInstance();
}
float C_BaseAnimating::ScriptGetPoseParameter( const char* szName )
{
CStudioHdr* pHdr = GetModelPtr();
@ -4736,6 +4852,17 @@ C_BaseAnimating *C_BaseAnimating::BecomeRagdollOnClient()
const float boneDt = 0.1f;
GetRagdollInitBoneArrays( boneDelta0, boneDelta1, currentBones, boneDt );
pRagdoll->InitAsClientRagdoll( boneDelta0, boneDelta1, currentBones, boneDt );
#ifdef MAPBASE_VSCRIPT
// Hook for ragdolling
if (m_ScriptScope.IsInitialized() && g_Hook_OnClientRagdoll.CanRunInScope( m_ScriptScope ))
{
// ragdoll
ScriptVariant_t args[] = { ScriptVariant_t( pRagdoll->GetScriptInstance() ) };
g_Hook_OnClientRagdoll.Call( m_ScriptScope, NULL, args );
}
#endif
return pRagdoll;
}

View File

@ -454,6 +454,28 @@ public:
virtual bool IsViewModel() const;
#ifdef MAPBASE_VSCRIPT
const Vector& ScriptGetAttachmentOrigin(int iAttachment);
const Vector& ScriptGetAttachmentAngles(int iAttachment);
HSCRIPT ScriptGetAttachmentMatrix(int iAttachment);
void ScriptGetBoneTransform( int iBone, HSCRIPT hTransform );
int ScriptGetSequenceActivity( int iSequence ) { return GetSequenceActivity( iSequence ); }
float ScriptGetSequenceMoveDist( int iSequence ) { return GetSequenceMoveDist( GetModelPtr(), iSequence ); }
int ScriptSelectWeightedSequence( int activity ) { return SelectWeightedSequence( (Activity)activity ); }
// For VScript
void SetSkin( int iSkin ) { m_nSkin = iSkin; }
int GetForceBone() { return m_nForceBone; }
void SetForceBone( int iBone ) { m_nForceBone = iBone; }
const Vector& GetRagdollForce() { return m_vecForce; }
void SetRagdollForce( const Vector &vecForce ) { m_vecForce = vecForce; }
HSCRIPT ScriptBecomeRagdollOnClient();
static ScriptHook_t g_Hook_OnClientRagdoll;
float ScriptGetPoseParameter(const char* szName);
#endif
void ScriptSetPoseParameter(const char* szName, float fValue);
@ -475,10 +497,6 @@ protected:
virtual bool CalcAttachments();
#ifdef MAPBASE_VSCRIPT
int ScriptGetSequenceActivity( int iSequence ) { return GetSequenceActivity( iSequence ); }
#endif
private:
// This method should return true if the bones have changed + SetupBones needs to be called
virtual float LastBoneChangedTime() { return FLT_MAX; }
@ -667,6 +685,9 @@ public:
C_ClientRagdoll( bool bRestoring = true );
DECLARE_CLASS( C_ClientRagdoll, C_BaseAnimating );
DECLARE_DATADESC();
#ifdef MAPBASE_VSCRIPT
DECLARE_ENT_SCRIPTDESC();
#endif
// inherited from IPVSNotify
virtual void OnPVSStatusChanged( bool bInPVS );
@ -688,6 +709,11 @@ public:
void FadeOut( void );
virtual float LastBoneChangedTime();
#ifdef MAPBASE_VSCRIPT
HSCRIPT ScriptGetRagdollObject( int iIndex );
int ScriptGetRagdollObjectCount();
#endif
bool m_bFadeOut;
bool m_bImportant;
float m_flEffectTime;

View File

@ -442,6 +442,7 @@ BEGIN_ENT_SCRIPTDESC_ROOT( C_BaseEntity, "Root class of all client-side entities
#ifdef MAPBASE_VSCRIPT
DEFINE_SCRIPTFUNC( ValidateScriptScope, "Ensure that an entity's script scope has been created" )
DEFINE_SCRIPTFUNC( GetOrCreatePrivateScriptScope, "Create and retrieve the script-side data associated with an entity" )
DEFINE_SCRIPTFUNC( GetScriptScope, "Retrieve the script-side data associated with an entity" )
DEFINE_SCRIPTFUNC( GetHealth, "" )
@ -456,23 +457,92 @@ BEGIN_ENT_SCRIPTDESC_ROOT( C_BaseEntity, "Root class of all client-side entities
DEFINE_SCRIPTFUNC( GetClassname, "" )
DEFINE_SCRIPTFUNC_NAMED( GetEntityName, "GetName", "" )
DEFINE_SCRIPTFUNC_NAMED( SetAbsOrigin, "SetOrigin", "" )
DEFINE_SCRIPTFUNC_NAMED( ScriptSetForward, "SetForwardVector", "Set the orientation of the entity to have this forward vector" )
DEFINE_SCRIPTFUNC( GetLocalOrigin, "GetLocalOrigin" )
DEFINE_SCRIPTFUNC( SetLocalOrigin, "SetLocalOrigin" )
DEFINE_SCRIPTFUNC( GetLocalAngles, "GetLocalAngles" )
DEFINE_SCRIPTFUNC( SetLocalAngles, "SetLocalAngles" )
DEFINE_SCRIPTFUNC_NAMED( WorldSpaceCenter, "GetCenter", "Get vector to center of object - absolute coords" )
DEFINE_SCRIPTFUNC_NAMED( ScriptEyePosition, "EyePosition", "Get vector to eye position - absolute coords" )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetAngles, "GetAngles", "Get entity pitch, yaw, roll as a vector" )
DEFINE_SCRIPTFUNC_NAMED( ScriptEyeAngles, "EyeAngles", "Get eye pitch, yaw, roll as a vector" )
DEFINE_SCRIPTFUNC_NAMED( GetAbsAngles, "GetAngles", "Get entity pitch, yaw, roll as a vector" )
DEFINE_SCRIPTFUNC_NAMED( SetAbsAngles, "SetAngles", "Set entity pitch, yaw, roll" )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetBoundingMins, "GetBoundingMins", "Get a vector containing min bounds, centered on object" )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetBoundingMaxs, "GetBoundingMaxs", "Get a vector containing max bounds, centered on object" )
DEFINE_SCRIPTFUNC_NAMED( ScriptEntityToWorldTransform, "EntityToWorldTransform", "Get the entity's transform" )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetPhysicsObject, "GetPhysicsObject", "Get the entity's physics object if it has one" )
DEFINE_SCRIPTFUNC( GetWaterLevel, "Get current level of water submergence" )
DEFINE_SCRIPTFUNC_NAMED( ScriptSetParent, "SetParent", "" )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetMoveParent, "GetMoveParent", "If in hierarchy, retrieves the entity's parent" )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetRootMoveParent, "GetRootMoveParent", "If in hierarchy, walks up the hierarchy to find the root parent" )
DEFINE_SCRIPTFUNC_NAMED( ScriptFirstMoveChild, "FirstMoveChild", "" )
DEFINE_SCRIPTFUNC_NAMED( ScriptNextMovePeer, "NextMovePeer", "" )
DEFINE_SCRIPTFUNC_NAMED( ScriptFollowEntity, "FollowEntity", "Begin following the specified entity. This makes this entity non-solid, parents it to the target entity, and teleports it to the specified entity's origin. The second parameter is whether or not to use bonemerging while following." )
DEFINE_SCRIPTFUNC( StopFollowingEntity, "Stops following an entity if we're following one." )
DEFINE_SCRIPTFUNC( IsFollowingEntity, "Returns true if this entity is following another entity." )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetFollowedEntity, "GetFollowedEntity", "Get the entity we're following." )
DEFINE_SCRIPTFUNC_NAMED( GetScriptOwnerEntity, "GetOwner", "Gets this entity's owner" )
DEFINE_SCRIPTFUNC_NAMED( SetScriptOwnerEntity, "SetOwner", "Sets this entity's owner" )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetColorVector, "GetRenderColorVector", "Get the render color as a vector" )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetColorR, "GetRenderColorR", "Get the render color's R value" )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetColorG, "GetRenderColorG", "Get the render color's G value" )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetColorB, "GetRenderColorB", "Get the render color's B value" )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetAlpha, "GetRenderAlpha", "Get the render color's alpha value" )
DEFINE_SCRIPTFUNC_NAMED( ScriptSetColorVector, "SetRenderColorVector", "Set the render color as a vector" )
DEFINE_SCRIPTFUNC_NAMED( ScriptSetColor, "SetRenderColor", "Set the render color" )
DEFINE_SCRIPTFUNC_NAMED( ScriptSetColorR, "SetRenderColorR", "Set the render color's R value" )
DEFINE_SCRIPTFUNC_NAMED( ScriptSetColorG, "SetRenderColorG", "Set the render color's G value" )
DEFINE_SCRIPTFUNC_NAMED( ScriptSetColorB, "SetRenderColorB", "Set the render color's B value" )
DEFINE_SCRIPTFUNC_NAMED( ScriptSetAlpha, "SetRenderAlpha", "Set the render color's alpha value" )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetRenderMode, "GetRenderMode", "Get render mode" )
DEFINE_SCRIPTFUNC_NAMED( ScriptSetRenderMode, "SetRenderMode", "Set render mode" )
DEFINE_SCRIPTFUNC( GetEffects, "Get effects" )
DEFINE_SCRIPTFUNC( AddEffects, "Add effect(s)" )
DEFINE_SCRIPTFUNC( RemoveEffects, "Remove effect(s)" )
DEFINE_SCRIPTFUNC( ClearEffects, "Clear effect(s)" )
DEFINE_SCRIPTFUNC( SetEffects, "Set effect(s)" )
DEFINE_SCRIPTFUNC( IsEffectActive, "Check if an effect is active" )
DEFINE_SCRIPTFUNC( GetFlags, "Get flags" )
DEFINE_SCRIPTFUNC( AddFlag, "Add flag" )
DEFINE_SCRIPTFUNC( RemoveFlag, "Remove flag" )
DEFINE_SCRIPTFUNC( GetEFlags, "Get Eflags" )
DEFINE_SCRIPTFUNC( AddEFlags, "Add Eflags" )
DEFINE_SCRIPTFUNC( RemoveEFlags, "Remove Eflags" )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetMoveType, "GetMoveType", "Get the move type" )
DEFINE_SCRIPTFUNC_NAMED( ScriptSetMoveType, "SetMoveType", "Set the move type" )
DEFINE_SCRIPTFUNC( GetCollisionGroup, "Get the collision group" )
DEFINE_SCRIPTFUNC( SetCollisionGroup, "Set the collision group" )
DEFINE_SCRIPTFUNC( GetSolidFlags, "Get solid flags" )
DEFINE_SCRIPTFUNC( AddSolidFlags, "Add solid flags" )
DEFINE_SCRIPTFUNC( RemoveSolidFlags, "Remove solid flags" )
DEFINE_SCRIPTFUNC( IsPlayer, "Returns true if this entity is a player." )
DEFINE_SCRIPTFUNC( IsNPC, "Returns true if this entity is a NPC." )
//DEFINE_SCRIPTFUNC( IsCombatCharacter, "Returns true if this entity is a combat character (player or NPC)." )
DEFINE_SCRIPTFUNC_NAMED( IsBaseCombatWeapon, "IsWeapon", "Returns true if this entity is a weapon." )
DEFINE_SCRIPTFUNC( IsWorld, "Returns true if this entity is the world." )
DEFINE_SCRIPTFUNC_NAMED( GetEntityIndex, "entindex", "" )
#endif
END_SCRIPTDESC();
#ifndef NO_ENTITY_PREDICTION

View File

@ -266,6 +266,7 @@ public:
bool ValidateScriptScope();
bool CallScriptFunction( const char* pFunctionName, ScriptVariant_t* pFunctionReturn );
HSCRIPT GetOrCreatePrivateScriptScope();
HSCRIPT GetScriptScope() { return m_ScriptScope; }
HSCRIPT LookupScriptFunction(const char* pFunctionName);
@ -275,6 +276,9 @@ public:
bool RunScript( const char* pScriptText, const char* pDebugFilename = "C_BaseEntity::RunScript" );
#endif
HSCRIPT GetScriptOwnerEntity();
virtual void SetScriptOwnerEntity(HSCRIPT pOwner);
HSCRIPT GetScriptInstance();
HSCRIPT m_hScriptInstance;
@ -1149,6 +1153,11 @@ public:
bool IsFollowingEntity();
CBaseEntity *GetFollowedEntity();
#ifdef MAPBASE_VSCRIPT
void ScriptFollowEntity( HSCRIPT hBaseEntity, bool bBoneMerge );
HSCRIPT ScriptGetFollowedEntity();
#endif
// For shadows rendering the correct body + sequence...
virtual int GetBody() { return 0; }
virtual int GetSkin() { return 0; }
@ -1170,15 +1179,39 @@ public:
void VScriptPrecacheScriptSound(const char* soundname);
const Vector& ScriptEyePosition(void) { static Vector vec; vec = EyePosition(); return vec; }
const Vector& ScriptGetAngles(void) { static Vector vec; QAngle qa = GetAbsAngles(); vec.x = qa.x; vec.y = qa.y; vec.z = qa.z; return vec; }
const QAngle& ScriptEyeAngles(void) { static QAngle ang; ang = EyeAngles(); return ang; }
void ScriptSetForward( const Vector& v ) { QAngle angles; VectorAngles( v, angles ); SetAbsAngles( angles ); }
const Vector& ScriptGetBoundingMins( void ) { return m_Collision.OBBMins(); }
const Vector& ScriptGetBoundingMaxs( void ) { return m_Collision.OBBMaxs(); }
HSCRIPT ScriptEntityToWorldTransform( void );
HSCRIPT ScriptGetPhysicsObject( void );
void ScriptSetParent( HSCRIPT hParent, const char *szAttachment );
HSCRIPT ScriptGetMoveParent( void );
HSCRIPT ScriptGetRootMoveParent();
HSCRIPT ScriptFirstMoveChild( void );
HSCRIPT ScriptNextMovePeer( void );
const Vector& ScriptGetColorVector();
int ScriptGetColorR() { return m_clrRender.GetR(); }
int ScriptGetColorG() { return m_clrRender.GetG(); }
int ScriptGetColorB() { return m_clrRender.GetB(); }
int ScriptGetAlpha() { return m_clrRender.GetA(); }
void ScriptSetColorVector( const Vector& vecColor );
void ScriptSetColor( int r, int g, int b );
void ScriptSetColorR( int iVal ) { SetRenderColorR( iVal ); }
void ScriptSetColorG( int iVal ) { SetRenderColorG( iVal ); }
void ScriptSetColorB( int iVal ) { SetRenderColorB( iVal ); }
void ScriptSetAlpha( int iVal ) { SetRenderColorA( iVal ); }
int ScriptGetRenderMode() { return GetRenderMode(); }
void ScriptSetRenderMode( int nRenderMode ) { SetRenderMode( (RenderMode_t)nRenderMode ); }
int ScriptGetMoveType() { return GetMoveType(); }
void ScriptSetMoveType( int iMoveType ) { SetMoveType( (MoveType_t)iMoveType ); }
#endif
// Stubs on client

View File

@ -24,6 +24,11 @@ BEGIN_NETWORK_TABLE( CDynamicProp, DT_DynamicProp )
RecvPropBool(RECVINFO(m_bUseHitboxesForRenderBox)),
END_NETWORK_TABLE()
#ifdef MAPBASE_VSCRIPT
// Allows client-side VScript to create dynamic props via CreateProp()
LINK_ENTITY_TO_CLASS( prop_dynamic, C_DynamicProp );
#endif
C_DynamicProp::C_DynamicProp( void )
{
m_iCachedFrameCount = -1;

View File

@ -35,6 +35,7 @@ $Project
$Folder "Mapbase"
{
$File "$SRCDIR\game\shared\mapbase\mapbase_shared.cpp"
$File "$SRCDIR\game\shared\mapbase\mapbase_usermessages.cpp"
$File "$SRCDIR\game\shared\mapbase\mapbase_rpc.cpp"
$File "$SRCDIR\game\shared\mapbase\mapbase_game_log.cpp"
$File "$SRCDIR\game\shared\mapbase\MapEdit.cpp"
@ -50,6 +51,7 @@ $Project
$File "$SRCDIR\game\shared\mapbase\vscript_consts_weapons.cpp" [$MAPBASE_VSCRIPT]
$File "$SRCDIR\game\shared\mapbase\weapon_custom_scripted.cpp" [$MAPBASE_VSCRIPT]
$File "$SRCDIR\game\shared\mapbase\weapon_custom_scripted.h" [$MAPBASE_VSCRIPT]
$File "$SRCDIR\game\shared\mapbase\logic_script_client.cpp" [$MAPBASE_VSCRIPT]
$File "mapbase\c_func_clientclip.cpp"
$File "mapbase\c_func_fake_worldportal.cpp"

View File

@ -469,6 +469,33 @@ static bool ScriptScreenTransform( const Vector &pos, HSCRIPT hArray )
}
return false;
}
// Creates a client-side prop
HSCRIPT CreateProp( const char *pszEntityName, const Vector &vOrigin, const char *pszModelName, int iAnim )
{
C_BaseAnimating *pBaseEntity = (C_BaseAnimating *)CreateEntityByName( pszEntityName );
if (!pBaseEntity)
return NULL;
pBaseEntity->SetAbsOrigin( vOrigin );
pBaseEntity->SetModelName( pszModelName );
if (!pBaseEntity->InitializeAsClientEntity( pszModelName, RENDER_GROUP_OPAQUE_ENTITY ))
{
Warning("Can't initialize %s as client entity\n", pszEntityName);
return NULL;
}
pBaseEntity->SetPlaybackRate( 1.0f );
int iSequence = pBaseEntity->SelectWeightedSequence( (Activity)iAnim );
if ( iSequence != -1 )
{
pBaseEntity->SetSequence( iSequence );
}
return ToHScript( pBaseEntity );
}
#endif
bool VScriptClientInit()
@ -548,6 +575,8 @@ bool VScriptClientInit()
ScriptRegisterFunction( g_pScriptVM, ScreenHeight, "Height of the screen in pixels" );
ScriptRegisterFunction( g_pScriptVM, IsWindowedMode, "" );
ScriptRegisterFunctionNamed( g_pScriptVM, ScriptScreenTransform, "ScreenTransform", "Get the x & y positions of a world position in screen space. Returns true if it's onscreen" );
ScriptRegisterFunction( g_pScriptVM, CreateProp, "Create an animating prop" );
#endif

View File

@ -623,18 +623,6 @@ CBaseEntity *CBaseEntity::GetFollowedEntity()
return GetMoveParent();
}
#ifdef MAPBASE_VSCRIPT
void CBaseEntity::ScriptFollowEntity( HSCRIPT hBaseEntity, bool bBoneMerge )
{
FollowEntity( ToEnt( hBaseEntity ), bBoneMerge );
}
HSCRIPT CBaseEntity::ScriptGetFollowedEntity()
{
return ToHScript( GetFollowedEntity() );
}
#endif
void CBaseEntity::SetClassname( const char *className )
{
m_iClassname = AllocPooledString( className );
@ -2360,6 +2348,7 @@ BEGIN_ENT_SCRIPTDESC_ROOT( CBaseEntity, "Root class of all server-side entities"
DEFINE_SCRIPTFUNC_NAMED( ScriptSetColorB, "SetRenderColorB", "Set the render color's B value" )
DEFINE_SCRIPTFUNC_NAMED( ScriptSetAlpha, "SetRenderAlpha", "Set the render color's alpha value" )
// LEGACY
DEFINE_SCRIPTFUNC_NAMED( ScriptGetColorVector, "GetColorVector", SCRIPT_HIDE )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetColorR, "GetColorR", SCRIPT_HIDE )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetColorG, "GetColorG", SCRIPT_HIDE )
@ -2370,6 +2359,7 @@ BEGIN_ENT_SCRIPTDESC_ROOT( CBaseEntity, "Root class of all server-side entities"
DEFINE_SCRIPTFUNC_NAMED( ScriptSetColorG, "SetColorG", SCRIPT_HIDE )
DEFINE_SCRIPTFUNC_NAMED( ScriptSetColorB, "SetColorB", SCRIPT_HIDE )
DEFINE_SCRIPTFUNC_NAMED( ScriptSetAlpha, "SetAlpha", SCRIPT_HIDE )
// END LEGACY
DEFINE_SCRIPTFUNC_NAMED( ScriptGetRenderMode, "GetRenderMode", "Get render mode" )
DEFINE_SCRIPTFUNC_NAMED( ScriptSetRenderMode, "SetRenderMode", "Set render mode" )
@ -8849,51 +8839,6 @@ HSCRIPT CBaseEntity::GetScriptScope()
return m_ScriptScope;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
#ifdef MAPBASE_VSCRIPT
HSCRIPT CBaseEntity::GetOrCreatePrivateScriptScope()
{
ValidateScriptScope();
return m_ScriptScope;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CBaseEntity::ScriptSetParent(HSCRIPT hParent, const char *szAttachment)
{
CBaseEntity *pParent = ToEnt(hParent);
if ( !pParent )
{
SetParent(NULL);
return;
}
// if an attachment is specified, the parent needs to be CBaseAnimating
if ( szAttachment && szAttachment[0] != '\0' )
{
CBaseAnimating *pAnimating = pParent->GetBaseAnimating();
if ( !pAnimating )
{
Warning("ERROR: Tried to set parent for entity %s (%s), but its parent has no model.\n", GetClassname(), GetDebugName());
return;
}
int iAttachment = pAnimating->LookupAttachment(szAttachment);
if ( iAttachment <= 0 )
{
Warning("ERROR: Tried to set parent for entity %s (%s), but it has no attachment named %s.\n", GetClassname(), GetDebugName(), szAttachment);
return;
}
SetParent(pParent, iAttachment);
SetMoveType(MOVETYPE_NONE);
return;
}
SetParent(pParent);
}
#endif
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
HSCRIPT CBaseEntity::ScriptGetMoveParent(void)
@ -10143,6 +10088,7 @@ void CBaseEntity::RunOnPostSpawnScripts(void)
}
}
#ifndef MAPBASE_VSCRIPT // This is shared now
HSCRIPT CBaseEntity::GetScriptOwnerEntity()
{
return ToHScript(GetOwnerEntity());
@ -10152,6 +10098,7 @@ void CBaseEntity::SetScriptOwnerEntity(HSCRIPT pOwner)
{
SetOwnerEntity(ToEnt(pOwner));
}
#endif
//-----------------------------------------------------------------------------
// VScript access to model's key values
@ -10318,46 +10265,6 @@ const char *CBaseEntity::ScriptGetKeyValue( const char *pszKeyName )
return szValue;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
const Vector& CBaseEntity::ScriptGetColorVector()
{
static Vector vecColor;
vecColor.Init( m_clrRender.GetR(), m_clrRender.GetG(), m_clrRender.GetB() );
return vecColor;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CBaseEntity::ScriptSetColorVector( const Vector& vecColor )
{
SetRenderColor( vecColor.x, vecColor.y, vecColor.z );
}
void CBaseEntity::ScriptSetColor( int r, int g, int b )
{
SetRenderColor( r, g, b );
}
//-----------------------------------------------------------------------------
// Vscript: Gets the entity matrix transform
//-----------------------------------------------------------------------------
HSCRIPT CBaseEntity::ScriptEntityToWorldTransform( void )
{
return g_pScriptVM->RegisterInstance( &EntityToWorldTransform() );
}
//-----------------------------------------------------------------------------
// Vscript: Gets the entity's physics object if it has one
//-----------------------------------------------------------------------------
HSCRIPT CBaseEntity::ScriptGetPhysicsObject( void )
{
if (VPhysicsGetObject())
return g_pScriptVM->RegisterInstance( VPhysicsGetObject() );
else
return NULL;
}
//-----------------------------------------------------------------------------
// Vscript: Dispatch an interaction to the entity
//-----------------------------------------------------------------------------

View File

@ -169,6 +169,7 @@ BEGIN_ENT_SCRIPTDESC( CRagdollProp, CBaseAnimating, "Ragdoll physics prop." )
DEFINE_SCRIPTFUNC( SetSourceClassName, "Sets the ragdoll's source classname." )
DEFINE_SCRIPTFUNC( HasPhysgunInteraction, "Checks if the ragdoll has the specified interaction." )
// TODO: Proper shared ragdoll funcs?
DEFINE_SCRIPTFUNC_NAMED( ScriptGetRagdollObject, "GetRagdollObject", "Gets the ragdoll object of the specified index." )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetRagdollObjectCount, "GetRagdollObjectCount", "Gets the number of ragdoll objects on this ragdoll." )

View File

@ -31,6 +31,7 @@ $Project
$Folder "Mapbase"
{
$File "$SRCDIR\game\shared\mapbase\mapbase_shared.cpp"
$File "$SRCDIR\game\shared\mapbase\mapbase_usermessages.cpp"
$File "$SRCDIR\game\shared\mapbase\mapbase_rpc.cpp"
$File "$SRCDIR\game\shared\mapbase\mapbase_game_log.cpp"
$File "$SRCDIR\game\shared\mapbase\MapEdit.cpp"
@ -46,6 +47,7 @@ $Project
$File "$SRCDIR\game\shared\mapbase\vscript_consts_weapons.cpp" [$MAPBASE_VSCRIPT]
$File "$SRCDIR\game\shared\mapbase\weapon_custom_scripted.cpp" [$MAPBASE_VSCRIPT]
$File "$SRCDIR\game\shared\mapbase\weapon_custom_scripted.h" [$MAPBASE_VSCRIPT]
$File "$SRCDIR\game\shared\mapbase\logic_script_client.cpp" [$MAPBASE_VSCRIPT]
$File "mapbase\ai_grenade.cpp"
$File "mapbase\ai_grenade.h"

View File

@ -2418,6 +2418,18 @@ void CBaseEntity::FollowEntity( CBaseEntity *pBaseEntity, bool bBoneMerge )
}
}
#ifdef MAPBASE_VSCRIPT
void CBaseEntity::ScriptFollowEntity( HSCRIPT hBaseEntity, bool bBoneMerge )
{
FollowEntity( ToEnt( hBaseEntity ), bBoneMerge );
}
HSCRIPT CBaseEntity::ScriptGetFollowedEntity()
{
return ToHScript( GetFollowedEntity() );
}
#endif
void CBaseEntity::SetEffectEntity( CBaseEntity *pEffectEnt )
{
if ( m_hEffectEntity.Get() != pEffectEnt )
@ -2607,3 +2619,97 @@ bool CBaseEntity::IsToolRecording() const
#endif
}
#endif
#ifdef MAPBASE_VSCRIPT
HSCRIPT CBaseEntity::GetOrCreatePrivateScriptScope()
{
ValidateScriptScope();
return m_ScriptScope;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CBaseEntity::ScriptSetParent(HSCRIPT hParent, const char *szAttachment)
{
CBaseEntity *pParent = ToEnt(hParent);
if ( !pParent )
{
SetParent(NULL);
return;
}
// if an attachment is specified, the parent needs to be CBaseAnimating
if ( szAttachment && szAttachment[0] != '\0' )
{
CBaseAnimating *pAnimating = pParent->GetBaseAnimating();
if ( !pAnimating )
{
Warning("ERROR: Tried to set parent for entity %s (%s), but its parent has no model.\n", GetClassname(), GetDebugName());
return;
}
int iAttachment = pAnimating->LookupAttachment(szAttachment);
if ( iAttachment <= 0 )
{
Warning("ERROR: Tried to set parent for entity %s (%s), but it has no attachment named %s.\n", GetClassname(), GetDebugName(), szAttachment);
return;
}
SetParent(pParent, iAttachment);
SetMoveType(MOVETYPE_NONE);
return;
}
SetParent(pParent);
}
HSCRIPT CBaseEntity::GetScriptOwnerEntity()
{
return ToHScript(GetOwnerEntity());
}
void CBaseEntity::SetScriptOwnerEntity(HSCRIPT pOwner)
{
SetOwnerEntity(ToEnt(pOwner));
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
const Vector& CBaseEntity::ScriptGetColorVector()
{
static Vector vecColor;
vecColor.Init( m_clrRender.GetR(), m_clrRender.GetG(), m_clrRender.GetB() );
return vecColor;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CBaseEntity::ScriptSetColorVector( const Vector& vecColor )
{
SetRenderColor( vecColor.x, vecColor.y, vecColor.z );
}
void CBaseEntity::ScriptSetColor( int r, int g, int b )
{
SetRenderColor( r, g, b );
}
//-----------------------------------------------------------------------------
// Vscript: Gets the entity matrix transform
//-----------------------------------------------------------------------------
HSCRIPT CBaseEntity::ScriptEntityToWorldTransform( void )
{
return g_pScriptVM->RegisterInstance( &EntityToWorldTransform() );
}
//-----------------------------------------------------------------------------
// Vscript: Gets the entity's physics object if it has one
//-----------------------------------------------------------------------------
HSCRIPT CBaseEntity::ScriptGetPhysicsObject( void )
{
if (VPhysicsGetObject())
return g_pScriptVM->RegisterInstance( VPhysicsGetObject() );
else
return NULL;
}
#endif

View File

@ -0,0 +1,232 @@
//========= Mapbase - https://github.com/mapbase-source/source-sdk-2013 ============//
//
// Purpose: Custom client-side equivalent of logic_script.
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "vscript_shared.h"
#include "tier1/fmtstr.h"
#ifdef CLIENT_DLL
ConVar cl_script_think_interval( "cl_script_think_interval", "0.1" );
#endif
//-----------------------------------------------------------------------------
// Purpose: An entity that acts as a container for client-side game scripts.
//-----------------------------------------------------------------------------
#define MAX_SCRIPT_GROUP_CLIENT 8
class CLogicScriptClient : public CBaseEntity
{
public:
DECLARE_CLASS( CLogicScriptClient, CBaseEntity );
DECLARE_DATADESC();
DECLARE_NETWORKCLASS();
#ifdef CLIENT_DLL
void OnDataChanged( DataUpdateType_t type )
{
BaseClass::OnDataChanged( type );
if ( !m_ScriptScope.IsInitialized() )
{
RunVScripts();
}
}
#else
int UpdateTransmitState() { return SetTransmitState( FL_EDICT_ALWAYS ); }
#endif
bool KeyValue( const char *szKeyName, const char *szValue )
{
if ( FStrEq( szKeyName, "vscripts" ) )
{
Q_strcpy( m_iszClientScripts.GetForModify(), szValue );
}
return BaseClass::KeyValue( szKeyName, szValue );
}
void RunVScripts()
{
#ifdef CLIENT_DLL
if (m_iszClientScripts == NULL_STRING)
{
CGMsg( 0, CON_GROUP_VSCRIPT, "%s has no client scripts", GetDebugName() );
return;
}
if (g_pScriptVM == NULL)
{
return;
}
ValidateScriptScope();
// All functions we want to have call chained instead of overwritten
// by other scripts in this entities list.
static const char* sCallChainFunctions[] =
{
"OnPostSpawn",
"Precache"
};
ScriptLanguage_t language = g_pScriptVM->GetLanguage();
// Make a call chainer for each in this entities scope
for (int j = 0; j < ARRAYSIZE( sCallChainFunctions ); ++j)
{
if (language == SL_PYTHON)
{
// UNDONE - handle call chaining in python
;
}
else if (language == SL_SQUIRREL)
{
//TODO: For perf, this should be precompiled and the %s should be passed as a parameter
HSCRIPT hCreateChainScript = g_pScriptVM->CompileScript( CFmtStr( "%sCallChain <- CSimpleCallChainer(\"%s\", self.GetScriptScope(), true)", sCallChainFunctions[j], sCallChainFunctions[j] ) );
g_pScriptVM->Run( hCreateChainScript, (HSCRIPT)m_ScriptScope );
}
}
char szScriptsList[255];
Q_strcpy( szScriptsList, m_iszClientScripts.Get() );
CUtlStringList szScripts;
V_SplitString( szScriptsList, " ", szScripts );
for (int i = 0; i < szScripts.Count(); i++)
{
CGMsg( 0, CON_GROUP_VSCRIPT, "%s executing script: %s\n", GetDebugName(), szScripts[i] );
RunScriptFile( szScripts[i], IsWorld() );
for (int j = 0; j < ARRAYSIZE( sCallChainFunctions ); ++j)
{
if (language == SL_PYTHON)
{
// UNDONE - handle call chaining in python
;
}
else if (language == SL_SQUIRREL)
{
//TODO: For perf, this should be precompiled and the %s should be passed as a parameter.
HSCRIPT hRunPostScriptExecute = g_pScriptVM->CompileScript( CFmtStr( "%sCallChain.PostScriptExecute()", sCallChainFunctions[j] ) );
g_pScriptVM->Run( hRunPostScriptExecute, (HSCRIPT)m_ScriptScope );
}
}
}
if (m_bClientThink)
{
SetNextClientThink( CLIENT_THINK_ALWAYS );
}
#else
// Avoids issues from having m_iszVScripts set without actually having a script scope
ValidateScriptScope();
if (m_bRunOnServer)
{
BaseClass::RunVScripts();
}
#endif
}
#ifdef CLIENT_DLL
void ClientThink()
{
ScriptVariant_t varThinkRetVal;
if (CallScriptFunction("ClientThink", &varThinkRetVal))
{
float flThinkFrequency = 0.0f;
if (!varThinkRetVal.AssignTo(&flThinkFrequency))
{
// use default think interval if script think function doesn't provide one
flThinkFrequency = cl_script_think_interval.GetFloat();
}
if (flThinkFrequency == CLIENT_THINK_ALWAYS)
SetNextClientThink( CLIENT_THINK_ALWAYS );
else
SetNextClientThink( gpGlobals->curtime + flThinkFrequency );
}
else
{
DevWarning("%s FAILED to call client script think function!\n", GetDebugName());
}
BaseClass::ClientThink();
}
#else
void InputCallScriptFunctionClient( inputdata_t &inputdata )
{
// TODO: Support for specific players?
CBroadcastRecipientFilter filter;
filter.MakeReliable();
const char *pszFunction = inputdata.value.String();
if (strlen( pszFunction ) > 64)
{
Msg("%s CallScriptFunctionClient: \"%s\" is too long at %i characters, must be 64 or less\n", GetDebugName(), pszFunction, strlen(pszFunction));
return;
}
UserMessageBegin( filter, "CallClientScriptFunction" );
WRITE_STRING( pszFunction ); // function
WRITE_SHORT( entindex() ); // entity
MessageEnd();
}
#endif
//CNetworkArray( string_t, m_iszGroupMembers, MAX_SCRIPT_GROUP_CLIENT );
CNetworkString( m_iszClientScripts, 128 );
CNetworkVar( bool, m_bClientThink );
#ifndef CLIENT_DLL
bool m_bRunOnServer;
#endif
};
LINK_ENTITY_TO_CLASS( logic_script_client, CLogicScriptClient );
BEGIN_DATADESC( CLogicScriptClient )
// TODO: Does this need to be saved?
//DEFINE_AUTO_ARRAY( m_iszClientScripts, FIELD_CHARACTER ),
//DEFINE_KEYFIELD( m_iszGroupMembers[0], FIELD_STRING, "Group00"),
//DEFINE_KEYFIELD( m_iszGroupMembers[1], FIELD_STRING, "Group01"),
//DEFINE_KEYFIELD( m_iszGroupMembers[2], FIELD_STRING, "Group02"),
//DEFINE_KEYFIELD( m_iszGroupMembers[3], FIELD_STRING, "Group03"),
//DEFINE_KEYFIELD( m_iszGroupMembers[4], FIELD_STRING, "Group04"),
//DEFINE_KEYFIELD( m_iszGroupMembers[5], FIELD_STRING, "Group05"),
//DEFINE_KEYFIELD( m_iszGroupMembers[6], FIELD_STRING, "Group06"),
//DEFINE_KEYFIELD( m_iszGroupMembers[7], FIELD_STRING, "Group07"),
DEFINE_KEYFIELD( m_bClientThink, FIELD_BOOLEAN, "ClientThink" ),
#ifndef CLIENT_DLL
DEFINE_KEYFIELD( m_bRunOnServer, FIELD_BOOLEAN, "RunOnServer" ),
DEFINE_INPUTFUNC( FIELD_STRING, "CallScriptFunctionClient", InputCallScriptFunctionClient ),
#endif
END_DATADESC()
IMPLEMENT_NETWORKCLASS_DT( CLogicScriptClient, DT_LogicScriptClient )
#ifdef CLIENT_DLL
//RecvPropArray( RecvPropString( RECVINFO( m_iszGroupMembers[0] ) ), m_iszGroupMembers ),
RecvPropString( RECVINFO( m_iszClientScripts ) ),
RecvPropBool( RECVINFO( m_bClientThink ) ),
#else
//SendPropArray( SendPropStringT( SENDINFO_ARRAY( m_iszGroupMembers ) ), m_iszGroupMembers ),
SendPropString( SENDINFO( m_iszClientScripts ) ),
SendPropBool( SENDINFO( m_bClientThink ) ),
#endif
END_NETWORK_TABLE()

View File

@ -16,10 +16,12 @@
#include "saverestore_utlvector.h"
#include "props_shared.h"
#include "utlbuffer.h"
#include "usermessages.h"
#ifdef CLIENT_DLL
#include "hud_closecaption.h"
#include "panelmetaclassmgr.h"
#include "c_soundscape.h"
#include "hud_macros.h"
#else
#include "soundscape_system.h"
#include "AI_ResponseSystem.h"

View File

@ -0,0 +1,64 @@
//========= Mapbase - https://github.com/mapbase-source/source-sdk-2013 ============//
//
// Purpose: Mapbase-specific user messages.
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "usermessages.h"
#ifdef CLIENT_DLL
#include "hud_macros.h"
#endif
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
#ifdef CLIENT_DLL
void __MsgFunc_CallClientScriptFunction( bf_read &msg )
{
char szFunction[64];
if (!msg.ReadString( szFunction, sizeof( szFunction ) ))
{
CGMsg( 0, CON_GROUP_VSCRIPT, "Unable to read function string\n" );
}
int idx = msg.ReadByte();
C_BaseEntity *pEntity = CBaseEntity::Instance( idx );
if (pEntity)
{
if (pEntity->m_ScriptScope.IsInitialized())
{
//CGMsg( 0, CON_GROUP_VSCRIPT, "%s calling function \"%s\"\n", pEntity->GetDebugName(), szFunction );
pEntity->CallScriptFunction( szFunction, NULL );
}
else
{
CGMsg( 0, CON_GROUP_VSCRIPT, "%s scope not initialized\n", pEntity->GetDebugName() );
}
}
else
{
CGMsg( 0, CON_GROUP_VSCRIPT, "Clientside entity not found for script function (index %i)\n", idx );
}
}
void HookMapbaseUserMessages( void )
{
// VScript
HOOK_MESSAGE( CallClientScriptFunction );
}
#endif
void RegisterMapbaseUserMessages( void )
{
// VScript
usermessages->Register( "CallClientScriptFunction", -1 );
#ifdef CLIENT_DLL
// TODO: Better placement?
HookMapbaseUserMessages();
#endif
}

View File

@ -13,6 +13,10 @@
void RegisterUserMessages( void );
#ifdef MAPBASE
void RegisterMapbaseUserMessages( void );
#endif
//-----------------------------------------------------------------------------
// Purpose: Force registration on .dll load
// FIXME: Should this be a client/server system?
@ -21,6 +25,11 @@ CUserMessages::CUserMessages()
{
// Game specific registration function;
RegisterUserMessages();
#ifdef MAPBASE
// Mapbase registration function;
RegisterMapbaseUserMessages();
#endif
}
CUserMessages::~CUserMessages()