From 54e8c81996d0a467081a2bb48675b99afeb7dcbe Mon Sep 17 00:00:00 2001 From: root Date: Mon, 24 Nov 2025 19:20:26 +0000 Subject: [PATCH] Server Auth Test --- .../compatibility/frameworks/esx/server.lua | 51 ++++- .../compatibility/frameworks/qb/server.lua | 40 +++- modules/injuries/client.lua | 6 +- modules/job/client/main.lua | 5 +- modules/job/client/medical_bag.lua | 5 +- modules/job/client/shops.lua | 14 +- modules/paramedic/client.lua | 9 +- modules/utils/client/utils.lua | 12 -- server.lua | 196 ++++++++++++++++-- 9 files changed, 294 insertions(+), 44 deletions(-) diff --git a/modules/compatibility/frameworks/esx/server.lua b/modules/compatibility/frameworks/esx/server.lua index f227090..454ee64 100644 --- a/modules/compatibility/frameworks/esx/server.lua +++ b/modules/compatibility/frameworks/esx/server.lua @@ -3,6 +3,7 @@ local ESX = GetResourceState('es_extended'):find('start') and exports['es_extend if not ESX then return end Framework = {} +medicalBags = medicalBags or {} local useOxInventory = lib.load("config").useOxInventory local ox_inventory = useOxInventory and exports.ox_inventory @@ -34,6 +35,13 @@ function Framework.playerJob(target) return xPlayer.job.name end +function Framework.getPlayerJobGrade(target) + local xPlayer = ESX.GetPlayerFromId(target) + if not xPlayer then return end + + return xPlayer.job.grade +end + function Framework.updateStatus(data) local xPlayer = ESX.GetPlayerFromId(data.target) @@ -72,6 +80,13 @@ function Framework.getDeathStatus(target) return data end +local moneyTypes = { + money = 'money', + cash = 'cash', + bank = 'bank', + black_money = 'black_money', +} + function Framework.addItem(target, item, amount) if ox_inventory then return ox_inventory:AddItem(target, item, amount) @@ -79,6 +94,9 @@ function Framework.addItem(target, item, amount) local xPlayer = ESX.GetPlayerFromId(target) if not xPlayer then return end + if moneyTypes[item] then + return xPlayer.addMoney(amount) + end return xPlayer.addInventoryItem(item, amount) end @@ -89,6 +107,9 @@ function Framework.removeItem(target, item, amount) local xPlayer = ESX.GetPlayerFromId(target) if not xPlayer then return end + if moneyTypes[item] then + return xPlayer.removeMoney(amount) + end return xPlayer.removeInventoryItem(item, amount) end @@ -114,6 +135,30 @@ function Framework.wipeInventory(target, keep) end end +function Framework.hasItem(target, item, amount) + local quantity = amount or 1 + + if ox_inventory then + local count = ox_inventory:Search(target, 'count', item) + return count and count >= quantity + end + + local xPlayer = ESX.GetPlayerFromId(target) + if not xPlayer then return end + + if moneyTypes[item] then + return xPlayer.getMoney() >= quantity + end + + for _, data in pairs(xPlayer.inventory or {}) do + if data and data.name == item and data.count >= quantity then + return true + end + end + + return false +end + local medicBagItem = lib.load("config").medicBagItem local emsJobs = lib.load("config").emsJobs local tabletItem = lib.load("config").tabletItem @@ -121,7 +166,11 @@ local tabletItem = lib.load("config").tabletItem ESX.RegisterUsableItem(medicBagItem, function(source, a, b) if not Framework.hasJob(source, emsJobs) then return end - TriggerClientEvent("ars_ambulancejob:placeMedicalBag", source) + if Framework.hasItem(source, medicBagItem, 1) then + Framework.removeItem(source, medicBagItem, 1) + medicalBags[source] = (medicalBags[source] or 0) + 1 + TriggerClientEvent("ars_ambulancejob:placeMedicalBag", source) + end end) ESX.RegisterUsableItem(tabletItem, function(source, a, b) diff --git a/modules/compatibility/frameworks/qb/server.lua b/modules/compatibility/frameworks/qb/server.lua index 9dd8ff0..ca1a886 100644 --- a/modules/compatibility/frameworks/qb/server.lua +++ b/modules/compatibility/frameworks/qb/server.lua @@ -3,6 +3,7 @@ QBCore = GetResourceState('qb-core'):find('start') and exports['qb-core']:GetCor if not QBCore then return end Framework = {} +medicalBags = medicalBags or {} local useOxInventory = lib.load("config").useOxInventory local ox_inventory = useOxInventory and exports.ox_inventory @@ -35,6 +36,14 @@ function Framework.playerJob(target) return xPlayer.PlayerData.job.name end +function Framework.getPlayerJobGrade(target) + local xPlayer = QBCore.Functions.GetPlayer(target) + if not xPlayer then return end + + local grade = xPlayer.PlayerData.job.grade + return type(grade) == "table" and grade.level or grade +end + function Framework.updateStatus(data) local Player = QBCore.Functions.GetPlayer(data.target) @@ -108,6 +117,31 @@ function Framework.wipeInventory(target, keep) exports["qb-inventory"]:ClearInventory(target, keep) end +function Framework.hasItem(target, item, amount) + local quantity = amount or 1 + + if ox_inventory then + local count = ox_inventory:Search(target, 'count', item) + return count and count >= quantity + end + + local xPlayer = QBCore.Functions.GetPlayer(target) + if not xPlayer then return end + + if item == "money" or item == "cash" then + return xPlayer.PlayerData.money["cash"] >= quantity + end + + local inventory = xPlayer.PlayerData.items or {} + for _, data in pairs(inventory) do + if data and data.name == item and data.amount >= quantity then + return true + end + end + + return false +end + local medicBagItem = lib.load("config").medicBagItem local emsJobs = lib.load("config").emsJobs local tabletItem = lib.load("config").tabletItem @@ -115,7 +149,11 @@ local tabletItem = lib.load("config").tabletItem QBCore.Functions.CreateUseableItem(medicBagItem, function(source, item) if not Framework.hasJob(source, emsJobs) then return end - TriggerClientEvent("ars_ambulancejob:placeMedicalBag", source) + local removed = Framework.removeItem(source, medicBagItem, 1) + if removed then + medicalBags[source] = (medicalBags[source] or 0) + 1 + TriggerClientEvent("ars_ambulancejob:placeMedicalBag", source) + end end) QBCore.Functions.CreateUseableItem(tabletItem, function(source, item) if not Framework.hasJob(source, emsJobs) then return end diff --git a/modules/injuries/client.lua b/modules/injuries/client.lua index 9ac49a8..16cb164 100644 --- a/modules/injuries/client.lua +++ b/modules/injuries/client.lua @@ -95,7 +95,11 @@ function checkInjuries(data) dataToSend.bone = v.bone TriggerServerEvent("ars_ambulancejob:healPlayer", dataToSend) - utils.addRemoveItem("add", "money", (100 * (v.value / 10))) + TriggerServerEvent("ars_ambulancejob:claimReward", { + type = "injury", + target = data.target, + bone = v.bone + }) utils.showNotification(locale("injury_treated")) utils.debug("Injury treated " .. dataToSend.bone) diff --git a/modules/job/client/main.lua b/modules/job/client/main.lua index 58d0069..3a51ddc 100644 --- a/modules/job/client/main.lua +++ b/modules/job/client/main.lua @@ -327,7 +327,10 @@ RegisterNetEvent("ars_ambulancejob:playHealAnim", function(data) utils.useItem("defibrillator", consumeItemPerUse) - utils.addRemoveItem("add", "money", reviveReward) + TriggerServerEvent("ars_ambulancejob:claimReward", { + type = "revive", + target = data.targetServerId + }) elseif data.anim == "dead" then utils.showNotification(locale("action_revived_notification")) diff --git a/modules/job/client/medical_bag.lua b/modules/job/client/medical_bag.lua index 7b62338..e93a820 100644 --- a/modules/job/client/medical_bag.lua +++ b/modules/job/client/medical_bag.lua @@ -7,6 +7,7 @@ local PlaceObjectOnGroundProperly = PlaceObjectOnGroundProperly local DeleteEntity = DeleteEntity local ClearPedTasks = ClearPedTasks local RegisterNetEvent = RegisterNetEvent +local TriggerServerEvent = TriggerServerEvent local medicBagProp = lib.load("config").medicBagProp local useOxInventory = lib.load("config").useOxInventory @@ -35,8 +36,6 @@ local function placeMedicalBag() medicBag = CreateObjectNoOffset(medicBagProp, coords.x, coords.y, coords.z, true, false) PlaceObjectOnGroundProperly(medicBag) - utils.addRemoveItem("remove", "medicalbag", 1) - Target.addLocalEntity(medicBag, { { label = locale('open_medical_bag'), @@ -61,7 +60,7 @@ local function placeMedicalBag() DeleteEntity(type(data) == "number" and data or data.entity) ClearPedTasks(playerPed) - utils.addRemoveItem("add", "medicalbag", 1) + TriggerServerEvent("ars_ambulancejob:returnMedicalBag") end }, }) diff --git a/modules/job/client/shops.lua b/modules/job/client/shops.lua index d6fe34f..7554b2d 100644 --- a/modules/job/client/shops.lua +++ b/modules/job/client/shops.lua @@ -56,14 +56,16 @@ local function createShops() }) if not amount then return end - local quantity = amount[1] - local totalPrice = item.price * quantity + local quantity = tonumber(amount[1]) + if not quantity or quantity < 1 then return end - local hasMoney = Framework.hasItem("money", totalPrice) - if not hasMoney then return utils.showNotification(locale("not_enough_money")) end + quantity = math.floor(quantity) + if quantity < 1 then return end - utils.addRemoveItem("remove", "money", totalPrice) - utils.addRemoveItem("add", item.name, quantity) + local result = lib.callback.await('ars_ambulancejob:purchaseItem', false, name, item.name, quantity) + if not result or result.success then return end + + utils.showNotification(locale(result.reason)) end, } end diff --git a/modules/paramedic/client.lua b/modules/paramedic/client.lua index 42a0646..cd389a5 100644 --- a/modules/paramedic/client.lua +++ b/modules/paramedic/client.lua @@ -17,11 +17,10 @@ local function openParamedicMenu(ped, hospital) { title = locale("get_treated_paramedic"), onSelect = function() - local hasMoney = Framework.hasItem("money", paramedicTreatmentPrice) - if not hasMoney then return utils.showNotification(locale("not_enough_money")) end - - - utils.addRemoveItem("remove", "money", paramedicTreatmentPrice) + local paid = lib.callback.await('ars_ambulancejob:payParamedicTreatment', false) + if not paid then + return utils.showNotification(locale("not_enough_money")) + end local dict = lib.requestAnimDict("anim@gangops@morgue@table@") local playerPed = cache.ped or PlayerPedId() diff --git a/modules/utils/client/utils.lua b/modules/utils/client/utils.lua index 895b8c0..333aa15 100644 --- a/modules/utils/client/utils.lua +++ b/modules/utils/client/utils.lua @@ -109,18 +109,6 @@ function utils.getClosestHospital() return closestHospital end -function utils.addRemoveItem(type, item, quantity) - local data = {} - data.toggle = type == "remove" - data.item = item - data.quantity = quantity - - utils.debug(type, item, quantity) - utils.debug(data) - - TriggerServerEvent("ars_ambulancejob:removAddItem", data) -end - function utils.useItem(item, value) local data = {} data.item = item diff --git a/server.lua b/server.lua index 97a4224..72b97b6 100644 --- a/server.lua +++ b/server.lua @@ -1,9 +1,59 @@ player = {} +medicalBags = medicalBags or {} +local pendingRewards = {} distressCalls = {} -local emsJobs = lib.load("config").emsJobs -local useOxInventory = lib.load("config").useOxInventory +local config = lib.load("config") +local emsJobs = config.emsJobs +local reviveReward = config.reviveReward or 0 +local medicBagItem = config.medicBagItem +local paramedicPrice = config.paramedicTreatmentPrice or 0 +local useOxInventory = config.useOxInventory +local hospitals = lib.load("data.hospitals") local ox_inventory = useOxInventory and exports.ox_inventory +local pharmacies = {} +for _, hospital in pairs(hospitals) do + if hospital.pharmacy then + for id, pharmacy in pairs(hospital.pharmacy) do + pharmacies[id] = pharmacy + end + end +end + +local function getPharmacyItem(pharmacyId, itemName) + local pharmacy = pharmacies[pharmacyId] + if not pharmacy or not pharmacy.items then return end + + for _, item in ipairs(pharmacy.items) do + if item.name == itemName then + return item, pharmacy + end + end +end + +local function ensureRewardCache(source) + if not pendingRewards[source] then + pendingRewards[source] = { + revives = {}, + injuries = {} + } + end + + return pendingRewards[source] +end + +local function cleanupRewardCache(source) + local rewards = pendingRewards[source] + if not rewards then return end + + local hasRevives = rewards.revives and next(rewards.revives) + local hasInjuries = rewards.injuries and next(rewards.injuries) + + if not hasRevives and not hasInjuries then + pendingRewards[source] = nil + end +end + RegisterNetEvent("ars_ambulancejob:updateDeathStatus", function(death) local source = source local data = {} @@ -43,14 +93,34 @@ RegisterNetEvent("ars_ambulancejob:healPlayer", function(data) return print(source .. ' probile modder') end + local targetServerId = tonumber(data.targetServerId) if data.injury then - TriggerClientEvent('ars_ambulancejob:healPlayer', tonumber(data.targetServerId), data) + local targetPlayer = Player(targetServerId) + if not targetPlayer then return end + + local injuries = targetPlayer.state.injuries or {} + local injury = injuries[data.bone] + if not injury then return end + + local reward = math.floor(100 * ((injury.value or 0) / 10)) + if reward > 0 then + local rewards = ensureRewardCache(source) + rewards.injuries[targetServerId] = rewards.injuries[targetServerId] or {} + rewards.injuries[targetServerId][data.bone] = reward + end + + TriggerClientEvent('ars_ambulancejob:healPlayer', targetServerId, data) else data.anim = "medic" TriggerClientEvent("ars_ambulancejob:playHealAnim", source, data) data.anim = "dead" - TriggerClientEvent("ars_ambulancejob:playHealAnim", data.targetServerId, data) + TriggerClientEvent("ars_ambulancejob:playHealAnim", targetServerId, data) + + if reviveReward and reviveReward > 0 then + local rewards = ensureRewardCache(source) + rewards.revives[targetServerId] = reviveReward + end end end) @@ -87,14 +157,6 @@ RegisterNetEvent("ars_ambulancejob:callCompleted", function(call) end end) -RegisterNetEvent("ars_ambulancejob:removAddItem", function(data) - local source = source - - local method = data.toggle and Framework.removeItem or Framework.addItem - - method(source, data.item, data.quantity) -end) - RegisterNetEvent("ars_ambulancejob:useItem", function(data) if not Framework.hasJob(source, emsJobs) then return end @@ -107,11 +169,12 @@ RegisterNetEvent("ars_ambulancejob:useItem", function(data) Framework.removeItem(data.item) end) -local removeItemsOnRespawn = lib.load("config").removeItemsOnRespawn +local removeItemsOnRespawn = config.removeItemsOnRespawn +local keepItemsOnRespawn = config.keepItemsOnRespawn RegisterNetEvent("ars_ambulancejob:removeInventory", function() local source = source if player[source].isDead and removeItemsOnRespawn then - Framework.wipeInventory(source, lib.load("config").keepItemsOnRespawn) + Framework.wipeInventory(source, keepItemsOnRespawn) end end) @@ -167,6 +230,111 @@ lib.callback.register('ars_ambulancejob:getMedicsOniline', function(source) return count end) +lib.callback.register('ars_ambulancejob:purchaseItem', function(source, pharmacyId, itemName, quantity) + quantity = tonumber(quantity) + if not quantity or quantity < 1 then return { success = false, reason = 'invalid_quantity' } end + + local item, pharmacy = getPharmacyItem(pharmacyId, itemName) + if not item then return { success = false, reason = 'invalid_item' } end + + if pharmacy.job and not Framework.hasJob(source, emsJobs) then + return { success = false, reason = 'no_access' } + end + + if pharmacy.job and pharmacy.grade then + local jobGrade = Framework.getPlayerJobGrade and Framework.getPlayerJobGrade(source) or 0 + if jobGrade < pharmacy.grade then + return { success = false, reason = 'no_access' } + end + end + + local totalPrice = math.floor(item.price * quantity) + if totalPrice < 1 then return { success = false, reason = 'invalid_price' } end + + if not Framework.hasItem(source, 'money', totalPrice) then + return { success = false, reason = 'not_enough_money' } + end + + Framework.removeItem(source, 'money', totalPrice) + Framework.addItem(source, item.name, quantity) + + return { success = true } +end) + +lib.callback.register('ars_ambulancejob:payParamedicTreatment', function(source) + if paramedicPrice <= 0 then return true end + + if not Framework.hasItem(source, 'money', paramedicPrice) then + return false + end + + Framework.removeItem(source, 'money', paramedicPrice) + return true +end) + +RegisterNetEvent("ars_ambulancejob:claimReward", function(payload) + local source = source + if not Framework.hasJob(source, emsJobs) then return end + if type(payload) ~= "table" then return end + + local rewards = pendingRewards[source] + if not rewards then return end + + if payload.type == "revive" then + local target = tonumber(payload.target) + if not target then return end + + local reward = rewards.revives[target] + if not reward then return end + + rewards.revives[target] = nil + Framework.addItem(source, "money", reward) + + elseif payload.type == "injury" then + local target = tonumber(payload.target) + local bone = payload.bone + if not target or not bone then return end + + local patientRewards = rewards.injuries[target] + if not patientRewards then return end + + local reward = patientRewards[bone] + if not reward then return end + + patientRewards[bone] = nil + if not next(patientRewards) then + rewards.injuries[target] = nil + end + + Framework.addItem(source, "money", reward) + end + + cleanupRewardCache(source) +end) + +RegisterNetEvent("ars_ambulancejob:returnMedicalBag", function() + local source = source + if not Framework.hasJob(source, emsJobs) then return end + + local deployed = medicalBags[source] + if not deployed or deployed < 1 then return end + + deployed -= 1 + if deployed <= 0 then + medicalBags[source] = nil + else + medicalBags[source] = deployed + end + + Framework.addItem(source, medicBagItem, 1) +end) + +AddEventHandler('playerDropped', function() + local source = source + pendingRewards[source] = nil + medicalBags[source] = nil +end) + if ox_inventory then lib.callback.register('ars_ambulancejob:getItem', function(source, name) local item = ox_inventory:GetSlotWithItem(source, name)