mirror of
				https://github.com/Ukendio/jecs.git
				synced 2025-11-04 02:49:18 +00:00 
			
		
		
		
	Initial commit
This commit is contained in:
		
							parent
							
								
									7c025a3782
								
							
						
					
					
						commit
						ba74d6b471
					
				
					 1 changed files with 101 additions and 67 deletions
				
			
		
							
								
								
									
										168
									
								
								jecs.luau
									
									
									
									
									
								
							
							
						
						
									
										168
									
								
								jecs.luau
									
									
									
									
									
								
							| 
						 | 
					@ -89,7 +89,8 @@ local EcsOnDeleteTarget = HI_COMPONENT_ID +  8
 | 
				
			||||||
local EcsDelete =         HI_COMPONENT_ID +  9
 | 
					local EcsDelete =         HI_COMPONENT_ID +  9
 | 
				
			||||||
local EcsRemove =         HI_COMPONENT_ID + 10
 | 
					local EcsRemove =         HI_COMPONENT_ID + 10
 | 
				
			||||||
local EcsName =           HI_COMPONENT_ID + 11
 | 
					local EcsName =           HI_COMPONENT_ID + 11
 | 
				
			||||||
local EcsRest =           HI_COMPONENT_ID + 12
 | 
					local EcsTableCreate =    HI_COMPONENT_ID + 12
 | 
				
			||||||
 | 
					local EcsRest =           HI_COMPONENT_ID + 13
 | 
				
			||||||
 | 
					
 | 
				
			||||||
local ECS_PAIR_FLAG =                       0x8
 | 
					local ECS_PAIR_FLAG =                       0x8
 | 
				
			||||||
local ECS_ID_FLAGS_MASK =                  0x10
 | 
					local ECS_ID_FLAGS_MASK =                  0x10
 | 
				
			||||||
| 
						 | 
					@ -250,6 +251,40 @@ local function ecs_pair_second(world, e)
 | 
				
			||||||
	return entity_index_get_alive(world.entity_index, ECS_ENTITY_T_LO(e))
 | 
						return entity_index_get_alive(world.entity_index, ECS_ENTITY_T_LO(e))
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					local function query_match(query, archetype)
 | 
				
			||||||
 | 
						local matches = true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						local records = archetype.records
 | 
				
			||||||
 | 
						for _, id in query.ids do
 | 
				
			||||||
 | 
							if not records[id] then
 | 
				
			||||||
 | 
								matches = false
 | 
				
			||||||
 | 
								break
 | 
				
			||||||
 | 
							end
 | 
				
			||||||
 | 
						end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return matches
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					local function observer_invoke(observer, event)
 | 
				
			||||||
 | 
						table.insert(observer.query.compatible_archetypes, event.archetype)
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					local function emit(world: World, event)
 | 
				
			||||||
 | 
						local map = world.observerable[event.id]
 | 
				
			||||||
 | 
						if not map then
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						end
 | 
				
			||||||
 | 
						local observer_list: {[string]: any} = map[event.component]
 | 
				
			||||||
 | 
						if not observer_list then
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						end
 | 
				
			||||||
 | 
						for _, observer in observer_list do
 | 
				
			||||||
 | 
							if query_match(observer.query, event.archetype) then
 | 
				
			||||||
 | 
								observer_invoke(observer, event)
 | 
				
			||||||
 | 
							end
 | 
				
			||||||
 | 
						end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
local function archetype_move(entity_index: EntityIndex, to: Archetype, dst_row: i24, from: Archetype, src_row: i24)
 | 
					local function archetype_move(entity_index: EntityIndex, to: Archetype, dst_row: i24, from: Archetype, src_row: i24)
 | 
				
			||||||
	local src_columns = from.columns
 | 
						local src_columns = from.columns
 | 
				
			||||||
	local dst_columns = to.columns
 | 
						local dst_columns = to.columns
 | 
				
			||||||
