Hand Viewmodels: Difference between revisions
(adding fix for singleplayer) |
No edit summary |
||
Line 1: | Line 1: | ||
== Introduction == | ==Introduction== | ||
Have you ever wanted fancy c_ models like {{Team Fortress 2|4}} and all those cool games? | |||
Have you ever wanted fancy c_ models like all those cool games? | |||
Well, now you can! | Well, now you can! | ||
== Implementation == | ==Implementation== | ||
Create the following file and put it in the '''src/game/shared''' folder: | Create the following file and put it in the '''src/game/shared''' folder: | ||
=== handviewmodel_shared.cpp === | ===handviewmodel_shared.cpp=== | ||
<source lang=cpp> | <source lang=cpp> | ||
#include "cbase.h" | #include "cbase.h" | ||
Line 44: | Line 41: | ||
</source> | </source> | ||
=== player.h === | ===player.h=== | ||
In '''src/server/player.h''' you should now add the following below the <code>CreateViewModel( int viewmodelindex = 0 );</code> declaration: | In '''src/server/player.h''' you should now add the following below the <code>CreateViewModel( int viewmodelindex = 0 );</code> declaration: | ||
<source lang=cpp> | <source lang=cpp> | ||
Line 51: | Line 47: | ||
</source> | </source> | ||
=== player.cpp === | ===player.cpp=== | ||
In '''src/server/player.cpp''' put this below the <code>CreateViewModel( int index /*=0*/ )</code> function: | In '''src/server/player.cpp''' put this below the <code>CreateViewModel( int index /*=0*/ )</code> function: | ||
<source lang=cpp> | <source lang=cpp> | ||
Line 83: | Line 78: | ||
</source> | </source> | ||
=== your_player.cpp === | ===your_player.cpp=== | ||
{{Note|Depending on the base you're modifying you'll have to pick the relevant file for this. If it's an SP mod modify '''hl2_player.cpp''', if it's an MP mod modify '''hl2mp_player.cpp''' or if you have your own player class just modify that.}} | {{Note|Depending on the base you're modifying you'll have to pick the relevant file for this. If it's an SP mod modify '''hl2_player.cpp''', if it's an MP mod modify '''hl2mp_player.cpp''' or if you have your own player class just modify that.}} | ||
So now that the <code>HandViewModel</code> has been created we need to set its model. | So now that the <code>HandViewModel</code> has been created we need to set its model. | ||
Line 103: | Line 96: | ||
</source> | </source> | ||
== Fixes == | ==Fixes== | ||
===Fix for multiplayer mods with a round system=== | |||
=== 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 <code>hand_viewmodel</code>) into <code>s_PreserveEnts[]</code> array which is located in the gamerules file ('''hl2mp_gamerules.cpp''' for example) so it will look something like this: | 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 <code>hand_viewmodel</code>) into <code>s_PreserveEnts[]</code> array which is located in the gamerules file ('''hl2mp_gamerules.cpp''' for example) so it will look something like this: | ||
Line 157: | Line 148: | ||
If you don't do it, your hands viewmodel '''will be removed every time new round has started'''. | If you don't do it, your hands viewmodel '''will be removed every time new round has started'''. | ||
=== Fix for multiplayer mods with first person ragdolls === | ===Fix for multiplayer mods with first person ragdolls=== | ||
In multiplayer, an error was found where hands are displayed at the time of the player's death if you have [[First Person Ragdolls|first person ragdolls]] implemented. | In multiplayer, an error was found where hands are displayed at the time of the player's death if you have [[First Person Ragdolls|first person ragdolls]] implemented. | ||
Line 166: | Line 156: | ||
</source> | </source> | ||
=== Fix for vanishing hands in singleplayer === | ===Fix for vanishing hands in singleplayer=== | ||
In singleplayer if the player take a prop using the +use key the hands model will vansih until the player fire with a weapon, the same thing appen when the player exit a vehicle. | In singleplayer if the player take a prop using the +use key the hands model will vansih until the player fire with a weapon, the same thing appen when the player exit a vehicle. | ||
To prevent it you need to edit the fonction <code>void CBaseCombatWeapon::SetWeaponVisible( bool visible )</code> in '''basecombatweapon_shared.cpp''' : | To prevent it you need to edit the fonction <code>void CBaseCombatWeapon::SetWeaponVisible( bool visible )</code> in '''basecombatweapon_shared.cpp''' : | ||
Line 212: | Line 201: | ||
</source> | </source> | ||
[[Category: Programming]] | [[Category:Programming]] | ||
[[Category: Tutorials]] | [[Category:Tutorials]] |
Revision as of 02:03, 28 August 2024
Introduction
Have you ever wanted fancy c_ models like Team Fortress 2 and 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" );
Fixes
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.
Fix for multiplayer mods with first person ragdolls
In multiplayer, an error was found where hands are displayed at the time of the player's death if you have first person ragdolls implemented.
To prevent it, open player.cpp and find the PlayerDeathThink(void)
function and add this somewere inside it:
GetViewModel(1)->SetModel( "" ); // FIX: Removes hand model when the player is dead
Fix for vanishing hands in singleplayer
In singleplayer if the player take a prop using the +use key the hands model will vansih until the player fire with a weapon, the same thing appen when the player exit a vehicle.
To prevent it you need to edit the fonction void CBaseCombatWeapon::SetWeaponVisible( bool visible )
in basecombatweapon_shared.cpp :
void CBaseCombatWeapon::SetWeaponVisible( bool visible )
{
CBaseViewModel *vm = NULL;
CBaseViewModel* hm = NULL;
CBasePlayer *pOwner = ToBasePlayer( GetOwner() );
if ( pOwner )
{
vm = pOwner->GetViewModel();
hm = pOwner->GetViewModel(1);
}
if ( visible )
{
RemoveEffects( EF_NODRAW );
if ( vm )
{
vm->RemoveEffects( EF_NODRAW );
}
if ( hm )
{
hm->RemoveEffects( EF_NODRAW );
}
}
else
{
AddEffects( EF_NODRAW );
if ( vm )
{
vm->AddEffects( EF_NODRAW );
}
if ( hm )
{
hm->AddEffects( EF_NODRAW );
}
}
}