mirror of
https://github.com/Ukendio/jecs.git
synced 2025-04-25 01:20:04 +00:00
Add iter method
This commit is contained in:
parent
c5daddd505
commit
97acbd66ab
3 changed files with 101 additions and 4 deletions
39
lib/init.lua
39
lib/init.lua
|
@ -173,8 +173,8 @@ local World = {}
|
||||||
World.__index = World
|
World.__index = World
|
||||||
function World.new()
|
function World.new()
|
||||||
local self = setmetatable({
|
local self = setmetatable({
|
||||||
entityIndex = {},
|
entityIndex = {} :: EntityIndex,
|
||||||
componentIndex = {},
|
componentIndex = {} :: ComponentIndex,
|
||||||
archetypes = {},
|
archetypes = {},
|
||||||
archetypeIndex = {},
|
archetypeIndex = {},
|
||||||
ROOT_ARCHETYPE = (nil :: any) :: Archetype,
|
ROOT_ARCHETYPE = (nil :: any) :: Archetype,
|
||||||
|
@ -285,10 +285,10 @@ local function archetypeTraverseAdd(world: World, componentId: i53, from: Archet
|
||||||
return edge.add
|
return edge.add
|
||||||
end
|
end
|
||||||
|
|
||||||
local function ensureRecord(entityIndex, entityId: i53): Record
|
local function ensureRecord(entityIndex: EntityIndex, entityId: i53): Record
|
||||||
local id = entityId
|
local id = entityId
|
||||||
if not entityIndex[id] then
|
if not entityIndex[id] then
|
||||||
entityIndex[id] = {}
|
entityIndex[id] = {} :: Record
|
||||||
end
|
end
|
||||||
return entityIndex[id] :: Record
|
return entityIndex[id] :: Record
|
||||||
end
|
end
|
||||||
|
@ -632,6 +632,37 @@ function World.observer(world: World, ...)
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function World.__iter(world: World): () -> (number?, unknown?)
|
||||||
|
local entityIndex = world.entityIndex
|
||||||
|
local last
|
||||||
|
|
||||||
|
return function()
|
||||||
|
local entity, record = next(entityIndex, last)
|
||||||
|
if not entity then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
last = entity
|
||||||
|
|
||||||
|
local archetype = record.archetype
|
||||||
|
if not archetype then
|
||||||
|
-- Returns only the entity id as an entity without data should not return
|
||||||
|
-- data and allow the user to get an error if they don't handle the case.
|
||||||
|
return entity
|
||||||
|
end
|
||||||
|
|
||||||
|
local row = record.row
|
||||||
|
local types = archetype.types
|
||||||
|
local columns = archetype.columns
|
||||||
|
local entityData = {}
|
||||||
|
for i, column in columns do
|
||||||
|
-- We use types because the key should be the component ID not the column index
|
||||||
|
entityData[types[i]] = column[row]
|
||||||
|
end
|
||||||
|
|
||||||
|
return entity, entityData
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
return table.freeze({
|
return table.freeze({
|
||||||
World = World,
|
World = World,
|
||||||
ON_ADD = ON_ADD,
|
ON_ADD = ON_ADD,
|
||||||
|
|
|
@ -299,5 +299,38 @@ return function()
|
||||||
expect(world:get(id, Poison)).to.never.be.ok()
|
expect(world:get(id, Poison)).to.never.be.ok()
|
||||||
expect(world:get(id, Health)).to.never.be.ok()
|
expect(world:get(id, Health)).to.never.be.ok()
|
||||||
end)
|
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()
|
||||||
|
else
|
||||||
|
error("unknown entity", id)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
expect(count).to.equal(3)
|
||||||
|
end)
|
||||||
end)
|
end)
|
||||||
end
|
end
|
|
@ -110,6 +110,39 @@ TEST("world:query", function()
|
||||||
CHECK(world:get(id, Health) == nil)
|
CHECK(world:get(id, Health) == nil)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
do CASE "Should allow iterating the whole world"
|
||||||
|
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
|
||||||
|
CHECK(data[A] == true)
|
||||||
|
CHECK(data[B] == nil)
|
||||||
|
elseif id == eB then
|
||||||
|
CHECK(data[B] == true)
|
||||||
|
CHECK(data[A] == nil)
|
||||||
|
elseif id == eAB then
|
||||||
|
CHECK(data[A] == true)
|
||||||
|
CHECK(data[B] == true)
|
||||||
|
else
|
||||||
|
error("unknown entity", id)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
CHECK(count == 3)
|
||||||
|
end
|
||||||
|
|
||||||
end)
|
end)
|
||||||
|
|
||||||
FINISH()
|
FINISH()
|
Loading…
Reference in a new issue