@benev/archimedes 0.1.0-1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (133) hide show
  1. package/LICENSE +23 -0
  2. package/README.md +19 -0
  3. package/package.json +44 -0
  4. package/s/_archive/GLOSSARY.md +31 -0
  5. package/s/_archive/README.md +209 -0
  6. package/s/_archive/core/authority.ts +62 -0
  7. package/s/_archive/core/contact/codecs.i.ts +3 -0
  8. package/s/_archive/core/contact/codecs.ts +14 -0
  9. package/s/_archive/core/contact/contact.test.ts +32 -0
  10. package/s/_archive/core/contact/contact.ts +63 -0
  11. package/s/_archive/core/contact/types.ts +24 -0
  12. package/s/_archive/core/contact/wiring.i.ts +3 -0
  13. package/s/_archive/core/contact/wiring.ts +212 -0
  14. package/s/_archive/core/fiber.ts +94 -0
  15. package/s/_archive/core/liaison.ts +73 -0
  16. package/s/_archive/core/parcels/inbox.ts +83 -0
  17. package/s/_archive/core/parcels/parceller.ts +20 -0
  18. package/s/_archive/core/parcels/parcels.test.ts +136 -0
  19. package/s/_archive/core/parcels/types.ts +5 -0
  20. package/s/_archive/core/parcels/utils/nanny.ts +23 -0
  21. package/s/_archive/core/simulator.ts +11 -0
  22. package/s/_archive/core/speculator.ts +63 -0
  23. package/s/_archive/core/types.ts +32 -0
  24. package/s/_archive/core/utils/handle-telegrams.ts +34 -0
  25. package/s/_archive/core/utils/is-input-dispatch.ts +10 -0
  26. package/s/_archive/core/utils/make-telegram-for-inputs.ts +12 -0
  27. package/s/_archive/core/utils/on-channel-message.ts +11 -0
  28. package/s/_archive/eureka/eureka.ts +20 -0
  29. package/s/_archive/eureka/index.ts +0 -0
  30. package/s/_archive/eureka/integration/context.ts +9 -0
  31. package/s/_archive/eureka/integration/simulator.ts +75 -0
  32. package/s/_archive/eureka/integration/types.ts +12 -0
  33. package/s/_archive/eureka/integration/utils/inputs.ts +24 -0
  34. package/s/_archive/eureka/integration/utils/relevance.ts +10 -0
  35. package/s/_archive/eureka/parts/entity.ts +37 -0
  36. package/s/_archive/eureka/parts/system.ts +38 -0
  37. package/s/_archive/eureka/parts/types.ts +21 -0
  38. package/s/_archive/eureka/parts/world.ts +140 -0
  39. package/s/_archive/eureka/testing/eureka.test.ts +27 -0
  40. package/s/_archive/eureka/testing/integration.test.ts +40 -0
  41. package/s/_archive/eureka/testing/situations/health.ts +43 -0
  42. package/s/_archive/eureka/testing/situations/integration.ts +45 -0
  43. package/s/_archive/index.ts +6 -0
  44. package/s/_archive/session/client.ts +56 -0
  45. package/s/_archive/session/host.ts +71 -0
  46. package/s/_archive/session/meta/meta-client.ts +5 -0
  47. package/s/_archive/session/meta/meta-host.ts +18 -0
  48. package/s/_archive/session/meta/types.ts +15 -0
  49. package/s/_archive/session/parts/client-on.ts +8 -0
  50. package/s/_archive/session/parts/fiber-rpc.ts +28 -0
  51. package/s/_archive/session/parts/host-on.ts +9 -0
  52. package/s/_archive/session/parts/hub.ts +40 -0
  53. package/s/_archive/session/parts/netfibers.ts +14 -0
  54. package/s/_archive/session/parts/seat.ts +35 -0
  55. package/s/_archive/session/parts/spoke.ts +10 -0
  56. package/s/_archive/sugar/easy-host.ts +68 -0
  57. package/s/_archive/tests.test.ts +17 -0
  58. package/s/_archive/tools/averager.ts +29 -0
  59. package/s/_archive/tools/bucket.ts +17 -0
  60. package/s/_archive/tools/chronicle.ts +32 -0
  61. package/s/_archive/tools/disposers.ts +5 -0
  62. package/s/_archive/tools/id-counter.ts +13 -0
  63. package/s/_archive/tools/loop.ts +12 -0
  64. package/s/_archive/tools/pub.ts +22 -0
  65. package/s/_archive/tools/ticker.ts +22 -0
  66. package/s/_archive/tools/u8.ts +7 -0
  67. package/s/_archive/transports/sparrow/fibers.ts +19 -0
  68. package/s/_archive/transports/sparrow/start-sparrow-host.ts +26 -0
  69. package/s/_archive/transports/sparrow/utils/netfibers-from-cable.ts +10 -0
  70. package/s/ecs/index.ts +7 -0
  71. package/s/ecs/parts/changers.ts +16 -0
  72. package/s/ecs/parts/make-id.ts +7 -0
  73. package/s/ecs/parts/world.ts +68 -0
  74. package/s/ecs/test/setup-example-world.ts +42 -0
  75. package/s/ecs/test/setup-lifecycle-counts.ts +17 -0
  76. package/s/ecs/test.ts +99 -0
  77. package/s/ecs/types.ts +19 -0
  78. package/s/ecs/utils/is-match.ts +7 -0
  79. package/s/ecs/utils/optimizer.ts +38 -0
  80. package/s/index.ts +3 -0
  81. package/s/net/test.ts +9 -0
  82. package/s/net/types.ts +1 -0
  83. package/s/sim/test.ts +9 -0
  84. package/s/sim/types.ts +1 -0
  85. package/s/test.ts +8 -0
  86. package/x/ecs/index.d.ts +4 -0
  87. package/x/ecs/index.js +5 -0
  88. package/x/ecs/index.js.map +1 -0
  89. package/x/ecs/parts/changers.d.ts +4 -0
  90. package/x/ecs/parts/changers.js +11 -0
  91. package/x/ecs/parts/changers.js.map +1 -0
  92. package/x/ecs/parts/make-id.d.ts +1 -0
  93. package/x/ecs/parts/make-id.js +5 -0
  94. package/x/ecs/parts/make-id.js.map +1 -0
  95. package/x/ecs/parts/world.d.ts +11 -0
  96. package/x/ecs/parts/world.js +59 -0
  97. package/x/ecs/parts/world.js.map +1 -0
  98. package/x/ecs/test/setup-example-world.d.ts +10 -0
  99. package/x/ecs/test/setup-example-world.js +31 -0
  100. package/x/ecs/test/setup-example-world.js.map +1 -0
  101. package/x/ecs/test/setup-lifecycle-counts.d.ts +6 -0
  102. package/x/ecs/test/setup-lifecycle-counts.js +15 -0
  103. package/x/ecs/test/setup-lifecycle-counts.js.map +1 -0
  104. package/x/ecs/test.d.ts +13 -0
  105. package/x/ecs/test.js +85 -0
  106. package/x/ecs/test.js.map +1 -0
  107. package/x/ecs/types.d.ts +12 -0
  108. package/x/ecs/types.js +2 -0
  109. package/x/ecs/types.js.map +1 -0
  110. package/x/ecs/utils/is-match.d.ts +2 -0
  111. package/x/ecs/utils/is-match.js +4 -0
  112. package/x/ecs/utils/is-match.js.map +1 -0
  113. package/x/ecs/utils/optimizer.d.ts +9 -0
  114. package/x/ecs/utils/optimizer.js +37 -0
  115. package/x/ecs/utils/optimizer.js.map +1 -0
  116. package/x/index.d.ts +1 -0
  117. package/x/index.js +2 -0
  118. package/x/index.js.map +1 -0
  119. package/x/net/test.d.ts +4 -0
  120. package/x/net/test.js +7 -0
  121. package/x/net/test.js.map +1 -0
  122. package/x/net/types.d.ts +1 -0
  123. package/x/net/types.js +2 -0
  124. package/x/net/types.js.map +1 -0
  125. package/x/sim/test.d.ts +4 -0
  126. package/x/sim/test.js +7 -0
  127. package/x/sim/test.js.map +1 -0
  128. package/x/sim/types.d.ts +1 -0
  129. package/x/sim/types.js +2 -0
  130. package/x/sim/types.js.map +1 -0
  131. package/x/test.d.ts +1 -0
  132. package/x/test.js +6 -0
  133. package/x/test.js.map +1 -0
