mirror of
https://github.com/Ukendio/jecs.git
synced 2025-04-24 17:10:03 +00:00
Change invocation points for hooks
This commit is contained in:
parent
79a4a6a0c4
commit
e073a570b7
5 changed files with 2449 additions and 489 deletions
49
benches/visual/remove.bench.luau
Normal file
49
benches/visual/remove.bench.luau
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
--!optimize 2
|
||||||
|
--!native
|
||||||
|
|
||||||
|
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||||
|
local Matter = require(ReplicatedStorage.DevPackages.Matter)
|
||||||
|
local ecr = require(ReplicatedStorage.DevPackages.ecr)
|
||||||
|
local jecs = require(ReplicatedStorage.Lib)
|
||||||
|
local pair = jecs.pair
|
||||||
|
local ecs = jecs.World.new()
|
||||||
|
local mirror = require(ReplicatedStorage.mirror)
|
||||||
|
local mcs = mirror.World.new()
|
||||||
|
|
||||||
|
local C1 = ecs:component()
|
||||||
|
local C2 = ecs:entity()
|
||||||
|
ecs:add(C2, pair(jecs.OnDeleteTarget, jecs.Delete))
|
||||||
|
local C3 = ecs:entity()
|
||||||
|
ecs:add(C3, pair(jecs.OnDeleteTarget, jecs.Delete))
|
||||||
|
local C4 = ecs:entity()
|
||||||
|
ecs:add(C4, pair(jecs.OnDeleteTarget, jecs.Delete))
|
||||||
|
local E1 = mcs:component()
|
||||||
|
local E2 = mcs:entity()
|
||||||
|
mcs:add(E2, pair(jecs.OnDeleteTarget, jecs.Delete))
|
||||||
|
local E3 = mcs:entity()
|
||||||
|
mcs:add(E3, pair(jecs.OnDeleteTarget, jecs.Delete))
|
||||||
|
local E4 = mcs:entity()
|
||||||
|
mcs:add(E4, pair(jecs.OnDeleteTarget, jecs.Delete))
|
||||||
|
|
||||||
|
return {
|
||||||
|
ParameterGenerator = function()
|
||||||
|
end,
|
||||||
|
|
||||||
|
Functions = {
|
||||||
|
Mirror = function()
|
||||||
|
local m = mcs:entity()
|
||||||
|
for i = 1, 100 do
|
||||||
|
mcs:add(m, E3)
|
||||||
|
mcs:remove(m, E3)
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
|
||||||
|
Jecs = function()
|
||||||
|
local j = ecs:entity()
|
||||||
|
for i = 1, 100 do
|
||||||
|
ecs:add(j, C3)
|
||||||
|
ecs:remove(j, C3)
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
},
|
||||||
|
}
|
54
jecs.luau
54
jecs.luau
|
@ -860,16 +860,16 @@ local function world_set(world: World, entity: i53, id: i53, data: unknown): ()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local on_add = idr_hooks.on_add
|
|
||||||
if on_add then
|
|
||||||
on_add(entity)
|
|
||||||
end
|
|
||||||
|
|
||||||
local tr = to.records[id]
|
local tr = to.records[id]
|
||||||
local column = to.columns[tr]
|
local column = to.columns[tr]
|
||||||
|
|
||||||
column[record.row] = data
|
column[record.row] = data
|
||||||
|
|
||||||
|
local on_add = idr_hooks.on_add
|
||||||
|
if on_add then
|
||||||
|
on_add(entity)
|
||||||
|
end
|
||||||
|
|
||||||
local on_set = idr_hooks.on_set
|
local on_set = idr_hooks.on_set
|
||||||
if on_set then
|
if on_set then
|
||||||
on_set(entity, data)
|
on_set(entity, data)
|
||||||
|
@ -899,15 +899,16 @@ local function world_remove(world: World, entity: i53, id: i53)
|
||||||
if not from then
|
if not from then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
local to = archetype_traverse_remove(world, id, from)
|
|
||||||
|
|
||||||
if from ~= to then
|
if from.records[id] then
|
||||||
local idr = world.component_index[id]
|
local idr = world.component_index[id]
|
||||||
local on_remove = idr.hooks.on_remove
|
local on_remove = idr.hooks.on_remove
|
||||||
if on_remove then
|
if on_remove then
|
||||||
on_remove(entity)
|
on_remove(entity)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local to = archetype_traverse_remove(world, id, record.archetype)
|
||||||
|
|
||||||
entity_move(entity_index, entity, record, to)
|
entity_move(entity_index, entity, record, to)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -2413,51 +2414,44 @@ export type World = {
|
||||||
observable: any,
|
observable: any,
|
||||||
|
|
||||||
--- Creates a new entity
|
--- Creates a new entity
|
||||||
entity: (self: World) -> Entity,
|
entity: (self: World, id: Entity?) -> 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>(self: 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), 0)`, you will obtain the parent entity.
|
--- `world:target(id, ChildOf(parent), 0)`, you will obtain the parent entity.
|
||||||
target: <T, U>(self: World, id: Entity<T>, relation: Entity<U>, index: number?) -> Entity?,
|
target: (self: World, id: Entity, relation: Id, index: number?) -> 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>(self: World, id: Entity<T>) -> (),
|
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, U>(self: World, id: Entity<T>, component: Id<U>) -> (),
|
add: <T>(self: World, id: Entity, component: Id) -> (),
|
||||||
--- Assigns a value to a component on the given entity
|
--- Assigns a value to a component on the given entity
|
||||||
set: <T, U>(self: World, id: Entity<T>, component: Id<U>, data: U) -> (),
|
set: <T>(self: World, id: Entity, component: Id<T>, data: T) -> (),
|
||||||
|
|
||||||
cleanup: (self: World) -> (),
|
cleanup: (self: World) -> (),
|
||||||
-- Clears an entity from the world
|
-- Clears an entity from the world
|
||||||
clear: <T>(self: World, id: Entity<T>) -> (),
|
clear: (self: World, id: Entity) -> (),
|
||||||
--- Removes a component from the given entity
|
--- Removes a component from the given entity
|
||||||
remove: <T, U>(self: World, id: Entity<T>, component: Id<U>) -> (),
|
remove: (self: World, id: Entity, component: Id) -> (),
|
||||||
--- 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: (<T, A>(self: World, id: Entity<T>, Id<A>) -> A?)
|
get: (<A>(self: World, id: Entity, Id<A>) -> A?)
|
||||||
& (<T, A, B>(self: World, id: Entity<T>, Id<A>, Id<B>) -> (A?, B?))
|
& (<A, B>(self: World, id: Entity, Id<A>, Id<B>) -> (A?, B?))
|
||||||
& (<T, A, B, C>(self: World, id: Entity<T>, Id<A>, Id<B>, Id<C>) -> (A?, B?, C?))
|
& (<A, B, C>(self: World, id: Entity, Id<A>, Id<B>, Id<C>) -> (A?, B?, C?))
|
||||||
& <T, A, B, C, D>(self: World, id: Entity<T>, Id<A>, Id<B>, Id<C>, Id<D>) -> (A?, B?, C?, D?),
|
& <A, B, C, D>(self: World, id: Entity, Id<A>, Id<B>, Id<C>, Id<D>) -> (A?, B?, C?, D?),
|
||||||
|
|
||||||
--- Returns whether the entity has the ID.
|
--- Returns whether the entity has the ID.
|
||||||
has: (<T, U>(self: World, entity: Entity<T>, ...Id<U>) -> boolean)
|
has: (self: World, entity: Entity, ...Id) -> boolean,
|
||||||
& (<T, U, V>(self: World, entity: Entity<T>, Id<U>, Id<V>) -> boolean)
|
|
||||||
& (<T, U, V, W>(self: World, entity: Entity<T>, Id<U>, Id<V>, Id<W>) -> boolean)
|
|
||||||
& (<T, U, V, W, X>(self: World, entity: Entity<T>, Id<U>, Id<V>, Id<W>, Id<X>) -> boolean)
|
|
||||||
& (<T, U, V, W, X, Y>(self: World, entity: Entity<T>, Id<U>, Id<V>, Id<W>, Id<X>, Id<Y>) -> boolean)
|
|
||||||
& (<T, U, V, W, X, Y, Z>(self: World, entity: Entity<T>, Id<U>, Id<V>, Id<W>, Id<X>, Id<Y>, Id<Z>) -> boolean)
|
|
||||||
& (<T, U, V, W, X, Y, Z, A>(self: World, entity: Entity<T>, Id<U>, Id<V>, Id<W>, Id<X>, Id<Y>, Id<Z>, Id<A>) -> boolean)
|
|
||||||
& (<T, U, V, W, X, Y, Z, A>(self: World, entity: Entity<T>, Id<U>, Id<V>, Id<W>, Id<X>, Id<Y>, Id<Z>, Id<A>, ...unknown) -> boolean),
|
|
||||||
|
|
||||||
--- Get parent (target of ChildOf relationship) for entity. If there is no ChildOf relationship pair, it will return nil.
|
--- Get parent (target of ChildOf relationship) for entity. If there is no ChildOf relationship pair, it will return nil.
|
||||||
parent: <T>(self: World, entity: Entity<T>) -> Entity,
|
parent:(self: World, entity: Entity) -> Entity,
|
||||||
|
|
||||||
--- Checks if the world contains the given entity
|
--- Checks if the world contains the given entity
|
||||||
contains: <T>(self: World, entity: Entity<T>) -> boolean,
|
contains:(self: World, entity: Entity) -> boolean,
|
||||||
|
|
||||||
each: <T>(self: World, id: Id<T>) -> () -> Entity,
|
each: (self: World, id: Id) -> () -> Entity,
|
||||||
|
|
||||||
children: <T>(self: World, id: Id<T>) -> () -> Entity,
|
children: (self: World, id: Id) -> () -> Entity,
|
||||||
|
|
||||||
--- Searches the world for entities that match a given query
|
--- Searches the world for entities that match a given query
|
||||||
query: (<A>(World, Id<A>) -> Query<A>)
|
query: (<A>(World, Id<A>) -> Query<A>)
|
||||||
|
|
2765
mirror.luau
2765
mirror.luau
File diff suppressed because it is too large
Load diff
|
@ -124,15 +124,15 @@ TEST("#repro", function()
|
||||||
local tgts = {}
|
local tgts = {}
|
||||||
local pairwildcard = pair(relation, jecs.Wildcard)
|
local pairwildcard = pair(relation, jecs.Wildcard)
|
||||||
for _, archetype in world:query(pairwildcard):archetypes() do
|
for _, archetype in world:query(pairwildcard):archetypes() do
|
||||||
local tr = archetype.records[pairwildcard]
|
local tr = archetype.records[pairwildcard]
|
||||||
local count = archetype.counts[pairwildcard]
|
local count = archetype.counts[pairwildcard]
|
||||||
local types = archetype.types
|
local types = archetype.types
|
||||||
for _, entity in archetype.entities do
|
for _, entity in archetype.entities do
|
||||||
for i = 0, count - 1 do
|
for i = 0, count - 1 do
|
||||||
local tgt = jecs.pair_second(world, types[i + tr])
|
local tgt = jecs.pair_second(world, types[i + tr])
|
||||||
table.insert(tgts, tgt)
|
table.insert(tgts, tgt)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return tgts
|
return tgts
|
||||||
end
|
end
|
||||||
|
@ -148,22 +148,24 @@ TEST("#repro", function()
|
||||||
local e1 = world:entity()
|
local e1 = world:entity()
|
||||||
local e2 = world:entity()
|
local e2 = world:entity()
|
||||||
local e3 = world:entity()
|
local e3 = world:entity()
|
||||||
print(e1, e2, e3)
|
|
||||||
setAttacksAndEats(e3, e1)
|
setAttacksAndEats(e3, e1)
|
||||||
setAttacksAndEats(e3, e2)
|
setAttacksAndEats(e3, e2)
|
||||||
setAttacksAndEats(e1, e2)
|
setAttacksAndEats(e1, e2)
|
||||||
print("---------------- delete e2 ---------------")
|
|
||||||
local d = dwi(world)
|
local d = dwi(world)
|
||||||
for archetype_id in world.component_index[pair(jecs.Wildcard, e2)].cache do
|
|
||||||
local archetype = world.archetypes[archetype_id].type
|
|
||||||
testkit.print(archetype)
|
|
||||||
end
|
|
||||||
world:delete(e2)
|
world:delete(e2)
|
||||||
print("-----------------------------")
|
local types1 = { pair(Attacks, e1), pair(Eats, e1) }
|
||||||
testkit.print(d.tbl(e1).types)
|
table.sort(types1)
|
||||||
-- testkit.print(d.tbl(e3).types)
|
|
||||||
-- testkit.print(getTargets(Attacks))
|
|
||||||
-- testkit.print(getTargets(Eats))
|
CHECK(d.tbl(e1).type == "")
|
||||||
|
CHECK(d.tbl(e3).type == table.concat(types1, "_"))
|
||||||
|
|
||||||
|
for _, entity in getTargets(Attacks) do
|
||||||
|
CHECK(entity == e1)
|
||||||
|
end
|
||||||
|
for _, entity in getTargets(Eats) do
|
||||||
|
CHECK(entity == e1)
|
||||||
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
TEST("archetype", function()
|
TEST("archetype", function()
|
||||||
|
@ -235,7 +237,23 @@ TEST("world:cleanup()", function()
|
||||||
CHECK(#archetype_index["1_2_3"].entities == 1)
|
CHECK(#archetype_index["1_2_3"].entities == 1)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
local pe = require("@tools/entity_visualiser").prettify
|
||||||
|
local lifetime_tracker_add = require("@tools/lifetime_tracker")
|
||||||
|
|
||||||
TEST("world:entity()", function()
|
TEST("world:entity()", function()
|
||||||
|
do CASE "ensure id"
|
||||||
|
local w = world_new()
|
||||||
|
w = lifetime_tracker_add(w, {padding_enabled=false})
|
||||||
|
local id = w:entity()
|
||||||
|
CHECK(id == w:entity(id))
|
||||||
|
CHECK(w:entity(999 :: any) == 999 :: any)
|
||||||
|
w:print_snapshot()
|
||||||
|
local id1 = w:entity(999)
|
||||||
|
CHECK(w:contains(999))
|
||||||
|
CHECK(not w:contains(998))
|
||||||
|
print(w:entity(), "newest id after 999")
|
||||||
|
end
|
||||||
|
|
||||||
do
|
do
|
||||||
CASE("unique IDs")
|
CASE("unique IDs")
|
||||||
local world = jecs.World.new()
|
local world = jecs.World.new()
|
||||||
|
@ -1566,13 +1584,14 @@ TEST("repro", function()
|
||||||
do CASE "#1"
|
do CASE "#1"
|
||||||
local world = world_new()
|
local world = world_new()
|
||||||
local reproEntity = world:component()
|
local reproEntity = world:component()
|
||||||
local components = { Cooldown = world:component() :: jecs.Id<number> }
|
local components = { Cooldown = world:component() :: jecs.Entity<number> }
|
||||||
world:set(reproEntity, components.Cooldown, 2)
|
world:set(reproEntity, components.Cooldown, 2)
|
||||||
|
|
||||||
local function updateCooldowns(dt: number)
|
local function updateCooldowns(dt: number)
|
||||||
local toRemove = {}
|
local toRemove = {}
|
||||||
|
|
||||||
for id, cooldown in world:query(components.Cooldown):iter() do
|
local it = world:query(components.Cooldown):iter()
|
||||||
|
for id, cooldown in it do
|
||||||
cooldown -= dt
|
cooldown -= dt
|
||||||
|
|
||||||
if cooldown <= 0 then
|
if cooldown <= 0 then
|
||||||
|
|
|
@ -45,7 +45,10 @@ local function lifetime_tracker_add(world: jecs.World, opt)
|
||||||
padding_enabled = opt.padding_enabled
|
padding_enabled = opt.padding_enabled
|
||||||
|
|
||||||
local world_entity = world.entity
|
local world_entity = world.entity
|
||||||
w.entity = function(self)
|
w.entity = function(self, entity)
|
||||||
|
if entity then
|
||||||
|
return world_entity(world, entity)
|
||||||
|
end
|
||||||
local will_recycle = entity_index.max_id ~= entity_index.alive_count
|
local will_recycle = entity_index.max_id ~= entity_index.alive_count
|
||||||
local e = world_entity(world)
|
local e = world_entity(world)
|
||||||
if will_recycle then
|
if will_recycle then
|
||||||
|
@ -108,7 +111,7 @@ local function lifetime_tracker_add(world: jecs.World, opt)
|
||||||
local entity = dense_array[i]
|
local entity = dense_array[i]
|
||||||
local id = ECS_ID(entity)
|
local id = ECS_ID(entity)
|
||||||
local status = "alive"
|
local status = "alive"
|
||||||
if id > alive_count then
|
if not world:contains(entity) then
|
||||||
status = "dead"
|
status = "dead"
|
||||||
end
|
end
|
||||||
data[id] = status
|
data[id] = status
|
||||||
|
|
Loading…
Reference in a new issue