Skip to content

Commit

Permalink
Rework ProximityQuery API
Browse files Browse the repository at this point in the history
- Remove storage of created proximity tests (callback function will prevent GC cleanup)
- Simplify and rename API to create a single object
- All created proximity queries are unique (little to no benefit in "sharing" queries due to large parameter space)
  • Loading branch information
sturnclaw committed Oct 17, 2023
1 parent 24f62d3 commit 32cea10
Showing 1 changed file with 17 additions and 59 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,12 @@
-- Licensed under the terms of the GPL v3. See licenses/GPL-3.txt

local Engine = require 'Engine'
local Event = require 'Event'
local Space = require 'Space'
local Timer = require 'Timer'
local utils = require 'utils'
local Game = require 'Game'

---@class Modules.Common.ProximityTest
local ProximityTest = {}

---@type table<Body, table<string, Modules.Common.ProximityTest.Context>>
local activeTests = utils.automagic()
local ProximityQuery = {}

-- ─── Context ─────────────────────────────────────────────────────────────────

Expand All @@ -25,15 +20,14 @@ local bodyListMt = {
__mode = "k"
}

---@class Modules.Common.ProximityTest.Context
---@class ProximityQuery.Context
---@field New fun(body, dist, interval, type): self
---@field body Body
---@field dist number
local Context = utils.class 'Modules.Common.ProximityTest.Context'
local Context = utils.class 'ProximityQuery.Context'

function Context:Constructor(key, body, dist, type)
function Context:Constructor(body, dist, type)
self.bodies = setmetatable({}, bodyListMt)
self.key = key
self.body = body
self.dist = dist
self.filter = type
Expand All @@ -44,52 +38,28 @@ function Context:Constructor(key, body, dist, type)
end

function Context:Cancel()
activeTests[self.body][self.key] = nil
self.iter = nil
end

---@param fn fun(ctx: Modules.Common.ProximityTest.Context, enter: Body)
---@param fn fun(ctx: ProximityQuery.Context, enter: Body)
function Context:SetBodyEnter(fn)
self.onBodyEnter = fn
return self
end

---@param fn fun(ctx: Modules.Common.ProximityTest.Context, leave: Body)
---@param fn fun(ctx: ProximityQuery.Context, leave: Body)
function Context:SetBodyLeave(fn)
self.onBodyLeave = fn
return self
end

-- ─── Proximity Test ──────────────────────────────────────────────────────────

-- Class: ProximityTest
-- Class: ProximityQuery
--
-- This class provides a helper utility to allow using Space.GetBodiesNear() in
-- an efficient manner, providing an event-based API when bodies enter or leave
-- a user-specified relevancy range of the reference body.

local function makeTestKey(dist, interval, type)
return string.format("%d:%d:%s", dist, interval, type or "Body")
end

-- Function: GetTest
--
-- Retrieves the Context object for an active proximity test currently queued
--
-- Parameters:
--
-- body - the reference body object of the proximity test
-- key - the key value retrieved from the Context returned by RegisterTest
--
-- Returns:
--
-- context - the proximity test context object for the registered test
--
function ProximityTest:GetTest(body, key)
return activeTests[body][key]
end

-- Function: RegisterTest
-- Function: CreateQuery
--
-- Register a new periodic proximity test relative to the given body
--
Expand All @@ -107,14 +77,9 @@ end
--
-- context - the context object for the registered test
--
function ProximityTest:RegisterTest(body, dist, interval, type, overlap)
local key = makeTestKey(dist, interval, type)
if activeTests[body][key] then return activeTests[body][key] end

local context = Context.New(key, body, dist, type)
local cb = self:MakeCallback(context)

activeTests[body][key] = context
function ProximityQuery.CreateQuery(body, dist, interval, type, overlap)
local context = Context.New(body, dist, type)
local cb = ProximityQuery.MakeCallback(context)

-- Queue the start of the timer at a random timestamp inside the first interval period
-- This provides natural load balancing for large numbers of callbacks created on the same frame
Expand All @@ -137,11 +102,12 @@ function ProximityTest:RegisterTest(body, dist, interval, type, overlap)
end

---@private
---@param context Modules.Common.ProximityTest.Context
function ProximityTest:MakeCallback(context)
---@param context ProximityQuery.Context
function ProximityQuery.MakeCallback(context)
return function()
-- Callback has been cancelled
if not context.iter then
-- Callback has been cancelled or query body no longer exists,
-- stop ticking this query
if not context.iter or not context.body:exists() then
return true
end

Expand Down Expand Up @@ -170,12 +136,4 @@ function ProximityTest:MakeCallback(context)
end
end

Event.Register("onGameStart", function()
activeTests = utils.automagic()
end)

Event.Register("onGameEnd", function()
activeTests = utils.automagic()
end)

return ProximityTest
return ProximityQuery

0 comments on commit 32cea10

Please sign in to comment.