255 lines
9.6 KiB
Lua
255 lines
9.6 KiB
Lua
-- -- 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 |