| 
						 | 
					@ -535,15 +570,49 @@ local function archetype_append_to_records(
 | 
				
			||||||
	end
 | 
						end
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
local function archetype_create(world: World, types: { i24 }, ty, prev: i53?): Archetype
 | 
					local function create_observer_uni(world: World, component: number, event)
 | 
				
			||||||
 | 
						local map = world.observerable[event]
 | 
				
			||||||
 | 
						if not map then
 | 
				
			||||||
 | 
							map = {}
 | 
				
			||||||
 | 
							world.observerable[event] = map
 | 
				
			||||||
 | 
						end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						local observer_list = map[component]
 | 
				
			||||||
 | 
						if not observer_list then
 | 
				
			||||||
 | 
							observer_list = {}
 | 
				
			||||||
 | 
							map[component] = observer_list
 | 
				
			||||||
 | 
						end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						local observer = {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						table.insert(observer_list, observer)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return observer
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					local function archetype_create(world: World, id_types: { i24 }, ty, prev: i53?): Archetype
 | 
				
			||||||
	local archetype_id = (world.nextArchetypeId :: number) + 1
 | 
						local archetype_id = (world.nextArchetypeId :: number) + 1
 | 
				
			||||||
	world.nextArchetypeId = archetype_id
 | 
						world.nextArchetypeId = archetype_id
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	local length = #types
 | 
						local length = #id_types
 | 
				
			||||||
	local columns = (table.create(length) :: any) :: { Column }
 | 
						local columns = (table.create(length) :: any) :: { Column }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	local records: { ArchetypeRecord } = {}
 | 
						local records: { ArchetypeRecord } = {}
 | 
				
			||||||
	for i, componentId in types do
 | 
					
 | 
				
			||||||
 | 
						local archetype: Archetype = {
 | 
				
			||||||
 | 
							columns = columns,
 | 
				
			||||||
 | 
							entities = {},
 | 
				
			||||||
 | 
							id = archetype_id,
 | 
				
			||||||
 | 
							records = records,
 | 
				
			||||||
 | 
							type = ty,
 | 
				
			||||||
 | 
							types = id_types,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							add = {},
 | 
				
			||||||
 | 
							remove = {},
 | 
				
			||||||
 | 
							refs = {} :: GraphEdge,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for i, componentId in id_types do
 | 
				
			||||||
		local idr = id_record_ensure(world, componentId)
 | 
							local idr = id_record_ensure(world, componentId)
 | 
				
			||||||
		archetype_append_to_records(idr, archetype_id, records, componentId, i)
 | 
							archetype_append_to_records(idr, archetype_id, records, componentId, i)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -564,21 +633,10 @@ local function archetype_create(world: World, types: { i24 }, ty, prev: i53?): A
 | 
				
			||||||
		else
 | 
							else
 | 
				
			||||||
			columns[i] = NULL_ARRAY
 | 
								columns[i] = NULL_ARRAY
 | 
				
			||||||
		end
 | 
							end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							emit(world, { id = EcsTableCreate, component = componentId, archetype = archetype})
 | 
				
			||||||
	end
 | 
						end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	local archetype: Archetype = {
 | 
					 | 
				
			||||||
		columns = columns,
 | 
					 | 
				
			||||||
		entities = {},
 | 
					 | 
				
			||||||
		id = archetype_id,
 | 
					 | 
				
			||||||
		records = records,
 | 
					 | 
				
			||||||
		type = ty,
 | 
					 | 
				
			||||||
		types = types,
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		add = {},
 | 
					 | 
				
			||||||
		remove = {},
 | 
					 | 
				
			||||||
		refs = {} :: GraphEdge,
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	world.archetypeIndex[ty] = archetype
 | 
						world.archetypeIndex[ty] = archetype
 | 
				
			||||||
	world.archetypes[archetype_id] = archetype
 | 
						world.archetypes[archetype_id] = archetype
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1477,6 +1535,15 @@ local function query_archetypes(query)
 | 
				
			||||||
	return query.compatible_archetypes
 | 
						return query.compatible_archetypes
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					local function query_cached(query)
 | 
				
			||||||
 | 
						for _, component in query.ids do
 | 
				
			||||||
 | 
							local observer = create_observer_uni(query.world, component, EcsTableCreate)
 | 
				
			||||||
 | 
							observer.query = query
 | 
				
			||||||
 | 
						end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return query
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
local Query = {}
 | 
					local Query = {}
 | 
				
			||||||
Query.__index = Query
 | 
					Query.__index = Query
 | 
				
			||||||
Query.__iter = query_iter
 | 
					Query.__iter = query_iter
 | 
				
			||||||
| 
						 | 
					@ -1484,6 +1551,7 @@ Query.iter = query_iter_init
 | 
				
			||||||
Query.without = query_without
 | 
					Query.without = query_without
 | 
				
			||||||
Query.with = query_with
 | 
					Query.with = query_with
 | 
				
			||||||
Query.archetypes = query_archetypes
 | 
					Query.archetypes = query_archetypes
 | 
				
			||||||
 | 
					Query.cached = query_cached
 | 
				
			||||||
 | 
					
 | 
				
			||||||
local function world_query(world: World, ...)
 | 
					local function world_query(world: World, ...)
 | 
				
			||||||
	local compatible_archetypes = {}
 | 
						local compatible_archetypes = {}
 | 
				
			||||||
| 
						 | 
					@ -1496,10 +1564,16 @@ local function world_query(world: World, ...)
 | 
				
			||||||
	local idr: IdRecord?
 | 
						local idr: IdRecord?
 | 
				
			||||||
	local componentIndex = world.componentIndex
 | 
						local componentIndex = world.componentIndex
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						local q = setmetatable({
 | 
				
			||||||
 | 
							ids = ids,
 | 
				
			||||||
 | 
							compatible_archetypes = compatible_archetypes,
 | 
				
			||||||
 | 
							world = world,
 | 
				
			||||||
 | 
						}, Query)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for _, id in ids do
 | 
						for _, id in ids do
 | 
				
			||||||
		local map = componentIndex[id]
 | 
							local map = componentIndex[id]
 | 
				
			||||||
		if not map then
 | 
							if not map then
 | 
				
			||||||
			return EMPTY_QUERY
 | 
								return q
 | 
				
			||||||
		end
 | 
							end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if idr == nil or map.size < idr.size then
 | 
							if idr == nil or map.size < idr.size then
 | 
				
			||||||
| 
						 | 
					@ -1508,7 +1582,7 @@ local function world_query(world: World, ...)
 | 
				
			||||||
	end
 | 
						end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if not idr then
 | 
						if not idr then
 | 
				
			||||||
		return EMPTY_QUERY
 | 
							return q
 | 
				
			||||||
	end
 | 
						end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for archetype_id in idr.cache do
 | 
						for archetype_id in idr.cache do
 | 
				
			||||||
| 
						 | 
					@ -1536,15 +1610,6 @@ local function world_query(world: World, ...)
 | 
				
			||||||
		compatible_archetypes[length] = compatibleArchetype
 | 
							compatible_archetypes[length] = compatibleArchetype
 | 
				
			||||||
	end
 | 
						end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if length == 0 then
 | 
					 | 
				
			||||||
		return EMPTY_QUERY
 | 
					 | 
				
			||||||
	end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	local q = setmetatable({
 | 
					 | 
				
			||||||
		compatible_archetypes = compatible_archetypes,
 | 
					 | 
				
			||||||
		ids = ids,
 | 
					 | 
				
			||||||
	}, Query) :: any
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return q
 | 
						return q
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1730,6 +1795,7 @@ function World.new()
 | 
				
			||||||
		nextComponentId = 0 :: number,
 | 
							nextComponentId = 0 :: number,
 | 
				
			||||||
		nextEntityId = 0 :: number,
 | 
							nextEntityId = 0 :: number,
 | 
				
			||||||
		ROOT_ARCHETYPE = (nil :: any) :: Archetype,
 | 
							ROOT_ARCHETYPE = (nil :: any) :: Archetype,
 | 
				
			||||||
 | 
							observerable = {}
 | 
				
			||||||
	}, World) :: any
 | 
						}, World) :: any
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	self.ROOT_ARCHETYPE = archetype_create(self, {}, "")
 | 
						self.ROOT_ARCHETYPE = archetype_create(self, {}, "")
 | 
				
			||||||
