Fix component overriding when in disorder

This commit is contained in:
Ukendio 2024-05-02 20:15:25 +02:00
parent e5e1aec6b2
commit 051cacd3de
2 changed files with 50 additions and 31 deletions

View file

@ -51,31 +51,38 @@ local REST = HI_COMPONENT_ID + 4
local function transitionArchetype( local function transitionArchetype(
entityIndex: EntityIndex, entityIndex: EntityIndex,
destinationArchetype: Archetype, to: Archetype,
destinationRow: i24, destinationRow: i24,
sourceArchetype: Archetype, from: Archetype,
sourceRow: i24 sourceRow: i24
) )
local columns = sourceArchetype.columns local columns = from.columns
local sourceEntities = sourceArchetype.entities local sourceEntities = from.entities
local destinationEntities = destinationArchetype.entities local destinationEntities = to.entities
local destinationColumns = destinationArchetype.columns local destinationColumns = to.columns
local tr = to.records
local types = from.types
for componentId, column in columns do for i, column in columns do
local targetColumn = destinationColumns[componentId] local targetColumn = destinationColumns[tr[types[i]]]
if targetColumn then if targetColumn then
targetColumn[destinationRow] = column[sourceRow] targetColumn[destinationRow] = column[sourceRow]
end end
if sourceRow ~= #column then
column[sourceRow] = column[#column] column[sourceRow] = column[#column]
column[#column] = nil column[#column] = nil
end end
end
destinationEntities[destinationRow] = sourceEntities[sourceRow] destinationEntities[destinationRow] = sourceEntities[sourceRow]
entityIndex[sourceEntities[sourceRow]].row = destinationRow entityIndex[sourceEntities[sourceRow]].row = destinationRow
local movedAway = #sourceEntities local movedAway = #sourceEntities
if sourceRow ~= movedAway then
sourceEntities[sourceRow] = sourceEntities[movedAway] sourceEntities[sourceRow] = sourceEntities[movedAway]
entityIndex[sourceEntities[movedAway]].row = sourceRow entityIndex[sourceEntities[movedAway]].row = sourceRow
end
sourceEntities[movedAway] = nil sourceEntities[movedAway] = nil
end end
@ -145,7 +152,9 @@ local function archetypeOf(world: World, types: { i24 }, prev: Archetype?): Arch
} }
world.archetypeIndex[ty] = archetype world.archetypeIndex[ty] = archetype
world.archetypes[id] = archetype world.archetypes[id] = archetype
if #types > 0 then
createArchetypeRecords(world.componentIndex, archetype, prev) createArchetypeRecords(world.componentIndex, archetype, prev)
end
return archetype return archetype
end end
@ -180,8 +189,6 @@ local function emit(world, eventDescription)
}) })
end end
local function onNotifyAdd(world, archetype, otherArchetype, row: number, added: Ty) local function onNotifyAdd(world, archetype, otherArchetype, row: number, added: Ty)
if #added > 0 then if #added > 0 then
emit(world, { emit(world, {
@ -194,13 +201,13 @@ local function onNotifyAdd(world, archetype, otherArchetype, row: number, added:
end end
end end
export type World = typeof(World.new()) export type World = typeof(World.new())
local function ensureArchetype(world: World, types, prev) local function ensureArchetype(world: World, types, prev)
if #types < 1 then if #types < 1 then
return world.ROOT_ARCHETYPE return world.ROOT_ARCHETYPE
end end
local ty = hash(types) local ty = hash(types)
local archetype = world.archetypeIndex[ty] local archetype = world.archetypeIndex[ty]
if archetype then if archetype then
@ -270,26 +277,25 @@ end
function World.set(world: World, entityId: i53, componentId: i53, data: unknown) function World.set(world: World, entityId: i53, componentId: i53, data: unknown)
local record = ensureRecord(world.entityIndex, entityId) local record = ensureRecord(world.entityIndex, entityId)
local sourceArchetype = record.archetype local from = record.archetype
local destinationArchetype = archetypeTraverseAdd(world, componentId, sourceArchetype) local to = archetypeTraverseAdd(world, componentId, from)
if sourceArchetype == destinationArchetype then if from == to then
local archetypeRecord = destinationArchetype.records[componentId] local archetypeRecord = to.records[componentId]
destinationArchetype.columns[archetypeRecord][record.row] = data from.columns[archetypeRecord][record.row] = data
return return
end end
if from then
if sourceArchetype then moveEntity(world.entityIndex, entityId, record, to)
moveEntity(world.entityIndex, entityId, record, destinationArchetype)
else else
if #destinationArchetype.types > 0 then if #to.types > 0 then
newEntity(entityId, record, destinationArchetype) newEntity(entityId, record, to)
onNotifyAdd(world, destinationArchetype, sourceArchetype, record.row, { componentId }) onNotifyAdd(world, to, from, record.row, { componentId })
end end
end end
local archetypeRecord = destinationArchetype.records[componentId] local archetypeRecord = to.records[componentId]
destinationArchetype.columns[archetypeRecord][record.row] = data to.columns[archetypeRecord][record.row] = data
end end
local function archetypeTraverseRemove(world: World, componentId: i53, archetype: Archetype?): Archetype local function archetypeTraverseRemove(world: World, componentId: i53, archetype: Archetype?): Archetype

View file

@ -6,7 +6,6 @@ local TEST, CASE, CHECK, FINISH, SKIP = testkit.test()
local N = 10 local N = 10
TEST("world:query", function() TEST("world:query", function()
do CASE "should query all matching entities" do CASE "should query all matching entities"
local world = jecs.World.new() local world = jecs.World.new()
@ -83,6 +82,20 @@ TEST("world:query", function()
end end
do CASE "should allow setting components in arbitrary order"
local world = jecs.World.new()
local Health = world:component()
local Poison = world:component()
local id = world:entity()
world:set(id, Poison, 5)
world:set(id, Health, 50)
CHECK(world:get(id, Poison) == 5)
end
end) end)
FINISH() FINISH()