mirror of
				https://github.com/Ukendio/jecs.git
				synced 2025-11-03 18:39:19 +00:00 
			
		
		
		
	Add component trait lazily
	
		
			
	
		
	
	
		
	
		
			Some checks failed
		
		
	
	
	
				
					
				
			
		
			Some checks failed
		
		
	
	
This commit is contained in:
		
							parent
							
								
									5de842d144
								
							
						
					
					
						commit
						29a66d92c2
					
				
					 3 changed files with 80 additions and 24 deletions
				
			
		| 
						 | 
					@ -160,6 +160,10 @@ local function monitors_new<T...>(
 | 
				
			||||||
	end
 | 
						end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	local function removed(entity: jecs.Entity, component: jecs.Id)
 | 
						local function removed(entity: jecs.Entity, component: jecs.Id)
 | 
				
			||||||
 | 
							local r = jecs.record(world, entity)
 | 
				
			||||||
 | 
							if not archetypes[r.archetype.id] then
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							end
 | 
				
			||||||
		local EcsOnRemove = jecs.OnRemove :: jecs.Id
 | 
							local EcsOnRemove = jecs.OnRemove :: jecs.Id
 | 
				
			||||||
		if callback ~= nil then
 | 
							if callback ~= nil then
 | 
				
			||||||
			callback(entity, EcsOnRemove)
 | 
								callback(entity, EcsOnRemove)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										88
									
								
								jecs.luau
									
									
									
									
									
								
							
							
						
						
									
										88
									
								
								jecs.luau
									
									
									
									
									
								
							| 
						 | 
					@ -1078,18 +1078,6 @@ local function archetype_traverse_add(
 | 
				
			||||||
	return to
 | 
						return to
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
local function world_component(world: world): i53
 | 
					 | 
				
			||||||
	local id = (world.max_component_id :: number) + 1
 | 
					 | 
				
			||||||
	if id > HI_COMPONENT_ID then
 | 
					 | 
				
			||||||
		-- IDs are partitioned into ranges because component IDs are not nominal,
 | 
					 | 
				
			||||||
		-- so it needs to error when IDs intersect into the entity range.
 | 
					 | 
				
			||||||
		error("Too many components, consider using world:entity() instead to create components.")
 | 
					 | 
				
			||||||
	end
 | 
					 | 
				
			||||||
	world.max_component_id = id
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return id
 | 
					 | 
				
			||||||
end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
local function archetype_fast_delete_last(columns: { Column }, column_count: number)
 | 
					local function archetype_fast_delete_last(columns: { Column }, column_count: number)
 | 
				
			||||||
	for i, column in columns do
 | 
						for i, column in columns do
 | 
				
			||||||
		if column ~= NULL_ARRAY then
 | 
							if column ~= NULL_ARRAY then
 | 
				
			||||||
| 
						 | 
					@ -1327,6 +1315,9 @@ local function query_iter_init(query: QueryInner): () -> (number, ...any)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				entities = archetype.entities
 | 
									entities = archetype.entities
 | 
				
			||||||
				i = #entities
 | 
									i = #entities
 | 
				
			||||||
 | 
									if i == 0 then
 | 
				
			||||||
 | 
										continue
 | 
				
			||||||
 | 
									end
 | 
				
			||||||
				entity = entities[i]
 | 
									entity = entities[i]
 | 
				
			||||||
				columns_map = archetype.columns_map
 | 
									columns_map = archetype.columns_map
 | 
				
			||||||
				a = columns_map[A]
 | 
									a = columns_map[A]
 | 
				
			||||||
| 
						 | 
					@ -1349,6 +1340,9 @@ local function query_iter_init(query: QueryInner): () -> (number, ...any)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				entities = archetype.entities
 | 
									entities = archetype.entities
 | 
				
			||||||
				i = #entities
 | 
									i = #entities
 | 
				
			||||||
 | 
									if i == 0 then
 | 
				
			||||||
 | 
										continue
 | 
				
			||||||
 | 
									end
 | 
				
			||||||
				entity = entities[i]
 | 
									entity = entities[i]
 | 
				
			||||||
				columns_map = archetype.columns_map
 | 
									columns_map = archetype.columns_map
 | 
				
			||||||
				a = columns_map[A]
 | 
									a = columns_map[A]
 | 
				
			||||||
| 
						 | 
					@ -1372,6 +1366,9 @@ local function query_iter_init(query: QueryInner): () -> (number, ...any)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				entities = archetype.entities
 | 
									entities = archetype.entities
 | 
				
			||||||
				i = #entities
 | 
									i = #entities
 | 
				
			||||||
 | 
									if i == 0 then
 | 
				
			||||||
 | 
										continue
 | 
				
			||||||
 | 
									end
 | 
				
			||||||
				entity = entities[i]
 | 
									entity = entities[i]
 | 
				
			||||||
				columns_map = archetype.columns_map
 | 
									columns_map = archetype.columns_map
 | 
				
			||||||
				a = columns_map[A]
 | 
									a = columns_map[A]
 | 
				
			||||||
| 
						 | 
					@ -1396,6 +1393,9 @@ local function query_iter_init(query: QueryInner): () -> (number, ...any)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				entities = archetype.entities
 | 
									entities = archetype.entities
 | 
				
			||||||
				i = #entities
 | 
									i = #entities
 | 
				
			||||||
 | 
									if i == 0 then
 | 
				
			||||||
 | 
										continue
 | 
				
			||||||
 | 
									end
 | 
				
			||||||
				entity = entities[i]
 | 
									entity = entities[i]
 | 
				
			||||||
				columns_map = archetype.columns_map
 | 
									columns_map = archetype.columns_map
 | 
				
			||||||
				a = columns_map[A]
 | 
									a = columns_map[A]
 | 
				
			||||||
| 
						 | 
					@ -1421,6 +1421,9 @@ local function query_iter_init(query: QueryInner): () -> (number, ...any)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				entities = archetype.entities
 | 
									entities = archetype.entities
 | 
				
			||||||
				i = #entities
 | 
									i = #entities
 | 
				
			||||||
 | 
									if i == 0 then
 | 
				
			||||||
 | 
										continue
 | 
				
			||||||
 | 
									end
 | 
				
			||||||
				entity = entities[i]
 | 
									entity = entities[i]
 | 
				
			||||||
				columns_map = archetype.columns_map
 | 
									columns_map = archetype.columns_map
 | 
				
			||||||
				a = columns_map[A]
 | 
									a = columns_map[A]
 | 
				
			||||||
| 
						 | 
					@ -1447,6 +1450,9 @@ local function query_iter_init(query: QueryInner): () -> (number, ...any)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				entities = archetype.entities
 | 
									entities = archetype.entities
 | 
				
			||||||
				i = #entities
 | 
									i = #entities
 | 
				
			||||||
 | 
									if i == 0 then
 | 
				
			||||||
 | 
										continue
 | 
				
			||||||
 | 
									end
 | 
				
			||||||
				entity = entities[i]
 | 
									entity = entities[i]
 | 
				
			||||||
				columns_map = archetype.columns_map
 | 
									columns_map = archetype.columns_map
 | 
				
			||||||
				a = columns_map[A]
 | 
									a = columns_map[A]
 | 
				
			||||||
| 
						 | 
					@ -1474,6 +1480,9 @@ local function query_iter_init(query: QueryInner): () -> (number, ...any)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				entities = archetype.entities
 | 
									entities = archetype.entities
 | 
				
			||||||
				i = #entities
 | 
									i = #entities
 | 
				
			||||||
 | 
									if i == 0 then
 | 
				
			||||||
 | 
										continue
 | 
				
			||||||
 | 
									end
 | 
				
			||||||
				entity = entities[i]
 | 
									entity = entities[i]
 | 
				
			||||||
				columns_map = archetype.columns_map
 | 
									columns_map = archetype.columns_map
 | 
				
			||||||
				a = columns_map[A]
 | 
									a = columns_map[A]
 | 
				
			||||||
| 
						 | 
					@ -1502,6 +1511,9 @@ local function query_iter_init(query: QueryInner): () -> (number, ...any)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				entities = archetype.entities
 | 
									entities = archetype.entities
 | 
				
			||||||
				i = #entities
 | 
									i = #entities
 | 
				
			||||||
 | 
									if i == 0 then
 | 
				
			||||||
 | 
										continue
 | 
				
			||||||
 | 
									end
 | 
				
			||||||
				entity = entities[i]
 | 
									entity = entities[i]
 | 
				
			||||||
				columns_map = archetype.columns_map
 | 
									columns_map = archetype.columns_map
 | 
				
			||||||
				a = columns_map[A]
 | 
									a = columns_map[A]
 | 
				
			||||||
| 
						 | 
					@ -1533,6 +1545,9 @@ local function query_iter_init(query: QueryInner): () -> (number, ...any)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				entities = archetype.entities
 | 
									entities = archetype.entities
 | 
				
			||||||
				i = #entities
 | 
									i = #entities
 | 
				
			||||||
 | 
									if i == 0 then
 | 
				
			||||||
 | 
										continue
 | 
				
			||||||
 | 
									end
 | 
				
			||||||
				entity = entities[i]
 | 
									entity = entities[i]
 | 
				
			||||||
				columns_map = archetype.columns_map
 | 
									columns_map = archetype.columns_map
 | 
				
			||||||
				a = columns_map[A]
 | 
									a = columns_map[A]
 | 
				
			||||||
| 
						 | 
					@ -1700,6 +1715,9 @@ local function query_cached(query: QueryInner)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				entities = archetype.entities
 | 
									entities = archetype.entities
 | 
				
			||||||
				i = #entities
 | 
									i = #entities
 | 
				
			||||||
 | 
									if i == 0 then
 | 
				
			||||||
 | 
										continue
 | 
				
			||||||
 | 
									end
 | 
				
			||||||
				entity = entities[i]
 | 
									entity = entities[i]
 | 
				
			||||||
				columns_map = archetype.columns_map
 | 
									columns_map = archetype.columns_map
 | 
				
			||||||
				a = columns_map[A]
 | 
									a = columns_map[A]
 | 
				
			||||||
| 
						 | 
					@ -1722,6 +1740,9 @@ local function query_cached(query: QueryInner)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				entities = archetype.entities
 | 
									entities = archetype.entities
 | 
				
			||||||
				i = #entities
 | 
									i = #entities
 | 
				
			||||||
 | 
									if i == 0 then
 | 
				
			||||||
 | 
										continue
 | 
				
			||||||
 | 
									end
 | 
				
			||||||
				entity = entities[i]
 | 
									entity = entities[i]
 | 
				
			||||||
				columns_map = archetype.columns_map
 | 
									columns_map = archetype.columns_map
 | 
				
			||||||
				a = columns_map[A]
 | 
									a = columns_map[A]
 | 
				
			||||||
| 
						 | 
					@ -1745,6 +1766,9 @@ local function query_cached(query: QueryInner)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				entities = archetype.entities
 | 
									entities = archetype.entities
 | 
				
			||||||
				i = #entities
 | 
									i = #entities
 | 
				
			||||||
 | 
									if i == 0 then
 | 
				
			||||||
 | 
										continue
 | 
				
			||||||
 | 
									end
 | 
				
			||||||
				entity = entities[i]
 | 
									entity = entities[i]
 | 
				
			||||||
				columns_map = archetype.columns_map
 | 
									columns_map = archetype.columns_map
 | 
				
			||||||
				a = columns_map[A]
 | 
									a = columns_map[A]
 | 
				
			||||||
| 
						 | 
					@ -1769,6 +1793,9 @@ local function query_cached(query: QueryInner)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				entities = archetype.entities
 | 
									entities = archetype.entities
 | 
				
			||||||
				i = #entities
 | 
									i = #entities
 | 
				
			||||||
 | 
									if i == 0 then
 | 
				
			||||||
 | 
										continue
 | 
				
			||||||
 | 
									end
 | 
				
			||||||
				entity = entities[i]
 | 
									entity = entities[i]
 | 
				
			||||||
				columns_map = archetype.columns_map
 | 
									columns_map = archetype.columns_map
 | 
				
			||||||
				a = columns_map[A]
 | 
									a = columns_map[A]
 | 
				
			||||||
| 
						 | 
					@ -1853,6 +1880,10 @@ local function query_cached(query: QueryInner)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				entities = archetype.entities
 | 
									entities = archetype.entities
 | 
				
			||||||
				i = #entities
 | 
									i = #entities
 | 
				
			||||||
 | 
									if i == 0 then
 | 
				
			||||||
 | 
										continue
 | 
				
			||||||
 | 
									end
 | 
				
			||||||
 | 
									entity = entities[i]
 | 
				
			||||||
				columns_map = archetype.columns_map
 | 
									columns_map = archetype.columns_map
 | 
				
			||||||
				a = columns_map[A]
 | 
									a = columns_map[A]
 | 
				
			||||||
				b = columns_map[B]
 | 
									b = columns_map[B]
 | 
				
			||||||
| 
						 | 
					@ -1880,6 +1911,9 @@ local function query_cached(query: QueryInner)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				entities = archetype.entities
 | 
									entities = archetype.entities
 | 
				
			||||||
				i = #entities
 | 
									i = #entities
 | 
				
			||||||
 | 
									if i == 0 then
 | 
				
			||||||
 | 
										continue
 | 
				
			||||||
 | 
									end
 | 
				
			||||||
				entity = entities[i]
 | 
									entity = entities[i]
 | 
				
			||||||
				columns_map = archetype.columns_map
 | 
									columns_map = archetype.columns_map
 | 
				
			||||||
				a = columns_map[A]
 | 
									a = columns_map[A]
 | 
				
			||||||
| 
						 | 
					@ -1911,6 +1945,9 @@ local function query_cached(query: QueryInner)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				entities = archetype.entities
 | 
									entities = archetype.entities
 | 
				
			||||||
				i = #entities
 | 
									i = #entities
 | 
				
			||||||
 | 
									if i == 0 then
 | 
				
			||||||
 | 
										continue
 | 
				
			||||||
 | 
									end
 | 
				
			||||||
				entity = entities[i]
 | 
									entity = entities[i]
 | 
				
			||||||
				columns_map = archetype.columns_map
 | 
									columns_map = archetype.columns_map
 | 
				
			||||||
				a = columns_map[A]
 | 
									a = columns_map[A]
 | 
				
			||||||
| 
						 | 
					@ -2150,6 +2187,10 @@ local function world_new()
 | 
				
			||||||
		removed = {} :: Signal
 | 
							removed = {} :: Signal
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						-- We need to cache the moment the world is registered, that way
 | 
				
			||||||
 | 
						-- `world:component` will not pollute the global registration of components.
 | 
				
			||||||
 | 
						local max_component_id = ecs_max_component_id
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	local world = {
 | 
						local world = {
 | 
				
			||||||
		archetype_edges = archetype_edges,
 | 
							archetype_edges = archetype_edges,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3124,6 +3165,19 @@ local function world_new()
 | 
				
			||||||
		world.archetype_index = new_archetype_map
 | 
							world.archetype_index = new_archetype_map
 | 
				
			||||||
	end
 | 
						end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						local function world_component(world: world): i53
 | 
				
			||||||
 | 
							max_component_id += 1
 | 
				
			||||||
 | 
							if max_component_id > HI_COMPONENT_ID then
 | 
				
			||||||
 | 
								-- IDs are partitioned into ranges because component IDs are not nominal,
 | 
				
			||||||
 | 
								-- so it needs to error when IDs intersect into the entity range.
 | 
				
			||||||
 | 
								error("Too many components, consider using world:entity() instead to create components.")
 | 
				
			||||||
 | 
							end
 | 
				
			||||||
 | 
							world.max_component_id = max_component_id
 | 
				
			||||||
 | 
							inner_world_add(world, max_component_id, EcsComponent)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return max_component_id
 | 
				
			||||||
 | 
						end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	world.entity = inner_world_entity
 | 
						world.entity = inner_world_entity
 | 
				
			||||||
	world.query = world_query :: any
 | 
						world.query = world_query :: any
 | 
				
			||||||
	world.remove = inner_world_remove
 | 
						world.remove = inner_world_remove
 | 
				
			||||||
| 
						 | 
					@ -3143,14 +3197,12 @@ local function world_new()
 | 
				
			||||||
	world.children = world_children
 | 
						world.children = world_children
 | 
				
			||||||
	world.range = world_range
 | 
						world.range = world_range
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for i = 1, HI_COMPONENT_ID do
 | 
						for i = 1, EcsRest do
 | 
				
			||||||
		local e = entity_index_new_id(entity_index)
 | 
							entity_index_new_id(entity_index)
 | 
				
			||||||
		inner_world_add(world, e, EcsComponent)
 | 
					 | 
				
			||||||
	end
 | 
						end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for i = HI_COMPONENT_ID + 1, EcsRest do
 | 
						for i = 1, max_component_id do
 | 
				
			||||||
		-- Initialize built-in components
 | 
							inner_world_add(world, i, EcsComponent)
 | 
				
			||||||
		entity_index_new_id(entity_index)
 | 
					 | 
				
			||||||
	end
 | 
						end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	inner_world_add(world, EcsName, EcsComponent)
 | 
						inner_world_add(world, EcsName, EcsComponent)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -335,11 +335,11 @@ TEST("bulk", function()
 | 
				
			||||||
	do CASE "Should bulk add with hooks moving archetypes without previous"
 | 
						do CASE "Should bulk add with hooks moving archetypes without previous"
 | 
				
			||||||
		local world = jecs.world()
 | 
							local world = jecs.world()
 | 
				
			||||||
		local c1, c2, c3 = world:component(), world:component(), world:component()
 | 
							local c1, c2, c3 = world:component(), world:component(), world:component()
 | 
				
			||||||
		
 | 
					
 | 
				
			||||||
		world:added(c1, function(e)
 | 
							world:added(c1, function(e)
 | 
				
			||||||
			world:set(e, c3, "hello")
 | 
								world:set(e, c3, "hello")
 | 
				
			||||||
		end)
 | 
							end)
 | 
				
			||||||
		
 | 
					
 | 
				
			||||||
		local e = world:entity()
 | 
							local e = world:entity()
 | 
				
			||||||
		jecs.bulk_insert(world, e, {c1,c2}, {true, 123})
 | 
							jecs.bulk_insert(world, e, {c1,c2}, {true, 123})
 | 
				
			||||||
		CHECK(world:get(e, c1) == true)
 | 
							CHECK(world:get(e, c1) == true)
 | 
				
			||||||
| 
						 | 
					@ -350,11 +350,11 @@ TEST("bulk", function()
 | 
				
			||||||
	do CASE "Should bulk add with hooks moving archetypes with previous"
 | 
						do CASE "Should bulk add with hooks moving archetypes with previous"
 | 
				
			||||||
		local world = jecs.world()
 | 
							local world = jecs.world()
 | 
				
			||||||
		local c1, c2, c3 = world:component(), world:component(), world:component()
 | 
							local c1, c2, c3 = world:component(), world:component(), world:component()
 | 
				
			||||||
		
 | 
					
 | 
				
			||||||
		world:added(c1, function(e)
 | 
							world:added(c1, function(e)
 | 
				
			||||||
			world:set(e, c3, "hello")
 | 
								world:set(e, c3, "hello")
 | 
				
			||||||
		end)
 | 
							end)
 | 
				
			||||||
		
 | 
					
 | 
				
			||||||
		local e = world:entity()
 | 
							local e = world:entity()
 | 
				
			||||||
		world:add(e, world:entity())
 | 
							world:add(e, world:entity())
 | 
				
			||||||
		jecs.bulk_insert(world, e, {c1,c2}, {true, 123})
 | 
							jecs.bulk_insert(world, e, {c1,c2}, {true, 123})
 | 
				
			||||||
| 
						 | 
					@ -550,9 +550,9 @@ TEST("world:add()", function()
 | 
				
			||||||
end)
 | 
					end)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
TEST("world:children()", function()
 | 
					TEST("world:children()", function()
 | 
				
			||||||
	local world = jecs.world()
 | 
					 | 
				
			||||||
	local C = jecs.component()
 | 
						local C = jecs.component()
 | 
				
			||||||
	local T = jecs.tag()
 | 
						local T = jecs.tag()
 | 
				
			||||||
 | 
						local world = jecs.world()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	local e1 = world:entity()
 | 
						local e1 = world:entity()
 | 
				
			||||||
	world:set(e1, C, true)
 | 
						world:set(e1, C, true)
 | 
				
			||||||
| 
						 | 
					@ -2510,7 +2510,7 @@ TEST("#repro2", function()
 | 
				
			||||||
	local entity = world:entity()
 | 
						local entity = world:entity()
 | 
				
			||||||
	world:set(entity, pair(Lifetime, Particle), 1)
 | 
						world:set(entity, pair(Lifetime, Particle), 1)
 | 
				
			||||||
	world:set(entity, pair(Lifetime, Beam), 2)
 | 
						world:set(entity, pair(Lifetime, Beam), 2)
 | 
				
			||||||
	world:set(entity, pair(4 :: any, 5 :: any), 6) -- noise
 | 
						world:set(entity, pair(world:component(), world:component()), 6) -- noise
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	CHECK(world:get(entity, pair(Lifetime, Particle)) == 1)
 | 
						CHECK(world:get(entity, pair(Lifetime, Particle)) == 1)
 | 
				
			||||||
	CHECK(world:get(entity, pair(Lifetime, Beam)) == 2)
 | 
						CHECK(world:get(entity, pair(Lifetime, Beam)) == 2)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue