local decorationsByGarage = {} local decorationUsedBy = {} local ALLOWED_UPDATE_KEYS = { coords = true, rotation = true, inStash = true, lightData = true, } lib.callback.register("garages:decorate:saveObject", function(sourcePlayer, garageId, objectData) local playerIdentifier = GetPlayerIdentifier(sourcePlayer) objectData.created = os.time() local newId = db.saveObject(playerIdentifier, objectData) objectData.id = newId if not decorationsByGarage[garageId] then decorationsByGarage[garageId] = {} end decorationsByGarage[garageId][#decorationsByGarage[garageId] + 1] = objectData objectData.uniq = tostring("garage_" .. newId) TriggerClientEvent("garages:decorate:addObject", -1, garageId, objectData) Debug("garages:decorate:saveObject", "Saved", garageId, "Id", newId, "Data", objectData) return true end) RegisterNetEvent("garages:decorate:updateObject") AddEventHandler("garages:decorate:updateObject", function(garageId, objectId, updateData) local playerSource = source if not updateData then return Notification(playerSource, i18n.t("decorate.invalid_data"), "error") end Debug("data", updateData) local hasInvalidKey = table.find(updateData, function(value, key) return not ALLOWED_UPDATE_KEYS[key] end) if hasInvalidKey then Notification(playerSource, i18n.t("decorate.invalid_data"), "error") Debug("unsecured", updateData) Debug("garages:decorate:updateObject", "User trying to exploit update profile event", playerSource, updateData) return end local foundObject = table.find(decorationsByGarage[garageId], function(obj) return obj.id == objectId end) if not foundObject then return Notification(playerSource, i18n.t("decorate.invalid_object"), "error") end local success = db.updateObject(objectId, updateData) if not success then Notification(playerSource, i18n.t("decorate.failed_update"), "error") return end for key, value in pairs(updateData) do if value and (key == "coords" or key == "rotation" or key == "lightData") then Debug("garages:decorate:updateObject", "Decoding", key, value) updateData[key] = json.decode(value) end foundObject[key] = updateData[key] end TriggerClientEvent("garages:decorate:updateObject", -1, garageId, objectId, updateData) Debug("garages:decorate:updateObject", "Updated", garageId, "Id", objectId, "data", updateData) end) local function GetFurniturePriceByObject(modelName) for categoryKey, category in pairs(Config.Furniture) do if categoryKey ~= "navigation" then for _, item in pairs(category.items) do if item.object == modelName then return item.price end if item.colors then for _, colorVariant in pairs(item.colors) do if colorVariant.object == modelName then return item.price end end end end end end end RegisterNetEvent("garages:decorate:sellFurniture") AddEventHandler("garages:decorate:sellFurniture", function(garageId, objectId) local playerSource = source local foundObject = table.find(decorationsByGarage[garageId], function(obj) return obj.id == objectId end) if not foundObject then return Notification(playerSource, i18n.t("decorate.invalid_object"), "error") end local success = db.deleteObject(objectId) if not success then Notification(playerSource, i18n.t("decorate.failed_sell"), "error") return end local price = GetFurniturePriceByObject(foundObject.modelName) local sellGain = price * Config.SellObjectCommision AddAccountMoney(playerSource, Config.MoneyType, sellGain) decorationsByGarage[garageId] = table.filter(decorationsByGarage[garageId], function(obj) return obj.id ~= objectId end) TriggerClientEvent("garages:decorate:sellFurniture", -1, garageId, objectId) Notification(playerSource, i18n.t("decorate.sold_furniture", { price = sellGain }), "success") end) local function GetDecorations(garageId) if not decorationsByGarage[garageId] then local dbObjects = db.getObjects(garageId) decorationsByGarage[garageId] = dbObjects or {} end for key, value in pairs(decorationsByGarage) do if key == "coords" and type(value) == "string" then decorationsByGarage[key] = json.decode(value) Error("If you see this error please report this ERROR TO THE QUASAR. It will not affect the server but it will help us to improve the script. Thank you!") elseif key == "rotation" and type(value) == "string" then decorationsByGarage[key] = json.decode(value) Error("If you see this error please report this ERROR TO THE QUASAR. It will not affect the server but it will help us to improve the script. Thank you!") elseif key == "lightData" and type(value) == "string" then decorationsByGarage[key] = json.decode(value) Error("If you see this error please report this ERROR TO THE QUASAR. It will not affect the server but it will help us to improve the script. Thank you!") end end return decorationsByGarage[garageId] or {} end function ClearDecorations(garageId) decorationsByGarage[garageId] = nil Debug("ClearDecorations", garageId) end lib.callback.register("garages:decorate:getDecorations", function(sourcePlayer, garageId) return GetDecorations(garageId) end) lib.callback.register("garages:decorate:buyDecorationObject", function(sourcePlayer, price) local balance = GetAccountMoney(sourcePlayer, Config.MoneyType) if not price then Error("Price is nil", price) return false end if price > balance then Notification(sourcePlayer, i18n.t("decorate.no_money", { price = price }), "error") return false end RemoveAccountMoney(sourcePlayer, Config.MoneyType, price) return true end) lib.callback.register("garages:decorate:getDecorationAvailable", function(sourcePlayer, garageId) local usedBy = decorationUsedBy[garageId] Debug("garages:decorate:getDecorationAvailable", garageId, "UsedBy", usedBy) if not usedBy then return true end return usedBy end) RegisterNetEvent("garages:decorate:updateDecorationUsedBy") AddEventHandler("garages:decorate:updateDecorationUsedBy", function(garageId, isUsing) local playerSource = source decorationUsedBy[garageId] = (isUsing and playerSource) and playerSource or nil Debug("garages:decorate:updateDecorationUsedBy", garageId, "UsedBy", isUsing) end) AddEventHandler("playerDropped", function(reason) local playerSource = source for garageId, usedByPlayer in pairs(decorationUsedBy) do if usedByPlayer == playerSource then decorationUsedBy[garageId] = nil end end end) RegisterNetEvent("garages:fiveguard:freecam") AddEventHandler("garages:fiveguard:freecam", function(isActive) local playerSource = source if not Config.FiveGuard then return end local fiveGuard = exports[Config.FiveGuard] fiveGuard:SetTempPermission(playerSource, "Client", "BypassFreecam", isActive, isActive, false) fiveGuard:SetTempPermission(playerSource, "Client", "BypassNoclip", isActive, isActive, false) end)