Raised This Month: $12 Target: $400
 3% 

[TUT-CS] Changing player models and lowering svc_bad


Post New Thread Reply   
 
Thread Tools Display Modes
Author Message
MeRcyLeZZ
Veteran Member
Join Date: Dec 2007
Old 04-02-2008 , 21:41   [TUT-CS] Changing player models and lowering svc_bad
Reply With Quote #1

Update: (07/2011)
You can now download the CS Player Models API with built in svc_bad prevention here:
http://forums.alliedmods.net/showthread.php?t=161255

About

This tutorial is intended for intermediate to advanced AMXX scripters who have to deal with changing player models in Counter-Strike. It will go over the different available methods and their incidence on the commonly known SVC_BAD errors.

SVC_BAD

If you are unaware of it, this error is usually caused by badly formed engine messages. When they arrive, the most likely outcome is your getting kicked out of the server you were playing on, and one of these errors showing up on your console:
  • Host_Error: Illegible Server Message: SVC_BAD
  • Host_Error: UserMsg: Not Present on Client ###
  • Host_Error: CL_ParseServerMessage: Bad server message
  • And the like...
Normally, reasons of this are:
  • Network data getting corrupted on the way
  • MODs or plugins sending a nonexistant/invalid message
  • MODs or plugins sending messages with an incorrect number of arguments
However, it also shows up when changing lots of player models at once and it's triggered on almost every client for no apparent reason. Probably some kind of glitch that VALVe will never fix, so what can we do about it? Read on...


Natives from the CStrike module

Probably your first attempt at changing player models was using these. Sure, this method has the advantage of simplicity and you only have to learn three natives. But we're gonna see why you shouldn't be using them if your plugin changes many models (e.g. zombie mods).

From looking at the source, we know that it sets the model on the player's InfoBuffer and keeps track of it, nothing wrong with that so far...
Code:
static cell AMX_NATIVE_CALL cs_set_user_model(AMX *amx, cell *params) // cs_set_user_model(index, const model[]); = 2 params
{
	// ...

	g_players[params[1]].SetModel(model);
	g_players[params[1]].SetModelled(true);

	SETCLIENTKEYVALUE(params[1], GETINFOKEYBUFFER(pPlayer), "model", (char*)g_players[params[1]].GetModel());

	// ...
}
But here's the thing: to prevent CS from resetting the custom model, it does its checks on Player PostThink events so that when the model changes the custom one is immediately set back again.
Code:
void PlayerPostThink(edict_t* pPlayer) {
	int entityIndex = ENTINDEX(pPlayer);

	if(g_players[entityIndex].GetModelled()) {
		if (g_players[entityIndex].GetInspectModel() && strcmp(g_players[entityIndex].GetModel(), GETCLIENTKEYVALUE(GETINFOKEYBUFFER(pPlayer), "model")) != 0) {
			//LOG_CONSOLE(PLID, "%s should have model %s and currently has %s", STRING(pPlayer->v.netname), (char*)g_players[entityIndex].GetModel(), GETCLIENTKEYVALUE(GETINFOKEYBUFFER(pPlayer), "model"));
			SETCLIENTKEYVALUE(entityIndex, GETINFOKEYBUFFER(pPlayer), "model", (char*)g_players[entityIndex].GetModel());
			g_players[entityIndex].SetInspectModel(false);
		}
	}
	RETURN_META(MRES_IGNORED);
}
The problem comes on events like round start, when CS sets everyone's model back to the default ones (gign, sas, leet, etc). So if someone has a custom model it goes like this:
  • Player is given a custom model "zombie" - a message is sent to all players notifying of this
  • New Round - a lot of messages are sent: update scores, remove entites, spawn players, etc.
  • CS resets Player's model back to "leet" - another message added to the list
  • Player's model is changed again instantly on PostThink - yet another one
As you can see, a lot of network traffic goes on when a new round begins. You can even check it out by yourself with plugins like Message Logging by Damaged Soul.

Now, say all 32 players on the server have custom models. If it normally gets to send a lot of stuff when the round starts, now you have to include all the model update messages. Here's when the glitch we previosuly talked about takes part in: it would seem that whenever someone is close to getting a network channel overflow (i.e. receives too much data at once), then [almost] every player is kicked out with SVC_BAD...

