mirror of
https://github.com/Ukendio/jecs.git
synced 2025-04-24 17:10:03 +00:00
Add backwards iteration (#61)
* Iterate backwards * Should test for removing as well * Add test * Add faíling test * Add to changelog
This commit is contained in:
parent
6559c56d47
commit
c0e73273d1
3 changed files with 93 additions and 34 deletions
|
@ -10,12 +10,16 @@ The format is based on [Keep a Changelog][kac], and this project adheres to
|
||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Iterator now goes backwards instead to prevent common cases of iterator invalidation
|
||||||
|
|
||||||
## [0.2.1] - 2024-07-06
|
## [0.2.1] - 2024-07-06
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
* Added `jecs.Component` built-in component which will be added to ids created with `world:component()`.
|
- Added `jecs.Component` built-in component which will be added to ids created with `world:component()`.
|
||||||
* used to find every component id with `query(jecs.Component)
|
- Used to find every component id with `query(jecs.Component)
|
||||||
|
|
||||||
## [0.2.0] - 2024-07-03
|
## [0.2.0] - 2024-07-03
|
||||||
|
|
||||||
|
|
|
@ -184,13 +184,9 @@ local function nextEntityId(entityIndex: EntityIndex, index: i24): i53
|
||||||
return id
|
return id
|
||||||
end
|
end
|
||||||
|
|
||||||
local function transitionArchetype(
|
local function transitionArchetype(entityIndex: EntityIndex, to: Archetype,
|
||||||
entityIndex: EntityIndex,
|
destinationRow: i24, from: Archetype, sourceRow: i24)
|
||||||
to: Archetype,
|
|
||||||
destinationRow: i24,
|
|
||||||
from: Archetype,
|
|
||||||
sourceRow: i24
|
|
||||||
)
|
|
||||||
local columns = from.columns
|
local columns = from.columns
|
||||||
local sourceEntities = from.entities
|
local sourceEntities = from.entities
|
||||||
local destinationEntities = to.entities
|
local destinationEntities = to.entities
|
||||||
|
@ -690,11 +686,11 @@ local function preparedQuery(compatibleArchetypes: { Archetype },
|
||||||
|
|
||||||
local queryOutput = {}
|
local queryOutput = {}
|
||||||
|
|
||||||
local i = 1
|
local entities = archetype.entities
|
||||||
|
local i = #entities
|
||||||
|
|
||||||
local function queryNext(): ...any
|
local function queryNext(): ...any
|
||||||
local entityId = archetype.entities[i]
|
local entityId = entities[i]
|
||||||
|
|
||||||
while entityId == nil do
|
while entityId == nil do
|
||||||
lastArchetype += 1
|
lastArchetype += 1
|
||||||
archetype = compatibleArchetypes[lastArchetype]
|
archetype = compatibleArchetypes[lastArchetype]
|
||||||
|
@ -703,12 +699,13 @@ local function preparedQuery(compatibleArchetypes: { Archetype },
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
i = 1
|
entities = archetype.entities
|
||||||
entityId = archetype.entities[1]
|
i = #entities
|
||||||
|
entityId = entities[i]
|
||||||
end
|
end
|
||||||
|
|
||||||
local row = i
|
local row = i
|
||||||
i+=1
|
i-=1
|
||||||
|
|
||||||
local columns = archetype.columns
|
local columns = archetype.columns
|
||||||
local tr = indices[lastArchetype]
|
local tr = indices[lastArchetype]
|
||||||
|
@ -788,9 +785,10 @@ local function preparedQuery(compatibleArchetypes: { Archetype },
|
||||||
|
|
||||||
local it = {
|
local it = {
|
||||||
__iter = function()
|
__iter = function()
|
||||||
i = 1
|
|
||||||
lastArchetype = 1
|
lastArchetype = 1
|
||||||
archetype = compatibleArchetypes[1]
|
archetype = compatibleArchetypes[1]
|
||||||
|
entities = archetype.entities
|
||||||
|
i = #entities
|
||||||
|
|
||||||
return queryNext
|
return queryNext
|
||||||
end,
|
end,
|
||||||
|
|
|
@ -25,30 +25,23 @@ local N = 10
|
||||||
type World = jecs.WorldShim
|
type World = jecs.WorldShim
|
||||||
|
|
||||||
TEST("world", function()
|
TEST("world", function()
|
||||||
do CASE("should be iterable")
|
do CASE("should find every component id")
|
||||||
local world = jecs.World.new() :: World
|
local world = jecs.World.new() :: World
|
||||||
local A = world:component()
|
local A = world:component()
|
||||||
local B = world:component()
|
local B = world:component()
|
||||||
local eA = world:entity()
|
world:entity()
|
||||||
world:set(eA, A, true)
|
world:entity()
|
||||||
local eB = world:entity()
|
world:entity()
|
||||||
world:set(eB, B, true)
|
|
||||||
local eAB = world:entity()
|
|
||||||
world:set(eAB, A, true)
|
|
||||||
world:set(eAB, B, true)
|
|
||||||
|
|
||||||
for id, data in world do
|
local count = 0
|
||||||
if id == eA then
|
for componentId in world:query(jecs.Component) do
|
||||||
CHECK(data[A] == true)
|
if componentId ~= A and componentId ~= B then
|
||||||
CHECK(data[B] == nil)
|
error("found entity")
|
||||||
elseif id == eB then
|
|
||||||
CHECK(data[A] == nil)
|
|
||||||
CHECK(data[B] == true)
|
|
||||||
elseif id == eAB then
|
|
||||||
CHECK(data[A] == true)
|
|
||||||
CHECK(data[B] == true)
|
|
||||||
end
|
end
|
||||||
|
count += 1
|
||||||
end
|
end
|
||||||
|
|
||||||
|
CHECK(count == 2)
|
||||||
end
|
end
|
||||||
|
|
||||||
do CASE("should remove its components")
|
do CASE("should remove its components")
|
||||||
|
@ -395,6 +388,70 @@ TEST("world", function()
|
||||||
end
|
end
|
||||||
CHECK(count == 2)
|
CHECK(count == 2)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
do CASE "should be able to add/remove matching entity during iteration"
|
||||||
|
local world = jecs.World.new()
|
||||||
|
local Name = world:component()
|
||||||
|
for i = 1, 5 do
|
||||||
|
local e = world:entity()
|
||||||
|
world:set(e, Name, tostring(e))
|
||||||
|
end
|
||||||
|
local count = 0
|
||||||
|
for id, name in world:query(Name) do
|
||||||
|
count += 1
|
||||||
|
CHECK(id == tonumber(name))
|
||||||
|
|
||||||
|
world:remove(id, Name)
|
||||||
|
local e = world:entity()
|
||||||
|
world:set(e, Name, tostring(e))
|
||||||
|
end
|
||||||
|
CHECK(count == 5)
|
||||||
|
end
|
||||||
|
|
||||||
|
do CASE "should allow adding a matching entity during iteration"
|
||||||
|
local world = jecs.World.new()
|
||||||
|
local A = world:component()
|
||||||
|
local B = world:component()
|
||||||
|
|
||||||
|
local e1 = world:entity()
|
||||||
|
local e2 = world:entity()
|
||||||
|
world:add(e1, A)
|
||||||
|
world:add(e2, A)
|
||||||
|
world:add(e2, B)
|
||||||
|
|
||||||
|
local count = 0
|
||||||
|
for id in world:query(A) do
|
||||||
|
local e = world:entity()
|
||||||
|
world:add(e, A)
|
||||||
|
world:add(e, B)
|
||||||
|
count += 1
|
||||||
|
end
|
||||||
|
|
||||||
|
CHECK(count == 3)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
do CASE "should not iterate same entity when adding component"
|
||||||
|
local world = jecs.World.new()
|
||||||
|
local A = world:component()
|
||||||
|
local B = world:component()
|
||||||
|
|
||||||
|
local e1 = world:entity()
|
||||||
|
local e2 = world:entity()
|
||||||
|
world:add(e1, A)
|
||||||
|
world:add(e2, A)
|
||||||
|
world:add(e2, B)
|
||||||
|
|
||||||
|
local count = 0
|
||||||
|
for id in world:query(A) do
|
||||||
|
world:add(id, B)
|
||||||
|
|
||||||
|
count += 1
|
||||||
|
end
|
||||||
|
|
||||||
|
print(count)
|
||||||
|
CHECK(count == 2)
|
||||||
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
FINISH()
|
FINISH()
|
||||||
|
|
Loading…
Reference in a new issue