Add replace method to query (#46)

* Add replace function

* Add next method

* Remove tostring

* Fix EmptyQuery

* add replace method

* merge conflicts

* return self in without

* Make aliases relative

* Add test

* add to changelog
This commit is contained in:
Marcus 2024-07-07 04:53:17 +02:00 committed by GitHub
parent b73d7e12b7
commit 0fe23e151c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 120 additions and 53 deletions

View file

@ -1,6 +1,6 @@
{
"aliases": {
"jecs": "C:/Users/Marcus/Documents/packages/jecs/src",
"testkit": "C:/Users/Marcus/Documents/packages/jecs/testkit"
"jecs": "src",
"testkit": "testkit"
}
}

View file

@ -10,6 +10,11 @@ The format is based on [Keep a Changelog][kac], and this project adheres to
## [Unreleased]
### Added
- Added `query:replace(function(...T) return ...U end)` for replacing components in place
- Method is fast pathed to replacing the data to the components for each corresponding entity
### Changed
- Iterator now goes backwards instead to prevent common cases of iterator invalidation
@ -109,12 +114,3 @@ The format is based on [Keep a Changelog][kac], and this project adheres to
[0.0.0-prototype-rc.3]: https://github.com/ukendio/jecs/releases/tag/v0.0.0-prototype.rc.3
[0.0.0-prototype.rc.2]: https://github.com/ukendio/jecs/releases/tag/v0.0.0-prototype.rc.2
[0.0.0-prototype-rc.1]: https://github.com/ukendio/jecs/releases/tag/v0.0.0-prototype.rc.1

View file

@ -7,6 +7,7 @@ local function TITLE(title: string)
print()
print(testkit.color.white(title))
end
local jecs = require("@jecs")
local mirror = require("../mirror/init")

View file

@ -662,16 +662,24 @@ local function noop(_self: Query, ...): () -> ()
end
local EmptyQuery = {
__iter = noop,
without = noop,
__iter = iterNoop,
next = noop,
replace = noop,
without = function(self)
return self
end
}
EmptyQuery.__index = EmptyQuery
setmetatable(EmptyQuery, EmptyQuery)
export type Query = typeof(EmptyQuery)
type CompatibleArchetype = { archetype: Archetype, indices: { number } }
local function replaceMult(row, columns, ...)
for i, column in columns do
column[row] = select(i, ...)
end
end
local function preparedQuery(compatibleArchetypes: { Archetype },
components: { i53? }, indices: { { number } })
@ -783,17 +791,60 @@ local function preparedQuery(compatibleArchetypes: { Archetype },
return self
end
local it = {
__iter = function()
lastArchetype = 1
archetype = compatibleArchetypes[1]
entities = archetype.entities
i = #entities
local function iter()
lastArchetype = 1
archetype = compatibleArchetypes[1]
entities = archetype.entities
i = #entities
return queryNext
end,
return queryNext
end
local function replace(_, fn)
for i, archetype in compatibleArchetypes do
local tr = indices[i]
local columns = archetype.columns
for row in archetype.entities do
if queryLength == 1 then
local a = columns[tr[1]]
local pa = fn(a[row])
a[row] = pa
elseif queryLength == 2 then
local a = columns[tr[1]]
local b = columns[tr[2]]
a[row], b[row] = fn(a[row], b[row])
elseif queryLength == 3 then
local a = columns[tr[1]]
local b = columns[tr[2]]
local c = columns[tr[3]]
a[row], b[row], c[row] = fn(a[row], b[row], c[row])
elseif queryLength == 4 then
local a = columns[tr[1]]
local b = columns[tr[2]]
local c = columns[tr[3]]
local d = columns[tr[4]]
a[row], b[row], c[row], d[row] = fn(
a[row], b[row], c[row], d[row])
else
for i = 1, queryLength do
queryOutput[i] = columns[tr[i]][row]
end
replaceMult(row, columns, fn(unpack(queryOutput)))
end
end
end
end
local it = {
__iter = iter,
next = queryNext,
without = without
without = without,
replace = replace
}
return setmetatable(it, it) :: any

View file

@ -449,9 +449,28 @@ TEST("world", function()
count += 1
end
print(count)
CHECK(count == 2)
end
do CASE "should replace component data"
local world = jecs.World.new()
local A = world:component()
local B = world:component()
local C = world:component()
local e = world:entity()
world:set(e, A, 1)
world:set(e, B, true)
world:set(e, C, "hello ")
world:query(A, B, C):replace(function(a, b, c)
return a * 2, not b, c.."world"
end)
CHECK(world:get(e, A) == 2)
CHECK(world:get(e, B) == false)
CHECK(world:get(e, C) == "hello world")
end
end)
FINISH()