@draug/engine 1.0.9 → 1.0.11

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.
package/README.md CHANGED
@@ -1,5 +1,6 @@
1
1
  # @draug/engine
2
2
 
3
+ ![NPM Version](https://img.shields.io/npm/v/%40draug%2Fengine?style=flat)
3
4
  [![Socket Badge](https://badge.socket.dev/npm/package/@draug/engine/1.0.6)](https://badge.socket.dev/npm/package/@draug/engine/1.0.6)
4
5
 
5
6
  Small ECS-first game skeleton for TypeScript: a `World` holds entities, components (plain data), systems (per-frame logic), double-buffered events, typed resources, and optional plugins. A thin `Runtime` plus `GameLoop` / `Clock` help you step simulation on a steady timer instead of growing everything inside one giant class.
@@ -244,7 +245,7 @@ In Node, `performance.now()` is available on modern versions; otherwise pass `{
244
245
 
245
246
  ### Runtime (optional)
246
247
 
247
- `Runtime` is a tiny wrapper: `update(dt)` forwards to `world.update(dt)`. In the Amber workspace it is usually constructed together with `@draug/assets`’s `AssetsManager` for loading textures and similar; for a headless server or a toy sim you can ignore `Runtime` and call `world.update` directly from your own driver.
248
+ `Runtime` is a tiny wrapper: `update(dt)` forwards to `world.update(dt)`. In the Amber workspace it is usually constructed together with `AssetsManager` from this package for loading textures and similar; for a headless server or a toy sim you can ignore `Runtime` and call `world.update` directly from your own driver.
248
249
 
249
250
  ## Configuration
250
251
 
@@ -268,7 +269,7 @@ Issues and PRs are welcome in the [GitHub repository](https://github.com/yazmeya
268
269
 
269
270
  - **Author:** future_undefined — [GitHub @yazmeyaa](https://github.com/yazmeyaa) · [evgenijantonenkov456@gmail.com](mailto:evgenijantonenkov456@gmail.com)
270
271
 
271
- Related workspace packages: `@draug/core` (DAG sort, object pools, etc.) and `@draug/types` (shared `ClassType` helpers). Everything this library exposes to apps is listed in `src/index.ts` in the repository.
272
+ Related workspace packages: `@draug/types` (WebSocket `RawData` helper for networking code). Everything this library exposes to apps is listed in `src/index.ts` in the repository.
272
273
 
273
274
  ## License
274
275
 
package/dist/index.cjs CHANGED
@@ -20,15 +20,21 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/index.ts
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
+ Asset: () => Asset,
24
+ AssetState: () => AssetState,
25
+ AssetStorage: () => AssetStorage,
26
+ AssetsManager: () => AssetsManager,
23
27
  Clock: () => Clock,
24
28
  Commands: () => Commands,
25
29
  Component: () => Component,
26
30
  ComponentAlreadyRegisteredError: () => ComponentAlreadyRegisteredError,
27
31
  ComponentStorage: () => ComponentStorage,
28
32
  ComponentsManager: () => ComponentsManager,
33
+ DAGNode: () => DAGNode,
29
34
  EntitiesManager: () => EntitiesManager,
30
35
  EntityMaskNotFoundError: () => EntityMaskNotFoundError,
31
36
  EntityRef: () => EntityRef,
37
+ ErrDAGCycleDetected: () => ErrDAGCycleDetected,
32
38
  ErrMissingPluginMetadata: () => ErrMissingPluginMetadata,
33
39
  ErrMissingSystemMetadata: () => ErrMissingSystemMetadata,
34
40
  ErrNotAPlugin: () => ErrNotAPlugin,
@@ -38,6 +44,7 @@ __export(index_exports, {
38
44
  EventBuffer: () => EventBuffer,
39
45
  EventBus: () => EventBus,
40
46
  GameLoop: () => GameLoop,
47
+ ObjectPool: () => ObjectPool,
41
48
  Plugin: () => Plugin,
42
49
  PluginBase: () => PluginBase,
43
50
  PluginError: () => PluginError,
@@ -50,18 +57,62 @@ __export(index_exports, {
50
57
  SystemError: () => SystemError,
51
58
  SystemsManager: () => SystemsManager,
52
59
  UnregisteredComponentStorageError: () => UnregisteredComponentStorageError,
60
+ VisitedState: () => VisitedState,
53
61
  World: () => World3,
54
62
  createEventKey: () => createEventKey,
55
63
  entry: () => entry,
56
64
  getPluginMetadata: () => getPluginMetadata,
57
65
  getSystemMetadata: () => getSystemMetadata,
58
66
  isPlugin: () => isPlugin,
59
- isSystem: () => isSystem
67
+ isSystem: () => isSystem,
68
+ topologicalSort: () => topologicalSort
60
69
  });
61
70
  module.exports = __toCommonJS(index_exports);
62
71
 
72
+ // src/core/graph/dag.ts
73
+ var VisitedState = /* @__PURE__ */ ((VisitedState2) => {
74
+ VisitedState2[VisitedState2["Unvisited"] = 0] = "Unvisited";
75
+ VisitedState2[VisitedState2["Visiting"] = 1] = "Visiting";
76
+ VisitedState2[VisitedState2["Visited"] = 2] = "Visited";
77
+ return VisitedState2;
78
+ })(VisitedState || {});
79
+ var DAGNode = class {
80
+ data;
81
+ vertices = [];
82
+ constructor(data, vertices) {
83
+ this.data = data;
84
+ if (vertices)
85
+ this.vertices = vertices;
86
+ }
87
+ };
88
+ var ErrDAGCycleDetected = class extends Error {
89
+ constructor() {
90
+ super(`Cycle detected!`);
91
+ }
92
+ };
93
+ function topologicalSort(nodes) {
94
+ const visited = /* @__PURE__ */ new Map();
95
+ const result = [];
96
+ const dfs = (node) => {
97
+ const state = visited.get(node) ?? 0 /* Unvisited */;
98
+ if (state === 2 /* Visited */) return;
99
+ if (state === 1 /* Visiting */) {
100
+ throw new ErrDAGCycleDetected();
101
+ }
102
+ visited.set(node, 1 /* Visiting */);
103
+ for (const child of node.vertices) {
104
+ dfs(child);
105
+ }
106
+ visited.set(node, 2 /* Visited */);
107
+ result.push(node);
108
+ };
109
+ for (const node of nodes) {
110
+ dfs(node);
111
+ }
112
+ return result.reverse();
113
+ }
114
+
63
115
  // src/ecs/system.ts
64
- var import_core = require("@draug/core");
65
116
  var SystemError = class extends Error {
66
117
  constructor(target) {
67
118
  super(`[System Error] (System "${target.name}".`);
@@ -160,7 +211,7 @@ var SystemsManager = class {
160
211
  buildSystemsArray() {
161
212
  const map = /* @__PURE__ */ new Map();
162
213
  for (const [ctor, system] of this.systems_.entries()) {
163
- map.set(ctor, new import_core.DAGNode(system));
214
+ map.set(ctor, new DAGNode(system));
164
215
  }
165
216
  for (const ctor of this.systems_.keys()) {
166
217
  const currentNode = map.get(ctor);
@@ -173,7 +224,7 @@ var SystemsManager = class {
173
224
  depNode.vertices.push(currentNode);
174
225
  }
175
226
  }
176
- this.executionOrder_ = (0, import_core.topologicalSort)(map.values()).map((x) => x.data);
227
+ this.executionOrder_ = topologicalSort(map.values()).map((x) => x.data);
177
228
  }
178
229
  };
179
230
 
@@ -274,8 +325,36 @@ var EventBus = class {
274
325
  }
275
326
  };
276
327
 
328
+ // src/core/memory/pool.ts
329
+ var ObjectPool = class {
330
+ pool_;
331
+ factory_;
332
+ cursor_;
333
+ constructor(factory, initialSize = 1024) {
334
+ this.pool_ = new Array(initialSize);
335
+ for (let i = 0; i < initialSize; i++) {
336
+ this.pool_[i] = factory();
337
+ }
338
+ this.factory_ = factory;
339
+ this.cursor_ = initialSize - 1;
340
+ }
341
+ acquire() {
342
+ if (this.cursor_ < 0) this.grow();
343
+ return this.pool_[this.cursor_--];
344
+ }
345
+ release(obj) {
346
+ this.pool_[++this.cursor_] = obj;
347
+ }
348
+ grow() {
349
+ const oldSize = this.pool_.length;
350
+ const newSize = oldSize * 2;
351
+ for (let i = oldSize; i < newSize; i++) this.pool_[i] = this.factory_();
352
+ this.cursor_ = newSize - 1;
353
+ this.pool_.length = newSize;
354
+ }
355
+ };
356
+
277
357
  // src/ecs/components/component-storage.ts
278
- var import_core2 = require("@draug/core");
279
358
  var import_bitmap_index = require("bitmap-index");
280
359
  var import_ts_sparse_set = require("ts-sparse-set");
281
360
  var ComponentStorage = class {
@@ -287,7 +366,7 @@ var ComponentStorage = class {
287
366
  constructor(cap = ECS_DEFAULTS.MAX_ENTITY_COUNT, factory, cls) {
288
367
  this.set_ = new import_ts_sparse_set.SparseSet(cap);
289
368
  this.bits_ = new import_bitmap_index.Bitmap(cap);
290
- this.pool_ = new import_core2.ObjectPool(factory, cap);
369
+ this.pool_ = new ObjectPool(factory, cap);
291
370
  this.cls = cls;
292
371
  }
293
372
  bitmap() {
@@ -646,7 +725,6 @@ var QueryManager = class {
646
725
  };
647
726
 
648
727
  // src/plugin/plugin.ts
649
- var import_core3 = require("@draug/core");
650
728
  var PluginMetadataSymbol = /* @__PURE__ */ Symbol("plugin");
651
729
  function Plugin(metadata) {
652
730
  return (target) => {
@@ -729,7 +807,7 @@ var PluginsManager = class {
729
807
  build() {
730
808
  const nodes = /* @__PURE__ */ new Map();
731
809
  for (const id2 of this.plugins_.keys()) {
732
- nodes.set(id2, new import_core3.DAGNode(id2));
810
+ nodes.set(id2, new DAGNode(id2));
733
811
  }
734
812
  for (const [id2, entry2] of this.plugins_) {
735
813
  const node = nodes.get(id2);
@@ -744,9 +822,9 @@ var PluginsManager = class {
744
822
  }
745
823
  let sortedNodes;
746
824
  try {
747
- sortedNodes = (0, import_core3.topologicalSort)(nodes.values());
825
+ sortedNodes = topologicalSort(nodes.values());
748
826
  } catch (e) {
749
- if (e instanceof import_core3.ErrDAGCycleDetected) {
827
+ if (e instanceof ErrDAGCycleDetected) {
750
828
  throw new ErrDAGCycleDetectedPlugin();
751
829
  }
752
830
  throw e;
@@ -903,17 +981,169 @@ var Runtime = class {
903
981
  this.world.update(dt);
904
982
  }
905
983
  };
984
+
985
+ // src/assets/assets.ts
986
+ var AssetState = /* @__PURE__ */ ((AssetState2) => {
987
+ AssetState2[AssetState2["NOT_READY"] = 1] = "NOT_READY";
988
+ AssetState2[AssetState2["LOADING"] = 2] = "LOADING";
989
+ AssetState2[AssetState2["READY"] = 3] = "READY";
990
+ return AssetState2;
991
+ })(AssetState || {});
992
+ var Asset = class {
993
+ constructor(id2, url, loader, disposer) {
994
+ this.id = id2;
995
+ this.url = url;
996
+ this.loader = loader;
997
+ this.disposer = disposer;
998
+ }
999
+ id;
1000
+ url;
1001
+ loader;
1002
+ disposer;
1003
+ data_ = null;
1004
+ state_ = 1 /* NOT_READY */;
1005
+ loading_ = null;
1006
+ disposed_ = false;
1007
+ async load() {
1008
+ if (this.state_ === 3 /* READY */)
1009
+ return this.data_;
1010
+ if (this.state_ === 2 /* LOADING */)
1011
+ return this.loading_;
1012
+ this.state_ = 2 /* LOADING */;
1013
+ this.disposed_ = false;
1014
+ this.loading_ = this.loader(this.url).then((data) => {
1015
+ if (this.disposed_) return data;
1016
+ this.data_ = data;
1017
+ this.state_ = 3 /* READY */;
1018
+ this.loading_ = null;
1019
+ return data;
1020
+ }).catch((err) => {
1021
+ this.state_ = 1 /* NOT_READY */;
1022
+ this.loading_ = null;
1023
+ throw err;
1024
+ });
1025
+ return this.loading_;
1026
+ }
1027
+ reset() {
1028
+ this.data_ = null;
1029
+ this.loading_ = null;
1030
+ this.state_ = 1 /* NOT_READY */;
1031
+ }
1032
+ async dispose() {
1033
+ this.disposed_ = true;
1034
+ if (this.data_)
1035
+ await this.disposer(this.data_);
1036
+ this.reset();
1037
+ }
1038
+ getData() {
1039
+ if (this.state_ !== 3 /* READY */)
1040
+ throw new Error("Data is not loaded yet!");
1041
+ return this.data_;
1042
+ }
1043
+ };
1044
+ var AssetStorage = class {
1045
+ constructor(nextIdFn_, defaultLoader_, defaultDisposer_) {
1046
+ this.nextIdFn_ = nextIdFn_;
1047
+ this.defaultLoader_ = defaultLoader_;
1048
+ this.defaultDisposer_ = defaultDisposer_;
1049
+ }
1050
+ nextIdFn_;
1051
+ defaultLoader_;
1052
+ defaultDisposer_;
1053
+ items_ = /* @__PURE__ */ new Map();
1054
+ newAsset(id2, url, loader, disposer) {
1055
+ return new Asset(id2, url, loader, disposer);
1056
+ }
1057
+ add(url) {
1058
+ const id2 = this.nextIdFn_();
1059
+ const rs = this.newAsset(id2, url, this.defaultLoader_, this.defaultDisposer_);
1060
+ this.items_.set(id2, rs);
1061
+ return rs;
1062
+ }
1063
+ addCustom(url, customLoader, customDisposer) {
1064
+ const id2 = this.nextIdFn_();
1065
+ const rs = this.newAsset(id2, url, customLoader, customDisposer);
1066
+ this.items_.set(id2, rs);
1067
+ return rs;
1068
+ }
1069
+ get(id2) {
1070
+ const item = this.items_.get(id2);
1071
+ return item ?? null;
1072
+ }
1073
+ tryGet(id2) {
1074
+ const item = this.items_.get(id2);
1075
+ if (!item)
1076
+ throw new Error(`Asset with id ${id2} in storage ${this.constructor.name} not exist`);
1077
+ return item;
1078
+ }
1079
+ async remove(id2) {
1080
+ const item = this.items_.get(id2);
1081
+ if (!item) return;
1082
+ await item.dispose();
1083
+ this.items_.delete(id2);
1084
+ }
1085
+ async loadAll() {
1086
+ await Promise.all(
1087
+ Array.from(this.items_.values(), (r) => r.load())
1088
+ );
1089
+ }
1090
+ async clearAll() {
1091
+ await Promise.all(
1092
+ Array.from(this.items_.values(), (r) => r.dispose())
1093
+ );
1094
+ this.items_.clear();
1095
+ }
1096
+ };
1097
+ var NOOP_DISPOSER = async () => {
1098
+ };
1099
+ var AssetsManager = class {
1100
+ storages_ = /* @__PURE__ */ new Map();
1101
+ currId = 0;
1102
+ nextIdFn = () => {
1103
+ return ++this.currId;
1104
+ };
1105
+ register(res, defaultLoader, defaultDisposer = NOOP_DISPOSER) {
1106
+ const storage = new AssetStorage(
1107
+ this.nextIdFn,
1108
+ defaultLoader,
1109
+ defaultDisposer
1110
+ );
1111
+ this.storages_.set(res, storage);
1112
+ return storage;
1113
+ }
1114
+ getStorage(res) {
1115
+ return this.storages_.get(res) ?? null;
1116
+ }
1117
+ tryGetStorage(res) {
1118
+ const s = this.storages_.get(res);
1119
+ if (!s)
1120
+ throw new Error(`Storage ${res.name} is not registered!`);
1121
+ return s;
1122
+ }
1123
+ async loadAll() {
1124
+ await Promise.all(Array.from(this.storages_.values(), (s) => s.loadAll()));
1125
+ }
1126
+ disposeAll() {
1127
+ Array.from(this.storages_.values(), (s) => s.clearAll());
1128
+ }
1129
+ };
906
1130
  // Annotate the CommonJS export names for ESM import in node:
907
1131
  0 && (module.exports = {
1132
+ Asset,
1133
+ AssetState,
1134
+ AssetStorage,
1135
+ AssetsManager,
908
1136
  Clock,
909
1137
  Commands,
910
1138
  Component,
911
1139
  ComponentAlreadyRegisteredError,
912
1140
  ComponentStorage,
913
1141
  ComponentsManager,
1142
+ DAGNode,
914
1143
  EntitiesManager,
915
1144
  EntityMaskNotFoundError,
916
1145
  EntityRef,
1146
+ ErrDAGCycleDetected,
917
1147
  ErrMissingPluginMetadata,
918
1148
  ErrMissingSystemMetadata,
919
1149
  ErrNotAPlugin,
@@ -923,6 +1153,7 @@ var Runtime = class {
923
1153
  EventBuffer,
924
1154
  EventBus,
925
1155
  GameLoop,
1156
+ ObjectPool,
926
1157
  Plugin,
927
1158
  PluginBase,
928
1159
  PluginError,
@@ -935,12 +1166,14 @@ var Runtime = class {
935
1166
  SystemError,
936
1167
  SystemsManager,
937
1168
  UnregisteredComponentStorageError,
1169
+ VisitedState,
938
1170
  World,
939
1171
  createEventKey,
940
1172
  entry,
941
1173
  getPluginMetadata,
942
1174
  getSystemMetadata,
943
1175
  isPlugin,
944
- isSystem
1176
+ isSystem,
1177
+ topologicalSort
945
1178
  });
946
1179
  //# sourceMappingURL=index.cjs.map