Simplified Points

Reduced code and calculations should hopefully be more performant
This commit is contained in:
Mr.Crowley committed 2025-08-15 23:54:55 -05:00
1 parent 7a598dd8d8
commit bdde5124ff
3 files changed
+377 -224

No files matched your search

+2 -1
View File
@@ -47,6 +47,7 @@ cLib = {
Math = Math or Require("lib/utility/shared/math.lua"),
LA = LA or Require("lib/utility/shared/la.lua"),
Perlin = Perlin or Require("lib/utility/shared/perlin.lua"),
-- Zones = Poly or Require("lib/zones/shared/zones.lua"),
-- Action = Action or Require("lib/entities/shared/actions.lua"),
}
@@ -71,7 +72,7 @@ cLib.Placeable = Placeable or Require("lib/placers/client/object_placer.lua")
cLib.Utility = Utility or Require("lib/utility/client/utility.lua")
cLib.PlaceableObject = ObjectPlacer or Require("lib/placers/client/placeable_object.lua")
cLib.Raycast = Raycast or Require("lib/raycast/client/raycast.lua")
cLib.Point = Point or Require("lib/points/client/points.lua")
cLib.Point = Point or Require("lib/points/client/pointsv2.lua")
cLib.Particle = Particle or Require("lib/particles/client/particles.lua")
cLib.Cache = Cache or Require("lib/cache/client/cache.lua")
cLib.ClientEntity = ClientEntity or Require("lib/entities/client/client_entity.lua")
+223 -223
View File
@@ -1,255 +1,255 @@
-- Grid-based point system
Point = {}
local ActivePoints = {}
local GridCells = {}
local LoopStarted = false
local insidePoints = {}
local data = {} -- 👈 Move this outside the function
-- -- 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
-- -- 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
-- -- 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.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)
-- ---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
}
-- -- 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
-- -- 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
-- -- 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
-- ---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
-- -- Clean up empty cells
-- if GridCells[oldCellKey].count <= 0 then
-- GridCells[oldCellKey] = nil
-- end
-- end
-- Add to new cell
Point.RegisterInGrid(point)
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 = {}
-- ---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
-- -- 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
-- 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
-- ---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
-- 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
-- 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)
-- ---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
-- 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)
-- -- 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
-- -- 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
-- -- 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
-- 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
-- ---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 {}
-- 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
-- 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
-- ---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
-- if GridCells[cellKey].count <= 0 then
-- GridCells[cellKey] = nil
-- end
-- end
ActivePoints[id] = 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
-- ---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
-- 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
-- ---Returns all points
-- ---@return table
-- function Point.GetAll()
-- return ActivePoints
-- end
return Point
-- return Point
+152
View File
@@ -0,0 +1,152 @@
local GRIDE_SIZE_X = 8968.83 / 2
local GRIDE_SIZE_Y = 126200.40 / 2
local CELL_SIZE = 500
local Grid = {}
Grid.Generated = false
local Grids = {}
Point = {}
Point.All = {}
function Grid.Generate()
if Grid.Generated then return end
Grid.Generated = true
local numOfCellsX = math.ceil(GRIDE_SIZE_X / CELL_SIZE)
local numOfCellsY = math.ceil(GRIDE_SIZE_Y / CELL_SIZE)
for x = -numOfCellsX, numOfCellsX do
Grids[x] = {}
for y = -numOfCellsY, numOfCellsY do
Grids[x][y] = {}
end
end
end
function Grid.GetCellId(coords)
local cellX = math.floor(coords.x / CELL_SIZE) + 1
local cellY = math.floor(coords.y / CELL_SIZE) + 1
return string.format("%d_%d", cellX, cellY)
end
function Grid.GetCellByCoords(coords)
local cellX = math.floor(coords.x / CELL_SIZE) + 1
local cellY = math.floor(coords.y / CELL_SIZE) + 1
if Grids[cellX] and Grids[cellX][cellY] then
return Grids[cellX][cellY]
end
return nil
end
local Points = {}
Points.Started = false
function Point.StartLoop()
if Points.Started then return end
Points.Started = true
CreateThread(function()
while Points.Started do
local playerPed = PlayerPedId()
if playerPed ~= -1 then
local coords = GetEntityCoords(playerPed)
local cell = Grid.GetCellByCoords(coords)
for _, point in pairs(cell or {}) do
if point.isEntity then
local entity = point.target
if DoesEntityExist(entity) then
local entityCoords = GetEntityCoords(entity)
local distance = #(coords - entityCoords)
if distance < point.distance then
if not point.inside then
point.inside = true
point.args = point?.onEnter(point, point.args) or point.args
end
elseif point.inside then
point.inside = false
point.args = point?.onExit(point, point.args) or point.args
end
end
else
local distance = #(coords.xyz - point.coords.xyz)
if distance < point.distance then
if not point.inside then
point.inside = true
point.args = point?.onEnter(point, point.args) or point.args
end
elseif point.inside then
point.inside = false
point.args = point?.onExit(point, point.args) or point.args
end
end
end
end
Wait(1000)
end
end)
end
function Point.Register(id, target, distance, args, _onEnter, _onExit)
local isEntity = type(target) == "number"
local coords = isEntity and GetEntityCoords(target) or target
print(target)
Grid.Generate()
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.inside = false -- Track if player is inside
self.args = args or {}
local grid = Grid.GetCellByCoords(coords)
self.cellKey = Grid.GetCellId(coords)
grid[self.cellKey] = self
Point.All[id] = self
Point.StartLoop()
return self
end
function Point.Remove(id)
local point = Point.All[id]
if not point then return false end
-- Remove from grid
local grid = Grid.GetCellByCoords(point.coords)
if grid then
grid[point.cellKey] = nil
end
Point.All[id] = nil
return true
end
function Point.Get(id)
return Point.All[id]
end
function Point.UpdateCoords(id, coords)
local point = Point.All[id]
if not point then return end
local newGrid = Grid.GetCellByCoords(coords)
if not newGrid or newGrid[point.cellKey] then return end
local oldGrid = Grid.GetCellByCoords(point.coords)
if oldGrid then
oldGrid[point.cellKey] = nil
end
-- Add to new grid
point.coords = coords
point.cellKey = string.format("%d_%d", newGrid.x, newGrid.y)
newGrid[point.cellKey] = point
return true
end
function Point.GetAll()
return Point.All
end
return Point