Monthly Target: $400 Donations: $23
 5% 

[SNIPPET][CSS]custom viewmodels without flickers and without disabling prediction


Post New Thread Reply   
 
Thread Tools Display Modes
Author Message
blodia
Veteran Member
Join Date: Sep 2009
Location: UK
Old 03-30-2012 , 15:01   [SNIPPET][CSS]custom viewmodels without flickers and without disabling prediction
Reply With Quote #1

PHP Code:
#include <sourcemod>
#include <sdktools>
#include <sdkhooks>

#pragma semicolon 1

#define EF_NODRAW 32

new CustomModel1;
new 
CustomModel2;

new 
bool:SpawnCheck[MAXPLAYERS+1];
new 
ClientVM[MAXPLAYERS+1][2];
new 
bool:IsCustom[MAXPLAYERS+1];

public 
OnPluginStart()
{
    
HookEvent("player_death"Event_PlayerDeath);
    
HookEvent("player_spawn"Event_PlayerSpawn);
    
    for (new 
client 1client <= MaxClientsclient++) 
    { 
        if (
IsClientInGame(client)) 
        {
            
SDKHook(clientSDKHook_PostThinkPostOnPostThinkPost);
            
            
//find both of the clients viewmodels
            
ClientVM[client][0] = GetEntPropEnt(clientProp_Send"m_hViewModel");
            
            new 
PVM = -1;
            while ((
PVM FindEntityByClassname(PVM"predicted_viewmodel")) != -1)
            {
                if (
GetEntPropEnt(PVMProp_Send"m_hOwner") == client)
                {
                    if (
GetEntProp(PVMProp_Send"m_nViewModelIndex") == 1)
                    {
                        
ClientVM[client][1] = PVM;
                        break;
                    }
                }
            }
        } 
    }
}

public 
OnMapStart()
{
    
CustomModel1 PrecacheModel("models/Weapons/v_smg_p90.mdl");
    
CustomModel2 PrecacheModel("models/Weapons/v_smg_tmp.mdl");
}

public 
OnClientPutInServer(client)
{
    
SDKHook(clientSDKHook_PostThinkPostOnPostThinkPost);
}

public 
OnEntityCreated(entity, const String:classname[])
{
    if (
StrEqual(classname"predicted_viewmodel"false))
    {
        
SDKHook(entitySDKHook_SpawnOnEntitySpawned);
    }
}

//find both of the clients viewmodels
public OnEntitySpawned(entity)
{
    new 
Owner GetEntPropEnt(entityProp_Send"m_hOwner");
    if ((
Owner 0) && (Owner <= MaxClients))
    {
        if (
GetEntProp(entityProp_Send"m_nViewModelIndex") == 0)
        {
            
ClientVM[Owner][0] = entity;
        }
        else if (
GetEntProp(entityProp_Send"m_nViewModelIndex") == 1)
        {
            
ClientVM[Owner][1] = entity;
        }
    }
}

