2025-10-26 16:20:27 -04:00
|
|
|
local GRIDE_SIZE_X = 8968.83
|
2025-10-14 00:26:48 -05:00
|
|
|
local GRIDE_SIZE_Y = 126200.40
|
2025-08-15 23:54:55 -05:00
|
|
|
local CELL_SIZE = 500
|
|
|
|
|
|
|
|
|
|
local Grid = {}
|
|
|
|
|
Grid.Generated = false
|
|
|
|
|
local Grids = {}
|
|
|
|
|
Point = {}
|
|
|
|
|
Point.All = {}
|
2025-11-14 18:36:35 -06:00
|
|
|
Point.LastInside = nil
|
2025-08-15 23:54:55 -05:00
|
|
|
|
|
|
|
|
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
|
2025-08-16 19:27:06 -05:00
|
|
|
return Grids[cellX][cellY]
|
2025-08-15 23:54:55 -05:00
|
|
|
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)
|
2025-11-14 18:36:35 -06:00
|
|
|
if Point.LastInside ~= cell then
|
|
|
|
|
for _, point in pairs(Point.LastInside or {}) do
|
|
|
|
|
if point.inside then
|
|
|
|
|
point.inside = false
|
|
|
|
|
point.args = point?.onExit(point, point.args) or point.args
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
Point.LastInside = cell
|
|
|
|
|
end
|
2025-08-15 23:54:55 -05:00
|
|
|
for _, point in pairs(cell or {}) do
|
2025-10-26 16:20:27 -04:00
|
|
|
local entity = point.target
|
|
|
|
|
local targetCoords = point.isEntity and DoesEntityExist(entity) and GetEntityCoords(entity) or point.coords
|
|
|
|
|
if not point.disable and targetCoords then
|
|
|
|
|
targetCoords = vector3(targetCoords.x, targetCoords.y, targetCoords.z)
|
|
|
|
|
local distance = #(coords - targetCoords)
|
2025-08-15 23:54:55 -05:00
|
|
|
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
|
2025-08-23 22:53:49 -05:00
|
|
|
if point.inside and point.onUpdate then
|
|
|
|
|
point.onUpdate(point, point.args)
|
|
|
|
|
end
|
2025-08-15 23:54:55 -05:00
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
Wait(1000)
|
|
|
|
|
end
|
|
|
|
|
end)
|
|
|
|
|
end
|
|
|
|
|
|
2025-08-23 22:53:49 -05:00
|
|
|
function Point.Register(id, target, distance, args, _onEnter, _onExit, _onUpdate)
|
2025-08-15 23:54:55 -05:00
|
|
|
local isEntity = type(target) == "number"
|
|
|
|
|
local coords = isEntity and GetEntityCoords(target) or target
|
|
|
|
|
Grid.Generate()
|
2025-08-23 22:53:49 -05:00
|
|
|
local self = args or {}
|
2025-08-15 23:54:55 -05:00
|
|
|
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
|
2025-08-23 22:53:49 -05:00
|
|
|
self.onUpdate = _onUpdate or function() end
|
2025-08-15 23:54:55 -05:00
|
|
|
self.inside = false -- Track if player is inside
|
2025-09-10 17:43:18 -05:00
|
|
|
self.args = args or {} --DEPRICATED 2025-09-10
|
2025-08-15 23:54:55 -05:00
|
|
|
local grid = Grid.GetCellByCoords(coords)
|
2025-08-16 19:27:06 -05:00
|
|
|
grid[id] = self
|
2025-08-15 23:54:55 -05:00
|
|
|
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
|
2025-08-16 19:27:06 -05:00
|
|
|
grid[point.id] = nil
|
2025-08-15 23:54:55 -05:00
|
|
|
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)
|
2025-08-16 19:27:06 -05:00
|
|
|
if not newGrid or newGrid[point.id] then return end
|
2025-08-15 23:54:55 -05:00
|
|
|
local oldGrid = Grid.GetCellByCoords(point.coords)
|
|
|
|
|
if oldGrid then
|
2025-08-16 19:27:06 -05:00
|
|
|
oldGrid[point.id] = nil
|
2025-08-15 23:54:55 -05:00
|
|
|
end
|
|
|
|
|
point.coords = coords
|
2025-08-16 19:27:06 -05:00
|
|
|
newGrid[point.id] = point
|
2025-08-15 23:54:55 -05:00
|
|
|
return true
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function Point.GetAll()
|
|
|
|
|
return Point.All
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
return Point
|