Or at least that's what I noticed. And if you're lucky enough to remain unkicked, you may also note that the game world "freezes" for some seconds while the other players are being kicked (like some server side "high CPU usage" kind of lag).

-----

By the way, another issue you may run into when having the CStrike module handle your custom models, is that whenever you use the cs_set_user_team() native on a player, his model gets changed regardless of passing CS_DONTCHANGE as a third argument.

We can see the reason of this by taking a look at the source code again.
Code:
static cell AMX_NATIVE_CALL cs_set_user_team(AMX *amx, cell *params) // cs_set_user_team(index, team, model = 0); = 3 params
{
	// ...

	int model = params[3];

	*((int *)pPlayer->pvPrivateData + OFFSET_TEAM) = params[2];
	if (model != 0)
		*((int *)pPlayer->pvPrivateData + OFFSET_INTERNALMODEL) = model;
	
	// This makes the model get updated right away.
	MDLL_ClientUserInfoChanged(pPlayer, GETINFOKEYBUFFER(pPlayer)); //  If this causes any problems for WON, do this line only in STEAM builds.

	// ...
}
After the team and internal model are set, it makes a call to DLL_ClientUserInfoChanged, which effectively causes CS to reset the player's model.

-----


Workaround #1 - Using Fakemeta

So basically we need to find a way to reproduce the functionality of the previous natives that allows us to have full control over them, to avoid having our models changed all at once on round start. Fakemeta has all we need.

There are 5 things we're gonna have to cover:
  • Setting a player's model
  • Retrieving a player's model
  • Setting back the original (default) model
  • Preventing CS from changing our custom model
  • Preventing players from changing our custom model

To start with, you should set up 2 global arrays: the first one will be a boolean indicating whether the player is using a custom model or not, and the second will store the name (string) of the custom model when present.
Code:
new g_has_custom_model[33] new g_player_model[33][32]
1. To set a model we simply tell the engine to set the new KeyValue pair for the Client:
Code:
stock fm_cs_set_user_model( player, const modelname[] ) {     // Set new model     engfunc( EngFunc_SetClientKeyValue, player, engfunc( EngFunc_GetInfoKeyBuffer, player ), "model", modelname )         // Remember this player has a custom model     g_has_custom_model[player] = true }
2. To retrieve the model: we could just make use of the cs_get_user_model() native, but if you're planning not to include <cstrike> at all, use this instead: (edit: model is now passed byref- thanks XxAvalanchexX)
Code:
stock fm_cs_get_user_model( player, model[], len ) {     // Retrieve current model     engfunc( EngFunc_InfoKeyValue, engfunc( EngFunc_GetInfoKeyBuffer, player ), "model", model, len ) }
3. To restore the default model, as we've seen earlier it's enough to tell the engine the Client's UserInfo has changed, and CS will do the job for us:
Code:
stock fm_cs_reset_user_model( player ) {     // Player doesn't have a custom model any longer     g_has_custom_model[player] = false         dllfunc( DLLFunc_ClientUserInfoChanged, player, engfunc( EngFunc_GetInfoKeyBuffer, player ) ) }
4. To block CS from changing the model, we make use of the forward FM_SetClientKeyValue:
Code:
public plugin_init() {     // ...     register_forward( FM_SetClientKeyValue, "fw_SetClientKeyValue" ) } public fw_SetClientKeyValue( id, const infobuffer[], const key[] ) {     // Block CS model changes     if ( g_has_custom_model[id] && equal( key, "model" ) )         return FMRES_SUPERCEDE;         return FMRES_IGNORED; }
5. However, since we are blocking SetClientKeyValue, CS will no longer prevent a player from changing his model by typing model "modelname" in his console (thanks Cheap_Suit). So we have to take care of this as well:
Code:
public plugin_init() {     // ...     register_forward( FM_SetClientKeyValue, "fw_SetClientKeyValue" ) } public fw_SetClientKeyValue( id, const infobuffer[], const key[] ) {     // Block CS model changes     if ( g_has_custom_model[id] && equal( key, "model" ) )     {         // Get current model         static currentmodel[32]         fm_cs_get_user_model( id, currentmodel, charsmax( currentmodel ) )                 // Check whether it matches the custom model - if not, set it again         if ( !equal( currentmodel, g_player_model[id] ) )             fm_cs_set_user_model( id, g_player_model[id] )                 return FMRES_SUPERCEDE;     }         return FMRES_IGNORED; }
Note that you can also use: set_user_info( player, "model", modelname ) and get_user_info( player, "model", model[], len ) to set and retrieve player models. They seem to work fine too and are easier to type, but this was supposed to be FakeMeta's way so yeah...

Finally, to make sure there is always a delay between model changes, you can use the following code whenever you need to change a player's model:
Code:
#define MODELCHANGE_DELAY 0.5 // delay between model changes new Float:g_models_targettime // target time for the last model change public fm_cs_user_model_update( id ) {     static Float:current_time     current_time = get_gametime()         // Delay needed?     if ( current_time - g_models_targettime >= MODELCHANGE_DELAY )     {         fm_cs_set_user_model( id )         g_models_targettime = current_time     }     else     {         set_task( (g_models_targettime + MODELCHANGE_DELAY) - current_time, "fm_cs_set_user_model", id )         g_models_targettime = g_models_targettime + MODELCHANGE_DELAY     } }

OK, that's about it. Now you can have tasks in your script changing player models one at a time, instead of all of them changed instantly on Round Start. For an example check CS Player Models API (link at the top).


Workaround #2 - Separate entities

Say you already tried implementing the previous method into your plugin and setting longer delays for the tasks, but you're still getting SVC_BAD every now and then. Is there any other solution worth a try? Well, simply don't change any models. Hey, I'm being serious!

This last method consists on making the actual players invisible and having individual entities (which have your custom player models) to follow them and copy their movements. So even though it looks like it, you aren't actually changing player models at all and no SVC_BAD kicking should occur. (idea taken from ChickenMod 1.0.5.1)

Bad news are, the entities could fail to create or just make the server less stable (not to mention that a higher entity count also means higher CPU usage), so it's kinda experimental.

That said, let's get on with it. Note that you'll need 2 entities for every player, since making them invisible also hides their weapons. First, set up 3 global arrays. One to store the model name, while the others will be used to store the index of the entities following the player. Also, add defines for their classnames if you wish.
Code:
new g_player_model[33][32] new g_ent_playermodel[33] new g_ent_weaponmodel[33] new const PLAYERMODEL_CLASSNAME[] = "ent_playermodel" new const WEAPONMODEL_CLASSNAME[] = "ent_weaponmodel"
Next, this is the function you'll need to call whenever you want to set a custom player model:
Code:
stock fm_set_playermodel_ent( id, const modelname[] ) {     // Make original player entity invisible     set_pev( id, pev_rendermode, kRenderTransTexture )     // This is not 0 because it would hide the shadow and some effects when firing weapons     set_pev( id, pev_renderamt, 1.0 )         // Since we're passing the short model name to the function     // we need to make the full path out of it     static modelpath[100]     formatex( modelpath, charsmax( modelpath ), "models/player/%s/%s.mdl", modelname, modelname )         // Check if the entity assigned to this player exists     if ( !pev_valid( g_ent_playermodel[id] ) )     {         // If it doesn't, proceed to create a new one         g_ent_playermodel[id] = engfunc( EngFunc_CreateNamedEntity, engfunc( EngFunc_AllocString, "info_target" ) )                 // If it failed to create for some reason, at least this will prevent further "Invalid entity" errors...         if ( !pev_valid( g_ent_playermodel[id] ) ) return;                 // Set its classname         set_pev( g_ent_playermodel[id], pev_classname, PLAYERMODEL_CLASSNAME )                 // Make it follow the player         set_pev( g_ent_playermodel[id], pev_movetype, MOVETYPE_FOLLOW )         set_pev( g_ent_playermodel[id], pev_aiment, id )         set_pev( g_ent_playermodel[id], pev_owner, id )     }         // Entity exists now, set its model     engfunc( EngFunc_SetModel, g_ent_playermodel[id], modelpath ) }
This stock will return whether a player is using a custom model:
Code:
stock fm_has_custom_model( id ) {     return pev_valid( g_ent_playermodel[id] ) ? true : false; }
This one will be called after a weapon change event to update our "weaponmodel" ent:
Code:
stock fm_set_weaponmodel_ent( id ) {     // Get the player's p_ weapon model     static model[100]     pev( id, pev_weaponmodel2, model, charsmax( model ) )         // Check if the entity assigned to this player exists     if ( !pev_valid(g_ent_weaponmodel[id]) )     {         // If it doesn't, proceed to create a new one         g_ent_weaponmodel[id] = engfunc( EngFunc_CreateNamedEntity, engfunc( EngFunc_AllocString, "info_target" ) )                 // If it failed to create for some reason, at least this will prevent further "Invalid entity" errors...         if ( !pev_valid( g_ent_weaponmodel[id] ) ) return;                 // Set its classname         set_pev( g_ent_weaponmodel[id], pev_classname, WEAPONMODEL_CLASSNAME )                 // Make it follow the player         set_pev( g_ent_weaponmodel[id], pev_movetype, MOVETYPE_FOLLOW )         set_pev( g_ent_weaponmodel[id], pev_aiment, id )         set_pev( g_ent_weaponmodel[id], pev_owner, id )     }         // Entity exists now, set its model     engfunc( EngFunc_SetModel, g_ent_weaponmodel[id], model ) }
Finally, this is the function that will get rid of your custom player model: (and entities)
Code:
stock fm_remove_model_ents( id ) {     // Make the player visible again     set_pev( id, pev_rendermode, kRenderNormal )         // Remove "playermodel" ent if present     if ( pev_valid( g_ent_playermodel[id] ) )     {         engfunc( EngFunc_RemoveEntity, g_ent_playermodel[id] )         g_ent_playermodel[id] = 0     }     // Remove "weaponmodel" ent if present     if ( pev_valid( g_ent_weaponmodel[id] ) )     {         engfunc( EngFunc_RemoveEntity, g_ent_weaponmodel[id] )         g_ent_weaponmodel[id] = 0     } }
It wasn't that hard right? But there are still some issues left to take care of...

1. When a player dies, the corpse that's spawned on the ground will not have the custom model set. To fix this we need to hook the corpse message like so:
Code:
public plugin_init() {     // ...     register_message( get_user_msgid( "ClCorpse" ), "message_clcorpse" ) } public message_clcorpse() {     // Get player's id     static id     id = get_msg_arg_int( 12 )         // Check if the player is using a custom player model     if ( fm_has_custom_model( id ) )     {         // Set correct model on player corpse         set_msg_arg_string( 1, g_player_model[id] )     } }
2. If we want to give the player a different rendering (e.g. glow) we'll need to set it on our custom entity instead:
Code:
// Set a red glow on the "playermodel" entity set_pev( g_ent_playermodel[id], pev_renderfx, kRenderFxGlowShell ) set_pev( g_ent_playermodel[id], pev_color, Float:{200.0, 0.0, 0.0} ) set_pev( g_ent_playermodel[id], pev_renderamt, 50.0 ) // Or, if you're using fakemeta_util's stock instead: fm_set_rendering( g_ent_playermodel[id], kRenderFxGlowShell, 200, 0, 0, kRenderNormal, 50 )
3. If the model is big enough, its owner may be able to see part of it even though he shouldn't: (thanks Orangutanz)
Edit: You might not need this one after all, I did some tests and the models were automatically hidden to me. In such case better leave it out, since it's an expensive forward.
Code:
public plugin_init() {     // ...     register_forward( FM_AddToFullPack, "fw_AddToFullPack" ) } public fw_AddToFullPack( es, e, ent, host, hostflags, player ) {     // Narrow down our matches a bit     if ( player ) return FMRES_IGNORED;         // Check if it's one of our custom model ents being sent to its owner     if ( ent == g_ent_playermodel[host] || ent == g_ent_weaponmodel[host] )         return FMRES_SUPERCEDE;         return FMRES_IGNORED; }

Alright, I'm gonna put it all together in a nice example now for clarity:
Code:
#include <amxmodx> #include <fakemeta> #include <hamsandwich> #include <cstrike> new const ZOMBIE_MODEL[] = "zombie" // The model we're gonna use for zombies new const PLAYERMODEL_CLASSNAME[] = "ent_playermodel" new const WEAPONMODEL_CLASSNAME[] = "ent_weaponmodel" new g_player_model[33][32] // player's model name (string) new g_ent_playermodel[33] // playermodel entity following this player new g_ent_weaponmodel[33] // weaponmodel entity following this player new g_zombie[33] // whether the player is a zombie new g_glow[33] // whether the player has glow /*================================================================================  [Plugin Start] =================================================================================*/ public plugin_precache() {     new modelpath[100]     formatex( modelpath, charsmax( modelpath ), "models/player/%s/%s.mdl", ZOMBIE_MODEL, ZOMBIE_MODEL )     engfunc( EngFunc_PrecacheModel, modelpath ) } public plugin_init() {     register_plugin( "Player Model Changer Example", "0.3", "MeRcyLeZZ" )         RegisterHam( Ham_Spawn, "player", "fw_PlayerSpawn", 1 )     register_forward( FM_AddToFullPack, "fw_AddToFullPack" )     register_event( "CurWeapon", "event_curweapon", "be", "1=1" )     register_message( get_user_msgid( "ClCorpse" ), "message_clcorpse" )         register_clcmd( "say /glow", "clcmd_sayglow" ) } /*================================================================================  [Player Spawn Event] =================================================================================*/ public fw_PlayerSpawn( id ) {        // Not alive or didn't join a team yet     if ( !is_user_alive( id ) || !cs_get_user_team( id ) )         return;         // Set to zombie if on Terrorist team     g_zombie[id] = cs_get_user_team( id ) == CS_TEAM_T ? true : false;         // Check if the player is a zombie     if ( g_zombie[id] )     {         // Store our custom model in g_player_model[id]         copy( g_player_model[id], charsmax( g_player_model[] ), ZOMBIE_MODEL )                 // Set the model on our playermodel entity         fm_set_playermodel_ent( id, g_player_model[id] )     }     // Not a zombie, but still has a custom model     else if ( fm_has_custom_model( id ) )     {         // Reset it back to default         fm_remove_model_ents( id )     } } /*================================================================================  [Add to Full Pack Forward] =================================================================================*/ public fw_AddToFullPack( es, e, ent, host, hostflags, player ) {     // Narrow down our matches a bit     if ( player ) return FMRES_IGNORED;         // Check if it's one of our custom model ents being sent to its owner     if ( ent == g_ent_playermodel[host] || ent == g_ent_weaponmodel[host] )         return FMRES_SUPERCEDE;         return FMRES_IGNORED; } /*================================================================================  [Weapon Change Event] =================================================================================*/ public event_curweapon( id ) {     // Check if the player is using a custom player model     if ( fm_has_custom_model( id ) )     {         // Update weapon model on entity         fm_set_weaponmodel_ent( id )     } } /*================================================================================  [ClCorpse Message] =================================================================================*/ public message_clcorpse() {     // Get player's id     static id     id = get_msg_arg_int( 12 )         // Check if the player is using a custom player model     if ( fm_has_custom_model( id ) )     {         // Set correct model on player corpse         set_msg_arg_string( 1, g_player_model[id] )     } } /*================================================================================  [Client Disconnect Event] =================================================================================*/ public client_disconnect( id ) {     // Check if the player was using a custom player model     if ( fm_has_custom_model( id ) )     {         // Remove custom entities         fm_remove_model_ents( id )     } } /*================================================================================  [Client Command: Say /Glow] =================================================================================*/ public clcmd_sayglow( id ) {     // Turn glow on/off     g_glow[id] = !( g_glow[id] )         // Check if the player is using a custom player model     if ( fm_has_custom_model( id ) )     {         // Check if the player has glow         if ( g_glow[id] )         {             // Set glow on playermodel entity             fm_set_rendering( g_ent_playermodel[id], kRenderFxGlowShell, 200, 0, 0, kRenderNormal, 50 )         }         else         {             // Remove glow on playermodel entity             fm_set_rendering( g_ent_playermodel[id] )         }     }     else     {         // Set and remove glow the usual way         if ( g_glow[id] )         {             fm_set_rendering( id, kRenderFxGlowShell, 200, 0, 0, kRenderNormal, 50 )         }         else         {             fm_set_rendering( id )         }     } } /*================================================================================  [Stocks] =================================================================================*/ stock fm_set_playermodel_ent( id, const modelname[] ) {     // Make original player entity invisible     set_pev( id, pev_rendermode, kRenderTransTexture )     // This is not 0 because it would hide the shadow and some effects when firing weapons     set_pev( id, pev_renderamt, 1.0 )         // Since we're passing the short model name to the function     // we need to make the full path out of it     static modelpath[100]     formatex( modelpath, charsmax( modelpath ), "models/player/%s/%s.mdl", modelname, modelname )         // Check if the entity assigned to this player exists     if ( !pev_valid( g_ent_playermodel[id] ) )     {         // If it doesn't, proceed to create a new one         g_ent_playermodel[id] = engfunc( EngFunc_CreateNamedEntity, engfunc( EngFunc_AllocString, "info_target" ) )                 // If it failed to create for some reason, at least this will prevent further "Invalid entity" errors...         if ( !pev_valid( g_ent_playermodel[id] ) ) return;                 // Set its classname         set_pev( g_ent_playermodel[id], pev_classname, PLAYERMODEL_CLASSNAME )                 // Make it follow the player         set_pev( g_ent_playermodel[id], pev_movetype, MOVETYPE_FOLLOW )         set_pev( g_ent_playermodel[id], pev_aiment, id )         set_pev( g_ent_playermodel[id], pev_owner, id )     }         // Entity exists now, set its model     engfunc( EngFunc_SetModel, g_ent_playermodel[id], modelpath ) } stock fm_has_custom_model( id ) {     return pev_valid( g_ent_playermodel[id] ) ? true : false; } stock fm_set_weaponmodel_ent( id ) {     // Get the player's p_ weapon model     static model[100]     pev( id, pev_weaponmodel2, model, charsmax( model ) )         // Check if the entity assigned to this player exists     if ( !pev_valid(g_ent_weaponmodel[id]) )     {         // If it doesn't, proceed to create a new one         g_ent_weaponmodel[id] = engfunc( EngFunc_CreateNamedEntity, engfunc( EngFunc_AllocString, "info_target" ) )                 // If it failed to create for some reason, at least this will prevent further "Invalid entity" errors...         if ( !pev_valid( g_ent_weaponmodel[id] ) ) return;                 // Set its classname         set_pev( g_ent_weaponmodel[id], pev_classname, WEAPONMODEL_CLASSNAME )                 // Make it follow the player         set_pev( g_ent_weaponmodel[id], pev_movetype, MOVETYPE_FOLLOW )         set_pev( g_ent_weaponmodel[id], pev_aiment, id )         set_pev( g_ent_weaponmodel[id], pev_owner, id )     }         // Entity exists now, set its model     engfunc( EngFunc_SetModel, g_ent_weaponmodel[id], model ) } stock fm_remove_model_ents( id ) {     // Make the player visible again     set_pev( id, pev_rendermode, kRenderNormal )         // Remove "playermodel" ent if present     if ( pev_valid( g_ent_playermodel[id] ) )     {         engfunc( EngFunc_RemoveEntity, g_ent_playermodel[id] )         g_ent_playermodel[id] = 0     }     // Remove "weaponmodel" ent if present     if ( pev_valid( g_ent_weaponmodel[id] ) )     {         engfunc( EngFunc_RemoveEntity, g_ent_weaponmodel[id] )         g_ent_weaponmodel[id] = 0     } } // Set entity's rendering type (from fakemeta_util) stock fm_set_rendering(entity, fx = kRenderFxNone, r = 255, g = 255, b = 255, render = kRenderNormal, amount = 16) {     new Float:color[3]     color[0] = float(r)     color[1] = float(g)     color[2] = float(b)         set_pev(entity, pev_renderfx, fx)     set_pev(entity, pev_rendercolor, color)     set_pev(entity, pev_rendermode, render)     set_pev(entity, pev_renderamt, float(amount)) }


Final Words

That's it. These are probably the best workarounds to SVC_BAD to the date. You can even try including both methods in a single plugin, and adding a define (or CVAR) for server admins to change if they're getting errors or whatever.

Also, feel free to check Zombie Plague Mod for implementation details for using multiple random models.

I'm up for any kind of suggestions, questions, comments, or experiences you've had on the subject.

Thanks for reading,
__________________

Last edited by MeRcyLeZZ; 07-06-2011 at 23:55.
MeRcyLeZZ is offline
Styles
Veteran Member
Join Date: Jul 2004
Location: California
Old 04-03-2008 , 14:41   Re: [Tutorial-CS] A word about changing player models (and lowering svc_bad errors)
Reply With Quote #2

wow this is a really good tutorial! Thanks, This is very good to know!. Btw, your english was fine
Styles is offline
Send a message via AIM to Styles
atomen
Veteran Member
Join Date: Oct 2006
Location: Stockholm, Sweden
Old 04-03-2008 , 18:36   Re: [Tutorial-CS] A word about changing player models (and lowering svc_bad errors)
Reply With Quote #3

Excellent tutorial !
I had no clue about this before.
__________________
atomen is offline
Send a message via MSN to atomen
DarkEnergy
SourceMod Donor
Join Date: Apr 2008
Location: Georgia Tech, MSECE
Old 04-06-2008 , 20:59   Re: [Tutorial-CS] A word about changing player models (and lowering svc_bad errors)
Reply With Quote #4

where is your server?
DarkEnergy is offline
XxAvalanchexX
Veteran Member
Join Date: Oct 2004
Location: abort73.com
Old 04-09-2008 , 20:51   Re: [Tutorial-CS] A word about changing player models (and lowering svc_bad errors)
Reply With Quote #5

Hiho, this is very nifty, I never even knew about this! I have a comment and a question for you. The comment: you can't really return a string for fm_get_user_model, you have to have set one by-reference. The question: since you block setclientkeyvalue, do the models still get reset on new round?
__________________
No longer around. Thanks your support, everyone! As always:
THIS ONES FOR YOU
3000 PTS
XxAvalanchexX is offline
MeRcyLeZZ
Veteran Member
Join Date: Dec 2007
Old 04-09-2008 , 21:55   Re: [Tutorial-CS] A word about changing player models (and lowering svc_bad errors)
Reply With Quote #6

Quote:
Originally Posted by DarkEnergy View Post
where is your server?
Please use PM for off-topic questions.
Quote:
Originally Posted by XxAvalanchexX View Post
Hiho, this is very nifty, I never even knew about this! I have a comment and a question for you. The comment: you can't really return a string for fm_get_user_model, you have to have set one by-reference. The question: since you block setclientkeyvalue, do the models still get reset on new round?
1. My bad, I should fix that.
2. No, they never get reset/changed as long as it's blocked.

Thanks everyone for the input.
__________________
MeRcyLeZZ is offline
Cheap_Suit
Veteran Member
Join Date: May 2004
Old 04-10-2008 , 00:44   Re: [Tutorial-CS] A word about changing player models (and lowering svc_bad errors)
Reply With Quote #7

What if the user types in "model leet" for example, in the console?
__________________
HDD fried, failed to backup files. Sorry folks, just don't have free time anymore. This is goodbye.
Cheap_Suit is offline
MeRcyLeZZ
Veteran Member
Join Date: Dec 2007
Old 04-10-2008 , 16:11   Re: [Tutorial-CS] A word about changing player models (and lowering svc_bad errors)
Reply With Quote #8

Quote:
Originally Posted by Cheap_Suit View Post
What if the user types in "model leet" for example, in the console?
Damn, can't believe I missed that one. Thanks for pointing it out.
I had to make it hook ClientUserInfoChanged and check the model everytime, but it's fixed

P.S. Funny (or noob) enough, no one at my server seemed to know about that, and I had been using that code for over a month...
__________________

Last edited by MeRcyLeZZ; 04-10-2008 at 16:27.
MeRcyLeZZ is offline
DarkEnergy
SourceMod Donor
Join Date: Apr 2008
Location: Georgia Tech, MSECE
Old 04-19-2008 , 15:25   Re: [Tutorial-CS] A word about changing player models (and lowering svc_bad errors)
Reply With Quote #9

fm_set_user_model(id, modelname[]) aint working for me some how
DarkEnergy is offline
Old 04-29-2008, 16:11
atomen
This message has been deleted by atomen.
Exolent[jNr]
Veteran Member
Join Date: Feb 2007
Location: Tennessee
Old 04-29-2008 , 16:27   Re: [Tutorial-CS] A word about changing player models (and lowering svc_bad errors)
Reply With Quote #10

infobuffer on both fakemeta forwards need to be strings.

Code:
FM_SetClientKeyValue,		// void )	(iClientIndex, szInfoBuffer[], szKey[], szValue[])
FM_ClientUserInfoChanged,	// void )	(ent, szInfo[])
__________________
No private work or selling mods.
Quote:
Originally Posted by xPaw View Post
I love you exolent!
Exolent[jNr] 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 17:02.


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