diff --git a/lib/utility/shared/callbacks.lua b/lib/callback/shared/callback.lua similarity index 100% rename from lib/utility/shared/callbacks.lua rename to lib/callback/shared/callback.lua diff --git a/lib/generators/server/lootTables.lua b/lib/generators/server/lootTables.lua deleted file mode 100644 index 9adc49d..0000000 --- a/lib/generators/server/lootTables.lua +++ /dev/null @@ -1,74 +0,0 @@ -LootTable = LootTable or {} - -local lootTables = {} - -LootTable.Register = function(name, items) - local repackedTable = {} - for k, v in pairs(items) do - table.insert(repackedTable, { - name = k, - min = v.min, - max = v.max, - chance = v.chance, - tier = v.tier, - item = v.item, - metadata = v.metadata - }) - end - lootTables[name] = repackedTable - return lootTables[name] -end - -LootTable.Get = function(name) - assert(name, "No Name Passed For Loot Table") - return lootTables[name] or {} -end - -LootTable.GetRandomItem = function(name, tier, randomNumber) - assert(name, "No Name Passed For Loot Table") - if tier == nil then tier = 1 end - local lootTable = lootTables[name] or {} - math.randomseed(GetGameTimer()) - local chance = randomNumber or math.random(1, 100) - for _, v in pairs(lootTable) do - if v.chance <= chance and tier == v.tier then - return { item = v.item, metadata = v.metadata, count = math.random(v.min, v.max), tier = v.tier, chance = v.chance} - end - end -end - -LootTable.GetRandomItems = function(name, tier, randomNumber) - assert(name, "No Name Passed For Loot Table") - if tier == nil then tier = 1 end - local lootTable = LootTable.Get(name) - math.randomseed(GetGameTimer()) - local chance = randomNumber or math.random(1, 100) - local items = {} - for _, v in pairs(lootTable) do - if v.chance <= chance and tier == v.tier then - table.insert(items,{item = v.item, metadata = v.metadata, count = math.random(v.min, v.max), tier = v.tier, chance = v.chance}) - end - end - return items -end - -LootTable.GetRandomItemsWithLimit = function(name, tier, randomNumber) - assert(name, "No Name Passed For Loot Table") - if tier == nil then tier = 1 end - local lootTable = LootTable.Get(name) - math.randomseed(GetGameTimer()) - local chance = randomNumber or math.random(1, 100) - local items = {} - for k = #lootTable, 1, -1 do - local v = lootTable[k] - if chance <= v.chance and tier == v.tier then - table.insert(items, {v.item, v.metadata, math.random(v.min, v.max), v.tier, v.chance}) - table.remove(lootTable, k) - end - end - return items -end --- - -exports('LootTable', LootTable) -return LootTable \ No newline at end of file diff --git a/lib/init.lua b/lib/init.lua index b97a442..ed37f5d 100644 --- a/lib/init.lua +++ b/lib/init.lua @@ -39,10 +39,10 @@ end cLib = { Require = Require, - Callback = Callback or Require("lib/utility/shared/callbacks.lua"), + Callback = Callback or Require("lib/callback/shared/callback.lua"), Ids = Ids or Require("lib/utility/shared/ids.lua"), ReboundEntities = ReboundEntities or Require("lib/utility/shared/rebound_entities.lua"), - Tables = Tables or Require("lib/utility/shared/tables.lua"), + Tables = Table or Require("lib/utility/shared/tables.lua"), Prints = Prints or Require("lib/utility/shared/prints.lua"), Math = Math or Require("lib/utility/shared/math.lua"), LA = LA or Require("lib/utility/shared/la.lua"), diff --git a/lib/points/client/points.lua b/lib/points/client/points.lua deleted file mode 100644 index 569d29c..0000000 --- a/lib/points/client/points.lua +++ /dev/null @@ -1,255 +0,0 @@ --- -- Grid-based point system --- Point = {} --- local ActivePoints = {} --- local GridCells = {} --- local LoopStarted = false --- local insidePoints = {} --- local data = {} -- 👈 Move this outside the function - --- -- Grid configuration --- local GRID_SIZE = 500.0 -- Size of each grid cell --- local CELL_BUFFER = 1 -- Number of adjacent cells to check - --- -- Consider adding these optimizations --- local ADAPTIVE_WAIT = false -- Adjust wait time based on player speed - --- ---This is an internal function, do not call this externally --- function Point.GetCellKey(coords) --- local cellX = math.floor(coords.x / GRID_SIZE) --- local cellY = math.floor(coords.y / GRID_SIZE) --- return cellX .. ":" .. cellY --- end - --- ---This is an internal function, do not call this externally --- function Point.RegisterInGrid(point) --- local cellKey = Point.GetCellKey(point.coords) - --- -- Initialize cell if it doesn't exist --- GridCells[cellKey] = GridCells[cellKey] or { --- points = {}, --- count = 0 --- } - --- -- Add point to cell --- GridCells[cellKey].points[point.id] = point --- GridCells[cellKey].count = GridCells[cellKey].count + 1 - --- -- Store cell reference in point --- point.cellKey = cellKey --- end - --- ---This is an internal function, do not call this externally --- function Point.UpdateInGrid(point, oldCellKey) --- -- Remove from old cell if cell key changed --- if oldCellKey and oldCellKey ~= point.cellKey then --- if GridCells[oldCellKey] and GridCells[oldCellKey].points[point.id] then --- GridCells[oldCellKey].points[point.id] = nil --- GridCells[oldCellKey].count = GridCells[oldCellKey].count - 1 - --- -- Clean up empty cells --- if GridCells[oldCellKey].count <= 0 then --- GridCells[oldCellKey] = nil --- end --- end - --- -- Add to new cell --- Point.RegisterInGrid(point) --- end --- end - --- ---Gets nearby cells based on the coords --- ---@param coords table --- ---@return table --- function Point.GetNearbyCells(coords) --- local cellX = math.floor(coords.x / GRID_SIZE) --- local cellY = math.floor(coords.y / GRID_SIZE) --- local nearbyCells = {} - --- -- Get current and adjacent cells --- for x = cellX - CELL_BUFFER, cellX + CELL_BUFFER do --- for y = cellY - CELL_BUFFER, cellY + CELL_BUFFER do --- local key = x .. ":" .. y --- if GridCells[key] then --- table.insert(nearbyCells, key) --- end --- end --- end - --- return nearbyCells --- end - --- ---Returns all points in the same cell as the given point --- ---This will require you to pass the point object --- ---@param point table --- ---@return table --- function Point.CheckPointsInSameCell(point) --- local cellKey = point.cellKey --- if not GridCells[cellKey] then return {} end - --- local nearbyPoints = {} --- for id, otherPoint in pairs(GridCells[cellKey].points) do --- if id ~= point.id then --- local distance = #(point.coords - otherPoint.coords) --- if distance < (point.distance + otherPoint.distance) then --- nearbyPoints[id] = otherPoint --- end --- end --- end - --- return nearbyPoints --- end - --- ---Internal function that starts the loop. Do not call this function directly. --- function Point.StartLoop() --- if LoopStarted then return false end --- LoopStarted = true --- -- Remove the "local data = {}" line from here --- CreateThread(function() --- while LoopStarted do --- local playerPed = PlayerPedId() --- while playerPed == -1 do --- Wait(100) --- playerPed = PlayerPedId() --- end --- local playerCoords = GetEntityCoords(playerPed) --- local targetsExist = false --- local playerCellKey = Point.GetCellKey(playerCoords) --- local nearbyCells = Point.GetNearbyCells(playerCoords) - --- local playerSpeed = GetEntitySpeed(playerPed) --- local maxWeight = 1000 --- local waitTime = ADAPTIVE_WAIT and math.max(maxWeight/10, maxWeight - playerSpeed * maxWeight/10) or maxWeight --- -- Process only points in nearby cells --- for _, cellKey in ipairs(nearbyCells) do --- if GridCells[cellKey] then --- for id, point in pairs(GridCells[cellKey].points) do --- targetsExist = true - --- -- Update entity position if needed --- local oldCellKey = point.cellKey --- if point.isEntity then --- point.coords = GetEntityCoords(point.target) --- point.cellKey = Point.GetCellKey(point.coords) --- Point.UpdateInGrid(point, oldCellKey) --- end --- local coords = point.coords and vector3(point.coords.x, point.coords.y, point.coords.z) or vector3(0, 0, 0) --- local distance = #(playerCoords - coords) --- --local distance = #(playerCoords - point.coords) - --- -- Check if player entered/exited the point --- if distance < point.distance then --- if not point.inside then --- point.inside = true --- data[point.id] = data[point.id] or point.args or {} --- data[point.id] = point.onEnter(point, data[point.id]) --- insidePoints[point.id] = point --- end --- -- Modified main loop exit handler --- elseif point.inside then --- point.inside = false --- data[point.id] = data[point.id] or point.args or {} --- local result = point.onExit(point, data[point.id]) --- data[point.id] = result ~= nil and result or data[point.id] -- ← Use consistent fallback --- point.args = data[point.id] -- ← Update point.args to match data[point.id] --- insidePoints[point.id] = nil --- end - --- -- if point.onNearby then --- -- point.onNearby(GridCells[cellKey]?.points, waitTime) --- -- end --- end --- end --- end - --- for id, insidepoint in pairs(insidePoints) do --- local pos = insidepoint.coords and vector3(insidepoint.coords.x, insidepoint.coords.y, insidepoint.coords.z) or vector3(0, 0, 0) --- local dist = #(playerCoords - pos) --- if dist > insidepoint.distance then --- insidepoint.inside = false --- data[insidepoint.id] = data[insidepoint.id] or insidepoint.args or {} --- local result = insidepoint.onExit(insidepoint, data[insidepoint.id]) --- data[insidepoint.id] = result ~= nil and result or data[insidepoint.id] --- insidepoint.args = data[insidepoint.id] -- ← Keep data in sync --- insidePoints[insidepoint.id] = nil --- end --- end --- Wait(waitTime) -- Faster updates when moving quickly --- end --- end) --- return true --- end - --- ---Create a point based on a vector or entityID --- ---@param id string --- ---@param target number || vector3 --- ---@param distance number --- ---@param _onEnter function --- ---@param _onExit function --- ---@param _onNearby function --- ---@param data self --- ---@return table --- function Point.Register(id, target, distance, args, _onEnter, _onExit, _onNearby) --- local isEntity = type(target) == "number" --- local coords = isEntity and GetEntityCoords(target) or target - --- local self = {} --- self.id = id --- self.target = target -- Store entity ID or Vector3 --- self.isEntity = isEntity --- self.coords = coords --- self.distance = distance --- self.onEnter = _onEnter or function() end --- self.onExit = _onExit or function() end --- self.onNearby = _onNearby or function() end --- self.inside = false -- Track if player is inside --- self.args = args or {} - --- ActivePoints[id] = self --- Point.RegisterInGrid(self) --- Point.StartLoop() --- return self --- end - --- ---Remove an exsisting point by its id --- ---@param id string --- function Point.Remove(id) --- local point = ActivePoints[id] --- if point then --- local cellKey = point.cellKey --- if GridCells[cellKey] and GridCells[cellKey].points[id] then --- GridCells[cellKey].points[id] = nil --- GridCells[cellKey].count = GridCells[cellKey].count - 1 - --- if GridCells[cellKey].count <= 0 then --- GridCells[cellKey] = nil --- end --- end - --- ActivePoints[id] = nil --- end --- end - --- ---Returnes a point by its id --- ---@param id string --- ---@return table --- function Point.Get(id) --- return ActivePoints[id] --- end - --- function Point.UpdateCoords(id, coords) --- local point = ActivePoints[id] --- if point then --- point.coords = coords --- local oldCellKey = point.cellKey --- point.cellKey = Point.GetCellKey(coords) --- Point.UpdateInGrid(point, oldCellKey) --- end --- end - --- ---Returns all points --- ---@return table --- function Point.GetAll() --- return ActivePoints --- end - --- return Point \ No newline at end of file diff --git a/lib/statebags/client/client.lua b/lib/statebags/client/client.lua deleted file mode 100644 index 2c2c364..0000000 --- a/lib/statebags/client/client.lua +++ /dev/null @@ -1,48 +0,0 @@ -ClientStateBag = {} - ----Gets an entity from a statebag name ----@param entityId string The entity ID or statebag name ----@return number|nil entity The entity handle or nil if not found -local function getStateBagEntity(entityId) - local _entity = GetEntityFromStateBagName(entityId) - return _entity -end - -local function getPlayerFromStateBagName(stateBagName) - return getPlayerFromStateBagName(stateBagName) -end - ----Adds a handler for entity statebag changes ----@param keyName string The statebag key to watch for changes ----@param entityId string|nil The specific entity ID to watch, or nil for all entities ----@param callback function The callback function to handle changes (function(entityId, key, value, lastValue, replicated)) ----@return number handler The handler ID -function ClientStateBag.AddEntityChangeHandler(keyName, entityId, callback) - return AddStateBagChangeHandler(keyName, entityId or nil, function(bagName, key, value, lastValue, replicated) - local entity = getStateBagEntity(bagName) - if not DoesEntityExist(entity) then return end - if entity then - return callback(entity, key, value, lastValue, replicated) - end - end) -end - ----Adds a handler for player statebag changes ----@param keyName string The statebag key to watch for changes ----@param filter boolean|nil If true, only watch for changes from the current player ----@param callback function The callback function to handle changes (function(playerId, key, value, lastValue, replicated)) ----@return number handler The handler ID -function ClientStateBag.AddPlayerChangeHandler(keyName, filter, callback) - return AddStateBagChangeHandler(keyName, filter and ("player:%s"):format(GetPlayerServerId(PlayerId())) or nil, - function(bagName, key, value, lastValue, replicated) - local actualPlayerId = getPlayerFromStateBagName(bagName) - if DoesEntityExist(actualPlayerId) and (actualPlayerId ~= PlayerPedId()) then -- you cant have a statebag value if you are not the player - return false - end - if actualPlayerId and actualPlayerId ~= 0 then - return callback(tonumber(actualPlayerId), key, value, lastValue, replicated) - end - end) -end - -return ClientStateBag diff --git a/lib/statebags/server/server.lua b/lib/statebags/server/server.lua deleted file mode 100644 index e69de29..0000000 diff --git a/lib/utility/shared/math.lua b/lib/utility/shared/math.lua index 30717ce..499d8c4 100644 --- a/lib/utility/shared/math.lua +++ b/lib/utility/shared/math.lua @@ -1,5 +1,59 @@ Math = Math or {} + + +---@class Math +------@field public name string @add name field to class Car, you'll see it in code completion +Math = {} + + +--- Rounds a number to the nearest whole number. +---@param value number: The value to round. +---@return number: The rounded value. +function Math.Round(value) + return math.floor(value + 0.5) +end + +function Math.Truncate(value, decimals) + local mul = decimals and (10 ^ decimals) or 1 + if value < 0 then + return math.ceil(value * mul) / mul + else + return math.floor(value * mul) / mul + end +end + +--- Warps the number around from max to min and vice versa. +---@param value number: The value to wrap. +---@param min number: The minimum value. +---@param max number: The maximum value. +---@return number: The wrapped value. +function Math.Wrap(value, min, max) + local range = max - min + return (value - min) % range + min +end + +--- Gets an interpolated value between two numbers. +---@see https://en.wikipedia.org/wiki/Smoothstep +---@param value number The interpolation value. +---@param min number : The minimum value. +---@param max number : The maximum value. +---@return number The interpolated value. +function Math.Smooth(value, min, max) + value = Math.Clamp((value - min) / (max - min), 0, 1) + return value * value * (3 - 2 * value) +end + +--- Maps a value from one range to another. +---@param value number The value to map. +---@param inMin number The minimum value for the provided value. +---@param inMax number The maximum value for the provided value. +---@param outMin number The minimum value for the output. +---@param outMax number The maximum value for the output. +function Math.Map(value, inMin, inMax, outMin, outMax) + return (value - inMin) / (inMax - inMin) * (outMax - outMin) + outMin +end + function Math.Clamp(value, min, max) return math.min(math.max(value, min), max) end diff --git a/lib/utility/shared/perlin.lua b/lib/utility/shared/perlin.lua deleted file mode 100644 index 36ff967..0000000 --- a/lib/utility/shared/perlin.lua +++ /dev/null @@ -1,110 +0,0 @@ -local Perlin = {} - --- Permutation table for random gradients -local perm = {} -local grad3 = { - {1,1,0}, {-1,1,0}, {1,-1,0}, {-1,-1,0}, - {1,0,1}, {-1,0,1}, {1,0,-1}, {-1,0,-1}, - {0,1,1}, {0,-1,1}, {0,1,-1}, {0,-1,-1} -} - --- Initialize permutation table -local function ShufflePermutation() - local p = {} - for i = 0, 255 do - p[i] = i - end - for i = 255, 1, -1 do - local j = math.random(i + 1) - 1 - p[i], p[j] = p[j], p[i] - end - for i = 0, 255 do - perm[i] = p[i] - perm[i + 256] = p[i] -- Repeat for wrapping - end -end - -ShufflePermutation() -- Randomize on load - --- Dot product helper -local function Dot(g, x, y, z) - return g[1] * x + g[2] * y + (z and g[3] * z or 0) -end - --- Fade function (smootherstep) -local function Fade(t) - return t * t * t * (t * (t * 6 - 15) + 10) -end - --- Linear interpolation -local function Lerp(a, b, t) - return a + (b - a) * t -end - --- **Perlin Noise 1D** -function Perlin.Noise1D(x) - local X = math.floor(x) & 255 - x = x - math.floor(x) - local u = Fade(x) - - local a = perm[X] - local b = perm[X + 1] - - return Lerp(a, b, u) * (2 / 255) - 1 -end - --- **Perlin Noise 2D** -function Perlin.Noise2D(x, y) - local X = math.floor(x) & 255 - local Y = math.floor(y) & 255 - x, y = x - math.floor(x), y - math.floor(y) - - local u, v = Fade(x), Fade(y) - - local aa = perm[X] + Y - local ab = perm[X] + Y + 1 - local ba = perm[X + 1] + Y - local bb = perm[X + 1] + Y + 1 - - return Lerp( - Lerp(Dot(grad3[perm[aa] % 12 + 1], x, y), Dot(grad3[perm[ba] % 12 + 1], x - 1, y), u), - Lerp(Dot(grad3[perm[ab] % 12 + 1], x, y - 1), Dot(grad3[perm[bb] % 12 + 1], x - 1, y - 1), u), - v - ) -end - --- **Perlin Noise 3D** -function Perlin.Noise3D(x, y, z) - local X = math.floor(x) & 255 - local Y = math.floor(y) & 255 - local Z = math.floor(z) & 255 - x, y, z = x - math.floor(x), y - math.floor(y), z - math.floor(z) - - local u, v, w = Fade(x), Fade(y), Fade(z) - - local aaa = perm[X] + Y + Z - local aba = perm[X] + Y + Z + 1 - local aab = perm[X] + Y + 1 + Z - local abb = perm[X] + Y + 1 + Z + 1 - local baa = perm[X + 1] + Y + Z - local bba = perm[X + 1] + Y + Z + 1 - local bab = perm[X + 1] + Y + 1 + Z - local bbb = perm[X + 1] + Y + 1 + Z + 1 - - return Lerp( - Lerp( - Lerp(Dot(grad3[perm[aaa] % 12 + 1], x, y, z), Dot(grad3[perm[baa] % 12 + 1], x - 1, y, z), u), - Lerp(Dot(grad3[perm[aab] % 12 + 1], x, y - 1, z), Dot(grad3[perm[bab] % 12 + 1], x - 1, y - 1, z), u), - v - ), - Lerp( - Lerp(Dot(grad3[perm[aba] % 12 + 1], x, y, z - 1), Dot(grad3[perm[bba] % 12 + 1], x - 1, y, z - 1), u), - Lerp(Dot(grad3[perm[abb] % 12 + 1], x, y - 1, z - 1), Dot(grad3[perm[bbb] % 12 + 1], x - 1, y - 1, z - 1), u), - v - ), - w - ) -end - -exports('Perlin', Perlin) -return Perlin diff --git a/lib/utility/shared/rebound_entities.lua b/lib/utility/shared/rebound_entities.lua deleted file mode 100644 index 2ab3ee7..0000000 --- a/lib/utility/shared/rebound_entities.lua +++ /dev/null @@ -1,324 +0,0 @@ -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 diff --git a/lib/utility/shared/rebound_entitiy_actions.lua b/lib/utility/shared/rebound_entitiy_actions.lua deleted file mode 100644 index 78bee35..0000000 --- a/lib/utility/shared/rebound_entitiy_actions.lua +++ /dev/null @@ -1,45 +0,0 @@ -local ReboundEntities = ReboundEntities or Require("lib/utility/shared/rebound_entities.lua") -- Fixed path -local Action = Action or Require("lib/entities/shared/actions.lua") -- Fixed path and name -local LA = LA or Require("lib/utility/shared/la.lua") -- Fixed path - -REA = {} - -if not IsDuplicityVersion() then goto client end - - - -if IsDuplicityVersion() then return end -::client:: - -local ActionsInProgress = {} - - -Action.Create("LerpToPosition", function(reboundId, start, position, duration, shouldRepeat, overrideStartTime) - local re = ReboundEntities.GetById(reboundId) -- Use GetById - assert(re, "Rebound entity not found") - local entity = re and re.entity - if not entity or not DoesEntityExist(entity) then return end -- Check existence - local startTime = GetGameTimer() - local endTime = overrideStartTime or startTime + duration - ActionsInProgress[reboundId] = {reboundId, start, position, duration, shouldRepeat, startTime} - local t = 0 - CreateThread(function() - while shouldRepeat or t < 1 do - -- Check if entity still exists - if not re.entity or not DoesEntityExist(re.entity) then - ActionsInProgress[reboundId] = nil - break - end - entity = re.entity -- Update entity handle in case it changed (unlikely but safe) - t = (GetGameTimer() - startTime) / duration - local lerpPosition = LA.LerpVector(start, position, t) - SetEntityCoordsNoOffset(entity, lerpPosition.x, lerpPosition.y, lerpPosition.z, false, false, false) -- Use NoOffset - Wait(0) - end - -- Set final position if not repeating - if not shouldRepeat and re.entity and DoesEntityExist(re.entity) then - SetEntityCoordsNoOffset(re.entity, position.x, position.y, position.z, false, false, false) - end - ActionsInProgress[reboundId] = nil -- Clear when done - end) -end) diff --git a/modules/math/computation.lua b/modules/math/computation.lua deleted file mode 100644 index f007806..0000000 --- a/modules/math/computation.lua +++ /dev/null @@ -1,70 +0,0 @@ - ----@class Math -------@field public name string @add name field to class Car, you'll see it in code completion -Math = {} - ---- If the value is less than the minimum, it will return the minimum. ---- If the value is greater than the maximum, it will return the maximum. ---- Otherwise, it will return the value. ----@param value number: The value to clamp. ----@param min number: The minimum value. ----@param max number: The maximum value. ----@return number: The clamped value. -function Math.Clamp(value, min, max) - if value < min then - return min - elseif value > max then - return max - else - return value - end -end - ---- Rounds a number to the nearest whole number. ----@param value number: The value to round. ----@return number: The rounded value. -function Math.Round(value) - return math.floor(value + 0.5) -end - -function Math.Truncate(value, decimals) - local mul = decimals and (10 ^ decimals) or 1 - if value < 0 then - return math.ceil(value * mul) / mul - else - return math.floor(value * mul) / mul - end -end - ---- Warps the number around from max to min and vice versa. ----@param value number: The value to wrap. ----@param min number: The minimum value. ----@param max number: The maximum value. ----@return number: The wrapped value. -function Math.Wrap(value, min, max) - local range = max - min - return (value - min) % range + min -end - ---- Gets an interpolated value between two numbers. ----@see https://en.wikipedia.org/wiki/Smoothstep ----@param value number The interpolation value. ----@param min number : The minimum value. ----@param max number : The maximum value. ----@return number The interpolated value. -function Math.Smooth(value, min, max) - value = Math.Clamp((value - min) / (max - min), 0, 1) - return value * value * (3 - 2 * value) -end - ---- Maps a value from one range to another. ----@param value number The value to map. ----@param inMin number The minimum value for the provided value. ----@param inMax number The maximum value for the provided value. ----@param outMin number The minimum value for the output. ----@param outMax number The maximum value for the output. -function Math.Map(value, inMin, inMax, outMin, outMax) - return (value - inMin) / (inMax - inMin) * (outMax - outMin) + outMin -end - -return Math \ No newline at end of file