247 lines
7.7 KiB
Lua
247 lines
7.7 KiB
Lua
-- Grid-based point system
|
|
Point = {}
|
|
local ActivePoints = {}
|
|
local GridCells = {}
|
|
local LoopStarted = false
|
|
|
|
-- Grid configuration
|
|
local GRID_SIZE = 150.0 -- Size of each grid cell
|
|
local CELL_BUFFER = 1 -- Number of adjacent cells to check
|
|
|
|
-- Consider adding these optimizations
|
|
local ADAPTIVE_WAIT = true -- 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
|
|
|
|
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 distance = #(playerCoords - point.coords)
|
|
|
|
-- Check if player entered/exited the point
|
|
if distance < point.distance then
|
|
if not point.inside then
|
|
print("Entered point: ", point.distance)
|
|
point.inside = true
|
|
point.onEnter(point)
|
|
end
|
|
elseif point.inside then
|
|
print("Exited point: ", point.id)
|
|
point.inside = false
|
|
point.onExit(point)
|
|
end
|
|
if point.onNearby then
|
|
point.onNearby(GridCells[cellKey]?.points, waitTime)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
--kills the loop if no targets exist
|
|
if not targetsExist then
|
|
LoopStarted = false
|
|
break
|
|
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, _onEnter, _onExit, _onNearby, data)
|
|
local isEntity = type(target) == "number"
|
|
local coords = isEntity and GetEntityCoords(target) or target
|
|
|
|
local self = data or {}
|
|
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
|
|
|
|
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
|
|
|
|
---Returns all points
|
|
---@return table
|
|
function Point.GetAll()
|
|
return ActivePoints
|
|
end
|
|
|
|
-- Usage example for checking nearby points
|
|
-- This is fucking hot. +20 points for crowley
|
|
--[[
|
|
Point.Register("point1", vector3(100, 100, 30), 5.0,
|
|
function(point)
|
|
print("Entered point1")
|
|
end,
|
|
function(point)
|
|
print("Exited point1")
|
|
end,
|
|
function(nearbyPoints)
|
|
print("Point1 has nearby points:")
|
|
for id, point in pairs(nearbyPoints) do
|
|
print("- " .. id .. " at distance: " .. #(point.coords - ActivePoints["point1"].coords))
|
|
end
|
|
end
|
|
)
|
|
--]]
|
|
|
|
return Point |