| 
						 | 
					@ -1793,13 +1859,14 @@ export type Entity<T = unknown> = number & { __T: T }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Iter<T...> = (query: Query<T...>) -> () -> (Entity, T...)
 | 
					type Iter<T...> = (query: Query<T...>) -> () -> (Entity, T...)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Query<T...> = typeof(setmetatable({}, {
 | 
					export type Query<T...> = typeof(setmetatable({}, {
 | 
				
			||||||
	__iter = (nil :: any) :: Iter<T...>,
 | 
						__iter = (nil :: any) :: Iter<T...>,
 | 
				
			||||||
})) & {
 | 
					})) & {
 | 
				
			||||||
	iter: Iter<T...>,
 | 
						iter: Iter<T...>,
 | 
				
			||||||
	with: (self: Query<T...>, ...i53) -> Query<T...>,
 | 
						with: (self: Query<T...>, ...Id) -> Query<T...>,
 | 
				
			||||||
	without: (self: Query<T...>, ...i53) -> Query<T...>,
 | 
						without: (self: Query<T...>, ...Id) -> Query<T...>,
 | 
				
			||||||
	archetypes: (self: Query<T...>) -> { Archetype },
 | 
						archetypes: (self: Query<T...>) -> { Archetype },
 | 
				
			||||||
 | 
						cached: (self: Query<T...>) -> Query<T...>
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export type World = {
 | 
					export type World = {
 | 
				
			||||||
| 
						 | 
					@ -1812,6 +1879,8 @@ export type World = {
 | 
				
			||||||
	nextComponentId: number,
 | 
						nextComponentId: number,
 | 
				
			||||||
	nextEntityId: number,
 | 
						nextEntityId: number,
 | 
				
			||||||
	nextArchetypeId: number,
 | 
						nextArchetypeId: number,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						observerable: { [string]: { [Id]: { query: Query<i53> } } }
 | 
				
			||||||
} & {
 | 
					} & {
 | 
				
			||||||
	--- Creates a new entity
 | 
						--- Creates a new entity
 | 
				
			||||||
	entity: (self: World) -> Entity,
 | 
						entity: (self: World) -> Entity,
 | 
				
			||||||
| 
						 | 
					@ -1854,42 +1923,7 @@ export type World = {
 | 
				
			||||||
	children: (self: World, id: Id) -> () -> Entity,
 | 
						children: (self: World, id: Id) -> () -> Entity,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	--- Searches the world for entities that match a given query
 | 
						--- Searches the world for entities that match a given query
 | 
				
			||||||
	query: (<A>(self: World, Id<A>) -> Query<A>)
 | 
						query: (<A>(self: World, a: { __T: A }) -> Query<A>)
 | 
				
			||||||
		& (<A, B>(self: World, Id<A>, Id<B>) -> Query<A, B>)
 | 
					 | 
				
			||||||
		& (<A, B, C>(self: World, Id<A>, Id<B>, Id<C>) -> Query<A, B, C>)
 | 
					 | 
				
			||||||
		& (<A, B, C, D>(self: World, Id<A>, Id<B>, Id<C>, Id<D>) -> Query<A, B, C, D>)
 | 
					 | 
				
			||||||
		& (<A, B, C, D, E>(self: World, Id<A>, Id<B>, Id<C>, Id<D>, Id<E>) -> Query<A, B, C, D, E>)
 | 
					 | 
				
			||||||
		& (<A, B, C, D, E, F>(
 | 
					 | 
				
			||||||
			self: World,
 | 
					 | 
				
			||||||
			Id<A>,
 | 
					 | 
				
			||||||
			Id<B>,
 | 
					 | 
				
			||||||
			Id<C>,
 | 
					 | 
				
			||||||
			Id<D>,
 | 
					 | 
				
			||||||
			Id<E>,
 | 
					 | 
				
			||||||
			Id<F>
 | 
					 | 
				
			||||||
		) -> Query<A, B, C, D, E, F>)
 | 
					 | 
				
			||||||
		& (<A, B, C, D, E, F, G>(
 | 
					 | 
				
			||||||
			self: World,
 | 
					 | 
				
			||||||
			Id<A>,
 | 
					 | 
				
			||||||
			Id<B>,
 | 
					 | 
				
			||||||
			Id<C>,
 | 
					 | 
				
			||||||
			Id<D>,
 | 
					 | 
				
			||||||
			Id<E>,
 | 
					 | 
				
			||||||
			Id<F>,
 | 
					 | 
				
			||||||
			Id<G>
 | 
					 | 
				
			||||||
		) -> Query<A, B, C, D, E, F, G>)
 | 
					 | 
				
			||||||
		& (<A, B, C, D, E, F, G, H>(
 | 
					 | 
				
			||||||
			self: World,
 | 
					 | 
				
			||||||
			Id<A>,
 | 
					 | 
				
			||||||
			Id<B>,
 | 
					 | 
				
			||||||
			Id<C>,
 | 
					 | 
				
			||||||
			Id<D>,
 | 
					 | 
				
			||||||
			Id<E>,
 | 
					 | 
				
			||||||
			Id<F>,
 | 
					 | 
				
			||||||
			Id<G>,
 | 
					 | 
				
			||||||
			Id<H>,
 | 
					 | 
				
			||||||
			...Id<any>
 | 
					 | 
				
			||||||
		) -> Query<A, B, C, D, E, F, G, H>),
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
return {
 | 
					return {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue