fix(esx_lib/points): keep the points loop alive when a callback errors

Every point from every resource is served by one shared thread, and the enter, leave
and inside callbacks are all invoked bare. A Lua error in any one of them terminates
that coroutine, and nothing restarts it - startLoop only runs once, from the spawn
handler in es_extended.

So a single faulty third party resource takes down point detection for the whole
client. Shops, garages and job markers stop reacting, with no hint beyond one stack
trace, until the player reconnects.

inside is the worst of the three because it runs every frame while the player stands
in the point, so it is also dropped from insidePoints once it errors. Otherwise the
guard would turn a dead thread into a console flood at framerate. enter and leave only
fire on a transition, so they stay registered.

Measured in game on artifact 25770, with a healthy point, a point whose enter raises
and a point whose inside raises, all created while standing on them:

  before: the healthy point fired enter, then the broken one raised at points/client.lua
          and after that nothing happened at all - no leave when walking away, and
          points created afterwards never fired enter either, the thread was gone
  after:  both failures are logged against the owning point and resource, all three
          points fired leave when walking away, and points created afterwards worked
          normally. The inside failure printed once rather than every frame.

The runtime already prints the error and its stack, so the added line only names the
point and the resource it came from.
This commit is contained in:
Selt
2026-07-27 16:18:57 +02:00
parent ca597cf6f4
commit 9a248406b0
+9 -6
View File
@@ -50,8 +50,11 @@ function xLib.points.startLoop()
while true do
local coords = GetEntityCoords(PlayerPedId())
for _, point in pairs(insidePoints) do
point.inside(#(coords - point.coords))
for handle, point in pairs(insidePoints) do
if not pcall(point.inside, #(coords - point.coords)) then
insidePoints[handle] = nil
print(("[^1ERROR^7] point ^5%s^7 from ^5%s^7 errored on inside"):format(handle, point.resource))
end
end
local now = GetGameTimer()
@@ -63,8 +66,8 @@ function xLib.points.startLoop()
if not point.nearby then
point.nearby = true
if point.enter then
point.enter()
if point.enter and not pcall(point.enter) then
print(("[^1ERROR^7] point ^5%s^7 from ^5%s^7 errored on enter"):format(handle, point.resource))
end
if point.inside then
@@ -74,8 +77,8 @@ function xLib.points.startLoop()
elseif point.nearby then
point.nearby = false
if point.leave then
point.leave()
if point.leave and not pcall(point.leave) then
print(("[^1ERROR^7] point ^5%s^7 from ^5%s^7 errored on leave"):format(handle, point.resource))
end
insidePoints[handle] = nil