Hand Viewmodels
Introduction
Have you ever wanted fancy c_ models like all those cool games?
Well, now you can!
Implementation
Create the following file and put it in the src/game/shared folder:
#include "cbase.h"
#include "baseviewmodel_shared.h"
#if defined( CLIENT_DLL )
#define CHandViewModel C_HandViewModel
#endif
class CHandViewModel : public CBaseViewModel
{
DECLARE_CLASS( CHandViewModel, CBaseViewModel );
public:
DECLARE_NETWORKCLASS();
private:
};
LINK_ENTITY_TO_CLASS( hand_viewmodel, CHandViewModel );
IMPLEMENT_NETWORKCLASS_ALIASED( HandViewModel, DT_HandViewModel )
// For whatever reason the parent doesn't get sent
// And I don't really want to mess with BaseViewModel
// so now it does
BEGIN_NETWORK_TABLE( CHandViewModel, DT_HandViewModel )
#ifndef CLIENT_DLL
SendPropEHandle( SENDINFO_NAME( m_hMoveParent, moveparent ) ),
#else
RecvPropInt( RECVINFO_NAME( m_hNetworkMoveParent, moveparent ), 0, RecvProxy_IntToMoveParent ),
#endif
END_NETWORK_TABLE()
player.h
In src/server/player.h you should now add the following below the CreateViewModel( int viewmodelindex = 0 );
declaration:
virtual void CreateHandModel( int viewmodelindex = 1, int iOtherVm = 0 );
player.cpp
In src/server/player.cpp put this below the CreateViewModel( int index /*=0*/ )
function:
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBasePlayer::CreateHandModel( int index, int iOtherVm )
{
Assert( index >= 0 && index < MAX_VIEWMODELS && iOtherVm >= 0 && iOtherVm < MAX_VIEWMODELS );
if ( GetViewModel( index ) )
return;
CBaseViewModel *vm = (CBaseViewModel *)CreateEntityByName( "hand_viewmodel" );
if ( vm )
{
vm->SetAbsOrigin( GetAbsOrigin() );
vm->SetOwner( this );
vm->SetIndex( index );
DispatchSpawn( vm );
vm->FollowEntity( GetViewModel( iOtherVm ), true );
m_hViewModel.Set( index, vm );
}
}
Now we need to call it. So inside the Spawn
function, and below CreateViewModel();
, add:
CreateHandModel();
your_player.cpp

So now that the HandViewModel
has been created we need to set its model.
Put this in your player's Spawn
function sometime after the hand model has been created:
GetViewModel(1)->SetModel( "models/coolhandsfolder/cool_arms.mdl" );


Also make sure your model has been precached first! To do this add the following into your Precache
function:
PrecacheModel( "models/coolhandsfolder/cool_arms.mdl" );
Fix for multiplayer mods with a round system
If you are using this method for multiplayer and your mod has a round system, you will have to add your new viewmodel's entity name (in this tutorial it's hand_viewmodel
) into s_PreserveEnts[]
array which is located in the gamerules file (hl2mp_gamerules.cpp for example) so it will look something like this:
static const char *s_PreserveEnts[] =
{
"ai_network",
"ai_hint",
"hl2mp_gamerules",
"team_manager",
"player_manager",
"env_soundscape",
"env_soundscape_proxy",
"env_soundscape_triggerable",
"env_sun",
"env_wind",
"env_fog_controller",
"func_brush",
"func_wall",
"func_buyzone",
"func_illusionary",
"infodecal",
"info_projecteddecal",
"info_node",
"info_target",
"info_node_hint",
"info_player_deathmatch",
"info_player_combine",
"info_player_rebel",
"info_map_parameters",
"keyframe_rope",
"move_rope",
"info_ladder",
"player",
"point_viewcontrol",
"scene_manager",
"shadow_control",
"sky_camera",
"soundent",
"trigger_soundscape",
"viewmodel",
"predicted_viewmodel",
"hand_viewmodel", // Our new viewmodel entity
"worldspawn",
"point_devshot_camera",
"", // END Marker
};
If you don't do it, your hands viewmodel will be removed every time new round has started.