mirror of
				https://github.com/Ukendio/jecs.git
				synced 2025-11-04 02:49:18 +00:00 
			
		
		
		
	Add entity visualiser
	
		
			
	
		
	
	
		
	
		
			Some checks are pending
		
		
	
	
	
				
					
				
			
		
			Some checks are pending
		
		
	
	
This commit is contained in:
		
							parent
							
								
									d15266b6d5
								
							
						
					
					
						commit
						de8e263828
					
				
					 6 changed files with 123 additions and 72 deletions
				
			
		
							
								
								
									
										4
									
								
								.luaurc
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								.luaurc
									
									
									
									
									
								
							| 
						 | 
				
			
			@ -1,9 +1,9 @@
 | 
			
		|||
{
 | 
			
		||||
    "aliases": {
 | 
			
		||||
        "jecs": "jecs",
 | 
			
		||||
        "testkit": "test/testkit",
 | 
			
		||||
        "testkit": "tools/testkit",
 | 
			
		||||
        "mirror": "mirror",
 | 
			
		||||
        "tools": "tools"
 | 
			
		||||
        "tools": "tools",
 | 
			
		||||
    },
 | 
			
		||||
    "languageMode": "strict"
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,4 +1,6 @@
 | 
			
		|||
local jecs = require("@jecs")
 | 
			
		||||
local pair = jecs.pair
 | 
			
		||||
local ChildOf = jecs.ChildOf
 | 
			
		||||
local lifetime_tracker_add = require("@tools/lifetime_tracker")
 | 
			
		||||
local world = lifetime_tracker_add(jecs.world())
 | 
			
		||||
world:print_snapshot()
 | 
			
		||||
| 
						 | 
				
			
			@ -8,13 +10,15 @@ world:delete(e)
 | 
			
		|||
 | 
			
		||||
world:print_snapshot()
 | 
			
		||||
local e2 = world:entity()
 | 
			
		||||
world:add(e2, pair(ChildOf, e1))
 | 
			
		||||
local e3 = world:entity()
 | 
			
		||||
world:add(e3, pair(ChildOf, e1))
 | 
			
		||||
world:print_snapshot()
 | 
			
		||||
world:delete(e1)
 | 
			
		||||
world:delete(e2)
 | 
			
		||||
world:delete(e3)
 | 
			
		||||
world:print_snapshot()
 | 
			
		||||
world:print_entities()
 | 
			
		||||
world:print_entity_index()
 | 
			
		||||
world:entity()
 | 
			
		||||
world:entity()
 | 
			
		||||
world:print_snapshot()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										33
									
								
								tools/ansi.luau
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								tools/ansi.luau
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,33 @@
 | 
			
		|||
return {
 | 
			
		||||
	white_underline = function(s: any)
 | 
			
		||||
		return `\27[1;4m{s}\27[0m`
 | 
			
		||||
	end,
 | 
			
		||||
 | 
			
		||||
	white = function(s: any)
 | 
			
		||||
		return `\27[37;1m{s}\27[0m`
 | 
			
		||||
	end,
 | 
			
		||||
 | 
			
		||||
	green = function(s: any)
 | 
			
		||||
		return `\27[32;1m{s}\27[0m`
 | 
			
		||||
	end,
 | 
			
		||||
 | 
			
		||||
	red = function(s: any)
 | 
			
		||||
		return `\27[31;1m{s}\27[0m`
 | 
			
		||||
	end,
 | 
			
		||||
 | 
			
		||||
	yellow = function(s: any)
 | 
			
		||||
		return `\27[33;1m{s}\27[0m`
 | 
			
		||||
	end,
 | 
			
		||||
 | 
			
		||||
	red_highlight = function(s: any)
 | 
			
		||||
		return `\27[41;1;30m{s}\27[0m`
 | 
			
		||||
	end,
 | 
			
		||||
 | 
			
		||||
	green_highlight = function(s: any)
 | 
			
		||||
		return `\27[42;1;30m{s}\27[0m`
 | 
			
		||||
	end,
 | 
			
		||||
 | 
			
		||||
	gray = function(s: any)
 | 
			
		||||
		return `\27[30;1m{s}\27[0m`
 | 
			
		||||
	end,
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										50
									
								
								tools/entity_visualiser.luau
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								tools/entity_visualiser.luau
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,50 @@
 | 
			
		|||
local jecs = require("@jecs")
 | 
			
		||||
local ECS_GENERATION = jecs.ECS_GENERATION
 | 
			
		||||
local ECS_ID = jecs.ECS_ID
 | 
			
		||||
local ansi = require("@tools/ansi")
 | 
			
		||||
 | 
			
		||||
local function pe(e: any)
 | 
			
		||||
	local gen = ECS_GENERATION(e)
 | 
			
		||||
	return ansi.green(`e{ECS_ID(e)}`)..ansi.yellow(`v{gen}`)
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
local function name(world: jecs.World, id: any)
 | 
			
		||||
	return world:get(id, jecs.Name) or `${id}`
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
local function components(world: jecs.World, entity: any)
 | 
			
		||||
	local r = jecs.entity_index_try_get(world.entity_index, entity)
 | 
			
		||||
	if not r then
 | 
			
		||||
		return false
 | 
			
		||||
	end
 | 
			
		||||
 | 
			
		||||
	local archetype = r.archetype
 | 
			
		||||
	local row = r.row
 | 
			
		||||
	print(`Entity {pe(entity)}`)
 | 
			
		||||
	print("-----------------------------------------------------")
 | 
			
		||||
	for i, column in archetype.columns do
 | 
			
		||||
		local component = archetype.types[i]
 | 
			
		||||
		local n
 | 
			
		||||
		if jecs.IS_PAIR(component) then
 | 
			
		||||
			n = `({name(world, jecs.pair_first(world, component))}, {name(world, jecs.pair_second(world, component))})`
 | 
			
		||||
		else
 | 
			
		||||
			n = name(world, component)
 | 
			
		||||
		end
 | 
			
		||||
		local data = column[row] or "TAG"
 | 
			
		||||
		print(`| {n} | {data} |`)
 | 
			
		||||
	end
 | 
			
		||||
	print("-----------------------------------------------------")
 | 
			
		||||
	return true
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
local world = jecs.world()
 | 
			
		||||
local A = world:component()
 | 
			
		||||
world:set(A, jecs.Name, "A")
 | 
			
		||||
local e = world:entity()
 | 
			
		||||
world:set(e, A, true)
 | 
			
		||||
components(world, e)
 | 
			
		||||
 | 
			
		||||
return {
 | 
			
		||||
	components = components,
 | 
			
		||||
	prettify = pe
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -4,70 +4,19 @@ local ECS_ID = jecs.ECS_ID
 | 
			
		|||
local __ = jecs.Wildcard
 | 
			
		||||
local pair = jecs.pair
 | 
			
		||||
 | 
			
		||||
local testkit = require("@testkit")
 | 
			
		||||
local BENCH, START = testkit.benchmark()
 | 
			
		||||
 | 
			
		||||
local it = testkit.test()
 | 
			
		||||
local TEST, CASE = it.TEST, it.CASE
 | 
			
		||||
local CHECK, FINISH = it.CHECK, it.FINISH
 | 
			
		||||
local SKIP, FOCUS = it.SKIP, it.FOCUS
 | 
			
		||||
local CHECK_EXPECT_ERR = it.CHECK_EXPECT_ERR
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
local c = {
 | 
			
		||||
	white_underline = function(s: any)
 | 
			
		||||
		return `\27[1;4m{s}\27[0m`
 | 
			
		||||
	end,
 | 
			
		||||
 | 
			
		||||
	white = function(s: any)
 | 
			
		||||
		return `\27[37;1m{s}\27[0m`
 | 
			
		||||
	end,
 | 
			
		||||
 | 
			
		||||
	green = function(s: any)
 | 
			
		||||
		return `\27[32;1m{s}\27[0m`
 | 
			
		||||
	end,
 | 
			
		||||
 | 
			
		||||
	red = function(s: any)
 | 
			
		||||
		return `\27[31;1m{s}\27[0m`
 | 
			
		||||
	end,
 | 
			
		||||
 | 
			
		||||
	yellow = function(s: any)
 | 
			
		||||
		return `\27[33;1m{s}\27[0m`
 | 
			
		||||
	end,
 | 
			
		||||
 | 
			
		||||
	red_highlight = function(s: any)
 | 
			
		||||
		return `\27[41;1;30m{s}\27[0m`
 | 
			
		||||
	end,
 | 
			
		||||
 | 
			
		||||
	green_highlight = function(s: any)
 | 
			
		||||
		return `\27[42;1;30m{s}\27[0m`
 | 
			
		||||
	end,
 | 
			
		||||
 | 
			
		||||
	gray = function(s: any)
 | 
			
		||||
		return `\27[30;1m{s}\27[0m`
 | 
			
		||||
	end,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
local function pe(e: any)
 | 
			
		||||
	local gen = ECS_GENERATION(e)
 | 
			
		||||
	return c.green(`e{ECS_ID(e)}`)..c.yellow(`v{gen}`)
 | 
			
		||||
end
 | 
			
		||||
local pe = require("@tools/entity_visualiser").prettify
 | 
			
		||||
 | 
			
		||||
function print_centered_entity(entity, width: number)
 | 
			
		||||
    local entity_str = tostring(entity)
 | 
			
		||||
    local entity_length = #entity_str
 | 
			
		||||
 | 
			
		||||
    -- Calculate total padding needed to center the string
 | 
			
		||||
    local padding_total = width - 2 - entity_length  -- Subtract 2 for the `| |` characters
 | 
			
		||||
    local padding_total = width - 2 - entity_length
 | 
			
		||||
 | 
			
		||||
    -- Calculate padding for the left and right
 | 
			
		||||
    local padding_left = math.floor(padding_total / 2)
 | 
			
		||||
    local padding_right = padding_total - padding_left
 | 
			
		||||
 | 
			
		||||
    -- Build the centered string
 | 
			
		||||
    local centered_str = string.rep(" ", padding_left) .. entity_str .. string.rep(" ", padding_right)
 | 
			
		||||
 | 
			
		||||
    -- Print with pipes around the centered string
 | 
			
		||||
    print("|" .. centered_str .. "|")
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -82,36 +31,51 @@ local function lifetime_tracker_add(world: jecs.World)
 | 
			
		|||
 | 
			
		||||
	local w = setmetatable({}, { __index = world })
 | 
			
		||||
	w.delete = function(self, e)
 | 
			
		||||
		print("Entity deleted:", e)
 | 
			
		||||
 | 
			
		||||
		for child in world:each(pair(__, e)) do
 | 
			
		||||
		print(`*deleting {pe(e)}`)
 | 
			
		||||
 | 
			
		||||
		local idr_t = component_index[pair(__, e)]
 | 
			
		||||
		if idr_t then
 | 
			
		||||
			print(`{pe(e)} has the following dependencies:`)
 | 
			
		||||
			for archetype_id in idr_t.cache do
 | 
			
		||||
				local archetype = world.archetypes[archetype_id]
 | 
			
		||||
				local entities = {}
 | 
			
		||||
				for _, dependency in archetype.entities do
 | 
			
		||||
					print(`  {pe(dependency)}`)
 | 
			
		||||
				end
 | 
			
		||||
			end
 | 
			
		||||
		end
 | 
			
		||||
		return world_delete(world, e)
 | 
			
		||||
 | 
			
		||||
		world_delete(world, e)
 | 
			
		||||
		print(`*deleted {pe(e)}`)
 | 
			
		||||
	end
 | 
			
		||||
	w.entity = function(self)
 | 
			
		||||
		local e = world_entity(world)
 | 
			
		||||
		print("Entity created:", pe(e))
 | 
			
		||||
		print(`*created {pe(e)}`)
 | 
			
		||||
		return e
 | 
			
		||||
	end
 | 
			
		||||
	w.print_entities = function(self)
 | 
			
		||||
	w.print_entity_index = function(self)
 | 
			
		||||
		local max_id = entity_index.max_id
 | 
			
		||||
		local alive_count = entity_index.alive_count
 | 
			
		||||
		local alive = table.move(dense_array, 1+jecs.Rest::any, alive_count, 1, {})
 | 
			
		||||
		local dead = table.move(dense_array, alive_count + 1, max_id, 1, {})
 | 
			
		||||
 | 
			
		||||
		local sep = "|--------|"
 | 
			
		||||
		print("|-alive--|")
 | 
			
		||||
		for i = 1, #alive do
 | 
			
		||||
			local e = pe(alive[i])
 | 
			
		||||
			print_centered_entity(e, 32)
 | 
			
		||||
			print(sep)
 | 
			
		||||
		if #alive > 0 then
 | 
			
		||||
			print("|-alive--|")
 | 
			
		||||
			for i = 1, #alive do
 | 
			
		||||
				local e = pe(alive[i])
 | 
			
		||||
				print_centered_entity(e, 32)
 | 
			
		||||
				print(sep)
 | 
			
		||||
			end
 | 
			
		||||
			print("\n")
 | 
			
		||||
		end
 | 
			
		||||
		print("\n")
 | 
			
		||||
		print("|--dead--|")
 | 
			
		||||
		for i = 1, #dead do
 | 
			
		||||
			print_centered_entity(pe(dead[i]), 32)
 | 
			
		||||
			print(sep)
 | 
			
		||||
 | 
			
		||||
		if #dead > 0 then
 | 
			
		||||
			print("|--dead--|")
 | 
			
		||||
			for i = 1, #dead do
 | 
			
		||||
				print_centered_entity(pe(dead[i]), 32)
 | 
			
		||||
				print(sep)
 | 
			
		||||
			end
 | 
			
		||||
		end
 | 
			
		||||
	end
 | 
			
		||||
	local timelines = {}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue