mirror of
https://github.com/Ukendio/jecs.git
synced 2026-05-13 14:24:14 +00:00
Compare commits
No commits in common. "bfc3eb99808aace211253e2d2762caf520ad4b20" and "19823453aadc321760e6252a82710a2bad9b0da4" have entirely different histories.
bfc3eb9980
...
19823453aa
3 changed files with 1 additions and 264 deletions
8
src/jecs.d.ts
vendored
8
src/jecs.d.ts
vendored
|
|
@ -155,14 +155,6 @@ export class World {
|
||||||
*/
|
*/
|
||||||
target(entity: Entity, relation: Entity, index?: number): Entity | undefined;
|
target(entity: Entity, relation: Entity, index?: number): Entity | undefined;
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets an iterator for all targets of a relationship.
|
|
||||||
* Returns an empty iterator if no matches are found.
|
|
||||||
* @param entity The entity using a relationship pair.
|
|
||||||
* @param relation The "relationship" component/tag
|
|
||||||
*/
|
|
||||||
targets(entity: Entity, relation: Entity): IterFn<[]>
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deletes an entity (and its components/relationships) from the world entirely.
|
* Deletes an entity (and its components/relationships) from the world entirely.
|
||||||
* @param entity The entity to delete.
|
* @param entity The entity to delete.
|
||||||
|
|
|
||||||
|
|
@ -194,7 +194,6 @@ type world = {
|
||||||
entity: (self: world, id: i53?) -> i53,
|
entity: (self: world, id: i53?) -> i53,
|
||||||
component: (self: world) -> i53,
|
component: (self: world) -> i53,
|
||||||
target: (self: world, id: i53, relation: i53, index: number?) -> i53?,
|
target: (self: world, id: i53, relation: i53, index: number?) -> i53?,
|
||||||
targets: (self: world, id: i53, relation: i53) -> () -> i53?,
|
|
||||||
delete: (self: world, id: i53) -> (),
|
delete: (self: world, id: i53) -> (),
|
||||||
add: (self: world, id: i53, component: i53) -> (),
|
add: (self: world, id: i53, component: i53) -> (),
|
||||||
set: (self: world, id: i53, component: i53, data: any) -> (),
|
set: (self: world, id: i53, component: i53, data: any) -> (),
|
||||||
|
|
@ -254,14 +253,6 @@ export type World = {
|
||||||
index: number?
|
index: number?
|
||||||
) -> Entity<unknown>?,
|
) -> Entity<unknown>?,
|
||||||
|
|
||||||
-- Gets an iterator for all targets of a relationship.
|
|
||||||
-- Returns an empty iterator if no matches are found.
|
|
||||||
targets: <T>(
|
|
||||||
self: World,
|
|
||||||
id: Entity<T> | number,
|
|
||||||
relation: ecs_entity_t<Component>
|
|
||||||
) -> () -> Id,
|
|
||||||
|
|
||||||
--- Deletes an entity and all it's related components and relationships.
|
--- Deletes an entity and all it's related components and relationships.
|
||||||
delete: <T>(self: World, id: Entity<T>) -> (),
|
delete: <T>(self: World, id: Entity<T>) -> (),
|
||||||
|
|
||||||
|
|
@ -3311,50 +3302,6 @@ local function world_new(DEBUG: boolean?)
|
||||||
ECS_PAIR_SECOND(nth))
|
ECS_PAIR_SECOND(nth))
|
||||||
end
|
end
|
||||||
|
|
||||||
local NOOP = NOOP :: () -> i53
|
|
||||||
|
|
||||||
local function world_targets(world: world, entity: i53, relation: i53): () -> i53?
|
|
||||||
local record = entity_index_try_get_unsafe(entity)
|
|
||||||
if not record then
|
|
||||||
return NOOP
|
|
||||||
end
|
|
||||||
|
|
||||||
local archetype = record.archetype
|
|
||||||
if not archetype then
|
|
||||||
return NOOP
|
|
||||||
end
|
|
||||||
|
|
||||||
local r = ECS_PAIR(relation, EcsWildcard)
|
|
||||||
local ct_idx = world.component_index
|
|
||||||
local idr = ct_idx[r]
|
|
||||||
|
|
||||||
if not idr then
|
|
||||||
return NOOP
|
|
||||||
end
|
|
||||||
|
|
||||||
local archetype_id = archetype.id
|
|
||||||
local count = idr.counts[archetype_id]
|
|
||||||
if not count then
|
|
||||||
return NOOP
|
|
||||||
end
|
|
||||||
|
|
||||||
local nth = idr.records[archetype_id]
|
|
||||||
local end_count = nth + count
|
|
||||||
|
|
||||||
local archetype_types = archetype.types
|
|
||||||
local sparse_array = entity_index.sparse_array
|
|
||||||
local dense_array = entity_index.dense_array
|
|
||||||
|
|
||||||
return function(): i53?
|
|
||||||
if nth == end_count then
|
|
||||||
return nil
|
|
||||||
end
|
|
||||||
local target = dense_array[sparse_array[ECS_PAIR_SECOND(archetype_types[nth])].dense]
|
|
||||||
nth += 1
|
|
||||||
return target
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function world_parent(world: world, entity: i53): i53?
|
local function world_parent(world: world, entity: i53): i53?
|
||||||
return world_target(world, entity, EcsChildOf, 0)
|
return world_target(world, entity, EcsChildOf, 0)
|
||||||
end
|
end
|
||||||
|
|
@ -3783,7 +3730,6 @@ local function world_new(DEBUG: boolean?)
|
||||||
world.get = world_get :: any
|
world.get = world_get :: any
|
||||||
world.has = world_has :: any
|
world.has = world_has :: any
|
||||||
world.target = world_target
|
world.target = world_target
|
||||||
world.targets = world_targets
|
|
||||||
world.parent = world_parent
|
world.parent = world_parent
|
||||||
world.contains = world_contains
|
world.contains = world_contains
|
||||||
world.exists = world_exists
|
world.exists = world_exists
|
||||||
|
|
|
||||||
203
test/tests.luau
203
test/tests.luau
|
|
@ -3077,7 +3077,7 @@ TEST("world:set()", function()
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
TEST("world:target()", function()
|
TEST("world:target", function()
|
||||||
do CASE "nth index"
|
do CASE "nth index"
|
||||||
local world = jecs.world()
|
local world = jecs.world()
|
||||||
local A = world:component()
|
local A = world:component()
|
||||||
|
|
@ -3178,207 +3178,6 @@ TEST("world:target()", function()
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
TEST("world:targets()", function()
|
|
||||||
do CASE "should find single relation"
|
|
||||||
local world = jecs.world()
|
|
||||||
|
|
||||||
local Alice = world:entity()
|
|
||||||
local Bob = world:entity()
|
|
||||||
local Likes = world:entity()
|
|
||||||
|
|
||||||
world:add(Alice, jecs.pair(Likes, Bob))
|
|
||||||
|
|
||||||
local i = 0
|
|
||||||
for target in world:targets(Alice, Likes) do
|
|
||||||
i += 1
|
|
||||||
CHECK(target == Bob)
|
|
||||||
end
|
|
||||||
CHECK(i == 1)
|
|
||||||
end
|
|
||||||
do CASE "basic iteration"
|
|
||||||
local world = jecs.world()
|
|
||||||
|
|
||||||
local ROOT = world:entity()
|
|
||||||
local e1 = world:entity()
|
|
||||||
local targets = {}
|
|
||||||
|
|
||||||
for i = 1, 10 do
|
|
||||||
local target = world:entity()
|
|
||||||
targets[i] = target
|
|
||||||
world:add(e1, pair(ROOT, target))
|
|
||||||
end
|
|
||||||
|
|
||||||
local i = 0
|
|
||||||
for target in world:targets(e1, ROOT) do
|
|
||||||
i += 1
|
|
||||||
CHECK(targets[i] == target)
|
|
||||||
end
|
|
||||||
|
|
||||||
CHECK(i == 10)
|
|
||||||
end
|
|
||||||
do CASE "multiple iterations"
|
|
||||||
local world = jecs.world()
|
|
||||||
|
|
||||||
local ROOT = world:entity()
|
|
||||||
local OTHER = world:entity()
|
|
||||||
|
|
||||||
local e = world:entity()
|
|
||||||
|
|
||||||
local root_targets = {}
|
|
||||||
local other_targets = {}
|
|
||||||
|
|
||||||
for i = 1, 5 do
|
|
||||||
local t = world:entity()
|
|
||||||
root_targets[i] = t
|
|
||||||
world:add(e, pair(ROOT, t))
|
|
||||||
end
|
|
||||||
|
|
||||||
for i = 1, 3 do
|
|
||||||
local t = world:entity()
|
|
||||||
other_targets[i] = t
|
|
||||||
world:add(e, pair(OTHER, t))
|
|
||||||
end
|
|
||||||
|
|
||||||
local i = 0
|
|
||||||
for target in world:targets(e, ROOT) do
|
|
||||||
i += 1
|
|
||||||
CHECK(root_targets[i] == target)
|
|
||||||
end
|
|
||||||
CHECK(i == 5)
|
|
||||||
|
|
||||||
local j = 0
|
|
||||||
for target in world:targets(e, OTHER) do
|
|
||||||
j += 1
|
|
||||||
CHECK(other_targets[j] == target)
|
|
||||||
end
|
|
||||||
CHECK(j == 3)
|
|
||||||
end
|
|
||||||
do CASE "empty iterator"
|
|
||||||
local world = jecs.world()
|
|
||||||
|
|
||||||
local ROOT = world:entity()
|
|
||||||
local OTHER = world:entity()
|
|
||||||
|
|
||||||
local e = world:entity()
|
|
||||||
|
|
||||||
world:add(e, pair(ROOT, world:entity()))
|
|
||||||
|
|
||||||
local count = 0
|
|
||||||
for _ in world:targets(e, OTHER) do
|
|
||||||
count += 1
|
|
||||||
end
|
|
||||||
|
|
||||||
CHECK(count == 0)
|
|
||||||
end
|
|
||||||
do CASE "should ignore deleted targets"
|
|
||||||
local world = jecs.world()
|
|
||||||
|
|
||||||
local ROOT = world:entity()
|
|
||||||
local e = world:entity()
|
|
||||||
|
|
||||||
local alive = {}
|
|
||||||
local dead = {}
|
|
||||||
|
|
||||||
for i = 1, 3 do
|
|
||||||
local t = world:entity()
|
|
||||||
alive[#alive + 1] = t
|
|
||||||
world:add(e, pair(ROOT, t))
|
|
||||||
end
|
|
||||||
|
|
||||||
for i = 1, 2 do
|
|
||||||
local t = world:entity()
|
|
||||||
dead[#dead + 1] = t
|
|
||||||
world:add(e, pair(ROOT, t))
|
|
||||||
world:delete(t)
|
|
||||||
end
|
|
||||||
|
|
||||||
local count = 0
|
|
||||||
for t in world:targets(e, ROOT) do
|
|
||||||
count += 1
|
|
||||||
CHECK(t ~= nil)
|
|
||||||
end
|
|
||||||
|
|
||||||
CHECK(count == #alive)
|
|
||||||
end
|
|
||||||
do CASE "should properly handle rapid add/remove calls"
|
|
||||||
local world = jecs.world()
|
|
||||||
|
|
||||||
local ROOT = world:entity()
|
|
||||||
local e = world:entity()
|
|
||||||
|
|
||||||
local alive = {}
|
|
||||||
local all_targets = {} :: {Entity}
|
|
||||||
|
|
||||||
for i = 1, 100 do
|
|
||||||
local t = world:entity()
|
|
||||||
all_targets[#all_targets + 1] = t
|
|
||||||
|
|
||||||
world:add(e, jecs.pair(ROOT, t))
|
|
||||||
alive[t] = true
|
|
||||||
end
|
|
||||||
|
|
||||||
for i = 1, 500 do
|
|
||||||
local t: Entity
|
|
||||||
while t == nil do
|
|
||||||
t = all_targets[math.random(#all_targets)]
|
|
||||||
end
|
|
||||||
|
|
||||||
if math.random() < 0.5 then
|
|
||||||
world:remove(e, jecs.pair(ROOT, t))
|
|
||||||
alive[t] = nil
|
|
||||||
else
|
|
||||||
world:add(e, jecs.pair(ROOT, t))
|
|
||||||
alive[t] = true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local entity_index = world.entity_index
|
|
||||||
local function entity_index_check_alive(entity)
|
|
||||||
local r = entity_index.sparse_array[ECS_ID(entity)]
|
|
||||||
|
|
||||||
if not r or r.dense == 0 then
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
|
|
||||||
local dense = r.dense
|
|
||||||
if dense > entity_index.alive_count then
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
return entity_index.dense_array[dense] ~= nil
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
for i=1, 10 do
|
|
||||||
local seen = {}
|
|
||||||
for t in world:targets(e, ROOT) do
|
|
||||||
CHECK(entity_index_check_alive(t))
|
|
||||||
CHECK(entity_index_check_alive(jecs.pair(ROOT, t)))
|
|
||||||
|
|
||||||
CHECK(alive[t] == true)
|
|
||||||
|
|
||||||
CHECK(seen[t] == nil)
|
|
||||||
seen[t] = true
|
|
||||||
end
|
|
||||||
|
|
||||||
for t, _ in pairs(alive) do
|
|
||||||
CHECK(seen[t] == true)
|
|
||||||
end
|
|
||||||
|
|
||||||
for j = 1, #all_targets do
|
|
||||||
local t = all_targets[j]
|
|
||||||
|
|
||||||
if math.random() < 0.5 then
|
|
||||||
world:remove(e, jecs.pair(ROOT, t))
|
|
||||||
alive[t] = nil
|
|
||||||
else
|
|
||||||
world:add(e, jecs.pair(ROOT, t))
|
|
||||||
alive[t] = true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
|
|
||||||
TEST("#adding a recycled target", function()
|
TEST("#adding a recycled target", function()
|
||||||
local world = jecs.world()
|
local world = jecs.world()
|
||||||
local R = world:component()
|
local R = world:component()
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue