diff --git a/.gitignore b/.gitignore index e55c9567d..f957c79eb 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,8 @@ yarn.lock server/created_doors_data.txt /server/db +server/server.ptr.cfg +server/server.ptr.cfg +server/resources/\[sandbox\]/sandbox-phone/server/bizphone.lua +server/resources/\[sandbox\]/sandbox-dealerships/server/sales.lua +server/config/database.ptr.cfg diff --git a/server/resources/[sandbox]/sandbox-laptop/client/main.lua b/server/resources/[sandbox]/sandbox-laptop/client/main.lua index f7f8e7503..92495e1ed 100644 --- a/server/resources/[sandbox]/sandbox-laptop/client/main.lua +++ b/server/resources/[sandbox]/sandbox-laptop/client/main.lua @@ -46,10 +46,7 @@ AddEventHandler("Characters:Client:Updated", function() _settings = LocalPlayer.state.Character:GetData("LaptopSettings") exports['sandbox-laptop']:SetData("player", LocalPlayer.state.Character:GetData()) - if - LocalPlayer.state.laptopOpen - and not (exports.ox_inventory:Search('count', 'laptop') == 0) - then + if LocalPlayer.state.laptopOpen and (exports.ox_inventory:Search('count', 'laptop') == 0) then exports['sandbox-laptop']:Close(true) end end) @@ -78,7 +75,7 @@ RegisterNetEvent("UI:Client:Reset", function(manual) end) AddEventHandler("UI:Client:Close", function(context) - if context ~= "laptop" then + if context == "laptop" then exports['sandbox-laptop']:Close() end end) diff --git a/server/resources/[sandbox]/sandbox-phone/client/bizphone.lua b/server/resources/[sandbox]/sandbox-phone/client/bizphone.lua index b1cb1bf6f..2052cc6ac 100644 --- a/server/resources/[sandbox]/sandbox-phone/client/bizphone.lua +++ b/server/resources/[sandbox]/sandbox-phone/client/bizphone.lua @@ -1,16 +1,32 @@ -local phoneModel = `vw_prop_casino_phone_01a` +local phoneModel = `v_ret_gc_phone` local _createdPhones = {} +local function HasBizAccess(jobName) + if not LocalPlayer.state.loggedIn then return false end + + if type(LocalPlayer.state.onDuty) == "string" then + return LocalPlayer.state.onDuty == jobName + end + + local jobs = LocalPlayer.state.jobs + if type(jobs) == "table" and jobs[jobName] then + return true + end + + return false +end + function CreateBizPhoneObject(coords, rotation) RequestModel(phoneModel) while not HasModelLoaded(phoneModel) do Wait(1) end - local obj = CreateObject(phoneModel, coords.x, coords.y, coords.z, false, true, false) - SetEntityRotation(obj, rotation.x, rotation.y, rotation.z) + local obj = CreateObject(phoneModel, coords.x, coords.y, coords.z, false, false, false) + SetEntityCoordsNoOffset(obj, coords.x, coords.y, coords.z, false, false, false) + SetEntityRotation(obj, rotation.x, rotation.y, rotation.z, 2, true) FreezeEntityPosition(obj, true) - SetEntityCoords(obj, coords.x, coords.y, coords.z) + SetEntityAsMissionEntity(obj, true, true) while not DoesEntityExist(obj) do Wait(1) @@ -24,115 +40,78 @@ function CreateBizPhones() Wait(100) end - for k, v in pairs(GlobalState.BizPhones) do + for _, v in pairs(GlobalState.BizPhones) do local object = CreateBizPhoneObject(v.coords, v.rotation) - exports.ox_target:addEntity(object, { + exports.ox_target:addLocalEntity(object, { { - icon = "phone-volume", - label = "Phone", + icon = "phone", + label = "Answer Call", onSelect = function() - TriggerEvent("Phone:Client:MakeBizCall", { id = v.id }) + TriggerEvent("Phone:Client:AcceptBizCall", nil, { id = v.id }) end, - groups = { v.job }, - canInteract = function(data) - if data then - local pData = GlobalState[string.format("BizPhone:%s", data.id)] - if pData and pData.state > 1 then - return true - end - end - end, - label = function(data) - if data then - local pData = GlobalState[string.format("BizPhone:%s", data.id)] - if pData then - if pData.state == 2 then - return string.format("On Call (%s)", pData.callingStr) - else - return string.format("Dialing (%s)", pData.number) - end - end - end - return "" + canInteract = function() + local pData = GlobalState[("BizPhone:%s"):format(v.id)] + return HasBizAccess(v.job) and pData and pData.state == 1 end, }, { icon = "phone", label = "Make Call", - event = "Phone:Client:MakeBizCall", onSelect = function() - TriggerEvent("Phone:Client:MakeBizCall", { id = v.id }) + TriggerEvent("Phone:Client:MakeBizCall", nil, { id = v.id }) end, - groups = { v.job }, - canInteract = function(data) - if data then - local pData = GlobalState[string.format("BizPhone:%s", data.id)] - if not pData then - return true - end - end + canInteract = function() + local pData = GlobalState[("BizPhone:%s"):format(v.id)] + return HasBizAccess(v.job) and not pData end, }, { - icon = "phone", - label = "Answer Phone", + icon = "phone-volume", + label = "Dialing…", onSelect = function() - TriggerEvent("Phone:Client:AcceptBizCall", { id = v.id }) + TriggerEvent("Phone:Client:MakeBizCall", { id = v.id }) end, - groups = { v.job }, - canInteract = function(data) - if data then - local pData = GlobalState[string.format("BizPhone:%s", data.id)] - if pData and pData.state == 1 then - return true - end - end + canInteract = function() + local pData = GlobalState[("BizPhone:%s"):format(v.id)] + return HasBizAccess(v.job) and pData and pData.state > 1 and pData.state ~= 2 end, - label = function(data) - if data then - local pData = GlobalState[string.format("BizPhone:%s", data.id)] - if pData and pData.state == 1 then - return string.format("Answer Call From %s", pData.callingStr) - end + }, + { + icon = "phone-volume", + label = "On Call", + onSelect = function() + local pData = GlobalState[("BizPhone:%s"):format(v.id)] + if pData then + exports["sandbox-hud"]:Notification("inform", ("On Call: %s"):format(pData.callingStr or "Unknown")) end - return "" + end, + canInteract = function() + local pData = GlobalState[("BizPhone:%s"):format(v.id)] + return HasBizAccess(v.job) and pData and pData.state == 2 end, }, { icon = "phone", label = "Hang Up", onSelect = function() - TriggerEvent("Phone:Client:DeclineBizCall", { id = v.id }) + TriggerEvent("Phone:Client:DeclineBizCall", nil, { id = v.id }) end, - groups = { v.job }, - canInteract = function(data) - if data then - local pData = GlobalState[string.format("BizPhone:%s", data.id)] - if pData then - return true - end - end + canInteract = function() + local pData = GlobalState[("BizPhone:%s"):format(v.id)] + return HasBizAccess(v.job) and pData ~= nil end, }, { icon = "phone-slash", - label = "Mute Phone", - event = "Phone:Client:MuteBiz", + label = "Toggle Mute", onSelect = function() - TriggerEvent("Phone:Client:MuteBiz", { id = v.id }) + TriggerEvent("Phone:Client:MuteBiz", nil, { id = v.id }) end, - groups = { v.job }, - label = function(data) - if data then - local pData = GlobalState[string.format("BizPhone:%s:Muted", data.id)] - if pData then - return "Unmute Phone" - end - end - return "Mute Phone" + canInteract = function() + return HasBizAccess(v.job) end, - } + }, }) table.insert(_createdPhones, object) @@ -140,12 +119,12 @@ function CreateBizPhones() end function CleanupBizPhones() - for k, v in ipairs(_createdPhones) do - if DoesEntityExist(v) then - DeleteEntity(v) + for _, ent in ipairs(_createdPhones) do + if DoesEntityExist(ent) then + exports.ox_target:removeLocalEntity(ent) + DeleteEntity(ent) end end - _createdPhones = {} end @@ -212,7 +191,7 @@ AddEventHandler("Phone:Client:MakeBizCallConfirm", function(values, data) end end) -RegisterNetEvent("Phone:Client:Phone:AcceptBizCall", function(number) +RegisterNetEvent("Phone:Client:AcceptBizCall", function(number) if LocalPlayer.state.bizCall then exports['sandbox-hud']:InfoOverlayShow("On Call", string.format("To Number: %s", number)) exports["sandbox-sounds"]:StopOne("ringing.ogg") @@ -220,15 +199,29 @@ RegisterNetEvent("Phone:Client:Phone:AcceptBizCall", function(number) end) RegisterNetEvent("Phone:Client:Biz:Recieve", function(id, coords, radius) - if LocalPlayer.state.loggedIn and not GlobalState[string.format("BizPhone:%s:Muted", id)] then - local myCoords = GetEntityCoords(LocalPlayer.state.ped) - if #(myCoords - coords) <= 150.0 then - exports["sandbox-sounds"]:LoopLocation(string.format("bizphones-%s", id), coords, radius, "bizphone.ogg", 0.1) - SetTimeout(30000, function() - exports["sandbox-sounds"]:StopDistance(string.format("bizphones-%s", id), "bizphone.ogg") - end) - end + if not LocalPlayer.state.loggedIn or GlobalState[("BizPhone:%s:Muted"):format(id)] then return end + + -- Coerce coords into vector3 (handles table or json-string coords) + if type(coords) == 'string' then + local ok, decoded = pcall(json.decode, coords) + if ok and decoded then coords = decoded end + end + if type(coords) == 'table' then + coords = vector3(coords.x + 0.0, coords.y + 0.0, coords.z + 0.0) end + + radius = tonumber(radius) or 15.0 + + local ped = PlayerPedId() + local myCoords = GetEntityCoords(ped) + + if #(myCoords - coords) <= 150.0 then + exports["sandbox-sounds"]:LoopLocation(("bizphones-%s"):format(id), coords, radius, "bizphone.ogg", 0.1) + SetTimeout(30000, function() + exports["sandbox-sounds"]:StopDistance(("bizphones-%s"):format(id), "bizphone.ogg") + end) + end + print("BIZ RING coords type:", type(coords), coords) end) AddEventHandler("Phone:Client:DeclineBizCall", function(entityData, data) @@ -277,4 +270,4 @@ RegisterNetEvent("Phone:Client:Biz:End", function(id) LocalPlayer.state.bizCall = nil exports["sandbox-sounds"]:PlayOne("ended.ogg", 0.15) end -end) +end) \ No newline at end of file diff --git a/server/resources/[sandbox]/sandbox-phone/server/apps/phone.lua b/server/resources/[sandbox]/sandbox-phone/server/apps/phone.lua index a2c057add..652cba236 100644 --- a/server/resources/[sandbox]/sandbox-phone/server/apps/phone.lua +++ b/server/resources/[sandbox]/sandbox-phone/server/apps/phone.lua @@ -1,6 +1,17 @@ local _calls = {} local _bizCallHandlers = {} -- The people who answered the business call +local function normalizePhoneNumber(num) + if not num then return nil end + -- keep it consistent with your generator/format (you use ###-###-####) + return tostring(num) +end + +local function getBizIdFromNumber(number) + number = normalizePhoneNumber(number) + return number and _bizPhoneNumbersCheck[number] or nil +end + exports("CallEnd", function(source, business) if business then if _bizPhones[business] and _bizPhones[business].call then @@ -747,4 +758,4 @@ AddEventHandler("Phone:Server:RegisterCallbacks", function() cb(false) end end) -end) +end) \ No newline at end of file diff --git a/server/resources/[sandbox]/sandbox-phone/server/bizphone.lua b/server/resources/[sandbox]/sandbox-phone/server/bizphone.lua index 80b89939a..d271fe0a5 100644 --- a/server/resources/[sandbox]/sandbox-phone/server/bizphone.lua +++ b/server/resources/[sandbox]/sandbox-phone/server/bizphone.lua @@ -240,7 +240,7 @@ function InitBizPhones() for k, v in ipairs(bP) do _bizPhoneNumbers[v.id] = v.number _bizPhoneNumbersCheck[v.number] = v.id - GlobalState[string.format("BizPhone:%s:Muted", v.id)] = v.muted + GlobalState[("BizPhone:%s:Muted"):format(v.id)] = (v.muted == 1 or v.muted == true) end local trans = {} @@ -269,4 +269,4 @@ function InitBizPhones() MySQL.transaction.await(trans) GlobalState.BizPhones = _bizPhones -end +end \ No newline at end of file diff --git a/server/resources/[sandbox]/sandbox-sounds/client/sounds.lua b/server/resources/[sandbox]/sandbox-sounds/client/sounds.lua index 47fcf0823..f58916efb 100644 --- a/server/resources/[sandbox]/sandbox-sounds/client/sounds.lua +++ b/server/resources/[sandbox]/sandbox-sounds/client/sounds.lua @@ -7,6 +7,29 @@ RegisterNUICallback("SoundEnd", function(data, cb) end end) +local function toVec3(v) + if not v then return nil end + + -- if someone sent coords as json string + if type(v) == 'string' then + local ok, decoded = pcall(json.decode, v) + if ok and decoded then + v = decoded + end + end + + -- if someone sent coords as table {x=..., y=..., z=...} + if type(v) == 'table' then + local x, y, z = v.x, v.y, v.z + if x and y and z then + return vector3(tonumber(x) or 0.0, tonumber(y) or 0.0, tonumber(z) or 0.0) + end + end + + -- if already a vector3, just return it + return v +end + exports("PlayOne", function(soundFile, soundVolume) exports['sandbox-base']:LoggerTrace("Sounds", ("^2Playing Sound %s On Client Only^7"):format(soundFile)) _sounds[LocalPlayer.state.ID] = _sounds[LocalPlayer.state.ID] or {} @@ -63,13 +86,35 @@ exports("LoopDistance", function(maxDistance, soundFile, soundVolume) }) end) -exports("LoopLocation", function(location, maxDistance, soundFile, soundVolume) - exports["sandbox-base"]:ServerCallback("Sounds:Loop:Location", { - location = location, - maxDistance = maxDistance, - soundFile = soundFile, - soundVolume = soundVolume, - }) +exports("LoopLocation", function(a, b, c, d, e) + local key, location, maxDistance, soundFile, soundVolume + + -- LoopLocation(key, location, maxDistance, file, vol) + if type(a) == "string" then + key = a + location = b + maxDistance = c + soundFile = d + soundVolume = e + else + -- LoopLocation(location, maxDistance, file, vol) + key = nil + location = a + maxDistance = b + soundFile = c + soundVolume = d + end + + local loc = toVec3(location) + if not loc then return end + + exports["sandbox-base"]:ServerCallback("Sounds:Loop:Location", { + playerNetId = key, -- ✅ use key + location = { x = loc.x, y = loc.y, z = loc.z }, + maxDistance = tonumber(maxDistance) or 0.0, + soundFile = soundFile, + soundVolume = tonumber(soundVolume) or 0.0, + }) end) exports("StopOne", function(soundFile) @@ -85,15 +130,17 @@ exports("StopOne", function(soundFile) end) exports("StopDistance", function(pNet, soundFile) - exports["sandbox-base"]:ServerCallback("Sounds:Stop:Distance", { - soundFile = soundFile, - }) + exports["sandbox-base"]:ServerCallback("Sounds:Stop:Distance", { + playerNetId = pNet, + soundFile = soundFile, + }) end) exports("StopLocation", function(pNet, soundFile) - exports["sandbox-base"]:ServerCallback("Sounds:Stop:Distance", { - soundFile = soundFile, - }) + exports["sandbox-base"]:ServerCallback("Sounds:Stop:Distance", { + playerNetId = pNet, + soundFile = soundFile, + }) end) exports("FadeOne", function(soundFile) @@ -308,49 +355,41 @@ function DoLoopDistance(playerNetId, maxDistance, soundFile, soundVolume) end function DoLoopLocation(playerNetId, location, maxDistance, soundFile, soundVolume) - exports['sandbox-base']:LoggerTrace( - ("^2Looping Sound %s Per Request From %s at location %s For Distance %s^7"):format( - soundFile, - playerNetId, - json.encode(location), - maxDistance - ) - ) - local distIs = #(GetEntityCoords(LocalPlayer.state.ped) - location) - local vol = soundVolume * (1.0 - (distIs / maxDistance)) - if distIs > maxDistance then - vol = 0 - end - - _sounds[playerNetId] = _sounds[playerNetId] or {} - _sounds[playerNetId][soundFile] = { - file = soundFile, - volume = soundVolume, - distance = maxDistance, - } - SendNUIMessage({ - action = "loopSound", - source = playerNetId, - file = soundFile, - volume = vol, - }) - - CreateThread(function() - while _sounds[playerNetId] ~= nil and _sounds[playerNetId][soundFile] ~= nil do - local distIs = #(GetEntityCoords(LocalPlayer.state.ped) - location) - vol = soundVolume * (1.0 - (distIs / maxDistance)) - if distIs > maxDistance or not LocalPlayer.state.loggedIn then - vol = 0 - end - SendNUIMessage({ - action = "updateVol", - source = playerNetId, - file = soundFile, - volume = vol, - }) - Wait(100) - end - end) + location = toVec3(location) + maxDistance = tonumber(maxDistance) or 0.0 + soundVolume = tonumber(soundVolume) or 0.0 + + if not location then return end + + exports['sandbox-base']:LoggerTrace( + ("^2Looping Sound %s Per Request From %s at location %s For Distance %s^7"):format( + soundFile, + playerNetId, + json.encode(location), + maxDistance + ) + ) + + local ped = PlayerPedId() + local distIs = #(GetEntityCoords(ped) - location) + local vol = soundVolume * (1.0 - (distIs / maxDistance)) + if distIs > maxDistance then vol = 0 end + + _sounds[playerNetId] = _sounds[playerNetId] or {} + _sounds[playerNetId][soundFile] = { file = soundFile, volume = soundVolume, distance = maxDistance } + + SendNUIMessage({ action = "loopSound", source = playerNetId, file = soundFile, volume = vol }) + + CreateThread(function() + while _sounds[playerNetId] and _sounds[playerNetId][soundFile] do + local distIs2 = #(GetEntityCoords(PlayerPedId()) - location) + local vol2 = soundVolume * (1.0 - (distIs2 / maxDistance)) + if distIs2 > maxDistance or not LocalPlayer.state.loggedIn then vol2 = 0 end + + SendNUIMessage({ action = "updateVol", source = playerNetId, file = soundFile, volume = vol2 }) + Wait(100) + end + end) end function DoStopDistance(playerNetId, soundFile) @@ -366,6 +405,19 @@ function DoStopDistance(playerNetId, soundFile) end end +RegisterNetEvent("Sounds:Client:DoLoopLocation", function(playerNetId, location, maxDistance, soundFile, soundVolume) + -- convert location to vector3 + if type(location) == 'string' then + local ok, decoded = pcall(json.decode, location) + if ok and decoded then location = decoded end + end + if type(location) == 'table' then + location = vector3(tonumber(location.x) or 0.0, tonumber(location.y) or 0.0, tonumber(location.z) or 0.0) + end + + DoLoopLocation(playerNetId, location, tonumber(maxDistance) or 0.0, soundFile, tonumber(soundVolume) or 0.0) +end) + RegisterNetEvent("Sounds:Client:Play:One", function(playerNetId, soundFile, soundVolume) DoPlayDistance(playerNetId, soundFile, soundVolume) end) diff --git a/server/resources/[sandbox]/sandbox-sounds/server/sounds.lua b/server/resources/[sandbox]/sandbox-sounds/server/sounds.lua index f7f5de785..7800a7940 100644 --- a/server/resources/[sandbox]/sandbox-sounds/server/sounds.lua +++ b/server/resources/[sandbox]/sandbox-sounds/server/sounds.lua @@ -1,139 +1,177 @@ AddEventHandler('onResourceStart', function(resource) - if resource == GetCurrentResourceName() then - Wait(1000) - RegisterCallbacks() - end + if resource == GetCurrentResourceName() then + Wait(1000) + RegisterCallbacks() + end end) exports("PlayOne", function(clientNetId, soundFile, soundVolume) - TriggerClientEvent("Sounds:Client:Play:One", clientNetId, soundFile, soundVolume) + TriggerClientEvent("Sounds:Client:Play:One", clientNetId, soundFile, soundVolume) end) exports("PlayDistance", function(clientNetId, maxDistance, soundFile, soundVolume) - TriggerClientEvent("Sounds:Client:Play:Distance", -1, clientNetId, maxDistance, soundFile, soundVolume) + TriggerClientEvent("Sounds:Client:Play:Distance", -1, clientNetId, maxDistance, soundFile, soundVolume) end) -exports("PlayLocation", function(clientNetId, Location, maxDistance, soundFile, soundVolume) - TriggerClientEvent( - "Sounds:Client:Play:Location", - -1, - clientNetId, - Location, - maxDistance, - soundFile, - soundVolume - ) +exports("PlayLocation", function(clientNetId, location, maxDistance, soundFile, soundVolume) + TriggerClientEvent( + "Sounds:Client:Play:Location", + -1, + clientNetId, + location, + maxDistance, + soundFile, + soundVolume + ) end) exports("PlayAll", function(clientNetId, soundFile, soundVolume) - TriggerClientEvent("Sounds:Client:Play:One", -1, clientNetId, soundFile, soundVolume) + TriggerClientEvent("Sounds:Client:Play:One", -1, clientNetId, soundFile, soundVolume) end) exports("PlayJob", function(clientNetId, soundFile, job, soundVolume) - for k, v in ipairs(GetPlayers()) do - local myDuty = Player(v).state.onDuty - if myDuty and job[myDuty] then - TriggerClientEvent( - "Sounds:Client:Play:One", - v, - clientNetId, - soundFile, - soundVolume - ) - end - end + for _, src in ipairs(GetPlayers()) do + local duty = Player(src).state.onDuty + if duty and job[duty] then + TriggerClientEvent( + "Sounds:Client:Play:One", + src, + clientNetId, + soundFile, + soundVolume + ) + end + end end) exports("LoopOne", function(clientNetId, soundFile, soundVolume) - TriggerClientEvent("Sounds:Client:Loop:One", clientNetId, soundFile, soundVolume) + TriggerClientEvent("Sounds:Client:Loop:One", clientNetId, soundFile, soundVolume) end) exports("LoopDistance", function(clientNetId, maxDistance, soundFile, soundVolume) - TriggerClientEvent("Sounds:Client:Loop:Distance", -1, clientNetId, maxDistance, soundFile, soundVolume) + TriggerClientEvent("Sounds:Client:Loop:Distance", -1, clientNetId, maxDistance, soundFile, soundVolume) end) -exports("LoopLocation", function(clientNetId, Location, maxDistance, soundFile, soundVolume) - TriggerClientEvent( - "Sounds:Client:Loop:Location", - -1, - clientNetId, - Location, - maxDistance, - soundFile, - soundVolume - ) +exports("LoopLocation", function(clientNetId, location, maxDistance, soundFile, soundVolume) + TriggerClientEvent( + "Sounds:Client:Loop:Location", + -1, + clientNetId, + location, + maxDistance, + soundFile, + soundVolume + ) end) exports("StopOne", function(clientNetId, soundFile) - TriggerClientEvent("Sounds:Client:Stop:One", clientNetId, soundFile) + TriggerClientEvent("Sounds:Client:Stop:One", clientNetId, soundFile) end) exports("StopDistance", function(clientNetId, soundFile) - TriggerClientEvent("Sounds:Client:Stop:Distance", -1, clientNetId, soundFile) + TriggerClientEvent("Sounds:Client:Stop:Distance", -1, clientNetId, soundFile) end) -exports("StopLocation", function(clientNetId, location, soundFile) - TriggerClientEvent("Sounds:Client:Stop:Distance", -1, clientNetId, soundFile) +exports("StopLocation", function(clientNetId, soundFile) + TriggerClientEvent("Sounds:Client:Stop:Distance", -1, clientNetId, soundFile) end) function RegisterCallbacks() - exports["sandbox-base"]:RegisterServerCallback("Sounds:Play:Distance", function(source, data, cb) - exports["sandbox-sounds"]:PlayDistance(source, data.maxDistance, data.soundFile, data.soundVolume) - end) - exports["sandbox-base"]:RegisterServerCallback("Sounds:Play:Location", function(source, data, cb) - exports["sandbox-sounds"]:PlayLocation(source, data.location, data.maxDistance, data.soundFile, data.soundVolume) - end) - - exports["sandbox-base"]:RegisterServerCallback("Sounds:Loop:Distance", function(source, data, cb) - exports["sandbox-sounds"]:LoopDistance(source, data.maxDistance, data.soundFile, data.soundVolume) - end) - - exports["sandbox-base"]:RegisterServerCallback("Sounds:Loop:Location", function(source, data, cb) - exports["sandbox-sounds"]:LoopLocation(source, data.location, data.maxDistance, data.soundFile, data.soundVolume) - end) - - exports["sandbox-base"]:RegisterServerCallback("Sounds:Stop:Distance", function(source, data, cb) - exports["sandbox-sounds"]:StopDistance(source, data.soundFile) - end) + exports["sandbox-base"]:RegisterServerCallback("Sounds:Play:Distance", function(source, data, cb) + exports["sandbox-sounds"]:PlayDistance( + source, + data.maxDistance, + data.soundFile, + data.soundVolume + ) + cb(true) + end) + + exports["sandbox-base"]:RegisterServerCallback("Sounds:Play:Location", function(source, data, cb) + exports["sandbox-sounds"]:PlayLocation( + source, + data.location, + data.maxDistance, + data.soundFile, + data.soundVolume + ) + cb(true) + end) + + exports["sandbox-base"]:RegisterServerCallback("Sounds:Loop:Distance", function(source, data, cb) + exports["sandbox-sounds"]:LoopDistance( + source, + data.maxDistance, + data.soundFile, + data.soundVolume + ) + cb(true) + end) + + exports["sandbox-base"]:RegisterServerCallback("Sounds:Loop:Location", function(source, data, cb) + -- normalize location payload + local loc = data.location + if type(loc) == "vector3" then + loc = { x = loc.x, y = loc.y, z = loc.z } + end + + TriggerClientEvent( + "Sounds:Client:DoLoopLocation", + -1, + data.playerNetId or source, + loc, + data.maxDistance, + data.soundFile, + data.soundVolume + ) + + cb(true) + end) + + exports["sandbox-base"]:RegisterServerCallback("Sounds:Stop:Distance", function(source, data, cb) + local key = data.playerNetId or source + TriggerClientEvent("Sounds:Client:Stop:Distance", -1, key, data.soundFile) + cb(true) + end) end AddEventHandler("Characters:Server:PlayerLoggedOut", function(source) - TriggerClientEvent("Sounds:Client:Stop:All", -1, source) + TriggerClientEvent("Sounds:Client:Stop:All", -1, source) end) AddEventHandler("Characters:Server:PlayerDropped", function(source) - TriggerClientEvent("Sounds:Client:Stop:All", -1, source) + TriggerClientEvent("Sounds:Client:Stop:All", -1, source) end) AddEventHandler("Sounds:Server:Play:One", function(soundFile, soundVolume) - exports["sandbox-sounds"]:PlayOne(soundFile, soundVolume) + exports["sandbox-sounds"]:PlayOne(source, soundFile, soundVolume) end) AddEventHandler("Sounds:Server:Play:Distance", function(playerNetId, maxDistance, soundFile, soundVolume) - exports["sandbox-sounds"]:PlayDistance(playerNetId, maxDistance, soundFile, soundVolume) + exports["sandbox-sounds"]:PlayDistance(playerNetId, maxDistance, soundFile, soundVolume) end) AddEventHandler("Sounds:Server:Play:All", function(playerNetId, soundFile, soundVolume) - exports["sandbox-sounds"]:PlayAll(playerNetId, soundFile, soundVolume) + exports["sandbox-sounds"]:PlayAll(playerNetId, soundFile, soundVolume) end) AddEventHandler("Sounds:Server:Play:Job", function(playerNetId, soundFile, job, soundVolume) - exports["sandbox-sounds"]:PlayJob(playerNetId, soundFile, job, soundVolume) + exports["sandbox-sounds"]:PlayJob(playerNetId, soundFile, job, soundVolume) end) AddEventHandler("Sounds:Server:Loop:One", function(soundFile, soundVolume) - exports["sandbox-sounds"]:LoopOne(soundFile, soundVolume) + exports["sandbox-sounds"]:LoopOne(source, soundFile, soundVolume) end) AddEventHandler("Sounds:Server:Loop:Distance", function(playerNetId, maxDistance, soundFile, soundVolume) - exports["sandbox-sounds"]:LoopDistance(playerNetId, maxDistance, soundFile, soundVolume) + exports["sandbox-sounds"]:LoopDistance(playerNetId, maxDistance, soundFile, soundVolume) end) AddEventHandler("Sounds:Server:Stop:One", function(soundFile) - exports["sandbox-sounds"]:StopOne(soundFile) + exports["sandbox-sounds"]:StopOne(source, soundFile) end) AddEventHandler("Sounds:Server:Stop:Distance", function(playerNetId, soundFile) - exports["sandbox-sounds"]:StopDistance(playerNetId, soundFile) + exports["sandbox-sounds"]:StopDistance(playerNetId, soundFile) end)