1
0
Fork 0
forked from Simnation/Main
Main/resources/[carscripts]/community_bridge/lib/utility/shared/rebound_entities.lua
2025-08-06 16:37:06 +02:00

324 lines
10 KiB
Lua

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")
registeredFunctions[id] = false
end
function FireFunctions(...)
for _, func in pairs(registeredFunctions) do
func(...)
end
end
function ReboundEntities.Register(entityData)
assert(entityData and entityData.position, "Invalid entity data")
entityData.id = entityData.id or Ids.CreateUniqueId(Entities)
entityData.isServer = isServer
setmetatable(entityData, { __tostring = function() return entityData.id end })
Entities[entityData.id] = entityData
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)]
end
function ReboundEntities.GetByModel(model)
local entities = {}
for _, entity in pairs(Entities) do
if entity.model == model then
table.insert(entities, entity)
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)
if dist < closestDist then
closest, closestDist = entity, dist
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)
end
end
return entities
end
function ReboundEntities.SetOnSyncKeyChange(entityData, cb)
local data = ReboundEntities.GetById(entityData.id or entityData)
assert(data, "Entity not found")
data.onSyncKeyChange = cb
end
exports('ReboundEntities', ReboundEntities)
if not isServer then goto client end
function ReboundEntities.Create(entityData, src)
local entity = ReboundEntities.Register(entityData)
assert(entity and entity.position, "Invalid entity data")
entity.rotation = entity.rotation or vector3(0, 0, entityData.heading or 0)
TriggerClientEvent(GetCurrentResourceName() .. ":client:CreateReboundEntity", src or -1, entity)
return entity
end
function ReboundEntities.SetCheckRestricted(entityData, cb)
assert(type(cb) == "function", "Check restricted is not a function")
entityData.restricted = cb
end
function ReboundEntities.CheckRestricted(src, entityData)
return entityData.restricted and entityData.restricted(tonumber(src), entityData) or false
end
function ReboundEntities.Refresh(src)
TriggerClientEvent(GetCurrentResourceName() .. ":client:CreateReboundEntities", tonumber(src), ReboundEntities.GetAccessibleList(src))
end
function ReboundEntities.Delete(id)
Unregister(id)
TriggerClientEvent(GetCurrentResourceName() .. ":client:DeleteReboundEntity", -1, id)
end
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
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")
entity.rotation = entity.rotation or vector3(0, 0, 0)
if restricted then ReboundEntities.SetCheckRestricted(entity, restricted) end
if not ReboundEntities.CheckRestricted(src, entity) then
_entityDatas[entity.id] = entity
end
end
TriggerClientEvent(GetCurrentResourceName() .. ":client:CreateReboundEntities", src or -1, _entityDatas)
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)
end
function ReboundEntities.GetAccessibleList(src)
local list = {}
for _, data in pairs(ReboundEntities.GetAll()) do
if not ReboundEntities.CheckRestricted(src, data) then
list[data.id] = data
end
end
return list
end
RegisterNetEvent("playerJoining", function()
ReboundEntities.Refresh(source)
end)
AddEventHandler('onResourceStart', function(resource)
if resource ~= GetCurrentResourceName() then return end
Wait(1000)
for _, src in pairs(GetPlayers()) do
ReboundEntities.Refresh(src)
end
end)
::client::
if isServer then return ReboundEntities end
function ReboundEntities.LoadModel(model)
assert(model, "Model is nil")
model = type(model) == "number" and model or GetHashKey(model) -- Corrected to GetHashKey
RequestModel(model)
for i = 1, 100 do
if HasModelLoaded(model) then return model end
Wait(100)
end
error(string.format("Failed to load model %s", model))
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
return entity, true
end
function ReboundEntities.SetOnSpawn(id, cb)
local entity = ReboundEntities.GetById(tostring(id))
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
return nil, nil
end
function ReboundEntities.SetOnDespawn(id, cb)
local entity = ReboundEntities.GetById(tostring(id))
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())
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)
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
end
end
function ReboundEntities.CreateClient(entityData)
local entity = ReboundEntities.Register(entityData)
if entity then ReboundEntities.SpawnLoop() end
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
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
end
return _entityDatas
end
function ReboundEntities.DeleteMultipleClient(ids)
for _, id in pairs(ids) do
ReboundEntities.DeleteClient(id)
end
end
local function DeleteFromServer(id)
local entityData = ReboundEntities.GetById(tostring(id))
if entityData then
entityData.isServer = nil
ReboundEntities.DeleteClient(id)
end
end
local function DeleteMultipleFromServer(ids)
for _, id in pairs(ids) do
DeleteFromServer(id)
end
end
RegisterNetEvent(GetCurrentResourceName() .. ":client:CreateReboundEntity", function(entityData)
ReboundEntities.CreateClient(entityData)
end)
RegisterNetEvent(GetCurrentResourceName() .. ":client:DeleteReboundEntity", function(id)
DeleteFromServer(id)
end)
RegisterNetEvent(GetCurrentResourceName() .. ":client:CreateReboundEntities", function(entityDatas)
ReboundEntities.CreateMultipleClient(entityDatas)
end)
RegisterNetEvent(GetCurrentResourceName() .. ":client:DeleteReboundEntities", function(ids)
ReboundEntities.DeleteMultipleClient(ids)
end)
RegisterNetEvent(GetCurrentResourceName() .. ":client:SetReboundSyncData", function(id, key, value)
local entityData = ReboundEntities.GetById(id)
if not entityData then return end
entityData[key] = value
if entityData.onSyncKeyChange then
entityData.onSyncKeyChange(entityData, key, value)
end
end)
AddEventHandler('onResourceStop', function(resource)
if resource ~= GetCurrentResourceName() then return end
spawnLoopRunning = false
for _, entity in pairs(Entities) do
if entity.entity then DeleteEntity(tonumber(entity.entity)) end
end
end)
return ReboundEntities