1
0
Fork 0
forked from Simnation/Main
This commit is contained in:
Nordi98 2025-08-12 16:56:50 +02:00
parent 9178871ecd
commit 640cdd069b
9 changed files with 583 additions and 269 deletions

View file

@ -1,4 +1,5 @@
local NextId = 1
local Entities = {}
UtilityNet = UtilityNet or {}
@ -10,24 +11,27 @@ UtilityNet = UtilityNet or {}
-- }
UtilityNet.CreateEntity = function(model, coords, options, callId)
options = options or {}
local hashmodel = nil
--#region Checks
if not model or (type(model) ~= "string" and type(model) ~= "number") then
error("Invalid model, got "..type(model).." expected string or number", 0)
else
if type(model) == "string" then
model = GetHashKey(model)
hashmodel = GetHashKey(model)
else
hashmodel = model
end
end
if not coords or type(coords) ~= "vector3" then
error("Invalid coords, got "..type(coords).." expected vector3", 0)
end
options = options or {}
--#endregion
--#region Event
TriggerEvent("Utility:Net:EntityCreating", model, coords, options)
TriggerEvent("Utility:Net:EntityCreating", hashmodel, coords, options)
-- EntityCreating event can be canceled, in that case we dont create the entity
if WasEventCanceled() then
@ -35,29 +39,27 @@ UtilityNet.CreateEntity = function(model, coords, options, callId)
end
--#endregion
local entities = GlobalState.Entities
local slice = GetSliceFromCoords(coords)
local object = {
id = NextId,
model = model,
model = options.abstract and model or hashmodel,
coords = coords,
slice = slice,
options = options,
createdBy = options.resource or GetInvokingResource(),
createdBy = options.createdBy or GetInvokingResource(),
}
if not entities[slice] then
entities[slice] = {}
if not Entities[slice] then
Entities[slice] = {}
end
entities[slice][object.id] = object
GlobalState.Entities = entities
Entities[slice][object.id] = object
RegisterEntityState(object.id)
NextId = NextId + 1
TriggerLatentClientEvent("Utility:Net:EntityCreated", -1, 5120, callId, object.id)
TriggerLatentClientEvent("Utility:Net:EntityCreated", -1, 5120, callId, object)
return object.id
end
@ -85,103 +87,32 @@ UtilityNet.DeleteEntity = function(uNetId)
--#endregion
local entities = GlobalState.Entities
local entity = UtilityNet.InternalFindFromNetId(uNetId)
if entity then
entities[entity.slice][entity.id] = nil
Entities[entity.slice][entity.id] = nil
end
GlobalState.Entities = entities
TriggerLatentEventForListeners("Utility:Net:RequestDeletion", uNetId, 5120, uNetId)
TriggerLatentClientEvent("Utility:Net:RequestDeletion", -1, 5120, uNetId)
ClearEntityStates(uNetId) -- Clear states after trigger
end
local queues = {
ModelsRenderDistance = {},
Entities = {},
}
local function StartQueueUpdateLoop(bagkey)
local queue = queues[bagkey]
Citizen.CreateThread(function()
while queue.updateLoop do
-- Nothing added in the last 100ms
if (GetGameTimer() - queue.lastInt) > 200 then
local old = GlobalState[bagkey]
if bagkey == "Entities" then
UtilityNet.ForEachEntity(function(entity)
if queue[entity.id] then
-- Rotation need to be handled separately
if queue[entity.id].rotation then
old[entity.slice][entity.id].options.rotation = queue[entity.id].rotation
queue[entity.id].rotation = nil
end
for k,v in pairs(queue[entity.id]) do
-- If slice need to be updated, move entity to new slice
if k == "slice" and v ~= entity.slice then
local newSlice = v
old[newSlice][entity.id] = old[entity.slice][entity.id] -- Copy to new slice
old[entity.slice][entity.id] = nil -- Remove from old
entity = old[newSlice][entity.id] -- Update entity variable
end
old[entity.slice][entity.id][k] = v
end
end
end)
else
for k,v in pairs(old) do
-- Net id need to be updated
if queue[v.id] then
-- Rotation need to be handled separately
if queue[v.id].rotation then
v.options.rotation = queue[v.id].rotation
queue[v.id].rotation = nil
end
for k2,v2 in pairs(queue[v.id]) do
v[k2] = v2
end
end
end
end
-- Refresh GlobalState
GlobalState[bagkey] = old
queues[bagkey].updateLoop = false
queues[bagkey] = {}
end
Citizen.Wait(150)
UtilityNet.InternalFindFromNetId = function(uNetId)
for sliceI, slice in pairs(Entities) do
if slice[uNetId] then
return slice[uNetId], sliceI
end
end)
end
end
local function InsertValueInQueue(bagkey, id, value)
-- If it is already in the queue with some values that need to be updated, we merge the 2 updates into 1
if queues[bagkey][id] then
queues[bagkey][id] = table.merge(queues[bagkey][id], value)
UtilityNet.GetEntities = function(slice)
if slice then
return Entities[slice]
else
queues[bagkey][id] = value
end
queues[bagkey].lastInt = GetGameTimer()
if not queues[bagkey].updateLoop then
queues[bagkey].updateLoop = true
StartQueueUpdateLoop(bagkey)
return Entities
end
end
UtilityNet.SetModelRenderDistance = function(model, distance)
if type(model) == "string" then
model = GetHashKey(model)
@ -192,30 +123,57 @@ UtilityNet.SetModelRenderDistance = function(model, distance)
GlobalState.ModelsRenderDistance = _
end
UtilityNet.SetEntityRotation = function(uNetId, newRotation)
UtilityNet.SetEntityRotation = function(uNetId, newRotation, skipRotationUpdate)
local source = source
if type(newRotation) ~= "vector3" then
error("Invalid rotation, got "..type(newRotation).." expected vector3", 2)
end
InsertValueInQueue("Entities", uNetId, {rotation = newRotation})
if newRotation.x ~= newRotation.x or newRotation.y ~= newRotation.y or newRotation.z ~= newRotation.z then
error("Invalid rotation, got "..type(newRotation).." (with NaN) expected vector3", 2)
end
local entity, slice = UtilityNet.InternalFindFromNetId(uNetId)
Entities[slice][uNetId].options.rotation = newRotation
-- Except caller since it will be already updated
TriggerLatentEventForListenersExcept("Utility:Net:RefreshRotation", uNetId, 5120, source, uNetId, newRotation)
TriggerLatentClientEvent("Utility:Net:RefreshRotation", -1, 5120, uNetId, newRotation, skipRotationUpdate)
end
UtilityNet.SetEntityCoords = function(uNetId, newCoords)
UtilityNet.SetEntityCoords = function(uNetId, newCoords, skipPositionUpdate)
local source = source
if type(newCoords) ~= "vector3" then
error("Invalid coords, got "..type(newCoords).." expected vector3", 2)
end
InsertValueInQueue("Entities", uNetId, {coords = newCoords, slice = GetSliceFromCoords(newCoords)})
if newCoords.x ~= newCoords.x or newCoords.y ~= newCoords.y or newCoords.z ~= newCoords.z then
error("Invalid coords, got "..type(newCoords).." (with NaN) expected vector3", 2)
end
local entity, slice = UtilityNet.InternalFindFromNetId(uNetId)
local newSlice = GetSliceFromCoords(newCoords)
if newSlice ~= slice then
local old = Entities[slice][uNetId]
if not Entities[newSlice] then
Entities[newSlice] = {}
end
Entities[slice][uNetId] = nil
Entities[newSlice][uNetId] = old
slice = newSlice
end
Entities[slice][uNetId].coords = newCoords
Entities[slice][uNetId].slice = GetSliceFromCoords(newCoords)
-- Except caller since it will be already updated
TriggerLatentEventForListenersExcept("Utility:Net:RefreshCoords", uNetId, 5120, source, uNetId, newCoords)
TriggerLatentClientEvent("Utility:Net:RefreshCoords", -1, 5120, uNetId, newCoords, skipPositionUpdate)
end
UtilityNet.SetEntityModel = function(uNetId, model)
@ -229,10 +187,12 @@ UtilityNet.SetEntityModel = function(uNetId, model)
model = GetHashKey(model)
end
InsertValueInQueue("Entities", uNetId, {model = model})
local entity, slice = UtilityNet.InternalFindFromNetId(uNetId)
Entities[slice][uNetId].model = model
-- Except caller since it will be already updated
TriggerLatentEventForListenersExcept("Utility:Net:RefreshModel", uNetId, 5120, source, uNetId, model)
TriggerLatentClientEvent("Utility:Net:RefreshModel", -1, 5120, uNetId, model)
end
--#region Events
@ -244,7 +204,7 @@ UtilityNet.RegisterEvents = function()
RegisterNetEvent("Utility:Net:DeleteEntity", function(uNetId)
UtilityNet.DeleteEntity(uNetId)
end)
RegisterNetEvent("Utility:Net:SetModelRenderDistance", function(model, distance)
UtilityNet.SetModelRenderDistance(model, distance)
end)
@ -274,13 +234,8 @@ UtilityNet.RegisterEvents = function()
RegisterNetEvent("Utility:Net:SetEntityModel", UtilityNet.SetEntityModel)
RegisterNetEvent("Utility:Net:SetEntityRotation", UtilityNet.SetEntityRotation)
-- Clear all entities on resource stop
AddEventHandler("onResourceStop", function(resource)
if resource == GetCurrentResourceName() then
UtilityNet.ForEachEntity(function(v)
TriggerLatentEventForListeners("Utility:Net:RequestDeletion", v, 5120, v)
end)
end
RegisterNetEvent("Utility:Net:GetEntities", function()
TriggerClientEvent("Utility:Net:GetEntities", source, UtilityNet.GetEntities())
end)
end
--#endregion
@ -289,6 +244,8 @@ end
exports("CreateEntity", UtilityNet.CreateEntity)
exports("DeleteEntity", UtilityNet.DeleteEntity)
exports("SetModelRenderDistance", UtilityNet.SetModelRenderDistance)
exports("GetEntities", UtilityNet.GetEntities)
exports("InternalFindFromNetId", UtilityNet.InternalFindFromNetId)
exports("SetEntityModel", UtilityNet.SetEntityModel)
exports("SetEntityCoords", UtilityNet.SetEntityCoords)

View file

@ -44,6 +44,7 @@ UpdateStateValueForListeners = function(uNetId, key, value)
end
for k,v in pairs(EntitiesStates[uNetId].listeners) do
TriggerEvent("Utility:Net:UpdateStateValue", uNetId, key, value)
TriggerClientEvent("Utility:Net:UpdateStateValue", v, uNetId, key, value)
end
end
@ -161,6 +162,7 @@ RegisterNetEvent("Utility:Net:GetState", function(uNetId)
local source = source
if not EntitiesStates[uNetId] then
warn("GetState: No state found for "..uNetId)
TriggerClientEvent("Utility:Net:GetState"..uNetId, source, nil)
return
end
@ -168,6 +170,19 @@ RegisterNetEvent("Utility:Net:GetState", function(uNetId)
ListenStateUpdates(source, uNetId)
TriggerClientEvent("Utility:Net:GetState"..uNetId, source, EntitiesStates[uNetId].states)
end)
-- Single value
RegisterNetEvent("Utility:Net:GetStateValue", function(uNetId, key)
local source = source
if not EntitiesStates[uNetId] then
warn("GetStateValue: No state found for "..uNetId)
TriggerClientEvent("Utility:Net:GetStateValue"..uNetId, source, nil)
return
end
TriggerClientEvent("Utility:Net:GetStateValue"..uNetId, source, EntitiesStates[uNetId].states[key])
end)
--#endregion
-- On player disconnect remove all listeners of that player (prevent useless bandwidth usage)