mirror of
https://github.com/Ukendio/jecs.git
synced 2025-04-25 09:30:03 +00:00
Fix world_has_any checking for inverse statement
This commit is contained in:
parent
6d45af93f0
commit
4092a6c855
2 changed files with 125 additions and 31 deletions
|
@ -365,7 +365,7 @@ local function world_has_any(world: World, entity: number, ...: i53): boolean
|
||||||
local records = archetype.records
|
local records = archetype.records
|
||||||
|
|
||||||
for i = 1, select("#", ...) do
|
for i = 1, select("#", ...) do
|
||||||
if not records[select(i, ...)] then
|
if records[select(i, ...)] then
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -1407,7 +1407,7 @@ World.target = world_target
|
||||||
World.parent = world_parent
|
World.parent = world_parent
|
||||||
World.contains = world_contains
|
World.contains = world_contains
|
||||||
|
|
||||||
function World.new(): t_world
|
function World.new(): self: World
|
||||||
local self = setmetatable({
|
local self = setmetatable({
|
||||||
archetypeIndex = {} :: { [string]: Archetype },
|
archetypeIndex = {} :: { [string]: Archetype },
|
||||||
archetypes = {} :: Archetypes,
|
archetypes = {} :: Archetypes,
|
||||||
|
@ -1464,44 +1464,40 @@ type World = {
|
||||||
nextComponentId: number,
|
nextComponentId: number,
|
||||||
nextEntityId: number,
|
nextEntityId: number,
|
||||||
nextArchetypeId: number,
|
nextArchetypeId: number,
|
||||||
}
|
} & {
|
||||||
|
|
||||||
export type t_world = typeof(setmetatable(
|
|
||||||
{} :: {
|
|
||||||
|
|
||||||
--- Creates a new entity
|
--- Creates a new entity
|
||||||
entity: (t_world) -> Entity,
|
entity: (self: World) -> Entity,
|
||||||
--- Creates a new entity located in the first 256 ids.
|
--- Creates a new entity located in the first 256 ids.
|
||||||
--- These should be used for static components for fast access.
|
--- These should be used for static components for fast access.
|
||||||
component: <T>(t_world) -> Entity<T>,
|
component: <T>(self: World) -> Entity<T>,
|
||||||
--- Gets the target of an relationship. For example, when a user calls
|
--- Gets the target of an relationship. For example, when a user calls
|
||||||
--- `world:target(id, ChildOf(parent))`, you will obtain the parent entity.
|
--- `world:target(id, ChildOf(parent))`, you will obtain the parent entity.
|
||||||
target: (t_world, id: Entity, relation: Entity) -> Entity?,
|
target: (self: World, id: Entity, relation: Entity) -> Entity?,
|
||||||
--- Deletes an entity and all it's related components and relationships.
|
--- Deletes an entity and all it's related components and relationships.
|
||||||
delete: (t_world, id: Entity) -> (),
|
delete: (self: World, id: Entity) -> (),
|
||||||
|
|
||||||
--- Adds a component to the entity with no value
|
--- Adds a component to the entity with no value
|
||||||
add: <T>(world: t_world, id: Entity, component: Entity<T>) -> (),
|
add: <T>(self: World, id: Entity, component: Entity<T>) -> (),
|
||||||
--- Assigns a value to a component on the given entity
|
--- Assigns a value to a component on the given entity
|
||||||
set: <T>(world: World, id: Entity, component: Entity<T>, data: T) -> (),
|
set: <T>(self: World, id: Entity, component: Entity<T>, data: T) -> (),
|
||||||
|
|
||||||
-- Clears an entity from the world
|
-- Clears an entity from the world
|
||||||
clear: (t_world, id: Entity) -> (),
|
clear: (self: World, id: Entity) -> (),
|
||||||
--- Removes a component from the given entity
|
--- Removes a component from the given entity
|
||||||
remove: (t_world, id: Entity, component: Entity) -> (),
|
remove: (self: World, id: Entity, component: Entity) -> (),
|
||||||
--- Retrieves the value of up to 4 components. These values may be nil.
|
--- Retrieves the value of up to 4 components. These values may be nil.
|
||||||
get: (<A>(t_world, id: any, Entity<A>) -> A)
|
get: (<A>(self: World, id: any, Entity<A>) -> A)
|
||||||
& (<A, B>(t_world, id: Entity, Entity<A>, Entity<B>) -> (A, B))
|
& (<A, B>(self: World, id: Entity, Entity<A>, Entity<B>) -> (A, B))
|
||||||
& (<A, B, C>(t_world, id: Entity, Entity<A>, Entity<B>, Entity<C>) -> (A, B, C))
|
& (<A, B, C>(self: World, id: Entity, Entity<A>, Entity<B>, Entity<C>) -> (A, B, C))
|
||||||
& <A, B, C, D>(t_world, id: Entity, Entity<A>, Entity<B>, Entity<C>, Entity<D>) -> (A, B, C, D),
|
& <A, B, C, D>(self: World, id: Entity, Entity<A>, Entity<B>, Entity<C>, Entity<D>) -> (A, B, C, D),
|
||||||
|
|
||||||
--- Searches the world for entities that match a given query
|
--- Searches the world for entities that match a given query
|
||||||
query: (<A>(t_world, Entity<A>) -> Query<A>)
|
query: (<A>(self: World, Entity<A>) -> Query<A>)
|
||||||
& (<A, B>(t_world, Entity<A>, Entity<B>) -> Query<A, B>)
|
& (<A, B>(self: World, Entity<A>, Entity<B>) -> Query<A, B>)
|
||||||
& (<A, B, C>(t_world, Entity<A>, Entity<B>, Entity<C>) -> Query<A, B, C>)
|
& (<A, B, C>(self: World, Entity<A>, Entity<B>, Entity<C>) -> Query<A, B, C>)
|
||||||
& (<A, B, C, D>(t_world, Entity<A>, Entity<B>, Entity<C>, Entity<D>) -> Query<A, B, C, D>)
|
& (<A, B, C, D>(self: World, Entity<A>, Entity<B>, Entity<C>, Entity<D>) -> Query<A, B, C, D>)
|
||||||
& (<A, B, C, D, E>(
|
& (<A, B, C, D, E>(
|
||||||
t_world,
|
self: World,
|
||||||
Entity<A>,
|
Entity<A>,
|
||||||
Entity<B>,
|
Entity<B>,
|
||||||
Entity<C>,
|
Entity<C>,
|
||||||
|
@ -1509,7 +1505,7 @@ export type t_world = typeof(setmetatable(
|
||||||
Entity<E>
|
Entity<E>
|
||||||
) -> Query<A, B, C, D, E>)
|
) -> Query<A, B, C, D, E>)
|
||||||
& (<A, B, C, D, E, F>(
|
& (<A, B, C, D, E, F>(
|
||||||
t_world,
|
self: World,
|
||||||
Entity<A>,
|
Entity<A>,
|
||||||
Entity<B>,
|
Entity<B>,
|
||||||
Entity<C>,
|
Entity<C>,
|
||||||
|
@ -1518,7 +1514,7 @@ export type t_world = typeof(setmetatable(
|
||||||
Entity<F>
|
Entity<F>
|
||||||
) -> Query<A, B, C, D, E, F>)
|
) -> Query<A, B, C, D, E, F>)
|
||||||
& (<A, B, C, D, E, F, G>(
|
& (<A, B, C, D, E, F, G>(
|
||||||
t_world,
|
self: World,
|
||||||
Entity<A>,
|
Entity<A>,
|
||||||
Entity<B>,
|
Entity<B>,
|
||||||
Entity<C>,
|
Entity<C>,
|
||||||
|
@ -1528,7 +1524,7 @@ export type t_world = typeof(setmetatable(
|
||||||
Entity<G>
|
Entity<G>
|
||||||
) -> Query<A, B, C, D, E, F, G>)
|
) -> Query<A, B, C, D, E, F, G>)
|
||||||
& (<A, B, C, D, E, F, G, H>(
|
& (<A, B, C, D, E, F, G, H>(
|
||||||
t_world,
|
self: World,
|
||||||
Entity<A>,
|
Entity<A>,
|
||||||
Entity<B>,
|
Entity<B>,
|
||||||
Entity<C>,
|
Entity<C>,
|
||||||
|
@ -1539,12 +1535,10 @@ export type t_world = typeof(setmetatable(
|
||||||
Entity<H>,
|
Entity<H>,
|
||||||
...Entity<any>
|
...Entity<any>
|
||||||
) -> Query<A, B, C, D, E, F, G, H>),
|
) -> Query<A, B, C, D, E, F, G, H>),
|
||||||
}, {}
|
}
|
||||||
))
|
|
||||||
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
World = World :: { new: () -> t_world },
|
World = World :: { new: () -> World },
|
||||||
|
|
||||||
OnAdd = EcsOnAdd :: Entity,
|
OnAdd = EcsOnAdd :: Entity,
|
||||||
OnRemove = EcsOnRemove :: Entity,
|
OnRemove = EcsOnRemove :: Entity,
|
||||||
|
|
100
test/tests.luau
100
test/tests.luau
|
@ -1142,5 +1142,105 @@ TEST("Hooks", function()
|
||||||
CHECK(not world:has(e1, A))
|
CHECK(not world:has(e1, A))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
do CASE "the filip incident"
|
||||||
|
local world = jecs.World.new()
|
||||||
|
|
||||||
|
export type Iterator<T> = () -> (Entity, T?, T?)
|
||||||
|
export type Destructor = () -> ()
|
||||||
|
|
||||||
|
-- Helpers
|
||||||
|
|
||||||
|
type ValuesMap<T> = { [Entity]: T? }
|
||||||
|
type ChangeSet = { [Entity]: true? }
|
||||||
|
type ChangeSets = { [ChangeSet]: true? }
|
||||||
|
type ChangeSetsCache = {
|
||||||
|
Added: ChangeSets,
|
||||||
|
Changed: ChangeSets,
|
||||||
|
Removed: ChangeSets,
|
||||||
|
}
|
||||||
|
|
||||||
|
local cachedChangeSets = {}
|
||||||
|
local function getChangeSets(component): ChangeSetsCache
|
||||||
|
if cachedChangeSets[component] == nil then
|
||||||
|
local changeSetsAdded: ChangeSets = {}
|
||||||
|
local changeSetsChanged: ChangeSets = {}
|
||||||
|
local changeSetsRemoved: ChangeSets = {}
|
||||||
|
world:set(component, jecs.OnAdd, function(id)
|
||||||
|
for set in changeSetsAdded do
|
||||||
|
set[id] = true
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
world:set(component, jecs.OnSet, function(id)
|
||||||
|
for set in changeSetsChanged do
|
||||||
|
set[id] = true
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
world:set(component, jecs.OnRemove, function(id)
|
||||||
|
for set in changeSetsRemoved do
|
||||||
|
set[id] = true
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
cachedChangeSets[component] = {
|
||||||
|
Added = changeSetsAdded,
|
||||||
|
Changed = changeSetsChanged,
|
||||||
|
Removed = changeSetsRemoved,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
return cachedChangeSets[component]
|
||||||
|
end
|
||||||
|
|
||||||
|
local function ChangeTracker<T>(component): (Iterator<T>, Destructor)
|
||||||
|
local values: ValuesMap<T> = {}
|
||||||
|
local changeSet: ChangeSet = {}
|
||||||
|
|
||||||
|
for id in world:query(component) do
|
||||||
|
changeSet[id] = true
|
||||||
|
end
|
||||||
|
|
||||||
|
local changeSets = getChangeSets(component)
|
||||||
|
changeSets.Added[changeSet] = true
|
||||||
|
changeSets.Changed[changeSet] = true
|
||||||
|
changeSets.Removed[changeSet] = true
|
||||||
|
|
||||||
|
local id: Entity? = nil
|
||||||
|
local iter: Iterator<T> = function()
|
||||||
|
id = next(changeSet)
|
||||||
|
if id then
|
||||||
|
changeSet[id] = nil
|
||||||
|
local old: T? = values[id]
|
||||||
|
local new: T? = world:get(id, component)
|
||||||
|
if old ~= nil and new == nil then
|
||||||
|
-- Old value but no new value = removed
|
||||||
|
values[id] = nil
|
||||||
|
else
|
||||||
|
-- Old+new value or just new value = new becomes old
|
||||||
|
values[id] = new
|
||||||
|
end
|
||||||
|
return id, old, new
|
||||||
|
end
|
||||||
|
return nil :: any, nil, nil
|
||||||
|
end
|
||||||
|
|
||||||
|
local destroy: Destructor = function()
|
||||||
|
changeSets.Added[changeSet] = nil
|
||||||
|
changeSets.Changed[changeSet] = nil
|
||||||
|
changeSets.Removed[changeSet] = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
return iter, destroy
|
||||||
|
end
|
||||||
|
|
||||||
|
local Transform = world:component()
|
||||||
|
local iter, destroy = ChangeTracker(Transform)
|
||||||
|
|
||||||
|
local e1 = world:entity()
|
||||||
|
world:set(e1, Transform, {1,1})
|
||||||
|
local counter = 0
|
||||||
|
for _ in iter do
|
||||||
|
counter += 1
|
||||||
|
end
|
||||||
|
CHECK(counter == 1)
|
||||||
|
end
|
||||||
|
|
||||||
end)
|
end)
|
||||||
FINISH()
|
FINISH()
|
||||||
|
|
Loading…
Reference in a new issue