mirror of
				https://github.com/Ukendio/jecs.git
				synced 2025-11-04 02:49:18 +00:00 
			
		
		
		
	Fix 9+ term queries and cascaded deletion bug with different archetype
This commit is contained in:
		
							parent
							
								
									bd00edc8c0
								
							
						
					
					
						commit
						96446f4a31
					
				
					 2 changed files with 169 additions and 98 deletions
				
			
		| 
						 | 
					@ -1979,7 +1979,7 @@ local function query_cached(query: QueryInner)
 | 
				
			||||||
				output[i - 8] = columns_map[ids[i]::any][row]
 | 
									output[i - 8] = columns_map[ids[i]::any][row]
 | 
				
			||||||
			end
 | 
								end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			return entity, a[row], b[row], c[row], d[row], e[row], f[row], g[row], unpack(output)
 | 
								return entity, a[row], b[row], c[row], d[row], e[row], f[row], g[row], h[row], unpack(output)
 | 
				
			||||||
		end
 | 
							end
 | 
				
			||||||
	end
 | 
						end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3095,7 +3095,6 @@ local function world_new()
 | 
				
			||||||
							local child = entities[i]
 | 
												local child = entities[i]
 | 
				
			||||||
							inner_world_delete(world, child)
 | 
												inner_world_delete(world, child)
 | 
				
			||||||
						end
 | 
											end
 | 
				
			||||||
						break
 | 
					 | 
				
			||||||
					end
 | 
										end
 | 
				
			||||||
				else
 | 
									else
 | 
				
			||||||
					for archetype_id in cr.records do
 | 
										for archetype_id in cr.records do
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										264
									
								
								test/tests.luau
									
									
									
									
									
								
							
							
						
						
									
										264
									
								
								test/tests.luau
									
									
									
									
									
								
							| 
						 | 
					@ -24,25 +24,7 @@ type Id<T=unknown> = jecs.Id<T>
 | 
				
			||||||
local entity_visualiser = require("@tools/entity_visualiser")
 | 
					local entity_visualiser = require("@tools/entity_visualiser")
 | 
				
			||||||
local dwi = entity_visualiser.stringify
 | 
					local dwi = entity_visualiser.stringify
 | 
				
			||||||
 | 
					
 | 
				
			||||||
TEST("", function()
 | 
					 | 
				
			||||||
	local world = jecs.world()
 | 
					 | 
				
			||||||
	local a = world:entity()
 | 
					 | 
				
			||||||
	local b = world:entity()
 | 
					 | 
				
			||||||
	local c = world:entity()
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	world:add(a, pair(ChildOf, b))
 | 
					 | 
				
			||||||
	world:add(a, pair(ChildOf, c))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	CHECK(not world:has(a, pair(ChildOf, b)))
 | 
					 | 
				
			||||||
	CHECK(world:has(a, pair(ChildOf, c)))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	world:remove(a, pair(ChildOf, c))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	CHECK(not world:has(a, pair(ChildOf, b)))
 | 
					 | 
				
			||||||
	CHECK(not world:has(a, pair(ChildOf, c)))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
end)
 | 
					 | 
				
			||||||
