mirror of
https://github.com/Ukendio/jecs.git
synced 2025-04-24 17:10:03 +00:00
Release (#44)
* Add release * Release 0.1.0 * Move the benches to bench.project.json
This commit is contained in:
parent
f55993180b
commit
b8f7bed84c
8 changed files with 43 additions and 780 deletions
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,
|
|
||||||
},
|
|
||||||
})
|
|
|
@ -4,7 +4,4 @@ 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