mirror of
				https://github.com/Ukendio/jecs.git
				synced 2025-10-31 01:09:16 +00:00 
			
		
		
		
	Merge branch 'main' of https://github.com/Ukendio/jecs into add-docs
This commit is contained in:
		
						commit
						09ae7794ea
					
				
					 9 changed files with 117 additions and 781 deletions
				
			
		
							
								
								
									
										73
									
								
								.github/workflows/release.yaml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								.github/workflows/release.yaml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,73 @@ | ||||||
|  | name: Release | ||||||
|  | 
 | ||||||
|  | on: | ||||||
|  |   push: | ||||||
|  |     tags: ["v*"] | ||||||
|  | 
 | ||||||
|  | jobs: | ||||||
|  |   build: | ||||||
|  |     name: Build | ||||||
|  |     runs-on: ubuntu-latest | ||||||
|  |     steps: | ||||||
|  |       - name: Checkout Project | ||||||
|  |         uses: actions/checkout@v3 | ||||||
|  | 
 | ||||||
|  |       - name: Install Aftman | ||||||
|  |         uses: ok-nick/setup-aftman@v0.3.0 | ||||||
|  | 
 | ||||||
|  |       - name: Install Dependencies | ||||||
|  |         run: wally install | ||||||
|  | 
 | ||||||
|  |       - name: Build | ||||||
|  |         run: rojo build --output build.rbxm default.project.json | ||||||
|  | 
 | ||||||
|  |       - name: Upload Build Artifact | ||||||
|  |         uses: actions/upload-artifact@v3 | ||||||
|  |         with: | ||||||
|  |           name: build | ||||||
|  |           path: build.rbxm | ||||||
|  | 
 | ||||||
|  |   release: | ||||||
|  |     name: Release | ||||||
|  |     needs: [build] | ||||||
|  |     runs-on: ubuntu-latest | ||||||
|  |     permissions: | ||||||
|  |       contents: write | ||||||
|  |     steps: | ||||||
|  |       - name: Checkout Project | ||||||
|  |         uses: actions/checkout@v3 | ||||||
|  | 
 | ||||||
|  |       - name: Download Jecs Build | ||||||
|  |         uses: actions/download-artifact@v3 | ||||||
|  |         with: | ||||||
|  |           name: build | ||||||
|  |           path: build | ||||||
|  | 
 | ||||||
|  |       - name: Rename Build | ||||||
|  |         run: mv build/build.rbxm jecs.rbxm | ||||||
|  | 
 | ||||||
|  |       - name: Create Release | ||||||
|  |         uses: softprops/action-gh-release@v1 | ||||||
|  |         with: | ||||||
|  |           name: Matter ${{ github.ref_name }} | ||||||
|  |           body: | | ||||||
|  |             Matter ${{ github.ref_name }} is now available! | ||||||
|  |           files: | | ||||||
|  |             jecs.rbxm | ||||||
|  | 
 | ||||||
|  |   publish: | ||||||
|  |     name: Publish | ||||||
|  |     needs: [release] | ||||||
|  |     runs-on: ubuntu-latest | ||||||
|  |     steps: | ||||||
|  |       - name: Checkout Project | ||||||
|  |         uses: actions/checkout@v3 | ||||||
|  | 
 | ||||||
|  |       - name: Install Aftman | ||||||
|  |         uses: ok-nick/setup-aftman@v0.3.0 | ||||||
|  | 
 | ||||||
|  |       - name: Wally Login | ||||||
|  |         run: wally login --token ${{ secrets.WALLY_AUTH_TOKEN }} | ||||||
|  | 
 | ||||||