public 
OnPostThinkPost(client)
{
    static 
OldWeapon[MAXPLAYERS 1];
    static 
OldSequence[MAXPLAYERS 1];
    static 
Float:OldCycle[MAXPLAYERS 1];
    
    
decl String:ClassName[30];
    new 
WeaponIndex;
    
    
//handle spectators
    
if (!IsPlayerAlive(client))
    {
        new 
spec GetEntPropEnt(clientProp_Send"m_hObserverTarget");
        if (
spec != -1)
        {
            
WeaponIndex GetEntPropEnt(specProp_Send"m_hActiveWeapon");
            
GetEdictClassname(WeaponIndexClassNamesizeof(ClassName));
            if (
StrEqual("weapon_ump45"ClassNamefalse))
            {
                
SetEntProp(ClientVM[client][1], Prop_Send"m_nModelIndex"CustomModel1);
            }
            else if (
StrEqual("weapon_mp5navy"ClassNamefalse))
            {
                
SetEntProp(ClientVM[client][1], Prop_Send"m_nModelIndex"CustomModel2);
            }
        }
        
        return;
    }
    
    
WeaponIndex GetEntPropEnt(clientProp_Send"m_hActiveWeapon");
    new 
Sequence GetEntProp(ClientVM[client][0], Prop_Send"m_nSequence");
    new 
Float:Cycle GetEntPropFloat(ClientVM[client][0], Prop_Data"m_flCycle");
    
    if (
WeaponIndex <= 0)
    {
        new 
EntEffects GetEntProp(ClientVM[client][1], Prop_Send"m_fEffects");
        
EntEffects |= EF_NODRAW;
        
SetEntProp(ClientVM[client][1], Prop_Send"m_fEffects"EntEffects);
        
        
IsCustom[client] = false;
            
        
OldWeapon[client] = WeaponIndex;
        
OldSequence[client] = Sequence;
        
OldCycle[client] = Cycle;
        
        return;
    }
    
    
//just stuck the weapon switching in here aswell instead of a separate hook
    
if (WeaponIndex != OldWeapon[client])
    {
        
GetEdictClassname(WeaponIndexClassNamesizeof(ClassName));
        if (
StrEqual("weapon_ump45"ClassNamefalse))
        {
            
//hide viewmodel
            
new EntEffects GetEntProp(ClientVM[client][0], Prop_Send"m_fEffects");
            
EntEffects |= EF_NODRAW;
            
SetEntProp(ClientVM[client][0], Prop_Send"m_fEffects"EntEffects);
            
//unhide unused viewmodel
            
EntEffects GetEntProp(ClientVM[client][1], Prop_Send"m_fEffects");
            
EntEffects &= ~EF_NODRAW;
            
SetEntProp(ClientVM[client][1], Prop_Send"m_fEffects"EntEffects);
            
            
//set model and copy over props from viewmodel to used viewmodel
            
SetEntProp(ClientVM[client][1], Prop_Send"m_nModelIndex"CustomModel1);
            
SetEntPropEnt(ClientVM[client][1], Prop_Send"m_hWeapon"GetEntPropEnt(ClientVM[client][0], Prop_Send"m_hWeapon"));
            
            
SetEntProp(ClientVM[client][1], Prop_Send"m_nSequence"GetEntProp(ClientVM[client][0], Prop_Send"m_nSequence"));
            
SetEntPropFloat(ClientVM[client][1], Prop_Send"m_flPlaybackRate"GetEntPropFloat(ClientVM[client][0], Prop_Send"m_flPlaybackRate"));
            
            
IsCustom[client] = true;
        }
        else if (
StrEqual("weapon_mp5navy"ClassNamefalse))
        {
            new 
EntEffects GetEntProp(ClientVM[client][0], Prop_Send"m_fEffects");
            
EntEffects |= EF_NODRAW;
            
SetEntProp(ClientVM[client][0], Prop_Send"m_fEffects"EntEffects);
            
            
EntEffects GetEntProp(ClientVM[client][1], Prop_Send"m_fEffects");
            
EntEffects &= ~EF_NODRAW;
            
SetEntProp(ClientVM[client][1], Prop_Send"m_fEffects"EntEffects);
            
            
SetEntProp(ClientVM[client][1], Prop_Send"m_nModelIndex"CustomModel2);
            
SetEntPropEnt(ClientVM[client][1], Prop_Send"m_hWeapon"GetEntPropEnt(ClientVM[client][0], Prop_Send"m_hWeapon"));
            
            
SetEntProp(ClientVM[client][1], Prop_Send"m_nSequence"GetEntProp(ClientVM[client][0], Prop_Send"m_nSequence"));
            
SetEntPropFloat(ClientVM[client][1], Prop_Send"m_flPlaybackRate"GetEntPropFloat(ClientVM[client][0], Prop_Send"m_flPlaybackRate"));
            
            
IsCustom[client] = true;
        }
        else
        {
            
//hide unused viewmodel if the current weapon isn't using it
            
new EntEffects GetEntProp(ClientVM[client][1], Prop_Send"m_fEffects");
            
EntEffects |= EF_NODRAW;
            
SetEntProp(ClientVM[client][1], Prop_Send"m_fEffects"EntEffects);
            
            
IsCustom[client] = false;
        }
    }
    else
    {
        if (
IsCustom[client])
        {
            
//copy the animation stuff from the viewmodel to the used one every frame
            
SetEntProp(ClientVM[client][1], Prop_Send"m_nSequence"GetEntProp(ClientVM[client][0], Prop_Send"m_nSequence"));
            
SetEntPropFloat(ClientVM[client][1], Prop_Send"m_flPlaybackRate"GetEntPropFloat(ClientVM[client][0], Prop_Send"m_flPlaybackRate"));
            
            if ((
Cycle OldCycle[client]) && (Sequence == OldSequence[client]))
            {
                
SetEntProp(ClientVM[client][1], Prop_Send"m_nSequence"0);
            }
        }
    }
    
//hide viewmodel a frame after spawning
    
if (SpawnCheck[client])
    {
        
SpawnCheck[client] = false;
        if (
IsCustom[client])
        {
            new 
EntEffects GetEntProp(ClientVM[client][0], Prop_Send"m_fEffects");
            
EntEffects |= EF_NODRAW;
            
SetEntProp(ClientVM[client][0], Prop_Send"m_fEffects"EntEffects);
        }
    }
    
    
OldWeapon[client] = WeaponIndex;
    
OldSequence[client] = Sequence;
    
OldCycle[client] = Cycle;
}
//hide viewmodel on death
public Event_PlayerDeath(Handle:event, const String:name[], bool:dontBroadcast)
{
    new 
UserId GetEventInt(event"userid");
    new 
client GetClientOfUserId(UserId);
    
    new 
EntEffects GetEntProp(ClientVM[client][1], Prop_Send"m_fEffects");
    
EntEffects |= EF_NODRAW;
    
SetEntProp(ClientVM[client][1], Prop_Send"m_fEffects"EntEffects);
}

//when a player repsawns at round start after surviving previous round the viewmodel is unhidden
public Event_PlayerSpawn(Handle:event, const String:name[], bool:dontBroadcast)
{
    new 
UserId GetEventInt(event"userid");
    new 
client GetClientOfUserId(UserId);
    
    
//use to delay hiding viewmodel a frame or it won't work
    
SpawnCheck[client] = true;

i saw some people wanted to know how to this this from here.

this snippet changes the ump45 viewmodel to the p90 and the mp5 viewmodel to the tmp. i stuck the 2nd weapon code in there last minute just so you could see how it was done, that needs recoding a bit since theres a lot of duplicate code. in css each client gets 2 viewmodel entities, one seems to be unused from what i could tell so i just use that as a proxy. the unused viewmodel isn't predicted so clients with high pings will get delays before animations are played.

the code handle spectators aswell (thanks to GoD-Tony for mentioning a way to get it to work). in the thread mentioned above there is a snippet for world models but its not worth it because the model won't change when its on the ground or on the players back, also if the players weapon changes serverside which wasn't done on the client e.g weapon drop/pickup the weapon becomes invisible.

as long as the custom model has the same number of animations as the original, all custom animations have the same names as those in the original and the custom animations are the same length as the originals things will work fine otherwise you get animation glitches and such.

this snippet(modified) may work in other games if they also give clients an unused viewmodel, tf2 uses an extra one for the spies cloak activating/deactivating hand. in the sdk code clients can only have a maximum of 2 viewmodels, it may be different for hl2 mods and games may have their own maximum defined.

if clients haven't got the maximum number of viewmodels you can create a new one using an sdk call on the player using berni's virtual offset dumper look for CreateViewModel(int). the parameter is an index for how many viewmodels the client has, "m_nViewModelIndex" on the viewmodel stores its index, if the client has one viewmodel, its index will be 0, if they have 2 one will be 0 and the other 1 like an array. so to create a 2nd viewmodel you want to use an index of 1, 2 for a 3rd etc.

Last edited by blodia; 05-03-2012 at 15:51.
blodia is offline
Zephyrus
Cool Pig B)
Join Date: Jun 2010
Location: Hungary
Old 03-30-2012 , 15:05   Re: [SNIPPET][CSS]custom viewmodels without animation glitches or disabled prediction
Reply With Quote #2

very nice, so the problem why it didnt work for you the first time is that you created a new entity instead using the unused one? nice find indeed
__________________
Taking private C++/PHP/SourcePawn requests, PM me.
Zephyrus is offline
blodia
Veteran Member
Join Date: Sep 2009
Location: UK
Old 03-30-2012 , 15:08   Re: [SNIPPET][CSS]custom viewmodels without flickers and without disabling prediction
Reply With Quote #3

yeah, it would have been better if the new one worked cause i have no idea what the so called unused one is for. i'm guessing any more than the maximum not created with CreateViewModel(this checks if the client has the maximum) don't get properly linked to the player. in the original thread the first snippet i posted i was manually creating the new viewmodel based on CreateViewModel's code without the check which is proberly why it didn't work.

Last edited by blodia; 03-30-2012 at 15:20.
blodia is offline
GoD-Tony
Veteran Member
Join Date: Jul 2005
Old 03-31-2012 , 11:43   Re: [SNIPPET][CSS]custom viewmodels without flickers and without disabling prediction
Reply With Quote #4

From a quick test this seems to be working great. Very nice find blodia.
__________________
GoD-Tony is offline
Blowst
Member
Join Date: Feb 2011
Location: Korea, Republic of
Old 04-01-2012 , 11:45   Re: [SNIPPET][CSS]custom viewmodels without flickers and without disabling prediction
Reply With Quote #5

Great! Enormous Thanks!!
__________________
Sorry about my poor English


Blowst is offline
andi67
Veteran Member
Join Date: Mar 2007
Location: Somewhere near you!!!
Old 04-02-2012 , 10:35   Re: [SNIPPET][CSS]custom viewmodels without flickers and without disabling prediction
Reply With Quote #6

seems like DODS didn´t like it , I got this errors:
Quote:
L 04/02/2012 - 15:40:20: [SM] [0] Line 136, D:\e\Plugins Sourcemod\sourcemod-1.4.1-windows\addons\sourcemod\scripting\viewmodelc hanger.sp::OnPostThinkPost()
L 04/02/2012 - 15:40:20: [SM] Native "GetEntPropEnt" reported: Property "m_hWeapon" not found (entity 0/worldspawn)
L 04/02/2012 - 15:40:20: [SM] Displaying call stack trace for plugin "viewmodelchanger.smx":
L 04/02/2012 - 15:40:20: [SM] [0] Line 122, D:\e\Plugins Sourcemod\sourcemod-1.4.1-windows\addons\sourcemod\scripting\viewmodelc hanger.sp::OnPostThinkPost()
L 04/02/2012 - 15:40:20: [SM] Native "GetEntPropEnt" reported: Property "m_hWeapon" not found (entity 0/worldspawn)
L 04/02/2012 - 15:40:20: [SM] Displaying call stack trace for plugin "viewmodelchanger.smx":
__________________
andi67 is offline
blodia
Veteran Member
Join Date: Sep 2009
Location: UK
Old 04-02-2012 , 11:46   Re: [SNIPPET][CSS]custom viewmodels without flickers and without disabling prediction
Reply With Quote #7

looks like you only have one viewmodel, try the sdkcall mentioned in the first post with 1 as the parameter, if it still doesn't work then it means you can only have one viewmodel in dods.
blodia is offline
andi67
Veteran Member
Join Date: Mar 2007
Location: Somewhere near you!!!
Old 04-03-2012 , 00:05   Re: [SNIPPET][CSS]custom viewmodels without flickers and without disabling prediction
Reply With Quote #8

https://developer.valvesoftware.com/wiki/Viewmodel

Valve says each player has 2 viewmodels.....?
__________________

Last edited by andi67; 04-03-2012 at 00:28.
andi67 is offline
triohala
Junior Member
Join Date: Apr 2012
Old 04-05-2012 , 05:29   Re: [SNIPPET][CSS]custom viewmodels without flickers and without disabling prediction
Reply With Quote #9

I have problem with hands animation ("m_nSequence"), than hit to wall or something animations works, because m_nSequence randomly changes to 2,4,5... but if you hitting nothing, just slashing air, m_nSequence returns 3 every time, so animation stuck.. So you need wait after m_nSequence return 0 and than press one time left (or right) mouse button, and again wait... if dont wait.. animation stuck.... ;/

Last edited by triohala; 04-05-2012 at 05:30.
triohala is offline
blodia
Veteran Member
Join Date: Sep 2009
Location: UK
Old 04-05-2012 , 13:56   Re: [SNIPPET][CSS]custom viewmodels without flickers and without disabling prediction
Reply With Quote #10

m_nSequence is the animation played so it changes whenever an animation is played. to me seems the model you're using doesn't have all the animations or same animation names.

m_nSequence is an enumeration of all the animations compiled in the model, from what i can tell 0 is the idle animation, i'm not sure how the rest are listed. as i mentioned in the first post your custom model must have the same number of animations or with will edit glitches when the game tries to play animations that aren't there, same issue if the names don't match as the game plays animations by name. if the custom model animations are too long they will get cut short when another animation begins or if they're too short you will get pauses before the next one e.g reload animation will finish but the gun hasn't reloaded yet.
blodia is offline
Reply


Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT -4. The time now is 22:52.


Powered by vBulletin®
Copyright ©2000 - 2015, vBulletin Solutions, Inc.
Theme made by Freecode