AlliedModders

AlliedModders (https://forums.alliedmods.net/index.php)
-   Code Snippets/Tutorials (https://forums.alliedmods.net/forumdisplay.php?f=83)
-   -   [TUT] 1 Player Model For All - The best anti-crash way (https://forums.alliedmods.net/showthread.php?t=344166)

Jhob94 10-06-2023 09:25

[TUT] 1 Player Model For All - The best anti-crash way
 
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.

mlibre 10-19-2023 09:50

Re: [TUT] 1 Player Model For All - The best anti-crash way
 
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

Jhob94 10-19-2023 10:07

Re: [TUT] 1 Player Model For All - The best anti-crash way
 
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)


All times are GMT -4. The time now is 04:43.

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