mirror of
https://github.com/Ukendio/jecs.git
synced 2025-04-24 17:10:03 +00:00
Compare commits
3 commits
9d83c3bc13
...
045408af37
Author | SHA1 | Date | |
---|---|---|---|
|
045408af37 | ||
|
59e7fd1f41 | ||
|
f3befa3adb |
4 changed files with 601 additions and 422 deletions
|
@ -5,21 +5,21 @@ local lifetime_tracker_add = require("@tools/lifetime_tracker")
|
||||||
local pe = require("@tools/entity_visualiser").prettify
|
local pe = require("@tools/entity_visualiser").prettify
|
||||||
local world = lifetime_tracker_add(jecs.world(), {padding_enabled=false})
|
local world = lifetime_tracker_add(jecs.world(), {padding_enabled=false})
|
||||||
local FriendsWith = world:component()
|
local FriendsWith = world:component()
|
||||||
local _1 = world:print_snapshot()
|
world:print_snapshot()
|
||||||
local e1 = world:entity()
|
local e1 = world:entity()
|
||||||
local e2 = world:entity()
|
local e2 = world:entity()
|
||||||
world:delete(e2)
|
world:delete(e2)
|
||||||
|
|
||||||
local _2 = world:print_snapshot()
|
world:print_snapshot()
|
||||||
local e3 = world:entity()
|
local e3 = world:entity()
|
||||||
world:add(e3, pair(ChildOf, e1))
|
world:add(e3, pair(ChildOf, e1))
|
||||||
local e4 = world:entity()
|
local e4 = world:entity()
|
||||||
world:add(e4, pair(FriendsWith, e3))
|
world:add(e4, pair(FriendsWith, e3))
|
||||||
local _3 = world:print_snapshot()
|
world:print_snapshot()
|
||||||
world:delete(e1)
|
world:delete(e1)
|
||||||
world:delete(e3)
|
world:delete(e3)
|
||||||
local _4 = world:print_snapshot()
|
world:print_snapshot()
|
||||||
world:print_entity_index()
|
world:print_entity_index()
|
||||||
world:entity()
|
world:entity()
|
||||||
world:entity()
|
world:entity()
|
||||||
local _5 = world:print_snapshot()
|
world:print_snapshot()
|
||||||
|
|
|
@ -117,6 +117,62 @@ local function name(world, e)
|
||||||
return world:get(e, jecs.Name)
|
return world:get(e, jecs.Name)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
TEST("#repro2", function()
|
||||||
|
local world = world_new()
|
||||||
|
local Lifetime = world:component() :: jecs.Id<number>
|
||||||
|
local Particle = world:entity()
|
||||||
|
local Beam = world:entity()
|
||||||
|
|
||||||
|
local entity = world:entity()
|
||||||
|
world:set(entity, pair(Lifetime, Particle), 1)
|
||||||
|
world:set(entity, pair(Lifetime, Beam), 2)
|
||||||
|
world:set(entity, pair(4, 5), 6) -- noise
|
||||||
|
|
||||||
|
local entity_visualizer = require("@tools/entity_visualiser")
|
||||||
|
entity_visualizer.components(world, entity)
|
||||||
|
|
||||||
|
for e in world:each(pair(Lifetime, __)) do
|
||||||
|
local i = 0
|
||||||
|
local nth = world:target(e, Lifetime, i)
|
||||||
|
while nth do
|
||||||
|
entity_visualizer.components(world, e)
|
||||||
|
|
||||||
|
local data = world:get(e, pair(Lifetime, nth))
|
||||||
|
data -= 1
|
||||||
|
if data <= 0 then
|
||||||
|
world:remove(e, pair(Lifetime, nth))
|
||||||
|
else
|
||||||
|
world:set(e, pair(Lifetime, nth), data)
|
||||||
|
end
|
||||||
|
i += 1
|
||||||
|
nth = world:target(e, Lifetime, i)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
CHECK(not world:has(entity, pair(Lifetime, Particle)))
|
||||||
|
CHECK(world:get(entity, pair(Lifetime, Beam)) == 1)
|
||||||
|
end)
|
||||||
|
|
||||||
|
local lifetime_tracker_add = require("@tools/lifetime_tracker")
|
||||||
|
|
||||||
|
TEST("another", function()
|
||||||
|
local world = world_new()
|
||||||
|
world = lifetime_tracker_add(world, {padding_enabled=false})
|
||||||
|
local e1 = world:entity()
|
||||||
|
local e2 = world:entity()
|
||||||
|
local e3 = world:entity()
|
||||||
|
world:delete(e2)
|
||||||
|
world:print_entity_index()
|
||||||
|
print(pair(e1, e2))
|
||||||
|
print(pair(e2, e3))
|
||||||
|
local e2_e3 = pair(e2, e3)
|
||||||
|
CHECK(jecs.pair_first(world, e2_e3) == 0)
|
||||||
|
CHECK(jecs.pair_second(world, e2_e3) == e3)
|
||||||
|
CHECK_EXPECT_ERR(function()
|
||||||
|
world:add(e1, pair(e2, e3))
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
|
||||||
TEST("#repro", function()
|
TEST("#repro", function()
|
||||||
local world = world_new()
|
local world = world_new()
|
||||||
|
|
||||||
|
@ -186,9 +242,9 @@ end)
|
||||||
|
|
||||||
TEST("world:cleanup()", function()
|
TEST("world:cleanup()", function()
|
||||||
local world = world_new()
|
local world = world_new()
|
||||||
local A = world:component()
|
local A = world:component() :: jecs.Id<boolean>
|
||||||
local B = world:component()
|
local B = world:component() :: jecs.Id<boolean>
|
||||||
local C = world:component()
|
local C = world:component() :: jecs.Id<boolean>
|
||||||
|
|
||||||
local e1 = world:entity()
|
local e1 = world:entity()
|
||||||
local e2 = world:entity()
|
local e2 = world:entity()
|
||||||
|
@ -299,7 +355,7 @@ TEST("world:entity()", function()
|
||||||
|
|
||||||
do CASE "Recycling max generation"
|
do CASE "Recycling max generation"
|
||||||
local world = world_new()
|
local world = world_new()
|
||||||
local pin = jecs.Rest::number + 1
|
local pin = (jecs.Rest :: any) :: number + 1
|
||||||
for i = 1, 2^16-1 do
|
for i = 1, 2^16-1 do
|
||||||
local e = world:entity()
|
local e = world:entity()
|
||||||
world:delete(e)
|
world:delete(e)
|
||||||
|
@ -513,21 +569,22 @@ TEST("world:query()", function()
|
||||||
do CASE "pairs"
|
do CASE "pairs"
|
||||||
local world = jecs.World.new()
|
local world = jecs.World.new()
|
||||||
|
|
||||||
local C1 = world:component()
|
local C1 = world:component() :: jecs.Id<boolean>
|
||||||
local C2 = world:component()
|
local C2 = world:component() :: jecs.Id<boolean>
|
||||||
local T1 = world:entity()
|
local T1 = world:entity()
|
||||||
local T2 = world:entity()
|
local T2 = world:entity()
|
||||||
|
|
||||||
local e = world:entity()
|
local e = world:entity()
|
||||||
|
|
||||||
world:set(e, pair(C1, C2), true)
|
local C1_C2 = pair(C1, C2)
|
||||||
|
world:set(e, C1_C2, true)
|
||||||
world:set(e, pair(C1, T1), true)
|
world:set(e, pair(C1, T1), true)
|
||||||
world:set(e, pair(T1, C1), true)
|
world:set(e, pair(T1, C1), true)
|
||||||
CHECK_EXPECT_ERR(function()
|
CHECK_EXPECT_ERR(function()
|
||||||
world:set(e, pair(T1, T2), true :: any)
|
world:set(e, pair(T1, T2), true :: any)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
for id, a, b, c, d in world:query(pair(C1, C2), pair(C1, T1), pair(T1, C1), pair(T1, T2)) :: any do
|
for id, a, b, c, d in world:query(pair(C1, C2), pair(C1, T1), pair(T1, C1), pair(T1, T2)):iter() do
|
||||||
CHECK(a == true)
|
CHECK(a == true)
|
||||||
CHECK(b == true)
|
CHECK(b == true)
|
||||||
CHECK(c == true)
|
CHECK(c == true)
|
||||||
|
@ -823,8 +880,9 @@ TEST("world:query()", function()
|
||||||
local bob = world:entity()
|
local bob = world:entity()
|
||||||
|
|
||||||
world:delete(Apples)
|
world:delete(Apples)
|
||||||
|
CHECK_EXPECT_ERR(function()
|
||||||
world:set(bob, pair(Eats, Apples), "bob eats apples")
|
world:set(bob, pair(Eats, Apples), "bob eats apples")
|
||||||
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
do
|
do
|
||||||
|
@ -1394,24 +1452,10 @@ TEST("world:target", function()
|
||||||
CHECK(world:target(e, C, 0) == D)
|
CHECK(world:target(e, C, 0) == D)
|
||||||
CHECK(world:target(e, C, 1) == nil)
|
CHECK(world:target(e, C, 1) == nil)
|
||||||
|
|
||||||
-- for id in archetype.records do
|
|
||||||
-- local f = world:get(ecs_pair_first(world, id), jecs.Name)
|
|
||||||
-- local s = world:get(ecs_pair_second(world, id), jecs.Name)
|
|
||||||
-- print(`({f}, {s})`)
|
|
||||||
-- end
|
|
||||||
--
|
|
||||||
|
|
||||||
CHECK(archetype.records[pair(A, B)] == 1)
|
CHECK(archetype.records[pair(A, B)] == 1)
|
||||||
CHECK(archetype.records[pair(A, C)] == 2)
|
CHECK(archetype.records[pair(A, C)] == 2)
|
||||||
CHECK(archetype.records[pair(A, D)] == 3)
|
CHECK(archetype.records[pair(A, D)] == 3)
|
||||||
CHECK(archetype.records[pair(A, E)] == 4)
|
CHECK(archetype.records[pair(A, E)] == 4)
|
||||||
-- print("(A, B)", archetype.records[pair(A, B)])
|
|
||||||
-- print("(A, C)", archetype.records[pair(A, C)])
|
|
||||||
-- print("(A, D)", archetype.records[pair(A, D)])
|
|
||||||
-- print("(A, E)", archetype.records[pair(A, E)])
|
|
||||||
|
|
||||||
-- print(pair(A, D), pair(B, C))
|
|
||||||
-- print("(B, C)", archetype.records[pair(B, C)])
|
|
||||||
|
|
||||||
CHECK(world:target(e, C, 0) == D)
|
CHECK(world:target(e, C, 0) == D)
|
||||||
CHECK(world:target(e, C, 1) == nil)
|
CHECK(world:target(e, C, 1) == nil)
|
||||||
|
|
108
tools/runtime_lints.luau
Normal file
108
tools/runtime_lints.luau
Normal file
|
@ -0,0 +1,108 @@
|
||||||
|
local function dbg_info(n: number): any
|
||||||
|
return debug.info(n, "s")
|
||||||
|
end
|
||||||
|
local function throw(msg: string)
|
||||||
|
local s = 1
|
||||||
|
local root = dbg_info(1)
|
||||||
|
repeat
|
||||||
|
s += 1
|
||||||
|
until dbg_info(s) ~= root
|
||||||
|
if warn then
|
||||||
|
error(msg, s)
|
||||||
|
else
|
||||||
|
print(`[jecs] error: {msg}\n`)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function ASSERT<T>(v: T, msg: string)
|
||||||
|
if v then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
throw(msg)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function runtime_lints_add(world)
|
||||||
|
local function get_name(id)
|
||||||
|
return world_get_one_inline(world, id, EcsName)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function bname(id): string
|
||||||
|
local name: string
|
||||||
|
if ECS_IS_PAIR(id) then
|
||||||
|
local first = get_name(world, ecs_pair_first(world, id))
|
||||||
|
local second = get_name(world, ecs_pair_second(world, id))
|
||||||
|
name = `pair({first}, {second})`
|
||||||
|
else
|
||||||
|
return get_name(world, id)
|
||||||
|
end
|
||||||
|
if name then
|
||||||
|
return name
|
||||||
|
else
|
||||||
|
return `${id}`
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function ID_IS_TAG(world: World, id)
|
||||||
|
if ECS_IS_PAIR(id) then
|
||||||
|
id = ecs_pair_first(world, id)
|
||||||
|
end
|
||||||
|
return not world_has_one_inline(world, id, EcsComponent)
|
||||||
|
end
|
||||||
|
|
||||||
|
World.query = function(world: World, ...)
|
||||||
|
ASSERT((...), "Requires at least a single component")
|
||||||
|
return world_query(world, ...)
|
||||||
|
end
|
||||||
|
|
||||||
|
World.set = function(world: World, entity: i53, id: i53, value: any): ()
|
||||||
|
local is_tag = ID_IS_TAG(world, id)
|
||||||
|
if is_tag and value == nil then
|
||||||
|
local _1 = bname(world, entity)
|
||||||
|
local _2 = bname(world, id)
|
||||||
|
local why = "cannot set component value to nil"
|
||||||
|
throw(why)
|
||||||
|
return
|
||||||
|
elseif value ~= nil and is_tag then
|
||||||
|
local _1 = bname(world, entity)
|
||||||
|
local _2 = bname(world, id)
|
||||||
|
local why = `cannot set a component value because {_2} is a tag`
|
||||||
|
why ..= `\n[jecs] note: consider using "world:add({_1}, {_2})" instead`
|
||||||
|
throw(why)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
world_set(world, entity, id, value)
|
||||||
|
end
|
||||||
|
|
||||||
|
World.add = function(world: World, entity: i53, id: i53, value: any)
|
||||||
|
if value ~= nil then
|
||||||
|
local _1 = bname(world, entity)
|
||||||
|
local _2 = bname(world, id)
|
||||||
|
throw("You provided a value when none was expected. " .. `Did you mean to use "world:add({_1}, {_2})"`)
|
||||||
|
end
|
||||||
|
|
||||||
|
world_add(world, entity, id)
|
||||||
|
end
|
||||||
|
|
||||||
|
World.get = function(world: World, entity: i53, ...)
|
||||||
|
local length = select("#", ...)
|
||||||
|
ASSERT(length < 5, "world:get does not support more than 4 components")
|
||||||
|
local _1
|
||||||
|
for i = 1, length do
|
||||||
|
local id = select(i, ...)
|
||||||
|
local id_is_tag = not world_has(world, id, EcsComponent)
|
||||||
|
if id_is_tag then
|
||||||
|
local name = get_name(world, id)
|
||||||
|
if not _1 then
|
||||||
|
_1 = get_name(world, entity)
|
||||||
|
end
|
||||||
|
throw(
|
||||||
|
`cannot get (#{i}) component {name} value because it is a tag.`
|
||||||
|
.. `\n[jecs] note: If this was intentional, use "world:has({_1}, {name}) instead"`
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return world_get(world, entity, ...)
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in a new issue