mirror of
				https://github.com/Ukendio/jecs.git
				synced 2025-11-04 02:49:18 +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 to: Archetype
 | 
				
			||||||
			local idr: ComponentRecord
 | 
								local idr: ComponentRecord
 | 
				
			||||||
			if ECS_IS_PAIR(id::number) then
 | 
								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]
 | 
									local edge = archetype_edges[src.id]
 | 
				
			||||||
				to = edge[id]
 | 
									to = edge[id]
 | 
				
			||||||
				if not to then
 | 
									if to == nil then
 | 
				
			||||||
					local first = ECS_PAIR_FIRST(id::number)
 | 
										if idr and (bit32.btest(idr.flags) == true) then
 | 
				
			||||||
					local wc = ECS_PAIR(first, EcsWildcard)
 | 
											local cr = idr.records[src.id]
 | 
				
			||||||
					idr = component_index[wc]
 | 
											if cr then
 | 
				
			||||||
					if idr and bit32.btest(idr.flags, ECS_ID_IS_EXCLUSIVE) 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]
 | 
											local cr = idr.records[src.id]
 | 
				
			||||||
						if cr then
 | 
											if cr then
 | 
				
			||||||
							local on_remove = idr.on_remove
 | 
												local on_remove = idr.on_remove
 | 
				
			||||||
| 
						 | 
					@ -2340,18 +2371,11 @@ local function world_new()
 | 
				
			||||||
							local dst = table.clone(id_types)
 | 
												local dst = table.clone(id_types)
 | 
				
			||||||
							dst[cr] = id
 | 
												dst[cr] = id
 | 
				
			||||||
							to = archetype_ensure(world, dst)
 | 
												to = archetype_ensure(world, dst)
 | 
				
			||||||
						else
 | 
					 | 
				
			||||||
							to = find_archetype_with(world, id, src)
 | 
					 | 
				
			||||||
							idr = component_index[id]
 | 
					 | 
				
			||||||
						end
 | 
											end
 | 
				
			||||||
					else
 | 
					 | 
				
			||||||
						to = find_archetype_with(world, id, src)
 | 
					 | 
				
			||||||
						idr = component_index[id]
 | 
					 | 
				
			||||||
					end
 | 
										end
 | 
				
			||||||
					edge[id] = to
 | 
										if not to then
 | 
				
			||||||
					archetype_edges[to.id][id] = src
 | 
											to = find_archetype_with(world, id, src)
 | 
				
			||||||
				else
 | 
										end
 | 
				
			||||||
					idr = component_index[id]
 | 
					 | 
				
			||||||
				end
 | 
									end
 | 
				
			||||||
			else
 | 
								else
 | 
				
			||||||
				local edges = archetype_edges
 | 
									local edges = archetype_edges
 | 
				
			||||||
| 
						 | 
					@ -2401,14 +2425,46 @@ local function world_new()
 | 
				
			||||||
		end
 | 
							end
 | 
				
			||||||
		local to: Archetype
 | 
							local to: Archetype
 | 
				
			||||||
		local idr: ComponentRecord
 | 
							local idr: ComponentRecord
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if ECS_IS_PAIR(id::number) then
 | 
							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]
 | 
								local edge = archetype_edges[src.id]
 | 
				
			||||||
			to = edge[id]
 | 
								to = edge[id]
 | 
				
			||||||
			if not to then
 | 
								if to == nil then
 | 
				
			||||||
				local first = ECS_PAIR_FIRST(id::number)
 | 
									if idr and (bit32.btest(idr.flags) == true) then
 | 
				
			||||||
				local wc = ECS_PAIR(first, EcsWildcard)
 | 
										local cr = idr.records[src.id]
 | 
				
			||||||
				idr = component_index[wc]
 | 
										if cr then
 | 
				
			||||||
				if idr and bit32.btest(idr.flags, ECS_ID_IS_EXCLUSIVE) 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]
 | 
										local cr = idr.records[src.id]
 | 
				
			||||||
					if cr then
 | 
										if cr then
 | 
				
			||||||
						local on_remove = idr.on_remove
 | 
											local on_remove = idr.on_remove
 | 
				
			||||||
| 
						 | 
					@ -2422,18 +2478,11 @@ local function world_new()
 | 
				
			||||||
						local dst = table.clone(id_types)
 | 
											local dst = table.clone(id_types)
 | 
				
			||||||
						dst[cr] = id
 | 
											dst[cr] = id
 | 
				
			||||||
						to = archetype_ensure(world, dst)
 | 
											to = archetype_ensure(world, dst)
 | 
				
			||||||
					else
 | 
					 | 
				
			||||||
						to = find_archetype_with(world, id, src)
 | 
					 | 
				
			||||||
						idr = component_index[id]
 | 
					 | 
				
			||||||
					end
 | 
										end
 | 
				
			||||||
				else
 | 
					 | 
				
			||||||
					to = find_archetype_with(world, id, src)
 | 
					 | 
				
			||||||
					idr = component_index[id]
 | 
					 | 
				
			||||||
				end
 | 
									end
 | 
				
			||||||
				edge[id] = to
 | 
									if not to then
 | 
				
			||||||
				archetype_edges[to.id][id] = src
 | 
										to = find_archetype_with(world, id, src)
 | 
				
			||||||
			else
 | 
									end
 | 
				
			||||||
				idr = component_index[id]
 | 
					 | 
				
			||||||
			end
 | 
								end
 | 
				
			||||||
		else
 | 
							else
 | 
				
			||||||
			local edges = archetype_edges
 | 
								local edges = archetype_edges
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -346,23 +346,12 @@ TEST("world:add()", function()
 | 
				
			||||||
		world:add(A, jecs.Exclusive)
 | 
							world:add(A, jecs.Exclusive)
 | 
				
			||||||
		local on_remove_call = false
 | 
							local on_remove_call = false
 | 
				
			||||||
		world:set(A, jecs.OnRemove, function(e, id)
 | 
							world:set(A, jecs.OnRemove, function(e, id)
 | 
				
			||||||
			CHECK(e == e_ptr)
 | 
					 | 
				
			||||||
			CHECK(id == jecs.pair(A, B))
 | 
					 | 
				
			||||||
			on_remove_call = true
 | 
								on_remove_call = true
 | 
				
			||||||
		end)
 | 
							end)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		local on_add_call_count = 0
 | 
							local on_add_call_count = 0
 | 
				
			||||||
		world:set(A, jecs.OnAdd, function(e, id)
 | 
							world:set(A, jecs.OnAdd, function(e, id)
 | 
				
			||||||
			on_add_call_count += 1
 | 
								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)
 | 
							end)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -377,6 +366,17 @@ TEST("world:add()", function()
 | 
				
			||||||
		CHECK(world:has(e, pair(A, B)) == false)
 | 
							CHECK(world:has(e, pair(A, B)) == false)
 | 
				
			||||||
		CHECK(world:has(e, pair(A, C)) == true)
 | 
							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
 | 
						end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	do CASE "idempotent"
 | 
						do CASE "idempotent"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue