From add9ad39399a7c78780bd0849b44af08c9c434f7 Mon Sep 17 00:00:00 2001 From: Ukendio Date: Sat, 2 Aug 2025 06:17:35 +0200 Subject: [PATCH] Support setting signal on cached Relation --- jecs.luau | 26 ++++++++++++------- package.json | 2 +- test/tests.luau | 53 +++++++++++++++++++++++++++++++++------ wally.toml | 2 +- werewitch.luau | 66 ------------------------------------------------- 5 files changed, 64 insertions(+), 85 deletions(-) delete mode 100755 werewitch.luau diff --git a/jecs.luau b/jecs.luau index 37c550a..ce5f5ba 100755 --- a/jecs.luau +++ b/jecs.luau @@ -24,10 +24,10 @@ export type Archetype = { export type QueryInner = { compatible_archetypes: { Archetype }, - ids: { i53 }, - filter_with: { i53 }, - filter_without: { i53 }, - next: () -> (number, ...any), + ids: { Id }, + filter_with: { Id }, + filter_without: { Id }, + next: () -> (Entity, ...any), world: World, } @@ -54,6 +54,8 @@ export type Query = typeof(setmetatable( archetypes: (self: Query) -> { Archetype }, cached: (self: Query) -> Query, ids: { Id }, + patch: (self: Query, fn: (T...) -> (T...)) -> (), + view: (self: Query) -> View, -- world: World }, {} :: { @@ -68,6 +70,12 @@ export type Observer = { query: QueryInner, } + +export type observer = { + callback: (archetype: archetype) -> (), + query: query, +} + type archetype = { id: number, types: { i53 }, @@ -504,7 +512,7 @@ local function ecs_pair_second(world: world, e: i53) return ecs_get_alive(world, obj) end -local function query_match(query: QueryInner, archetype: archetype) +local function query_match(query: query, archetype: archetype) local columns_map = archetype.columns_map local with = query.filter_with @@ -526,7 +534,7 @@ local function query_match(query: QueryInner, archetype: archetype) return true end -local function find_observers(world: world, event: i53, component: i53): { Observer }? +local function find_observers(world: world, event: i53, component: i53): { observer }? local cache = world.observable[event] if not cache then return nil @@ -2615,7 +2623,7 @@ local function world_new() table.insert(listeners, existing_hook) end - local idr = world.component_index[component] + local idr = component_index[ECS_PAIR(component, EcsWildcard)] or component_index[component] if idr then idr.on_add = on_add else @@ -2650,7 +2658,7 @@ local function world_new() table.insert(listeners, existing_hook) end - local idr = world.component_index[component] + local idr = component_index[ECS_PAIR(component, EcsWildcard)] or component_index[component] if idr then idr.on_change = on_change else @@ -2681,7 +2689,7 @@ local function world_new() table.insert(listeners, existing_hook) end - local idr = world.component_index[component] + local idr = component_index[ECS_PAIR(component, EcsWildcard)] or component_index[component] if idr then idr.on_remove = on_remove else diff --git a/package.json b/package.json index 871da8e..d9f7e66 100755 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@rbxts/jecs", - "version": "0.9.0-rc.7", + "version": "0.9.0-rc.8", "description": "Stupidly fast Entity Component System", "main": "jecs.luau", "repository": { diff --git a/test/tests.luau b/test/tests.luau index e7c2bc1..c10c014 100755 --- a/test/tests.luau +++ b/test/tests.luau @@ -1064,40 +1064,77 @@ end) TEST("world:added", function() local world = jecs.world() - do CASE "Should work even if set after the component has been used" local A = world:component() - world:set(world:entity(), A, 2) local ran = false world:added(A, function() ran = true end) - local entity = world:entity() world:set(entity, A, 3) + CHECK(ran) + end + + + do CASE "Should work even if set after the pair has been used" + local A = world:component() + local B = world:component() + + world:set(world:entity(), A, 2) + world:set(world:entity(), pair(A, B), 2) + + world:added(A, function() + ran = true + end) + + local entity = world:entity() + world:set(entity, pair(A, B), 3) + CHECK(ran) + end + + do CASE "Should allow setting signal after Relation has been used as a component" + local A = world:component() + local B = world:component() + + world:add(world:entity(), A) + + world:added(A, function() + ran = true + end) + + world:add(world:entity(), pair(A, B)) + CHECK(ran) + end + + do CASE "Should invoke signal for the Relation being set as a key despite a pair with Relation having been cached" + local A = world:component() + local B = world:component() + + world:add(world:entity(), pair(A, B)) + + world:added(A, function() + ran = true + end) + + world:add(world:entity(), A) CHECK(ran) end do CASE "Should not override hook" local A = world:component() - local count = 1 local function counter() count += 1 end - world:set(A, jecs.OnAdd, counter) world:added(A, counter) world:set(world:entity(), A, false) CHECK(count == (1 + 2)) world:set(world:entity(), A, false) - CHECK(count == (1 + (2 * 2))) end - - end) TEST("world:range()", function() diff --git a/wally.toml b/wally.toml index 12df0ed..8331b79 100755 --- a/wally.toml +++ b/wally.toml @@ -1,6 +1,6 @@ [package] name = "ukendio/jecs" -version = "0.9.0-rc.7" +version = "0.9.0-rc.8" registry = "https://github.com/UpliftGames/wally-index" realm = "shared" license = "MIT" diff --git a/werewitch.luau b/werewitch.luau deleted file mode 100755 index 7c8d4dd..0000000 --- a/werewitch.luau +++ /dev/null @@ -1,66 +0,0 @@ -local jecs = require("@jecs") - -local world = jecs.world() -local pair = jecs.pair - -local IsA = world:entity() - -local traits = { - IsA = IsA -} - -world:set(IsA, jecs.OnAdd, function(component, id) - local second = jecs.pair_second(world, id) - assert(second ~= component, "circular") - - local is_tag = jecs.is_tag(world, second) - world:added(component, function(entity, _, value) - if is_tag then - world:add(entity, second) - else - world:set(entity, second, value) - end - end) - - world:removed(component, function(entity) - world:remove(entity, second) - end) - - if not is_tag then - world:changed(component, function(entity, _, value) - world:set(entity, second, value) - end) - end - - local r = jecs.record(world, second) :: jecs.Record - local archetype = r.archetype - if not archetype then - return - end - local types = archetype.types - - for _, id in types do - if jecs.is_tag(world, id) then - world:add(component, id) - else - local metadata = world:get(second, id) - if not world:has(component, id) then - world:set(component, id, metadata) - end - end - end - - -- jecs.bulk_insert(world, component, ids, values) -end) - -local Witch = world:entity() -local Werewolf = world:entity() - -local WereWitch = world:entity() -world:add(WereWitch, pair(IsA, Witch)) -world:add(WereWitch, pair(IsA, Werewolf)) - -local e = world:entity() -world:add(e, WereWitch) -print(world:has(e, pair(IsA, Witch))) -- false -print(world:has(e, Witch)) -- true