Scripts/resources/[il]/illenium-appearance/game/util.lua
2024-12-29 20:49:12 +01:00

440 lines
14 KiB
Lua

local hashesComputed = false
local PED_TATTOOS = {}
local pedModelsByHash = {}
local function tofloat(num)
return num + 0.0
end
local function isPedFreemodeModel(ped)
local model = GetEntityModel(ped)
return model == `mp_m_freemode_01` or model == `mp_f_freemode_01`
end
local function computePedModelsByHash()
for i = 1, #Config.Peds.pedConfig do
local peds = Config.Peds.pedConfig[i].peds
for j = 1, #peds do
pedModelsByHash[joaat(peds[j])] = peds[j]
end
end
end
---@param ped number entity id
---@return string
--- Get the model name from an entity's model hash
local function getPedModel(ped)
if not hashesComputed then
computePedModelsByHash()
hashesComputed = true
end
return pedModelsByHash[GetEntityModel(ped)]
end
---@param ped number entity id
---@return table<number, table<string, number>>
local function getPedComponents(ped)
local size = #constants.PED_COMPONENTS_IDS
local components = table.create(size, 0)
for i = 1, size do
local componentId = constants.PED_COMPONENTS_IDS[i]
components[i] = {
component_id = componentId,
drawable = GetPedDrawableVariation(ped, componentId),
texture = GetPedTextureVariation(ped, componentId),
}
end
return components
end
---@param ped number entity id
---@return table<number, table<string, number>>
local function getPedProps(ped)
local size = #constants.PED_PROPS_IDS
local props = table.create(size, 0)
for i = 1, size do
local propId = constants.PED_PROPS_IDS[i]
props[i] = {
prop_id = propId,
drawable = GetPedPropIndex(ped, propId),
texture = GetPedPropTextureIndex(ped, propId),
}
end
return props
end
local function round(number, decimalPlaces)
return tonumber(string.format("%." .. (decimalPlaces or 0) .. "f", number))
end
---@param ped number entity id
---@return table <number, number>
---```
---{ shapeFirst, shapeSecond, shapeThird, skinFirst, skinSecond, skinThird, shapeMix, skinMix, thirdMix }
---```
local function getPedHeadBlend(ped)
-- GET_PED_HEAD_BLEND_DATA
local shapeFirst, shapeSecond, shapeThird, skinFirst, skinSecond, skinThird, shapeMix, skinMix, thirdMix = Citizen.InvokeNative(0x2746BD9D88C5C5D0, ped, Citizen.PointerValueIntInitialized(0), Citizen.PointerValueIntInitialized(0), Citizen.PointerValueIntInitialized(0), Citizen.PointerValueIntInitialized(0), Citizen.PointerValueIntInitialized(0), Citizen.PointerValueIntInitialized(0), Citizen.PointerValueFloatInitialized(0), Citizen.PointerValueFloatInitialized(0), Citizen.PointerValueFloatInitialized(0))
shapeMix = tonumber(string.sub(shapeMix, 0, 4))
if shapeMix > 1 then shapeMix = 1 end
skinMix = tonumber(string.sub(skinMix, 0, 4))
if skinMix > 1 then skinMix = 1 end
if not thirdMix then
thirdMix = 0
end
thirdMix = tonumber(string.sub(thirdMix, 0, 4))
if thirdMix > 1 then thirdMix = 1 end
return {
shapeFirst = shapeFirst,
shapeSecond = shapeSecond,
shapeThird = shapeThird,
skinFirst = skinFirst,
skinSecond = skinSecond,
skinThird = skinThird,
shapeMix = shapeMix,
skinMix = skinMix,
thirdMix = thirdMix
}
end
---@param ped number entity id
---@return table<number, table<string, number>>
local function getPedFaceFeatures(ped)
local size = #constants.FACE_FEATURES
local faceFeatures = table.create(0, size)
for i = 1, size do
local feature = constants.FACE_FEATURES[i]
faceFeatures[feature] = round(GetPedFaceFeature(ped, i-1), 1)
end
return faceFeatures
end
---@param ped number entity id
---@return table<number, table<string, number>>
local function getPedHeadOverlays(ped)
local size = #constants.HEAD_OVERLAYS
local headOverlays = table.create(0, size)
for i = 1, size do
local overlay = constants.HEAD_OVERLAYS[i]
local _, value, _, firstColor, secondColor, opacity = GetPedHeadOverlayData(ped, i-1)
if value ~= 255 then
opacity = round(opacity, 1)
else
value = 0
opacity = 0
end
headOverlays[overlay] = {style = value, opacity = opacity, color = firstColor, secondColor = secondColor}
end
return headOverlays
end
---@param ped number entity id
---@return table<string, number>
local function getPedHair(ped)
return {
style = GetPedDrawableVariation(ped, 2),
color = GetPedHairColor(ped),
highlight = GetPedHairHighlightColor(ped),
texture = GetPedTextureVariation(ped, 2)
}
end
local function getPedDecorationType()
local pedModel = GetEntityModel(cache.ped)
local decorationType
if pedModel == `mp_m_freemode_01` then
decorationType = "male"
elseif pedModel == `mp_f_freemode_01` then
decorationType = "female"
else
decorationType = IsPedMale(cache.ped) and "male" or "female"
end
return decorationType
end
local function getPedAppearance(ped)
local eyeColor = GetPedEyeColor(ped)
return {
model = getPedModel(ped) or "mp_m_freemode_01",
headBlend = getPedHeadBlend(ped),
faceFeatures = getPedFaceFeatures(ped),
headOverlays = getPedHeadOverlays(ped),
components = getPedComponents(ped),
props = getPedProps(ped),
hair = getPedHair(ped),
tattoos = client.getPedTattoos(),
eyeColor = eyeColor < #constants.EYE_COLORS and eyeColor or 0
}
end
local function setPlayerModel(model)
if type(model) == "string" then model = joaat(model) end
if IsModelInCdimage(model) then
RequestModel(model)
while not HasModelLoaded(model) do Wait(0) end
SetPlayerModel(cache.playerId, model)
Wait(150)
SetModelAsNoLongerNeeded(model)
if isPedFreemodeModel(cache.ped) then
SetPedDefaultComponentVariation(cache.ped)
-- Check if the model is male or female, then change the face mix based on this.
if model == `mp_m_freemode_01` then
SetPedHeadBlendData(cache.ped, 0, 0, 0, 0, 0, 0, 0, 0, 0, false)
elseif model == `mp_f_freemode_01` then
SetPedHeadBlendData(cache.ped, 45, 21, 0, 20, 15, 0, 0.3, 0.1, 0, false)
end
end
PED_TATTOOS = {}
return cache.ped
end
return cache.playerId
end
local function setPedHeadBlend(ped, headBlend)
if headBlend and isPedFreemodeModel(ped) then
SetPedHeadBlendData(ped, headBlend.shapeFirst, headBlend.shapeSecond, headBlend.shapeThird, headBlend.skinFirst, headBlend.skinSecond, headBlend.skinThird, tofloat(headBlend.shapeMix or 0), tofloat(headBlend.skinMix or 0), tofloat(headBlend.thirdMix or 0), false)
end
end
local function setPedFaceFeatures(ped, faceFeatures)
if faceFeatures then
for k, v in pairs(constants.FACE_FEATURES) do
SetPedFaceFeature(ped, k-1, tofloat(faceFeatures[v]))
end
end
end
local function setPedHeadOverlays(ped, headOverlays)
if headOverlays then
for k, v in pairs(constants.HEAD_OVERLAYS) do
local headOverlay = headOverlays[v]
SetPedHeadOverlay(ped, k-1, headOverlay.style, tofloat(headOverlay.opacity))
if headOverlay.color then
local colorType = 1
if v == "blush" or v == "lipstick" or v == "makeUp" then
colorType = 2
end
SetPedHeadOverlayColor(ped, k-1, colorType, headOverlay.color, headOverlay.secondColor)
end
end
end
end
local function applyAutomaticFade(ped, style)
local gender = getPedDecorationType()
local hairDecoration = constants.HAIR_DECORATIONS[gender][style]
if(hairDecoration) then
AddPedDecorationFromHashes(ped, hairDecoration[1], hairDecoration[2])
end
end
local function setTattoos(ped, tattoos, style)
local isMale = client.getPedDecorationType() == "male"
ClearPedDecorations(ped)
if Config.AutomaticFade then
tattoos["ZONE_HAIR"] = {}
PED_TATTOOS["ZONE_HAIR"] = {}
applyAutomaticFade(ped, style or GetPedDrawableVariation(ped, 2))
end
for k in pairs(tattoos) do
for i = 1, #tattoos[k] do
local tattoo = tattoos[k][i]
local tattooGender = isMale and tattoo.hashMale or tattoo.hashFemale
for _ = 1, (tattoo.opacity or 0.1) * 10 do
AddPedDecorationFromHashes(ped, joaat(tattoo.collection), joaat(tattooGender))
end
end
end
if Config.RCoreTattoosCompatibility then
TriggerEvent("rcore_tattoos:applyOwnedTattoos")
end
end
local function setPedHair(ped, hair, tattoos)
if hair then
SetPedComponentVariation(ped, 2, hair.style, hair.texture, 0)
SetPedHairColor(ped, hair.color, hair.highlight)
if isPedFreemodeModel(ped) then
setTattoos(ped, tattoos or PED_TATTOOS, hair.style)
end
end
end
local function setPedEyeColor(ped, eyeColor)
if eyeColor then
SetPedEyeColor(ped, eyeColor)
end
end
local function setPedComponent(ped, component)
if component then
if isPedFreemodeModel(ped) and (component.component_id == 0 or component.component_id == 2) then
return
end
SetPedComponentVariation(ped, component.component_id, component.drawable, component.texture, 0)
end
end
local function setPedComponents(ped, components)
if components then
for _, v in pairs(components) do
setPedComponent(ped, v)
end
end
end
local function setPedProp(ped, prop)
if prop then
if prop.drawable == -1 then
ClearPedProp(ped, prop.prop_id)
else
SetPedPropIndex(ped, prop.prop_id, prop.drawable, prop.texture, false)
end
end
end
local function setPedProps(ped, props)
if props then
for _, v in pairs(props) do
setPedProp(ped, v)
end
end
end
local function setPedTattoos(ped, tattoos)
PED_TATTOOS = tattoos
setTattoos(ped, tattoos)
end
local function getPedTattoos()
return PED_TATTOOS
end
local function addPedTattoo(ped, tattoos)
setTattoos(ped, tattoos)
end
local function removePedTattoo(ped, tattoos)
setTattoos(ped, tattoos)
end
local function setPreviewTattoo(ped, tattoos, tattoo)
local isMale = client.getPedDecorationType() == "male"
local tattooGender = isMale and tattoo.hashMale or tattoo.hashFemale
ClearPedDecorations(ped)
for _ = 1, (tattoo.opacity or 0.1) * 10 do
AddPedDecorationFromHashes(ped, joaat(tattoo.collection), tattooGender)
end
for k in pairs(tattoos) do
for i = 1, #tattoos[k] do
local aTattoo = tattoos[k][i]
if aTattoo.name ~= tattoo.name then
local aTattooGender = isMale and aTattoo.hashMale or aTattoo.hashFemale
for _ = 1, (aTattoo.opacity or 0.1) * 10 do
AddPedDecorationFromHashes(ped, joaat(aTattoo.collection), joaat(aTattooGender))
end
end
end
end
if Config.AutomaticFade then
applyAutomaticFade(ped, GetPedDrawableVariation(ped, 2))
end
end
local function setPedAppearance(ped, appearance)
if appearance then
setPedComponents(ped, appearance.components)
setPedProps(ped, appearance.props)
if appearance.headBlend and isPedFreemodeModel(ped) then setPedHeadBlend(ped, appearance.headBlend) end
if appearance.faceFeatures then setPedFaceFeatures(ped, appearance.faceFeatures) end
if appearance.headOverlays then setPedHeadOverlays(ped, appearance.headOverlays) end
if appearance.hair then setPedHair(ped, appearance.hair, appearance.tattoos) end
if appearance.eyeColor then setPedEyeColor(ped, appearance.eyeColor) end
if appearance.tattoos then setPedTattoos(ped, appearance.tattoos) end
end
end
local function setPlayerAppearance(appearance)
if appearance then
setPlayerModel(appearance.model)
setPedAppearance(cache.ped, appearance)
end
end
exports("getPedModel", getPedModel)
exports("getPedComponents", getPedComponents)
exports("getPedProps", getPedProps)
exports("getPedHeadBlend", getPedHeadBlend)
exports("getPedFaceFeatures", getPedFaceFeatures)
exports("getPedHeadOverlays", getPedHeadOverlays)
exports("getPedHair", getPedHair)
exports("getPedAppearance", getPedAppearance)
exports("setPlayerModel", setPlayerModel)
exports("setPedHeadBlend", setPedHeadBlend)
exports("setPedFaceFeatures", setPedFaceFeatures)
exports("setPedHeadOverlays", setPedHeadOverlays)
exports("setPedHair", setPedHair)
exports("setPedEyeColor", setPedEyeColor)
exports("setPedComponent", setPedComponent)
exports("setPedComponents", setPedComponents)
exports("setPedProp", setPedProp)
exports("setPedProps", setPedProps)
exports("setPlayerAppearance", setPlayerAppearance)
exports("setPedAppearance", setPedAppearance)
exports("setPedTattoos", setPedTattoos)
client = {
getPedAppearance = getPedAppearance,
setPlayerModel = setPlayerModel,
setPedHeadBlend = setPedHeadBlend,
setPedFaceFeatures = setPedFaceFeatures,
setPedHair = setPedHair,
setPedHeadOverlays = setPedHeadOverlays,
setPedEyeColor = setPedEyeColor,
setPedComponent = setPedComponent,
setPedProp = setPedProp,
setPlayerAppearance = setPlayerAppearance,
setPedAppearance = setPedAppearance,
getPedDecorationType = getPedDecorationType,
isPedFreemodeModel = isPedFreemodeModel,
setPreviewTattoo = setPreviewTattoo,
setPedTattoos = setPedTattoos,
getPedTattoos = getPedTattoos,
addPedTattoo = addPedTattoo,
removePedTattoo = removePedTattoo,
getPedModel = getPedModel,
setPedComponents = setPedComponents,
setPedProps = setPedProps,
getPedComponents = getPedComponents,
getPedProps = getPedProps
}