mirror of
				https://github.com/Ukendio/jecs.git
				synced 2025-10-31 09:09:18 +00:00 
			
		
		
		
	Cleanup functions and add missing types (#53)
* update * Cleanup functions and add missing types * Replace 0x10 with ECS_ID_FLAGS_MASK * Fixes
This commit is contained in:
		
							parent
							
								
									1d7fe3d93a
								
							
						
					
					
						commit
						f852ca9a88
					
				
					 1 changed files with 54 additions and 59 deletions
				
			
		
							
								
								
									
										113
									
								
								lib/init.lua
									
									
									
									
									
								
							
							
						
						
									
										113
									
								
								lib/init.lua
									
									
									
									
									
								
							|  | @ -11,14 +11,14 @@ type ArchetypeId = number | ||||||
| 
 | 
 | ||||||
| type Column = { any } | type Column = { any } | ||||||
| 
 | 
 | ||||||
|  | type ArchetypeEdge = { | ||||||
|  | 	add: Archetype, | ||||||
|  | 	remove: Archetype, | ||||||
|  | } | ||||||
|  | 
 | ||||||
| type Archetype = { | type Archetype = { | ||||||
| 	id: number, | 	id: number, | ||||||
| 	edges: { | 	edges: { [i53]: ArchetypeEdge }, | ||||||
| 		[i53]: { |  | ||||||
| 			add: Archetype, |  | ||||||
| 			remove: Archetype, |  | ||||||
| 		}, |  | ||||||
| 	}, |  | ||||||
| 	types: Ty, | 	types: Ty, | ||||||
| 	type: string | number, | 	type: string | number, | ||||||
| 	entities: { number }, | 	entities: { number }, | ||||||
|  | @ -75,7 +75,7 @@ local ECS_ID_FLAGS_MASK = 0x10 | ||||||
| local ECS_ENTITY_MASK = bit32.lshift(1, 24) | local ECS_ENTITY_MASK = bit32.lshift(1, 24) | ||||||
| local ECS_GENERATION_MASK = bit32.lshift(1, 16) | local ECS_GENERATION_MASK = bit32.lshift(1, 16) | ||||||
| 
 | 
 | ||||||
| local function addFlags(isPair: boolean) | local function addFlags(isPair: boolean): number | ||||||
| 	local typeFlags = 0x0 | 	local typeFlags = 0x0 | ||||||
| 
 | 
 | ||||||
| 	if isPair then | 	if isPair then | ||||||
|  | @ -95,29 +95,21 @@ local function addFlags(isPair: boolean) | ||||||
| end | end | ||||||
| 
 | 
 | ||||||
| local function ECS_COMBINE(source: number, target: number): i53 | local function ECS_COMBINE(source: number, target: number): i53 | ||||||
| 	local e = source * 268435456 + target * ECS_ID_FLAGS_MASK | 	return (source * 268435456) + (target * ECS_ID_FLAGS_MASK) | ||||||
| 	return e |  | ||||||
| end | end | ||||||
| 
 | 
 | ||||||
| local function ECS_IS_PAIR(e: number) | local function ECS_IS_PAIR(e: number): boolean | ||||||
| 	if e > ECS_ENTITY_MASK then | 	return if e > ECS_ENTITY_MASK then (e % ECS_ID_FLAGS_MASK) // FLAGS_PAIR ~= 0 else false | ||||||
| 		return (e % 2 ^ 4) // FLAGS_PAIR ~= 0 |  | ||||||
| 	end |  | ||||||
| 	return false |  | ||||||
| end | end | ||||||
| 
 | 
 | ||||||
| -- HIGH 24 bits LOW 24 bits | -- HIGH 24 bits LOW 24 bits | ||||||
| local function ECS_GENERATION(e: i53) | local function ECS_GENERATION(e: i53): i24 | ||||||
| 	if e > ECS_ENTITY_MASK then | 	return if e > ECS_ENTITY_MASK then (e // ECS_ID_FLAGS_MASK) % ECS_GENERATION_MASK else 0 | ||||||
| 		e = e // 0x10 |  | ||||||
| 		return e % ECS_GENERATION_MASK |  | ||||||
| 	end |  | ||||||
| 	return 0 |  | ||||||
| end | end | ||||||
| 
 | 
 | ||||||
| local function ECS_GENERATION_INC(e: i53) | local function ECS_GENERATION_INC(e: i53) | ||||||
| 	if e > ECS_ENTITY_MASK then | 	if e > ECS_ENTITY_MASK then | ||||||
| 		local flags = e // 0x10 | 		local flags = e // ECS_ID_FLAGS_MASK | ||||||
| 		local id = flags // ECS_ENTITY_MASK | 		local id = flags // ECS_ENTITY_MASK | ||||||
| 		local generation = flags % ECS_GENERATION_MASK | 		local generation = flags % ECS_GENERATION_MASK | ||||||
| 
 | 
 | ||||||
|  | @ -128,29 +120,20 @@ end | ||||||
| 
 | 
 | ||||||
| -- FIRST gets the high ID | -- FIRST gets the high ID | ||||||
| local function ECS_ENTITY_T_HI(e: i53): i24 | local function ECS_ENTITY_T_HI(e: i53): i24 | ||||||
| 	if e > ECS_ENTITY_MASK then | 	return if e > ECS_ENTITY_MASK then (e // ECS_ID_FLAGS_MASK) % ECS_ENTITY_MASK else e | ||||||
| 		e = e // 0x10 |  | ||||||
| 		return e % ECS_ENTITY_MASK |  | ||||||
| 	end |  | ||||||
| 	return e |  | ||||||
| end | end | ||||||
| 
 | 
 | ||||||
| -- SECOND | -- SECOND | ||||||
| local function ECS_ENTITY_T_LO(e: i53): i24 | local function ECS_ENTITY_T_LO(e: i53): i24 | ||||||
| 	if e > ECS_ENTITY_MASK then | 	return if e > ECS_ENTITY_MASK then (e // ECS_ID_FLAGS_MASK) // ECS_ENTITY_MASK else e | ||||||
| 		e = e // 0x10 |  | ||||||
| 		return e // ECS_ENTITY_MASK |  | ||||||
| 	end |  | ||||||
| 	return e |  | ||||||
| end | end | ||||||
| 
 | 
 | ||||||
| local function ECS_PAIR(pred: i53, obj: i53): i53 | local function ECS_PAIR(pred: i53, obj: i53): i53 | ||||||
| 	return ECS_COMBINE(ECS_ENTITY_T_LO(obj), ECS_ENTITY_T_LO(pred)) + addFlags(--[[isPair]] true) :: i53 | 	return ECS_COMBINE(ECS_ENTITY_T_LO(obj), ECS_ENTITY_T_LO(pred)) + addFlags(--[[isPair]] true) :: i53 | ||||||
| end | end | ||||||
| 
 | 
 | ||||||
| local function getAlive(entityIndex: EntityIndex, id: i24) | local function getAlive(entityIndex: EntityIndex, id: i24): i53 | ||||||
| 	local entityId = entityIndex.dense[id] | 	return entityIndex.dense[id] | ||||||
| 	return entityId |  | ||||||
| end | end | ||||||
| 
 | 
 | ||||||
| -- ECS_PAIR_FIRST, gets the relationship target / obj / HIGH bits | -- ECS_PAIR_FIRST, gets the relationship target / obj / HIGH bits | ||||||
|  | @ -236,7 +219,7 @@ local function archetypeAppend(entity: number, archetype: Archetype): number | ||||||
| 	return length | 	return length | ||||||
| end | end | ||||||
| 
 | 
 | ||||||
| local function newEntity(entityId: i53, record: Record, archetype: Archetype) | local function newEntity(entityId: i53, record: Record, archetype: Archetype): Record | ||||||
| 	local row = archetypeAppend(entityId, archetype) | 	local row = archetypeAppend(entityId, archetype) | ||||||
| 	record.archetype = archetype | 	record.archetype = archetype | ||||||
| 	record.row = row | 	record.row = row | ||||||
|  | @ -252,7 +235,7 @@ local function moveEntity(entityIndex: EntityIndex, entityId: i53, record: Recor | ||||||
| 	record.row = destinationRow | 	record.row = destinationRow | ||||||
| end | end | ||||||
| 
 | 
 | ||||||
| local function hash(arr): string | local function hash(arr: { number }): string | ||||||
| 	return table.concat(arr, "_") | 	return table.concat(arr, "_") | ||||||
| end | end | ||||||
| 
 | 
 | ||||||
|  | @ -262,10 +245,10 @@ local function ensureComponentRecord( | ||||||
| 	componentId: number, | 	componentId: number, | ||||||
| 	i: number | 	i: number | ||||||
| ): ArchetypeMap | ): ArchetypeMap | ||||||
| 	local archetypesMap = componentIndex[componentId]  | 	local archetypesMap = componentIndex[componentId] | ||||||
| 
 | 
 | ||||||
| 	if not archetypesMap then | 	if not archetypesMap then | ||||||
| 		archetypesMap = ({ size = 0, cache = {} }  :: any) :: ArchetypeMap | 		archetypesMap = ({ size = 0, cache = {} } :: any) :: ArchetypeMap | ||||||
| 		componentIndex[componentId] = archetypesMap | 		componentIndex[componentId] = archetypesMap | ||||||
| 	end | 	end | ||||||
| 
 | 
 | ||||||
|  | @ -275,7 +258,7 @@ local function ensureComponentRecord( | ||||||
| 	return archetypesMap | 	return archetypesMap | ||||||
| end | end | ||||||
| 
 | 
 | ||||||
| local function ECS_ID_IS_WILDCARD(e) | local function ECS_ID_IS_WILDCARD(e: i53): boolean | ||||||
| 	assert(ECS_IS_PAIR(e)) | 	assert(ECS_IS_PAIR(e)) | ||||||
| 	local first = ECS_ENTITY_T_HI(e) | 	local first = ECS_ENTITY_T_HI(e) | ||||||
| 	local second = ECS_ENTITY_T_LO(e) | 	local second = ECS_ENTITY_T_LO(e) | ||||||
|  | @ -329,7 +312,8 @@ end | ||||||
| 
 | 
 | ||||||
| local World = {} | local World = {} | ||||||
| World.__index = World | World.__index = World | ||||||
| function World.new() | 
 | ||||||
|  | function World.new(): World | ||||||
| 	local self = setmetatable({ | 	local self = setmetatable({ | ||||||
| 		archetypeIndex = {} :: { [string]: Archetype }, | 		archetypeIndex = {} :: { [string]: Archetype }, | ||||||
| 		archetypes = {} :: Archetypes, | 		archetypes = {} :: Archetypes, | ||||||
|  | @ -347,12 +331,13 @@ function World.new() | ||||||
| 		ROOT_ARCHETYPE = (nil :: any) :: Archetype, | 		ROOT_ARCHETYPE = (nil :: any) :: Archetype, | ||||||
| 	}, World) | 	}, World) | ||||||
| 	self.ROOT_ARCHETYPE = archetypeOf(self, {}) | 	self.ROOT_ARCHETYPE = archetypeOf(self, {}) | ||||||
|  | 
 | ||||||
| 	return self | 	return self | ||||||
| end | end | ||||||
| 
 | 
 | ||||||
| export type World = typeof(World.new()) | export type World = typeof(World.new()) | ||||||
| 
 | 
 | ||||||
| function World.component(world: World) | function World.component(world: World): i53 | ||||||
| 	local componentId = world.nextComponentId + 1 | 	local componentId = world.nextComponentId + 1 | ||||||
| 	if componentId > HI_COMPONENT_ID then | 	if componentId > HI_COMPONENT_ID then | ||||||
| 		-- IDs are partitioned into ranges because component IDs are not nominal, | 		-- IDs are partitioned into ranges because component IDs are not nominal, | ||||||
|  | @ -363,7 +348,7 @@ function World.component(world: World) | ||||||
| 	return nextEntityId(world.entityIndex, componentId) | 	return nextEntityId(world.entityIndex, componentId) | ||||||
| end | end | ||||||
| 
 | 
 | ||||||
| function World.entity(world: World) | function World.entity(world: World): i53 | ||||||
| 	local entityId = world.nextEntityId + 1 | 	local entityId = world.nextEntityId + 1 | ||||||
| 	world.nextEntityId = entityId | 	world.nextEntityId = entityId | ||||||
| 	return nextEntityId(world.entityIndex, entityId + REST) | 	return nextEntityId(world.entityIndex, entityId + REST) | ||||||
|  | @ -411,6 +396,7 @@ local function archetypeDelete(world: World, id: i53) | ||||||
| 	local componentIndex = world.componentIndex | 	local componentIndex = world.componentIndex | ||||||
| 	local archetypesMap = componentIndex[id] | 	local archetypesMap = componentIndex[id] | ||||||
| 	local archetypes = world.archetypes | 	local archetypes = world.archetypes | ||||||
|  | 
 | ||||||
| 	if archetypesMap then | 	if archetypesMap then | ||||||
| 		for archetypeId in archetypesMap.cache do | 		for archetypeId in archetypesMap.cache do | ||||||
| 			for _, entity in archetypes[archetypeId].entities do | 			for _, entity in archetypes[archetypeId].entities do | ||||||
|  | @ -472,7 +458,7 @@ local function ensureArchetype(world: World, types, prev): Archetype | ||||||
| 	return archetypeOf(world, types, prev) | 	return archetypeOf(world, types, prev) | ||||||
| end | end | ||||||
| 
 | 
 | ||||||
| local function findInsert(types: { i53 }, toAdd: i53) | local function findInsert(types: { i53 }, toAdd: i53): number | ||||||
| 	for i, id in types do | 	for i, id in types do | ||||||
| 		if id == toAdd then | 		if id == toAdd then | ||||||
| 			return -1 | 			return -1 | ||||||
|  | @ -484,7 +470,7 @@ local function findInsert(types: { i53 }, toAdd: i53) | ||||||
| 	return #types + 1 | 	return #types + 1 | ||||||
| end | end | ||||||
| 
 | 
 | ||||||
| local function findArchetypeWith(world: World, node: Archetype, componentId: i53) | local function findArchetypeWith(world: World, node: Archetype, componentId: i53): Archetype | ||||||
| 	local types = node.types | 	local types = node.types | ||||||
| 	-- Component IDs are added incrementally, so inserting and sorting | 	-- Component IDs are added incrementally, so inserting and sorting | ||||||
| 	-- them each time would be expensive. Instead this insertion sort can find the insertion | 	-- them each time would be expensive. Instead this insertion sort can find the insertion | ||||||
|  | @ -502,7 +488,7 @@ local function findArchetypeWith(world: World, node: Archetype, componentId: i53 | ||||||
| 	return ensureArchetype(world, destinationType, node) | 	return ensureArchetype(world, destinationType, node) | ||||||
| end | end | ||||||
| 
 | 
 | ||||||
| local function ensureEdge(archetype: Archetype, componentId: i53) | local function ensureEdge(archetype: Archetype, componentId: i53): ArchetypeEdge | ||||||
| 	local edges = archetype.edges | 	local edges = archetype.edges | ||||||
| 	local edge = edges[componentId] | 	local edge = edges[componentId] | ||||||
| 	if not edge then | 	if not edge then | ||||||
|  | @ -600,7 +586,7 @@ function World.remove(world: World, entityId: i53, componentId: i53) | ||||||
| end | end | ||||||
| 
 | 
 | ||||||
| -- Keeping the function as small as possible to enable inlining | -- Keeping the function as small as possible to enable inlining | ||||||
| local function get(record: Record, componentId: i24) | local function get(record: Record, componentId: i24): any | ||||||
| 	local archetype = record.archetype | 	local archetype = record.archetype | ||||||
| 	if not archetype then | 	if not archetype then | ||||||
| 		return nil | 		return nil | ||||||
|  | @ -615,7 +601,7 @@ local function get(record: Record, componentId: i24) | ||||||
| 	return archetype.columns[archetypeRecord][record.row] | 	return archetype.columns[archetypeRecord][record.row] | ||||||
| end | end | ||||||
| 
 | 
 | ||||||
| function World.get(world: World, entityId: i53, a: i53, b: i53?, c: i53?, d: i53?, e: i53?): any | function World.get(world: World, entityId: i53, a: i53, b: i53?, c: i53?, d: i53?, e: i53?): ...any | ||||||
| 	local id = entityId | 	local id = entityId | ||||||
| 	local record = world.entityIndex.sparse[id] | 	local record = world.entityIndex.sparse[id] | ||||||
| 	if not record then | 	if not record then | ||||||
|  | @ -654,9 +640,7 @@ export type Query = typeof(EmptyQuery) | ||||||
| 
 | 
 | ||||||
| type CompatibleArchetype = { archetype: Archetype, indices: { number } } | type CompatibleArchetype = { archetype: Archetype, indices: { number } } | ||||||
| 
 | 
 | ||||||
| local function PreparedQuery( | local function PreparedQuery(compatibleArchetypes: { CompatibleArchetype } , components: { i53 })  | ||||||
| 	compatibleArchetypes: { CompatibleArchetype } , components: { i53 })  |  | ||||||
| 
 |  | ||||||
| 	local queryLength = #components | 	local queryLength = #components | ||||||
| 	 | 	 | ||||||
| 	local lastArchetype = 1 | 	local lastArchetype = 1 | ||||||
|  | @ -673,7 +657,7 @@ local function PreparedQuery( | ||||||
| 
 | 
 | ||||||
| 	local i = 1 | 	local i = 1 | ||||||
| 
 | 
 | ||||||
| 	local function queryNext()  | 	local function queryNext(): ...any | ||||||
| 		local archetype = compatibleArchetype.archetype | 		local archetype = compatibleArchetype.archetype | ||||||
| 		local entityId = archetype.entities[i] | 		local entityId = archetype.entities[i] | ||||||
| 
 | 
 | ||||||
|  | @ -745,15 +729,15 @@ local function PreparedQuery( | ||||||
| 		return entityId, unpack(queryOutput, 1, queryLength) | 		return entityId, unpack(queryOutput, 1, queryLength) | ||||||
| 	end | 	end | ||||||
| 	 | 	 | ||||||
| 	function preparedQuery:__iter() | 	function preparedQuery:__iter(): () -> ...any | ||||||
| 		return queryNext | 		return queryNext | ||||||
| 	end | 	end | ||||||
| 
 | 
 | ||||||
| 	function preparedQuery:next()  | 	function preparedQuery:next(): ...any | ||||||
| 		return queryNext()	 | 		return queryNext()	 | ||||||
| 	end | 	end | ||||||
| 
 | 
 | ||||||
| 	function preparedQuery:without(...) | 	function preparedQuery:without(...: any): Query | ||||||
| 		local withoutComponents = { ... } | 		local withoutComponents = { ... } | ||||||
| 		for i = #compatibleArchetypes, 1, -1 do | 		for i = #compatibleArchetypes, 1, -1 do | ||||||
| 			local archetype = compatibleArchetypes[i].archetype | 			local archetype = compatibleArchetypes[i].archetype | ||||||
|  | @ -783,7 +767,7 @@ local function PreparedQuery( | ||||||
| 	return setmetatable({}, preparedQuery) :: any | 	return setmetatable({}, preparedQuery) :: any | ||||||
| end | end | ||||||
| 
 | 
 | ||||||
| function World.query(world: World, ...): Query | function World.query(world: World, ...: any): Query | ||||||
| 	-- breaking? | 	-- breaking? | ||||||
| 	if (...) == nil then | 	if (...) == nil then | ||||||
| 		error("Missing components") | 		error("Missing components") | ||||||
|  | @ -840,15 +824,20 @@ function World.query(world: World, ...): Query | ||||||
| 	return PreparedQuery(compatibleArchetypes, components) | 	return PreparedQuery(compatibleArchetypes, components) | ||||||
| end | end | ||||||
| 
 | 
 | ||||||
| function World.__iter(world: World): () -> any  | type WorldIterator = (() -> (i53, { [unknown]: unknown? })) & (() -> ()) & (() -> i53) | ||||||
|  | 
 | ||||||
|  | function World.__iter(world: World): WorldIterator | ||||||
| 	local dense = world.entityIndex.dense | 	local dense = world.entityIndex.dense | ||||||
| 	local sparse = world.entityIndex.sparse | 	local sparse = world.entityIndex.sparse | ||||||
| 	local last | 	local last | ||||||
| 
 | 
 | ||||||
| 	return function() | 	-- new solver doesnt like the world iterator type even tho its correct | ||||||
|  | 	-- so any cast here i come | ||||||
|  | 	local function iterator() | ||||||
| 		local lastEntity: number?, entityId: number = next(dense, last) | 		local lastEntity: number?, entityId: number = next(dense, last) | ||||||
| 		if not lastEntity then  | 		if not lastEntity then | ||||||
| 			return  | 			-- ignore type error | ||||||
|  | 			return | ||||||
| 		end | 		end | ||||||
| 
 | 
 | ||||||
| 		last = lastEntity | 		last = lastEntity | ||||||
|  | @ -872,8 +861,14 @@ function World.__iter(world: World): () -> any | ||||||
| 
 | 
 | ||||||
| 		return entityId, entityData | 		return entityId, entityData | ||||||
| 	end | 	end | ||||||
|  | 
 | ||||||
|  | 	return iterator :: any | ||||||
| end | end | ||||||
| 
 | 
 | ||||||
|  | -- freezing it incase somebody tries doing something stupid and modifying it | ||||||
|  | -- (unlikely but its easy to add extra safety so) | ||||||
|  | table.freeze(World) | ||||||
|  | 
 | ||||||
| -- __nominal_type_dont_use could not be any or T as it causes a type error | -- __nominal_type_dont_use could not be any or T as it causes a type error | ||||||
| -- or produces a union | -- or produces a union | ||||||
| export type Entity<T = any> = number & { __nominal_type_dont_use: T } | export type Entity<T = any> = number & { __nominal_type_dont_use: T } | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue