mirror of
				https://github.com/Ukendio/jecs.git
				synced 2025-11-03 18:39:19 +00:00 
			
		
		
		
	Fix on_remove hook not called on cached edge
This commit is contained in:
		
							parent
							
								
									d99088ea1e
								
							
						
					
					
						commit
						117a5e0ca7
					
				
					 2 changed files with 90 additions and 41 deletions
				
			
		
							
								
								
									
										109
									
								
								jecs.luau
									
									
									
									
									
								
							
							
						
						
									
										109
									
								
								jecs.luau
									
									
									
									
									
								
							| 
						 | 
				
			
			@ -2320,13 +2320,44 @@ local function world_new()
 | 
			
		|||
			local to: Archetype
 | 
			
		||||
			local idr: ComponentRecord
 | 
			
		||||
			if ECS_IS_PAIR(id::number) then
 | 
			
		||||
				local first = ECS_PAIR_FIRST(id::number)
 | 
			
		||||
				local wc = ECS_PAIR(first, EcsWildcard)
 | 
			
		||||
				idr = component_index[wc]
 | 
			
		||||
 | 
			
		||||
				local edge = archetype_edges[src.id]
 | 
			
		||||
				to = edge[id]
 | 
			
		||||
				if not to then
 | 
			
		||||
					local first = ECS_PAIR_FIRST(id::number)
 | 
			
		||||
					local wc = ECS_PAIR(first, EcsWildcard)
 | 
			
		||||
					idr = component_index[wc]
 | 
			
		||||
					if idr and bit32.btest(idr.flags, ECS_ID_IS_EXCLUSIVE) then
 | 
			
		||||
				if to == nil then
 | 
			
		||||
					if idr and (bit32.btest(idr.flags) == true) then
 | 
			
		||||
						local cr = idr.records[src.id]
 | 
			
		||||
						if cr then
 | 
			
		||||
							local on_remove = idr.on_remove
 | 
			
		||||
							local id_types = src.types
 | 
			
		||||
							if on_remove then
 | 
			
		||||
								on_remove(entity, id_types[cr])
 | 
			
		||||
 | 
			
		||||
								src = record.archetype
 | 
			
		||||
								id_types = src.types
 | 
			
		||||
								cr = idr.records[src.id]
 | 
			
		||||
							end
 | 
			
		||||
 | 
			
		||||
							local dst = table.clone(id_types)
 | 
			
		||||
							dst[cr] = id
 | 
			
		||||
							to = archetype_ensure(world, dst)
 | 
			
		||||
						end
 | 
			
		||||
					end
 | 
			
		||||
 | 
			
		||||
					if not to then
 | 
			
		||||
						to = find_archetype_with(world, id, src)
 | 
			
		||||
					end
 | 
			
		||||
 | 
			
		||||
					if not idr then
 | 
			
		||||
						idr = component_index[wc]
 | 
			
		||||
					end
 | 
			
		||||
 | 
			
		||||
					edge[id] = to
 | 
			
		||||
					archetype_edges[(to :: Archetype).id][id] = src
 | 
			
		||||
				else
 | 
			
		||||
					if bit32.btest(idr.flags, ECS_ID_IS_EXCLUSIVE) then
 | 
			
		||||
						local cr = idr.records[src.id]
 | 
			
		||||
						if cr then
 | 
			
		||||
							local on_remove = idr.on_remove
 | 
			
		||||
| 
						 | 
				
			
			@ -2340,18 +2371,11 @@ local function world_new()
 | 
			
		|||
							local dst = table.clone(id_types)
 | 
			
		||||
							dst[cr] = id
 | 
			
		||||
							to = archetype_ensure(world, dst)
 | 
			
		||||
						else
 | 
			
		||||
							to = find_archetype_with(world, id, src)
 | 
			
		||||
							idr = component_index[id]
 | 
			
		||||
						end
 | 
			
		||||
					else
 | 
			
		||||
						to = find_archetype_with(world, id, src)
 | 
			
		||||
						idr = component_index[id]
 | 
			
		||||
					end
 | 
			
		||||
					edge[id] = to
 | 
			
		||||
					archetype_edges[to.id][id] = src
 | 
			
		||||
				else
 | 
			
		||||
					idr = component_index[id]
 | 
			
		||||
					if not to then
 | 
			
		||||
						to = find_archetype_with(world, id, src)
 | 
			
		||||
					end
 | 
			
		||||
				end
 | 
			
		||||
			else
 | 
			
		||||
				local edges = archetype_edges
 | 
			
		||||
