mirror of
				https://github.com/Ukendio/jecs.git
				synced 2025-10-31 01:09:16 +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