From 5f36f8a1e583471384df8b878b8d12f581686742 Mon Sep 17 00:00:00 2001 From: Chelo Lima Date: Fri, 8 May 2026 21:13:50 -0500 Subject: [PATCH 1/3] Update playeroutfits.lua Add Auto SQL DB Fix (Migration) --- server/database/playeroutfits.lua | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/server/database/playeroutfits.lua b/server/database/playeroutfits.lua index 0648bc8..2ad2774 100644 --- a/server/database/playeroutfits.lua +++ b/server/database/playeroutfits.lua @@ -34,3 +34,30 @@ end function Database.PlayerOutfits.DeleteByID(id) MySQL.query.await("DELETE FROM player_outfits WHERE id = ?", {id}) end + + +Citizen.CreateThread(function() + local result = MySQL.query.await("DESCRIBE player_outfits") + if result then + local hasComponents, hasProps, outfitIdColumn = false, false, nil + + for i=1, #result do + if result[i].Field == "components" then hasComponents = true end + if result[i].Field == "props" then hasProps = true end + if result[i].Field == "outfitId" then outfitIdColumn = result[i] end + end + + -- Fehlende Spalten hinzufügen + if not hasComponents then + MySQL.query.await("ALTER TABLE player_outfits ADD COLUMN components LONGTEXT DEFAULT NULL") + end + if not hasProps then + MySQL.query.await("ALTER TABLE player_outfits ADD COLUMN props LONGTEXT DEFAULT NULL") + end + + -- outfitId reparieren (auf Nullable setzen) + if outfitIdColumn and outfitIdColumn.Null == "NO" then + MySQL.query.await("ALTER TABLE player_outfits MODIFY COLUMN outfitId varchar(50) DEFAULT NULL") + end + end +end) From 0432eb04c58cbede0cff5c3c7ca6d820dc9e21a4 Mon Sep 17 00:00:00 2001 From: Chelo Lima Date: Fri, 8 May 2026 21:14:56 -0500 Subject: [PATCH 2/3] Update playeroutfits.lua Fixed PlayerOutfit Saves :-) --- server/database/playeroutfits.lua | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/server/database/playeroutfits.lua b/server/database/playeroutfits.lua index 2ad2774..723b157 100644 --- a/server/database/playeroutfits.lua +++ b/server/database/playeroutfits.lua @@ -13,15 +13,13 @@ function Database.PlayerOutfits.GetByOutfit(name, citizenid) -- for validate dup end function Database.PlayerOutfits.Add(citizenID, outfitName, model, components, props) - return MySQL.insert.await("INSERT INTO player_outfits (citizenid, outfitname, model, components, props) VALUES (?, ?, ?, ?, ?)", { - citizenID, - outfitName, - model, - components, - props + local skinData = json.encode({components = components, props = props}) + return MySQL.insert.await("INSERT INTO player_outfits (citizenid, outfitname, model, components, props, skin) VALUES (?, ?, ?, ?, ?, ?)", { + citizenID, outfitName, model, components, props, skinData }) end + function Database.PlayerOutfits.Update(outfitID, model, components, props) return MySQL.update.await("UPDATE player_outfits SET model = ?, components = ?, props = ? WHERE id = ?", { model, From e3e144c54fc8b24b7dd638ee854a343382d36bd8 Mon Sep 17 00:00:00 2001 From: Chelo Lima Date: Fri, 8 May 2026 21:17:32 -0500 Subject: [PATCH 3/3] Update server.lua Fixes new getOutfitForPLayer for old Skin Menus... --- server/server.lua | 38 ++++++++++++++++---------------------- 1 file changed, 16 insertions(+), 22 deletions(-) diff --git a/server/server.lua b/server/server.lua index 024906b..fe72719 100644 --- a/server/server.lua +++ b/server/server.lua @@ -12,7 +12,6 @@ local function getMoneyForShop(shopType) elseif shopType == "surgeon" then money = Config.SurgeonCost end - return money end @@ -20,12 +19,23 @@ local function getOutfitsForPlayer(citizenid) outfitCache[citizenid] = {} local result = Database.PlayerOutfits.GetAllByCitizenID(citizenid) for i = 1, #result, 1 do + local components = result[i].components and json.decode(result[i].components) + local props = result[i].props and json.decode(result[i].props) + + if (not components or not props) and result[i].skin then + local legacyData = json.decode(result[i].skin) + if legacyData then + components = components or legacyData.components + props = props or legacyData.props + end + end + outfitCache[citizenid][#outfitCache[citizenid] + 1] = { id = result[i].id, name = result[i].outfitname, model = result[i].model, - components = json.decode(result[i].components), - props = json.decode(result[i].props) + components = components or {}, + props = props or {} } end end @@ -39,15 +49,12 @@ local function GenerateUniqueCode() return code end --- Callback(s) - lib.callback.register("illenium-appearance:server:generateOutfitCode", function(_, outfitID) local existingOutfitCode = Database.PlayerOutfitCodes.GetByOutfitID(outfitID) if not existingOutfitCode then local code = GenerateUniqueCode() local id = Database.PlayerOutfitCodes.Add(outfitID, code) if not id then - print("Something went wrong while generating outfit code") return end return code @@ -61,22 +68,16 @@ lib.callback.register("illenium-appearance:server:importOutfitCode", function(so if not existingOutfitCode then return nil end - local playerOutfit = Database.PlayerOutfits.GetByID(existingOutfitCode.outfitid) if not playerOutfit then return end - - if playerOutfit.citizenid == citizenID then return end -- Validation when someone tried to duplicate own outfit - if Database.PlayerOutfits.GetByOutfit(outfitName, citizenID) then return end -- Validation duplicate outfit name, if validate on local id, someone can "spam error" server-sided - + if playerOutfit.citizenid == citizenID then return end + if Database.PlayerOutfits.GetByOutfit(outfitName, citizenID) then return end local id = Database.PlayerOutfits.Add(citizenID, outfitName, playerOutfit.model, playerOutfit.components, playerOutfit.props) - if not id then - print("Something went wrong while importing the outfit") return end - outfitCache[citizenID][#outfitCache[citizenID] + 1] = { id = id, name = outfitName, @@ -84,7 +85,6 @@ lib.callback.register("illenium-appearance:server:importOutfitCode", function(so components = json.decode(playerOutfit.components), props = json.decode(playerOutfit.props) } - return true end) @@ -105,7 +105,6 @@ end) lib.callback.register("illenium-appearance:server:payForTattoo", function(source, tattoo) local src = source local cost = tattoo.cost or Config.TattooCost - if Framework.RemoveMoney(src, "cash", cost) then lib.notify(src, { title = _L("purchase.tattoo.success.title"), @@ -138,11 +137,9 @@ lib.callback.register("illenium-appearance:server:getManagementOutfits", functio if mType == "Gang" then job = Framework.GetGang(source) end - local grade = tonumber(job.grade.level) local managementOutfits = {} local result = Database.ManagementOutfits.GetAllByJob(mType, job.name, gender) - for i = 1, #result, 1 do if grade >= result[i].minrank then managementOutfits[#managementOutfits + 1] = { @@ -251,10 +248,9 @@ RegisterNetEvent("illenium-appearance:server:saveManagementOutfit", function(out if not id then return end - lib.notify(src, { title = _L("outfits.save.success.title"), - description = string.format(_L("outfits.save.success.description"), outfitData.Name), + description = string.format(_L("outfits.save.success.description"), outfitData.Name), type = "success", position = Config.NotifyOptions.position }) @@ -274,7 +270,6 @@ RegisterNetEvent("illenium-appearance:server:deleteOutfit", function(id) local citizenID = Framework.GetPlayerID(src) Database.PlayerOutfitCodes.DeleteByOutfitID(id) Database.PlayerOutfits.DeleteByID(id) - for k, v in ipairs(outfitCache[citizenID]) do if v.id == id then table.remove(outfitCache[citizenID], k) @@ -337,7 +332,6 @@ if Config.EnableJobOutfitsCommand then lib.addCommand("joboutfits", { help = _L("commands.joboutfits.title"), }, function(source) TriggerClientEvent("illenium-apearance:client:outfitsCommand", source, true) end) - lib.addCommand("gangoutfits", { help = _L("commands.gangoutfits.title"), }, function(source) TriggerClientEvent("illenium-apearance:client:outfitsCommand", source) end)