Files
ox_lib/imports/zones/client.lua
T

376 lines
9.4 KiB
Lua
Raw Normal View History

local glm = require 'glm'
2022-05-07 11:47:39 +10:00
Zones = {}
local function makeTriangles(t)
local t1, t2
if t[3] and t[4] then
t1 = mat(t[1], t[2], t[3])
t2 = mat(t[2], t[3], t[4])
else
t1 = mat(t[1], t[2], t[3] or t[4])
end
return t1, t2
end
2022-04-29 00:41:21 +10:00
local function getTriangles(polygon)
local triangles = {}
if polygon:isConvex() then
for i = 2, #polygon - 1 do
triangles[#triangles + 1] = mat(polygon[1], polygon[i], polygon[i + 1])
end
return triangles
end
2022-04-29 00:41:21 +10:00
local points = {}
local sides = {}
local horizontals = {}
2022-04-29 00:41:21 +10:00
for i = 1, #polygon do
2022-05-11 13:38:27 +10:00
local h
local point = polygon[i]
local unique = true
for j = 1, #horizontals do
if point.y == horizontals[j][1].y then
h = j
horizontals[j][#horizontals[j] + 1] = point
unique = false
break
end
end
if unique then
h = #horizontals + 1
horizontals[h] = {point}
end
2022-04-29 00:41:21 +10:00
sides[i] = {polygon[i], polygon[i + 1] or polygon[1]}
points[polygon[i]] = {side = i, horizontal = h, uses = 0}
2022-04-29 00:41:21 +10:00
end
2022-05-11 13:38:27 +10:00
local extremes = { polygon.projectToAxis(polygon, vec(1, 0, 0)) }
for i = 1, #horizontals do
local horizontal = horizontals[i]
local hLineStart, hLineEnd = vec(extremes[1], horizontal[1].yz), vec(extremes[2], horizontal[1].yz)
for j = 1, #sides do
local sideStart, sideEnd = sides[j][1], sides[j][2]
local bool, d, d2 = glm.segment.intersectsSegment(hLineStart, hLineEnd, sideStart, sideEnd)
if d > 0.001 and d < 0.999 and d2 > 0.001 and d2 < 0.999 then
local newPoint = glm.segment.getPoint(hLineStart, hLineEnd, d)
local valid
for l = 1, #horizontal do
local point = horizontal[l]
valid = polygon.contains(polygon, (point + newPoint) / 2, 0.1)
if valid then
for m = 1, #sides do
local sideStart, sideEnd = sides[m][1], sides[m][2]
local bool, d, d2 = glm.segment.intersectsSegment(point, newPoint, sides[m][1], sides[m][2])
if d > 0.001 and d < 0.999 and d2 > 0.001 and d2 < 0.999 then
valid = false
break
2022-04-29 00:41:21 +10:00
end
end
end
if valid then
horizontals[i][#horizontals[i] + 1] = newPoint
sides[j][#sides[j] + 1] = newPoint
points[newPoint] = {side = j, horizontal = i, uses = 0}
break
2022-04-29 00:41:21 +10:00
end
end
end
end
end
local function up(a, b)
2022-04-29 00:41:21 +10:00
return a.y > b.y
end
local function down(a, b)
2022-04-29 00:41:21 +10:00
return a.y < b.y
end
local function right(a, b)
return a.x > b.x
end
local function left(a, b)
return a.x < b.x
end
2022-04-29 00:41:21 +10:00
for i = 1, #sides do
local side = sides[i]
2022-04-29 00:41:21 +10:00
local direction = side[1].y - side[2].y
direction = direction > 0 and up or down
2022-04-29 00:41:21 +10:00
table.sort(side, direction)
2022-04-29 00:41:21 +10:00
for j = 1, #side - 1 do
local a, b = side[j], side[j + 1]
local aData, bData = points[a], points[b]
local aPos, bPos
if aData.horizontal ~= bData.horizontal then
local aHorizontal, bHorizontal = horizontals[aData.horizontal], horizontals[bData.horizontal]
local c, d
if aHorizontal[2] then
local direction = a.x - (a.x ~= aHorizontal[1].x and aHorizontal[1].x or aHorizontal[2].x)
direction = direction > 0 and right or left
table.sort(aHorizontal, direction)
for l = 1, #aHorizontal do
if a == aHorizontal[l] then
aPos = l
elseif c and aPos then
break
2022-04-29 00:41:21 +10:00
else
c = aHorizontal[l]
2022-04-29 00:41:21 +10:00
end
end
end
if bHorizontal[2] then
local direction = b.x - (b.x ~= bHorizontal[1].x and bHorizontal[1].x or bHorizontal[2].x)
direction = direction > 0 and right or left
table.sort(bHorizontal, direction)
for l = 1, #bHorizontal do
if b == bHorizontal[l] then
bPos = l
elseif bPos and d then
break
2022-04-29 00:41:21 +10:00
else
d = bHorizontal[l]
2022-04-29 00:41:21 +10:00
end
end
end
if aData.uses < 2 then
if c and d then
if points[c].side ~= points[d].side then
local done
for l = aPos > 1 and aPos - 1 or 1, aPos > #aHorizontal and aPos + 1 or #aHorizontal do
c = aHorizontal[l]
if c ~= a then
for m = bPos > 1 and bPos - 1 or 1, bPos > #bHorizontal and bPos + 1 or #bHorizontal do
d = bHorizontal[m]
local sideDifference = points[c].side - points[d].side
if d ~= b and sideDifference >= -1 and sideDifference <= 1 then
done = true
break
end
end
end
if done then break end
2022-04-29 00:41:21 +10:00
end
end
c = polygon.contains(polygon, (a + c) / 2, 0.1) and c or nil
d = polygon.contains(polygon, (b + d) / 2, 0.1) and d or nil
2022-04-29 00:41:21 +10:00
end
if c and not d then
for l = aPos > 1 and aPos - 1 or 1, aPos < #aHorizontal and aPos + 1 or #aHorizontal do
c = aHorizontal[l]
if c and c ~= a then
local sideDifference = bData.side - points[c].side
if sideDifference >= -1 and sideDifference <= 1 then
break
end
end
2022-04-29 00:41:21 +10:00
end
elseif d and not c then
for l = bPos > 1 and bPos - 1 or 1, bPos < #bHorizontal and bPos + 1 or #bHorizontal do
d = aHorizontal[l]
if d and d ~= b then
local sideDifference = aData.side - points[d].side
if sideDifference >= -1 and sideDifference <= 1 then
break
end
2022-04-29 00:41:21 +10:00
end
end
end
if c or d then
local t = {a, b, c, d}
nTriangles = #triangles
triangles[nTriangles + 1], triangles[nTriangles + 2] = makeTriangles(t)
if c and d then
for i = 1, #t do
points[t[i]].uses += 1
end
else
for k, v in pairs(t) do
points[v].uses += 2
end
end
end
2022-04-29 00:41:21 +10:00
end
else
aData.uses += 1
bData.uses += 1
2022-04-29 00:41:21 +10:00
end
end
end
return triangles
end
local function removeZone(self)
2022-05-07 11:47:39 +10:00
Zones[self.id] = nil
end
2022-04-25 21:33:56 +10:00
local inside = {}
local insideCount
local tick
CreateThread(function()
while true do
local coords = GetEntityCoords(cache.ped)
2022-04-25 21:33:56 +10:00
table.wipe(inside)
insideCount = 0
2022-05-07 11:47:39 +10:00
for _, zone in pairs(Zones) do
local contains = zone:contains(coords)
zone.distance = #(zone.coords - coords)
2022-04-25 21:33:56 +10:00
if contains then
if zone.onEnter and not zone.insideZone then
zone:onEnter()
end
2022-04-25 21:33:56 +10:00
if zone.inside then
insideCount += 1
inside[insideCount] = zone
end
if not zone.insideZone then
2022-04-25 21:33:56 +10:00
zone.insideZone = true
end
elseif zone.insideZone then
zone.insideZone = false
2022-04-25 21:33:56 +10:00
if zone.onExit then
zone:onExit()
end
end
if zone.debug then
insideCount += 1
inside[insideCount] = zone
end
end
if not tick then
if insideCount > 0 then
tick = SetInterval(function()
for i = 1, insideCount do
local zone = inside[i]
if zone.debug then
if zone.inside then zone:inside() end
zone:debug()
elseif zone.insideZone then
zone:inside()
end
end
end)
end
elseif insideCount == 0 then
tick = ClearInterval(tick)
end
Wait(300)
end
end)
local DrawLine = DrawLine
local DrawPoly = DrawPoly
local function debugPoly(self)
for i = 1, #self.triangles do
local triangle = self.triangles[i]
DrawPoly(triangle[1].x, triangle[1].y, triangle[1].z, triangle[2].x, triangle[2].y, triangle[2].z, triangle[3].x, triangle[3].y, triangle[3].z, 255, 42, 24, 100)
DrawPoly(triangle[2].x, triangle[2].y, triangle[2].z, triangle[1].x, triangle[1].y, triangle[1].z, triangle[3].x, triangle[3].y, triangle[3].z, 255, 42, 24, 100)
2022-04-27 17:13:26 +10:00
end
for i = 1, #self.polygon do
local thickness = vec(0, 0, self.thickness / 2)
local a = self.polygon[i] + thickness
local b = self.polygon[i] - thickness
local c = (self.polygon[i + 1] or self.polygon[1]) + thickness
local d = (self.polygon[i + 1] or self.polygon[1]) - thickness
DrawLine(a.x, a.y, a.z, b.x, b.y, b.z, 255, 42, 24, 225)
DrawLine(a.x, a.y, a.z, c.x, c.y, c.z, 255, 42, 24, 225)
DrawLine(b.x, b.y, b.z, d.x, d.y, d.z, 255, 42, 24, 225)
end
2022-04-27 17:13:26 +10:00
end
2022-05-06 14:28:45 +10:00
local function debugSphere(self)
2022-05-10 15:29:07 +10:00
DrawMarker(28, self.coords.x, self.coords.y, self.coords.z, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, self.radius, self.radius, self.radius, 255, 42, 24, 100, false, false, false, true, false, false, false)
2022-05-06 14:28:45 +10:00
end
2022-04-27 17:09:32 +10:00
local glm_polygon_contains = glm.polygon.contains
local function contains(self, coords)
2022-05-14 12:34:12 +10:00
return glm_polygon_contains(self.polygon, coords, self.thickness / 4)
end
2022-05-06 14:28:45 +10:00
local function insideSphere(self, coords)
return #(self.coords - coords) < self.radius
2022-04-27 17:09:32 +10:00
end
return {
poly = function(data)
2022-05-07 11:47:39 +10:00
data.id = #Zones + 1
data.thickness = data.thickness or 4
2022-04-25 21:33:56 +10:00
data.polygon = glm.polygon.new(data.points)
2022-05-07 11:19:27 +10:00
data.coords = data.polygon:centroid()
data.remove = removeZone
2022-04-27 17:09:32 +10:00
data.contains = contains
if data.debug then
data.triangles = getTriangles(data.polygon)
data.debug = debugPoly
end
2022-05-07 11:47:39 +10:00
Zones[data.id] = data
2022-04-26 23:06:23 +10:00
return data
end,
2022-04-26 23:06:23 +10:00
box = function(data)
2022-05-07 11:47:39 +10:00
data.id = #Zones + 1
data.size = data.size and data.size / 2 or vec3(2)
data.thickness = data.size.z * 2 or 4
2022-04-27 17:11:36 +10:00
data.rotation = quat(data.rotation or 0, vec3(0, 0, 1))
data.polygon = (data.rotation * glm.polygon.new({
vec3(data.size.x, data.size.y, 0),
vec3(-data.size.x, data.size.y, 0),
vec3(-data.size.x, -data.size.y, 0),
vec3(data.size.x, -data.size.y, 0),
2022-05-07 11:19:27 +10:00
}) + data.coords)
2022-04-26 23:06:23 +10:00
data.remove = removeZone
2022-04-27 17:09:32 +10:00
data.contains = contains
2022-04-26 23:06:23 +10:00
if data.debug then
data.triangles = {makeTriangles({data.polygon[1], data.polygon[2], data.polygon[4], data.polygon[3]})}
data.debug = debugPoly
end
2022-05-07 11:47:39 +10:00
Zones[data.id] = data
2022-04-25 21:33:56 +10:00
return data
2022-05-06 14:28:45 +10:00
end,
sphere = function(data)
2022-05-07 11:47:39 +10:00
data.id = #Zones + 1
2022-05-06 14:28:45 +10:00
data.radius = (data.radius or 2) + 0.0
data.remove = removeZone
data.contains = insideSphere
if data.debug then
data.debug = debugSphere
end
2022-05-07 11:47:39 +10:00
Zones[data.id] = data
2022-05-06 14:28:45 +10:00
return data
end,
}