Hey all,
Sooooo, there was something bugging me for a while now, and that is the fact that most of the character creation resources / frameworks feel…incomplete. More specifically, it felt like the hairstyles (default ones) are not…finished.
In this thread / tutorial / thing, I am going to show you how to go from this:
To this:
The problem:
The reason why some haircuts look weird on most servers, but ok-ish (at least better) in GTA:O, is because R* uses “Ped Decorations” to fill in the textures. (just like tattoos, clothing details, and some other stuff).
Those decorations are not set with the hair Ped Component, but you have to add them yourself, using AddPedDecorationFromHashes(): AddPedDecorationFromHashes - FiveM Natives @ Cfx.re Docs
The data:
ok CritteR, but how do I know which decoration goes for my haircut??
Well…you don’t, but I do (for most of them), and I am going to give you my full list (and implementation).
Behold, my wacky mapping-array-translator-thing:
hairDecorDefault = {'mpbeach_overlays', "FM_hair_fuzz"} --if the haircut is not there, add some hair fuzz. It will not always match, but it's better than having the hair look "glued on".
hairDecor = {
['m'] = {
[0] = {"",""}, --who doesn't like a shiny head from time to time?
[1] = {"multiplayer_overlays", "FM_M_Hair_001_a"},
[2] = {"multiplayer_overlays", "NG_M_Hair_002"},
[3] = {"multiplayer_overlays", "FM_M_Hair_003_a"},
[4] = {"multiplayer_overlays", "NG_M_Hair_004"},
[5] = {"multiplayer_overlays", "FM_M_Hair_long_a"},
[6] = {"multiplayer_overlays", "FM_M_Hair_006_a"},
[8] = {"multiplayer_overlays", "FM_M_Hair_008_a"},
[9] = {"multiplayer_overlays", "NG_M_Hair_009"},
[10] = {"multiplayer_overlays", "NG_M_Hair_013"},
[11] = {"multiplayer_overlays", "NG_M_Hair_002"},
[12] = {"multiplayer_overlays", "NG_M_Hair_011"},
[13] = {"multiplayer_overlays", "NG_M_Hair_012"},
[14] = {"multiplayer_overlays", "NG_M_Hair_014"},
[15] = {"multiplayer_overlays", "NG_M_Hair_015"},
[16] = {"multiplayer_overlays", "NGBea_M_Hair_000"},
[17] = {"multiplayer_overlays", "NGBea_M_Hair_001"},
[18] = {"mpbusiness_overlays", "FM_Bus_M_Hair_000_a"},
[19] = {"mpbusiness_overlays", "FM_Bus_M_Hair_001_a"},
[20] = {"mphipster_overlays", "FM_Hip_M_Hair_000_a"},
[21] = {"mphipster_overlays", "FM_Hip_M_Hair_001_a"},
[22] = {"multiplayer_overlays", "NGInd_M_Hair_000"},
--23
[24] = {"mplowrider_overlays", "LR_M_Hair_000"},
[25] = {"mplowrider_overlays", "LR_M_Hair_001"},
[26] = {"mplowrider_overlays", "LR_M_Hair_002"},
[27] = {"mplowrider_overlays", "LR_M_Hair_003"},
[28] = {"mplowrider2_overlays", "LR_M_Hair_004"},
[29] = {"mplowrider2_overlays", "LR_M_Hair_005"},
[30] = {"mplowrider2_overlays", "LR_M_Hair_006"},
[31] = {"mpbiker_overlays", "MP_Biker_Hair_000_M"},
[32] = {"mpbiker_overlays", "MP_Biker_Hair_001_M"},
[33] = {"mpbiker_overlays", "MP_Biker_Hair_002_M"},
[34] = {"mpbiker_overlays", "MP_Biker_Hair_003_M"},
[35] = {"mpbiker_overlays", "MP_Biker_Hair_004_M"},
[36] = {"mpbiker_overlays", "MP_Biker_Hair_005_M"},
[72] = {"mpgunrunning_overlays", "MP_Gunrunning_Hair_M_000_M"},
[73] = {"mpgunrunning_overlays", "MP_Gunrunning_Hair_M_001_M"},
[74] = {"mpvinewood_overlays", "MP_Vinewood_Hair_M_000_M"},
[75] = {"mptuner_overlays", "MP_Tuner_Hair_001_M"},
[76] = {"mpsecurity_overlays", "MP_Security_Hair_001_M"},
},
['f'] = {
[0] = {"",""}, --who doesn't like a shiny head from time to time?
[1] = {"multiplayer_overlays", "NG_F_Hair_001"},
[2] = {"multiplayer_overlays", "NG_F_Hair_002"},
[3] = {"multiplayer_overlays", "FM_F_Hair_003_a"},
[4] = {"multiplayer_overlays", "NG_F_Hair_004"},
[5] = {"multiplayer_overlays", "FM_F_Hair_005_a"},
[6] = {"multiplayer_overlays", "FM_F_Hair_006_a"},
[7] = {"multiplayer_overlays", "NG_F_Hair_007"},
[8] = {"multiplayer_overlays", "NG_F_Hair_008"},
[9] = {"multiplayer_overlays", "NG_F_Hair_009"},
[10] = {"multiplayer_overlays", "NG_F_Hair_010"},
[11] = {"multiplayer_overlays", "NG_F_Hair_011"},
[12] = {"multiplayer_overlays", "NG_F_Hair_012"},
[13] = {"multiplayer_overlays", "FM_F_Hair_013_a"},
[14] = {"multiplayer_overlays", "FM_F_Hair_014_a"},
[15] = {"multiplayer_overlays", "NG_M_Hair_015"},
[16] = {"multiplayer_overlays", "NGBea_F_Hair_000"},
[17] = {"mpbusiness_overlays", "FM_Bus_F_Hair_a"},
[18] = {"multiplayer_overlays", "NG_F_Hair_007"},
[19] = {"multiplayer_overlays", "NGBus_F_Hair_000"},
[20] = {"multiplayer_overlays", "NGBus_F_Hair_001"},
[21] = {"multiplayer_overlays", "NGBea_F_Hair_001"},
[22] = {"mphipster_overlays", "FM_Hip_F_Hair_000_a"},
[23] = {"multiplayer_overlays", "NGInd_F_Hair_000"},
--24
[25] = {"mplowrider_overlays", "LR_F_Hair_000"},
[26] = {"mplowrider_overlays", "LR_F_Hair_001"},
[27] = {"mplowrider_overlays", "LR_F_Hair_002"},
[29] = {"mplowrider2_overlays", "LR_F_Hair_003"},
[30] = {"mplowrider2_overlays", "LR_F_Hair_004"},
[31] = {"mplowrider2_overlays", "LR_F_Hair_006"},
[32] = {"mpbiker_overlays", "MP_Biker_Hair_000_F"},
[33] = {"mpbiker_overlays", "MP_Biker_Hair_001_F"},
[34] = {"mpbiker_overlays", "MP_Biker_Hair_002_F"},
[35] = {"mpbiker_overlays", "MP_Biker_Hair_003_F"},
[38] = {"mpbiker_overlays", "MP_Biker_Hair_004_F"},
[36] = {"mpbiker_overlays", "MP_Biker_Hair_005_F"},
[37] = {"mpbiker_overlays", "MP_Biker_Hair_005_F"},
[76] = {"mpgunrunning_overlays", "MP_Gunrunning_Hair_F_000_F"},
[77] = {"mpgunrunning_overlays", "MP_Gunrunning_Hair_F_001_F"},
[78] = {"mpvinewood_overlays", "MP_Vinewood_Hair_F_000_F"},
[79] = {"mptuner_overlays", "MP_Tuner_Hair_000_F"},
[80] = {"mpsecurity_overlays", "MP_Security_Hair_000_F"},
},
}
This is basically:
hairDecor[Ped_Type][Hair Drawable ID] = {_decorCollection, _decorOverlay}
What I did basically, I opened up openIV
, searched for hair overlays through all the DLCs overlay .xmls, and matched them with hair component drawable ids that I thought matched what R* uses.
Some of them are missing, and I suspect R* uses a generic decoration for them, like the hair fuzz, or “FM_M_Hair_long_a”.
My solution:
I just added this code, after setting up my hair component:
if hairDecor[char.gender][char.hair] ~= nil then
AddPedDecorationFromHashes(ped, hairDecor[char.gender][char.hair][1], hairDecor[char.gender][char.hair][2])
else
AddPedDecorationFromHashes(ped, hairDecorDefault[1], hairDecorDefault[2])
end
In my case:
-- ped = PlayerPedId()
-- char.gender = "m" or "f", depending on freemode_ped used.
-- char.hair = GetPedDrawableVariation(ped, 2)
Notes:
When doing this in a, let’s say, barber shop menu, keep in mind that AddPedDecorationFromHashes(), as the native implies, ADDS decorations, not REPLACE them!
I, personally, use ClearPedDecorations(ped)
before setting the hair decorator. This will 100% cause problems if you have tattoos on your peds, but that’s a bug future CritteR will have to deal with.