mirror of
				https://github.com/Ukendio/jecs.git
				synced 2025-10-30 16:59:17 +00:00 
			
		
		
		
	Add docs (#45)
* Initial commit * Add section for standalone * Fix docs * Add pages to docs * Remove redundant files
This commit is contained in:
		
							parent
							
								
									f1ba9c4a55
								
							
						
					
					
						commit
						0567856a59
					
				
					 7 changed files with 665 additions and 412 deletions
				
			
		|  | @ -31,7 +31,7 @@ local Name = world:component() | ||||||
| local function parent(entity)  | local function parent(entity)  | ||||||
|     return world:target(entity, ChildOf) |     return world:target(entity, ChildOf) | ||||||
| end | end | ||||||
| local function name(entity)  | local function getName(entity)  | ||||||
|     return world:get(entity, Name) |     return world:get(entity, Name) | ||||||
| end | end | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
							
								
								
									
										45
									
								
								docs/api-types.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								docs/api-types.md
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,45 @@ | ||||||
|  | # World | ||||||
|  | 
 | ||||||
|  | A World contains all ECS data | ||||||
|  | Games can have multiple worlds, although typically only one is necessary. These worlds are isolated from each other, meaning they donot share the same entities nor component IDs. | ||||||
|  | 
 | ||||||
|  | --- | ||||||
|  | 
 | ||||||
|  | # Entity | ||||||
|  | 
 | ||||||
|  | An unique id. | ||||||
|  | 
 | ||||||
|  | Entities consist out of a number unique to the entity in the lower 32 bits, and a counter used to track entity liveliness in the upper 32 bits. When an id is recycled, its generation count is increased. This causes recycled ids to be very large (>4 billion), which is normal. | ||||||
|  | 
 | ||||||
|  | --- | ||||||
|  | 
 | ||||||
|  | # QueryIter | ||||||
|  | 
 | ||||||
|  | A result from the `World:query` function. | ||||||
|  | 
 | ||||||
|  | Queries are used to iterate over entities that match against the set collection of components. | ||||||
|  | 
 | ||||||
|  | Calling it in a loop will allow iteration over the results. | ||||||
|  | 
 | ||||||
|  | ```lua | ||||||
|  | for id, enemy, charge, model in world:query(Enemy, Charge, Model) do | ||||||
|  | 	-- Do something | ||||||
|  | end | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ### QueryIter.without | ||||||
|  | 
 | ||||||
|  | QueryIter.without(iter: QueryIter | ||||||
|  |                   ...: [Entity](../api-types/Entity)): QueryIter | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | Create a new Query Iterator from the filter | ||||||
|  | 
 | ||||||
|  | #### Parameters | ||||||
|  |     world   The world. | ||||||
|  |     ...     The collection of components to filter archetypes against. | ||||||
|  | 
 | ||||||
|  | #### Returns | ||||||
|  | 
 | ||||||
|  | The new query iterator. | ||||||
|  | 
 | ||||||
							
								
								
									
										19
									
								
								docs/tutorials/quick-start/getting-started.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								docs/tutorials/quick-start/getting-started.md
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,19 @@ | ||||||
|  | # Getting Started  | ||||||
|  | This section will provide a walk through setting up your development environment and a quick overview of the different features and concepts in Jecs with short examples. | ||||||
|  | 
 | ||||||
|  | ## Installing Jecs | ||||||
|  | 
 | ||||||
|  | To use Jecs, you will need to add the library to your project's source folder. | ||||||
|  | 
 | ||||||
|  | ## Installing as standalone | ||||||
|  | Head over to the [Releases](https://github.com/ukendio/jecs/releases/latest) page and install the rbxm file. | ||||||
|  |  | ||||||
|  | 
 | ||||||
|  | ## Installing with Wally | ||||||
|  | Jecs is available as a package on [wally.run](https://wally.run/package/ukendio/jecs) | ||||||
|  | 
 | ||||||
|  | Add it to your project's Wally.toml like this: | ||||||
|  | ```toml | ||||||
|  | [dependencies] | ||||||
|  | jecs = "0.1.0" # Make sure this is the latest version | ||||||
|  | ``` | ||||||
							
								
								
									
										
											BIN
										
									
								
								docs/tutorials/quick-start/rbxm.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								docs/tutorials/quick-start/rbxm.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 34 KiB | 
							
								
								
									
										121
									
								
								lib/init.lua
									
									
									
									
									
								
							
							
						
						
									
										121
									
								
								lib/init.lua
									
									
									
									
									
								
							|  | @ -26,12 +26,11 @@ type Archetype = { | ||||||
| 	records: {}, | 	records: {}, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| type Record = { | type Record = { | ||||||
| 	archetype: Archetype, | 	archetype: Archetype, | ||||||
| 	row: number, | 	row: number, | ||||||
| 	dense: i24, | 	dense: i24, | ||||||
| 	componentRecord: ArchetypeMap | 	componentRecord: ArchetypeMap, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| type EntityIndex = { dense: { [i24]: i53 }, sparse: { [i53]: Record } } | type EntityIndex = { dense: { [i24]: i53 }, sparse: { [i53]: Record } } | ||||||
|  | @ -52,7 +51,7 @@ type ArchetypeMap = { | ||||||
| 	first: ArchetypeMap, | 	first: ArchetypeMap, | ||||||
| 	second: ArchetypeMap, | 	second: ArchetypeMap, | ||||||
| 	parent: ArchetypeMap, | 	parent: ArchetypeMap, | ||||||
| 	size: number | 	size: number, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| type ComponentIndex = { [i24]: ArchetypeMap } | type ComponentIndex = { [i24]: ArchetypeMap } | ||||||
|  | @ -96,7 +95,7 @@ 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 * 2^28 + target * ECS_ID_FLAGS_MASK | 	local e = source * 268435456 + target * ECS_ID_FLAGS_MASK | ||||||
| 	return e | 	return e | ||||||
| end | end | ||||||
| 
 | 
 | ||||||
|  | @ -104,38 +103,33 @@ local function ECS_IS_PAIR(e: number) | ||||||
| 	return (e % 2 ^ 4) // FLAGS_PAIR ~= 0 | 	return (e % 2 ^ 4) // FLAGS_PAIR ~= 0 | ||||||
| end | end | ||||||
| 
 | 
 | ||||||
| function separate(entity: number) |  | ||||||
|     local _typeFlags = entity % 0x10 |  | ||||||
|     entity //= ECS_ID_FLAGS_MASK |  | ||||||
|     return entity // ECS_ENTITY_MASK, entity % ECS_GENERATION_MASK, _typeFlags |  | ||||||
| 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) | ||||||
|     e //= 0x10 | 	e = e // 0x10 | ||||||
| 	return e % ECS_GENERATION_MASK | 	return e % ECS_GENERATION_MASK | ||||||
| end | end | ||||||
| 
 | 
 | ||||||
| -- SECOND |  | ||||||
| local function ECS_ENTITY_T_LO(e: i53)  |  | ||||||
|     e //= 0x10 |  | ||||||
|     return e // ECS_ENTITY_MASK |  | ||||||
| end |  | ||||||
| 
 |  | ||||||
| local function ECS_GENERATION_INC(e: i53) | local function ECS_GENERATION_INC(e: i53) | ||||||
|     local id, generation, flags = separate(e)     | 	local flags = e // 0x10 | ||||||
|  | 	local id = flags // ECS_ENTITY_MASK | ||||||
|  | 	local generation = flags % ECS_GENERATION_MASK | ||||||
| 
 | 
 | ||||||
| 	return ECS_COMBINE(id, generation + 1) + flags | 	return ECS_COMBINE(id, generation + 1) + flags | ||||||
| end | end | ||||||
| 
 | 
 | ||||||
| -- FIRST gets the high ID | -- FIRST gets the high ID | ||||||
| local function ECS_ENTITY_T_HI(entity: i53): i24 | local function ECS_ENTITY_T_HI(e: i53): i24 | ||||||
|     entity //= 0x10 | 	e = e // 0x10 | ||||||
|     local first = entity % ECS_ENTITY_MASK | 	return e % ECS_ENTITY_MASK | ||||||
|     return first |  | ||||||
| end | end | ||||||
| 
 | 
 | ||||||
| local function ECS_PAIR(pred: number, obj: number) | -- SECOND | ||||||
|  | local function ECS_ENTITY_T_LO(e: i53) | ||||||
|  | 	e = e // 0x10 | ||||||
|  | 	return e // ECS_ENTITY_MASK | ||||||
|  | end | ||||||
|  | 
 | ||||||
|  | local function ECS_PAIR(pred: i53, obj: i53): i53 | ||||||
| 	local first | 	local first | ||||||
| 	local second: number = WILDCARD | 	local second: number = WILDCARD | ||||||
| 
 | 
 | ||||||
|  | @ -148,35 +142,28 @@ local function ECS_PAIR(pred: number, obj: number) | ||||||
| 		second = ECS_ENTITY_T_LO(pred) | 		second = ECS_ENTITY_T_LO(pred) | ||||||
| 	end | 	end | ||||||
| 
 | 
 | ||||||
| 	return ECS_COMBINE( | 	return ECS_COMBINE(ECS_ENTITY_T_LO(first), second) + addFlags(--[[isPair]] true) | ||||||
| 		ECS_ENTITY_T_LO(first), second) + addFlags(--[[isPair]] true) |  | ||||||
| end | end | ||||||
| 
 | 
 | ||||||
| local function getAlive(entityIndex: EntityIndex, id: i24) | local function getAlive(entityIndex: EntityIndex, id: i24) | ||||||
| 	local entityId = entityIndex.dense[id] | 	local entityId = entityIndex.dense[id] | ||||||
| 	local record = entityIndex.sparse[entityIndex.dense[id]] |  | ||||||
| 	if not record then  |  | ||||||
| 		error(id.." is not alive") |  | ||||||
| 	end |  | ||||||
| 	return entityId | 	return entityId | ||||||
| end | end | ||||||
| 
 | 
 | ||||||
| -- ECS_PAIR_FIRST, gets the relationship target / obj / HIGH bits | -- ECS_PAIR_FIRST, gets the relationship target / obj / HIGH bits | ||||||
| local function ECS_PAIR_RELATION(entityIndex, e) | local function ECS_PAIR_RELATION(entityIndex, e) | ||||||
|     assert(ECS_IS_PAIR(e)) |  | ||||||
| 	return getAlive(entityIndex, ECS_ENTITY_T_HI(e)) | 	return getAlive(entityIndex, ECS_ENTITY_T_HI(e)) | ||||||
| end | end | ||||||
| 
 | 
 | ||||||
| -- ECS_PAIR_SECOND gets the relationship / pred / LOW bits | -- ECS_PAIR_SECOND gets the relationship / pred / LOW bits | ||||||
| local function ECS_PAIR_OBJECT(entityIndex, e) | local function ECS_PAIR_OBJECT(entityIndex, e) | ||||||
|     assert(ECS_IS_PAIR(e)) |  | ||||||
| 	return getAlive(entityIndex, ECS_ENTITY_T_LO(e)) | 	return getAlive(entityIndex, ECS_ENTITY_T_LO(e)) | ||||||
| end | end | ||||||
| 
 | 
 | ||||||
| local function nextEntityId(entityIndex, index: i24): i53 | local function nextEntityId(entityIndex, index: i24): i53 | ||||||
| 	local id = ECS_COMBINE(index, 0) | 	local id = ECS_COMBINE(index, 0) | ||||||
| 	entityIndex.sparse[id] = { | 	entityIndex.sparse[id] = { | ||||||
| 		dense = index | 		dense = index, | ||||||
| 	} :: Record | 	} :: Record | ||||||
| 	entityIndex.dense[index] = id | 	entityIndex.dense[index] = id | ||||||
| 
 | 
 | ||||||
|  | @ -252,7 +239,7 @@ local function newEntity(entityId: i53, record: Record, archetype: Archetype) | ||||||
| 	return record | 	return record | ||||||
| end | end | ||||||
| 
 | 
 | ||||||
| local function moveEntity(entityIndex, entityId: i53, record: Record, to: Archetype) | local function moveEntity(entityIndex: EntityIndex, entityId: i53, record: Record, to: Archetype) | ||||||
| 	local sourceRow = record.row | 	local sourceRow = record.row | ||||||
| 	local from = record.archetype | 	local from = record.archetype | ||||||
| 	local destinationRow = archetypeAppend(entityId, to) | 	local destinationRow = archetypeAppend(entityId, to) | ||||||
|  | @ -265,7 +252,12 @@ local function hash(arr): string | number | ||||||
| 	return table.concat(arr, "_") | 	return table.concat(arr, "_") | ||||||
| end | end | ||||||
| 
 | 
 | ||||||
| local function ensureComponentRecord(componentIndex: ComponentIndex, archetypeId, componentId, i): ArchetypeMap | local function ensureComponentRecord( | ||||||
|  | 	componentIndex: ComponentIndex, | ||||||
|  | 	archetypeId: number, | ||||||
|  | 	componentId: number, | ||||||
|  | 	i: number | ||||||
|  | ): ArchetypeMap | ||||||
| 	local archetypesMap = componentIndex[componentId] | 	local archetypesMap = componentIndex[componentId] | ||||||
| 
 | 
 | ||||||
| 	if not archetypesMap then | 	if not archetypesMap then | ||||||
|  | @ -286,7 +278,6 @@ local function ECS_ID_IS_WILDCARD(e) | ||||||
| 	return first == WILDCARD or second == WILDCARD | 	return first == WILDCARD or second == WILDCARD | ||||||
| end | end | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| local function archetypeOf(world: any, types: { i24 }, prev: Archetype?): Archetype | local function archetypeOf(world: any, types: { i24 }, prev: Archetype?): Archetype | ||||||
| 	local ty = hash(types) | 	local ty = hash(types) | ||||||
| 
 | 
 | ||||||
|  | @ -306,26 +297,24 @@ local function archetypeOf(world: any, types: {i24}, prev: Archetype?): Archetyp | ||||||
| 			local object = ECS_PAIR_OBJECT(world.entityIndex, componentId) | 			local object = ECS_PAIR_OBJECT(world.entityIndex, componentId) | ||||||
| 
 | 
 | ||||||
| 			local idr_r = ECS_PAIR(relation, WILDCARD) | 			local idr_r = ECS_PAIR(relation, WILDCARD) | ||||||
| 			ensureComponentRecord( | 			ensureComponentRecord(componentIndex, id, idr_r, i) | ||||||
| 				componentIndex, id, idr_r, i) |  | ||||||
| 			records[idr_r] = i | 			records[idr_r] = i | ||||||
| 
 | 
 | ||||||
| 			local idr_t = ECS_PAIR(WILDCARD, object) | 			local idr_t = ECS_PAIR(WILDCARD, object) | ||||||
| 			ensureComponentRecord( | 			ensureComponentRecord(componentIndex, id, idr_t, i) | ||||||
| 				componentIndex, id, idr_t, i) |  | ||||||
| 			records[idr_t] = i | 			records[idr_t] = i | ||||||
| 		end | 		end | ||||||
| 		columns[i] = {} | 		columns[i] = {} | ||||||
| 	end | 	end | ||||||
| 
 | 
 | ||||||
| 	local archetype = { | 	local archetype = { | ||||||
| 		columns = columns; | 		columns = columns, | ||||||
| 		edges = {}; | 		edges = {}, | ||||||
| 		entities = {}; | 		entities = {}, | ||||||
| 		id = id; | 		id = id, | ||||||
| 		records = records; | 		records = records, | ||||||
| 		type = ty; | 		type = ty, | ||||||
| 		types = types; | 		types = types, | ||||||
| 	} | 	} | ||||||
| 	world.archetypeIndex[ty] = archetype | 	world.archetypeIndex[ty] = archetype | ||||||
| 	world.archetypes[id] = archetype | 	world.archetypes[id] = archetype | ||||||
|  | @ -337,20 +326,20 @@ local World = {} | ||||||
| World.__index = World | World.__index = World | ||||||
| function World.new() | function World.new() | ||||||
| 	local self = setmetatable({ | 	local self = setmetatable({ | ||||||
| 		archetypeIndex = {}; | 		archetypeIndex = {}, | ||||||
| 		archetypes = {} :: Archetypes; | 		archetypes = {} :: Archetypes, | ||||||
| 		componentIndex = {} :: ComponentIndex; | 		componentIndex = {} :: ComponentIndex, | ||||||
| 		entityIndex = { | 		entityIndex = { | ||||||
| 			dense = {}, | 			dense = {}, | ||||||
| 			sparse = {} | 			sparse = {}, | ||||||
| 		} :: EntityIndex; | 		} :: EntityIndex, | ||||||
| 		hooks = { | 		hooks = { | ||||||
| 			[ON_ADD] = {}; | 			[ON_ADD] = {}, | ||||||
| 		}; | 		}, | ||||||
| 		nextArchetypeId = 0; | 		nextArchetypeId = 0, | ||||||
| 		nextComponentId = 0; | 		nextComponentId = 0, | ||||||
| 		nextEntityId = 0; | 		nextEntityId = 0, | ||||||
| 		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 | ||||||
|  | @ -644,20 +633,20 @@ end | ||||||
| 
 | 
 | ||||||
| -- the less creation the better | -- the less creation the better | ||||||
| local function actualNoOperation() end | local function actualNoOperation() end | ||||||
| local function noop(_self: Query, ...: i53): () -> (number, ...any) | local function noop(_self: Query, ...): () -> () | ||||||
| 	return actualNoOperation :: any | 	return actualNoOperation :: any | ||||||
| end | end | ||||||
| 
 | 
 | ||||||
| local EmptyQuery = { | local EmptyQuery = { | ||||||
| 	__iter = noop; | 	__iter = noop, | ||||||
| 	without = noop; | 	without = noop, | ||||||
| } | } | ||||||
| EmptyQuery.__index = EmptyQuery | EmptyQuery.__index = EmptyQuery | ||||||
| setmetatable(EmptyQuery, EmptyQuery) | setmetatable(EmptyQuery, EmptyQuery) | ||||||
| 
 | 
 | ||||||
| export type Query = typeof(EmptyQuery) | export type Query = typeof(EmptyQuery) | ||||||
| 
 | 
 | ||||||
| function World.query(world: World, ...: i53): Query | function World.query(world: World, ...): Query | ||||||
| 	-- breaking? | 	-- breaking? | ||||||
| 	if (...) == nil then | 	if (...) == nil then | ||||||
| 		error("Missing components") | 		error("Missing components") | ||||||
|  | @ -708,7 +697,7 @@ function World.query(world: World, ...: i53): Query | ||||||
| 		length += 1 | 		length += 1 | ||||||
| 		compatibleArchetypes[length] = { | 		compatibleArchetypes[length] = { | ||||||
| 			archetype = archetype, | 			archetype = archetype, | ||||||
| 			indices = indices | 			indices = indices, | ||||||
| 		} | 		} | ||||||
| 	end | 	end | ||||||
| 
 | 
 | ||||||
|  | @ -857,11 +846,11 @@ function World.__iter(world: World): () -> (number?, unknown?) | ||||||
| end | end | ||||||
| 
 | 
 | ||||||
| return table.freeze({ | return table.freeze({ | ||||||
| 	World = World; | 	World = World, | ||||||
| 
 | 
 | ||||||
| 	OnAdd = ON_ADD; | 	OnAdd = ON_ADD, | ||||||
| 	OnRemove = ON_REMOVE; | 	OnRemove = ON_REMOVE, | ||||||
| 	OnSet = ON_SET; | 	OnSet = ON_SET, | ||||||
| 	Wildcard = WILDCARD, | 	Wildcard = WILDCARD, | ||||||
| 	w = WILDCARD, | 	w = WILDCARD, | ||||||
| 	Rest = REST, | 	Rest = REST, | ||||||
|  |  | ||||||
							
								
								
									
										186
									
								
								mkdocs.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										186
									
								
								mkdocs.yml
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,186 @@ | ||||||
|  | site_name: Fusion | ||||||
|  | site_url: https://elttob.uk/Fusion/ | ||||||
|  | repo_name: dphfox/Fusion | ||||||
|  | repo_url: https://github.com/dphfox/Fusion | ||||||
|  | 
 | ||||||
|  | extra: | ||||||
|  |   version: | ||||||
|  |     provider: mike | ||||||
|  | 
 | ||||||
|  | theme: | ||||||
|  |   name: material | ||||||
|  |   custom_dir: docs/assets/overrides | ||||||
|  |   logo: assets/logo | ||||||
|  |   favicon: assets/logo-dark.svg | ||||||
|  |   palette: | ||||||
|  |     - media: "(prefers-color-scheme: dark)" | ||||||
|  |       scheme: fusiondoc-dark | ||||||
|  |       toggle: | ||||||
|  |         icon: octicons/sun-24 | ||||||
|  |         title: Switch to light theme | ||||||
|  |     - media: "(prefers-color-scheme: light)" | ||||||
|  |       scheme: fusiondoc-light | ||||||
|  |       toggle: | ||||||
|  |         icon: octicons/moon-24 | ||||||
|  |         title: Switch to dark theme | ||||||
|  |   font: | ||||||
|  |     text: Plus Jakarta Sans | ||||||
|  |     code: JetBrains Mono | ||||||
|  |   features: | ||||||
|  |     - navigation.tabs | ||||||
|  |     - navigation.top | ||||||
|  |     - navigation.sections | ||||||
|  |     - navigation.instant | ||||||
|  |     - navigation.indexes | ||||||
|  |     - search.suggest | ||||||
|  |     - search.highlight | ||||||
|  |   icon: | ||||||
|  |     repo: octicons/mark-github-16 | ||||||
|  | 
 | ||||||
|  | extra_css: | ||||||
|  |   - assets/theme/fusiondoc.css | ||||||
|  |   - assets/theme/colours.css | ||||||
|  |   - assets/theme/code.css | ||||||
|  |   - assets/theme/paragraph.css | ||||||
|  |   - assets/theme/page.css | ||||||
|  |   - assets/theme/admonition.css | ||||||
|  |   - assets/theme/404.css | ||||||
|  |   - assets/theme/api-reference.css | ||||||
|  |   - assets/theme/dev-tools.css | ||||||
|  | 
 | ||||||
|  | extra_javascript: | ||||||
|  |   - assets/scripts/smooth-scroll.js | ||||||
|  | 
 | ||||||
|  | nav: | ||||||
|  |   - Home: index.md | ||||||
|  |   - Tutorials: | ||||||
|  |     - Get Started: tutorials/index.md | ||||||
|  |     - Installing Fusion: tutorials/get-started/installing-fusion.md | ||||||
|  |     - Developer Tools: tutorials/get-started/developer-tools.md | ||||||
|  |     - Getting Help: tutorials/get-started/getting-help.md | ||||||
|  |     - Fundamentals: | ||||||
|  |       - Scopes: tutorials/fundamentals/scopes.md | ||||||
|  |       - Values: tutorials/fundamentals/values.md | ||||||
|  |       - Observers: tutorials/fundamentals/observers.md | ||||||
|  |       - Computeds: tutorials/fundamentals/computeds.md | ||||||
|  |     - Tables: | ||||||
|  |       - ForValues: tutorials/tables/forvalues.md | ||||||
|  |       - ForKeys: tutorials/tables/forkeys.md | ||||||
|  |       - ForPairs: tutorials/tables/forpairs.md | ||||||
|  |     - Animation: | ||||||
|  |       - Tweens: tutorials/animation/tweens.md | ||||||
|  |       - Springs: tutorials/animation/springs.md | ||||||
|  |     - Roblox: | ||||||
|  |       - Hydration: tutorials/roblox/hydration.md | ||||||
|  |       - New Instances: tutorials/roblox/new-instances.md | ||||||
|  |       - Parenting: tutorials/roblox/parenting.md | ||||||
|  |       - Events: tutorials/roblox/events.md | ||||||
|  |       - Change Events: tutorials/roblox/change-events.md | ||||||
|  |       - Outputs: tutorials/roblox/outputs.md | ||||||
|  |       - References: tutorials/roblox/references.md | ||||||
|  |     - Best Practices: | ||||||
|  |       - Components: tutorials/best-practices/components.md | ||||||
|  |       - Instance Handling: tutorials/best-practices/instance-handling.md | ||||||
|  |       - Callbacks: tutorials/best-practices/callbacks.md | ||||||
|  |       - State: tutorials/best-practices/state.md | ||||||
|  |       - Sharing Values: tutorials/best-practices/sharing-values.md | ||||||
|  |       - Error Safety: tutorials/best-practices/error-safety.md | ||||||
|  |       - Optimisation: tutorials/best-practices/optimisation.md | ||||||
|  |      | ||||||
|  |   - Examples: | ||||||
|  |     - Home: examples/index.md | ||||||
|  |     - Cookbook: | ||||||
|  |       - examples/cookbook/index.md | ||||||
|  |       - Player List: examples/cookbook/player-list.md | ||||||
|  |       - Animated Computed: examples/cookbook/animated-computed.md | ||||||
|  |       - Fetch Data From Server: examples/cookbook/fetch-data-from-server.md | ||||||
|  |       - Light & Dark Theme: examples/cookbook/light-and-dark-theme.md | ||||||
|  |       - Button Component: examples/cookbook/button-component.md | ||||||
|  |       - Loading Spinner: examples/cookbook/loading-spinner.md | ||||||
|  |       - Drag & Drop: examples/cookbook/drag-and-drop.md | ||||||
|  |   - API Reference: | ||||||
|  |     - api-reference/index.md | ||||||
|  |     - General: | ||||||
|  |       - Errors: api-reference/general/errors.md | ||||||
|  |       - Types: | ||||||
|  |         - Contextual: api-reference/general/types/contextual.md | ||||||
|  |         - Version: api-reference/general/types/version.md | ||||||
|  |       - Members: | ||||||
|  |         - Contextual: api-reference/general/members/contextual.md | ||||||
|  |         - Safe: api-reference/general/members/safe.md | ||||||
|  |         - version: api-reference/general/members/version.md | ||||||
|  |     - Memory: | ||||||
|  |       - Types: | ||||||
|  |         - Scope: api-reference/memory/types/scope.md | ||||||
|  |         - ScopedObject: api-reference/memory/types/scopedobject.md | ||||||
|  |         - Task: api-reference/memory/types/task.md | ||||||
|  |       - Members: | ||||||
|  |         - deriveScope: api-reference/memory/members/derivescope.md | ||||||
|  |         - doCleanup: api-reference/memory/members/docleanup.md | ||||||
|  |         - scoped: api-reference/memory/members/scoped.md | ||||||
|  |     - State: | ||||||
|  |       - Types: | ||||||
|  |         - UsedAs: api-reference/state/types/usedas.md  | ||||||
|  |         - Computed: api-reference/state/types/computed.md  | ||||||
|  |         - Dependency: api-reference/state/types/dependency.md  | ||||||
|  |         - Dependent: api-reference/state/types/dependent.md  | ||||||
|  |         - For: api-reference/state/types/for.md  | ||||||
|  |         - Observer: api-reference/state/types/observer.md  | ||||||
|  |         - StateObject: api-reference/state/types/stateobject.md  | ||||||
|  |         - Use: api-reference/state/types/use.md  | ||||||
|  |         - Value: api-reference/state/types/value.md  | ||||||
|  |       - Members: | ||||||
|  |         - Computed: api-reference/state/members/computed.md | ||||||
|  |         - ForKeys: api-reference/state/members/forkeys.md | ||||||
|  |         - ForPairs: api-reference/state/members/forpairs.md | ||||||
|  |         - ForValues: api-reference/state/members/forvalues.md | ||||||
|  |         - Observer: api-reference/state/members/observer.md | ||||||
|  |         - peek: api-reference/state/members/peek.md | ||||||
|  |         - Value: api-reference/state/members/value.md | ||||||
|  |     - Roblox: | ||||||
|  |       - Types: | ||||||
|  |         - Child: api-reference/roblox/types/child.md | ||||||
|  |         - PropertyTable: api-reference/roblox/types/propertytable.md | ||||||
|  |         - SpecialKey: api-reference/roblox/types/specialkey.md | ||||||
|  |       - Members: | ||||||
|  |         - Attribute: api-reference/roblox/members/attribute.md | ||||||
|  |         - AttributeChange: api-reference/roblox/members/attributechange.md | ||||||
|  |         - AttributeOut: api-reference/roblox/members/attributeout.md | ||||||
|  |         - Children: api-reference/roblox/members/children.md | ||||||
|  |         - Hydrate: api-reference/roblox/members/hydrate.md | ||||||
|  |         - New: api-reference/roblox/members/new.md | ||||||
|  |         - OnChange: api-reference/roblox/members/onchange.md | ||||||
|  |         - OnEvent: api-reference/roblox/members/onevent.md | ||||||
|  |         - Out: api-reference/roblox/members/out.md | ||||||
|  |         - Ref: api-reference/roblox/members/ref.md | ||||||
|  |     - Animation: | ||||||
|  |       - Types: | ||||||
|  |         - Animatable: api-reference/animation/types/animatable.md | ||||||
|  |         - Spring: api-reference/animation/types/spring.md | ||||||
|  |         - Tween: api-reference/animation/types/tween.md | ||||||
|  |       - Members: | ||||||
|  |         - Tween: api-reference/animation/members/tween.md | ||||||
|  |         - Spring: api-reference/animation/members/spring.md | ||||||
|  |   - Extras: | ||||||
|  |     - Home: extras/index.md | ||||||
|  |     - Backgrounds: extras/backgrounds.md | ||||||
|  |     - Brand Guidelines: extras/brand-guidelines.md | ||||||
|  | 
 | ||||||
|  | markdown_extensions: | ||||||
|  |   - admonition | ||||||
|  |   - attr_list | ||||||
|  |   - meta | ||||||
|  |   - md_in_html | ||||||
|  |   - pymdownx.superfences | ||||||
|  |   - pymdownx.betterem | ||||||
|  |   - pymdownx.details | ||||||
|  |   - pymdownx.tabbed: | ||||||
|  |       alternate_style: true | ||||||
|  |   - pymdownx.inlinehilite | ||||||
|  |   - toc: | ||||||
|  |       permalink: true | ||||||
|  |   - pymdownx.highlight: | ||||||
|  |       guess_lang: false | ||||||
|  |   - pymdownx.emoji: | ||||||
|  |       emoji_index: !!python/name:materialx.emoji.twemoji | ||||||
|  |       emoji_generator: !!python/name:materialx.emoji.to_svg | ||||||
|  | @ -1,5 +1,5 @@ | ||||||
| local testkit = require("../testkit") |  | ||||||
| local jecs = require("../lib/init") | local jecs = require("../lib/init") | ||||||
|  | local testkit = require("../testkit") | ||||||
| local __ = jecs.Wildcard | local __ = jecs.Wildcard | ||||||
| local ECS_ID, ECS_GENERATION = jecs.ECS_ID, jecs.ECS_GENERATION | local ECS_ID, ECS_GENERATION = jecs.ECS_ID, jecs.ECS_GENERATION | ||||||
| local ECS_GENERATION_INC = jecs.ECS_GENERATION_INC | local ECS_GENERATION_INC = jecs.ECS_GENERATION_INC | ||||||
|  | @ -23,7 +23,8 @@ end | ||||||
| local N = 10 | local N = 10 | ||||||
| 
 | 
 | ||||||
| TEST("world", function() | TEST("world", function() | ||||||
|     do CASE "should be iterable"  | 	do | ||||||
|  | 		CASE("should be iterable") | ||||||
| 		local world = jecs.World.new() | 		local world = jecs.World.new() | ||||||
| 		local A = world:component() | 		local A = world:component() | ||||||
| 		local B = world:component() | 		local B = world:component() | ||||||
|  | @ -55,7 +56,8 @@ TEST("world", function() | ||||||
| 		CHECK(count == 3 + 2) | 		CHECK(count == 3 + 2) | ||||||
| 	end | 	end | ||||||
| 
 | 
 | ||||||
|     do CASE "should query all matching entities" | 	do | ||||||
|  | 		CASE("should query all matching entities") | ||||||
| 		local world = jecs.World.new() | 		local world = jecs.World.new() | ||||||
| 		local A = world:component() | 		local A = world:component() | ||||||
| 		local B = world:component() | 		local B = world:component() | ||||||
|  | @ -65,7 +67,9 @@ TEST("world", function() | ||||||
| 			local id = world:entity() | 			local id = world:entity() | ||||||
| 
 | 
 | ||||||
| 			world:set(id, A, true) | 			world:set(id, A, true) | ||||||
|             if i > 5 then world:set(id, B, true) end | 			if i > 5 then | ||||||
|  | 				world:set(id, B, true) | ||||||
|  | 			end | ||||||
| 			entities[i] = id | 			entities[i] = id | ||||||
| 		end | 		end | ||||||
| 
 | 
 | ||||||
|  | @ -74,10 +78,10 @@ TEST("world", function() | ||||||
| 		end | 		end | ||||||
| 
 | 
 | ||||||
| 		CHECK(#entities == 0) | 		CHECK(#entities == 0) | ||||||
| 
 |  | ||||||
| 	end | 	end | ||||||
| 
 | 
 | ||||||
|     do CASE "should query all matching entities when irrelevant component is removed" | 	do | ||||||
|  | 		CASE("should query all matching entities when irrelevant component is removed") | ||||||
| 		local world = jecs.World.new() | 		local world = jecs.World.new() | ||||||
| 		local A = world:component() | 		local A = world:component() | ||||||
| 		local B = world:component() | 		local B = world:component() | ||||||
|  | @ -91,7 +95,9 @@ TEST("world", function() | ||||||
| 			-- https://github.com/Ukendio/jecs/pull/15 | 			-- https://github.com/Ukendio/jecs/pull/15 | ||||||
| 			world:set(id, B, true) | 			world:set(id, B, true) | ||||||
| 			world:set(id, A, true) | 			world:set(id, A, true) | ||||||
|             if i > 5 then world:remove(id, B) end | 			if i > 5 then | ||||||
|  | 				world:remove(id, B) | ||||||
|  | 			end | ||||||
| 			entities[i] = id | 			entities[i] = id | ||||||
| 		end | 		end | ||||||
| 
 | 
 | ||||||
|  | @ -104,7 +110,8 @@ TEST("world", function() | ||||||
| 		CHECK(added == N) | 		CHECK(added == N) | ||||||
| 	end | 	end | ||||||
| 
 | 
 | ||||||
|     do CASE "should query all entities without B" | 	do | ||||||
|  | 		CASE("should query all entities without B") | ||||||
| 		local world = jecs.World.new() | 		local world = jecs.World.new() | ||||||
| 		local A = world:component() | 		local A = world:component() | ||||||
| 		local B = world:component() | 		local B = world:component() | ||||||
|  | @ -119,7 +126,6 @@ TEST("world", function() | ||||||
| 			else | 			else | ||||||
| 				world:set(id, B, true) | 				world:set(id, B, true) | ||||||
| 			end | 			end | ||||||
|              |  | ||||||
| 		end | 		end | ||||||
| 
 | 
 | ||||||
| 		for id in world:query(A):without(B) do | 		for id in world:query(A):without(B) do | ||||||
|  | @ -127,10 +133,10 @@ TEST("world", function() | ||||||
| 		end | 		end | ||||||
| 
 | 
 | ||||||
| 		CHECK(#entities == 0) | 		CHECK(#entities == 0) | ||||||
| 
 |  | ||||||
| 	end | 	end | ||||||
| 
 | 
 | ||||||
|     do CASE "should allow setting components in arbitrary order"  | 	do | ||||||
|  | 		CASE("should allow setting components in arbitrary order") | ||||||
| 		local world = jecs.World.new() | 		local world = jecs.World.new() | ||||||
| 
 | 
 | ||||||
| 		local Health = world:entity() | 		local Health = world:entity() | ||||||
|  | @ -143,7 +149,8 @@ TEST("world", function() | ||||||
| 		CHECK(world:get(id, Poison) == 5) | 		CHECK(world:get(id, Poison) == 5) | ||||||
| 	end | 	end | ||||||
| 
 | 
 | ||||||
|     do CASE "should allow deleting components"  | 	do | ||||||
|  | 		CASE("should allow deleting components") | ||||||
| 		local world = jecs.World.new() | 		local world = jecs.World.new() | ||||||
| 
 | 
 | ||||||
| 		local Health = world:entity() | 		local Health = world:entity() | ||||||
|  | @ -162,10 +169,10 @@ TEST("world", function() | ||||||
| 		CHECK(world:get(id, Health) == nil) | 		CHECK(world:get(id, Health) == nil) | ||||||
| 		CHECK(world:get(id1, Poison) == 500) | 		CHECK(world:get(id1, Poison) == 500) | ||||||
| 		CHECK(world:get(id1, Health) == 50) | 		CHECK(world:get(id1, Health) == 50) | ||||||
| 
 |  | ||||||
| 	end | 	end | ||||||
| 
 | 
 | ||||||
|     do CASE "should allow remove that doesn't exist on entity"  | 	do | ||||||
|  | 		CASE("should allow remove that doesn't exist on entity") | ||||||
| 		local world = jecs.World.new() | 		local world = jecs.World.new() | ||||||
| 
 | 
 | ||||||
| 		local Health = world:entity() | 		local Health = world:entity() | ||||||
|  | @ -179,7 +186,8 @@ TEST("world", function() | ||||||
| 		CHECK(world:get(id, Health) == 50) | 		CHECK(world:get(id, Health) == 50) | ||||||
| 	end | 	end | ||||||
| 
 | 
 | ||||||
|     do CASE "should increment generation"  | 	do | ||||||
|  | 		CASE("should increment generation") | ||||||
| 		local world = jecs.World.new() | 		local world = jecs.World.new() | ||||||
| 		local e = world:entity() | 		local e = world:entity() | ||||||
| 		CHECK(ECS_ID(e) == 1 + jecs.Rest) | 		CHECK(ECS_ID(e) == 1 + jecs.Rest) | ||||||
|  | @ -189,7 +197,8 @@ TEST("world", function() | ||||||
| 		CHECK(ECS_GENERATION(e) == 1) -- 1 | 		CHECK(ECS_GENERATION(e) == 1) -- 1 | ||||||
| 	end | 	end | ||||||
| 
 | 
 | ||||||
|     do CASE "should get alive from index in the dense array"  | 	do | ||||||
|  | 		CASE("should get alive from index in the dense array") | ||||||
| 		local world = jecs.World.new() | 		local world = jecs.World.new() | ||||||
| 		local _e = world:entity() | 		local _e = world:entity() | ||||||
| 		local e2 = world:entity() | 		local e2 = world:entity() | ||||||
|  | @ -203,7 +212,8 @@ TEST("world", function() | ||||||
| 		CHECK(ECS_PAIR_OBJECT(world.entityIndex, pair) == e3) | 		CHECK(ECS_PAIR_OBJECT(world.entityIndex, pair) == e3) | ||||||
| 	end | 	end | ||||||
| 
 | 
 | ||||||
|     do CASE "should allow querying for relations"  | 	do | ||||||
|  | 		CASE("should allow querying for relations") | ||||||
| 		local world = jecs.World.new() | 		local world = jecs.World.new() | ||||||
| 		local Eats = world:entity() | 		local Eats = world:entity() | ||||||
| 		local Apples = world:entity() | 		local Apples = world:entity() | ||||||
|  | @ -216,7 +226,8 @@ TEST("world", function() | ||||||
| 		end | 		end | ||||||
| 	end | 	end | ||||||
| 
 | 
 | ||||||
|     do CASE "should allow wildcards in queries"  | 	do | ||||||
|  | 		CASE("should allow wildcards in queries") | ||||||
| 		local world = jecs.World.new() | 		local world = jecs.World.new() | ||||||
| 		local Eats = world:entity() | 		local Eats = world:entity() | ||||||
| 		local Apples = world:entity() | 		local Apples = world:entity() | ||||||
|  | @ -235,7 +246,8 @@ TEST("world", function() | ||||||
| 		end | 		end | ||||||
| 	end | 	end | ||||||
| 
 | 
 | ||||||
|     do CASE "should match against multiple pairs"  | 	do | ||||||
|  | 		CASE("should match against multiple pairs") | ||||||
| 		local world = jecs.World.new() | 		local world = jecs.World.new() | ||||||
| 		local Eats = world:entity() | 		local Eats = world:entity() | ||||||
| 		local Apples = world:entity() | 		local Apples = world:entity() | ||||||
|  | @ -267,7 +279,8 @@ TEST("world", function() | ||||||
| 		CHECK(count == 1) | 		CHECK(count == 1) | ||||||
| 	end | 	end | ||||||
| 
 | 
 | ||||||
|     do CASE "should only relate alive entities"  | 	do | ||||||
|  | 		CASE("should only relate alive entities") | ||||||
| 
 | 
 | ||||||
| 		local world = jecs.World.new() | 		local world = jecs.World.new() | ||||||
| 		local Eats = world:entity() | 		local Eats = world:entity() | ||||||
|  | @ -294,7 +307,8 @@ TEST("world", function() | ||||||
| 		CHECK(world:get(bob, ECS_PAIR(Eats, Apples)) == nil) | 		CHECK(world:get(bob, ECS_PAIR(Eats, Apples)) == nil) | ||||||
| 	end | 	end | ||||||
| 
 | 
 | ||||||
|     do CASE "should error when setting invalid pair"  | 	do | ||||||
|  | 		CASE("should error when setting invalid pair") | ||||||
| 		local world = jecs.World.new() | 		local world = jecs.World.new() | ||||||
| 		local Eats = world:entity() | 		local Eats = world:entity() | ||||||
| 		local Apples = world:entity() | 		local Apples = world:entity() | ||||||
|  | @ -302,12 +316,11 @@ TEST("world", function() | ||||||
| 
 | 
 | ||||||
| 		world:delete(Apples) | 		world:delete(Apples) | ||||||
| 
 | 
 | ||||||
|         CHECK_NO_ERR("Apples should be dead", function()  |  | ||||||
| 		world:set(bob, ECS_PAIR(Eats, Apples), "bob eats apples") | 		world:set(bob, ECS_PAIR(Eats, Apples), "bob eats apples") | ||||||
|         end) |  | ||||||
| 	end | 	end | ||||||
| 
 | 
 | ||||||
|     do CASE "should find target for ChildOf"  | 	do | ||||||
|  | 		CASE("should find target for ChildOf") | ||||||
| 		local world = jecs.World.new() | 		local world = jecs.World.new() | ||||||
| 
 | 
 | ||||||
| 		local ChildOf = world:component() | 		local ChildOf = world:component() | ||||||
|  | @ -337,3 +350,4 @@ TEST("world", function() | ||||||
| end) | end) | ||||||
| 
 | 
 | ||||||
| FINISH() | FINISH() | ||||||
|  | 
 | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue