Extract invasive debugging from tiny
Debugging now uses more injection-based techniques. It may be slightly slower when enabled, but will have slightly *less* impact when disabled. In fact, the only debugging-specific code now in tiny proper should be tiny._wrapAddEntity(), which is never called within the library itself.
This commit is contained in:
parent
69bf5b60aa
commit
7cd6bcc090
45
lib/tiny.lua
45
lib/tiny.lua
|
@ -478,8 +478,6 @@ end
|
||||||
--- Adds an Entity to the world.
|
--- Adds an Entity to the world.
|
||||||
-- Also call this on Entities that have changed Components such that they
|
-- Also call this on Entities that have changed Components such that they
|
||||||
-- match different Filters. Returns the Entity.
|
-- match different Filters. Returns the Entity.
|
||||||
-- TODO: Track entity age when debugging?
|
|
||||||
-- TODO: Track debugName field when debugging?
|
|
||||||
function tiny.addEntity(world, entity)
|
function tiny.addEntity(world, entity)
|
||||||
local e2c = world.entitiesToChange
|
local e2c = world.entitiesToChange
|
||||||
e2c[#e2c + 1] = entity
|
e2c[#e2c + 1] = entity
|
||||||
|
@ -487,37 +485,18 @@ function tiny.addEntity(world, entity)
|
||||||
end
|
end
|
||||||
tiny_addEntity = tiny.addEntity
|
tiny_addEntity = tiny.addEntity
|
||||||
|
|
||||||
if tinyTrackEntityAges then
|
function tiny._wrapAddEntity(f)
|
||||||
local wrapped = tiny.addEntity
|
local wrapped = tiny.addEntity
|
||||||
function tiny.addEntity(world, entity)
|
function tiny.addEntity(world, entity)
|
||||||
local added = wrapped(world, entity)
|
local ret = wrapped(world, entity)
|
||||||
added[ENTITY_INIT_MS] = getCurrentTimeMilliseconds()
|
f(world, entity)
|
||||||
return added
|
return ret
|
||||||
end
|
|
||||||
tiny_addEntity = tiny.addEntity
|
|
||||||
end
|
|
||||||
|
|
||||||
if tinyWarnWhenNonDataOnEntities then
|
|
||||||
local wrapped = tiny.addEntity
|
|
||||||
function tiny.addEntity(world, entity)
|
|
||||||
local added = wrapped(world, entity)
|
|
||||||
local nonDataType = checkForNonData(added)
|
|
||||||
if nonDataType then
|
|
||||||
print("Detected non-data type '" .. nonDataType .. "' on entity")
|
|
||||||
end
|
|
||||||
return added
|
|
||||||
end
|
end
|
||||||
tiny_addEntity = tiny.addEntity
|
tiny_addEntity = tiny.addEntity
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Adds a System to the world. Returns the System.
|
--- Adds a System to the world. Returns the System.
|
||||||
function tiny.addSystem(world, system)
|
function tiny.addSystem(world, system)
|
||||||
if tinyLogSystemChanges then
|
|
||||||
print("addSystem '" .. (system.name or "unnamed") .. "'")
|
|
||||||
end
|
|
||||||
if system.world ~= nil then
|
|
||||||
error("System " .. system.name .. " already belongs to a World.")
|
|
||||||
end
|
|
||||||
local s2a = world.systemsToAdd
|
local s2a = world.systemsToAdd
|
||||||
s2a[#s2a + 1] = system
|
s2a[#s2a + 1] = system
|
||||||
system.world = world
|
system.world = world
|
||||||
|
@ -552,9 +531,6 @@ tiny_removeEntity = tiny.removeEntity
|
||||||
|
|
||||||
--- Removes a System from the world. Returns the System.
|
--- Removes a System from the world. Returns the System.
|
||||||
function tiny.removeSystem(world, system)
|
function tiny.removeSystem(world, system)
|
||||||
if tinyLogSystemChanges then
|
|
||||||
print("removeSystem '" .. (system.name or "unnamed") .. "'")
|
|
||||||
end
|
|
||||||
if system.world ~= world then
|
if system.world ~= world then
|
||||||
error("System " .. system.name .. " does not belong to this World.")
|
error("System " .. system.name .. " does not belong to this World.")
|
||||||
end
|
end
|
||||||
|
@ -616,10 +592,6 @@ function tiny_manageSystems(world)
|
||||||
end
|
end
|
||||||
s2r[i] = nil
|
s2r[i] = nil
|
||||||
|
|
||||||
-- Clean up System
|
|
||||||
if tinyLogSystemChanges then
|
|
||||||
print("Cleaning up system '" .. (system.name or "unnamed") .. "'")
|
|
||||||
end
|
|
||||||
system.world = nil
|
system.world = nil
|
||||||
system.entities = nil
|
system.entities = nil
|
||||||
system.indices = nil
|
system.indices = nil
|
||||||
|
@ -814,7 +786,6 @@ function tiny.update(world, dt, filter)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local tinyLogSystemUpdateTime = tinyLogSystemUpdateTime
|
|
||||||
-- Iterate through Systems IN ORDER
|
-- Iterate through Systems IN ORDER
|
||||||
for i = 1, #systems do
|
for i = 1, #systems do
|
||||||
local system = systems[i]
|
local system = systems[i]
|
||||||
|
@ -822,7 +793,6 @@ function tiny.update(world, dt, filter)
|
||||||
-- Update Systems that have an update method (most Systems)
|
-- Update Systems that have an update method (most Systems)
|
||||||
local update = system.update
|
local update = system.update
|
||||||
if update then
|
if update then
|
||||||
local currentMs = tinyLogSystemUpdateTime and getCurrentTimeMilliseconds()
|
|
||||||
local interval = system.interval
|
local interval = system.interval
|
||||||
if interval then
|
if interval then
|
||||||
local bufferedTime = (system.bufferedTime or 0) + dt
|
local bufferedTime = (system.bufferedTime or 0) + dt
|
||||||
|
@ -834,18 +804,11 @@ function tiny.update(world, dt, filter)
|
||||||
else
|
else
|
||||||
update(system, dt)
|
update(system, dt)
|
||||||
end
|
end
|
||||||
if tinyLogSystemUpdateTime then
|
|
||||||
local endTimeMs = getCurrentTimeMilliseconds()
|
|
||||||
print(tostring(endTimeMs - currentMs) .. "ms taken to update system '" .. system.name .. "'")
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
system.modified = false
|
system.modified = false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if tinyLogSystemUpdateTime then
|
|
||||||
print("")
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Iterate through Systems IN ORDER AGAIN
|
-- Iterate through Systems IN ORDER AGAIN
|
||||||
for i = 1, #systems do
|
for i = 1, #systems do
|
||||||
|
|
109
tiny-debug.lua
109
tiny-debug.lua
|
@ -1,21 +1,58 @@
|
||||||
tinyTrackEntityAges = false
|
local tiny = require("lib.tiny")
|
||||||
tinyLogSystemUpdateTime = false
|
require("lib.inspect")
|
||||||
tinyLogSystemChanges = false
|
|
||||||
tinyWarnWhenNonDataOnEntities = false
|
|
||||||
|
|
||||||
getCurrentTimeMilliseconds = function()
|
---@class TinyDebug
|
||||||
|
local tinyDebug = {}
|
||||||
|
|
||||||
|
-- TODO: Track some debugName field when debugging?
|
||||||
|
|
||||||
|
local function worldMetaIndex()
|
||||||
|
local worldMetaTable = getmetatable(tiny.world())
|
||||||
|
return worldMetaTable.__index
|
||||||
|
end
|
||||||
|
|
||||||
|
local function getCurrentTimeMilliseconds()
|
||||||
return love.timer.getTime() * 1000
|
return love.timer.getTime() * 1000
|
||||||
end
|
end
|
||||||
|
|
||||||
ENTITY_INIT_MS = { "ENTITY_INIT_MS" }
|
--- Only applies to already-created systems!
|
||||||
if tinyTrackEntityAges then
|
--- Performs a `world:refresh()` to ensure that all added systems are installed.
|
||||||
function tinyGetEntityAgeMs(entity)
|
---@param world World
|
||||||
return entity[ENTITY_INIT_MS]
|
function tinyDebug.logSystemUpdateTime(world)
|
||||||
|
world:refresh()
|
||||||
|
local systems = world.systems
|
||||||
|
for i = 1, #systems do
|
||||||
|
local system = systems[i]
|
||||||
|
local wrappedUpdate = system.update
|
||||||
|
system.update = function(...)
|
||||||
|
local currentMs = getCurrentTimeMilliseconds()
|
||||||
|
local ret = wrappedUpdate(...)
|
||||||
|
local endTimeMs = getCurrentTimeMilliseconds()
|
||||||
|
print(tostring(endTimeMs - currentMs) .. "ms taken to update system '" .. (system.name or i) .. "'")
|
||||||
|
return ret
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if tinyWarnWhenNonDataOnEntities then
|
function tinyDebug.trackEntityAges()
|
||||||
function checkForNonData(e, nested, tableCache)
|
ENTITY_INIT_MS = { "ENTITY_INIT_MS" }
|
||||||
|
-- tiny._trackEntityAges = true
|
||||||
|
|
||||||
|
tiny._wrapAddEntity(function(_, entity)
|
||||||
|
entity[ENTITY_INIT_MS] = getCurrentTimeMilliseconds()
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Throws an error if trackEntityAges() has not been called
|
||||||
|
function tinyDebug.getEntityAgeMs(entity)
|
||||||
|
if ENTITY_INIT_MS == nil then
|
||||||
|
error("trackEntityAges() has not been enabled!")
|
||||||
|
end
|
||||||
|
return entity[ENTITY_INIT_MS]
|
||||||
|
end
|
||||||
|
|
||||||
|
function tinyDebug.warnWhenNonDataOnEntities()
|
||||||
|
local function checkForNonData(e, nested, tableCache)
|
||||||
nested = nested or false
|
nested = nested or false
|
||||||
tableCache = tableCache or {}
|
tableCache = tableCache or {}
|
||||||
|
|
||||||
|
@ -39,4 +76,54 @@ if tinyWarnWhenNonDataOnEntities then
|
||||||
return valType
|
return valType
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
tiny._wrapAddEntity(function(_, entity)
|
||||||
|
local nonDataType = checkForNonData(entity)
|
||||||
|
if nonDataType then
|
||||||
|
print("Detected non-data type '" .. nonDataType .. "' on entity")
|
||||||
|
end
|
||||||
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function tinyDebug.throwOnUnusedEntities()
|
||||||
|
---@return boolean
|
||||||
|
local function entityMatchesASystem(world, entity)
|
||||||
|
local systems = world.systems
|
||||||
|
for i = 1, #systems do
|
||||||
|
local system = systems[i]
|
||||||
|
local filter = system.filter
|
||||||
|
if filter and filter(system, entity) then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
---@return Entity[]
|
||||||
|
local function anyUnmatchedEntities(world)
|
||||||
|
local unmatchedEntities = {}
|
||||||
|
local el = world.entities
|
||||||
|
|
||||||
|
for i = 1, #el do
|
||||||
|
if not entityMatchesASystem(world, el[i]) then
|
||||||
|
unmatchedEntities[#unmatchedEntities + 1] = el[i]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return unmatchedEntities
|
||||||
|
end
|
||||||
|
|
||||||
|
local tinyUpdate = tiny.update
|
||||||
|
worldMetaIndex().update = function(world, dt, filter)
|
||||||
|
local ret = tinyUpdate(world, dt, filter)
|
||||||
|
local ecAll = world:getEntityCount()
|
||||||
|
local unmatchedEntities = anyUnmatchedEntities(world)
|
||||||
|
if #unmatchedEntities ~= 0 then
|
||||||
|
error("UNUSED ENTITY COUNT: " .. #unmatchedEntities .. "/" .. ecAll .. " " .. Inspect(unmatchedEntities, { depth = 2 }))
|
||||||
|
end
|
||||||
|
return ret
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return tinyDebug
|
||||||
|
|
Loading…
Reference in New Issue