diff --git a/packages/ecs/Makefile b/packages/ecs/Makefile index 7f06c530..ce863f6f 100644 --- a/packages/ecs/Makefile +++ b/packages/ecs/Makefile @@ -1,8 +1,6 @@ SRC = wasm/SparseArray.cpp\ wasm/Entity.cpp\ wasm/Utils.cpp\ - wasm/Zipper.cpp\ - wasm/IndexedZipper.cpp\ wasm/Registry.cpp NAME := libecs diff --git a/packages/ecs/lib/libecs.d.ts b/packages/ecs/lib/libecs.d.ts index 8de38659..6839d53d 100644 --- a/packages/ecs/lib/libecs.d.ts +++ b/packages/ecs/lib/libecs.d.ts @@ -15,7 +15,6 @@ declare namespace RuntimeExports { interface WasmModule { } -type EmbindString = ArrayBuffer|Uint8Array|Uint8ClampedArray|Int8Array|string; export interface ClassHandle { isAliasOf(other: ClassHandle): boolean; delete(): void; @@ -51,50 +50,24 @@ export interface Entity extends ClassHandle { getId(): number; } -export interface MapStringSparseArray extends ClassHandle { - keys(): VectorString; - size(): number; - get(_0: EmbindString): SparseArray | undefined; - set(_0: EmbindString, _1: SparseArray | null): void; -} - -export interface VectorString extends ClassHandle { - size(): number; - get(_0: number): EmbindString | undefined; - push_back(_0: EmbindString): void; - resize(_0: number, _1: EmbindString): void; - set(_0: number, _1: EmbindString): boolean; -} - -export interface Zipper extends ClassHandle { - next(): any; - getValue(): any; -} - -export interface IndexedZipper extends ClassHandle { - next(): any; - getValue(): any; -} - export interface Registry extends ClassHandle { + registerComponent(_0: {name: string, [key: string]: any}): SparseArray; + getComponentsConst(_0: {name: string, [key: string]: any}): SparseArray; + getComponents(_0: {name: string, [key: string]: any}): SparseArray; spawnEntity(): Entity; killEntity(_0: Entity): void; clearEntities(): void; + removeComponent(_0: Entity, _1: {name: string, [key: string]: any}): void; + addSystem(_0: (registry: Registry) => void): void; runSystems(): void; clearSystems(): void; entityFromIndex(_0: number): Entity; removeSystem(_0: number): void; maxEntities(): number; - registerComponent(_0: any): SparseArray; - getComponentsConst(_0: any): SparseArray; - getComponents(_0: any): SparseArray; - getEntityComponentConst(_0: Entity, _1: any): any | undefined; - getEntityComponent(_0: Entity, _1: any): any | undefined; - addComponent(_0: Entity, _1: any): any | undefined; - removeComponent(_0: Entity, _1: any): void; - addSystem(_0: any): void; - getZipper(_0: any): Zipper; - getIndexedZipper(_0: any): IndexedZipper; + getEntityComponentConst(_0: Entity, _1: {name: string, [key: string]: any}): any | undefined; + getEntityComponent(_0: Entity, _1: {name: string, [key: string]: any}): any | undefined; + addComponent(_0: Entity, _1: {name: string, [key: string]: any}): any | undefined; + getZipper(_0: any): any; } interface EmbindModule { @@ -107,18 +80,6 @@ interface EmbindModule { Entity: { new(_0: number): Entity; }; - MapStringSparseArray: { - new(): MapStringSparseArray; - }; - VectorString: { - new(): VectorString; - }; - Zipper: { - new(_0: MapStringSparseArray): Zipper; - }; - IndexedZipper: { - new(_0: MapStringSparseArray): IndexedZipper; - }; Registry: { new(): Registry; }; diff --git a/packages/ecs/src/ecs-library.ts b/packages/ecs/src/ecs-library.ts index f7504ac0..f38588cf 100644 --- a/packages/ecs/src/ecs-library.ts +++ b/packages/ecs/src/ecs-library.ts @@ -1,9 +1,12 @@ import { type AssetManagerLibrary } from "@nanoforge/asset-manager"; import { BaseComponentSystemLibrary, type InitContext } from "@nanoforge/common"; -import type { Entity, MainModule, Registry, SparseArray, Zipper } from "../lib"; +import type { Entity, MainModule, Registry, SparseArray } from "../lib"; import { Module } from "../lib"; +export type Component = { name: string; [key: string]: any }; +export type System = (registry: Registry) => void; + export class ECSLibrary extends BaseComponentSystemLibrary { private module: MainModule; private registry: Registry; @@ -29,7 +32,7 @@ export class ECSLibrary extends BaseComponentSystemLibrary { return Promise.resolve(); } - addComponent(entity: Entity, component: any): void { + addComponent(entity: Entity, component: Component): void { this.registry.addComponent(entity, component); } @@ -37,19 +40,19 @@ export class ECSLibrary extends BaseComponentSystemLibrary { return this.registry.spawnEntity(); } - getComponents(component: any): SparseArray { + getComponents(component: Component): SparseArray { return this.registry.getComponents(component); } - removeComponent(entity: Entity, component: any): void { + removeComponent(entity: Entity, component: Component): void { this.registry.removeComponent(entity, component); } - getEntityComponent(entity: Entity, component: any): any | undefined { + getEntityComponent(entity: Entity, component: Component): Component | undefined { return this.registry.getEntityComponent(entity, component); } - getEntityComponentConst(entity: Entity, component: any): any | undefined { + getEntityComponentConst(entity: Entity, component: Component): Component | undefined { return this.registry.getEntityComponentConst(entity, component); } @@ -85,15 +88,11 @@ export class ECSLibrary extends BaseComponentSystemLibrary { return this.registry.maxEntities(); } - addSystem(system: any): void { + addSystem(system: System): void { this.registry.addSystem(system); } - getZipper(types: [any]): Zipper { + getZipper(types: [Component]): [any] { return this.registry.getZipper(types); } - - getIndexedZipper(types: [any]): Zipper { - return this.registry.getIndexedZipper(types); - } } diff --git a/packages/ecs/test/ecs-library.spec.ts b/packages/ecs/test/ecs-library.spec.ts index aff0a937..daf7b53b 100644 --- a/packages/ecs/test/ecs-library.spec.ts +++ b/packages/ecs/test/ecs-library.spec.ts @@ -4,6 +4,7 @@ import { EditableLibraryManager } from "@nanoforge/core/src/common/library/manag import { ECSLibrary } from "@nanoforge/ecs/src/ecs-library"; class Position { + name: string = "Position"; constructor( public x: number, public y: number, diff --git a/packages/ecs/test/wasm/IndexedZipper.spec.ts b/packages/ecs/test/wasm/IndexedZipper.spec.ts deleted file mode 100644 index 36f4991e..00000000 --- a/packages/ecs/test/wasm/IndexedZipper.spec.ts +++ /dev/null @@ -1,135 +0,0 @@ -import Module from "../../lib/libecs.js"; - -class Velocity { - x: number; - y: number; - - constructor(x: number, y: number) { - this.x = x; - this.y = y; - } -} - -class Position { - x: number; - y: number; - - constructor(x: number, y: number) { - this.x = x; - this.y = y; - } -} - -describe("IndexedZipper", () => { - test("basic instantation", async () => { - const m = await Module(); - const v = new m.MapStringSparseArray(); - - const zip = new m.IndexedZipper(v); - - expect(zip).toBeDefined(); - expect(zip.getValue()).toBeUndefined(); - }); - - test("single simple sparse array instantation", async () => { - const m = await Module(); - const r = new m.Registry(); - expect(r).toBeDefined(); - - for (let i = 0; i < 5; i++) { - const e = r.spawnEntity(); - r.addComponent(e, new Velocity(i, i)); - } - - const zip = r.getIndexedZipper([Velocity]); - expect(zip).toBeDefined(); - - for (let i = 0; i < 5; i++, zip.next()) { - expect(zip.getValue()).toStrictEqual({ entity: i, Velocity: new Velocity(i, i) }); - } - expect(zip.getValue()).toBeUndefined(); - }); - - test("single complex sparse array instantation", async () => { - const m = await Module(); - const r = new m.Registry(); - expect(r).toBeDefined(); - - for (let i = 0; i < 5; i++) { - const e = new m.Entity(i * 5); - r.addComponent(e, new Velocity(i, i)); - } - - const zip = r.getIndexedZipper([Velocity]); - expect(zip).toBeDefined(); - - for (let i = 0; i < 5; i++) { - expect(zip.getValue()).toStrictEqual({ entity: i * 5, Velocity: new Velocity(i, i) }); - zip.next(); - } - expect(zip.getValue()).toBeUndefined(); - }); - - test("multiple complex sparse array instantation", async () => { - const m = await Module(); - const r = new m.Registry(); - expect(r).toBeDefined(); - - for (let i = 0; i < 20; i++) { - const e = r.spawnEntity(); - if (i % 5 === 0) r.addComponent(e, new Velocity(0, i)); - if (i % 3 === 0) r.addComponent(e, new Position(i, 0)); - } - - const zip = r.getIndexedZipper([Velocity, Position]); - expect(zip).toBeDefined(); - - for (let i = 0; i < 20; i++) { - if (i % 3 === 0 && i % 5 === 0) { - expect(zip.getValue()).toStrictEqual({ - entity: i, - Velocity: new Velocity(0, i), - Position: new Position(i, 0), - }); - zip.next(); - } - } - expect(zip.getValue()).toBeUndefined(); - }); - - test("simple indexed zipper modification", async () => { - const m = await Module(); - const r = new m.Registry(); - expect(r).toBeDefined(); - - for (let i = 0; i < 20; i++) { - const e = r.spawnEntity(); - if (i % 5 === 0) { - r.addComponent(e, new Velocity(0, i)); - } - } - - let zip = r.getIndexedZipper([Velocity]); - expect(zip).toBeDefined(); - - for (let i = 0; i < 20; i++) { - if (i % 5 === 0) { - const vel = zip.getValue()["Velocity"]; - vel.y *= 2; - zip.next(); - } - } - - zip = r.getIndexedZipper([Velocity]); - for (let i = 0; i < 20; i++) { - if (i % 5 === 0) { - expect(zip.getValue()).toStrictEqual({ - entity: i, - Velocity: new Velocity(0, i * 2), - }); - zip.next(); - } - } - expect(zip.getValue()).toBeUndefined(); - }); -}); diff --git a/packages/ecs/test/wasm/Registry.spec.ts b/packages/ecs/test/wasm/Registry.spec.ts index 10f36a60..a5edffaa 100644 --- a/packages/ecs/test/wasm/Registry.spec.ts +++ b/packages/ecs/test/wasm/Registry.spec.ts @@ -1,6 +1,7 @@ import Module from "../../lib/libecs.js"; class Velocity { + name: string = "Velocity"; x: number; y: number; @@ -11,6 +12,7 @@ class Velocity { } class Position { + name: string = "Position"; x: number; y: number; diff --git a/packages/ecs/test/wasm/Zipper.spec.ts b/packages/ecs/test/wasm/Zipper.spec.ts index 151dbb5f..f200b1fd 100644 --- a/packages/ecs/test/wasm/Zipper.spec.ts +++ b/packages/ecs/test/wasm/Zipper.spec.ts @@ -1,6 +1,7 @@ import Module from "../../lib/libecs.js"; class Velocity { + name: string = "Velocity"; x: number; y: number; @@ -11,6 +12,7 @@ class Velocity { } class Position { + name: string = "Position"; x: number; y: number; @@ -21,16 +23,6 @@ class Position { } describe("Zipper", () => { - test("basic instantation", async () => { - const m = await Module(); - const v = new m.MapStringSparseArray(); - - const zip = new m.Zipper(v); - - expect(zip).toBeDefined(); - expect(zip.getValue()).toBeUndefined(); - }); - test("single simple sparse array instantation", async () => { const m = await Module(); const r = new m.Registry(); @@ -42,12 +34,15 @@ describe("Zipper", () => { } const zip = r.getZipper([Velocity]); - expect(zip).toBeDefined(); - for (let i = 0; i < 5; i++, zip.next()) { - expect(zip.getValue()).toStrictEqual({ Velocity: new Velocity(i, i) }); - } - expect(zip.getValue()).toBeUndefined(); + expect(zip).toBeDefined(); + expect(zip).toStrictEqual([ + { Velocity: new Velocity(0, 0) }, + { Velocity: new Velocity(1, 1) }, + { Velocity: new Velocity(2, 2) }, + { Velocity: new Velocity(3, 3) }, + { Velocity: new Velocity(4, 4) }, + ]); }); test("single complex sparse array instantation", async () => { @@ -63,11 +58,11 @@ describe("Zipper", () => { const zip = r.getZipper([Velocity]); expect(zip).toBeDefined(); - for (let i = 0; i < 5; i++) { - expect(zip.getValue()).toStrictEqual({ Velocity: new Velocity(i, i) }); - zip.next(); - } - expect(zip.getValue()).toBeUndefined(); + expect(zip[0]).toStrictEqual({ Velocity: new Velocity(0, 0) }); + expect(zip[5]).toStrictEqual({ Velocity: new Velocity(1, 1) }); + expect(zip[10]).toStrictEqual({ Velocity: new Velocity(2, 2) }); + expect(zip[15]).toStrictEqual({ Velocity: new Velocity(3, 3) }); + expect(zip[20]).toStrictEqual({ Velocity: new Velocity(4, 4) }); }); test("multiple complex sparse array instantation", async () => { @@ -77,12 +72,8 @@ describe("Zipper", () => { for (let i = 0; i < 20; i++) { const e = r.spawnEntity(); - if (i % 5 === 0) { - r.addComponent(e, new Velocity(0, i)); - } - if (i % 3 === 0) { - r.addComponent(e, new Position(i, 0)); - } + if (i % 5 === 0) r.addComponent(e, new Velocity(0, i)); + if (i % 3 === 0) r.addComponent(e, new Position(i, 0)); } const zip = r.getZipper([Velocity, Position]); @@ -90,17 +81,15 @@ describe("Zipper", () => { for (let i = 0; i < 20; i++) { if (i % 3 === 0 && i % 5 === 0) { - expect(zip.getValue()).toStrictEqual({ + expect(zip[i]).toStrictEqual({ Velocity: new Velocity(0, i), Position: new Position(i, 0), }); - zip.next(); } } - expect(zip.getValue()).toBeUndefined(); }); - test("simple zipper modification", async () => { + test("simple indexed zipper modification", async () => { const m = await Module(); const r = new m.Registry(); expect(r).toBeDefined(); @@ -117,21 +106,18 @@ describe("Zipper", () => { for (let i = 0; i < 20; i++) { if (i % 5 === 0) { - const vel = zip.getValue()["Velocity"]; + const vel = zip[i]["Velocity"]; vel.y *= 2; - zip.next(); } } zip = r.getZipper([Velocity]); for (let i = 0; i < 20; i++) { if (i % 5 === 0) { - expect(zip.getValue()).toStrictEqual({ + expect(zip[i]).toStrictEqual({ Velocity: new Velocity(0, i * 2), }); - zip.next(); } } - expect(zip.getValue()).toBeUndefined(); }); }); diff --git a/packages/ecs/wasm/IndexedZipper.cpp b/packages/ecs/wasm/IndexedZipper.cpp deleted file mode 100644 index 48729991..00000000 --- a/packages/ecs/wasm/IndexedZipper.cpp +++ /dev/null @@ -1,27 +0,0 @@ -/*⠀ ⠀⠀ ⠀⠀⠀⠀⢀⣀⣀⣀⣀⡀⠀⠀⠀⠀⠀⠀⠀ -**⠀⠀ ⠀⢀⣠⣾⡿⠿⠛⠛⠛⠛⠿⢿⣷⣄⡀⠀⠀⠀ -** _ __ ______ ⠀ ⠀ ⣰⣿⠛⠁⠀⠀⠀⠀⠀⠀⠀⠀⠈⠛⣿⣆⠀⠀ -** / | / /___ _____ ____ / ____/___ _________ ____ ⠀ ⣾⡿⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⢿⣷⠀ -** / |/ / __ `/ __ \/ __ \/ /_ / __ \/ ___/ __ `/ _ \ ⢰⣿⠃⠀⣤⣤⣤⣤⣤⣤⣤⣤⣤⣤⠤⠀⠀⠘⣿⡆ -** / /| / /_/ / / / / /_/ / __/ / /_/ / / / /_/ / __/ ⢸⣿⠀⠀⠀⠉⠛⠛⢻⣿⣿⣿⠉⠀⠀⠀⠀⠀⣿⡇ -** /_/ |_/\__,_/_/ /_/\____/_/ \____/_/ \__, /\___/ ⠸⣿⡄⠀⠀⠀⠀⣠⣾⣿⣿⣿⣤⠀⠀⠀⠀⢠⣿⠇ -** /____/ ⠀ ⢿⣷⡀⠀⠀⠀⠉⠁⠀⠀⠈⠉⠀⠀⠀⢀⣾⡿⠀ -** ⠀⠀⠹⣿⣤⡀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣤⣿⠏⠀⠀ -** 2025 ⠀⠀⠀⠈⠙⢿⣷⣶⣤⣤⣤⣤⣶⣾⡿⠋⠁⠀⠀⠀ -**⠀ ⠀⠀⠀⠀⠀⠀⠈⠉⠉⠉⠉⠁⠀⠀⠀⠀⠀⠀⠀ -*/ - -#include -#include - -#include "IndexedZipper.hpp" - -namespace nfo { - EMSCRIPTEN_BINDINGS(IndexedZipper) - { - emscripten::class_("IndexedZipper") - .constructor *> &>() - .function("next", &IndexedZipper::next) - .function("getValue", &IndexedZipper::get_value); - } -} // namespace nfo diff --git a/packages/ecs/wasm/IndexedZipper.hpp b/packages/ecs/wasm/IndexedZipper.hpp deleted file mode 100644 index 2fc9cea8..00000000 --- a/packages/ecs/wasm/IndexedZipper.hpp +++ /dev/null @@ -1,76 +0,0 @@ -/*⠀ ⠀⠀ ⠀⠀⠀⠀⢀⣀⣀⣀⣀⡀⠀⠀⠀⠀⠀⠀⠀ -**⠀⠀ ⠀⢀⣠⣾⡿⠿⠛⠛⠛⠛⠿⢿⣷⣄⡀⠀⠀⠀ -** _ __ ______ ⠀ ⠀ ⣰⣿⠛⠁⠀⠀⠀⠀⠀⠀⠀⠀⠈⠛⣿⣆⠀⠀ -** / | / /___ _____ ____ / ____/___ _________ ____ ⠀ ⣾⡿⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⢿⣷⠀ -** / |/ / __ `/ __ \/ __ \/ /_ / __ \/ ___/ __ `/ _ \ ⢰⣿⠃⠀⣤⣤⣤⣤⣤⣤⣤⣤⣤⣤⠤⠀⠀⠘⣿⡆ -** / /| / /_/ / / / / /_/ / __/ / /_/ / / / /_/ / __/ ⢸⣿⠀⠀⠀⠉⠛⠛⢻⣿⣿⣿⠉⠀⠀⠀⠀⠀⣿⡇ -** /_/ |_/\__,_/_/ /_/\____/_/ \____/_/ \__, /\___/ ⠸⣿⡄⠀⠀⠀⠀⣠⣾⣿⣿⣿⣤⠀⠀⠀⠀⢠⣿⠇ -** /____/ ⠀ ⢿⣷⡀⠀⠀⠀⠉⠁⠀⠀⠈⠉⠀⠀⠀⢀⣾⡿⠀ -** ⠀⠀⠹⣿⣤⡀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣤⣿⠏⠀⠀ -** 2025 ⠀⠀⠀⠈⠙⢿⣷⣶⣤⣤⣤⣤⣶⣾⡿⠋⠁⠀⠀⠀ -**⠀ ⠀⠀⠀⠀⠀⠀⠈⠉⠉⠉⠉⠁⠀⠀⠀⠀⠀⠀⠀ -*/ - -#pragma once - -#include -#include - -#include "SparseArray.hpp" -#include "Utils.hpp" - -namespace nfo { - class IndexedZipper { - public: - explicit IndexedZipper(const std::map *> &arrays) : _arrays(arrays), _max(0), _idx(0) - { - _max = arrays.empty() ? 0 : arrays.begin()->second->size(); - for (SparseArray *&arr : _arrays | std::views::values) { - _max = (std::min)(arr->size(), _max); - } - if (_idx < _max && !all_set()) - incr(); - } - - [[nodiscard]] emscripten::val get_value() const - { - if (_idx >= _max) - return emscripten::val::undefined(); - - emscripten::val res = emscripten::val::object(); - for (SparseArray *const &arr : _arrays | std::views::values) { - res.set(get_js_class_name((*arr)[_idx].value()), (*arr)[_idx].value_or(emscripten::val::undefined())); - } - res.set("entity", _idx); - return res; - } - - emscripten::val next() - { - incr(); - return get_value(); - } - - private: - void incr() - { - if (_idx >= _max) - return; - do { - _idx++; - } while (_idx < _max && !all_set()); - } - - [[nodiscard]] bool all_set() const - { - if (_idx >= _max) - return false; - - return std::ranges::all_of(_arrays | std::views::values, [this](SparseArray *const &arr) { return (*arr)[_idx].has_value(); }); - } - - std::map *> _arrays; - std::size_t _max; - std::size_t _idx; - }; -} // namespace nfo diff --git a/packages/ecs/wasm/Registry.cpp b/packages/ecs/wasm/Registry.cpp index 41d6b7e0..25f14a18 100644 --- a/packages/ecs/wasm/Registry.cpp +++ b/packages/ecs/wasm/Registry.cpp @@ -13,31 +13,33 @@ #include #include +#include "Utils.hpp" #include "Registry.hpp" namespace nfo { + EMSCRIPTEN_DECLARE_VAL_TYPE(System); + EMSCRIPTEN_BINDINGS(Registry) { + emscripten::register_type("{name: string, [key: string]: any}"); + emscripten::register_type("(registry: Registry) => void"); + emscripten::class_("Registry") .constructor() .function("registerComponent", &Registry::register_component) .function( "getComponentsConst", - emscripten::select_overload const &(const emscripten::val &) const, Registry>(&Registry::get_components) - ) - .function( - "getComponents", emscripten::select_overload &(const emscripten::val &), Registry>(&Registry::get_components) + emscripten::select_overload const &(const Component &) const, Registry>(&Registry::get_components) ) + .function("getComponents", emscripten::select_overload &(const Component &), Registry>(&Registry::get_components)) .function( "getEntityComponentConst", - emscripten::select_overload const &(Entity, const emscripten::val &) const, Registry>( - &Registry::get_entity_component - ) + emscripten::select_overload const &(Entity, const Component &) const, Registry>(&Registry::get_entity_component) ) .function( "getEntityComponent", - emscripten::select_overload &(Entity, const emscripten::val &), Registry>(&Registry::get_entity_component) + emscripten::select_overload &(Entity, const Component &), Registry>(&Registry::get_entity_component) ) .function("spawnEntity", &Registry::spawn_entity) .function("entityFromIndex", &Registry::entity_from_index) @@ -45,17 +47,14 @@ namespace nfo { .function("clearEntities", &Registry::clear_entities) .function( "addComponent", - emscripten::select_overload::reference_type &(const Entity &, emscripten::val &&), Registry>( - &Registry::add_component - ) + emscripten::select_overload::reference_type &(const Entity &, Component &&), Registry>(&Registry::add_component) ) - .function("removeComponent", emscripten::select_overload(&Registry::remove_component)) - .function("addSystem", emscripten::select_overload(&Registry::add_system)) + .function("removeComponent", emscripten::select_overload(&Registry::remove_component)) + .function("addSystem", emscripten::select_overload(&Registry::add_system)) .function("runSystems", &Registry::run_systems) .function("removeSystem", &Registry::remove_system) .function("clearSystems", &Registry::clear_systems) .function("getZipper", &Registry::get_zipper) - .function("getIndexedZipper", &Registry::get_indexed_zipper) .function("maxEntities", &Registry::max_entities); } } // namespace nfo diff --git a/packages/ecs/wasm/Registry.hpp b/packages/ecs/wasm/Registry.hpp index 1bd5601f..d0253021 100644 --- a/packages/ecs/wasm/Registry.hpp +++ b/packages/ecs/wasm/Registry.hpp @@ -21,15 +21,13 @@ #include #include "Entity.hpp" -#include "IndexedZipper.hpp" #include "SparseArray.hpp" #include "Utils.hpp" -#include "Zipper.hpp" namespace nfo { class Registry { public: - SparseArray ®ister_component(const emscripten::val &c) + SparseArray ®ister_component(const Component &c) { std::string component_type(get_js_class_name(c)); if (component_type == "entity" || component_type == "id") @@ -55,7 +53,7 @@ namespace nfo { return std::any_cast &>(_components_arrays[component_type]); } - SparseArray &get_components(const emscripten::val &c) + SparseArray &get_components(const Component &c) { const std::string component_type(get_js_class_name(c)); if (!_components_arrays.contains(component_type)) @@ -64,7 +62,7 @@ namespace nfo { return std::any_cast &>(components); } - [[nodiscard]] SparseArray const &get_components(const emscripten::val &c) const + [[nodiscard]] SparseArray const &get_components(const Component &c) const { const std::string component_type(get_js_class_name(c)); if (!_components_arrays.contains(component_type)) @@ -73,7 +71,7 @@ namespace nfo { return std::any_cast &>(components); } - std::optional &get_entity_component(const Entity e, const emscripten::val &c) + std::optional &get_entity_component(const Entity e, const Component &c) { const std::string component_type(get_js_class_name(c)); if (!_components_arrays.contains(component_type)) @@ -82,7 +80,7 @@ namespace nfo { return std::any_cast &>(components)[e]; } - [[nodiscard]] std::optional const &get_entity_component(const Entity e, const emscripten::val &c) const + [[nodiscard]] std::optional const &get_entity_component(const Entity e, const Component &c) const { const std::string component_type(get_js_class_name(c)); if (!_components_arrays.contains(component_type)) @@ -125,7 +123,7 @@ namespace nfo { _components_arrays.clear(); } - SparseArray::reference_type add_component(Entity const &to, emscripten::val &&c) + SparseArray::reference_type add_component(Entity const &to, Component &&c) { const std::string component_type(get_js_class_name(c)); if (!_components_arrays.contains(component_type)) { @@ -134,7 +132,7 @@ namespace nfo { return get_components(c).insert_at(to, c); } - void remove_component(Entity const &from, emscripten::val &&c) + void remove_component(Entity const &from, Component &&c) { const std::string component_type(get_js_class_name(c)); if (!_components_arrays.contains(component_type)) @@ -181,28 +179,34 @@ namespace nfo { return _next_entity; } - Zipper get_zipper(const emscripten::val &comps) + emscripten::val get_zipper(const emscripten::val &comps) { if (!comps.isArray()) - throw std::runtime_error("get_zipper: comps is not an array"); + throw std::runtime_error("getZipper: need an array of comps as parameter"); + std::size_t max = SIZE_MAX; std::map *> arrays; for (int i = 0; i < comps["length"].as(); i++) { - arrays[get_js_class_name(comps[i])] = &get_components(comps[i]); + SparseArray &components = get_components(Component(comps[i])); + arrays[get_js_class_name(comps[i])] = &components; + max = (std::min)(components.size(), max); } - return Zipper(arrays); - } - - IndexedZipper get_indexed_zipper(const emscripten::val &comps) - { - if (!comps.isArray()) - throw std::runtime_error("get_zipper: comps is not an array"); - std::map *> arrays; - for (int i = 0; i < comps["length"].as(); i++) { - arrays[get_js_class_name(comps[i])] = &get_components(comps[i]); + emscripten::val arr = emscripten::val::array(); + for (std::size_t idx = 0; idx < max; idx++) { + emscripten::val obj = emscripten::val::object(); + bool need_to_add = true; + for (const auto &[name, sparse_array] : arrays) { + if (!(*sparse_array)[idx].has_value()) { + need_to_add = false; + break; + } + obj.set(name, (*sparse_array)[idx].value()); + } + if (need_to_add) + arr.set(idx, obj); } - return IndexedZipper(arrays); + return arr; } private: diff --git a/packages/ecs/wasm/Utils.hpp b/packages/ecs/wasm/Utils.hpp index 3b45d3c2..1b7bd097 100644 --- a/packages/ecs/wasm/Utils.hpp +++ b/packages/ecs/wasm/Utils.hpp @@ -19,6 +19,9 @@ #define UNKNOWN_COMPONENT_TYPE "__magic_unkown_component_type" +EMSCRIPTEN_DECLARE_VAL_TYPE(Component); +EMSCRIPTEN_DECLARE_VAL_TYPE(ComponentArray); + std::optional json_to_str(const emscripten::val &c); std::optional get_js_member(const emscripten::val &c, const std::string &member); std::string get_js_class_name(const emscripten::val &c); diff --git a/packages/ecs/wasm/Zipper.cpp b/packages/ecs/wasm/Zipper.cpp deleted file mode 100644 index 5b654f7e..00000000 --- a/packages/ecs/wasm/Zipper.cpp +++ /dev/null @@ -1,30 +0,0 @@ -/*⠀ ⠀⠀ ⠀⠀⠀⠀⢀⣀⣀⣀⣀⡀⠀⠀⠀⠀⠀⠀⠀ -**⠀⠀ ⠀⢀⣠⣾⡿⠿⠛⠛⠛⠛⠿⢿⣷⣄⡀⠀⠀⠀ -** _ __ ______ ⠀ ⠀ ⣰⣿⠛⠁⠀⠀⠀⠀⠀⠀⠀⠀⠈⠛⣿⣆⠀⠀ -** / | / /___ _____ ____ / ____/___ _________ ____ ⠀ ⣾⡿⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⢿⣷⠀ -** / |/ / __ `/ __ \/ __ \/ /_ / __ \/ ___/ __ `/ _ \ ⢰⣿⠃⠀⣤⣤⣤⣤⣤⣤⣤⣤⣤⣤⠤⠀⠀⠘⣿⡆ -** / /| / /_/ / / / / /_/ / __/ / /_/ / / / /_/ / __/ ⢸⣿⠀⠀⠀⠉⠛⠛⢻⣿⣿⣿⠉⠀⠀⠀⠀⠀⣿⡇ -** /_/ |_/\__,_/_/ /_/\____/_/ \____/_/ \__, /\___/ ⠸⣿⡄⠀⠀⠀⠀⣠⣾⣿⣿⣿⣤⠀⠀⠀⠀⢠⣿⠇ -** /____/ ⠀ ⢿⣷⡀⠀⠀⠀⠉⠁⠀⠀⠈⠉⠀⠀⠀⢀⣾⡿⠀ -** ⠀⠀⠹⣿⣤⡀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣤⣿⠏⠀⠀ -** 2025 ⠀⠀⠀⠈⠙⢿⣷⣶⣤⣤⣤⣤⣶⣾⡿⠋⠁⠀⠀⠀ -**⠀ ⠀⠀⠀⠀⠀⠀⠈⠉⠉⠉⠉⠁⠀⠀⠀⠀⠀⠀⠀ -*/ - -#include -#include - -#include "Zipper.hpp" - -namespace nfo { - EMSCRIPTEN_BINDINGS(Zipper) - { - emscripten::register_map *>("MapStringSparseArray"); - emscripten::register_vector("VectorString"); - - emscripten::class_("Zipper") - .constructor *> &>() - .function("next", &Zipper::next) - .function("getValue", &Zipper::get_value); - } -} // namespace nfo diff --git a/packages/ecs/wasm/Zipper.hpp b/packages/ecs/wasm/Zipper.hpp deleted file mode 100644 index ec79c2b2..00000000 --- a/packages/ecs/wasm/Zipper.hpp +++ /dev/null @@ -1,77 +0,0 @@ -/*⠀ ⠀⠀ ⠀⠀⠀⠀⢀⣀⣀⣀⣀⡀⠀⠀⠀⠀⠀⠀⠀ -**⠀⠀ ⠀⢀⣠⣾⡿⠿⠛⠛⠛⠛⠿⢿⣷⣄⡀⠀⠀⠀ -** _ __ ______ ⠀ ⠀ ⣰⣿⠛⠁⠀⠀⠀⠀⠀⠀⠀⠀⠈⠛⣿⣆⠀⠀ -** / | / /___ _____ ____ / ____/___ _________ ____ ⠀ ⣾⡿⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⢿⣷⠀ -** / |/ / __ `/ __ \/ __ \/ /_ / __ \/ ___/ __ `/ _ \ ⢰⣿⠃⠀⣤⣤⣤⣤⣤⣤⣤⣤⣤⣤⠤⠀⠀⠘⣿⡆ -** / /| / /_/ / / / / /_/ / __/ / /_/ / / / /_/ / __/ ⢸⣿⠀⠀⠀⠉⠛⠛⢻⣿⣿⣿⠉⠀⠀⠀⠀⠀⣿⡇ -** /_/ |_/\__,_/_/ /_/\____/_/ \____/_/ \__, /\___/ ⠸⣿⡄⠀⠀⠀⠀⣠⣾⣿⣿⣿⣤⠀⠀⠀⠀⢠⣿⠇ -** /____/ ⠀ ⢿⣷⡀⠀⠀⠀⠉⠁⠀⠀⠈⠉⠀⠀⠀⢀⣾⡿⠀ -** ⠀⠀⠹⣿⣤⡀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣤⣿⠏⠀⠀ -** 2025 ⠀⠀⠀⠈⠙⢿⣷⣶⣤⣤⣤⣤⣶⣾⡿⠋⠁⠀⠀⠀ -**⠀ ⠀⠀⠀⠀⠀⠀⠈⠉⠉⠉⠉⠁⠀⠀⠀⠀⠀⠀⠀ -*/ - -#pragma once - -#include -#include - -#include "SparseArray.hpp" -#include "Utils.hpp" - -namespace nfo { - class Zipper { - public: - explicit Zipper(const std::map *> &arrays) : _arrays(arrays), _max(0), _idx(0) - { - _max = arrays.empty() ? 0 : arrays.begin()->second->size(); - for (SparseArray *&arr : _arrays | std::views::values) { - _max = (std::min)(arr->size(), _max); - } - if (_idx < _max && !all_set()) - incr(); - } - - [[nodiscard]] emscripten::val get_value() const - { - if (_idx >= _max) - return emscripten::val::undefined(); - - emscripten::val res = emscripten::val::object(); - for (SparseArray *const &arr : _arrays | std::views::values) { - res.set(get_js_class_name((*arr)[_idx].value()), (*arr)[_idx].value_or(emscripten::val::undefined())); - } - return res; - } - - emscripten::val next() - { - incr(); - return get_value(); - } - - private: - void incr() - { - if (_idx >= _max) - return; - do { - _idx++; - } while (_idx < _max && !all_set()); - } - - [[nodiscard]] bool all_set() const - { - if (_idx >= _max) - return false; - - return std::ranges::all_of(_arrays | std::views::values, [this](SparseArray *const &arr) { - return (*arr)[_idx].has_value(); - }); - } - - std::map *> _arrays; - std::size_t _max; - std::size_t _idx; - }; -} // namespace nfo