[STANDALONE] Mask Clipping Fix

Will you share this :smiley:

can you make this for hats too?

This guide is to specifically integrate the mask clipping script with dpclothing and illenium-appearance.

I moved the client.lua file from this mask clip script into my dpclothing Client folder, renamed as maskClip.lua and added to dpclothing fxmanifest.

Then changed line 54 from local function loop() to RegisterNetEvent('dpc:maskClip', function()

Then comment out/delete lines 107 through 112 to remove the for loop thread.

In Clothing.lua of dpclothing, replace ToggleClothing with this:

function ToggleClothing(which, extra)
	if Cooldown then return end
	local Toggle = Drawables[which] if extra then Toggle = Extras[which] end
	local Ped = PlayerPedId()
	local Cur = { -- Lets check what we are currently wearing.
		Drawable = GetPedDrawableVariation(Ped, Toggle.Drawable), 
		Id = Toggle.Drawable,
		Ped = Ped,
		Texture = GetPedTextureVariation(Ped, Toggle.Drawable),
	}
	local Gender = IsMpPed(Ped)
	if which ~= "Mask" then
		if not Gender then Notify(Lang("NotAllowedPed")) return false end -- We cancel the command here if the person is not using a multiplayer model.
	end
	local Table = Toggle.Table[Gender]
	if not Toggle.Table.Standalone then -- "Standalone" is for things that dont require a variant, like the shoes just need to be switched to a specific drawable. Looking back at this i should have planned ahead, but it all works so, meh!
		for k,v in pairs(Table) do
			if not Toggle.Remember then
				if k == Cur.Drawable then
					PlayToggleEmote(Toggle.Emote, function() SetPedComponentVariation(Ped, Toggle.Drawable, v, Cur.Texture, 0) end) return true
				end
			else
				if not LastEquipped[which] then
					if k == Cur.Drawable then
						PlayToggleEmote(Toggle.Emote, function() LastEquipped[which] = Cur SetPedComponentVariation(Ped, Toggle.Drawable, v, Cur.Texture, 0) end) return true
					end
				else
					local Last = LastEquipped[which]
					PlayToggleEmote(Toggle.Emote, function() SetPedComponentVariation(Ped, Toggle.Drawable, Last.Drawable, Last.Texture, 0) LastEquipped[which] = false end) return true
				end
			end
		end
		Notify(Lang("NoVariants")) return
	else
		if not LastEquipped[which] then
			if Cur.Drawable ~= Table then 
				PlayToggleEmote(Toggle.Emote, function()
					LastEquipped[which] = Cur
					SetPedComponentVariation(Ped, Toggle.Drawable, Table, 0, 0)
					if Toggle.Table.Extra then
						local Extras = Toggle.Table.Extra
						for k,v in pairs(Extras) do
							local ExtraCur = {Drawable = GetPedDrawableVariation(Ped, v.Drawable),  Texture = GetPedTextureVariation(Ped, v.Drawable), Id = v.Drawable}
							SetPedComponentVariation(Ped, v.Drawable, v.Id, v.Tex, 0)
							LastEquipped[v.Name] = ExtraCur
						end
					end
				end)
				if which == "Mask" then
					TriggerEvent("dpc:maskClip")
				end
				return true
			end
		else
			local Last = LastEquipped[which]
			PlayToggleEmote(Toggle.Emote, function()
				SetPedComponentVariation(Ped, Toggle.Drawable, Last.Drawable, Last.Texture, 0)
				LastEquipped[which] = false
				if Toggle.Table.Extra then
					local Extras = Toggle.Table.Extra
					for k,v in pairs(Extras) do
						if LastEquipped[v.Name] then
							local Last = LastEquipped[v.Name]
							SetPedComponentVariation(Ped, Last.Id, Last.Drawable, Last.Texture, 0)
							LastEquipped[v.Name] = false
						end
					end
				end
			end)
			if which == "Mask" then
				TriggerEvent("dpc:maskClip")
			end
			return true
		end
	end
	Notify(Lang("AlreadyWearing")) return false
end

Now for the illenium edits

Replace setPlayerAppearance(appearance) in game/util.lua with

local function setPlayerAppearance(appearance)
    if appearance then
        setPlayerModel(appearance.model)
        setPedAppearance(cache.ped, appearance)
    end
    TriggerEvent("dpc:maskClip")
end

TriggerEvent("dpc:maskClip") added to client/client.lua at following spots:
last line of InitAppearance() function

    TriggerEvent("dpc:maskClip")
end

last line before end, config) in InitializeCharacter(gender, onSubmit, onCancel) function

        TriggerEvent("dpc:maskClip")
    end, config)
end

last line before end, config) in OpenShop(config, isPedMenu, shopType) function

            TriggerEvent("dpc:maskClip")
        end, config)
    end, shopType)
end

in illenium-appearance:client:changeOutfit replace bottom few lines with this

           TriggerEvent("dpc:maskClip")
        end
        Framework.CachePed()
    end
end)

and finally replace bottom of illenium-appearance:client:reloadSkin with this

        TriggerEvent("dpc:maskClip")
    end)
end)
1 Like

Shared above

1 Like

illenium-appearance

Client.lua

local client = client
local reloadSkinTimer = GetGameTimer()

local function LoadPlayerUniform()
    lib.callback("illenium-appearance:server:getUniform", false, function(uniformData)
        if not uniformData then
            return
        end
        if Config.BossManagedOutfits then
            local result = lib.callback.await("illenium-appearance:server:getManagementOutfits", false, uniformData.type, Framework.GetGender())
            local uniform = nil
            for i = 1, #result, 1 do
                if result[i].name == uniformData.name then
                    uniform = {
                        type = uniformData.type,
                        name = result[i].name,
                        model = result[i].model,
                        components = result[i].components,
                        props = result[i].props,
                        disableSave = true,
                    }
                    break
                end
            end

            if not uniform then
                TriggerServerEvent("illenium-appearance:server:syncUniform", nil) -- Uniform doesn't exist anymore
                return
            end

            TriggerEvent("illenium-appearance:client:changeOutfit", uniform)
        else
            local outfits = Config.Outfits[uniformData.jobName][uniformData.gender]
            local uniform = nil
            for i = 1, #outfits, 1 do
                if outfits[i].name == uniformData.label then
                    uniform = outfits[i]
                    break
                end
            end

            if not uniform then
                TriggerServerEvent("illenium-appearance:server:syncUniform", nil) -- Uniform doesn't exist anymore
                return
            end

            uniform.jobName = uniformData.jobName
            uniform.gender = uniformData.gender

            TriggerEvent("illenium-appearance:client:loadJobOutfit", uniform)
        end
    end)
