@draug/engine 1.0.10 → 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 +2 -2
- package/dist/index.cjs +244 -11
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +84 -9
- package/dist/index.d.ts +84 -9
- package/dist/index.js +230 -6
- package/dist/index.js.map +1 -1
- package/package.json +1 -3
package/README.md
CHANGED
|
@@ -245,7 +245,7 @@ In Node, `performance.now()` is available on modern versions; otherwise pass `{
|
|
|
245
245
|
|
|
246
246
|
### Runtime (optional)
|
|
247
247
|
|
|
248
|
-
`Runtime` is a tiny wrapper: `update(dt)` forwards to `world.update(dt)`. In the Amber workspace it is usually constructed together with
|
|
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.
|
|
249
249
|
|
|
250
250
|
## Configuration
|
|
251
251
|
|
|
@@ -269,7 +269,7 @@ Issues and PRs are welcome in the [GitHub repository](https://github.com/yazmeya
|
|
|
269
269
|
|
|
270
270
|
- **Author:** future_undefined — [GitHub @yazmeyaa](https://github.com/yazmeyaa) · [evgenijantonenkov456@gmail.com](mailto:evgenijantonenkov456@gmail.com)
|
|
271
271
|
|
|
272
|
-
Related workspace packages: `@draug/
|
|
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.
|
|
273
273
|
|
|
274
274
|
## License
|
|
275
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
|
|
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_ =
|
|
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
|
|
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
|
|
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 =
|
|
825
|
+
sortedNodes = topologicalSort(nodes.values());
|
|
748
826
|
} catch (e) {
|
|
749
|
-
if (e instanceof
|
|
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
|