@@ -0,0 +1,10 @@
1
+
2
+ import {StdCable} from "sparrow-rtc"
3
+ import {Netfibers} from "../../../session/parts/netfibers.js"
4
+
5
+ export function netfibersFromCable(cable: StdCable) {
6
+ const netfibers = new Netfibers()
7
+ netfibers.megafiber.attachCable(cable)
8
+ return netfibers
9
+ }
10
+
package/s/ecs/index.ts ADDED
@@ -0,0 +1,7 @@
1
+
2
+ export * from "./parts/changers.js"
3
+ export * from "./parts/make-id.js"
4
+ export * from "./parts/world.js"
5
+
6
+ export * from "./types.js"
7
+
@@ -0,0 +1,16 @@
1
+
2
+ import {makeId} from "./make-id.js"
3
+ import {Change, Components, Id} from "../types.js"
4
+
5
+ export function create<C extends Components>(components: Partial<C>): Change {
6
+ return [makeId(), components]
7
+ }
8
+
9
+ export function update<C extends Components>(id: Id, components: Partial<C>): Change {
10
+ return [id, components]
11
+ }
12
+
13
+ export function del(id: Id): Change {
14
+ return [id]
15
+ }
16
+
@@ -0,0 +1,7 @@
1
+
2
+ import {hex} from "@e280/stz"
3
+
4
+ export function makeId() {
5
+ return hex.random(8)
6
+ }
7
+
@@ -0,0 +1,68 @@
1
+
2
+ import {GMap} from "@e280/stz"
3
+ import {Optimizer} from "../utils/optimizer.js"
4
+ import {Change, Components, Entities, Id, LifecycleCallbacks, LifecycleEnter, Select, System} from "../types.js"
5
+
6
+ export class World<C extends Components> {
7
+ #optimizer
8
+
9
+ constructor(public entities: Entities<Partial<C>> = new Map()) {
10
+ this.#optimizer = new Optimizer<C>(entities)
11
+ }
12
+
13
+ require<C2 extends Partial<C> = Partial<C>>(id: Id) {
14
+ return GMap.require(this.entities, id) as C2 & Partial<C>
15
+ }
16
+
17
+ *select<K extends keyof C>(...required: K[]) {
18
+ for (const entity of this.#optimizer.obtain(required)) {
19
+ const [,components] = entity
20
+ if (required.every(r => r in components))
21
+ yield entity as [id: Id, components: Select<C, K>]
22
+ }
23
+ }
24
+
25
+ lifecycle<K extends keyof C>(required: K[], enter: LifecycleEnter<C, K>) {
26
+ const alive = new GMap<Id, LifecycleCallbacks<C, K>>()
27
+ const sel = () => this.select(...required)
28
+
29
+ return function*() {
30
+ const current = new Map(sel())
31
+
32
+ for (const [id, callbacks] of alive) {
33
+ if (current.has(id)) continue
34
+ alive.delete(id)
35
+ callbacks.exit(id)
36
+ }
37
+
38
+ for (const [id, components] of current) {
39
+ const callbacks = alive.guarantee(id, () => enter(id, components))
40
+ callbacks.tick(id, components)
41
+ }
42
+ }
43
+ }
44
+
45
+ apply([id, components]: Change) {
46
+ if (components) {
47
+ this.entities.set(id, components as Partial<C>)
48
+ this.#optimizer.update(id, components as Partial<C>)
49
+ }
50
+ else {
51
+ this.entities.delete(id)
52
+ this.#optimizer.eliminate(id)
53
+ }
54
+ return id
55
+ }
56
+
57
+ execute(systems: System[]) {
58
+ const changes: Change[] = []
59
+ for (const system of systems) {
60
+ for (const change of system()) {
61
+ this.apply(change)
62
+ changes.push(change)
63
+ }
64
+ }
65
+ return changes
66
+ }
67
+ }
68
+
@@ -0,0 +1,42 @@
1
+
2
+ import {World} from "../parts/world.js"
3
+ import {del, update} from "../parts/changers.js"
4
+
5
+ export function setupExampleWorld() {
6
+ const world = new World<{
7
+ health: number
8
+ bleed: number
9
+ mana: number
10
+ manaRegen: number
11
+ }>()
12
+
13
+ const systems = [
14
+ function* manaRegen() {
15
+ for (const [id, c] of world.select("mana", "manaRegen")) {
16
+ if (c.manaRegen !== 0) {
17
+ const mana = c.mana + c.manaRegen
18
+ yield update(id, {...c, mana})
19
+ }
20
+ }
21
+ },
22
+
23
+ function* bleeding() {
24
+ for (const [id, c] of world.select("health", "bleed")) {
25
+ if (c.bleed !== 0) {
26
+ const health = c.health - c.bleed
27
+ yield update(id, {...c, health})
28
+ }
29
+ }
30
+ },
31
+
32
+ function* death() {
33
+ for (const [id, c] of world.select("health")) {
34
+ if (c.health <= 0)
35
+ yield del(id)
36
+ }
37
+ },
38
+ ]
39
+
40
+ return {world, systems}
41
+ }
42
+
@@ -0,0 +1,17 @@
1
+
2
+ import {expect} from "@e280/science"
3
+
4
+ export function setupLifecycleCounts() {
5
+ const counts = {
6
+ enters: 0,
7
+ ticks: 0,
8
+ exits: 0,
9
+ expect: (enters: number, ticks: number, exits: number) => {
10
+ expect(counts.enters).is(enters)
11
+ expect(counts.ticks).is(ticks)
12
+ expect(counts.exits).is(exits)
13
+ },
14
+ }
15
+ return counts
16
+ }
17
+
package/s/ecs/test.ts ADDED
@@ -0,0 +1,99 @@
1
+
2
+ import {suite, test, expect} from "@e280/science"
3
+ import {create, del, update} from "./parts/changers.js"
4
+ import {setupExampleWorld} from "./test/setup-example-world.js"
5
+ import {setupLifecycleCounts} from "./test/setup-lifecycle-counts.js"
6
+
7
+ export default suite({
8
+ "create an entity": test(async() => {
9
+ const {world} = setupExampleWorld()
10
+ expect(world.entities.size).is(0)
11
+ world.apply(create({health: 100}))
12
+ expect(world.entities.size).is(1)
13
+ }),
14
+
15
+ "delete an entity": test(async() => {
16
+ const {world} = setupExampleWorld()
17
+ const id = world.apply(create({health: 100}))
18
+ expect(world.entities.size).is(1)
19
+ world.apply(del(id))
20
+ expect(world.entities.size).is(0)
21
+ }),
22
+
23
+ "select an entity": test(async() => {
24
+ const {world} = setupExampleWorld()
25
+ world.apply(create({health: 100}))
26
+ expect([...world.select("health")].length).is(1)
27
+ }),
28
+
29
+ "select two entities": test(async() => {
30
+ const {world} = setupExampleWorld()
31
+ world.apply(create({health: 100}))
32
+ world.apply(create({health: 100}))
33
+ expect([...world.select("health")].length).is(2)
34
+ }),
35
+
36
+ "select with no component keys selects all": test(async() => {
37
+ const {world} = setupExampleWorld()
38
+ world.apply(create({health: 100}))
39
+ world.apply(create({health: 100}))
40
+ expect([...world.select()].length).is(2)
41
+ }),
42
+
43
+ "select doesn't include non-match": test(async() => {
44
+ const {world} = setupExampleWorld()
45
+ world.apply(create({health: 100}))
46
+ expect([...world.select("mana")].length).is(0)
47
+ }),
48
+
49
+ "select includes entities with extra components": test(async() => {
50
+ const {world} = setupExampleWorld()
51
+ world.apply(create({health: 100, mana: 100}))
52
+ expect([...world.select("health")].length).is(1)
53
+ }),
54
+
55
+ "wizard regens mana": test(async() => {
56
+ const {world, systems} = setupExampleWorld()
57
+ const wizardId = world.apply(create({health: 100, mana: 50, manaRegen: 1}))
58
+ const changes = world.execute(systems)
59
+ expect(changes.length).is(1)
60
+ expect(world.require(wizardId).mana).is(51)
61
+ }),
62
+
63
+ "death by bleeding": test(async() => {
64
+ const {world, systems} = setupExampleWorld()
65
+ const wizardId = world.apply(create({health: 2, bleed: 1}))
66
+ expect(world.require(wizardId).health).is(2)
67
+ world.execute(systems)
68
+ expect(world.require(wizardId).health).is(1)
69
+ world.execute(systems)
70
+ expect(world.entities.has(wizardId)).is(false)
71
+ }),
72
+
73
+ "lifecycles": test(async() => {
74
+ const {world} = setupExampleWorld()
75
+ const counts = setupLifecycleCounts()
76
+ const system = world.lifecycle(["health"], () => {
77
+ counts.enters++
78
+ return {
79
+ tick: () => void counts.ticks++,
80
+ exit: () => void counts.exits++,
81
+ }
82
+ })
83
+ counts.expect(0, 0, 0)
84
+
85
+ const wizardId = world.apply(create({health: 100, mana: 50}))
86
+ world.execute([system])
87
+ counts.expect(1, 1, 0)
88
+
89
+ world.apply(update(wizardId, {health: 100, mana: 100}))
90
+ world.execute([system])
91
+ counts.expect(1, 2, 0)
92
+
93
+ world.apply(del(wizardId))
94
+ world.execute([system])
95
+ counts.expect(1, 2, 1)
96
+ expect(world.entities.size).is(0)
97
+ }),
98
+ })
99
+
package/s/ecs/types.ts ADDED
@@ -0,0 +1,19 @@
1
+
2
+ export type Entities<C extends Components> = Map<Id, C>
3
+ export type Components = Record<string, unknown>
4
+ export type System = () => Generator<Change>
5
+
6
+ export type Id = string
7
+ export type AsComponents<C extends Components> = C
8
+ export type Change = [id: Id, components?: Partial<Components>]
9
+ export type Select<C extends Components, K extends keyof C> = Pick<C, K> & Partial<C>
10
+
11
+ export type LifecycleCallbacks<C extends Components, K extends keyof C> = {
12
+ tick: (id: Id, components: Select<C, K>) => void
13
+ exit: (id: Id) => void
14
+ }
15
+
16
+ export type LifecycleEnter<C extends Components, K extends keyof C> = (
17
+ (id: Id, components: Select<C, K>) => LifecycleCallbacks<C, K>
18
+ )
19
+
@@ -0,0 +1,7 @@
1
+
2
+ import {Components} from "../types.js"
3
+
4
+ export function isMatch(set: Set<any>, components: Components) {
5
+ return [...set].every(key => key in components)
6
+ }
7
+
@@ -0,0 +1,38 @@
1
+
2
+ import {GMap} from "@e280/stz"
3
+ import {isMatch} from "./is-match.js"
4
+ import {Components, Entities, Id, Select} from "../types.js"
5
+
6
+ export class Optimizer<C extends Components> {
7
+ #index = new GMap<Set<keyof C>, Entities<Partial<C>>>()
8
+
9
+ constructor(public entities: Entities<Partial<C>>) {}
10
+
11
+ obtain<K extends keyof C>(componentKeys: K[]): Entities<Select<C, K>> {
12
+ for (const set of this.#index.keys()) {
13
+ if (set.size !== componentKeys.length) continue
14
+ if (componentKeys.every(key => set.has(key)))
15
+ return this.#index.require(set) as Entities<Select<C, K>>
16
+ }
17
+ const set = new Set(componentKeys)
18
+ const ents: Entities<Select<C, K>> = new GMap()
19
+ this.#index.set(set, ents)
20
+ for (const [id, components] of this.entities)
21
+ if (isMatch(set, components))
22
+ ents.set(id, components as Select<C, K>)
23
+ return ents
24
+ }
25
+
26
+ update(id: Id, components: Partial<C>) {
27
+ for (const [set, ents] of this.#index) {
28
+ if (isMatch(set, components)) ents.set(id, components)
29
+ else ents.delete(id)
30
+ }
31
+ }
32
+
33
+ eliminate(id: Id) {
34
+ for (const ents of this.#index.values())
35
+ ents.delete(id)
36
+ }
37
+ }
38
+
package/s/index.ts ADDED
@@ -0,0 +1,3 @@
1
+
2
+ export * from "./ecs/index.js"
3
+
package/s/net/test.ts ADDED
@@ -0,0 +1,9 @@
1
+
2
+ import {suite, test, expect} from "@e280/science"
3
+
4
+ export default suite({
5
+ "todo": test(async() => {
6
+ expect(1 + 1).is(2)
7
+ }),
8
+ })
9
+
package/s/net/types.ts ADDED
@@ -0,0 +1 @@
1
+
package/s/sim/test.ts ADDED
@@ -0,0 +1,9 @@
1
+
2
+ import {suite, test, expect} from "@e280/science"
3
+
4
+ export default suite({
5
+ "todo": test(async() => {
6
+ expect(1 + 1).is(2)
7
+ }),
8
+ })
9
+
package/s/sim/types.ts ADDED
@@ -0,0 +1 @@
1
+
package/s/test.ts ADDED
@@ -0,0 +1,8 @@
1
+
2
+ import {run} from "@e280/science"
3
+ import ecs from "./ecs/test.js"
4
+ import net from "./net/test.js"
5
+ import sim from "./sim/test.js"
6
+
7
+ await run({ecs, net, sim})
8
+
@@ -0,0 +1,4 @@
1
+ export * from "./parts/changers.js";
2
+ export * from "./parts/make-id.js";
3
+ export * from "./parts/world.js";
4
+ export * from "./types.js";
package/x/ecs/index.js ADDED
@@ -0,0 +1,5 @@
1
+ export * from "./parts/changers.js";
2
+ export * from "./parts/make-id.js";
3
+ export * from "./parts/world.js";
4
+ export * from "./types.js";
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../s/ecs/index.ts"],"names":[],"mappings":"AACA,cAAc,qBAAqB,CAAA;AACnC,cAAc,oBAAoB,CAAA;AAClC,cAAc,kBAAkB,CAAA;AAEhC,cAAc,YAAY,CAAA"}
@@ -0,0 +1,4 @@
1
+ import { Change, Components, Id } from "../types.js";
2
+ export declare function create<C extends Components>(components: Partial<C>): Change;
3
+ export declare function update<C extends Components>(id: Id, components: Partial<C>): Change;
4
+ export declare function del(id: Id): Change;
@@ -0,0 +1,11 @@
1
+ import { makeId } from "./make-id.js";
2
+ export function create(components) {
3
+ return [makeId(), components];
4
+ }
5
+ export function update(id, components) {
6
+ return [id, components];
7
+ }
8
+ export function del(id) {
9
+ return [id];
10
+ }
11
+ //# sourceMappingURL=changers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"changers.js","sourceRoot":"","sources":["../../../s/ecs/parts/changers.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,MAAM,EAAC,MAAM,cAAc,CAAA;AAGnC,MAAM,UAAU,MAAM,CAAuB,UAAsB;IAClE,OAAO,CAAC,MAAM,EAAE,EAAE,UAAU,CAAC,CAAA;AAC9B,CAAC;AAED,MAAM,UAAU,MAAM,CAAuB,EAAM,EAAE,UAAsB;IAC1E,OAAO,CAAC,EAAE,EAAE,UAAU,CAAC,CAAA;AACxB,CAAC;AAED,MAAM,UAAU,GAAG,CAAC,EAAM;IACzB,OAAO,CAAC,EAAE,CAAC,CAAA;AACZ,CAAC"}
@@ -0,0 +1 @@
1
+ export declare function makeId(): string;
@@ -0,0 +1,5 @@
1
+ import { hex } from "@e280/stz";
2
+ export function makeId() {
3
+ return hex.random(8);
4
+ }
5
+ //# sourceMappingURL=make-id.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"make-id.js","sourceRoot":"","sources":["../../../s/ecs/parts/make-id.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,GAAG,EAAC,MAAM,WAAW,CAAA;AAE7B,MAAM,UAAU,MAAM;IACrB,OAAO,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAA;AACrB,CAAC"}
@@ -0,0 +1,11 @@
1
+ import { Change, Components, Entities, Id, LifecycleEnter, Select, System } from "../types.js";
2
+ export declare class World<C extends Components> {
3
+ #private;
4
+ entities: Entities<Partial<C>>;
5
+ constructor(entities?: Entities<Partial<C>>);
6
+ require<C2 extends Partial<C> = Partial<C>>(id: Id): C2 & Partial<C>;
7
+ select<K extends keyof C>(...required: K[]): Generator<[id: string, components: Select<C, K>], void, unknown>;
8
+ lifecycle<K extends keyof C>(required: K[], enter: LifecycleEnter<C, K>): () => Generator<never, void, unknown>;
9
+ apply([id, components]: Change): string;
10
+ execute(systems: System[]): Change[];
11
+ }
@@ -0,0 +1,59 @@
1
+ import { GMap } from "@e280/stz";
2
+ import { Optimizer } from "../utils/optimizer.js";
3
+ export class World {
4
+ entities;
5
+ #optimizer;
6
+ constructor(entities = new Map()) {
7
+ this.entities = entities;
8
+ this.#optimizer = new Optimizer(entities);
9
+ }
10
+ require(id) {
11
+ return GMap.require(this.entities, id);
12
+ }
13
+ *select(...required) {
14
+ for (const entity of this.#optimizer.obtain(required)) {
15
+ const [, components] = entity;
16
+ if (required.every(r => r in components))
17
+ yield entity;
18
+ }
19
+ }
20
+ lifecycle(required, enter) {
21
+ const alive = new GMap();
22
+ const sel = () => this.select(...required);
23
+ return function* () {
24
+ const current = new Map(sel());
25
+ for (const [id, callbacks] of alive) {
26
+ if (current.has(id))
27
+ continue;
28
+ alive.delete(id);
29
+ callbacks.exit(id);
30
+ }
31
+ for (const [id, components] of current) {
32
+ const callbacks = alive.guarantee(id, () => enter(id, components));
33
+ callbacks.tick(id, components);
34
+ }
35
+ };
36
+ }
37
+ apply([id, components]) {
38
+ if (components) {
39
+ this.entities.set(id, components);
40
+ this.#optimizer.update(id, components);
41
+ }
42
+ else {
43
+ this.entities.delete(id);
44
+ this.#optimizer.eliminate(id);
45
+ }
46
+ return id;
47
+ }
48
+ execute(systems) {
49
+ const changes = [];
50
+ for (const system of systems) {
51
+ for (const change of system()) {
52
+ this.apply(change);
53
+ changes.push(change);
54
+ }
55
+ }
56
+ return changes;
57
+ }
58
+ }
59
+ //# sourceMappingURL=world.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"world.js","sourceRoot":"","sources":["../../../s/ecs/parts/world.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,IAAI,EAAC,MAAM,WAAW,CAAA;AAC9B,OAAO,EAAC,SAAS,EAAC,MAAM,uBAAuB,CAAA;AAG/C,MAAM,OAAO,KAAK;IAGE;IAFnB,UAAU,CAAA;IAEV,YAAmB,WAAiC,IAAI,GAAG,EAAE;QAA1C,aAAQ,GAAR,QAAQ,CAAkC;QAC5D,IAAI,CAAC,UAAU,GAAG,IAAI,SAAS,CAAI,QAAQ,CAAC,CAAA;IAC7C,CAAC;IAED,OAAO,CAAqC,EAAM;QACjD,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,EAAE,EAAE,CAAoB,CAAA;IAC1D,CAAC;IAED,CAAC,MAAM,CAAoB,GAAG,QAAa;QAC1C,KAAK,MAAM,MAAM,IAAI,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC;YACvD,MAAM,CAAC,EAAC,UAAU,CAAC,GAAG,MAAM,CAAA;YAC5B,IAAI,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,UAAU,CAAC;gBACvC,MAAM,MAA4C,CAAA;QACpD,CAAC;IACF,CAAC;IAED,SAAS,CAAoB,QAAa,EAAE,KAA2B;QACtE,MAAM,KAAK,GAAG,IAAI,IAAI,EAAgC,CAAA;QACtD,MAAM,GAAG,GAAG,GAAG,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,QAAQ,CAAC,CAAA;QAE1C,OAAO,QAAQ,CAAC;YACf,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,GAAG,EAAE,CAAC,CAAA;YAE9B,KAAK,MAAM,CAAC,EAAE,EAAE,SAAS,CAAC,IAAI,KAAK,EAAE,CAAC;gBACrC,IAAI,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;oBAAE,SAAQ;gBAC7B,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,CAAA;gBAChB,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;YACnB,CAAC;YAED,KAAK,MAAM,CAAC,EAAE,EAAE,UAAU,CAAC,IAAI,OAAO,EAAE,CAAC;gBACxC,MAAM,SAAS,GAAG,KAAK,CAAC,SAAS,CAAC,EAAE,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,EAAE,EAAE,UAAU,CAAC,CAAC,CAAA;gBAClE,SAAS,CAAC,IAAI,CAAC,EAAE,EAAE,UAAU,CAAC,CAAA;YAC/B,CAAC;QACF,CAAC,CAAA;IACF,CAAC;IAED,KAAK,CAAC,CAAC,EAAE,EAAE,UAAU,CAAS;QAC7B,IAAI,UAAU,EAAE,CAAC;YAChB,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,EAAE,UAAwB,CAAC,CAAA;YAC/C,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,EAAE,UAAwB,CAAC,CAAA;QACrD,CAAC;aACI,CAAC;YACL,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,CAAA;YACxB,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC,CAAA;QAC9B,CAAC;QACD,OAAO,EAAE,CAAA;IACV,CAAC;IAED,OAAO,CAAC,OAAiB;QACxB,MAAM,OAAO,GAAa,EAAE,CAAA;QAC5B,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;YAC9B,KAAK,MAAM,MAAM,IAAI,MAAM,EAAE,EAAE,CAAC;gBAC/B,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAA;gBAClB,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;YACrB,CAAC;QACF,CAAC;QACD,OAAO,OAAO,CAAA;IACf,CAAC;CACD"}
@@ -0,0 +1,10 @@
1
+ import { World } from "../parts/world.js";
2
+ export declare function setupExampleWorld(): {
3
+ world: World<{
4
+ health: number;
5
+ bleed: number;
6
+ mana: number;
7
+ manaRegen: number;
8
+ }>;
9
+ systems: (() => Generator<import("../types.js").Change, void, unknown>)[];
10
+ };
@@ -0,0 +1,31 @@
1
+ import { World } from "../parts/world.js";
2
+ import { del, update } from "../parts/changers.js";
3
+ export function setupExampleWorld() {
4
+ const world = new World();
5
+ const systems = [
6
+ function* manaRegen() {
7
+ for (const [id, c] of world.select("mana", "manaRegen")) {
8
+ if (c.manaRegen !== 0) {
9
+ const mana = c.mana + c.manaRegen;
10
+ yield update(id, { ...c, mana });
11
+ }
12
+ }
13
+ },
14
+ function* bleeding() {
15
+ for (const [id, c] of world.select("health", "bleed")) {
16
+ if (c.bleed !== 0) {
17
+ const health = c.health - c.bleed;
18
+ yield update(id, { ...c, health });
19
+ }
20
+ }
21
+ },
22
+ function* death() {
23
+ for (const [id, c] of world.select("health")) {
24
+ if (c.health <= 0)
25
+ yield del(id);
26
+ }
27
+ },
28
+ ];
29
+ return { world, systems };
30
+ }
31
+ //# sourceMappingURL=setup-example-world.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setup-example-world.js","sourceRoot":"","sources":["../../../s/ecs/test/setup-example-world.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,KAAK,EAAC,MAAM,mBAAmB,CAAA;AACvC,OAAO,EAAC,GAAG,EAAE,MAAM,EAAC,MAAM,sBAAsB,CAAA;AAEhD,MAAM,UAAU,iBAAiB;IAChC,MAAM,KAAK,GAAG,IAAI,KAAK,EAKnB,CAAA;IAEJ,MAAM,OAAO,GAAG;QACf,QAAQ,CAAC,CAAC,SAAS;YAClB,KAAK,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,EAAE,CAAC;gBACzD,IAAI,CAAC,CAAC,SAAS,KAAK,CAAC,EAAE,CAAC;oBACvB,MAAM,IAAI,GAAG,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,SAAS,CAAA;oBACjC,MAAM,MAAM,CAAC,EAAE,EAAE,EAAC,GAAG,CAAC,EAAE,IAAI,EAAC,CAAC,CAAA;gBAC/B,CAAC;YACF,CAAC;QACF,CAAC;QAED,QAAQ,CAAC,CAAC,QAAQ;YACjB,KAAK,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,QAAQ,EAAE,OAAO,CAAC,EAAE,CAAC;gBACvD,IAAI,CAAC,CAAC,KAAK,KAAK,CAAC,EAAE,CAAC;oBACnB,MAAM,MAAM,GAAG,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,KAAK,CAAA;oBACjC,MAAM,MAAM,CAAC,EAAE,EAAE,EAAC,GAAG,CAAC,EAAE,MAAM,EAAC,CAAC,CAAA;gBACjC,CAAC;YACF,CAAC;QACF,CAAC;QAED,QAAQ,CAAC,CAAC,KAAK;YACd,KAAK,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC;gBAC9C,IAAI,CAAC,CAAC,MAAM,IAAI,CAAC;oBAChB,MAAM,GAAG,CAAC,EAAE,CAAC,CAAA;YACf,CAAC;QACF,CAAC;KACD,CAAA;IAED,OAAO,EAAC,KAAK,EAAE,OAAO,EAAC,CAAA;AACxB,CAAC"}
@@ -0,0 +1,6 @@
1
+ export declare function setupLifecycleCounts(): {
2
+ enters: number;
3
+ ticks: number;
4
+ exits: number;
5
+ expect: (enters: number, ticks: number, exits: number) => void;
6
+ };
@@ -0,0 +1,15 @@
1
+ import { expect } from "@e280/science";
2
+ export function setupLifecycleCounts() {
3
+ const counts = {
4
+ enters: 0,
5
+ ticks: 0,
6
+ exits: 0,
7
+ expect: (enters, ticks, exits) => {
8
+ expect(counts.enters).is(enters);
9
+ expect(counts.ticks).is(ticks);
10
+ expect(counts.exits).is(exits);
11
+ },
12
+ };
13
+ return counts;
14
+ }
15
+ //# sourceMappingURL=setup-lifecycle-counts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setup-lifecycle-counts.js","sourceRoot":"","sources":["../../../s/ecs/test/setup-lifecycle-counts.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,MAAM,EAAC,MAAM,eAAe,CAAA;AAEpC,MAAM,UAAU,oBAAoB;IACnC,MAAM,MAAM,GAAG;QACd,MAAM,EAAE,CAAC;QACT,KAAK,EAAE,CAAC;QACR,KAAK,EAAE,CAAC;QACR,MAAM,EAAE,CAAC,MAAc,EAAE,KAAa,EAAE,KAAa,EAAE,EAAE;YACxD,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,CAAA;YAChC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAA;YAC9B,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAA;QAC/B,CAAC;KACD,CAAA;IACD,OAAO,MAAM,CAAA;AACd,CAAC"}
@@ -0,0 +1,13 @@
1
+ declare const _default: {
2
+ "create an entity": import("@e280/science").Test;
3
+ "delete an entity": import("@e280/science").Test;
4
+ "select an entity": import("@e280/science").Test;
5
+ "select two entities": import("@e280/science").Test;
6
+ "select with no component keys selects all": import("@e280/science").Test;
7
+ "select doesn't include non-match": import("@e280/science").Test;
8
+ "select includes entities with extra components": import("@e280/science").Test;
9
+ "wizard regens mana": import("@e280/science").Test;
10
+ "death by bleeding": import("@e280/science").Test;
11
+ lifecycles: import("@e280/science").Test;
12
+ };
13
+ export default _default;