|  |       - name: Publish | ||||||
|  |         run: wally publish | ||||||
							
								
								
									
										31
									
								
								bench.project.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								bench.project.json
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,31 @@ | ||||||
|  | { | ||||||
|  |     "name": "jecs-test", | ||||||
|  |     "tree": { | ||||||
|  |         "$className": "DataModel", | ||||||
|  |         "StarterPlayer": { | ||||||
|  |             "$className": "StarterPlayer", | ||||||
|  |             "StarterPlayerScripts": { | ||||||
|  |             "$className": "StarterPlayerScripts", | ||||||
|  |             "$path": "tests" | ||||||
|  |             } | ||||||
|  |         }, | ||||||
|  |         "ReplicatedStorage": { | ||||||
|  |             "$className": "ReplicatedStorage", | ||||||
|  |             "Lib": { | ||||||
|  |                 "$path": "lib" | ||||||
|  |             }, | ||||||
|  |             "rgb": { | ||||||
|  |                 "$path": "rgb.lua" | ||||||
|  |             }, | ||||||
|  |             "benches": { | ||||||
|  |                 "$path": "benches" | ||||||
|  |             }, | ||||||
|  |             "mirror": { | ||||||
|  |                 "$path": "mirror" | ||||||
|  |             }, | ||||||
|  |             "DevPackages": { | ||||||
|  |                 "$path": "benches/visual/DevPackages" | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -1,372 +0,0 @@ | ||||||
| local testkit = require("../testkit") |  | ||||||
| local jecs = require("../lib/init") |  | ||||||
| local ecr = require("../DevPackages/_Index/centau_ecr@0.8.0/ecr/src/ecr") |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| local BENCH, START = testkit.benchmark() |  | ||||||
| 
 |  | ||||||
| local function TITLE(title: string) |  | ||||||
| 	print() |  | ||||||
| 	print(testkit.color.white(title)) |  | ||||||
| end |  | ||||||
| 
 |  | ||||||
| local N = 2^16-2 |  | ||||||
| 
 |  | ||||||
| type i53 = number |  | ||||||
| 
 |  | ||||||
| do TITLE "create" |  | ||||||
| 	BENCH("entity", function() |  | ||||||
| 		local world = jecs.World.new() |  | ||||||
| 		for i = 1, START(N) do |  | ||||||
| 			world:entity() |  | ||||||
| 		end |  | ||||||
| 	end) |  | ||||||
| end |  | ||||||
| 
 |  | ||||||
| --- component benchmarks |  | ||||||
| 
 |  | ||||||
| --todo: perform the same benchmarks for multiple components.? |  | ||||||
| -- these kind of operations only support 1 component at a time, which is |  | ||||||
| -- a shame, especially for archetypes where moving components is expensive. |  | ||||||
| 
 |  | ||||||
| do TITLE "set" |  | ||||||
| 	BENCH("add 1 component", function()  |  | ||||||
| 		local world = jecs.World.new() |  | ||||||
| 		local entities = {} |  | ||||||
| 
 |  | ||||||
| 		local A = world:component() |  | ||||||
| 		 |  | ||||||
| 		for i = 1, N do |  | ||||||
| 			entities[i] = world:entity() |  | ||||||
| 		end |  | ||||||
| 
 |  | ||||||
| 		for i = 1, START(N) do |  | ||||||
| 			world:set(entities[i], A, i) |  | ||||||
| 		end |  | ||||||
| 	end) |  | ||||||
| 
 |  | ||||||
| 	BENCH("change 1 component", function()  |  | ||||||
| 		local world = jecs.World.new() |  | ||||||
| 		local entities = {} |  | ||||||
| 
 |  | ||||||
| 		local A = world:component() |  | ||||||
| 		local e = world:entity() |  | ||||||
| 		world:set(e, A, 1) |  | ||||||
| 
 |  | ||||||
| 		for i = 1, START(N) do |  | ||||||
| 			world:set(e, A, 2) |  | ||||||
| 		end |  | ||||||
| 	end) |  | ||||||
| 
 |  | ||||||
| end |  | ||||||
| 
 |  | ||||||
| do TITLE "remove" |  | ||||||
| 	BENCH("1 component", function()  |  | ||||||
| 		local world = jecs.World.new() |  | ||||||
| 		local entities = {} |  | ||||||
| 
 |  | ||||||
| 		local A = world:component() |  | ||||||
| 		 |  | ||||||
| 		for i = 1, N do |  | ||||||
| 			local id = world:entity() |  | ||||||
| 			entities[i] = id |  | ||||||
| 			world:set(id, A, true) |  | ||||||
| 		end |  | ||||||
| 
 |  | ||||||
| 		for i = 1, START(N) do |  | ||||||
| 			world:remove(entities[i], A) |  | ||||||
| 		end |  | ||||||
| 
 |  | ||||||
| 	end) |  | ||||||
| end |  | ||||||
| 
 |  | ||||||
| do TITLE "get" |  | ||||||
| 	BENCH("1 component", function()  |  | ||||||
| 		local world = jecs.World.new() |  | ||||||
| 		local entities = {} |  | ||||||
| 
 |  | ||||||
| 		local A = world:component() |  | ||||||
| 
 |  | ||||||
| 		for i = 1, N do |  | ||||||
| 			local id = world:entity() |  | ||||||
| 			entities[i] = id |  | ||||||
| 			world:set(id, A, true) |  | ||||||
| 		end |  | ||||||
| 
 |  | ||||||
| 		for i = 1, START(N) do |  | ||||||
| 			-- ? curious why the overhead is roughly 80 ns. |  | ||||||
| 			world:get(entities[i], A) |  | ||||||
| 		end |  | ||||||
| 
 |  | ||||||
| 	end) |  | ||||||
| 
 |  | ||||||
| 	BENCH("2 component", function()  |  | ||||||
| 		local world = jecs.World.new() |  | ||||||
| 		local entities = {} |  | ||||||
| 
 |  | ||||||
| 		local A = world:component() |  | ||||||
| 		local B = world:component() |  | ||||||
| 		 |  | ||||||
| 		for i = 1, N do |  | ||||||
| 			local id = world:entity() |  | ||||||
| 			entities[i] = id |  | ||||||
| 			world:set(id, A, true) |  | ||||||
| 			world:set(id, B, true) |  | ||||||
| 		end |  | ||||||
| 
 |  | ||||||
| 		for i = 1, START(N) do |  | ||||||
| 			world:get(entities[i], A, B) |  | ||||||
| 		end |  | ||||||
| 
 |  | ||||||
| 	end) |  | ||||||
| 
 |  | ||||||
| 	BENCH("3 component", function()  |  | ||||||
| 		local world = jecs.World.new() |  | ||||||
| 		local entities = {} |  | ||||||
| 
 |  | ||||||
| 		local A = world:component() |  | ||||||
| 		local B = world:component() |  | ||||||
| 		local C = world:component() |  | ||||||
| 		 |  | ||||||
| 		for i = 1, N do |  | ||||||
| 			local id = world:entity() |  | ||||||
| 			entities[i] = id |  | ||||||
| 			world:set(id, A, true) |  | ||||||
| 			world:set(id, B, true) |  | ||||||
| 			world:set(id, C, true) |  | ||||||
| 		end |  | ||||||
| 
 |  | ||||||
| 		for i = 1, START(N) do |  | ||||||
| 			world:get(entities[i], A, B, C) |  | ||||||
| 		end |  | ||||||
| 
 |  | ||||||
| 	end) |  | ||||||
| 
 |  | ||||||
| 	BENCH("4 component", function()  |  | ||||||
| 		local world = jecs.World.new() |  | ||||||
| 		local entities = {} |  | ||||||
| 
 |  | ||||||
| 		local A = world:component() |  | ||||||
| 		local B = world:component() |  | ||||||
| 		local C = world:component() |  | ||||||
| 		local D = world:component() |  | ||||||
| 		 |  | ||||||
| 		for i = 1, N do |  | ||||||
| 			local id = world:entity() |  | ||||||
| 			entities[i] = id |  | ||||||
| 			world:set(id, A, true) |  | ||||||
| 			world:set(id, B, true) |  | ||||||
| 			world:set(id, C, true) |  | ||||||
| 			world:set(id, D, true) |  | ||||||
| 		end |  | ||||||
| 
 |  | ||||||
| 		for i = 1, START(N) do |  | ||||||
| 			world:get(entities[i], A, B, C, D) |  | ||||||
| 		end |  | ||||||
| 
 |  | ||||||
| 	end) |  | ||||||
| end |  | ||||||
| 
 |  | ||||||
| do TITLE (testkit.color.white_underline("Jecs query")) |  | ||||||
| 
 |  | ||||||
| 	local function count(query: () -> ()) |  | ||||||
| 		local n = 0 |  | ||||||
| 		for _ in query do |  | ||||||
| 			n += 1 |  | ||||||
| 		end |  | ||||||
| 		return n |  | ||||||
| 	end |  | ||||||
| 
 |  | ||||||
| 	local function flip() |  | ||||||
| 		return math.random() > 0.5 |  | ||||||
| 	end |  | ||||||
| 
 |  | ||||||
| 	local function view_bench( |  | ||||||
| 		world: jecs.World, |  | ||||||
| 		A: i53, B: i53, C: i53, D: i53, E: i53, F: i53, G: i53, H: i53, I: i53 |  | ||||||
| 	) |  | ||||||
| 
 |  | ||||||
| 		BENCH("1 component", function() |  | ||||||
| 			START(count(world:query(A))) |  | ||||||
| 			for _ in world:query(A) do end |  | ||||||
| 		end) |  | ||||||
| 
 |  | ||||||
| 		BENCH("2 component", function() |  | ||||||
| 			START(count(world:query(A, B))) |  | ||||||
| 			for _ in world:query(A, B) do end |  | ||||||
| 		end) |  | ||||||
| 
 |  | ||||||
| 		BENCH("4 component", function() |  | ||||||
| 			START(count(world:query(A, B, C, D))) |  | ||||||
| 			for _ in world:query(A, B, C, D) do end |  | ||||||
| 		end) |  | ||||||
| 
 |  | ||||||
| 		BENCH("8 component", function() |  | ||||||
| 			START(count(world:query(A, B, C, D, E, F, G, H))) |  | ||||||
| 			for _ in world:query(A, B, C, D, E, F, G, H) do end |  | ||||||
| 		end) |  | ||||||
| 	end |  | ||||||
| 
 |  | ||||||
| 	do TITLE "random components" |  | ||||||
| 
 |  | ||||||
| 		local world = jecs.World.new() |  | ||||||
| 
 |  | ||||||
| 		local A = world:component() |  | ||||||
| 		local B = world:component() |  | ||||||
| 		local C = world:component() |  | ||||||
| 		local D = world:component() |  | ||||||
| 		local E = world:component() |  | ||||||
| 		local F = world:component() |  | ||||||
| 		local G = world:component() |  | ||||||
| 		local H = world:component() |  | ||||||
| 		local I = world:component() |  | ||||||
| 
 |  | ||||||
| 		for i = 1, N do |  | ||||||
| 			local id = world:entity() |  | ||||||
| 			if flip() then world:set(id, A, true) end |  | ||||||
| 			if flip() then world:set(id, B, true) end |  | ||||||
| 			if flip() then world:set(id, C, true) end |  | ||||||
| 			if flip() then world:set(id, D, true) end |  | ||||||
| 			if flip() then world:set(id, E, true) end |  | ||||||
| 			if flip() then world:set(id, F, true) end |  | ||||||
| 			if flip() then world:set(id, G, true) end |  | ||||||
| 			if flip() then world:set(id, H, true) end |  | ||||||
| 			if flip() then world:set(id, I, true) end |  | ||||||
| 			 |  | ||||||
| 		end |  | ||||||
| 
 |  | ||||||
| 		view_bench(world, A, B, C, D, E, F, G, H, I) |  | ||||||
| 
 |  | ||||||
| 	end |  | ||||||
| 
 |  | ||||||
| 	do TITLE "one component in common" |  | ||||||
| 
 |  | ||||||
| 		local world = jecs.World.new() |  | ||||||
| 
 |  | ||||||
| 		local A = world:component() |  | ||||||
| 		local B = world:component() |  | ||||||
| 		local C = world:component() |  | ||||||
| 		local D = world:component() |  | ||||||
| 		local E = world:component() |  | ||||||
| 		local F = world:component() |  | ||||||
| 		local G = world:component() |  | ||||||
| 		local H = world:component() |  | ||||||
| 		local I = world:component() |  | ||||||
| 
 |  | ||||||
| 		for i = 1, N do |  | ||||||
| 			local id = world:entity() |  | ||||||
| 			local a = true |  | ||||||
| 			if flip() then world:set(id, B, true) else a = false end |  | ||||||
| 			if flip() then world:set(id, C, true) else a = false end |  | ||||||
| 			if flip() then world:set(id, D, true) else a = false end |  | ||||||
| 			if flip() then world:set(id, E, true) else a = false end |  | ||||||
| 			if flip() then world:set(id, F, true) else a = false end |  | ||||||
| 			if flip() then world:set(id, G, true) else a = false end |  | ||||||
| 			if flip() then world:set(id, H, true) else a = false end |  | ||||||
| 			if flip() then world:set(id, I, true) else a = false end |  | ||||||
| 			if a then world:set(id, A, true) end |  | ||||||
| 			 |  | ||||||
| 		end |  | ||||||
| 
 |  | ||||||
| 		view_bench(world, A, B, C, D, E, F, G, H, I) |  | ||||||
| 
 |  | ||||||
| 	end |  | ||||||
| 
 |  | ||||||
| end |  | ||||||
| 
 |  | ||||||
| do TITLE (testkit.color.white_underline("ECR query")) |  | ||||||
| 
 |  | ||||||
|     local A = ecr.component() |  | ||||||
|     local B = ecr.component() |  | ||||||
|     local C = ecr.component() |  | ||||||
|     local D = ecr.component() |  | ||||||
|     local E = ecr.component() |  | ||||||
|     local F = ecr.component() |  | ||||||
|     local G = ecr.component() |  | ||||||
|     local H = ecr.component() |  | ||||||
|     local I = ecr.component() |  | ||||||
| 
 |  | ||||||
| 	local function count(query: () -> ()) |  | ||||||
| 		local n = 0 |  | ||||||
| 		for _ in query do |  | ||||||
| 			n += 1 |  | ||||||
| 		end |  | ||||||
| 		return n |  | ||||||
| 	end |  | ||||||
| 
 |  | ||||||
| 	local function flip() |  | ||||||
| 		return math.random() > 0.5 |  | ||||||
| 	end |  | ||||||
| 
 |  | ||||||
| 	local function view_bench( |  | ||||||
| 		world: ecr.Registry, |  | ||||||
| 		A: i53, B: i53, C: i53, D: i53, E: i53, F: i53, G: i53, H: i53, I: i53 |  | ||||||
| 	) |  | ||||||
| 
 |  | ||||||
| 		BENCH("1 component", function() |  | ||||||
| 			START(count(world:view(A))) |  | ||||||
| 			for _ in world:view(A) do end |  | ||||||
| 		end) |  | ||||||
| 
 |  | ||||||
| 		BENCH("2 component", function() |  | ||||||
| 			START(count(world:view(A, B))) |  | ||||||
| 			for _ in world:view(A, B) do end |  | ||||||
| 		end) |  | ||||||
| 
 |  | ||||||
| 		BENCH("4 component", function() |  | ||||||
| 			START(count(world:view(A, B, C, D))) |  | ||||||
| 			for _ in world:view(A, B, C, D) do end |  | ||||||
| 		end) |  | ||||||
| 
 |  | ||||||
| 		BENCH("8 component", function() |  | ||||||
| 			START(count(world:view(A, B, C, D, E, F, G, H))) |  | ||||||
| 			for _ in world:view(A, B, C, D, E, F, G, H) do end |  | ||||||
| 		end) |  | ||||||
| 	end |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 	do TITLE "random components" |  | ||||||
|         local world = ecr.registry() |  | ||||||
| 
 |  | ||||||
| 		for i = 1, N do |  | ||||||
| 			local id = world.create() |  | ||||||
| 			if flip() then world:set(id, A, true) end |  | ||||||
| 			if flip() then world:set(id, B, true) end |  | ||||||
| 			if flip() then world:set(id, C, true) end |  | ||||||
| 			if flip() then world:set(id, D, true) end |  | ||||||
| 			if flip() then world:set(id, E, true) end |  | ||||||
| 			if flip() then world:set(id, F, true) end |  | ||||||
| 			if flip() then world:set(id, G, true) end |  | ||||||
| 			if flip() then world:set(id, H, true) end |  | ||||||
| 			if flip() then world:set(id, I, true) end |  | ||||||
| 			 |  | ||||||
| 		end |  | ||||||
| 
 |  | ||||||
| 		view_bench(world, A, B, C, D, E, F, G, H, I) |  | ||||||
| 
 |  | ||||||
| 	end |  | ||||||
| 
 |  | ||||||
| 	do TITLE "one component in common" |  | ||||||
| 
 |  | ||||||
| 		local world = ecr.registry() |  | ||||||
| 
 |  | ||||||
| 		for i = 1, N do |  | ||||||
| 			local id = world.create() |  | ||||||
| 			local a = true |  | ||||||
| 			if flip() then world:set(id, B, true) else a = false end |  | ||||||
| 			if flip() then world:set(id, C, true) else a = false end |  | ||||||
| 			if flip() then world:set(id, D, true) else a = false end |  | ||||||
| 			if flip() then world:set(id, E, true) else a = false end |  | ||||||
| 			if flip() then world:set(id, F, true) else a = false end |  | ||||||
| 			if flip() then world:set(id, G, true) else a = false end |  | ||||||
| 			if flip() then world:set(id, H, true) else a = false end |  | ||||||
| 			if flip() then world:set(id, I, true) else a = false end |  | ||||||
| 			if a then world:set(id, A, true) end |  | ||||||
| 			 |  | ||||||
| 		end |  | ||||||
| 
 |  | ||||||
| 		view_bench(world, A, B, C, D, E, F, G, H, I) |  | ||||||
| 
 |  | ||||||
| 	end |  | ||||||
| 
 |  | ||||||
| end |  | ||||||
|  | @ -2,7 +2,6 @@ | ||||||
| --!native | --!native | ||||||
| 
 | 
 | ||||||
| local ReplicatedStorage = game:GetService("ReplicatedStorage") | local ReplicatedStorage = game:GetService("ReplicatedStorage") | ||||||
| local rgb = require(ReplicatedStorage.rgb) |  | ||||||
| local Matter = require(ReplicatedStorage.DevPackages.Matter) | local Matter = require(ReplicatedStorage.DevPackages.Matter) | ||||||
| local jecs = require(ReplicatedStorage.Lib) | local jecs = require(ReplicatedStorage.Lib) | ||||||
| local ecr = require(ReplicatedStorage.DevPackages.ecr) | local ecr = require(ReplicatedStorage.DevPackages.ecr) | ||||||
|  |  | ||||||
							
								
								
									
										11
									
								
								benches/visual/wally.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								benches/visual/wally.toml
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,11 @@ | ||||||
|  | [package] | ||||||
|  | name = "private/private" | ||||||
|  | version = "0.1.0-rc.6" | ||||||
|  | registry = "https://github.com/UpliftGames/wally-index" | ||||||
|  | realm = "shared" | ||||||
|  | include = ["default.project.json", "lib/**", "lib", "wally.toml", "README.md"] | ||||||
|  | exclude = ["**"] | ||||||
|  | 
 | ||||||
|  | [dev-dependencies] | ||||||
|  | Matter = "matter-ecs/matter@0.8.0" | ||||||
|  | ecr = "centau/ecr@0.8.0" | ||||||
|  | @ -1,382 +0,0 @@ | ||||||
| local jecs = require(script.Parent) |  | ||||||
| local world = jecs.World.new() |  | ||||||
| 
 |  | ||||||
| local A, B, C, D = world:entity(), world:entity(), world:entity(), world:entity() |  | ||||||
| local E, F, G, H = world:entity(), world:entity(), world:entity(), world:entity() |  | ||||||
| print("A", A) |  | ||||||
| print("B", B) |  | ||||||
| print("C", C) |  | ||||||
| print("D", D) |  | ||||||
| print("E", E) |  | ||||||
| print("F", F) |  | ||||||
| print("G", G) |  | ||||||
| print("H", H) |  | ||||||
| 
 |  | ||||||
| local common = 0 |  | ||||||
| local N = 2^16-2 |  | ||||||
| local archetypes = {} |  | ||||||
| local function flip()  |  | ||||||
| 	return math.random() >= 0.5 |  | ||||||
| end |  | ||||||
| 
 |  | ||||||
| local amountOfCombination = 0 |  | ||||||
| for i = 1, N do  |  | ||||||
| 	local entity = world:entity() |  | ||||||
| 	local combination = "" |  | ||||||
| 
 |  | ||||||
| 	if flip() then  |  | ||||||
| 		combination ..= "2_" |  | ||||||
| 		world:set(entity, B, { value = true}) |  | ||||||
| 	end |  | ||||||
| 	if flip() then  |  | ||||||
| 		combination ..= "3_" |  | ||||||
| 		world:set(entity, C, { value = true}) |  | ||||||
| 	end |  | ||||||
| 	if flip() then  |  | ||||||
| 		combination ..= "4_" |  | ||||||
| 		world:set(entity, D, { value = true}) |  | ||||||
| 	end |  | ||||||
| 	if flip() then  |  | ||||||
| 		combination ..= "5_" |  | ||||||
| 		world:set(entity, E, { value = true}) |  | ||||||
| 	end |  | ||||||
| 	if flip() then  |  | ||||||
| 		combination ..= "6_" |  | ||||||
| 		world:set(entity, F, { value = true}) |  | ||||||
| 	end |  | ||||||
| 	if flip() then  |  | ||||||
| 		combination ..= "7_" |  | ||||||
| 		world:set(entity, G, { value = true}) |  | ||||||
| 	end |  | ||||||
| 	if flip() then  |  | ||||||
| 		combination ..= "8" |  | ||||||
| 		world:set(entity, H, { value = true}) |  | ||||||
| 	end |  | ||||||
| 
 |  | ||||||
| 	if #combination == 7 then  |  | ||||||
| 		combination = "1_" .. combination |  | ||||||
| 		common += 1 |  | ||||||
| 		world:set(entity, A, { value = true}) |  | ||||||
| 	end |  | ||||||
| 
 |  | ||||||
| 	if combination:find("2")  |  | ||||||
| 		and combination:find("3")  |  | ||||||
| 		and combination:find("4") |  | ||||||
| 		and combination:find("6") |  | ||||||
| 	then  |  | ||||||
| 		amountOfCombination += 1 |  | ||||||
| 	end |  | ||||||
| 	archetypes[combination] = true |  | ||||||
| end |  | ||||||
| 
 |  | ||||||
| return function() |  | ||||||
| 	describe("World", function() |  | ||||||
| 		it("should add component", function() |  | ||||||
| 			local id = world:entity() |  | ||||||
| 			world:set(id, A, true) |  | ||||||
| 			world:set(id, B, 1) |  | ||||||
| 
 |  | ||||||
| 			local id1 = world:entity() |  | ||||||
| 			world:set(id1, A, "hello") |  | ||||||
| 			expect(world:get(id, A)).to.equal(true) |  | ||||||
| 			expect(world:get(id, B)).to.equal(1) |  | ||||||
| 			expect(world:get(id1, A)).to.equal("hello") |  | ||||||
| 		end) |  | ||||||
| 
 |  | ||||||
| 		it("should remove component", function()  |  | ||||||
| 			local Tag = world:entity() |  | ||||||
| 			local entities = {} |  | ||||||
| 			for i = 1, 10 do  |  | ||||||
| 				local entity = world:entity() |  | ||||||
| 				entities[i] = entity |  | ||||||
| 				world:set(entity, Tag) |  | ||||||
| 			end |  | ||||||
| 
 |  | ||||||
| 			for i = 1, 10 do  |  | ||||||
| 				local entity = entities[i] |  | ||||||
| 				expect(world:get(entity, Tag)).to.equal(nil) |  | ||||||
| 				world:remove(entity, Tag) |  | ||||||
| 			end |  | ||||||
| 			 |  | ||||||
| 		end) |  | ||||||
| 
 |  | ||||||
| 		it("should override component data", function()  |  | ||||||
| 		 |  | ||||||
| 			local id = world:entity() |  | ||||||
| 			world:set(id, A, true) |  | ||||||
| 			expect(world:get(id, A)).to.equal(true) |  | ||||||
| 
 |  | ||||||
| 			world:set(id, A, false) |  | ||||||
| 			expect(world:get(id, A)).to.equal(false) |  | ||||||
| 
 |  | ||||||
| 		end) |  | ||||||
| 
 |  | ||||||
| 		it("should not query a removed component", function()  |  | ||||||
| 			local Tag = world:entity() |  | ||||||
| 			local AnotherTag = world:entity() |  | ||||||
| 
 |  | ||||||
| 			local entity = world:entity() |  | ||||||
| 			world:set(entity, Tag) |  | ||||||
| 			world:set(entity, AnotherTag) |  | ||||||
| 			world:remove(entity, AnotherTag) |  | ||||||
| 
 |  | ||||||
| 			local added = 0 |  | ||||||
| 			for e, t, a in world:query(Tag, AnotherTag) do  |  | ||||||
| 				added += 1 |  | ||||||
| 			end |  | ||||||
| 			expect(added).to.equal(0) |  | ||||||
| 		end) |  | ||||||
| 
 |  | ||||||
| 		it("should query correct number of compatible archetypes", function() |  | ||||||
| 			local added = 0 |  | ||||||
| 			for _ in world:query(B, C, D, F) do |  | ||||||
| 				added += 1 |  | ||||||
| 			end         |  | ||||||
| 			expect(added).to.equal(amountOfCombination) |  | ||||||
| 		end) |  | ||||||
| 
 |  | ||||||
| 		it("should not query poisoned players", function()  |  | ||||||
| 			local Player = world:entity() |  | ||||||
| 			local Health = world:entity() |  | ||||||
| 			local Poison = world:entity() |  | ||||||
| 
 |  | ||||||
| 			local one = world:entity() |  | ||||||
| 			world:set(one, Player, { name = "alice"}) |  | ||||||
| 			world:set(one, Health, 100) |  | ||||||
| 			world:set(one, Poison) |  | ||||||
| 
 |  | ||||||
| 			local two = world:entity() |  | ||||||
| 			world:set(two, Player, { name = "bob"}) |  | ||||||
| 			world:set(two, Health, 90) |  | ||||||
| 
 |  | ||||||
| 			local withoutCount = 0 |  | ||||||
| 			for _id, _player in world:query(Player):without(Poison) do |  | ||||||
| 				withoutCount += 1 |  | ||||||
| 			end |  | ||||||
| 
 |  | ||||||
| 			expect(withoutCount).to.equal(1) |  | ||||||
| 		end) |  | ||||||
| 
 |  | ||||||
| 		it("should allow calling world:entity before world:component", function()  |  | ||||||
| 			for _ = 1, 256 do  |  | ||||||
| 				world:entity() |  | ||||||
| 			end	 |  | ||||||
| 			expect(world:component()).to.be.ok() |  | ||||||
| 		end) |  | ||||||
| 
 |  | ||||||
| 		it("should skip iteration", function()  |  | ||||||
| 			local Position, Velocity = world:entity(), world:entity() |  | ||||||
| 			local e = world:entity() |  | ||||||
| 			world:set(e, Position, Vector3.zero) |  | ||||||
| 			world:set(e, Velocity, Vector3.one) |  | ||||||
| 			local added = 0 |  | ||||||
| 			for i in world:query(Position):without(Velocity) do |  | ||||||
| 				added += 1 |  | ||||||
| 			end         |  | ||||||
| 			expect(added).to.equal(0) |  | ||||||
| 		end) |  | ||||||
| 
 |  | ||||||
| 		it("should query all matching entities", function() |  | ||||||
| 
 |  | ||||||
| 			local world = jecs.World.new() |  | ||||||
| 			local A = world:component() |  | ||||||
| 			local B = world:component() |  | ||||||
| 
 |  | ||||||
| 			local entities = {} |  | ||||||
| 			for i = 1, N do |  | ||||||
| 				local id = world:entity() |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 				world:set(id, A, true) |  | ||||||
| 				if i > 5 then world:set(id, B, true) end |  | ||||||
| 				entities[i] = id |  | ||||||
| 			end |  | ||||||
| 
 |  | ||||||
| 			for id in world:query(A) do |  | ||||||
| 				local i = table.find(entities, id) |  | ||||||
| 				expect(i).to.be.ok() |  | ||||||
| 				table.remove(entities, i) |  | ||||||
| 			end |  | ||||||
| 
 |  | ||||||
| 			expect(#entities).to.equal(0) |  | ||||||
| 		end) |  | ||||||
| 
 |  | ||||||
| 		it("should query all matching entities when irrelevant component is removed", function() |  | ||||||
| 
 |  | ||||||
| 			 |  | ||||||
| 			local world = jecs.World.new() |  | ||||||
| 			local A = world:component() |  | ||||||
| 			local B = world:component() |  | ||||||
| 	 |  | ||||||
| 			local entities = {} |  | ||||||
| 			for i = 1, N do |  | ||||||
| 				local id = world:entity() |  | ||||||
| 	 |  | ||||||
| 				world:set(id, A, true) |  | ||||||
| 				world:set(id, B, true) |  | ||||||
| 				if i > 5 then world:remove(id, B, true) end |  | ||||||
| 				entities[i] = id |  | ||||||
| 			end |  | ||||||
| 	 |  | ||||||
| 			local added = 0 |  | ||||||
| 			for id in world:query(A) do |  | ||||||
| 				added += 1 |  | ||||||
| 				local i = table.find(entities, id) |  | ||||||
| 				expect(i).to.be.ok() |  | ||||||
| 				table.remove(entities, i) |  | ||||||
| 			end |  | ||||||
| 	 |  | ||||||
| 			expect(added).to.equal(N) |  | ||||||
| 		end) |  | ||||||
| 
 |  | ||||||
| 		it("should query all entities without B", function()  |  | ||||||
| 			local world = jecs.World.new() |  | ||||||
| 			local A = world:component() |  | ||||||
| 			local B = world:component() |  | ||||||
| 	 |  | ||||||
| 			local entities = {} |  | ||||||
| 			for i = 1, N do |  | ||||||
| 				local id = world:entity() |  | ||||||
| 	 |  | ||||||
| 				world:set(id, A, true) |  | ||||||
| 				if i < 5 then |  | ||||||
| 					entities[i] = id |  | ||||||
| 				else |  | ||||||
| 					world:set(id, B, true) |  | ||||||
| 				end |  | ||||||
| 				 |  | ||||||
| 			end |  | ||||||
| 	 |  | ||||||
| 			for id in world:query(A):without(B) do |  | ||||||
| 				local i = table.find(entities, id) |  | ||||||
| 				expect(i).to.be.ok() |  | ||||||
| 				table.remove(entities, i) |  | ||||||
| 			end |  | ||||||
| 	 |  | ||||||
| 			expect(#entities).to.equal(0) |  | ||||||
| 		end) |  | ||||||
| 
 |  | ||||||
| 		it("should allow setting components in arbitrary order", function()  |  | ||||||
| 			local world = jecs.World.new() |  | ||||||
| 
 |  | ||||||
| 			local Health = world:entity() |  | ||||||
| 			local Poison = world:component() |  | ||||||
| 
 |  | ||||||
| 			local id = world:entity() |  | ||||||
| 			world:set(id, Poison, 5) |  | ||||||
| 			world:set(id, Health, 50) |  | ||||||
| 
 |  | ||||||
| 			expect(world:get(id, Poison)).to.equal(5) |  | ||||||
| 		end) |  | ||||||
| 
 |  | ||||||
| 		it("Should allow deleting components", function()  |  | ||||||
| 			local world = jecs.World.new() |  | ||||||
| 
 |  | ||||||
| 			local Health = world:entity() |  | ||||||
| 			local Poison = world:component() |  | ||||||
| 
 |  | ||||||
| 			local id = world:entity() |  | ||||||
| 			world:set(id, Poison, 5) |  | ||||||
| 			world:set(id, Health, 50) |  | ||||||
| 			world:delete(id) |  | ||||||
| 
 |  | ||||||
| 			expect(world:get(id, Poison)).to.never.be.ok() |  | ||||||
| 			expect(world:get(id, Health)).to.never.be.ok() |  | ||||||
| 		end) |  | ||||||
| 
 |  | ||||||
| 		it("should allow iterating the whole world", function()  |  | ||||||
| 			local world = jecs.World.new() |  | ||||||
| 
 |  | ||||||
| 			local A, B = world:entity(), world:entity() |  | ||||||
| 
 |  | ||||||
| 			local eA = world:entity() |  | ||||||
| 			world:set(eA, A, true) |  | ||||||
| 			local eB = world:entity() |  | ||||||
| 			world:set(eB, B, true) |  | ||||||
| 			local eAB = world:entity() |  | ||||||
| 			world:set(eAB, A, true) |  | ||||||
| 			world:set(eAB, B, true) |  | ||||||
| 
 |  | ||||||
| 			local count = 0 |  | ||||||
| 			for id, data in world do |  | ||||||
| 				count += 1 |  | ||||||
| 				if id == eA then |  | ||||||
| 					expect(data[A]).to.be.ok() |  | ||||||
| 					expect(data[B]).to.never.be.ok() |  | ||||||
| 				elseif id == eB then |  | ||||||
| 					expect(data[B]).to.be.ok() |  | ||||||
| 					expect(data[A]).to.never.be.ok() |  | ||||||
| 				elseif id == eAB then |  | ||||||
| 					expect(data[A]).to.be.ok() |  | ||||||
| 					expect(data[B]).to.be.ok() |  | ||||||
| 				end |  | ||||||
| 			end |  | ||||||
| 
 |  | ||||||
| 			expect(count).to.equal(5) |  | ||||||
| 		end) |  | ||||||
| 
 |  | ||||||
|         it("should allow querying for relations", function() |  | ||||||
|             local world = jecs.World.new() |  | ||||||
|             local Eats = world:entity() |  | ||||||
|             local Apples = world:entity() |  | ||||||
|             local bob = world:entity() |  | ||||||
|              |  | ||||||
|             world:set(bob, jecs.pair(Eats, Apples), true) |  | ||||||
|             for e, bool in world:query(jecs.pair(Eats, Apples)) do  |  | ||||||
|                 expect(e).to.equal(bob) |  | ||||||
|                 expect(bool).to.equal(bool) |  | ||||||
|             end |  | ||||||
|         end) |  | ||||||
|          |  | ||||||
|         it("should allow wildcards in queries", function() |  | ||||||
|             local world = jecs.World.new() |  | ||||||
|             local Eats = world:entity() |  | ||||||
|             local Apples = world:entity() |  | ||||||
|             local bob = world:entity() |  | ||||||
|              |  | ||||||
|             world:set(bob, jecs.pair(Eats, Apples), "bob eats apples") |  | ||||||
|             for e, data in world:query(jecs.pair(Eats, jecs.w)) do  |  | ||||||
|                 expect(e).to.equal(bob) |  | ||||||
|                 expect(data).to.equal("bob eats apples") |  | ||||||
|             end |  | ||||||
|             for e, data in world:query(jecs.pair(jecs.w, Apples)) do  |  | ||||||
|                 expect(e).to.equal(bob) |  | ||||||
|                 expect(data).to.equal("bob eats apples") |  | ||||||
|             end |  | ||||||
|         end) |  | ||||||
| 
 |  | ||||||
|         it("should match against multiple pairs", function() |  | ||||||
|             local world = jecs.World.new() |  | ||||||
|             local pair = jecs.pair |  | ||||||
|             local Eats = world:entity() |  | ||||||
|             local Apples = world:entity() |  | ||||||
|             local Oranges =world:entity() |  | ||||||
|             local bob = world:entity() |  | ||||||
|             local alice = world:entity() |  | ||||||
|              |  | ||||||
|             world:set(bob, pair(Eats, Apples), "bob eats apples") |  | ||||||
|             world:set(alice, pair(Eats, Oranges), "alice eats oranges") |  | ||||||
|              |  | ||||||
|             local w = jecs.Wildcard |  | ||||||
|              |  | ||||||
|             local count = 0 |  | ||||||
|             for e, data in world:query(pair(Eats, w)) do  |  | ||||||
|                 count += 1 |  | ||||||
|                 if e == bob then  |  | ||||||
|                     expect(data).to.equal("bob eats apples") |  | ||||||
|                 else |  | ||||||
|                     expect(data).to.equal("alice eats oranges") |  | ||||||
|                 end |  | ||||||
|             end |  | ||||||
| 
 |  | ||||||
|             expect(count).to.equal(2) |  | ||||||
|             count = 0 |  | ||||||
| 
 |  | ||||||
|             for e, data in world:query(pair(w, Apples)) do  |  | ||||||
|                 count += 1 |  | ||||||
|                 expect(data).to.equal("bob eats apples") |  | ||||||
|             end |  | ||||||
|             expect(count).to.equal(1) |  | ||||||
|         end) |  | ||||||
| 	end) |  | ||||||
| end |  | ||||||
|  | @ -22,18 +22,6 @@ | ||||||
|         }, |         }, | ||||||
|         "mirror": { |         "mirror": { | ||||||
|           "$path": "mirror" |           "$path": "mirror" | ||||||
|         }, |  | ||||||
|         "DevPackages": { |  | ||||||
|           "$path": "DevPackages" |  | ||||||
|         } |  | ||||||
|       }, |  | ||||||
|       "TestService": { |  | ||||||
|         "$properties": { |  | ||||||
|           "ExecuteWithStudioRun": true |  | ||||||
|         }, |  | ||||||
|         "$className": "TestService", |  | ||||||
|         "run": { |  | ||||||
|           "$path": "tests.server.lua" |  | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | @ -1,9 +0,0 @@ | ||||||
| local ReplicatedStorage = game:GetService("ReplicatedStorage") |  | ||||||
| 
 |  | ||||||
| require(ReplicatedStorage.DevPackages.TestEZ).TestBootstrap:run({ |  | ||||||
| 	ReplicatedStorage.Lib, |  | ||||||
| 	nil, |  | ||||||
| 	{ |  | ||||||
| 		noXpcallByDefault = true, |  | ||||||
| 	}, |  | ||||||
| }) |  | ||||||
|  | @ -1,10 +1,7 @@ | ||||||
| [package] | [package] | ||||||
| name = "ukendio/jecs" | name = "ukendio/jecs" | ||||||
| version = "0.1.0-rc.6" | version = "0.1.0" | ||||||
| registry = "https://github.com/UpliftGames/wally-index" | registry = "https://github.com/UpliftGames/wally-index" | ||||||
| realm = "shared" | realm = "shared" | ||||||
| include = ["default.project.json", "lib/**", "lib", "wally.toml", "README.md"] | include = ["default.project.json", "lib/**", "lib", "wally.toml", "README.md"] | ||||||
| exclude = ["**"] | exclude = ["**"] | ||||||
| 
 |  | ||||||
| [dev-dependencies] |  | ||||||
| TestEZ = "roblox/testez@0.4.1" |  | ||||||
		Loading…
	
		Reference in a new issue