View Single Post
Author Message
Jhob94
AMX Mod X Donor
Join Date: Jul 2012
Old 10-06-2023 , 09:25   [TUT] 1 Player Model For All - The best anti-crash way
Reply With Quote #1

The best anti-crash is using 1 player model for all player models. This will save you resources precached and avoid crashes on multiple model changes.

Here i will teach you how to use 1 Model and than play with Sub-Models. On plugin you will play with pev_body.

First on Model.
1. Create a Folder to gather all the player models.
2. Decompile all your models into that folder
3. Edit QC file of your main model
Code:
//reference mesh(es)
$bodygroup "studio"
{
studio "model1"
studio "model2"
studio "model3"
studio "model4"
}
4. Compile the model & it's done

Crucial Information:

- The model1/2/etc that we use on bodygroup can be named whatever you want but it must be the name of the main SMD file of the sub-model.
- Your models must be 1 Part only (unless the second part is the bomb/defuse). If your model is divided into several parts it won't work (at least i don't know how to make it work)



After everything is done properly you will have one player model with several sub-models. Now we can go to the plugin part.

Code:
#include <amxmodx>
#include <hamsandwich>
#include <fakemeta>
#include <cstrike>
#include <cl_buy>

#define TASKID 4256
#define MODEL_TASK 8425

new g_szModelName[] = "my_multimodel"

new g_iBody[33]

public plugin_init()
{
	RegisterHam(Ham_AddPlayerItem, "player", "Player__AddPlayerItem", true)
	RegisterHam(Ham_Spawn, "player", "Player__Spawn", true)
	
	register_forward(FM_SetClientKeyValue, "Fw__SetClientKeyValue")
	register_forward(FM_ClientUserInfoChanged, "Fw__ClientUserInfoChanged")
}

public plugin_precache()
{
	new szPlayerModel[64]
	formatex(szPlayerModel, charsmax(szPlayerModel), "models/player/%s/%s.mdl", g_szModelName, g_szModelName)
	
	if(file_exists(szPlayerModel))
		engfunc(EngFunc_PrecacheModel, szPlayerModel)
}

public client_putinserver(id)
	g_iBody[id] = 0

public Player__AddPlayerItem(id , iWeapon)
{
	if(cs_get_weapon_id(iWeapon) == CSW_C4)
		set_pev(id, pev_body, g_iBody[id])
}

// You can remove this if players can't buy on your server, including Task__FixBody function
public client_buy(id, iItem)
{
	if(iItem == CSW_DEFUSER && !cs_get_user_defuse(id))
		set_task(0.5, "Task__FixBody", id + TASKID)
}

public Task__FixBody(id)
{
	id -= TASKID
	
	if(is_user_alive(id))
		set_pev(id, pev_body, g_iBody[id])
}

public Player__Spawn(id)
{
	if(is_user_alive(id))
	{
		static currentmodel[32]
		engfunc(EngFunc_InfoKeyValue, engfunc(EngFunc_GetInfoKeyBuffer, id), "model", currentmodel, charsmax(currentmodel))
		
		if(!equal(currentmodel, g_szModelName))
			set_task(random_float(0.1, 2.9), "Task__SetModel", id + MODEL_TASK)
			
	/* Example:
		g_iBody[id] = cs_get_user_team(id) == CS_TEAM_CT ? 0 : 1
		
		You should set body on spawn & on events where you would change the player model. Like Zombie Plague infection
		After changing g_iBody you must change pev_body.
		The reason we are using g_iBody is because we need to store the information for when a player buys defuse kit or gets a bomb
		because that will mess with pev_body. So we either do this or a looping task to check the pev_body value. This way is better.
	*/
	}
}

public Task__SetModel(id)
{
	id -= MODEL_TASK
	
	if(is_user_alive(id))
	{
		engfunc(EngFunc_SetClientKeyValue, id, engfunc(EngFunc_GetInfoKeyBuffer, id), "model", g_szModelName)
		set_pev(id, pev_body, g_iBody[id])
	}
}

public Fw__SetClientKeyValue(id, const infobuffer[], const key[])
{   
	if(equal(key, "model") && !equal(infobuffer, g_szModelName))
		return FMRES_SUPERCEDE
		
	return FMRES_IGNORED
}

public Fw__ClientUserInfoChanged(id)
{
	static currentmodel[32]
	engfunc(EngFunc_InfoKeyValue, engfunc(EngFunc_GetInfoKeyBuffer, id), "model", currentmodel, charsmax(currentmodel))
	
	if(!equal(currentmodel, g_szModelName))
		engfunc(EngFunc_SetClientKeyValue, id, engfunc(EngFunc_GetInfoKeyBuffer, id), "model", g_szModelName)
		
	return FMRES_IGNORED
}
In that code you already change the player model, all you need to do is manipulate the g_iBody[index] and set the pev_body when you need to. You can also create a models menu.

The client_buy forward can be found here. You don't need to use it if your server doesn't allow the player to buy a defuse kit.
The bomb part should remain for safety since if a player gets the bomb it will change his pev_body.

Also you must NOT use plugins that use the cs_set_user_defuse native.
__________________

Last edited by Jhob94; 10-06-2023 at 09:28.
Jhob94 is offline