end

function InitAppearance()
    Framework.UpdatePlayerData()
    lib.callback("illenium-appearance:server:getAppearance", false, function(appearance)
        if not appearance then
            return
        end

        client.setPlayerAppearance(appearance)
        if Config.PersistUniforms then
            LoadPlayerUniform()
        end
    end)
    ResetBlips()
    if Config.BossManagedOutfits then
        Management.AddItems()
    end
    RestorePlayerStats()
end

AddEventHandler("onResourceStart", function(resource)
    if resource == GetCurrentResourceName() then
        InitAppearance()
        TriggerEvent("dpc:maskClip")
    end
end)

local function getNewCharacterConfig()
    local config = GetDefaultConfig()
    config.enableExit   = false

    config.ped          = Config.NewCharacterSections.Ped
    config.headBlend    = Config.NewCharacterSections.HeadBlend
    config.faceFeatures = Config.NewCharacterSections.FaceFeatures
    config.headOverlays = Config.NewCharacterSections.HeadOverlays
    config.components   = Config.NewCharacterSections.Components
    config.props        = Config.NewCharacterSections.Props
    config.tattoos      = not Config.vms_tattooshop and Config.NewCharacterSections.Tattoos

    return config
end

function SetInitialClothes(initial)
    client.setPlayerModel(initial.Model)
    -- Fix for tattoo's appearing when creating a new character
    local ped = cache.ped
    client.setPedTattoos(ped, {})
    client.setPedComponents(ped, initial.Components)
    client.setPedProps(ped, initial.Props)
    client.setPedHair(ped, initial.Hair, {})
    ClearPedDecorations(ped)
end

function InitializeCharacter(gender, onSubmit, onCancel)
    SetInitialClothes(Config.InitialPlayerClothes[gender])
    local config = getNewCharacterConfig()
    TriggerServerEvent("illenium-appearance:server:ChangeRoutingBucket")
    client.startPlayerCustomization(function(appearance)
        if (appearance) then
            TriggerServerEvent("illenium-appearance:server:saveAppearance", appearance)
            if onSubmit then
                onSubmit()
            end
        elseif onCancel then
            onCancel()
        end
        Framework.CachePed()
        TriggerServerEvent("illenium-appearance:server:ResetRoutingBucket")
        TriggerEvent("dpc:maskClip")
    end, config)
end

function OpenShop(config, isPedMenu, shopType)
    lib.callback("illenium-appearance:server:hasMoney", false, function(hasMoney, money)
        if not hasMoney and not isPedMenu then
            lib.notify({
                title = "Cannot Enter Shop",
                description = "Not enough cash. Need $" .. money,
                type = "error",
                position = Config.NotifyOptions.position
            })
            return
        end

        client.startPlayerCustomization(function(appearance)
            if appearance then
                if not isPedMenu then
                    TriggerServerEvent("illenium-appearance:server:chargeCustomer", shopType)
                end
                TriggerServerEvent("illenium-appearance:server:saveAppearance", appearance)
            else
                lib.notify({
                    title = _L("cancelled.title"),
                    description = _L("cancelled.description"),
                    type = "inform",
                    position = Config.NotifyOptions.position
                })
            end
            Framework.CachePed()
            TriggerEvent("dpc:maskClip")
        end, config)
    end, shopType)
end

local function OpenClothingShop(isPedMenu)
    local config = GetDefaultConfig()
    config.components = true
    config.props = true

    if isPedMenu then
        config.ped = true
        config.headBlend = true
        config.faceFeatures = true
        config.headOverlays = true
        config.tattoos = not Config.vms_tattooshop and true
    end
    OpenShop(config, isPedMenu, "clothing")
end

RegisterNetEvent("illenium-appearance:client:openClothingShop", OpenClothingShop)

RegisterNetEvent("illenium-appearance:client:importOutfitCode", function()
    local response = lib.inputDialog(_L("outfits.import.title"), {
        {
            type = "input",
            label = _L("outfits.import.name.label"),
            placeholder = _L("outfits.import.name.placeholder"),
            default = _L("outfits.import.name.default"),
            required = true
        },
        {
            type = "input",
            label = _L("outfits.import.code.label"),
            placeholder = "XXXXXXXXXXXX",
            required = true
        }
    })

    if not response then
        return
    end

    local outfitName = response[1]
    local outfitCode = response[2]
    if outfitCode ~= nil then
        Wait(500)
        lib.callback("illenium-appearance:server:importOutfitCode", false, function(success)
            if success then
                lib.notify({
                    title = _L("outfits.import.success.title"),
                    description = _L("outfits.import.success.description"),
                    type = "success",
                    position = Config.NotifyOptions.position
                })
            else
                lib.notify({
                    title = _L("outfits.import.failure.title"),
                    description = _L("outfits.import.failure.description"),
                    type = "error",
                    position = Config.NotifyOptions.position
                })
            end
        end, outfitName, outfitCode)
    end
end)

RegisterNetEvent("illenium-appearance:client:generateOutfitCode", function(id)
    lib.callback("illenium-appearance:server:generateOutfitCode", false, function(code)
        if not code then
            lib.notify({
                title = _L("outfits.generate.failure.title"),
                description = _L("outfits.generate.failure.description"),
                type = "error",
                position = Config.NotifyOptions.position
            })
            return
        end
        lib.setClipboard(code)
        lib.inputDialog(_L("outfits.generate.success.title"), {
            {
                type = "input",
                label = _L("outfits.generate.success.description"),
                default = code,
                disabled = true
            }
        })
    end, id)
end)

RegisterNetEvent("illenium-appearance:client:saveOutfit", function()
    local response = lib.inputDialog(_L("outfits.save.title"), {
        {
            type = "input",
            label = _L("outfits.save.name.label"),
            placeholder = _L("outfits.save.name.placeholder"),
            required = true
        }
    })

    if not response then
        return
    end

    local outfitName = response[1]
    if outfitName then
        Wait(500)
        lib.callback("illenium-appearance:server:getOutfits", false, function(outfits)
            local outfitExists = false
            for i = 1, #outfits, 1 do
                if outfits[i].name:lower() == outfitName:lower() then
                    outfitExists = true
                    break
                end
            end

            if outfitExists then
                lib.notify({
                    title = _L("outfits.save.failure.title"),
                    description = _L("outfits.save.failure.description"),
                    type = "error",
                    position = Config.NotifyOptions.position
                })
                return
            end

            local pedModel = client.getPedModel(cache.ped)
            local pedComponents = client.getPedComponents(cache.ped)
            local pedProps = client.getPedProps(cache.ped)

            TriggerServerEvent("illenium-appearance:server:saveOutfit", outfitName, pedModel, pedComponents, pedProps)
        end)
    end
end)

RegisterNetEvent('illenium-appearance:client:updateOutfit', function(outfitID)
    if not outfitID then return end

    lib.callback("illenium-appearance:server:getOutfits", false, function(outfits)
        local outfitExists = false
        for i = 1, #outfits, 1 do
            if outfits[i].id == outfitID then
                outfitExists = true
                break
            end
        end

        if not outfitExists then
            lib.notify({
                title = _L("outfits.update.failure.title"),
                description = _L("outfits.update.failure.description"),
                type = "error",
                position = Config.NotifyOptions.position
            })
            return
        end

        local pedModel = client.getPedModel(cache.ped)
        local pedComponents = client.getPedComponents(cache.ped)
        local pedProps = client.getPedProps(cache.ped)

        TriggerServerEvent("illenium-appearance:server:updateOutfit", outfitID, pedModel, pedComponents, pedProps)
    end)
end)

local function RegisterChangeOutfitMenu(id, parent, outfits, mType)
    local changeOutfitMenu = {
        id = id,
        title = _L("outfits.change.title"),
        menu = parent,
        options = {}
    }
    for i = 1, #outfits, 1 do
        changeOutfitMenu.options[#changeOutfitMenu.options + 1] = {
            title = outfits[i].name,
            description = outfits[i].model,
            event = "illenium-appearance:client:changeOutfit",
            args = {
                type = mType,
                name = outfits[i].name,
                model = outfits[i].model,
                components = outfits[i].components,
                props = outfits[i].props,
                disableSave = mType and true or false
            }
        }
    end

    table.sort(changeOutfitMenu.options, function(a, b)
        return a.title < b.title
    end)

    lib.registerContext(changeOutfitMenu)
end

local function RegisterUpdateOutfitMenu(id, parent, outfits)
    local updateOutfitMenu = {
        id = id,
        title = _L("outfits.update.title"),
        menu = parent,
        options = {}
    }
    for i = 1, #outfits, 1 do
        updateOutfitMenu.options[#updateOutfitMenu.options + 1] = {
            title = outfits[i].name,
            description = outfits[i].model,
            event = "illenium-appearance:client:updateOutfit",
            args = outfits[i].id
        }
    end

    table.sort(updateOutfitMenu.options, function(a, b)
        return a.title < b.title
    end)

    lib.registerContext(updateOutfitMenu)
end

local function RegisterGenerateOutfitCodeMenu(id, parent, outfits)
    local generateOutfitCodeMenu = {
        id = id,
        title = _L("outfits.generate.title"),
        menu = parent,
        options = {}
    }
    for i = 1, #outfits, 1 do
        generateOutfitCodeMenu.options[#generateOutfitCodeMenu.options + 1] = {
            title = outfits[i].name,
            description = outfits[i].model,
            event = "illenium-appearance:client:generateOutfitCode",
            args = outfits[i].id
        }
    end

    lib.registerContext(generateOutfitCodeMenu)
end

local function RegisterDeleteOutfitMenu(id, parent, outfits, deleteEvent)
    local deleteOutfitMenu = {
        id = id,
        title = _L("outfits.delete.title"),
        menu = parent,
        options = {}
    }

    table.sort(outfits, function(a, b)
        return a.name < b.name
    end)

    for i = 1, #outfits, 1 do
        deleteOutfitMenu.options[#deleteOutfitMenu.options + 1] = {
            title = string.format(_L("outfits.delete.item.title"), outfits[i].name),
            description = string.format(_L("outfits.delete.item.description"), outfits[i].model, (outfits[i].gender and (" - Gender: " .. outfits[i].gender) or "")),
            event = deleteEvent,
            args = outfits[i].id
        }
    end

    lib.registerContext(deleteOutfitMenu)
end

RegisterNetEvent("illenium-appearance:client:OutfitManagementMenu", function(args)
    local bossMenuEvent = "qb-bossmenu:client:OpenMenu"
    if args.type == "Gang" then
        bossMenuEvent = "qb-gangmenu:client:OpenMenu"
    end

    local outfits = lib.callback.await("illenium-appearance:server:getManagementOutfits", false, args.type, Framework.GetGender())
    local managementMenuID = "illenium_appearance_outfit_management_menu"
    local changeManagementOutfitMenuID = "illenium_appearance_change_management_outfit_menu"
    local deleteManagementOutfitMenuID = "illenium_appearance_delete_management_outfit_menu"

    RegisterChangeOutfitMenu(changeManagementOutfitMenuID, managementMenuID, outfits, args.type)
    RegisterDeleteOutfitMenu(deleteManagementOutfitMenuID, managementMenuID, outfits, "illenium-appearance:client:DeleteManagementOutfit")
    local managementMenu = {
        id = managementMenuID,
        title = string.format(_L("outfits.manage.title"), args.type),
        options = {
            {
                title = _L("outfits.change.title"),
                description = string.format(_L("outfits.change.description"), args.type),
                menu = changeManagementOutfitMenuID,
            },
            {
                title = _L("outfits.save.menuTitle"),
                description = string.format(_L("outfits.save.menuDescription"), args.type),
                event = "illenium-appearance:client:SaveManagementOutfit",
                args = args.type
            },
            {
                title = _L("outfits.delete.title"),
                description = string.format(_L("outfits.delete.description"), args.type),
                menu = deleteManagementOutfitMenuID,
            },
            {
                title = _L("menu.returnTitle"),
                icon = "fa-solid fa-angle-left",
                event = bossMenuEvent
            }
        }
    }

    lib.registerContext(managementMenu)
    lib.showContext(managementMenuID)
end)

RegisterNetEvent("illenium-appearance:client:SaveManagementOutfit", function(mType)
    local outfitData = {
        Type = mType,
        Model = client.getPedModel(cache.ped),
        Components = client.getPedComponents(cache.ped),
        Props = client.getPedProps(cache.ped)
    }

    local rankValues

    if mType == "Job" then
        outfitData.JobName = client.job.name
        rankValues = Framework.GetRankInputValues("job")

    else
        outfitData.JobName = client.gang.name
        rankValues = Framework.GetRankInputValues("gang")
    end

    local dialogResponse = lib.inputDialog(_L("outfits.save.managementTitle"), {
            {
                label = _L("outfits.save.name.label"),
                type = "input",
                required = true
            },
            {
                label = _L("outfits.save.gender.label"),
                type = "select",
                options = {
                    {
                        label = _L("outfits.save.gender.male"), value = "male"
                    },
                    {
                        label = _L("outfits.save.gender.female"), value = "female"
                    }
                },
                default = "male",
            },
            {
                label = _L("outfits.save.rank.label"),
                type = "select",
                options = rankValues,
                default = "0"
            }
        })

    if not dialogResponse then
        return
    end


    outfitData.Name = dialogResponse[1]
    outfitData.Gender = dialogResponse[2]
    outfitData.MinRank = tonumber(dialogResponse[3])

    TriggerServerEvent("illenium-appearance:server:saveManagementOutfit", outfitData)

end)

local function RegisterWorkOutfitsListMenu(id, parent, menuData)
    local menu = {
        id = id,
        menu = parent,
        title = _L("jobOutfits.title"),
        options = {}
    }
    local event = "illenium-appearance:client:loadJobOutfit"
    if Config.BossManagedOutfits then
        event = "illenium-appearance:client:changeOutfit"
    end
    if menuData then
        for _, v in pairs(menuData) do
            menu.options[#menu.options + 1] = {
                title = v.name,
                event = event,
                args = v
            }
        end
    end
    lib.registerContext(menu)
end

function OpenMenu(isPedMenu, menuType, menuData)
    local mainMenuID = "illenium_appearance_main_menu"
    local mainMenu = {
        id = mainMenuID
    }
    local menuItems = {}

    local outfits = lib.callback.await("illenium-appearance:server:getOutfits", false)
    local changeOutfitMenuID = "illenium_appearance_change_outfit_menu"
    local updateOutfitMenuID = "illenium_appearance_update_outfit_menu"
    local deleteOutfitMenuID = "illenium_appearance_delete_outfit_menu"
    local generateOutfitCodeMenuID = "illenium_appearance_generate_outfit_code_menu"

    RegisterChangeOutfitMenu(changeOutfitMenuID, mainMenuID, outfits)
    RegisterUpdateOutfitMenu(updateOutfitMenuID, mainMenuID, outfits)
    RegisterDeleteOutfitMenu(deleteOutfitMenuID, mainMenuID, outfits, "illenium-appearance:client:deleteOutfit")
    RegisterGenerateOutfitCodeMenu(generateOutfitCodeMenuID, mainMenuID, outfits)
    local outfitMenuItems = {
        {
            title = _L("outfits.change.title"),
            description = _L("outfits.change.pDescription"),
            menu = changeOutfitMenuID
        },
        {
            title = _L("outfits.update.title"),
            description = _L("outfits.update.description"),
            menu = updateOutfitMenuID
        },
        {
            title = _L("outfits.save.menuTitle"),
            description = _L("outfits.save.description"),
            event = "illenium-appearance:client:saveOutfit"
        },
        {
            title = _L("outfits.generate.title"),
            description = _L("outfits.generate.description"),
            menu = generateOutfitCodeMenuID
        },
        {
            title = _L("outfits.delete.title"),
            description = _L("outfits.delete.mDescription"),
            menu = deleteOutfitMenuID
        },
        {
            title = _L("outfits.import.menuTitle"),
            description = _L("outfits.import.description"),
            event = "illenium-appearance:client:importOutfitCode"
        }
    }
    if menuType == "default" then
        local header = string.format(_L("clothing.title"), Config.ClothingCost)
        if isPedMenu then
            header = _L("clothing.titleNoPrice")
        end
        mainMenu.title = _L("clothing.options.title")
        menuItems[#menuItems + 1] = {
            title = header,
            description = _L("clothing.options.description"),
            event = "illenium-appearance:client:openClothingShop",
            args = isPedMenu
        }
        for i = 0, #outfitMenuItems, 1 do
            menuItems[#menuItems + 1] = outfitMenuItems[i]
        end
    elseif menuType == "outfit" then
        mainMenu.title = _L("clothing.outfits.title")
        for i = 0, #outfitMenuItems, 1 do
            menuItems[#menuItems + 1] = outfitMenuItems[i]
        end
    elseif menuType == "job-outfit" then
        mainMenu.title = _L("clothing.outfits.title")
        menuItems[#menuItems + 1] = {
            title = _L("clothing.outfits.civilian.title"),
            description = _L("clothing.outfits.civilian.description"),
            event = "illenium-appearance:client:reloadSkin",
            args = true
        }

        local workOutfitsMenuID = "illenium_appearance_work_outfits_menu"
        RegisterWorkOutfitsListMenu(workOutfitsMenuID, mainMenuID, menuData)

        menuItems[#menuItems + 1] = {
            title = _L("jobOutfits.title"),
            description = _L("jobOutfits.description"),
            menu = workOutfitsMenuID
        }
    end
    mainMenu.options = menuItems

    lib.registerContext(mainMenu)
    lib.showContext(mainMenuID)
end

RegisterNetEvent("illenium-appearance:client:openClothingShopMenu", function(isPedMenu)
    if type(isPedMenu) == "table" then
        isPedMenu = false
    end
    OpenMenu(isPedMenu, "default")
end)

RegisterNetEvent("illenium-appearance:client:OpenBarberShop", OpenBarberShop)

RegisterNetEvent("illenium-appearance:client:OpenTattooShop", OpenTattooShop)

RegisterNetEvent("illenium-appearance:client:OpenSurgeonShop", OpenSurgeonShop)

RegisterNetEvent("illenium-appearance:client:changeOutfit", function(data)
    local pedModel = client.getPedModel(cache.ped)
    local appearanceDB
    if pedModel ~= data.model then
        local p = promise.new()
        lib.callback("illenium-appearance:server:getAppearance", false, function(appearance)
            BackupPlayerStats()
            if appearance then
                client.setPlayerAppearance(appearance)
                RestorePlayerStats()
            else
                lib.notify({
                    title = _L("outfits.change.failure.title"),
                    description = _L("outfits.change.failure.description"),
                    type = "error",
                    position = Config.NotifyOptions.position
                })
            end
            p:resolve(appearance)
        end, data.model)
        appearanceDB = Citizen.Await(p)
    else
        appearanceDB = client.getPedAppearance(cache.ped)
    end
    if appearanceDB then
        client.setPedComponents(cache.ped, data.components)
        client.setPedProps(cache.ped, data.props)
        client.setPedHair(cache.ped, appearanceDB.hair, appearanceDB.tattoos)

        if data.disableSave then
            TriggerServerEvent("illenium-appearance:server:syncUniform", {
                type = data.type,
                name = data.name
            }) -- Is a uniform
        else
            local appearance = client.getPedAppearance(cache.ped)
            TriggerServerEvent("illenium-appearance:server:saveAppearance", appearance)
        end
		if Config.vms_tattooshop then
            exports['vms_tattooshop']:reloadPlayerTattoos()
            TriggerEvent("dpc:maskClip")
        end
        Framework.CachePed()
    end
end)

RegisterNetEvent("illenium-appearance:client:DeleteManagementOutfit", function(id)
    TriggerServerEvent("illenium-appearance:server:deleteManagementOutfit", id)
    lib.notify({
        title = _L("outfits.delete.management.success.title"),
        description = _L("outfits.delete.management.success.description"),
        type = "success",
        position = Config.NotifyOptions.position
    })
end)

RegisterNetEvent("illenium-appearance:client:deleteOutfit", function(id)
    TriggerServerEvent("illenium-appearance:server:deleteOutfit", id)
    lib.notify({
        title = _L("outfits.delete.success.title"),
        description = _L("outfits.delete.success.failure"),
        type = "success",
        position = Config.NotifyOptions.position
    })
end)

RegisterNetEvent("illenium-appearance:client:openJobOutfitsMenu", function(outfitsToShow)
    OpenMenu(nil, "job-outfit", outfitsToShow)
end)

local function InCooldown()
    return (GetGameTimer() - reloadSkinTimer) < Config.ReloadSkinCooldown
end

RegisterNetEvent("illenium-appearance:client:reloadSkin", function(bypassChecks)
    if not bypassChecks and InCooldown() or Framework.CheckPlayerMeta() or cache.vehicle or IsPedFalling(cache.ped) then
        lib.notify({
            title = _L("commands.reloadskin.failure.title"),
            description = _L("commands.reloadskin.failure.description"),
            type = "error",
            position = Config.NotifyOptions.position
        })
        return
    end

    reloadSkinTimer = GetGameTimer()
    BackupPlayerStats()

    lib.callback("illenium-appearance:server:getAppearance", false, function(appearance)
        if not appearance then
            return
        end
        client.setPlayerAppearance(appearance)
        if Config.PersistUniforms then
            TriggerServerEvent("illenium-appearance:server:syncUniform", nil)
        end
        RestorePlayerStats()
        TriggerEvent("dpc:maskClip")
    end)
end)

RegisterNetEvent("illenium-appearance:client:ClearStuckProps", function()
    if InCooldown() or Framework.CheckPlayerMeta() then
        lib.notify({
            title = _L("commands.clearstuckprops.failure.title"),
            description = _L("commands.clearstuckprops.failure.description"),
            type = "error",
            position = Config.NotifyOptions.position
        })
        return
    end

    reloadSkinTimer = GetGameTimer()

    for _, v in pairs(GetGamePool("CObject")) do
      if IsEntityAttachedToEntity(cache.ped, v) then
        SetEntityAsMissionEntity(v, true, true)
        DeleteObject(v)
        DeleteEntity(v)
      end
    end
end)

I installed the version as you said, but that doesn’t work with illenium-appearance if you make the client mask.lua and simply write it into fxmanifest.lua. Everything works perfectly on the client side

here is a picture with your version

and here my version

1 Like

It is working perfectly fine on our server with illenium. The additions to illenium just force it to load/detect the mask on player load/reload, otherwise the mask clipping often worked backwards of what it was supposed to do. Did extensive testing yesterday with it all.

1 Like

Just tested it with us but it doesn’t really matter, as long as it works that way

Added our edit to game/util.lua in illenium I missed during my write-up of the above post.

1 Like

Very nice Script! :slight_smile:

v1.1.0 Update

Update improves the following:

  • Code structure
  • Various clipping errors
  • Performance

Thoughts on further expansion into fixes for torsos, hats etc.

I’ve spent the last couple of days researching ways to fix the clipping on other clothing items – torsos in particular – and it seems to be a much greater task than fixing masks.
The fundamental problem is that GTA: Online is very restrictive compared to most FiveM servers, making picking a “most fitting” pair of arms very difficult, as FiveM players usually like to mix and match items that were never meant to be worn together. Unlike masks, that programmatically warp your face and shrink your head based on various flags set on the item itself, most torsos seem to actually be hand-scripted into the game. I’ve managed to somewhat recreate GTA: Online’s behavior up until a certain DLC, but it ultimately led to a lot of infighting when wearing conflicting shirts/jackets. I’m pretty sure GTA: Online picks hands before actually applying shirts. I can’t really do that without making event listeners for every clothing store script out there. I’ve not given up though, and am positive I can get something working. I’ll share my work so far below.

Torso/Arms Progress
---@class HeadBlendData
  ---@field shapeFirst integer
  ---@field shapeSecond integer
  ---@field shapeThird integer
  ---@field skinFirst integer
  ---@field skinSecond integer
  ---@field skinThird integer
  ---@field shapeMix number
  ---@field skinMix number
  ---@field thirdMix number

local freemodeModels<const> = {
  [`mp_m_freemode_01`] = 'mp_m_freemode_01',
  [`mp_f_freemode_01`] = 'mp_f_freemode_01'
}

---Is the model either of the freemode models?
  ---@param modelHash integer
local function isFreemodeModel(modelHash)
  return freemodeModels[modelHash] ~= nil
end

---Gets draw tag as integer
  ---@param hashName integer
local function getDLCDrawTag(hashName)
  local tag = -1
  if hashName == 0 then return tag end

  if DoesShopPedApparelHaveRestrictionTag(hashName, `DRAW_0`, 0) then tag = 0
  elseif DoesShopPedApparelHaveRestrictionTag(hashName, `DRAW_1`, 0) then tag = 1
  elseif DoesShopPedApparelHaveRestrictionTag(hashName, `DRAW_2`, 0) then tag = 2
  elseif DoesShopPedApparelHaveRestrictionTag(hashName, `DRAW_3`, 0) then tag = 3
  elseif DoesShopPedApparelHaveRestrictionTag(hashName, `DRAW_4`, 0) then tag = 4
  elseif DoesShopPedApparelHaveRestrictionTag(hashName, `DRAW_5`, 0) then tag = 5
  elseif DoesShopPedApparelHaveRestrictionTag(hashName, `DRAW_6`, 0) then tag = 6
  elseif DoesShopPedApparelHaveRestrictionTag(hashName, `DRAW_7`, 0) then tag = 7
  elseif DoesShopPedApparelHaveRestrictionTag(hashName, `DRAW_8`, 0) then tag = 8
  elseif DoesShopPedApparelHaveRestrictionTag(hashName, `DRAW_9`, 0) then tag = 9
  elseif DoesShopPedApparelHaveRestrictionTag(hashName, `DRAW_10`, 0) then tag = 10
  elseif DoesShopPedApparelHaveRestrictionTag(hashName, `DRAW_11`, 0) then tag = 11
  elseif DoesShopPedApparelHaveRestrictionTag(hashName, `DRAW_12`, 0) then tag = 12
  elseif DoesShopPedApparelHaveRestrictionTag(hashName, `DRAW_13`, 0) then tag = 13
  elseif DoesShopPedApparelHaveRestrictionTag(hashName, `DRAW_14`, 0) then tag = 14
  elseif DoesShopPedApparelHaveRestrictionTag(hashName, `DRAW_15`, 0) then tag = 15
  end

  return tag
end

---Get jacket from shirt
  ---@param pedModelHash integer
  ---@param shirt integer
  ---@return integer
local function getJacketFromShirt(pedModelHash, shirt)
  local jacket = -99
  if freemodeModels[pedModelHash] == 'mp_m_freemode_01' then
    if shirt <= 15 then jacket = 0
    elseif shirt <= 1 * 16 + 15 then jacket = 1
    elseif shirt <= 2 * 16 + 15 then jacket = 0
    elseif shirt <= 3 * 16 + 15 then jacket = -99
    elseif shirt <= 4 * 16 + 15 then jacket = -99
    elseif shirt <= 5 * 16 + 15 then jacket = 5
    elseif shirt <= 6 * 16 + 15 then jacket = -99
    elseif shirt <= 7 * 16 + 15 then jacket = -99
    elseif shirt <= 8 * 16 + 15 then jacket = 8
    elseif shirt <= 9 * 16 + 15 then jacket = 9
    elseif shirt <= 10 * 16 + 15 then jacket = -99
    elseif shirt <= 11 * 16 + 15 then jacket = -99
    elseif shirt <= 12 * 16 + 15 then jacket = 12
    elseif shirt <= 13 * 16 + 15 then jacket = 13
    elseif shirt <= 14 * 16 + 15 then jacket = 1
    elseif shirt <= 15 * 16 then jacket = 15
    end
  else
    if shirt <= 15 then jacket = 0
    elseif shirt <= 1 * 16 + 15 then jacket = 0
    elseif shirt <= 2 * 16 then jacket = -99
    elseif shirt <= 3 * 16 then jacket = -99
    elseif shirt <= 4 * 16 + 15 then jacket = 4
    elseif shirt <= 5 * 16 + 15 then jacket = 5
    elseif shirt <= 6 * 16 then jacket = -99
    elseif shirt <= 7 * 16 then jacket = -99
    elseif shirt <= 8 * 16 then jacket = -99
    elseif shirt <= 9 * 16 then jacket = -99
    elseif shirt <= 10 * 16 then jacket = -99
    elseif shirt <= 11 * 16 + 15 then jacket = 11
    elseif shirt <= 12 * 16 + 15 then jacket = 12
    elseif shirt <= 13 * 16 + 15 then jacket = 13
    elseif shirt <= 14 * 16 then jacket = -99
    elseif shirt <= 15 * 16 + 15 then jacket = 15
    end
  end
  return jacket
end

---Get torso for shirt/jacket combo
  ---@param ped integer
  ---@param pedModelHash integer
  ---@param currentShirt integer
  ---@param currentJacket integer
  ---@param currentPants integer
  ---@return integer
local function getTorsoForShirtJacketCombo(ped, pedModelHash, currentShirt, currentJacket, currentPants)
  -- To me this function is pretty disgusting, but it's kinda how R* did it
  local forcedTorso = -99

  local jacketHash<const> = GetHashNameForComponent(ped, 11, currentJacket, 0)
  local jacketTag<const> = getDLCDrawTag(jacketHash)

  local shirtHash<const> = GetHashNameForComponent(ped, 8, currentShirt, 0)
  local shirtTag<const> = getDLCDrawTag(shirtHash)

  if freemodeModels[pedModelHash] == 'mp_m_freemode_01' then

    if DoesShopPedApparelHaveRestrictionTag(jacketHash, `SILK_ROBE`, 0) then forcedTorso = 14
    elseif DoesShopPedApparelHaveRestrictionTag(jacketHash, `SILK_PYJAMAS`, 0) then forcedTorso = 6

    elseif shirtHash ~= 0 and DoesShopPedApparelHaveRestrictionTag(shirtHash, `STUNT_DRAW_1`, 0) then forcedTorso = 1
    elseif shirtHash ~= 0 and DoesShopPedApparelHaveRestrictionTag(shirtHash, `STUNT_DRAW_2`, 0) then forcedTorso = 4

    elseif
      DoesShopPedApparelHaveRestrictionTag(jacketHash, `BIKER_VEST`, 0)
      and not DoesShopPedApparelHaveRestrictionTag(jacketHash, `JACKET_ONLY`, 0)
    then
      if currentShirt == 15 * 16 then
        if
          DoesShopPedApparelHaveRestrictionTag(jacketHash, `BIKER_DRAW_0`, 0)
          or DoesShopPedApparelHaveRestrictionTag(jacketHash, `BIKER_DRAW_3`, 0)
          or DoesShopPedApparelHaveRestrictionTag(jacketHash, `BIKER_DRAW_13`, 0)
        then forcedTorso = 112
        elseif DoesShopPedApparelHaveRestrictionTag(jacketHash, `BIKER_DRAW_1`, 0) then forcedTorso = 113
        elseif DoesShopPedApparelHaveRestrictionTag(jacketHash, `BIKER_DRAW_2`, 0) then forcedTorso = 114
        elseif DoesShopPedApparelHaveRestrictionTag(jacketHash, `BIKER_DRAW_5`, 0) then forcedTorso = 5
        end
      else
        forcedTorso = getTorsoForShirtJacketCombo(ped, pedModelHash, -99, getJacketFromShirt(pedModelHash, currentShirt), currentPants)
        if forcedTorso == -99 then forcedTorso = 0 end
      end

    elseif DoesShopPedApparelHaveRestrictionTag(shirtHash, `OVERCOAT_ACCS`, 0) then forcedTorso = 12

    elseif
      (jacketHash ~= 0 and DoesShopPedApparelHaveRestrictionTag(jacketHash, `APART_DRAW_15`, 0))
      or (jacketHash ~= 0 and DoesShopPedApparelHaveRestrictionTag(jacketHash, `APART_DRAW_24`, 0))
      or DoesShopPedApparelHaveRestrictionTag(jacketHash, `BIKER_DRAW_6`, 0)
    then
      if currentShirt == 15 * 16 then
        forcedTorso = 14
      elseif
        (currentShirt >= 5 * 16 and currentShirt <= 5 * 16 + 15)
        or shirtTag == 5
      then
        forcedTorso = 6
      elseif
        (currentShirt >= 16 and currentShirt <= 16 + 15)
        or shirtTag == 1
      then
        forcedTorso = 1
      else
        forcedTorso = 4
      end

    elseif jacketHash ~= 0 and DoesShopPedApparelHaveRestrictionTag(jacketHash, `LOW2_OPEN_CHECK`, 0) then
      if currentShirt == 15 * 16 then
        forcedTorso = 14
      elseif 
        (currentShirt >= 5 * 16 and currentShirt <= 5 * 16 + 15)
        or shirtTag == 5
      then
        forcedTorso = 6
      else
        forcedTorso = 1
      end

    elseif jacketHash ~= 0 and DoesShopPedApparelHaveRestrictionTag(jacketHash, `HEIST_DRAW_7`, 0) then
      if
        (currentShirt >= 12 * 16 and currentShirt <= 12 * 16 + 15)
        or shirtTag == 12
      then
        forcedTorso = 0
      else
        forcedTorso = 11
      end

    elseif jacketHash ~= 0 and DoesShopPedApparelHaveRestrictionTag(jacketHash, `HEIST_DRAW_9`, 0) then
      if
        (currentShirt >= 5 * 16 and currentShirt <= 5 * 16 + 15)
        or shirtTag == 5
      then
        forcedTorso = 6
      elseif currentShirt == 15 * 16 then
        forcedTorso = 14
      elseif
        (currentShirt >= 16 and currentShirt <= 16 + 15)
        or shirtTag == 1
      then
        forcedTorso = 1
      end

    elseif jacketHash ~= 0 and DoesShopPedApparelHaveRestrictionTag(jacketHash, `TUX_JACKET`, 0) then
      forcedTorso = 12

    elseif jacketHash ~= 0 and DoesShopPedApparelHaveRestrictionTag(jacketHash, `SMUG_DRAW_6`, 0) then
      forcedTorso = 2

    elseif 
      (currentJacket >= 0 and currentJacket <= 16 + 15)
      or jacketTag == 0
      or jacketTag == 1
    then
      forcedTorso = 0

    elseif
      (currentJacket >= 3 * 16 and currentJacket <= 3 * 16 + 15)
      or (currentJacket >= 4 * 16 and currentJacket <= 4 * 16 + 15)
      or (currentJacket >= 6 * 16 and currentJacket <= 6 * 16 + 11)
      or (currentJacket >= 7 * 16 and currentJacket <= 7 * 16 + 15)
      or (currentJacket >= 10 * 16 and currentJacket <= 10 * 16 + 15)
      or jacketTag == 3
      or jacketTag == 4
      or jacketTag == 6
      or jacketTag == 7
      or jacketTag == 10
    then
      if
        (currentShirt >= 5 * 16 and currentShirt <= 5 * 16 + 15)
        or shirtTag == 5
      then
        forcedTorso = 6
      elseif
        currentShirt == 15 * 16
        or shirtTag == 15
      then
        forcedTorso = 14
      elseif
        (currentShirt >= 10 * 16 and currentShirt <= 10 * 16 + 15)
        or shirtTag == 10
      then
        forcedTorso = 4
      elseif
        (currentShirt >= 11 * 16 and currentShirt <= 11 * 16 + 15)
        or shirtTag == 11
      then
        forcedTorso = 12
      elseif
        (currentShirt >= 16 and currentShirt <= 16 + 15)
        or (currentShirt >= 14 * 16 and currentShirt <= 14 * 16 + 15)
        or shirtTag == 1
        or shirtTag == 14
      then
        forcedTorso = 1
      elseif
        (currentShirt >= 5 * 16 and currentShirt <= 5 * 16 + 15)
        or shirtTag == 5
      then
        forcedTorso = 6
      elseif
        (currentShirt >= 2 * 16 and currentShirt <= 2 * 16 + 15)
        or shirtTag == 2
      then
        forcedTorso = 4
      elseif shirtHash ~= 0 and DoesShopPedApparelHaveRestrictionTag(shirtHash, `SHIRT_BRACES`, 0) then
        if shirtHash ~= 0 and DoesShopPedApparelHaveRestrictionTag(shirtHash, `CLOSED_COLLAR`, 0) then
          forcedTorso = 4
        else
          forcedTorso = 1
        end
      elseif
        (currentShirt >= 9 * 16 and currentShirt <= 9 * 16 + 15)
        or shirtTag == 9
      then
        forcedTorso = 1
      elseif
        DoesShopPedApparelHaveRestrictionTag(shirtHash, `APART_DRAW_2`, 0)
        or DoesShopPedApparelHaveRestrictionTag(shirtHash, `APART_DRAW_3`, 0)
      then
        forcedTorso = 4
      end
      -- Check for other forced components here?
      -- DLC items?
    elseif
      (currentJacket >= 11 * 16 and currentJacket <= 11 * 16 + 15)
      or jacketTag == 11
    then
      if shirtHash ~= 0 and DoesShopPedApparelHaveRestrictionTag(shirtHash, `SWEAT_VEST`, 0) then
        forcedTorso = 6
      elseif
        (currentShirt >= 3 and currentShirt <= 3 + 15)
        or (currentShirt >= 7 * 16 and currentShirt <= 7 * 16 + 15)
        or shirtTag == 3
        or shirtTag == 7
      then
        forcedTorso = 11
      elseif
        (currentShirt >= 6 * 16 and currentShirt <= 6 * 16 + 15)
        or shirtTag == 6
      then
        forcedTorso = 11
      elseif shirtHash ~= 0 and DoesShopPedApparelHaveRestrictionTag(shirtHash, `LONG_SLEEVE`, 0) then
        forcedTorso = 12
      elseif currentShirt == 15 * 16 then
        forcedTorso = 15
      end
    elseif
      (currentJacket >= 9 * 16 and currentJacket <= 9 * 16 + 15)
      or jacketTag == 9
    then
      forcedTorso = 0
    elseif currentJacket == 15 * 16 then
      if currentShirt == 15 * 16 then
        forcedTorso = 15
      end
    end
  else
  end

  return forcedTorso
end

local MAX_DLC_JACKET =  15 * 16 + 1

---Get torso for jacket
  ---@param ped integer
  ---@param pedModelHash integer
  ---@param currentJacket integer
  ---@param currentShirt integer
  ---@return integer
local function getTorsoForJacket(ped, pedModelHash, currentJacket, currentShirt)
  local forcedTorso = -99

  if freemodeModels[pedModelHash] == 'mp_m_freemode_01' then
    if currentJacket <= 15 then forcedTorso = 0
    elseif currentJacket <= 16 + 15 then forcedTorso = 0
    elseif currentJacket <= 2 * 16 + 15 then forcedTorso = 2
    elseif currentJacket <= 3 * 16 + 15 then forcedTorso = 1
    elseif currentJacket <= 4 * 16 + 15 then forcedTorso = 1
    elseif currentJacket <= 5 * 16 + 15 then forcedTorso = 5
    elseif currentJacket <= 6 * 16 + 15 then forcedTorso = 12
    elseif currentJacket <= 7 * 16 + 15 then forcedTorso = 1
    elseif currentJacket <= 8 * 16 + 15 then forcedTorso = 8
    elseif currentJacket <= 9 * 16 + 15 then forcedTorso = 0
    elseif currentJacket <= 10 * 16 + 15 then forcedTorso = 1
    elseif currentJacket <= 11 * 16 + 15 then
      local shirtHash<const> = GetHashNameForComponent(ped, 8, currentShirt, 0)
      local shirtTag<const> = getDLCDrawTag(shirtHash)

      if 
        (currentShirt >= 6 * 16 and currentShirt <= 6 * 16 + 15)
        or (currentShirt >= 7 * 16 and currentShirt <= 7 * 16 + 15)
        or (currentShirt >= MAX_DLC_JACKET and shirtTag == 6)
        or (currentShirt >= MAX_DLC_JACKET and shirtTag == 7)
        or (currentShirt >= MAX_DLC_JACKET and DoesShopPedApparelHaveRestrictionTag(shirtHash, `VEST_SHIRT`, 0))
      then
        forcedTorso = -99
      else
        forcedTorso = 11
      end
    elseif currentJacket <= 12 * 16 + 15 then forcedTorso = 12
    elseif currentJacket <= 13 * 16 + 15 then forcedTorso = 11
    elseif currentJacket <= 14 * 16 + 15 then forcedTorso = 4
    elseif currentJacket == 15 * 16 then forcedTorso = 15
    elseif currentJacket >= MAX_DLC_JACKET then
      -- DLC item
    end

  else

  end

  return forcedTorso
end

---Handles arms fix
  ---@param ped integer
  ---@param pedModelHash integer
local function handleArms(ped, pedModelHash)
  local currentShirt<const> = GetPedDrawableVariation(ped, 8)
  local currentJacket<const> = GetPedDrawableVariation(ped, 11)

  local glovelessArms = getTorsoForShirtJacketCombo(ped, pedModelHash, currentShirt, currentJacket, GetPedDrawableVariation(ped, 4))
  if glovelessArms == -99 then
    glovelessArms = getTorsoForJacket(ped, pedModelHash, currentJacket, currentShirt)
    local jacketHash<const> = GetHashNameForComponent(ped, 11, currentJacket, 0)
    if 
      jacketHash == `DLC_MP_VAL_F_JBIB0_0`
      or jacketHash == `DLC_MP_VAL_F_JBIB0_1`
      or jacketHash == `DLC_MP_VAL_F_JBIB0_2`
      or jacketHash == `DLC_MP_VAL_F_JBIB0_3`
      or jacketHash == `DLC_MP_VAL_F_JBIB0_4`
      or jacketHash == `DLC_MP_VAL_F_JBIB0_5`
    then
      glovelessArms = 11
    elseif
      jacketHash == `DLC_MP_STUNT_M_JBIB_5_0`
      or jacketHash == `DLC_MP_STUNT_M_JBIB_5_1`
      or jacketHash == `DLC_MP_STUNT_M_JBIB_5_2`
      or jacketHash == `DLC_MP_STUNT_M_JBIB_5_3`
      or jacketHash == `DLC_MP_STUNT_M_JBIB_5_4`
      or jacketHash == `DLC_MP_STUNT_M_JBIB_5_5`
      or jacketHash == `DLC_MP_STUNT_M_JBIB_5_6`
      or jacketHash == `DLC_MP_STUNT_M_JBIB_5_7`
      or jacketHash == `DLC_MP_STUNT_M_JBIB_5_8`
      or jacketHash == `DLC_MP_STUNT_M_JBIB_5_9`
      or jacketHash == `DLC_MP_STUNT_M_JBIB_5_10`
      or jacketHash == `DLC_MP_STUNT_M_JBIB_5_11`
      or jacketHash == `DLC_MP_STUNT_M_JBIB_5_12`
      or jacketHash == `DLC_MP_STUNT_M_JBIB_5_13`
      or jacketHash == `DLC_MP_STUNT_M_JBIB_5_14`
      or jacketHash == `DLC_MP_STUNT_M_JBIB_5_15`
    then
      glovelessArms = 4
    elseif
      jacketHash == `DLC_MP_STUNT_F_JBIB_5_0`
      or jacketHash == `DLC_MP_STUNT_F_JBIB_5_1`
      or jacketHash == `DLC_MP_STUNT_F_JBIB_5_2`
      or jacketHash == `DLC_MP_STUNT_F_JBIB_5_3`
      or jacketHash == `DLC_MP_STUNT_F_JBIB_5_4`
      or jacketHash == `DLC_MP_STUNT_F_JBIB_5_5`
      or jacketHash == `DLC_MP_STUNT_F_JBIB_5_6`
      or jacketHash == `DLC_MP_STUNT_F_JBIB_5_7`
      or jacketHash == `DLC_MP_STUNT_F_JBIB_5_8`
      or jacketHash == `DLC_MP_STUNT_F_JBIB_5_9`
      or jacketHash == `DLC_MP_STUNT_F_JBIB_5_10`
      or jacketHash == `DLC_MP_STUNT_F_JBIB_5_11`
      or jacketHash == `DLC_MP_STUNT_F_JBIB_5_12`
      or jacketHash == `DLC_MP_STUNT_F_JBIB_5_13`
      or jacketHash == `DLC_MP_STUNT_F_JBIB_5_14`
      or jacketHash == `DLC_MP_STUNT_F_JBIB_5_15`
    then
      glovelessArms = 3
    end
  end

  if glovelessArms ~= -99 then
    -- Found glovelessArms
    -- ???
  else
    glovelessArms = -1
  end

  print('glovelessArms', glovelessArms)
  --SetPedComponentVariation(ped, 3, glovelessArms, 0, 0)
end

local function fixClothing()
  local ped<const> = PlayerPedId()
  if not DoesEntityExist(ped) then return end

  local pedModelHash<const> = GetEntityModel(ped)
  if not isFreemodeModel(pedModelHash) then return end

  handleArms(ped, pedModelHash)
end

CreateThread(function()
  while true do
    fixClothing()
    Wait(10)
  end
end)
6 Likes

You are a lion, I cant believe that you master this . Hope you will succeed

How do I make addon mask compatible? Awesome script btw

Great job thank you for the free release :heart:
Cops and Robbers V will use this fix :fire:

this is insane

Any more progress??

Hello, I would like to know if anyone has found the possibility of making this fix mask compatible with dpClothing and the new creator appearance

W

– Dan