| 
						 | 
				
			
			@ -2401,14 +2425,46 @@ local function world_new()
 | 
			
		|||
		end
 | 
			
		||||
		local to: Archetype
 | 
			
		||||
		local idr: ComponentRecord
 | 
			
		||||
 | 
			
		||||
		if ECS_IS_PAIR(id::number) then
 | 
			
		||||
			local first = ECS_PAIR_FIRST(id::number)
 | 
			
		||||
			local wc = ECS_PAIR(first, EcsWildcard)
 | 
			
		||||
			idr = component_index[wc]
 | 
			
		||||
 | 
			
		||||
			local edge = archetype_edges[src.id]
 | 
			
		||||
			to = edge[id]
 | 
			
		||||
			if not to then
 | 
			
		||||
				local first = ECS_PAIR_FIRST(id::number)
 | 
			
		||||
				local wc = ECS_PAIR(first, EcsWildcard)
 | 
			
		||||
				idr = component_index[wc]
 | 
			
		||||
				if idr and bit32.btest(idr.flags, ECS_ID_IS_EXCLUSIVE) then
 | 
			
		||||
			if to == nil then
 | 
			
		||||
				if idr and (bit32.btest(idr.flags) == true) then
 | 
			
		||||
					local cr = idr.records[src.id]
 | 
			
		||||
					if cr then
 | 
			
		||||
						local on_remove = idr.on_remove
 | 
			
		||||
						local id_types = src.types
 | 
			
		||||
						if on_remove then
 | 
			
		||||
							on_remove(entity, id_types[cr])
 | 
			
		||||
 | 
			
		||||
							src = record.archetype
 | 
			
		||||
							id_types = src.types
 | 
			
		||||
							cr = idr.records[src.id]
 | 
			
		||||
						end
 | 
			
		||||
 | 
			
		||||
						local dst = table.clone(id_types)
 | 
			
		||||
						dst[cr] = id
 | 
			
		||||
						to = archetype_ensure(world, dst)
 | 
			
		||||
					end
 | 
			
		||||
				end
 | 
			
		||||
 | 
			
		||||
				if not to then
 | 
			
		||||
					to = find_archetype_with(world, id, src)
 | 
			
		||||
				end
 | 
			
		||||
 | 
			
		||||
				if not idr then
 | 
			
		||||
					idr = component_index[wc]
 | 
			
		||||
				end
 | 
			
		||||
 | 
			
		||||
				edge[id] = to
 | 
			
		||||
				archetype_edges[(to :: Archetype).id][id] = src
 | 
			
		||||
			else
 | 
			
		||||
				if bit32.btest(idr.flags, ECS_ID_IS_EXCLUSIVE) then
 | 
			
		||||
					local cr = idr.records[src.id]
 | 
			
		||||
					if cr then
 | 
			
		||||
						local on_remove = idr.on_remove
 | 
			
		||||
| 
						 | 
				
			
			@ -2422,18 +2478,11 @@ local function world_new()
 | 
			
		|||
						local dst = table.clone(id_types)
 | 
			
		||||
						dst[cr] = id
 | 
			
		||||
						to = archetype_ensure(world, dst)
 | 
			
		||||
					else
 | 
			
		||||
						to = find_archetype_with(world, id, src)
 | 
			
		||||
						idr = component_index[id]
 | 
			
		||||
					end
 | 
			
		||||
				else
 | 
			
		||||
					to = find_archetype_with(world, id, src)
 | 
			
		||||
					idr = component_index[id]
 | 
			
		||||
				end
 | 
			
		||||
				edge[id] = to
 | 
			
		||||
				archetype_edges[to.id][id] = src
 | 
			
		||||
			else
 | 
			
		||||
				idr = component_index[id]
 | 
			
		||||
				if not to then
 | 
			
		||||
					to = find_archetype_with(world, id, src)
 | 
			
		||||
				end
 | 
			
		||||
			end
 | 
			
		||||
		else
 | 
			
		||||
			local edges = archetype_edges
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -346,23 +346,12 @@ TEST("world:add()", function()
 | 
			
		|||
		world:add(A, jecs.Exclusive)
 | 
			
		||||
		local on_remove_call = false
 | 
			
		||||
		world:set(A, jecs.OnRemove, function(e, id)
 | 
			
		||||
			CHECK(e == e_ptr)
 | 
			
		||||
			CHECK(id == jecs.pair(A, B))
 | 
			
		||||
			on_remove_call = true
 | 
			
		||||
		end)
 | 
			
		||||
 | 
			
		||||
		local on_add_call_count = 0
 | 
			
		||||
		world:set(A, jecs.OnAdd, function(e, id)
 | 
			
		||||
			on_add_call_count += 1
 | 
			
		||||
			if on_add_call_count == 1 then
 | 
			
		||||
				CHECK(e == e_ptr)
 | 
			
		||||
				CHECK(id == jecs.pair(A, B))
 | 
			
		||||
			elseif on_add_call_count == 2 then
 | 
			
		||||
				CHECK(e == e_ptr)
 | 
			
		||||
				CHECK(id == jecs.pair(A, C))
 | 
			
		||||
			else
 | 
			
		||||
				CHECK(false)
 | 
			
		||||
			end
 | 
			
		||||
		end)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -377,6 +366,17 @@ TEST("world:add()", function()
 | 
			
		|||
		CHECK(world:has(e, pair(A, B)) == false)
 | 
			
		||||
		CHECK(world:has(e, pair(A, C)) == true)
 | 
			
		||||
 | 
			
		||||
		-- We have to ensure that it actually invokes hooks everytime it
 | 
			
		||||
		-- traverses the archetype
 | 
			
		||||
		e = world:entity()
 | 
			
		||||
		world:add(e, pair(A, B))
 | 
			
		||||
		CHECK(on_add_call_count == 3)
 | 
			
		||||
		world:add(e, pair(A, C))
 | 
			
		||||
		CHECK(on_add_call_count == 4)
 | 
			
		||||
		CHECK(on_remove_call)
 | 
			
		||||
 | 
			
		||||
		CHECK(world:has(e, pair(A, B)) == false)
 | 
			
		||||
		CHECK(world:has(e, pair(A, C)) == true)
 | 
			
		||||
	end
 | 
			
		||||
 | 
			
		||||
	do CASE "idempotent"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue