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

[TUT] 1 Player Model For All - The best anti-crash way


Post New Thread Reply   
 
Thread Tools Display Modes
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
mlibre
Veteran Member
Join Date: Nov 2015
Location: return PLUGIN_CONTINUE
Old 10-19-2023 , 09:50   Re: [TUT] 1 Player Model For All - The best anti-crash way
Reply With Quote #2

I have not tried this method, I usually use EV_INT_skin to "merge" several models into one, of course it only changes the color
__________________
mlibre is offline
Jhob94
AMX Mod X Donor
Join Date: Jul 2012
Old 10-19-2023 , 10:07   Re: [TUT] 1 Player Model For All - The best anti-crash way
Reply With Quote #3

At first it may seem complicated but it is actually pretty simple.
The only problem is that you can’t insert some models into sub-models. I am not sure what’s the Polys limit but if the model has several polys divided into several body-parts you won’t be able to use it. (At least i’ve no idea how to combine them, i am not a model expert)
__________________
Jhob94 is offline
Reply



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 05:29.


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