op-multicharacter Setup
This guide shows how to connect kartik-clothing to op-multicharacter (by OTHERPLANET).
op-multicharacter loads one integration file per clothing resource and picks it with Config.Clothing. kartik-clothing gets its own pair of files, the same way op-multicharacter already supports its other clothing resources. None of its escrowed files need changing.
🛠️ Official File Edits
1. op-multicharacter/integrations/client/clothing/kartik-clothing.lua
Create this file. It dresses the selection preview peds and opens the kartik-clothing character creator for new characters:
if Config.Clothing ~= "kartik-clothing" then return end
function applySkinToPed(ped, skin)
if type(skin) ~= "table" then
debugPrint("^1[applySkinToPed]^0 Invalid skin data (expected table, got " .. type(skin) .. ").")
return
end
if type(skin.skin) ~= "table" then
debugPrint("^1[applySkinToPed]^0 Invalid skin.skin data (expected table, got " .. type(skin.skin) .. ").")
return
end
local ok, err = pcall(function()
exports['kartik-clothing']:setPedAppearance(ped, skin.skin)
end)
if not ok then
debugPrint("^1[applySkinToPed]^0 kartik-clothing setPedAppearance failed:", err)
end
end
function reapplySavedAppearance()
if isInsideNew then return end
local ok, data = pcall(function()
return lib.callback.await("op-multicharacter:getActiveSkin", false)
end)
if not ok or type(data) ~= "table" or type(data.skin) ~= "table" then return end
local ped = PlayerPedId()
if not DoesEntityExist(ped) then return end
applySkinToPed(ped, data)
end
local function revealWorldForClothingCreator()
if OPMC and type(OPMC.endCharMenuSession) == "function" then
OPMC.endCharMenuSession()
else
SendNUIMessage({ action = "setCharMenuSession", data = false })
end
SendNUIMessage({ action = "setBlackScreen", data = false })
SendNUIMessage({ action = "setloadervisible", data = false })
SendNUIMessage({ action = "setCreatorMenuVisible", data = false })
SendNUIMessage({ action = "setCharacterVisible", data = false })
SendNUIMessage({ action = "setcharVisible", data = false })
local playerPed = PlayerPedId()
if DoesEntityExist(playerPed) then
FreezeEntityPosition(playerPed, false)
SetEntityCollision(playerPed, true, true)
SetEntityVisible(playerPed, true, false)
SetEntityInvincible(playerPed, false)
ResetEntityAlpha(playerPed)
end
SetPlayerControl(PlayerId(), true, 0)
if IsScreenFadedOut() or IsScreenFadingOut() then
DoScreenFadeIn(400)
local deadline = GetGameTimer() + 3000
while not IsScreenFadedIn() and GetGameTimer() < deadline do
Wait(0)
end
end
end
function openCreationMenu(isMale)
if type(Config.SwitchHud) == "function" then
Config.SwitchHud(false)
end
revealWorldForClothingCreator()
exports['kartik-clothing']:startPlayerCustomization(function()
Fr.CharacterCreated()
end, { gender = isMale and 'male' or 'female' })
endDo not trigger
op-multicharacter:saveSkinfrom the creator callback. kartik-clothing has already saved the character by the time the callback runs, and it removes any locked items before saving. Saving again throughop-multicharacterskips that check and writes to theplayerskins/users.skintables, which kartik-clothing doesn't read.
2. op-multicharacter/integrations/server/clothing/kartik-clothing.lua
Create this file. It loads each character's skin for the selection screen:
if Config.Clothing ~= "kartik-clothing" then return end
function convertSkin(identifier)
local ok, skin = pcall(function()
return exports['kartik-clothing']:getPlayerAppearance(identifier)
end)
if ok and type(skin) == "table" then
return {skin = skin, model = skin.model or "mp_m_freemode_01"}
end
end
lib.callback.register("op-multicharacter:getActiveSkin", function(source)
local Player = Fr.getPlayerFromId(source)
if not Player then return nil end
local id = Player.identifier or (Player.PlayerData and Player.PlayerData.citizenid)
if type(id) ~= "string" or id == "" then return nil end
return convertSkin(id)
end)Use the export rather than querying
kc_player_skinsdirectly. The export swaps unlisted addon peds (saved ashash:<n>) for the default body, becauseop-multicharacterloads models withjoaat()and would otherwise hang on the selection screen.
3. op-multicharacter/config/MainConfig.lua
Add kartik-clothing to the supported list and select it:
-- SUPPORTED CLOTHING SCRIPTS
-- op-clothing (https://otherplanet.dev/product/clothing)
-- kartik-clothing
-- ...
Config.Clothing = "kartik-clothing"⚙️ Setup Instructions
-
Start kartik-clothing before
op-multicharacterin yourserver.cfg:ensure ox_lib ensure kartik-clothing ensure op-multicharacter -
Set
Config.Clothingtokartik-clothinginop-multicharacter/config/MainConfig.lua. Without this,op-multicharacterkeeps loading the old clothing integration and kartik-clothing is never used:Config.Clothing = "kartik-clothing" -
Leave
Config.Tattoos = "none". Tattoos are part of the kartik-clothing skin and show on the preview peds without a separate tattoo integration. -
The cutscene and spawn selector still run after the character creator is confirmed.
-
Remove your old clothing resource from your
server.cfg. If it wasillenium-appearance, run the migration so existing characters show up on the selection screen.
ZSX_Multicharacter Setup
This guide shows how to connect kartik-clothing to ZSX_Multicharacter (by ZSX Development).
Commands & Keys
kartik-clothing registers its commands through ox_lib, so every command appears with auto-completion suggestions, argument types, and help text directly in the in-game chat window as you type.