TEST("ardi", function()
 | 
					TEST("ardi", function()
 | 
				
			||||||
	local world = jecs.world()
 | 
						local world = jecs.world()
 | 
				
			||||||
	local r = world:entity()
 | 
						local r = world:entity()
 | 
				
			||||||
| 
						 | 
					@ -167,7 +149,6 @@ TEST("repeated pairs", function()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	local e2 = world:entity()
 | 
						local e2 = world:entity()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	print("-----")
 | 
					 | 
				
			||||||
	world:set(e2, p2, true)
 | 
						world:set(e2, p2, true)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	CHECK(world:get(e2, p2))
 | 
						CHECK(world:get(e2, p2))
 | 
				
			||||||
| 
						 | 
					@ -209,7 +190,6 @@ TEST("repro", function()
 | 
				
			||||||
	end
 | 
						end
 | 
				
			||||||
	CHECK(count == 1)
 | 
						CHECK(count == 1)
 | 
				
			||||||
	count = 0
 | 
						count = 0
 | 
				
			||||||
	print("----")
 | 
					 | 
				
			||||||
	world:add(e2v1, jecs.pair(relation, e1v1))
 | 
						world:add(e2v1, jecs.pair(relation, e1v1))
 | 
				
			||||||
	CHECK(world:has(e2v1, jecs.pair(relation, e1v1)))
 | 
						CHECK(world:has(e2v1, jecs.pair(relation, e1v1)))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -217,100 +197,140 @@ TEST("repro", function()
 | 
				
			||||||
		count += 1
 | 
							count += 1
 | 
				
			||||||
	end
 | 
						end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	print(count)
 | 
					 | 
				
			||||||
	CHECK(count==1)
 | 
						CHECK(count==1)
 | 
				
			||||||
end)
 | 
					end)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
TEST("bulk", function()
 | 
					TEST("bulk", function()
 | 
				
			||||||
	local world = jecs.world()
 | 
						do CASE "Should allow components and tags to be in disorder"
 | 
				
			||||||
	local A = world:component()
 | 
							local world = jecs.world()
 | 
				
			||||||
	local B = world:component()
 | 
							local A = world:component()
 | 
				
			||||||
	local C = world:component()
 | 
							local B = world:component()
 | 
				
			||||||
 | 
							local C = world:component()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	local D = world:component()
 | 
							local D = world:component()
 | 
				
			||||||
	local E = world:entity()
 | 
							local E = world:entity()
 | 
				
			||||||
	local F = world:component()
 | 
							local F = world:component()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	local e = world:entity()
 | 
							local e = world:entity()
 | 
				
			||||||
	local r = jecs.entity_index_try_get(world.entity_index, e)
 | 
							local r = jecs.entity_index_try_get(world.entity_index, e)
 | 
				
			||||||
	jecs.bulk_insert(world, e, { A, B, C }, { 1, 2, 3 })
 | 
							jecs.bulk_insert(world, e, { A, B, C }, { 1, 2, 3 })
 | 
				
			||||||
	CHECK(world:get(e, A) == 1)
 | 
							CHECK(world:get(e, A) == 1)
 | 
				
			||||||
	CHECK(world:get(e, B) == 2)
 | 
							CHECK(world:get(e, B) == 2)
 | 
				
			||||||
	CHECK(world:get(e, C) == 3)
 | 
							CHECK(world:get(e, C) == 3)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	jecs.bulk_insert(world, e,
 | 
							jecs.bulk_insert(world, e,
 | 
				
			||||||
		{ D, E, F },
 | 
								{ D, E, F },
 | 
				
			||||||
		{ 4, nil, 5 }
 | 
								{ 4, nil, 5 }
 | 
				
			||||||
	)
 | 
							)
 | 
				
			||||||
	CHECK(world:get(e, A) == 1)
 | 
							CHECK(world:get(e, A) == 1)
 | 
				
			||||||
	CHECK(world:get(e, B) == 2)
 | 
							CHECK(world:get(e, B) == 2)
 | 
				
			||||||
	CHECK(world:get(e, C) == 3)
 | 
							CHECK(world:get(e, C) == 3)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	CHECK(world:get(e, D) == 4)
 | 
							CHECK(world:get(e, D) == 4)
 | 
				
			||||||
	CHECK(world:get(e, E) == nil and world:has(e, E))
 | 
							CHECK(world:get(e, E) == nil and world:has(e, E))
 | 
				
			||||||
	CHECK(world:get(e, F) == 5)
 | 
							CHECK(world:get(e, F) == 5)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	jecs.bulk_insert(world, e,
 | 
							jecs.bulk_insert(world, e,
 | 
				
			||||||
		{ A, D, E, F, C },
 | 
								{ A, D, E, F, C },
 | 
				
			||||||
		{ 10, 40, nil, 50, 30 }
 | 
								{ 10, 40, nil, 50, 30 }
 | 
				
			||||||
	)
 | 
							)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	CHECK(world:get(e, A) == 10)
 | 
							CHECK(world:get(e, A) == 10)
 | 
				
			||||||
	CHECK(world:get(e, B) == 2)
 | 
							CHECK(world:get(e, B) == 2)
 | 
				
			||||||
	CHECK(world:get(e, C) == 30)
 | 
							CHECK(world:get(e, C) == 30)
 | 
				
			||||||
	CHECK(world:get(e, D) == 40)
 | 
							CHECK(world:get(e, D) == 40)
 | 
				
			||||||
	CHECK(world:get(e, E) == nil and world:has(e, E))
 | 
							CHECK(world:get(e, E) == nil and world:has(e, E))
 | 
				
			||||||
	CHECK(world:get(e, F) == 50)
 | 
							CHECK(world:get(e, F) == 50)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	local G = world:component()
 | 
							local G = world:component()
 | 
				
			||||||
	world:set(e, G, 100)
 | 
							world:set(e, G, 100)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	CHECK(world:get(e, A) == 10)
 | 
							CHECK(world:get(e, A) == 10)
 | 
				
			||||||
	CHECK(world:get(e, B) == 2)
 | 
							CHECK(world:get(e, B) == 2)
 | 
				
			||||||
	CHECK(world:get(e, C) == 30)
 | 
							CHECK(world:get(e, C) == 30)
 | 
				
			||||||
	CHECK(world:get(e, D) == 40)
 | 
							CHECK(world:get(e, D) == 40)
 | 
				
			||||||
	CHECK(world:get(e, E) == nil and world:has(e, E))
 | 
							CHECK(world:get(e, E) == nil and world:has(e, E))
 | 
				
			||||||
	CHECK(world:get(e, F) == 50)
 | 
							CHECK(world:get(e, F) == 50)
 | 
				
			||||||
	CHECK(world:get(e, G) == 100)
 | 
							CHECK(world:get(e, G) == 100)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	world:remove(e, B)
 | 
							world:remove(e, B)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	CHECK(world:get(e, A) == 10)
 | 
							CHECK(world:get(e, A) == 10)
 | 
				
			||||||
	CHECK(world:has(e, B) == false)
 | 
							CHECK(world:has(e, B) == false)
 | 
				
			||||||
	CHECK(world:get(e, C) == 30)
 | 
							CHECK(world:get(e, C) == 30)
 | 
				
			||||||
	CHECK(world:get(e, D) == 40)
 | 
							CHECK(world:get(e, D) == 40)
 | 
				
			||||||
	CHECK(world:get(e, E) == nil and world:has(e, E))
 | 
							CHECK(world:get(e, E) == nil and world:has(e, E))
 | 
				
			||||||
	CHECK(world:get(e, F) == 50)
 | 
							CHECK(world:get(e, F) == 50)
 | 
				
			||||||
	CHECK(world:get(e, G) == 100)
 | 
							CHECK(world:get(e, G) == 100)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	jecs.bulk_remove(world, e, { A, B, C, D })
 | 
							jecs.bulk_remove(world, e, { A, B, C, D })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	CHECK(world:has(e, A) == false)
 | 
							CHECK(world:has(e, A) == false)
 | 
				
			||||||
	CHECK(world:has(e, B) == false)
 | 
							CHECK(world:has(e, B) == false)
 | 
				
			||||||
	CHECK(world:has(e, C) == false)
 | 
							CHECK(world:has(e, C) == false)
 | 
				
			||||||
	CHECK(world:has(e, D) == false)
 | 
							CHECK(world:has(e, D) == false)
 | 
				
			||||||
	CHECK(world:get(e, E) == nil and world:has(e, E))
 | 
							CHECK(world:get(e, E) == nil and world:has(e, E))
 | 
				
			||||||
	CHECK(world:get(e, F) == 50)
 | 
							CHECK(world:get(e, F) == 50)
 | 
				
			||||||
	CHECK(world:get(e, G) == 100)
 | 
							CHECK(world:get(e, G) == 100)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	jecs.bulk_insert(world, e, { D, G }, { 999, 1 })
 | 
							jecs.bulk_insert(world, e, { D, G }, { 999, 1 })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	CHECK(world:has(e, A) == false)
 | 
							CHECK(world:has(e, A) == false)
 | 
				
			||||||
	CHECK(world:has(e, B) == false)
 | 
							CHECK(world:has(e, B) == false)
 | 
				
			||||||
	CHECK(world:has(e, C) == false)
 | 
							CHECK(world:has(e, C) == false)
 | 
				
			||||||
	CHECK(world:get(e, D) == 999)
 | 
							CHECK(world:get(e, D) == 999)
 | 
				
			||||||
	CHECK(world:get(e, E) == nil and world:has(e, E))
 | 
							CHECK(world:get(e, E) == nil and world:has(e, E))
 | 
				
			||||||
	CHECK(world:get(e, F) == 50)
 | 
							CHECK(world:get(e, F) == 50)
 | 
				
			||||||
	CHECK(world:get(e, G) == 1)
 | 
							CHECK(world:get(e, G) == 1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	jecs.bulk_remove(world, e, { A, B, C, D, E, F, G })
 | 
							jecs.bulk_remove(world, e, { A, B, C, D, E, F, G })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	CHECK(world:has(e, A) == false)
 | 
							CHECK(world:has(e, A) == false)
 | 
				
			||||||
	CHECK(world:has(e, B) == false)
 | 
							CHECK(world:has(e, B) == false)
 | 
				
			||||||
	CHECK(world:has(e, C) == false)
 | 
							CHECK(world:has(e, C) == false)
 | 
				
			||||||
	CHECK(world:has(e, D) == false)
 | 
							CHECK(world:has(e, D) == false)
 | 
				
			||||||
	CHECK(world:has(e, E) == false)
 | 
							CHECK(world:has(e, E) == false)
 | 
				
			||||||
	CHECK(world:has(e, F) == false)
 | 
							CHECK(world:has(e, F) == false)
 | 
				
			||||||
	CHECK(world:has(e, G) == false)
 | 
							CHECK(world:has(e, G) == false)
 | 
				
			||||||
 | 
						end
 | 
				
			||||||
 | 
						do CASE "Should bulk add by default when there is no values"
 | 
				
			||||||
 | 
							local world = jecs.world()
 | 
				
			||||||
 | 
							local t1, t2, t3 = world:entity(), world:entity(), world:entity()
 | 
				
			||||||
 | 
							local count = 0
 | 
				
			||||||
 | 
							local function counter()
 | 
				
			||||||
 | 
								count += 1
 | 
				
			||||||
 | 
							end
 | 
				
			||||||
 | 
							world:added(t1, counter)
 | 
				
			||||||
 | 
							world:added(t2, counter)
 | 
				
			||||||
 | 
							world:added(t3, counter)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							local e = world:entity()
 | 
				
			||||||
 | 
							jecs.bulk_insert(world, e, {t1,t2,t3}, {})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							CHECK(world:has(e, t1, t2, t3))
 | 
				
			||||||
 | 
							CHECK(count == 3)
 | 
				
			||||||
 | 
						end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						do CASE "Should bulk add by default when there is no values"
 | 
				
			||||||
 | 
							local world = jecs.world()
 | 
				
			||||||
 | 
							local c1, c2, c3 = world:component(), world:component(), world:component()
 | 
				
			||||||
 | 
							local count = 0
 | 
				
			||||||
 | 
							local function counter()
 | 
				
			||||||
 | 
								count += 1
 | 
				
			||||||
 | 
							end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							world:changed(c1, counter)
 | 
				
			||||||
 | 
							world:changed(c2, counter)
 | 
				
			||||||
 | 
							world:changed(c3, counter)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							local e = world:entity()
 | 
				
			||||||
 | 
							jecs.bulk_insert(world, e, {c1,c2,c3}, {1,2,3})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							jecs.bulk_insert(world, e, {c1,c2,c3}, {4,5,6})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							CHECK(world:has(e, c1, c2, c3))
 | 
				
			||||||
 | 
							CHECK(count == 3)
 | 
				
			||||||
 | 
						end
 | 
				
			||||||
end)
 | 
					end)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
TEST("repro", function()
 | 
					TEST("repro", function()
 | 
				
			||||||
| 
						 | 
					@ -705,6 +725,24 @@ TEST("world:contains()", function()
 | 
				
			||||||
end)
 | 
					end)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
TEST("world:delete()", function()
 | 
					TEST("world:delete()", function()
 | 
				
			||||||
 | 
						do CASE "Should delete children in different archetypes if they have the same parent"
 | 
				
			||||||
 | 
							local world = jecs.world()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						    local component = world:entity()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						    local parent = world:entity()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						    local child = world:entity()
 | 
				
			||||||
 | 
						    world:add(child, jecs.pair(jecs.ChildOf, parent))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						    local child2 = world:entity()
 | 
				
			||||||
 | 
						    world:add(child2, component) -- important, they need to be in different archetypes
 | 
				
			||||||
 | 
						    world:add(child2, jecs.pair(jecs.ChildOf, parent))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						    world:delete(parent)
 | 
				
			||||||
 | 
						    CHECK(not world:contains(child))
 | 
				
			||||||
 | 
						    CHECK(not world:contains(child2)) -- fails
 | 
				
			||||||
 | 
						end
 | 
				
			||||||
	do CASE "idr_t//delete_mask@3102..3108"
 | 
						do CASE "idr_t//delete_mask@3102..3108"
 | 
				
			||||||
		local world = jecs.world()
 | 
							local world = jecs.world()
 | 
				
			||||||
		local A = world:component()
 | 
							local A = world:component()
 | 
				
			||||||
| 
						 | 
					@ -1249,7 +1287,6 @@ TEST("world:added", function()
 | 
				
			||||||
		end)
 | 
							end)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		local entity = world:entity()
 | 
							local entity = world:entity()
 | 
				
			||||||
		print(pair(A, B))
 | 
					 | 
				
			||||||
		world:set(entity, pair(A, B), 3)
 | 
							world:set(entity, pair(A, B), 3)
 | 
				
			||||||
		CHECK(ran)
 | 
							CHECK(ran)
 | 
				
			||||||
	end
 | 
						end
 | 
				
			||||||
| 
						 | 
					@ -1797,6 +1834,41 @@ TEST("world:query()", function()
 | 
				
			||||||
		end
 | 
							end
 | 
				
			||||||
	end
 | 
						end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						do CASE "query more than 8 components"
 | 
				
			||||||
 | 
							local world = jecs.world()
 | 
				
			||||||
 | 
							local components = {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for i = 1, 15 do
 | 
				
			||||||
 | 
								local id = world:component()
 | 
				
			||||||
 | 
								world:component() -- make the components sparsely interleaved
 | 
				
			||||||
 | 
								components[i] = id
 | 
				
			||||||
 | 
							end
 | 
				
			||||||
 | 
							local e1 = world:entity()
 | 
				
			||||||
 | 
							for i, id in components do
 | 
				
			||||||
 | 
								world:set(e1, id, 13 ^ i)
 | 
				
			||||||
 | 
							end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							local q = world:query(unpack(components))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for entity, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o in q do
 | 
				
			||||||
 | 
								CHECK(a == 13 ^ 1)
 | 
				
			||||||
 | 
								CHECK(b == 13 ^ 2)
 | 
				
			||||||
 | 
								CHECK(c == 13 ^ 3)
 | 
				
			||||||
 | 
								CHECK(d == 13 ^ 4)
 | 
				
			||||||
 | 
								CHECK(e == 13 ^ 5)
 | 
				
			||||||
 | 
								CHECK(f == 13 ^ 6)
 | 
				
			||||||
 | 
								CHECK(g == 13 ^ 7)
 | 
				
			||||||
 | 
								CHECK(h == 13 ^ 8)
 | 
				
			||||||
 | 
								CHECK(i == 13 ^ 9)
 | 
				
			||||||
 | 
								CHECK(j == 13 ^ 10)
 | 
				
			||||||
 | 
								CHECK(k == 13 ^ 11)
 | 
				
			||||||
 | 
								CHECK(l == 13 ^ 12)
 | 
				
			||||||
 | 
								CHECK(m == 13 ^ 13)
 | 
				
			||||||
 | 
								CHECK(n == 13 ^ 14)
 | 
				
			||||||
 | 
								CHECK(o == 13 ^ 15)
 | 
				
			||||||
 | 
							end
 | 
				
			||||||
 | 
						end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	do CASE "should be able to get next results"
 | 
						do CASE "should be able to get next results"
 | 
				
			||||||
		local world = jecs.world()
 | 
							local world = jecs.world()
 | 
				
			||||||
		world:component()
 | 
							world:component()
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue