mirror of
				https://github.com/Ukendio/jecs.git
				synced 2025-11-03 18:39:19 +00:00 
			
		
		
		
	Bump versions (#259)
This commit is contained in:
		
							parent
							
								
									998b1d3528
								
							
						
					
					
						commit
						b521fe750a
					
				
					 12 changed files with 396 additions and 586 deletions
				
			
		
							
								
								
									
										211
									
								
								addons/ob.luau
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										211
									
								
								addons/ob.luau
									
									
									
									
									
										Executable file
									
								
							| 
						 | 
					@ -0,0 +1,211 @@
 | 
				
			||||||
 | 
					--!strict
 | 
				
			||||||
 | 
					local jecs = require("@jecs")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type World = jecs.World
 | 
				
			||||||
 | 
					type Query<T...> = jecs.Query<T...>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type Id<T=any> = jecs.Id<T>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type Entity<T> = jecs.Entity<T>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export type Iter<T...> = (Observer<T...>) -> () -> (jecs.Entity, T...)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export type Observer<T...> = typeof(setmetatable(
 | 
				
			||||||
 | 
						{} :: {
 | 
				
			||||||
 | 
							iter: Iter<T...>,
 | 
				
			||||||
 | 
							entities: { Entity<nil> },
 | 
				
			||||||
 | 
							disconnect: (Observer<T...>) -> ()
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						{} :: {
 | 
				
			||||||
 | 
							__iter: Iter<T...>,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					local function observers_new<T...>(
 | 
				
			||||||
 | 
						query: Query<T...>,
 | 
				
			||||||
 | 
						callback: ((Entity<nil>, Id<any>, value: any?) -> ())?
 | 
				
			||||||
 | 
					): Observer<T...>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						query:cached()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						local world = (query :: Query<T...> & { world: World }).world
 | 
				
			||||||
 | 
						callback = callback
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						local archetypes = {}
 | 
				
			||||||
 | 
						local terms = query.ids
 | 
				
			||||||
 | 
						local first = terms[1]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						local observers_on_create = world.observable[jecs.ArchetypeCreate][first]
 | 
				
			||||||
 | 
						local observer_on_create = observers_on_create[#observers_on_create]
 | 
				
			||||||
 | 
						observer_on_create.callback = function(archetype)
 | 
				
			||||||
 | 
							archetypes[archetype.id] = true
 | 
				
			||||||
 | 
						end
 | 
				
			||||||
 | 
						local observers_on_delete = world.observable[jecs.ArchetypeDelete][first]
 | 
				
			||||||
 | 
						local observer_on_delete = observers_on_delete[#observers_on_delete]
 | 
				
			||||||
 | 
						observer_on_delete.callback = function(archetype)
 | 
				
			||||||
 | 
							archetypes[archetype.id] = nil
 | 
				
			||||||
 | 
						end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						local entity_index = world.entity_index :: any
 | 
				
			||||||
 | 
						local i = 0
 | 
				
			||||||
 | 
						local entities = {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						local function emplaced<T, a>(
 | 
				
			||||||
 | 
							entity: jecs.Entity<T>,
 | 
				
			||||||
 | 
							id: jecs.Id<a>,
 | 
				
			||||||
 | 
							value: a?
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
							local r = entity_index.sparse_array[jecs.ECS_ID(entity)]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							local archetype = r.archetype
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if archetypes[archetype.id] then
 | 
				
			||||||
 | 
								i += 1
 | 
				
			||||||
 | 
								entities[i] = entity
 | 
				
			||||||
 | 
								if callback ~= nil then
 | 
				
			||||||
 | 
									callback(entity, id, value)
 | 
				
			||||||
 | 
								end
 | 
				
			||||||
 | 
							end
 | 
				
			||||||
 | 
						end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for _, term in terms do
 | 
				
			||||||
 | 
							world:added(term, emplaced)
 | 
				
			||||||
 | 
							world:changed(term, emplaced)
 | 
				
			||||||
 | 
					 	end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  	local function disconnect()
 | 
				
			||||||
 | 
					   		table.remove(observers_on_create, table.find(
 | 
				
			||||||
 | 
					     		observers_on_create,
 | 
				
			||||||
 | 
					       		observer_on_create
 | 
				
			||||||
 | 
					     	))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					     	table.remove(observers_on_delete, table.find(
 | 
				
			||||||
 | 
					      		observers_on_delete,
 | 
				
			||||||
 | 
					        	observer_on_delete
 | 
				
			||||||
 | 
					       	))
 | 
				
			||||||
 | 
					   	end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    local function iter()
 | 
				
			||||||
 | 
					  		local row = i
 | 
				
			||||||
 | 
					  		return function()
 | 
				
			||||||
 | 
					 			if row == 0 then
 | 
				
			||||||
 | 
					     			i = 0
 | 
				
			||||||
 | 
					      			table.clear(entities)
 | 
				
			||||||
 | 
					      		end
 | 
				
			||||||
 | 
					           	local entity = entities[row]
 | 
				
			||||||
 | 
					           	row -= 1
 | 
				
			||||||
 | 
					           	return entity
 | 
				
			||||||
 | 
					        end
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  	local observer = {
 | 
				
			||||||
 | 
					   		disconnect = disconnect,
 | 
				
			||||||
 | 
					     	entities = entities,
 | 
				
			||||||
 | 
					     	__iter = iter,
 | 
				
			||||||
 | 
					      	iter = iter
 | 
				
			||||||
 | 
					   	}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    setmetatable(observer, observer)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return (observer :: any) :: Observer<T...>
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					local function monitors_new<T...>(
 | 
				
			||||||
 | 
						query: Query<T...>,
 | 
				
			||||||
 | 
						callback: ((Entity<nil>, Id<any>, value: any?) -> ())?
 | 
				
			||||||
 | 
					): Observer<T...>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						query:cached()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						local world = (query :: Query<T...> & { world: World }).world
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						local archetypes = {}
 | 
				
			||||||
 | 
						local terms = query.ids
 | 
				
			||||||
 | 
						local first = terms[1]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						local observers_on_create = world.observable[jecs.ArchetypeCreate][first]
 | 
				
			||||||
 | 
						local observer_on_create = observers_on_create[#observers_on_create]
 | 
				
			||||||
 | 
						observer_on_create.callback = function(archetype)
 | 
				
			||||||
 | 
							archetypes[archetype.id] = true
 | 
				
			||||||
 | 
						end
 | 
				
			||||||
 | 
						local observers_on_delete = world.observable[jecs.ArchetypeDelete][first]
 | 
				
			||||||
 | 
						local observer_on_delete = observers_on_delete[#observers_on_delete]
 | 
				
			||||||
 | 
						observer_on_delete.callback = function(archetype)
 | 
				
			||||||
 | 
							archetypes[archetype.id] = nil
 | 
				
			||||||
 | 
						end
 | 
				
			||||||
 | 
						local entity_index = world.entity_index :: any
 | 
				
			||||||
 | 
						local i = 0
 | 
				
			||||||
 | 
						local entities = {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						local function emplaced<T, a>(
 | 
				
			||||||
 | 
							entity: jecs.Entity<T>,
 | 
				
			||||||
 | 
							id: jecs.Id<a>,
 | 
				
			||||||
 | 
							value: a?
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
							local r = jecs.entity_index_try_get_fast(
 | 
				
			||||||
 | 
								entity_index, entity :: any) :: jecs.Record
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							local archetype = r.archetype
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if archetypes[archetype.id] then
 | 
				
			||||||
 | 
								i += 1
 | 
				
			||||||
 | 
								entities[i] = entity
 | 
				
			||||||
 | 
								if callback ~= nil then
 | 
				
			||||||
 | 
									callback(entity, id, value)
 | 
				
			||||||
 | 
								end
 | 
				
			||||||
 | 
							end
 | 
				
			||||||
 | 
						end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						local function removed(entity: jecs.Entity, component: jecs.Id)
 | 
				
			||||||
 | 
							local EcsOnRemove = jecs.OnRemove :: jecs.Id
 | 
				
			||||||
 | 
							if callback ~= nil then
 | 
				
			||||||
 | 
								callback(entity, EcsOnRemove)
 | 
				
			||||||
 | 
							end
 | 
				
			||||||
 | 
						end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for _, term in terms do
 | 
				
			||||||
 | 
							world:added(term, emplaced)
 | 
				
			||||||
 | 
							world:removed(term, removed)
 | 
				
			||||||
 | 
					 	end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 	local function disconnect()
 | 
				
			||||||
 | 
					  		table.remove(observers_on_create, table.find(
 | 
				
			||||||
 | 
						  		observers_on_create,
 | 
				
			||||||
 | 
						    	observer_on_create
 | 
				
			||||||
 | 
						   	))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						   	table.remove(observers_on_delete, table.find(
 | 
				
			||||||
 | 
						      	observers_on_delete,
 | 
				
			||||||
 | 
						       	observer_on_delete
 | 
				
			||||||
 | 
					       	))
 | 
				
			||||||
 | 
					   	end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    local function iter()
 | 
				
			||||||
 | 
					  		local row = i
 | 
				
			||||||
 | 
					  		return function()
 | 
				
			||||||
 | 
					 			if row == 0 then
 | 
				
			||||||
 | 
					     			i = 0
 | 
				
			||||||
 | 
					     			table.clear(entities)
 | 
				
			||||||
 | 
					      		end
 | 
				
			||||||
 | 
					           	local entity = entities[row]
 | 
				
			||||||
 | 
					           	row -= 1
 | 
				
			||||||
 | 
					           	return entity
 | 
				
			||||||
 | 
					        end
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						local observer = {
 | 
				
			||||||
 | 
					  		disconnect = disconnect,
 | 
				
			||||||
 | 
						   	entities = entities,
 | 
				
			||||||
 | 
						   	__iter = iter,
 | 
				
			||||||
 | 
					       	iter = iter
 | 
				
			||||||
 | 
					   	}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    setmetatable(observer, observer)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return (observer :: any) :: Observer<T...>
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					return {
 | 
				
			||||||
 | 
						monitor = monitors_new,
 | 
				
			||||||
 | 
						observer = observers_new
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1,338 +0,0 @@
 | 
				
			||||||
--!strict
 | 
					 | 
				
			||||||
local jecs = require("@jecs")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export type Iter<T...> = (query: Query<T...>) -> () -> (jecs.Entity, T...)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type Id<T=any> = jecs.Id<T>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type Query<T...> = typeof(setmetatable(
 | 
					 | 
				
			||||||
	{} :: {
 | 
					 | 
				
			||||||
		iter: Iter<T...>,
 | 
					 | 
				
			||||||
		with: (<a>(Query<T...>, Id<a>) -> Query<T...>)
 | 
					 | 
				
			||||||
			& (<a, b>(Query<T...>, Id<a>, Id<b>) -> Query<T...>)
 | 
					 | 
				
			||||||
			& (<a, b, c>(Query<T...>, Id<a>, Id<b>, Id<c>) -> Query<T...>)
 | 
					 | 
				
			||||||
			& (<a, b, c>(Query<T...>, Id<a>, Id<b>, Id<c>) -> Query<T...>)
 | 
					 | 
				
			||||||
			& (<a, b, c, d>(Query<T...>, Id<a>, Id<b>, Id<c>, Id) -> Query<T...>),
 | 
					 | 
				
			||||||
		without: (<a>(Query<T...>, Id<a>) -> Query<T...>)
 | 
					 | 
				
			||||||
			& (<a, b>(Query<T...>, Id<a>, Id<b>) -> Query<T...>)
 | 
					 | 
				
			||||||
			& (<a, b, c>(Query<T...>, Id<a>, Id<b>, Id<c>) -> Query<T...>)
 | 
					 | 
				
			||||||
			& (<a, b, c>(Query<T...>, Id<a>, Id<b>, Id<c>) -> Query<T...>)
 | 
					 | 
				
			||||||
			& (<a, b, c, d>(Query<T...>, Id<a>, Id<b>, Id<c>, Id) -> Query<T...>),
 | 
					 | 
				
			||||||
		archetypes: (self: Query<T...>) -> { jecs.Archetype },
 | 
					 | 
				
			||||||
		cached: (self: Query<T...>) -> Query<T...>,
 | 
					 | 
				
			||||||
	},
 | 
					 | 
				
			||||||
	{} :: {
 | 
					 | 
				
			||||||
		__iter: Iter<T...>,
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export type PatchedWorld = jecs.World & {
 | 
					 | 
				
			||||||
	added: <T>(PatchedWorld, jecs.Id<T>, <e>(e: jecs.Entity<e>, id: jecs.Id<T>, value: T?) -> ()) -> () -> (),
 | 
					 | 
				
			||||||
	removed: <T>(PatchedWorld, jecs.Id<T>, (e: jecs.Entity, id: jecs.Id) -> ()) -> () -> (),
 | 
					 | 
				
			||||||
	changed:  <T>(PatchedWorld, jecs.Id<T>, <e>(e: jecs.Entity<e>, id: jecs.Id<T>, value: T) -> ()) -> () -> (),
 | 
					 | 
				
			||||||
	observer: <T...>(PatchedWorld, Query<T...>, callback: ((jecs.Entity, jecs.Id, any?) -> ())?) -> () -> () -> (jecs.Entity),
 | 
					 | 
				
			||||||
	monitor: <T...>(PatchedWorld, Query<T...>, callback: ((jecs.Entity, jecs.Id, any?) -> ())?) -> () -> () -> (jecs.Entity)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
local function observers_new<T...>(
 | 
					 | 
				
			||||||
	world: PatchedWorld,
 | 
					 | 
				
			||||||
	query: Query<T...>,
 | 
					 | 
				
			||||||
	callback: (<T, a>(jecs.Entity<T>, jecs.Id<a>, value: a?) -> ())?
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
	query = query:cached()
 | 
					 | 
				
			||||||
	callback = callback
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	local archetypes = {}
 | 
					 | 
				
			||||||
	local terms = query.ids
 | 
					 | 
				
			||||||
	local first = terms[1]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	local observers_on_create = world.observable[jecs.ArchetypeCreate][first]
 | 
					 | 
				
			||||||
	observers_on_create[#observers_on_create].callback = function(archetype)
 | 
					 | 
				
			||||||
		archetypes[archetype.id] = true
 | 
					 | 
				
			||||||
	end
 | 
					 | 
				
			||||||
	local observers_on_delete = world.observable[jecs.ArchetypeDelete][first]
 | 
					 | 
				
			||||||
	observers_on_delete[#observers_on_delete].callback = function(archetype)
 | 
					 | 
				
			||||||
		archetypes[archetype.id] = nil
 | 
					 | 
				
			||||||
	end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	local entity_index = world.entity_index :: any
 | 
					 | 
				
			||||||
	local i = 0
 | 
					 | 
				
			||||||
	local entities = {}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	local function emplaced<T, a>(
 | 
					 | 
				
			||||||
		entity: jecs.Entity<T>,
 | 
					 | 
				
			||||||
		id: jecs.Id<a>,
 | 
					 | 
				
			||||||
		value: a?
 | 
					 | 
				
			||||||
	)
 | 
					 | 
				
			||||||
		local r = entity_index.sparse_array[jecs.ECS_ID(entity)]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		local archetype = r.archetype
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if archetypes[archetype.id] then
 | 
					 | 
				
			||||||
			i += 1
 | 
					 | 
				
			||||||
			entities[i] = entity
 | 
					 | 
				
			||||||
			if callback ~= nil then
 | 
					 | 
				
			||||||
				callback(entity, id, value)
 | 
					 | 
				
			||||||
			end
 | 
					 | 
				
			||||||
		end
 | 
					 | 
				
			||||||
	end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for _, term in terms do
 | 
					 | 
				
			||||||
		world:added(term, emplaced)
 | 
					 | 
				
			||||||
		world:changed(term, emplaced)
 | 
					 | 
				
			||||||
 	end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  	return function()
 | 
					 | 
				
			||||||
  		local row = i
 | 
					 | 
				
			||||||
  		return function()
 | 
					 | 
				
			||||||
 			if row == 0 then
 | 
					 | 
				
			||||||
     			i = 0
 | 
					 | 
				
			||||||
	      		table.clear(entities)
 | 
					 | 
				
			||||||
      		end
 | 
					 | 
				
			||||||
           	local entity = entities[row]
 | 
					 | 
				
			||||||
           	row -= 1
 | 
					 | 
				
			||||||
           	return entity
 | 
					 | 
				
			||||||
		end
 | 
					 | 
				
			||||||
    end
 | 
					 | 
				
			||||||
end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
local function join(world, component)
 | 
					 | 
				
			||||||
	local sparse_array = {}
 | 
					 | 
				
			||||||
	local dense_array = {}
 | 
					 | 
				
			||||||
	local values = {}
 | 
					 | 
				
			||||||
	local max_id = 0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	world:added(component, function(entity, id, value)
 | 
					 | 
				
			||||||
		max_id += 1
 | 
					 | 
				
			||||||
		sparse_array[entity] = max_id
 | 
					 | 
				
			||||||
		dense_array[max_id] = entity
 | 
					 | 
				
			||||||
		values[max_id] = value
 | 
					 | 
				
			||||||
	end)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	world:removed(component, function(entity, id)
 | 
					 | 
				
			||||||
		local e_swap = dense_array[max_id]
 | 
					 | 
				
			||||||
		local v_swap = values[max_id]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		local dense = sparse_array[entity]
 | 
					 | 
				
			||||||
		dense_array[dense] = e_swap
 | 
					 | 
				
			||||||
		values[dense] = v_swap
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		sparse_array[entity] = nil
 | 
					 | 
				
			||||||
		dense_array[max_id] = nil
 | 
					 | 
				
			||||||
		values[max_id] = nil
 | 
					 | 
				
			||||||
		max_id -= 1
 | 
					 | 
				
			||||||
	end)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	world:changed(component, function(entity, id, value)
 | 
					 | 
				
			||||||
		values[sparse_array[entity]] = value
 | 
					 | 
				
			||||||
	end)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return function()
 | 
					 | 
				
			||||||
		local i = max_id
 | 
					 | 
				
			||||||
		return function(): ...any
 | 
					 | 
				
			||||||
			i -= 1
 | 
					 | 
				
			||||||
			if i == 0 then
 | 
					 | 
				
			||||||
				return nil
 | 
					 | 
				
			||||||
			end
 | 
					 | 
				
			||||||
			local e = dense_array[i]
 | 
					 | 
				
			||||||
			return e, values[i]
 | 
					 | 
				
			||||||
		end
 | 
					 | 
				
			||||||
	end
 | 
					 | 
				
			||||||
end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
local function monitors_new(world, query, callback)
 | 
					 | 
				
			||||||
	query = query:cached()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	local archetypes = {}
 | 
					 | 
				
			||||||
	local terms = query.ids
 | 
					 | 
				
			||||||
	local first = terms[1]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	local observers_on_create = world.observable[jecs.ArchetypeCreate][first]
 | 
					 | 
				
			||||||
	observers_on_create[#observers_on_create].callback = function(archetype)
 | 
					 | 
				
			||||||
		archetypes[archetype.id] = true
 | 
					 | 
				
			||||||
	end
 | 
					 | 
				
			||||||
	local observers_on_delete = world.observable[jecs.ArchetypeDelete][first]
 | 
					 | 
				
			||||||
	observers_on_delete[#observers_on_delete].callback = function(archetype)
 | 
					 | 
				
			||||||
		archetypes[archetype.id] = nil
 | 
					 | 
				
			||||||
	end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	local entity_index = world.entity_index :: any
 | 
					 | 
				
			||||||
	local i = 0
 | 
					 | 
				
			||||||
	local entities = {}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	local function emplaced<T, a>(
 | 
					 | 
				
			||||||
		entity: jecs.Entity<T>,
 | 
					 | 
				
			||||||
		id: jecs.Id<a>,
 | 
					 | 
				
			||||||
		value: a?
 | 
					 | 
				
			||||||
	)
 | 
					 | 
				
			||||||
		local r = jecs.entity_index_try_get_fast(
 | 
					 | 
				
			||||||
			entity_index, entity :: any) :: jecs.Record
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		local archetype = r.archetype
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if archetypes[archetype.id] then
 | 
					 | 
				
			||||||
			i += 1
 | 
					 | 
				
			||||||
			entities[i] = entity
 | 
					 | 
				
			||||||
			if callback ~= nil then
 | 
					 | 
				
			||||||
				callback(entity, id, value)
 | 
					 | 
				
			||||||
			end
 | 
					 | 
				
			||||||
		end
 | 
					 | 
				
			||||||
	end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	local function removed(entity: jecs.Entity, component: jecs.Id)
 | 
					 | 
				
			||||||
		local EcsOnRemove = jecs.OnRemove :: jecs.Id
 | 
					 | 
				
			||||||
		if callback ~= nil then
 | 
					 | 
				
			||||||
			callback(entity, EcsOnRemove)
 | 
					 | 
				
			||||||
		end
 | 
					 | 
				
			||||||
	end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for _, term in terms do
 | 
					 | 
				
			||||||
		world:added(term, emplaced)
 | 
					 | 
				
			||||||
		world:removed(term, removed)
 | 
					 | 
				
			||||||
 	end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return function()
 | 
					 | 
				
			||||||
		local row = i
 | 
					 | 
				
			||||||
		return function()
 | 
					 | 
				
			||||||
			if row == 0 then
 | 
					 | 
				
			||||||
				i = 0
 | 
					 | 
				
			||||||
				table.clear(entities)
 | 
					 | 
				
			||||||
			end
 | 
					 | 
				
			||||||
			local entity = entities[row]
 | 
					 | 
				
			||||||
			row -= 1
 | 
					 | 
				
			||||||
			return entity
 | 
					 | 
				
			||||||
		end
 | 
					 | 
				
			||||||
	end
 | 
					 | 
				
			||||||
end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
local function observers_add(world: jecs.World): PatchedWorld
 | 
					 | 
				
			||||||
	type Signal = { [jecs.Entity]: { (...any) -> () } }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	local world_mut = world :: jecs.World & {[string]: any}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	local signals = {
 | 
					 | 
				
			||||||
		added = {} :: Signal,
 | 
					 | 
				
			||||||
		emplaced = {} :: Signal,
 | 
					 | 
				
			||||||
		removed = {} :: Signal
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	world_mut.added = function<T>(
 | 
					 | 
				
			||||||
		_: jecs.World,
 | 
					 | 
				
			||||||
		component: jecs.Id<T>,
 | 
					 | 
				
			||||||
		fn: (e: jecs.Entity, id: jecs.Id, value: T) -> ()
 | 
					 | 
				
			||||||
	)
 | 
					 | 
				
			||||||
		local listeners = signals.added[component]
 | 
					 | 
				
			||||||
		if not listeners then
 | 
					 | 
				
			||||||
			listeners = {}
 | 
					 | 
				
			||||||
			signals.added[component] = listeners
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			local function on_add(entity, id, value)
 | 
					 | 
				
			||||||
				for _, listener in listeners :: any do
 | 
					 | 
				
			||||||
					listener(entity, id, value)
 | 
					 | 
				
			||||||
				end
 | 
					 | 
				
			||||||
			end
 | 
					 | 
				
			||||||
			local existing_hook = world:get(component, jecs.OnAdd)
 | 
					 | 
				
			||||||
			if existing_hook then
 | 
					 | 
				
			||||||
				table.insert(listeners, existing_hook)
 | 
					 | 
				
			||||||
			end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			local idr = world.component_index[component]
 | 
					 | 
				
			||||||
			if idr then
 | 
					 | 
				
			||||||
				idr.on_add = on_add
 | 
					 | 
				
			||||||
			else
 | 
					 | 
				
			||||||
				world:set(component, jecs.OnAdd, on_add)
 | 
					 | 
				
			||||||
			end
 | 
					 | 
				
			||||||
		end
 | 
					 | 
				
			||||||
		table.insert(listeners, fn)
 | 
					 | 
				
			||||||
		return function()
 | 
					 | 
				
			||||||
			local n = #listeners
 | 
					 | 
				
			||||||
			local i = table.find(listeners, fn)
 | 
					 | 
				
			||||||
			listeners[i] = listeners[n]
 | 
					 | 
				
			||||||
			listeners[n] = nil
 | 
					 | 
				
			||||||
		end
 | 
					 | 
				
			||||||
	end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	world_mut.changed = function<T>(
 | 
					 | 
				
			||||||
		_: jecs.World,
 | 
					 | 
				
			||||||
		component: jecs.Id<T>,
 | 
					 | 
				
			||||||
		fn: (e: jecs.Entity, id: jecs.Id, value: T) -> ()
 | 
					 | 
				
			||||||
	)
 | 
					 | 
				
			||||||
		local listeners = signals.emplaced[component]
 | 
					 | 
				
			||||||
		if not listeners then
 | 
					 | 
				
			||||||
			listeners = {}
 | 
					 | 
				
			||||||
			signals.emplaced[component] = listeners
 | 
					 | 
				
			||||||
			local function on_change(entity, id, value: any)
 | 
					 | 
				
			||||||
				for _, listener in listeners :: any do
 | 
					 | 
				
			||||||
					listener(entity, id, value)
 | 
					 | 
				
			||||||
				end
 | 
					 | 
				
			||||||
			end
 | 
					 | 
				
			||||||
			local existing_hook = world:get(component, jecs.OnChange)
 | 
					 | 
				
			||||||
			if existing_hook then
 | 
					 | 
				
			||||||
				table.insert(listeners, existing_hook)
 | 
					 | 
				
			||||||
			end
 | 
					 | 
				
			||||||
			local idr = world.component_index[component]
 | 
					 | 
				
			||||||
			if idr then
 | 
					 | 
				
			||||||
				idr.on_change = on_change
 | 
					 | 
				
			||||||
			else
 | 
					 | 
				
			||||||
				world:set(component, jecs.OnChange, on_change)
 | 
					 | 
				
			||||||
			end
 | 
					 | 
				
			||||||
		end
 | 
					 | 
				
			||||||
		table.insert(listeners, fn)
 | 
					 | 
				
			||||||
		return function()
 | 
					 | 
				
			||||||
			local n = #listeners
 | 
					 | 
				
			||||||
			local i = table.find(listeners, fn)
 | 
					 | 
				
			||||||
			listeners[i] = listeners[n]
 | 
					 | 
				
			||||||
			listeners[n] = nil
 | 
					 | 
				
			||||||
		end
 | 
					 | 
				
			||||||
	end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	world_mut.removed = function<T>(
 | 
					 | 
				
			||||||
		_: jecs.World,
 | 
					 | 
				
			||||||
		component: jecs.Id<T>,
 | 
					 | 
				
			||||||
		fn: (e: jecs.Entity, id: jecs.Id) -> ()
 | 
					 | 
				
			||||||
	)
 | 
					 | 
				
			||||||
		local listeners = signals.removed[component]
 | 
					 | 
				
			||||||
		if not listeners then
 | 
					 | 
				
			||||||
			listeners = {}
 | 
					 | 
				
			||||||
			signals.removed[component] = listeners
 | 
					 | 
				
			||||||
			local function on_remove(entity, id)
 | 
					 | 
				
			||||||
				for _, listener in listeners :: any do
 | 
					 | 
				
			||||||
					listener(entity, id)
 | 
					 | 
				
			||||||
				end
 | 
					 | 
				
			||||||
			end
 | 
					 | 
				
			||||||
			local existing_hook = world:get(component, jecs.OnRemove)
 | 
					 | 
				
			||||||
			if existing_hook then
 | 
					 | 
				
			||||||
				table.insert(listeners, existing_hook)
 | 
					 | 
				
			||||||
			end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			local idr = world.component_index[component]
 | 
					 | 
				
			||||||
			if idr then
 | 
					 | 
				
			||||||
				idr.on_remove = on_remove
 | 
					 | 
				
			||||||
			else
 | 
					 | 
				
			||||||
				world:set(component, jecs.OnRemove, on_remove)
 | 
					 | 
				
			||||||
			end
 | 
					 | 
				
			||||||
		end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		table.insert(listeners, fn)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		return function()
 | 
					 | 
				
			||||||
			local n = #listeners
 | 
					 | 
				
			||||||
			local i = table.find(listeners, fn)
 | 
					 | 
				
			||||||
			listeners[i] = listeners[n]
 | 
					 | 
				
			||||||
			listeners[n] = nil
 | 
					 | 
				
			||||||
		end
 | 
					 | 
				
			||||||
	end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	world_mut.signals = signals
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	world_mut.observer = observers_new
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	world_mut.monitor = monitors_new
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	world_mut.trackers = {}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return world_mut :: PatchedWorld
 | 
					 | 
				
			||||||
end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
return observers_add
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,190 +0,0 @@
 | 
				
			||||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
 | 
					 | 
				
			||||||
local jecs = require(ReplicatedStorage.ecs)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type Observer<T...> = {
 | 
					 | 
				
			||||||
	callback: (jecs.Entity) -> (),
 | 
					 | 
				
			||||||
	query: jecs.Query<T...>,
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export type PatchedWorld = jecs.World & {
 | 
					 | 
				
			||||||
	added: <T>(PatchedWorld, jecs.Id<T>, (e: jecs.Entity, id: jecs.Id<T>, value: T) -> ()) -> (),
 | 
					 | 
				
			||||||
	removed: (PatchedWorld, jecs.Id, (e: jecs.Entity, id: jecs.Id) -> ()) -> (),
 | 
					 | 
				
			||||||
	changed: <T>(PatchedWorld, jecs.Id<T>, (e: jecs.Entity, id: jecs.Id<T>, value: T) -> ()) -> (),
 | 
					 | 
				
			||||||
	-- deleted: (PatchedWorld, () -> ()) -> () -> (),
 | 
					 | 
				
			||||||
	observer: (PatchedWorld, Observer<any>) -> (),
 | 
					 | 
				
			||||||
	monitor: (PatchedWorld, Observer<any>) -> (),
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
local function observers_new(world, description)
 | 
					 | 
				
			||||||
	local query = description.query
 | 
					 | 
				
			||||||
	local callback = description.callback
 | 
					 | 
				
			||||||
	local terms = query.filter_with :: { jecs.Id }
 | 
					 | 
				
			||||||
	if not terms then
 | 
					 | 
				
			||||||
		local ids = query.ids
 | 
					 | 
				
			||||||
		query.filter_with = ids
 | 
					 | 
				
			||||||
		terms = ids
 | 
					 | 
				
			||||||
	end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	local entity_index = world.entity_index :: any
 | 
					 | 
				
			||||||
	local function emplaced(entity: jecs.Entity)
 | 
					 | 
				
			||||||
		local r = jecs.entity_index_try_get_fast(
 | 
					 | 
				
			||||||
			entity_index, entity :: any)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if not r then
 | 
					 | 
				
			||||||
			return
 | 
					 | 
				
			||||||
		end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		local archetype = r.archetype
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if jecs.query_match(query, archetype) then
 | 
					 | 
				
			||||||
			callback(entity)
 | 
					 | 
				
			||||||
		end
 | 
					 | 
				
			||||||
	end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for _, term in terms do
 | 
					 | 
				
			||||||
		world:added(term, emplaced)
 | 
					 | 
				
			||||||
		world:changed(term, emplaced)
 | 
					 | 
				
			||||||
 	end
 | 
					 | 
				
			||||||
end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
local function monitors_new(world, description)
 | 
					 | 
				
			||||||
	local query = description.query
 | 
					 | 
				
			||||||
	local callback = description.callback
 | 
					 | 
				
			||||||
	local terms = query.filter_with :: { jecs.Id }
 | 
					 | 
				
			||||||
	if not terms then
 | 
					 | 
				
			||||||
		local ids = query.ids
 | 
					 | 
				
			||||||
		query.filter_with = ids
 | 
					 | 
				
			||||||
		terms = ids
 | 
					 | 
				
			||||||
	end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	local entity_index = world.entity_index :: any
 | 
					 | 
				
			||||||
	local function emplaced(entity: jecs.Entity)
 | 
					 | 
				
			||||||
		local r = jecs.entity_index_try_get_fast(
 | 
					 | 
				
			||||||
			entity_index, entity :: any)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if not r then
 | 
					 | 
				
			||||||
			return
 | 
					 | 
				
			||||||
		end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		local archetype = r.archetype
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if jecs.query_match(query, archetype) then
 | 
					 | 
				
			||||||
			callback(entity, jecs.OnAdd)
 | 
					 | 
				
			||||||
		end
 | 
					 | 
				
			||||||
	end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	local function removed(entity: jecs.Entity, component: jecs.Id)
 | 
					 | 
				
			||||||
		local r = jecs.entity_index_try_get_fast(
 | 
					 | 
				
			||||||
			entity_index, entity :: any)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if not r then
 | 
					 | 
				
			||||||
			return
 | 
					 | 
				
			||||||
		end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		local archetype = r.archetype
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if jecs.query_match(query, archetype) then
 | 
					 | 
				
			||||||
			callback(entity, jecs.OnRemove)
 | 
					 | 
				
			||||||
		end
 | 
					 | 
				
			||||||
	end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for _, term in terms do
 | 
					 | 
				
			||||||
		world:added(term, emplaced)
 | 
					 | 
				
			||||||
		world:removed(term, removed)
 | 
					 | 
				
			||||||
 	end
 | 
					 | 
				
			||||||
end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
local function observers_add(world: jecs.World): PatchedWorld
 | 
					 | 
				
			||||||
	local signals = {
 | 
					 | 
				
			||||||
		added = {},
 | 
					 | 
				
			||||||
		emplaced = {},
 | 
					 | 
				
			||||||
		removed = {},
 | 
					 | 
				
			||||||
		deleted = {}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	world = world :: jecs.World & {[string]: any}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	world.added = function(_, component, fn)
 | 
					 | 
				
			||||||
		local listeners = signals.added[component]
 | 
					 | 
				
			||||||
		if not listeners then
 | 
					 | 
				
			||||||
			listeners = {}
 | 
					 | 
				
			||||||
			signals.added[component] = listeners
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			local idr = jecs.id_record_ensure(world :: any, component :: any)
 | 
					 | 
				
			||||||
			local rw = jecs.pair(component, jecs.Wildcard)
 | 
					 | 
				
			||||||
			local idr_r = jecs.id_record_ensure(world :: any, rw :: any)
 | 
					 | 
				
			||||||
			local function on_add(entity: number, id: number, value: any)
 | 
					 | 
				
			||||||
				for _, listener in listeners do
 | 
					 | 
				
			||||||
					listener(entity, id, value)
 | 
					 | 
				
			||||||
				end
 | 
					 | 
				
			||||||
			end
 | 
					 | 
				
			||||||
			world:set(component, jecs.OnAdd, on_add)
 | 
					 | 
				
			||||||
			idr.hooks.on_add = on_add :: any
 | 
					 | 
				
			||||||
			idr_r.hooks.on_add = on_add :: any
 | 
					 | 
				
			||||||
		end
 | 
					 | 
				
			||||||
		table.insert(listeners, fn)
 | 
					 | 
				
			||||||
	end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	world.changed = function(_, component, fn)
 | 
					 | 
				
			||||||
		local listeners = signals.emplaced[component]
 | 
					 | 
				
			||||||
		if not listeners then
 | 
					 | 
				
			||||||
			listeners = {}
 | 
					 | 
				
			||||||
			signals.emplaced[component] = listeners
 | 
					 | 
				
			||||||
			local idr = jecs.id_record_ensure(world :: any, component :: any)
 | 
					 | 
				
			||||||
			local rw = jecs.pair(component, jecs.Wildcard)
 | 
					 | 
				
			||||||
			local idr_r = jecs.id_record_ensure(world :: any, rw :: any)
 | 
					 | 
				
			||||||
			local function on_change(entity: number, id: number, value: any)
 | 
					 | 
				
			||||||
				for _, listener in listeners do
 | 
					 | 
				
			||||||
					listener(entity, id, value)
 | 
					 | 
				
			||||||
				end
 | 
					 | 
				
			||||||
			end
 | 
					 | 
				
			||||||
			world:set(component, jecs.OnChange, on_change)
 | 
					 | 
				
			||||||
			idr.hooks.on_change = on_change :: any
 | 
					 | 
				
			||||||
			idr_r.hooks.on_change = on_change :: any
 | 
					 | 
				
			||||||
		end
 | 
					 | 
				
			||||||
		table.insert(listeners, fn)
 | 
					 | 
				
			||||||
	end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	world.removed = function(_, component, fn)
 | 
					 | 
				
			||||||
		local listeners = signals.removed[component]
 | 
					 | 
				
			||||||
		if not listeners then
 | 
					 | 
				
			||||||
			listeners = {}
 | 
					 | 
				
			||||||
			signals.removed[component] = listeners
 | 
					 | 
				
			||||||
			local idr = jecs.id_record_ensure(world :: any, component :: any)
 | 
					 | 
				
			||||||
			local rw = jecs.pair(component, jecs.Wildcard)
 | 
					 | 
				
			||||||
			local idr_r = jecs.id_record_ensure(world :: any, rw :: any)
 | 
					 | 
				
			||||||
			local function on_remove(entity: number, id: number, value: any)
 | 
					 | 
				
			||||||
				for _, listener in listeners do
 | 
					 | 
				
			||||||
					listener(entity, id, value)
 | 
					 | 
				
			||||||
				end
 | 
					 | 
				
			||||||
			end
 | 
					 | 
				
			||||||
			world:set(component, jecs.OnRemove, on_remove)
 | 
					 | 
				
			||||||
			idr.hooks.on_remove = on_remove :: any
 | 
					 | 
				
			||||||
			idr_r.hooks.on_remove = on_remove :: any
 | 
					 | 
				
			||||||
		end
 | 
					 | 
				
			||||||
		table.insert(listeners, fn)
 | 
					 | 
				
			||||||
	end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	world.signals = signals
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	world.observer = observers_new
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	world.monitor = monitors_new
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	-- local world_delete = world.delete
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	-- world.deleted = function(_, fn)
 | 
					 | 
				
			||||||
	-- 	local listeners = signals.deleted
 | 
					 | 
				
			||||||
	-- 	table.insert(listeners, fn)
 | 
					 | 
				
			||||||
	-- end
 | 
					 | 
				
			||||||
	-- world.delete = function(world, entity)
 | 
					 | 
				
			||||||
	-- 	world_delete(world, entity)
 | 
					 | 
				
			||||||
	-- 	for _, fn in signals.deleted do
 | 
					 | 
				
			||||||
	-- 		fn(entity)
 | 
					 | 
				
			||||||
	-- 	end
 | 
					 | 
				
			||||||
	-- end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return world :: PatchedWorld
 | 
					 | 
				
			||||||
end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
return observers_add
 | 
					 | 
				
			||||||
| 
						 | 
					@ -2,13 +2,12 @@ local ReplicatedStorage = game:GetService("ReplicatedStorage")
 | 
				
			||||||
local ServerScriptService = game:GetService("ServerScriptService")
 | 
					local ServerScriptService = game:GetService("ServerScriptService")
 | 
				
			||||||
local jecs = require(ReplicatedStorage.ecs)
 | 
					local jecs = require(ReplicatedStorage.ecs)
 | 
				
			||||||
local schedule = require(ReplicatedStorage.schedule)
 | 
					local schedule = require(ReplicatedStorage.schedule)
 | 
				
			||||||
local observers_add = require(ReplicatedStorage.observers_add)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
local SYSTEM = schedule.SYSTEM
 | 
					local SYSTEM = schedule.SYSTEM
 | 
				
			||||||
local RUN = schedule.RUN
 | 
					local RUN = schedule.RUN
 | 
				
			||||||
 | 
					
 | 
				
			||||||
require(ReplicatedStorage.components)
 | 
					require(ReplicatedStorage.components)
 | 
				
			||||||
local world = observers_add(jecs.world())
 | 
					local world = jecs.world()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
local systems = ServerScriptService.systems
 | 
					local systems = ServerScriptService.systems
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -15,9 +15,6 @@ hero:
 | 
				
			||||||
    - theme: alt
 | 
					    - theme: alt
 | 
				
			||||||
      text: API References
 | 
					      text: API References
 | 
				
			||||||
      link: /api/jecs.md
 | 
					      link: /api/jecs.md
 | 
				
			||||||
    - theme: alt
 | 
					 | 
				
			||||||
      text: Observers
 | 
					 | 
				
			||||||
      link: /api/observers.md
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
features:
 | 
					features:
 | 
				
			||||||
  - title: Stupidly Fast
 | 
					  - title: Stupidly Fast
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -49,8 +49,8 @@ A tool for inspecting entity lifetimes
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### Helpers
 | 
					### Helpers
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#### [jecs_observers](https://github.com/Ukendio/jecs/blob/main/addons/observers.luau)
 | 
					#### [jecs_ob](https://github.com/Ukendio/jecs/blob/main/addons/ob.luau)
 | 
				
			||||||
Observers for queries and signals for components
 | 
					Observers & Monitors for queries
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### [hammer](https://github.com/Mark-Marks/hammer)
 | 
					### [hammer](https://github.com/Mark-Marks/hammer)
 | 
				
			||||||
A set of utilities for Jecs
 | 
					A set of utilities for Jecs
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										2
									
								
								jecs.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								jecs.d.ts
									
									
									
									
										vendored
									
									
								
							| 
						 | 
					@ -49,7 +49,7 @@ export type Archetype<T extends unknown[]> = {
 | 
				
			||||||
	type: string;
 | 
						type: string;
 | 
				
			||||||
	entities: number[];
 | 
						entities: number[];
 | 
				
			||||||
	columns: Column<unknown>[];
 | 
						columns: Column<unknown>[];
 | 
				
			||||||
	columns_map: { [K in keyof T]: Column<T[K]> }
 | 
						columns_map: Record<Id, Column<T[number]>>
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Iter<T extends unknown[]> = IterableFunction<LuaTuple<[Entity, ...T]>>;
 | 
					type Iter<T extends unknown[]> = IterableFunction<LuaTuple<[Entity, ...T]>>;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										141
									
								
								jecs.luau
									
									
									
									
									
								
							
							
						
						
									
										141
									
								
								jecs.luau
									
									
									
									
									
								
							| 
						 | 
					@ -53,6 +53,8 @@ export type Query<T...> = typeof(setmetatable(
 | 
				
			||||||
			& (<a, b, c, d>(Query<T...>, Id<a>, Id<b>, Id<c>, Id) -> Query<T...>),
 | 
								& (<a, b, c, d>(Query<T...>, Id<a>, Id<b>, Id<c>, Id) -> Query<T...>),
 | 
				
			||||||
		archetypes: (self: Query<T...>) -> { Archetype },
 | 
							archetypes: (self: Query<T...>) -> { Archetype },
 | 
				
			||||||
		cached: (self: Query<T...>) -> Query<T...>,
 | 
							cached: (self: Query<T...>) -> Query<T...>,
 | 
				
			||||||
 | 
							ids: { Id<any> },
 | 
				
			||||||
 | 
							-- world: World
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
	{} :: {
 | 
						{} :: {
 | 
				
			||||||
		__iter: Iter<T...>,
 | 
							__iter: Iter<T...>,
 | 
				
			||||||
| 
						 | 
					@ -66,7 +68,6 @@ export type Observer = {
 | 
				
			||||||
	query: QueryInner,
 | 
						query: QueryInner,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
type archetype = {
 | 
					type archetype = {
 | 
				
			||||||
	id: number,
 | 
						id: number,
 | 
				
			||||||
	types: { i53 },
 | 
						types: { i53 },
 | 
				
			||||||
| 
						 | 
					@ -129,7 +130,11 @@ type world = {
 | 
				
			||||||
	exists: (self: world, entity: i53) -> boolean,
 | 
						exists: (self: world, entity: i53) -> boolean,
 | 
				
			||||||
	each: (self: world, id: i53) -> () -> i53,
 | 
						each: (self: world, id: i53) -> () -> i53,
 | 
				
			||||||
	children: (self: world, id: i53) -> () -> i53,
 | 
						children: (self: world, id: i53) -> () -> i53,
 | 
				
			||||||
	query: (world, ...i53) -> Query<...any>
 | 
						query: (world, ...i53) -> Query<...any>,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						added: (world, i53, (e: i53, id: i53, value: any?) -> ()) -> () -> (),
 | 
				
			||||||
 | 
						changed: (world, i53, (e: i53, id: i53, value: any?) -> ()) -> () -> (),
 | 
				
			||||||
 | 
						removed: (world, i53, (e: i53, id: i53) -> ()) -> () -> (),
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export type World = {
 | 
					export type World = {
 | 
				
			||||||
| 
						 | 
					@ -145,6 +150,10 @@ export type World = {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	observable: Map<Id, Map<Id, { Observer }>>,
 | 
						observable: Map<Id, Map<Id, { Observer }>>,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						added: <T>(World, Id<T>, <e>(e: Entity<e>, id: Id<T>, value: T?) -> ()) -> () -> (),
 | 
				
			||||||
 | 
						removed: <T>(World, Id<T>, (e: Entity, id: Id<T>) -> ()) -> () -> (),
 | 
				
			||||||
 | 
						changed:  <T>(World, Id<T>, <e>(e: Entity<e>, id: Id<T>, value: T) -> ()) -> () -> (),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	--- Enforce a check on entities to be created within desired range
 | 
						--- Enforce a check on entities to be created within desired range
 | 
				
			||||||
	range: (self: World, range_begin: number, range_end: number?) -> (),
 | 
						range: (self: World, range_begin: number, range_end: number?) -> (),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2213,6 +2222,14 @@ local function world_new()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	local observable = {}
 | 
						local observable = {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						type Signal = { [i53]: { Listener<any> } }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						local signals = {
 | 
				
			||||||
 | 
							added = {} :: Signal,
 | 
				
			||||||
 | 
							changed = {} :: Signal,
 | 
				
			||||||
 | 
							removed = {} :: Signal
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	local world = {
 | 
						local world = {
 | 
				
			||||||
		archetype_edges = archetype_edges,
 | 
							archetype_edges = archetype_edges,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2226,9 +2243,11 @@ local function world_new()
 | 
				
			||||||
		max_component_id = ecs_max_component_id,
 | 
							max_component_id = ecs_max_component_id,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		observable = observable,
 | 
							observable = observable,
 | 
				
			||||||
 | 
							signals = signals,
 | 
				
			||||||
	} :: world
 | 
						} :: world
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	local ROOT_ARCHETYPE = archetype_create(world, {}, "")
 | 
						local ROOT_ARCHETYPE = archetype_create(world, {}, "")
 | 
				
			||||||
	world.ROOT_ARCHETYPE = ROOT_ARCHETYPE
 | 
						world.ROOT_ARCHETYPE = ROOT_ARCHETYPE
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2578,6 +2597,108 @@ local function world_new()
 | 
				
			||||||
		end
 | 
							end
 | 
				
			||||||
	end
 | 
						end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						type Listener<T> = (e: i53, id: i53, value: T?) -> ()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						world.added = function<T>(_: world, component: i53, fn: Listener<T>)
 | 
				
			||||||
 | 
							local listeners = signals.added[component]
 | 
				
			||||||
 | 
							if not listeners then
 | 
				
			||||||
 | 
								listeners = {}
 | 
				
			||||||
 | 
								signals.added[component] = listeners
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								local function on_add(entity, id, value)
 | 
				
			||||||
 | 
									for _, listener in listeners :: { Listener<T> } do
 | 
				
			||||||
 | 
										listener(entity, id, value)
 | 
				
			||||||
 | 
									end
 | 
				
			||||||
 | 
								end
 | 
				
			||||||
 | 
								local existing_hook = inner_world_get(world, component, EcsOnAdd) :: Listener<T>
 | 
				
			||||||
 | 
								if existing_hook then
 | 
				
			||||||
 | 
									table.insert(listeners, existing_hook)
 | 
				
			||||||
 | 
								end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								local idr = world.component_index[component]
 | 
				
			||||||
 | 
								if idr then
 | 
				
			||||||
 | 
									idr.on_add = on_add
 | 
				
			||||||
 | 
								else
 | 
				
			||||||
 | 
									inner_world_set(world, component, EcsOnAdd, on_add)
 | 
				
			||||||
 | 
								end
 | 
				
			||||||
 | 
							end
 | 
				
			||||||
 | 
							table.insert(listeners, fn)
 | 
				
			||||||
 | 
							return function()
 | 
				
			||||||
 | 
								local n = #listeners
 | 
				
			||||||
 | 
								local i = table.find(listeners, fn)
 | 
				
			||||||
 | 
								listeners[i] = listeners[n]
 | 
				
			||||||
 | 
								listeners[n] = nil
 | 
				
			||||||
 | 
							end
 | 
				
			||||||
 | 
						end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						world.changed = function<T>(
 | 
				
			||||||
 | 
							_: world,
 | 
				
			||||||
 | 
							component: i53,
 | 
				
			||||||
 | 
							fn: Listener<T>
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
							local listeners = signals.changed[component]
 | 
				
			||||||
 | 
							if not listeners then
 | 
				
			||||||
 | 
								listeners = {}
 | 
				
			||||||
 | 
								signals.changed[component] = listeners
 | 
				
			||||||
 | 
								local function on_change(entity, id, value: any)
 | 
				
			||||||
 | 
									for _, listener in listeners :: { Listener<T> }  do
 | 
				
			||||||
 | 
										listener(entity, id, value)
 | 
				
			||||||
 | 
									end
 | 
				
			||||||
 | 
								end
 | 
				
			||||||
 | 
								local existing_hook = inner_world_get(world, component, EcsOnChange) :: Listener<T>
 | 
				
			||||||
 | 
								if existing_hook then
 | 
				
			||||||
 | 
									table.insert(listeners, existing_hook)
 | 
				
			||||||
 | 
								end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								local idr = world.component_index[component]
 | 
				
			||||||
 | 
								if idr then
 | 
				
			||||||
 | 
									idr.on_change = on_change
 | 
				
			||||||
 | 
								else
 | 
				
			||||||
 | 
									inner_world_set(world, component, EcsOnChange, on_change)
 | 
				
			||||||
 | 
								end
 | 
				
			||||||
 | 
							end
 | 
				
			||||||
 | 
							table.insert(listeners, fn)
 | 
				
			||||||
 | 
							return function()
 | 
				
			||||||
 | 
								local n = #listeners
 | 
				
			||||||
 | 
								local i = table.find(listeners, fn)
 | 
				
			||||||
 | 
								listeners[i] = listeners[n]
 | 
				
			||||||
 | 
								listeners[n] = nil
 | 
				
			||||||
 | 
							end
 | 
				
			||||||
 | 
						end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						world.removed = function<T>(_: world, component: i53, fn: (i53, i53) -> ())
 | 
				
			||||||
 | 
							local listeners = signals.removed[component]
 | 
				
			||||||
 | 
							if not listeners then
 | 
				
			||||||
 | 
								listeners = {}
 | 
				
			||||||
 | 
								signals.removed[component] = listeners
 | 
				
			||||||
 | 
								local function on_remove(entity, id)
 | 
				
			||||||
 | 
									for _, listener in listeners :: { Listener<T> } do
 | 
				
			||||||
 | 
										listener(entity, id)
 | 
				
			||||||
 | 
									end
 | 
				
			||||||
 | 
								end
 | 
				
			||||||
 | 
								local existing_hook = inner_world_get(world, component, EcsOnRemove) :: Listener<T>
 | 
				
			||||||
 | 
								if existing_hook then
 | 
				
			||||||
 | 
									table.insert(listeners, existing_hook)
 | 
				
			||||||
 | 
								end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								local idr = world.component_index[component]
 | 
				
			||||||
 | 
								if idr then
 | 
				
			||||||
 | 
									idr.on_remove = on_remove
 | 
				
			||||||
 | 
								else
 | 
				
			||||||
 | 
									inner_world_set(world, component, EcsOnRemove, on_remove)
 | 
				
			||||||
 | 
								end
 | 
				
			||||||
 | 
							end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							table.insert(listeners, fn)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return function()
 | 
				
			||||||
 | 
								local n = #listeners
 | 
				
			||||||
 | 
								local i = table.find(listeners, fn)
 | 
				
			||||||
 | 
								listeners[i] = listeners[n]
 | 
				
			||||||
 | 
								listeners[n] = nil
 | 
				
			||||||
 | 
							end
 | 
				
			||||||
 | 
						end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	local function inner_world_has(world: World, entity: i53,
 | 
						local function inner_world_has(world: World, entity: i53,
 | 
				
			||||||
		a: i53, b: i53?, c: i53?, d: i53?, e: i53?): boolean
 | 
							a: i53, b: i53?, c: i53?, d: i53?, e: i53?): boolean
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3159,21 +3280,21 @@ return {
 | 
				
			||||||
	meta = (ECS_META :: any) :: <T, a>(id: Entity<T>, id: Id<a>, value: a?) -> Entity<T>,
 | 
						meta = (ECS_META :: any) :: <T, a>(id: Entity<T>, id: Id<a>, value: a?) -> Entity<T>,
 | 
				
			||||||
	is_tag = (ecs_is_tag :: any) :: <T>(World, Id<T>) -> boolean,
 | 
						is_tag = (ecs_is_tag :: any) :: <T>(World, Id<T>) -> boolean,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    OnAdd = (EcsOnAdd :: any) :: Entity<<T>(entity: Entity, id: Id<T>, data: T) -> ()>,
 | 
					    OnAdd = (EcsOnAdd :: any) :: Id<<T>(entity: Entity, id: Id<T>, data: T) -> ()>,
 | 
				
			||||||
	OnRemove = (EcsOnRemove :: any) :: Entity<(entity: Entity, id: Id) -> ()>,
 | 
						OnRemove = (EcsOnRemove :: any) :: Id<(entity: Entity, id: Id) -> ()>,
 | 
				
			||||||
	OnChange = (EcsOnChange :: any) :: Entity<<T>(entity: Entity, id: Id<T>, data: T) -> ()>,
 | 
						OnChange = (EcsOnChange :: any) :: Id<<T>(entity: Entity, id: Id<T>, data: T) -> ()>,
 | 
				
			||||||
	ChildOf = (EcsChildOf :: any) :: Entity,
 | 
						ChildOf = (EcsChildOf :: any) :: Entity,
 | 
				
			||||||
	Component = (EcsComponent :: any) :: Entity,
 | 
						Component = (EcsComponent :: any) :: Entity,
 | 
				
			||||||
	Wildcard = (EcsWildcard :: any) :: Entity,
 | 
						Wildcard = (EcsWildcard :: any) :: Id,
 | 
				
			||||||
	w = (EcsWildcard :: any) :: Entity,
 | 
						w = (EcsWildcard :: any) :: Id,
 | 
				
			||||||
	OnDelete = (EcsOnDelete :: any) :: Entity,
 | 
						OnDelete = (EcsOnDelete :: any) :: Entity,
 | 
				
			||||||
	OnDeleteTarget = (EcsOnDeleteTarget :: any) :: Entity,
 | 
						OnDeleteTarget = (EcsOnDeleteTarget :: any) :: Entity,
 | 
				
			||||||
	Delete = (EcsDelete :: any) :: Entity,
 | 
						Delete = (EcsDelete :: any) :: Entity,
 | 
				
			||||||
	Remove = (EcsRemove :: any) :: Entity,
 | 
						Remove = (EcsRemove :: any) :: Entity,
 | 
				
			||||||
	Name = (EcsName :: any) :: Entity<string>,
 | 
						Name = (EcsName :: any) :: Id<string>,
 | 
				
			||||||
	Exclusive = (EcsExclusive :: any) :: Entity,
 | 
						Exclusive = (EcsExclusive :: any) :: Entity,
 | 
				
			||||||
	ArchetypeCreate = EcsOnArchetypeCreate,
 | 
						ArchetypeCreate = (EcsOnArchetypeCreate :: any) :: Entity,
 | 
				
			||||||
	ArchetypeDelete = EcsOnArchetypeDelete,
 | 
						ArchetypeDelete = (EcsOnArchetypeDelete :: any) :: Entity,
 | 
				
			||||||
	Rest = (EcsRest :: any) :: Entity,
 | 
						Rest = (EcsRest :: any) :: Entity,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pair = ECS_PAIR :: <P, O>(first: Id<P>, second: Id<O>) -> Pair<P, O>,
 | 
						pair = ECS_PAIR :: <P, O>(first: Id<P>, second: Id<O>) -> Pair<P, O>,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,6 @@
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	"name": "@rbxts/jecs",
 | 
						"name": "@rbxts/jecs",
 | 
				
			||||||
	"version": "0.9.0-rc.5",
 | 
						"version": "0.9.0-rc.6",
 | 
				
			||||||
	"description": "Stupidly fast Entity Component System",
 | 
						"description": "Stupidly fast Entity Component System",
 | 
				
			||||||
	"main": "jecs.luau",
 | 
						"main": "jecs.luau",
 | 
				
			||||||
	"repository": {
 | 
						"repository": {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,42 +2,10 @@ local jecs = require("@jecs")
 | 
				
			||||||
local testkit = require("@testkit")
 | 
					local testkit = require("@testkit")
 | 
				
			||||||
local test = testkit.test()
 | 
					local test = testkit.test()
 | 
				
			||||||
local CASE, TEST, FINISH, CHECK = test.CASE, test.TEST, test.FINISH, test.CHECK
 | 
					local CASE, TEST, FINISH, CHECK = test.CASE, test.TEST, test.FINISH, test.CHECK
 | 
				
			||||||
local observers_add = require("@addons/observers")
 | 
					local ob = require("@addons/ob")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
TEST("addons/observers", function()
 | 
					TEST("addons/observers", function()
 | 
				
			||||||
	local world = observers_add(jecs.world())
 | 
						local world = jecs.world()
 | 
				
			||||||
 | 
					 | 
				
			||||||
	do CASE "Should work even if set after the component has been used"
 | 
					 | 
				
			||||||
		local A = world:component()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		world:set(world:entity(), A, 2)
 | 
					 | 
				
			||||||
		local ran = false
 | 
					 | 
				
			||||||
		world:added(A, function()
 | 
					 | 
				
			||||||
			ran = true
 | 
					 | 
				
			||||||
		end)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		local entity = world:entity()
 | 
					 | 
				
			||||||
		world:set(entity, A, 3)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		CHECK(ran)
 | 
					 | 
				
			||||||
	end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	do CASE "Should not override hook"
 | 
					 | 
				
			||||||
		local A = world:component()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		local count = 1
 | 
					 | 
				
			||||||
		local function counter()
 | 
					 | 
				
			||||||
			count += 1
 | 
					 | 
				
			||||||
		end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		world:set(A, jecs.OnAdd, counter)
 | 
					 | 
				
			||||||
		world:added(A, counter)
 | 
					 | 
				
			||||||
		world:set(world:entity(), A, false)
 | 
					 | 
				
			||||||
		CHECK(count == (1 + 2))
 | 
					 | 
				
			||||||
		world:set(world:entity(), A, false)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		CHECK(count == (1 + (2 * 2)))
 | 
					 | 
				
			||||||
	end
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	do CASE "Ensure ordering between signals and observers"
 | 
						do CASE "Ensure ordering between signals and observers"
 | 
				
			||||||
		local A = world:component()
 | 
							local A = world:component()
 | 
				
			||||||
| 
						 | 
					@ -48,11 +16,15 @@ TEST("addons/observers", function()
 | 
				
			||||||
			count += 1
 | 
								count += 1
 | 
				
			||||||
		end
 | 
							end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		world:observer(world:query(A, B), counter)
 | 
							ob.observer(world:query(A, B), counter)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		world:added(A, counter)
 | 
							world:added(A, counter)
 | 
				
			||||||
		world:added(A, counter)
 | 
							world:added(A, counter)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for _ in world:query(A) do
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		local e = world:entity()
 | 
							local e = world:entity()
 | 
				
			||||||
		world:add(e, A)
 | 
							world:add(e, A)
 | 
				
			||||||
		CHECK(count == 3)
 | 
							CHECK(count == 3)
 | 
				
			||||||
| 
						 | 
					@ -69,7 +41,7 @@ TEST("addons/observers", function()
 | 
				
			||||||
			count += 1
 | 
								count += 1
 | 
				
			||||||
		end
 | 
							end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		world:observer(world:query(A), counter)
 | 
							ob.observer(world:query(A), counter)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		local e = world:entity()
 | 
							local e = world:entity()
 | 
				
			||||||
		world:set(e, A, false)
 | 
							world:set(e, A, false)
 | 
				
			||||||
| 
						 | 
					@ -89,7 +61,7 @@ TEST("addons/observers", function()
 | 
				
			||||||
			count += 1
 | 
								count += 1
 | 
				
			||||||
		end
 | 
							end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		world:monitor(world:query(A), counter)
 | 
							ob.monitor(world:query(A), counter)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		local e = world:entity()
 | 
							local e = world:entity()
 | 
				
			||||||
		world:set(e, A, false)
 | 
							world:set(e, A, false)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1062,6 +1062,44 @@ TEST("world:each()", function()
 | 
				
			||||||
	end
 | 
						end
 | 
				
			||||||
end)
 | 
					end)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TEST("world:added", function()
 | 
				
			||||||
 | 
						local world = jecs.world()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						do CASE "Should work even if set after the component has been used"
 | 
				
			||||||
 | 
							local A = world:component()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							world:set(world:entity(), A, 2)
 | 
				
			||||||
 | 
							local ran = false
 | 
				
			||||||
 | 
							world:added(A, function()
 | 
				
			||||||
 | 
								ran = true
 | 
				
			||||||
 | 
							end)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							local entity = world:entity()
 | 
				
			||||||
 | 
							world:set(entity, A, 3)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							CHECK(ran)
 | 
				
			||||||
 | 
						end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						do CASE "Should not override hook"
 | 
				
			||||||
 | 
							local A = world:component()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							local count = 1
 | 
				
			||||||
 | 
							local function counter()
 | 
				
			||||||
 | 
								count += 1
 | 
				
			||||||
 | 
							end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							world:set(A, jecs.OnAdd, counter)
 | 
				
			||||||
 | 
							world:added(A, counter)
 | 
				
			||||||
 | 
							world:set(world:entity(), A, false)
 | 
				
			||||||
 | 
							CHECK(count == (1 + 2))
 | 
				
			||||||
 | 
							world:set(world:entity(), A, false)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							CHECK(count == (1 + (2 * 2)))
 | 
				
			||||||
 | 
						end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					end)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
TEST("world:range()", function()
 | 
					TEST("world:range()", function()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	do CASE "spawn entity under min range"
 | 
						do CASE "spawn entity under min range"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,6 @@
 | 
				
			||||||
[package]
 | 
					[package]
 | 
				
			||||||
name = "ukendio/jecs"
 | 
					name = "ukendio/jecs"
 | 
				
			||||||
version = "0.9.0-rc.5"
 | 
					version = "0.9.0-rc.6"
 | 
				
			||||||
registry = "https://github.com/UpliftGames/wally-index"
 | 
					registry = "https://github.com/UpliftGames/wally-index"
 | 
				
			||||||
realm = "shared"
 | 
					realm = "shared"
 | 
				
			||||||
license = "MIT"
 | 
					license = "MIT"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue