Files
community_bridge/lib/utility/shared/rebound_entities.lua
T

324 lines
10 KiB
Lua
Raw Normal View History

2025-02-05 17:42:50 -06:00
local Entities = {}
local isServer = IsDuplicityVersion()
local registeredFunctions = {}
ReboundEntities = {}
function ReboundEntities.AddFunction(func)
assert(func, "Func is nil")
table.insert(registeredFunctions, func)
return #registeredFunctions
end
function ReboundEntities.RemoveFunction(id)
assert(id and registeredFunctions[id], "Invalid ID")
2025-02-05 17:42:50 -06:00
registeredFunctions[id] = false
end
2025-02-15 21:16:44 -06:00
function FireFunctions(...)
for _, func in pairs(registeredFunctions) do
2025-02-15 21:16:44 -06:00
func(...)
2025-02-05 17:42:50 -06:00
end
end
function ReboundEntities.Register(entityData)
assert(entityData and entityData.position, "Invalid entity data")
entityData.id = entityData.id or Ids.CreateUniqueId(Entities)
2025-02-05 17:42:50 -06:00
entityData.isServer = isServer
setmetatable(entityData, { __tostring = function() return entityData.id end })
Entities[entityData.id] = entityData
2025-02-05 17:42:50 -06:00
FireFunctions(entityData)
return entityData
end
local function Unregister(id)
Entities[id] = nil
end
function ReboundEntities.GetSyncData(entityData, key)
return entityData[key]
end
function ReboundEntities.GetAll()
return Entities
end
function ReboundEntities.GetById(id)
return Entities[tostring(id)]
2025-02-05 17:42:50 -06:00
end
function ReboundEntities.GetByModel(model)
local entities = {}
for _, entity in pairs(Entities) do
if entity.model == model then
table.insert(entities, entity)
2025-02-05 17:42:50 -06:00
end
end
return entities
end
function ReboundEntities.GetClosest(pos)
local closest, closestDist = nil, 9999
for _, entity in pairs(Entities) do
local dist = #(pos - entity.position)
2025-02-05 17:42:50 -06:00
if dist < closestDist then
closest, closestDist = entity, dist
2025-02-05 17:42:50 -06:00
end
end
return closest
end
function ReboundEntities.GetWithinRadius(pos, radius)
local entities = {}
for _, entity in pairs(Entities) do
if #(pos - entity.position) < radius then
table.insert(entities, entity)
2025-02-05 17:42:50 -06:00
end
end
return entities
end
function ReboundEntities.SetOnSyncKeyChange(entityData, cb)
local data = ReboundEntities.GetById(entityData.id or entityData)
2025-02-05 17:42:50 -06:00
assert(data, "Entity not found")
data.onSyncKeyChange = cb
end
exports('ReboundEntities', ReboundEntities)
if not isServer then goto client end
2025-02-05 17:42:50 -06:00
function ReboundEntities.Create(entityData, src)
local entity = ReboundEntities.Register(entityData)
assert(entity and entity.position, "Invalid entity data")
2025-02-22 14:27:04 -06:00
entity.rotation = entity.rotation or vector3(0, 0, entityData.heading or 0)
TriggerClientEvent(GetCurrentResourceName() .. ":client:CreateReboundEntity", src or -1, entity)
2025-02-05 17:42:50 -06:00
return entity
end
2025-02-15 21:16:44 -06:00
2025-02-05 17:42:50 -06:00
function ReboundEntities.SetCheckRestricted(entityData, cb)
assert(type(cb) == "function", "Check restricted is not a function")
entityData.restricted = cb
end
2025-02-15 21:16:44 -06:00
2025-02-05 17:42:50 -06:00
function ReboundEntities.CheckRestricted(src, entityData)
return entityData.restricted and entityData.restricted(tonumber(src), entityData) or false
2025-02-05 17:42:50 -06:00
end
function ReboundEntities.Refresh(src)
TriggerClientEvent(GetCurrentResourceName() .. ":client:CreateReboundEntities", tonumber(src), ReboundEntities.GetAccessibleList(src))
2025-02-05 17:42:50 -06:00
end
function ReboundEntities.Delete(id)
Unregister(id)
TriggerClientEvent(GetCurrentResourceName() .. ":client:DeleteReboundEntity", -1, id)
2025-02-05 17:42:50 -06:00
end
2025-02-15 21:16:44 -06:00
function ReboundEntities.DeleteMultiple(entityDatas)
local ids = {}
for _, data in pairs(entityDatas) do
Unregister(data.id)
table.insert(ids, data.id)
end
TriggerClientEvent(GetCurrentResourceName() .. ":client:DeleteReboundEntities", -1, ids)
end
2025-02-05 17:42:50 -06:00
function ReboundEntities.CreateMultiple(entityDatas, src, restricted)
local _entityDatas = {}
for _, data in pairs(entityDatas) do
local entity = ReboundEntities.Register(data)
assert(entity and entity.position, "Invalid entity data")
2025-02-05 17:42:50 -06:00
entity.rotation = entity.rotation or vector3(0, 0, 0)
if restricted then ReboundEntities.SetCheckRestricted(entity, restricted) end
2025-02-05 17:42:50 -06:00
if not ReboundEntities.CheckRestricted(src, entity) then
_entityDatas[entity.id] = entity
end
end
TriggerClientEvent(GetCurrentResourceName() .. ":client:CreateReboundEntities", src or -1, _entityDatas)
2025-02-05 17:42:50 -06:00
return _entityDatas
end
function ReboundEntities.SetSyncData(entityData, key, value)
entityData[key] = value
if entityData.onSyncKeyChange then
entityData.onSyncKeyChange(entityData, key, value)
end
TriggerClientEvent(GetCurrentResourceName() .. ":client:SetReboundSyncData", -1, entityData.id, key, value)
2025-02-05 17:42:50 -06:00
end
function ReboundEntities.GetAccessibleList(src)
local list = {}
for _, data in pairs(ReboundEntities.GetAll()) do
2025-02-05 17:42:50 -06:00
if not ReboundEntities.CheckRestricted(src, data) then
list[data.id] = data
end
end
return list
end
2025-02-10 01:01:32 -06:00
RegisterNetEvent("playerJoining", function()
ReboundEntities.Refresh(source)
2025-02-05 17:42:50 -06:00
end)
AddEventHandler('onResourceStart', function(resource)
2025-04-29 16:22:46 -04:00
if resource ~= GetCurrentResourceName() then return end
Wait(1000)
for _, src in pairs(GetPlayers()) do
ReboundEntities.Refresh(src)
2025-02-05 17:42:50 -06:00
end
end)
::client::
if isServer then return ReboundEntities end
2025-02-05 17:42:50 -06:00
function ReboundEntities.LoadModel(model)
assert(model, "Model is nil")
2025-04-23 14:10:19 -05:00
model = type(model) == "number" and model or GetHashKey(model) -- Corrected to GetHashKey
2025-02-05 17:42:50 -06:00
RequestModel(model)
for i = 1, 100 do
if HasModelLoaded(model) then return model end
2025-02-05 17:42:50 -06:00
Wait(100)
end
error(string.format("Failed to load model %s", model))
2025-02-05 17:42:50 -06:00
end
function ReboundEntities.Spawn(entityData)
local model = entityData.model
local position = entityData.position
assert(position, "Position is nil")
local rotation = entityData.rotation or vector3(0, 0, 0)
local entity = model and CreateObject(ReboundEntities.LoadModel(model), position.x, position.y, position.z, false, false, false)
if entity then SetEntityRotation(entity, rotation.x, rotation.y, rotation.z) end
if entityData.onSpawn then entity = entityData.onSpawn(entityData, entity) or entity end
2025-02-05 17:42:50 -06:00
return entity, true
end
function ReboundEntities.SetOnSpawn(id, cb)
local entity = ReboundEntities.GetById(tostring(id))
2025-02-05 17:42:50 -06:00
assert(entity, "Entity not found")
entity.onSpawn = cb
return true
end
function ReboundEntities.Despawn(entityData)
local entity = entityData.entity
if entityData.onDespawn then entityData.onDespawn(entityData, entity) end
if entity and DoesEntityExist(entity) then DeleteEntity(entity) end
2025-02-05 17:42:50 -06:00
return nil, nil
end
function ReboundEntities.SetOnDespawn(id, cb)
local entity = ReboundEntities.GetById(tostring(id))
2025-02-05 17:42:50 -06:00
assert(entity, "Entity not found")
entity.onDespawn = cb
return true
end
local spawnLoopRunning = false
function ReboundEntities.SpawnLoop(distanceToCheck, waitTime)
if spawnLoopRunning then return end
spawnLoopRunning = true
distanceToCheck = distanceToCheck or 50
waitTime = waitTime or 2500
CreateThread(function()
while spawnLoopRunning do
for _, entity in pairs(Entities) do
local pos = GetEntityCoords(PlayerPedId())
2025-02-15 21:16:44 -06:00
local position = vector3(entity.position.x, entity.position.y, entity.position.z)
local dist = #(pos - position)
if dist <= distanceToCheck and not entity.entity then
entity.entity, entity.inRange = ReboundEntities.Spawn(entity)
elseif dist > distanceToCheck and entity.entity then
entity.entity, entity.inRange = ReboundEntities.Despawn(entity)
2025-02-05 17:42:50 -06:00
end
end
Wait(waitTime)
end
end)
end
function ReboundEntities.GetByEntity(entity)
for _, data in pairs(Entities) do
if data.entity == entity then return data end
2025-02-05 17:42:50 -06:00
end
end
function ReboundEntities.CreateClient(entityData)
local entity = ReboundEntities.Register(entityData)
if entity then ReboundEntities.SpawnLoop() end
2025-02-05 17:42:50 -06:00
return entity
end
function ReboundEntities.DeleteClient(id)
local entityData = ReboundEntities.GetById(tostring(id))
assert(not entityData.isServer, "Cannot delete server entity from client")
if entityData.entity then ReboundEntities.Despawn(entityData) end
2025-02-05 17:42:50 -06:00
Unregister(id)
return true
end
function ReboundEntities.CreateMultipleClient(entityDatas)
local _entityDatas = {}
for _, data in pairs(entityDatas) do
local entityData = ReboundEntities.CreateClient(data)
_entityDatas[entityData.id] = entityData
2025-02-05 17:42:50 -06:00
end
return _entityDatas
end
function ReboundEntities.DeleteMultipleClient(ids)
for _, id in pairs(ids) do
ReboundEntities.DeleteClient(id)
2025-02-05 17:42:50 -06:00
end
end
local function DeleteFromServer(id)
local entityData = ReboundEntities.GetById(tostring(id))
if entityData then
entityData.isServer = nil
ReboundEntities.DeleteClient(id)
end
2025-02-05 17:42:50 -06:00
end
local function DeleteMultipleFromServer(ids)
for _, id in pairs(ids) do
DeleteFromServer(id)
2025-02-05 17:42:50 -06:00
end
end
RegisterNetEvent(GetCurrentResourceName() .. ":client:CreateReboundEntity", function(entityData)
2025-02-05 17:42:50 -06:00
ReboundEntities.CreateClient(entityData)
end)
RegisterNetEvent(GetCurrentResourceName() .. ":client:DeleteReboundEntity", function(id)
2025-02-05 17:42:50 -06:00
DeleteFromServer(id)
end)
RegisterNetEvent(GetCurrentResourceName() .. ":client:CreateReboundEntities", function(entityDatas)
2025-02-05 17:42:50 -06:00
ReboundEntities.CreateMultipleClient(entityDatas)
end)
RegisterNetEvent(GetCurrentResourceName() .. ":client:DeleteReboundEntities", function(ids)
2025-02-15 21:16:44 -06:00
ReboundEntities.DeleteMultipleClient(ids)
2025-02-05 17:42:50 -06:00
end)
RegisterNetEvent(GetCurrentResourceName() .. ":client:SetReboundSyncData", function(id, key, value)
2025-02-05 17:42:50 -06:00
local entityData = ReboundEntities.GetById(id)
2025-04-29 16:22:46 -04:00
if not entityData then return end
entityData[key] = value
if entityData.onSyncKeyChange then
entityData.onSyncKeyChange(entityData, key, value)
2025-02-05 17:42:50 -06:00
end
end)
AddEventHandler('onResourceStop', function(resource)
2025-04-29 16:22:46 -04:00
if resource ~= GetCurrentResourceName() then return end
spawnLoopRunning = false
for _, entity in pairs(Entities) do
if entity.entity then DeleteEntity(tonumber(entity.entity)) end
2025-02-05 17:42:50 -06:00
end
end)
return ReboundEntities