Files
ox_lib/imports/points/client.lua
Linden fb2225e373 chore: add copyright notices to each file
Some people accidentally, mistakenly, and without any malicious intent forget to attribute code from this resource to its source. This change will hopefully assist people, so that they do not make that mistake again.
2025-03-18 18:46:09 +11:00

189 lines
4.9 KiB
Lua

--[[
https://github.com/overextended/ox_lib
This file is licensed under LGPL-3.0 or higher <https://www.gnu.org/licenses/lgpl-3.0.en.html>
Copyright (c) 2025 Linden <https://github.com/thelindat/fivem>
]]
---@class PointProperties
---@field coords vector3
---@field distance number
---@field onEnter? fun(self: CPoint)
---@field onExit? fun(self: CPoint)
---@field nearby? fun(self: CPoint)
---@field [string] any
---@class CPoint : PointProperties
---@field id number
---@field currentDistance number
---@field isClosest? boolean
---@field remove fun()
---@type table<number, CPoint>
local points = {}
---@type CPoint[]
local nearbyPoints = {}
local nearbyCount = 0
---@type CPoint?
local closestPoint
local tick
local function removePoint(self)
if closestPoint?.id == self.id then
closestPoint = nil
end
lib.grid.removeEntry(self)
points[self.id] = nil
end
CreateThread(function()
while true do
local coords = GetEntityCoords(cache.ped)
local newPoints = lib.grid.getNearbyEntries(coords, function(entry) return entry.remove == removePoint end) --[[@as CPoint[] ]]
local cellX, cellY = lib.grid.getCellPosition(coords)
cache.coords = coords
closestPoint = nil
if cellX ~= cache.lastCellX or cellY ~= cache.lastCellY then
for i = 1, nearbyCount do
local point = nearbyPoints[i]
if point.inside then
local distance = #(coords - point.coords)
if distance > point.radius then
if point.onExit then point:onExit() end
point.inside = nil
point.currentDistance = nil
end
end
end
cache.lastCellX = cellX
cache.lastCellY = cellY
end
if nearbyCount ~= 0 then
table.wipe(nearbyPoints)
nearbyCount = 0
end
for i = 1, #newPoints do
local point = newPoints[i]
local distance = #(coords - point.coords)
if distance <= point.radius then
point.currentDistance = distance
if not closestPoint or distance < (closestPoint.currentDistance or point.radius) then
if closestPoint then closestPoint.isClosest = nil end
point.isClosest = true
closestPoint = point
end
nearbyCount += 1
nearbyPoints[nearbyCount] = point
if point.onEnter and not point.inside then
point.inside = true
point:onEnter()
end
elseif point.currentDistance then
if point.onExit then point:onExit() end
point.inside = nil
point.currentDistance = nil
end
end
if not tick then
if nearbyCount ~= 0 then
tick = SetInterval(function()
for i = nearbyCount, 1, -1 do
local point = nearbyPoints[i]
if point and point.nearby then
point:nearby()
end
end
end)
end
elseif nearbyCount == 0 then
tick = ClearInterval(tick)
end
Wait(300)
end
end)
local function toVector(coords)
local _type = type(coords)
if _type ~= 'vector3' then
if _type == 'table' or _type == 'vector4' then
return vec3(coords[1] or coords.x, coords[2] or coords.y, coords[3] or coords.z)
end
error(("expected type 'vector3' or 'table' (received %s)"):format(_type))
end
return coords
end
lib.points = {}
---@return CPoint
---@overload fun(data: PointProperties): CPoint
---@overload fun(coords: vector3, distance: number, data?: PointProperties): CPoint
function lib.points.new(...)
local args = { ... }
local id = #points + 1
local self
-- Support sending a single argument containing point data
if type(args[1]) == 'table' then
self = args[1]
self.id = id
self.remove = removePoint
else
-- Backwards compatibility for original implementation (args: coords, distance, data)
self = {
id = id,
coords = args[1],
remove = removePoint,
}
end
self.coords = toVector(self.coords)
self.distance = self.distance or args[2]
self.radius = self.distance
if args[3] then
for k, v in pairs(args[3]) do
self[k] = v
end
end
lib.grid.addEntry(self)
points[id] = self
return self
end
function lib.points.getAllPoints() return points end
function lib.points.getNearbyPoints() return nearbyPoints end
---@return CPoint?
function lib.points.getClosestPoint() return closestPoint end
---@deprecated
lib.points.closest = lib.points.getClosestPoint
return lib.points