forked from Simnation/Main
178 lines
6.6 KiB
Lua
178 lines
6.6 KiB
Lua
![]() |
---@diagnostic disable: duplicate-set-field
|
||
|
if GetResourceState('esx_skin') == 'missing' then return end
|
||
|
if GetResourceState('rcore_clothing') ~= 'missing' then return end
|
||
|
Clothing = Clothing or {}
|
||
|
Clothing.Players = {}
|
||
|
|
||
|
Callback = Callback or Require("lib/utility/shared/callbacks.lua")
|
||
|
Table = Table or Require('lib/utility/shared/tables.lua')
|
||
|
|
||
|
---Internal function to get the full appearance data including skin, model, and converted format
|
||
|
---@param src number The server ID of the player
|
||
|
---@return table|nil The player's full appearance data or nil if not found
|
||
|
function Clothing.GetFullAppearanceData(src)
|
||
|
src = src and tonumber(src)
|
||
|
assert(src, "src is nil")
|
||
|
local citId = Bridge.Framework.GetPlayerIdentifier(src)
|
||
|
if not citId then return end
|
||
|
|
||
|
if Clothing.Players[citId] then return Clothing.Players[citId] end
|
||
|
|
||
|
local result = MySQL.query.await('SELECT skin FROM users WHERE identifier = ?', { citId })
|
||
|
if result[1] == nil then return end
|
||
|
|
||
|
local model = GetEntityModel(GetPlayerPed(src))
|
||
|
local skinData = json.decode(result[1].skin)
|
||
|
local converted = Clothing.ConvertToDefault(skinData)
|
||
|
|
||
|
-- Store complete data in the cache
|
||
|
Clothing.Players[citId] = {
|
||
|
model = model,
|
||
|
skin = skinData,
|
||
|
converted = converted
|
||
|
}
|
||
|
|
||
|
return Clothing.Players[citId]
|
||
|
end
|
||
|
|
||
|
---Retrieves a player's converted appearance data for easy use across modules
|
||
|
---@param src number The server ID of the player
|
||
|
---@param fullData boolean Optional - If true, returns the full data object including skin and model
|
||
|
---@return table|nil The player's converted appearance data or full appearance data if fullData=true
|
||
|
function Clothing.GetAppearance(src, fullData)
|
||
|
if fullData then
|
||
|
return Clothing.GetFullAppearanceData(src)
|
||
|
end
|
||
|
local completeData = Clothing.GetFullAppearanceData(src)
|
||
|
if not completeData then return nil end
|
||
|
return completeData.converted
|
||
|
end
|
||
|
|
||
|
---This will save the player's current appearance to the database
|
||
|
---@param src number|string
|
||
|
function Clothing.Save(src)
|
||
|
src = src and tonumber(src)
|
||
|
assert(src, "src is nil")
|
||
|
local citId = Bridge.Framework.GetPlayerIdentifier(src)
|
||
|
if not citId then return end
|
||
|
local currentClothing = Clothing.GetFullAppearanceData(src)
|
||
|
if not currentClothing then return end
|
||
|
local currentSkin = currentClothing.skin
|
||
|
local encodedSkin = json.encode(currentSkin)
|
||
|
MySQL.update.await('UPDATE users SET skin = ? WHERE identifier = ?', {
|
||
|
encodedSkin,
|
||
|
citId
|
||
|
})
|
||
|
end
|
||
|
|
||
|
---Sets a player's appearance based on the provided data
|
||
|
---@param src number The server ID of the player
|
||
|
---@param data table The appearance data to apply
|
||
|
---@param updateBackup boolean Whether to update the backup appearance data
|
||
|
---@return table|nil The updated player appearance data or nil if failed
|
||
|
function Clothing.SetAppearance(src, data, updateBackup, save)
|
||
|
src = src and tonumber(src)
|
||
|
assert(src, "src is nil")
|
||
|
local citId = Bridge.Framework.GetPlayerIdentifier(src)
|
||
|
if not citId then return end
|
||
|
local model = GetEntityModel(GetPlayerPed(src))
|
||
|
if not model then return end
|
||
|
local converted = Clothing.ConvertFromDefault(data)
|
||
|
|
||
|
-- Get full appearance data
|
||
|
local currentClothing = Clothing.GetFullAppearanceData(src)
|
||
|
if not currentClothing then return end
|
||
|
|
||
|
local currentSkin = currentClothing.skin
|
||
|
for k, v in pairs(converted) do
|
||
|
currentSkin[k] = v
|
||
|
end
|
||
|
|
||
|
|
||
|
if not Clothing.Players[citId].backup or updateBackup then
|
||
|
Clothing.Players[citId].backup = currentClothing.converted
|
||
|
end
|
||
|
|
||
|
Clothing.Players[citId] = Clothing.Players[citId] or {}
|
||
|
Clothing.Players[citId].skin = currentSkin
|
||
|
Clothing.Players[citId].model = model
|
||
|
Clothing.Players[citId].converted = Clothing.ConvertToDefault(currentSkin)
|
||
|
if save then
|
||
|
local encodedSkin = json.encode(currentSkin)
|
||
|
-- saving 1 sql call by adding the query here instead of calling save
|
||
|
MySQL.update.await('UPDATE users SET skin = ? WHERE identifier = ?', {
|
||
|
encodedSkin,
|
||
|
citId
|
||
|
})
|
||
|
end
|
||
|
TriggerClientEvent('community_bridge:client:SetAppearance', src, Clothing.Players[citId].converted)
|
||
|
return Clothing.Players[citId]
|
||
|
end
|
||
|
|
||
|
--- Sets a player's appearance based on gender-specific data
|
||
|
---@param src number The server ID of the player
|
||
|
---@param data table Table containing separate appearance data for male and female characters
|
||
|
---@return table|nil Appearance updated player appearance data or nil if failed
|
||
|
function Clothing.SetAppearanceExt(src, data)
|
||
|
local tbl = Clothing.IsMale(src) and data.male or data.female
|
||
|
Clothing.SetAppearance(src, tbl)
|
||
|
end
|
||
|
|
||
|
---Reverts a player's appearance to their backup appearance
|
||
|
---@param src number The server ID of the player
|
||
|
---@return boolean|nil Returns true if successful or nil if failed
|
||
|
function Clothing.Revert(src)
|
||
|
src = src and tonumber(src)
|
||
|
assert(src, "src is nil")
|
||
|
local currentClothing = Clothing.GetFullAppearanceData(src)
|
||
|
if not currentClothing then return end
|
||
|
local backup = currentClothing.backup
|
||
|
if not backup then return end
|
||
|
return Clothing.SetAppearance(src, backup)
|
||
|
end
|
||
|
|
||
|
---This will open the menu for the passed src
|
||
|
---@param src number|string
|
||
|
function Clothing.OpenMenu(src)
|
||
|
src = src and tonumber(src)
|
||
|
assert(src, "src is nil")
|
||
|
TriggerClientEvent('esx_skin:openMenu', src)
|
||
|
end
|
||
|
|
||
|
---Event handler for when a player loads into the server
|
||
|
---Caches the player's appearance data
|
||
|
AddEventHandler('community_bridge:Server:OnPlayerLoaded', function(src)
|
||
|
src = src and tonumber(src)
|
||
|
assert(src, "src is nil")
|
||
|
-- Use GetFullAppearanceData to cache the complete appearance
|
||
|
Clothing.GetFullAppearanceData(src)
|
||
|
end)
|
||
|
|
||
|
---Event handler for when a player disconnects from the server
|
||
|
---Removes the player's appearance data from the cache
|
||
|
AddEventHandler('community_bridge:Server:OnPlayerUnload', function(src)
|
||
|
src = src and tonumber(src)
|
||
|
assert(src, "src is nil")
|
||
|
local strSrc = tostring(src)
|
||
|
Clothing.Players[strSrc] = nil
|
||
|
end)
|
||
|
|
||
|
---Event handler for when the resource starts
|
||
|
---Caches appearance data for all currently connected players
|
||
|
AddEventHandler('onResourceStart', function(resource)
|
||
|
if resource ~= GetCurrentResourceName() then return end
|
||
|
for _, playerId in ipairs(GetPlayers()) do
|
||
|
local src = tonumber(playerId)
|
||
|
local strSrc = tostring(src)
|
||
|
if not Clothing.Players[strSrc] then
|
||
|
Clothing.Players[strSrc] = Clothing.GetAppearance(src)
|
||
|
end
|
||
|
end
|
||
|
end)
|
||
|
|
||
|
---Callback handler for retrieving a player's appearance data
|
||
|
Callback.Register('community_bridge:cb:GetAppearance', function(source)
|
||
|
local src = source
|
||
|
return Clothing.GetAppearance(src)
|
||
|
end)
|