@nice2dev/game-engine 1.0.2 → 1.0.4

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 (188) hide show
  1. package/dist/cjs/ai/BehaviorTree.js +1215 -0
  2. package/dist/cjs/ai/BehaviorTree.js.map +1 -0
  3. package/dist/cjs/ai/StateMachine.js +783 -0
  4. package/dist/cjs/ai/StateMachine.js.map +1 -0
  5. package/dist/cjs/editor/ShaderGraph.js +1616 -0
  6. package/dist/cjs/editor/ShaderGraph.js.map +1 -0
  7. package/dist/cjs/editor/TimelineEditor.js +819 -0
  8. package/dist/cjs/editor/TimelineEditor.js.map +1 -0
  9. package/dist/cjs/export/GodotExporter.js +1102 -0
  10. package/dist/cjs/export/GodotExporter.js.map +1 -0
  11. package/dist/cjs/export/PlatformExporter.js +236 -0
  12. package/dist/cjs/export/PlatformExporter.js.map +1 -0
  13. package/dist/cjs/export/ThreeJSExporter.js +1116 -0
  14. package/dist/cjs/export/ThreeJSExporter.js.map +1 -0
  15. package/dist/cjs/export/UnityExporter.js +1193 -0
  16. package/dist/cjs/export/UnityExporter.js.map +1 -0
  17. package/dist/cjs/export/WebExporter.js +1036 -0
  18. package/dist/cjs/export/WebExporter.js.map +1 -0
  19. package/dist/cjs/export/index.js +58 -0
  20. package/dist/cjs/export/index.js.map +1 -0
  21. package/dist/cjs/import/AsepriteImporter.js +761 -0
  22. package/dist/cjs/import/AsepriteImporter.js.map +1 -0
  23. package/dist/cjs/import/DragonBonesImporter.js +499 -0
  24. package/dist/cjs/import/DragonBonesImporter.js.map +1 -0
  25. package/dist/cjs/import/GameMakerImporter.js +559 -0
  26. package/dist/cjs/import/GameMakerImporter.js.map +1 -0
  27. package/dist/cjs/import/GodotSceneImporter.js +824 -0
  28. package/dist/cjs/import/GodotSceneImporter.js.map +1 -0
  29. package/dist/cjs/import/LDtkImporter.js +481 -0
  30. package/dist/cjs/import/LDtkImporter.js.map +1 -0
  31. package/dist/cjs/import/Live2DImporter.js +553 -0
  32. package/dist/cjs/import/Live2DImporter.js.map +1 -0
  33. package/dist/cjs/import/NdgFormat.js +499 -0
  34. package/dist/cjs/import/NdgFormat.js.map +1 -0
  35. package/dist/cjs/import/OgmoImporter.js +529 -0
  36. package/dist/cjs/import/OgmoImporter.js.map +1 -0
  37. package/dist/cjs/import/RPGMakerImporter.js +520 -0
  38. package/dist/cjs/import/RPGMakerImporter.js.map +1 -0
  39. package/dist/cjs/import/SceneImporter.js +449 -0
  40. package/dist/cjs/import/SceneImporter.js.map +1 -0
  41. package/dist/cjs/import/SpineImporter.js +583 -0
  42. package/dist/cjs/import/SpineImporter.js.map +1 -0
  43. package/dist/cjs/import/SpriterImporter.js +652 -0
  44. package/dist/cjs/import/SpriterImporter.js.map +1 -0
  45. package/dist/cjs/import/TiledMapImporter.js +859 -0
  46. package/dist/cjs/import/TiledMapImporter.js.map +1 -0
  47. package/dist/cjs/import/UnitySceneImporter.js +732 -0
  48. package/dist/cjs/import/UnitySceneImporter.js.map +1 -0
  49. package/dist/cjs/import/index.js +305 -0
  50. package/dist/cjs/import/index.js.map +1 -0
  51. package/dist/cjs/index.js +201 -0
  52. package/dist/cjs/index.js.map +1 -1
  53. package/dist/cjs/scripting/GraphToAST.js +567 -0
  54. package/dist/cjs/scripting/GraphToAST.js.map +1 -0
  55. package/dist/cjs/scripting/LanguageExporter.js +321 -0
  56. package/dist/cjs/scripting/LanguageExporter.js.map +1 -0
  57. package/dist/cjs/scripting/ScriptAST.js +67 -0
  58. package/dist/cjs/scripting/ScriptAST.js.map +1 -0
  59. package/dist/cjs/scripting/VisualScripting2.js +1140 -0
  60. package/dist/cjs/scripting/VisualScripting2.js.map +1 -0
  61. package/dist/cjs/scripting/exporters/CSharpExporter.js +503 -0
  62. package/dist/cjs/scripting/exporters/CSharpExporter.js.map +1 -0
  63. package/dist/cjs/scripting/exporters/GDScriptExporter.js +452 -0
  64. package/dist/cjs/scripting/exporters/GDScriptExporter.js.map +1 -0
  65. package/dist/cjs/scripting/exporters/LuaExporter.js +457 -0
  66. package/dist/cjs/scripting/exporters/LuaExporter.js.map +1 -0
  67. package/dist/cjs/scripting/exporters/PythonExporter.js +565 -0
  68. package/dist/cjs/scripting/exporters/PythonExporter.js.map +1 -0
  69. package/dist/cjs/scripting/exporters/RustExporter.js +525 -0
  70. package/dist/cjs/scripting/exporters/RustExporter.js.map +1 -0
  71. package/dist/cjs/scripting/exporters/TypeScriptExporter.js +570 -0
  72. package/dist/cjs/scripting/exporters/TypeScriptExporter.js.map +1 -0
  73. package/dist/cjs/systems/ParticleSystem2.js +1478 -0
  74. package/dist/cjs/systems/ParticleSystem2.js.map +1 -0
  75. package/dist/esm/ai/BehaviorTree.js +1186 -0
  76. package/dist/esm/ai/BehaviorTree.js.map +1 -0
  77. package/dist/esm/ai/StateMachine.js +767 -0
  78. package/dist/esm/ai/StateMachine.js.map +1 -0
  79. package/dist/esm/editor/ShaderGraph.js +1606 -0
  80. package/dist/esm/editor/ShaderGraph.js.map +1 -0
  81. package/dist/esm/editor/TimelineEditor.js +800 -0
  82. package/dist/esm/editor/TimelineEditor.js.map +1 -0
  83. package/dist/esm/export/GodotExporter.js +1100 -0
  84. package/dist/esm/export/GodotExporter.js.map +1 -0
  85. package/dist/esm/export/PlatformExporter.js +230 -0
  86. package/dist/esm/export/PlatformExporter.js.map +1 -0
  87. package/dist/esm/export/ThreeJSExporter.js +1114 -0
  88. package/dist/esm/export/ThreeJSExporter.js.map +1 -0
  89. package/dist/esm/export/UnityExporter.js +1191 -0
  90. package/dist/esm/export/UnityExporter.js.map +1 -0
  91. package/dist/esm/export/WebExporter.js +1033 -0
  92. package/dist/esm/export/WebExporter.js.map +1 -0
  93. package/dist/esm/export/index.js +44 -0
  94. package/dist/esm/export/index.js.map +1 -0
  95. package/dist/esm/import/AsepriteImporter.js +759 -0
  96. package/dist/esm/import/AsepriteImporter.js.map +1 -0
  97. package/dist/esm/import/DragonBonesImporter.js +496 -0
  98. package/dist/esm/import/DragonBonesImporter.js.map +1 -0
  99. package/dist/esm/import/GameMakerImporter.js +556 -0
  100. package/dist/esm/import/GameMakerImporter.js.map +1 -0
  101. package/dist/esm/import/GodotSceneImporter.js +822 -0
  102. package/dist/esm/import/GodotSceneImporter.js.map +1 -0
  103. package/dist/esm/import/LDtkImporter.js +479 -0
  104. package/dist/esm/import/LDtkImporter.js.map +1 -0
  105. package/dist/esm/import/Live2DImporter.js +550 -0
  106. package/dist/esm/import/Live2DImporter.js.map +1 -0
  107. package/dist/esm/import/NdgFormat.js +490 -0
  108. package/dist/esm/import/NdgFormat.js.map +1 -0
  109. package/dist/esm/import/OgmoImporter.js +526 -0
  110. package/dist/esm/import/OgmoImporter.js.map +1 -0
  111. package/dist/esm/import/RPGMakerImporter.js +517 -0
  112. package/dist/esm/import/RPGMakerImporter.js.map +1 -0
  113. package/dist/esm/import/SceneImporter.js +441 -0
  114. package/dist/esm/import/SceneImporter.js.map +1 -0
  115. package/dist/esm/import/SpineImporter.js +580 -0
  116. package/dist/esm/import/SpineImporter.js.map +1 -0
  117. package/dist/esm/import/SpriterImporter.js +649 -0
  118. package/dist/esm/import/SpriterImporter.js.map +1 -0
  119. package/dist/esm/import/TiledMapImporter.js +857 -0
  120. package/dist/esm/import/TiledMapImporter.js.map +1 -0
  121. package/dist/esm/import/UnitySceneImporter.js +730 -0
  122. package/dist/esm/import/UnitySceneImporter.js.map +1 -0
  123. package/dist/esm/import/index.js +279 -0
  124. package/dist/esm/import/index.js.map +1 -0
  125. package/dist/esm/index.js +36 -0
  126. package/dist/esm/index.js.map +1 -1
  127. package/dist/esm/scripting/GraphToAST.js +564 -0
  128. package/dist/esm/scripting/GraphToAST.js.map +1 -0
  129. package/dist/esm/scripting/LanguageExporter.js +311 -0
  130. package/dist/esm/scripting/LanguageExporter.js.map +1 -0
  131. package/dist/esm/scripting/ScriptAST.js +52 -0
  132. package/dist/esm/scripting/ScriptAST.js.map +1 -0
  133. package/dist/esm/scripting/VisualScripting2.js +1130 -0
  134. package/dist/esm/scripting/VisualScripting2.js.map +1 -0
  135. package/dist/esm/scripting/exporters/CSharpExporter.js +501 -0
  136. package/dist/esm/scripting/exporters/CSharpExporter.js.map +1 -0
  137. package/dist/esm/scripting/exporters/GDScriptExporter.js +450 -0
  138. package/dist/esm/scripting/exporters/GDScriptExporter.js.map +1 -0
  139. package/dist/esm/scripting/exporters/LuaExporter.js +455 -0
  140. package/dist/esm/scripting/exporters/LuaExporter.js.map +1 -0
  141. package/dist/esm/scripting/exporters/PythonExporter.js +563 -0
  142. package/dist/esm/scripting/exporters/PythonExporter.js.map +1 -0
  143. package/dist/esm/scripting/exporters/RustExporter.js +523 -0
  144. package/dist/esm/scripting/exporters/RustExporter.js.map +1 -0
  145. package/dist/esm/scripting/exporters/TypeScriptExporter.js +568 -0
  146. package/dist/esm/scripting/exporters/TypeScriptExporter.js.map +1 -0
  147. package/dist/esm/systems/ParticleSystem2.js +1471 -0
  148. package/dist/esm/systems/ParticleSystem2.js.map +1 -0
  149. package/dist/types/ai/BehaviorTree.d.ts +375 -0
  150. package/dist/types/ai/StateMachine.d.ts +296 -0
  151. package/dist/types/editor/ShaderGraph.d.ts +207 -0
  152. package/dist/types/editor/TimelineEditor.d.ts +393 -0
  153. package/dist/types/export/GodotExporter.d.ts +56 -0
  154. package/dist/types/export/PlatformExporter.d.ts +201 -0
  155. package/dist/types/export/ThreeJSExporter.d.ts +40 -0
  156. package/dist/types/export/UnityExporter.d.ts +69 -0
  157. package/dist/types/export/WebExporter.d.ts +58 -0
  158. package/dist/types/export/index.d.ts +19 -0
  159. package/dist/types/import/AsepriteImporter.d.ts +46 -0
  160. package/dist/types/import/DragonBonesImporter.d.ts +331 -0
  161. package/dist/types/import/GameMakerImporter.d.ts +375 -0
  162. package/dist/types/import/GodotSceneImporter.d.ts +34 -0
  163. package/dist/types/import/LDtkImporter.d.ts +177 -0
  164. package/dist/types/import/Live2DImporter.d.ts +237 -0
  165. package/dist/types/import/NdgFormat.d.ts +387 -0
  166. package/dist/types/import/OgmoImporter.d.ts +237 -0
  167. package/dist/types/import/RPGMakerImporter.d.ts +186 -0
  168. package/dist/types/import/SceneImporter.d.ts +276 -0
  169. package/dist/types/import/SpineImporter.d.ts +372 -0
  170. package/dist/types/import/SpriterImporter.d.ts +230 -0
  171. package/dist/types/import/TiledMapImporter.d.ts +57 -0
  172. package/dist/types/import/UnitySceneImporter.d.ts +87 -0
  173. package/dist/types/import/index.d.ts +59 -0
  174. package/dist/types/index.d.ts +29 -17
  175. package/dist/types/scripting/GraphToAST.d.ts +55 -0
  176. package/dist/types/scripting/LanguageExporter.d.ts +136 -0
  177. package/dist/types/scripting/ScriptAST.d.ts +312 -0
  178. package/dist/types/scripting/VisualScripting2.d.ts +353 -0
  179. package/dist/types/scripting/exporters/CSharpExporter.d.ts +44 -0
  180. package/dist/types/scripting/exporters/GDScriptExporter.d.ts +46 -0
  181. package/dist/types/scripting/exporters/LuaExporter.d.ts +46 -0
  182. package/dist/types/scripting/exporters/PythonExporter.d.ts +49 -0
  183. package/dist/types/scripting/exporters/RustExporter.d.ts +46 -0
  184. package/dist/types/scripting/exporters/TypeScriptExporter.d.ts +48 -0
  185. package/dist/types/scripting/exporters/index.d.ts +8 -0
  186. package/dist/types/scripting/index.d.ts +11 -0
  187. package/dist/types/systems/ParticleSystem2.d.ts +646 -0
  188. package/package.json +3 -3
@@ -0,0 +1,1215 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * @file BehaviorTree.ts
5
+ * @description Behavior Tree System with Graphical Editor Support
6
+ * PRO-1.4: Professional Editor Features
7
+ *
8
+ * Features:
9
+ * - Full behavior tree implementation
10
+ * - Composite nodes (Selector, Sequence, Parallel)
11
+ * - Decorator nodes (Inverter, Repeater, Succeeder, etc.)
12
+ * - Leaf nodes (Actions, Conditions)
13
+ * - Real-time preview and debugging
14
+ * - Blackboard system for shared data
15
+ * - Subtree support
16
+ * - Serialization support
17
+ */
18
+ /** Blackboard for sharing data between nodes */
19
+ class BTBlackboard {
20
+ constructor() {
21
+ this.data = new Map();
22
+ this.types = new Map();
23
+ this.listeners = new Map();
24
+ }
25
+ /** Set a value in the blackboard */
26
+ set(key, value) {
27
+ const name = typeof key === 'string' ? key : key.name;
28
+ const oldValue = this.data.get(name);
29
+ this.data.set(name, value);
30
+ if (typeof key !== 'string') {
31
+ this.types.set(name, key.type);
32
+ }
33
+ // Notify listeners
34
+ if (oldValue !== value) {
35
+ const callbacks = this.listeners.get(name);
36
+ if (callbacks) {
37
+ for (const cb of callbacks) {
38
+ cb(value);
39
+ }
40
+ }
41
+ }
42
+ }
43
+ /** Get a value from the blackboard */
44
+ get(key) {
45
+ const name = typeof key === 'string' ? key : key.name;
46
+ const value = this.data.get(name);
47
+ if (value === undefined && typeof key !== 'string' && key.defaultValue !== undefined) {
48
+ return key.defaultValue;
49
+ }
50
+ return value;
51
+ }
52
+ /** Check if key exists */
53
+ has(key) {
54
+ const name = typeof key === 'string' ? key : key.name;
55
+ return this.data.has(name);
56
+ }
57
+ /** Remove a key */
58
+ delete(key) {
59
+ const name = typeof key === 'string' ? key : key.name;
60
+ this.data.delete(name);
61
+ this.types.delete(name);
62
+ }
63
+ /** Clear all data */
64
+ clear() {
65
+ this.data.clear();
66
+ }
67
+ /** Subscribe to key changes */
68
+ subscribe(key, callback) {
69
+ const name = typeof key === 'string' ? key : key.name;
70
+ let callbacks = this.listeners.get(name);
71
+ if (!callbacks) {
72
+ callbacks = [];
73
+ this.listeners.set(name, callbacks);
74
+ }
75
+ callbacks.push(callback);
76
+ // Return unsubscribe function
77
+ return () => {
78
+ const idx = callbacks.indexOf(callback);
79
+ if (idx >= 0) {
80
+ callbacks.splice(idx, 1);
81
+ }
82
+ };
83
+ }
84
+ /** Get all keys */
85
+ keys() {
86
+ return Array.from(this.data.keys());
87
+ }
88
+ /** Clone the blackboard */
89
+ clone() {
90
+ const bb = new BTBlackboard();
91
+ for (const [key, value] of this.data) {
92
+ bb.data.set(key, value);
93
+ }
94
+ for (const [key, type] of this.types) {
95
+ bb.types.set(key, type);
96
+ }
97
+ return bb;
98
+ }
99
+ /** Export to JSON */
100
+ toJSON() {
101
+ const result = {};
102
+ for (const [key, value] of this.data) {
103
+ result[key] = value;
104
+ }
105
+ return result;
106
+ }
107
+ /** Import from JSON */
108
+ fromJSON(data) {
109
+ for (const [key, value] of Object.entries(data)) {
110
+ this.data.set(key, value);
111
+ }
112
+ }
113
+ }
114
+ /** Base class for all behavior tree nodes */
115
+ class BTNode {
116
+ constructor(type, category, name) {
117
+ /** Position in editor */
118
+ this.position = { x: 0, y: 0 };
119
+ /** Custom properties */
120
+ this.properties = {};
121
+ /** Current execution status (for debugging) */
122
+ this.lastStatus = 'inactive';
123
+ /** Last execution time (for profiling) */
124
+ this.lastExecutionTime = 0;
125
+ this.id = `bt_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
126
+ this.type = type;
127
+ this.category = category;
128
+ this.name = name;
129
+ }
130
+ /** Initialize the node */
131
+ initialize(context) { }
132
+ /** Reset the node state */
133
+ reset() {
134
+ this.lastStatus = 'inactive';
135
+ }
136
+ /** Called when execution is aborted */
137
+ abort() {
138
+ this.lastStatus = 'aborted';
139
+ }
140
+ /** Serialize to JSON */
141
+ toJSON() {
142
+ return {
143
+ id: this.id,
144
+ type: this.type,
145
+ category: this.category,
146
+ name: this.name,
147
+ position: this.position,
148
+ properties: this.properties,
149
+ comment: this.comment,
150
+ };
151
+ }
152
+ }
153
+ // ============================================================
154
+ // Composite Nodes
155
+ // ============================================================
156
+ /** Base class for composite nodes (have children) */
157
+ class BTComposite extends BTNode {
158
+ constructor(type, name) {
159
+ super(type, 'composite', name);
160
+ this.children = [];
161
+ this.currentChild = 0;
162
+ }
163
+ addChild(child) {
164
+ this.children.push(child);
165
+ }
166
+ removeChild(child) {
167
+ const idx = this.children.indexOf(child);
168
+ if (idx >= 0) {
169
+ this.children.splice(idx, 1);
170
+ }
171
+ }
172
+ reset() {
173
+ super.reset();
174
+ this.currentChild = 0;
175
+ for (const child of this.children) {
176
+ child.reset();
177
+ }
178
+ }
179
+ abort() {
180
+ super.abort();
181
+ // Abort currently running child
182
+ if (this.currentChild < this.children.length) {
183
+ this.children[this.currentChild].abort();
184
+ }
185
+ }
186
+ toJSON() {
187
+ return {
188
+ ...super.toJSON(),
189
+ children: this.children.map((c) => c.toJSON()),
190
+ };
191
+ }
192
+ }
193
+ /** Sequence: Runs children in order until one fails */
194
+ class BTSequence extends BTComposite {
195
+ constructor(name = 'Sequence') {
196
+ super('sequence', name);
197
+ }
198
+ tick(context) {
199
+ while (this.currentChild < this.children.length) {
200
+ const child = this.children[this.currentChild];
201
+ const status = child.tick(context);
202
+ child.lastStatus = status;
203
+ if (status === 'running') {
204
+ this.lastStatus = 'running';
205
+ return 'running';
206
+ }
207
+ if (status === 'failure') {
208
+ this.currentChild = 0;
209
+ this.lastStatus = 'failure';
210
+ return 'failure';
211
+ }
212
+ this.currentChild++;
213
+ }
214
+ this.currentChild = 0;
215
+ this.lastStatus = 'success';
216
+ return 'success';
217
+ }
218
+ clone() {
219
+ const node = new BTSequence(this.name);
220
+ node.properties = { ...this.properties };
221
+ node.position = { ...this.position };
222
+ node.children = this.children.map((c) => c.clone());
223
+ return node;
224
+ }
225
+ }
226
+ /** Selector: Runs children until one succeeds */
227
+ class BTSelector extends BTComposite {
228
+ constructor(name = 'Selector') {
229
+ super('selector', name);
230
+ }
231
+ tick(context) {
232
+ while (this.currentChild < this.children.length) {
233
+ const child = this.children[this.currentChild];
234
+ const status = child.tick(context);
235
+ child.lastStatus = status;
236
+ if (status === 'running') {
237
+ this.lastStatus = 'running';
238
+ return 'running';
239
+ }
240
+ if (status === 'success') {
241
+ this.currentChild = 0;
242
+ this.lastStatus = 'success';
243
+ return 'success';
244
+ }
245
+ this.currentChild++;
246
+ }
247
+ this.currentChild = 0;
248
+ this.lastStatus = 'failure';
249
+ return 'failure';
250
+ }
251
+ clone() {
252
+ const node = new BTSelector(this.name);
253
+ node.properties = { ...this.properties };
254
+ node.position = { ...this.position };
255
+ node.children = this.children.map((c) => c.clone());
256
+ return node;
257
+ }
258
+ }
259
+ /** Parallel: Runs all children simultaneously */
260
+ class BTParallel extends BTComposite {
261
+ constructor(name = 'Parallel') {
262
+ super('parallel', name);
263
+ /** Policy for determining success */
264
+ this.successPolicy = 'all';
265
+ /** Policy for determining failure */
266
+ this.failurePolicy = 'one';
267
+ this.childStatuses = [];
268
+ }
269
+ initialize(context) {
270
+ this.childStatuses = new Array(this.children.length).fill('running');
271
+ }
272
+ tick(context) {
273
+ let successCount = 0;
274
+ let failureCount = 0;
275
+ let runningCount = 0;
276
+ for (let i = 0; i < this.children.length; i++) {
277
+ // Skip already completed children
278
+ if (this.childStatuses[i] !== 'running') {
279
+ if (this.childStatuses[i] === 'success')
280
+ successCount++;
281
+ else if (this.childStatuses[i] === 'failure')
282
+ failureCount++;
283
+ continue;
284
+ }
285
+ const child = this.children[i];
286
+ const status = child.tick(context);
287
+ child.lastStatus = status;
288
+ this.childStatuses[i] = status;
289
+ if (status === 'success')
290
+ successCount++;
291
+ else if (status === 'failure')
292
+ failureCount++;
293
+ else
294
+ runningCount++;
295
+ }
296
+ // Check failure policy
297
+ if (this.failurePolicy === 'one' && failureCount > 0) {
298
+ this.reset();
299
+ this.lastStatus = 'failure';
300
+ return 'failure';
301
+ }
302
+ if (this.failurePolicy === 'all' && failureCount === this.children.length) {
303
+ this.reset();
304
+ this.lastStatus = 'failure';
305
+ return 'failure';
306
+ }
307
+ // Check success policy
308
+ if (this.successPolicy === 'one' && successCount > 0) {
309
+ this.reset();
310
+ this.lastStatus = 'success';
311
+ return 'success';
312
+ }
313
+ if (this.successPolicy === 'all' && successCount === this.children.length) {
314
+ this.reset();
315
+ this.lastStatus = 'success';
316
+ return 'success';
317
+ }
318
+ // Still running
319
+ if (runningCount > 0) {
320
+ this.lastStatus = 'running';
321
+ return 'running';
322
+ }
323
+ // Mixed results, depends on policy
324
+ this.reset();
325
+ this.lastStatus = 'failure';
326
+ return 'failure';
327
+ }
328
+ reset() {
329
+ super.reset();
330
+ this.childStatuses = [];
331
+ }
332
+ clone() {
333
+ const node = new BTParallel(this.name);
334
+ node.properties = { ...this.properties };
335
+ node.position = { ...this.position };
336
+ node.successPolicy = this.successPolicy;
337
+ node.failurePolicy = this.failurePolicy;
338
+ node.children = this.children.map((c) => c.clone());
339
+ return node;
340
+ }
341
+ }
342
+ /** Random Selector: Selects children in random order */
343
+ class BTRandomSelector extends BTComposite {
344
+ constructor(name = 'Random Selector') {
345
+ super('randomSelector', name);
346
+ this.shuffledOrder = [];
347
+ }
348
+ initialize(context) {
349
+ this.shuffle();
350
+ }
351
+ shuffle() {
352
+ this.shuffledOrder = this.children.map((_, i) => i);
353
+ for (let i = this.shuffledOrder.length - 1; i > 0; i--) {
354
+ const j = Math.floor(Math.random() * (i + 1));
355
+ [this.shuffledOrder[i], this.shuffledOrder[j]] = [
356
+ this.shuffledOrder[j],
357
+ this.shuffledOrder[i],
358
+ ];
359
+ }
360
+ }
361
+ tick(context) {
362
+ while (this.currentChild < this.shuffledOrder.length) {
363
+ const childIdx = this.shuffledOrder[this.currentChild];
364
+ const child = this.children[childIdx];
365
+ const status = child.tick(context);
366
+ child.lastStatus = status;
367
+ if (status === 'running') {
368
+ this.lastStatus = 'running';
369
+ return 'running';
370
+ }
371
+ if (status === 'success') {
372
+ this.currentChild = 0;
373
+ this.shuffle();
374
+ this.lastStatus = 'success';
375
+ return 'success';
376
+ }
377
+ this.currentChild++;
378
+ }
379
+ this.currentChild = 0;
380
+ this.shuffle();
381
+ this.lastStatus = 'failure';
382
+ return 'failure';
383
+ }
384
+ clone() {
385
+ const node = new BTRandomSelector(this.name);
386
+ node.properties = { ...this.properties };
387
+ node.position = { ...this.position };
388
+ node.children = this.children.map((c) => c.clone());
389
+ return node;
390
+ }
391
+ }
392
+ /** Random Sequence: Runs children in random order */
393
+ class BTRandomSequence extends BTComposite {
394
+ constructor(name = 'Random Sequence') {
395
+ super('randomSequence', name);
396
+ this.shuffledOrder = [];
397
+ }
398
+ initialize(context) {
399
+ this.shuffle();
400
+ }
401
+ shuffle() {
402
+ this.shuffledOrder = this.children.map((_, i) => i);
403
+ for (let i = this.shuffledOrder.length - 1; i > 0; i--) {
404
+ const j = Math.floor(Math.random() * (i + 1));
405
+ [this.shuffledOrder[i], this.shuffledOrder[j]] = [
406
+ this.shuffledOrder[j],
407
+ this.shuffledOrder[i],
408
+ ];
409
+ }
410
+ }
411
+ tick(context) {
412
+ while (this.currentChild < this.shuffledOrder.length) {
413
+ const childIdx = this.shuffledOrder[this.currentChild];
414
+ const child = this.children[childIdx];
415
+ const status = child.tick(context);
416
+ child.lastStatus = status;
417
+ if (status === 'running') {
418
+ this.lastStatus = 'running';
419
+ return 'running';
420
+ }
421
+ if (status === 'failure') {
422
+ this.currentChild = 0;
423
+ this.shuffle();
424
+ this.lastStatus = 'failure';
425
+ return 'failure';
426
+ }
427
+ this.currentChild++;
428
+ }
429
+ this.currentChild = 0;
430
+ this.shuffle();
431
+ this.lastStatus = 'success';
432
+ return 'success';
433
+ }
434
+ clone() {
435
+ const node = new BTRandomSequence(this.name);
436
+ node.properties = { ...this.properties };
437
+ node.position = { ...this.position };
438
+ node.children = this.children.map((c) => c.clone());
439
+ return node;
440
+ }
441
+ }
442
+ // ============================================================
443
+ // Decorator Nodes
444
+ // ============================================================
445
+ /** Base class for decorator nodes (single child) */
446
+ class BTDecorator extends BTNode {
447
+ constructor(type, name) {
448
+ super(type, 'decorator', name);
449
+ this.child = null;
450
+ }
451
+ setChild(child) {
452
+ this.child = child;
453
+ }
454
+ reset() {
455
+ var _a;
456
+ super.reset();
457
+ (_a = this.child) === null || _a === void 0 ? void 0 : _a.reset();
458
+ }
459
+ abort() {
460
+ var _a;
461
+ super.abort();
462
+ (_a = this.child) === null || _a === void 0 ? void 0 : _a.abort();
463
+ }
464
+ toJSON() {
465
+ return {
466
+ ...super.toJSON(),
467
+ children: this.child ? [this.child.toJSON()] : [],
468
+ };
469
+ }
470
+ }
471
+ /** Inverter: Inverts child's result */
472
+ class BTInverter extends BTDecorator {
473
+ constructor(name = 'Inverter') {
474
+ super('inverter', name);
475
+ }
476
+ tick(context) {
477
+ if (!this.child) {
478
+ this.lastStatus = 'failure';
479
+ return 'failure';
480
+ }
481
+ const status = this.child.tick(context);
482
+ this.child.lastStatus = status;
483
+ if (status === 'running') {
484
+ this.lastStatus = 'running';
485
+ return 'running';
486
+ }
487
+ const inverted = status === 'success' ? 'failure' : 'success';
488
+ this.lastStatus = inverted;
489
+ return inverted;
490
+ }
491
+ clone() {
492
+ var _a;
493
+ const node = new BTInverter(this.name);
494
+ node.properties = { ...this.properties };
495
+ node.position = { ...this.position };
496
+ node.child = ((_a = this.child) === null || _a === void 0 ? void 0 : _a.clone()) || null;
497
+ return node;
498
+ }
499
+ }
500
+ /** Succeeder: Always returns success */
501
+ class BTSucceeder extends BTDecorator {
502
+ constructor(name = 'Succeeder') {
503
+ super('succeeder', name);
504
+ }
505
+ tick(context) {
506
+ if (!this.child) {
507
+ this.lastStatus = 'success';
508
+ return 'success';
509
+ }
510
+ const status = this.child.tick(context);
511
+ this.child.lastStatus = status;
512
+ if (status === 'running') {
513
+ this.lastStatus = 'running';
514
+ return 'running';
515
+ }
516
+ this.lastStatus = 'success';
517
+ return 'success';
518
+ }
519
+ clone() {
520
+ var _a;
521
+ const node = new BTSucceeder(this.name);
522
+ node.properties = { ...this.properties };
523
+ node.position = { ...this.position };
524
+ node.child = ((_a = this.child) === null || _a === void 0 ? void 0 : _a.clone()) || null;
525
+ return node;
526
+ }
527
+ }
528
+ /** Failer: Always returns failure */
529
+ class BTFailer extends BTDecorator {
530
+ constructor(name = 'Failer') {
531
+ super('failer', name);
532
+ }
533
+ tick(context) {
534
+ if (!this.child) {
535
+ this.lastStatus = 'failure';
536
+ return 'failure';
537
+ }
538
+ const status = this.child.tick(context);
539
+ this.child.lastStatus = status;
540
+ if (status === 'running') {
541
+ this.lastStatus = 'running';
542
+ return 'running';
543
+ }
544
+ this.lastStatus = 'failure';
545
+ return 'failure';
546
+ }
547
+ clone() {
548
+ var _a;
549
+ const node = new BTFailer(this.name);
550
+ node.properties = { ...this.properties };
551
+ node.position = { ...this.position };
552
+ node.child = ((_a = this.child) === null || _a === void 0 ? void 0 : _a.clone()) || null;
553
+ return node;
554
+ }
555
+ }
556
+ /** Repeater: Repeats child N times */
557
+ class BTRepeater extends BTDecorator {
558
+ constructor(name = 'Repeater', times = -1) {
559
+ super('repeater', name);
560
+ this.times = -1; // -1 = infinite
561
+ this.currentCount = 0;
562
+ this.times = times;
563
+ }
564
+ tick(context) {
565
+ if (!this.child) {
566
+ this.lastStatus = 'failure';
567
+ return 'failure';
568
+ }
569
+ while (this.times === -1 || this.currentCount < this.times) {
570
+ const status = this.child.tick(context);
571
+ this.child.lastStatus = status;
572
+ if (status === 'running') {
573
+ this.lastStatus = 'running';
574
+ return 'running';
575
+ }
576
+ this.currentCount++;
577
+ this.child.reset();
578
+ }
579
+ this.currentCount = 0;
580
+ this.lastStatus = 'success';
581
+ return 'success';
582
+ }
583
+ reset() {
584
+ super.reset();
585
+ this.currentCount = 0;
586
+ }
587
+ clone() {
588
+ var _a;
589
+ const node = new BTRepeater(this.name, this.times);
590
+ node.properties = { ...this.properties };
591
+ node.position = { ...this.position };
592
+ node.child = ((_a = this.child) === null || _a === void 0 ? void 0 : _a.clone()) || null;
593
+ return node;
594
+ }
595
+ }
596
+ /** RepeatUntilFail: Repeats until child fails */
597
+ class BTRepeatUntilFail extends BTDecorator {
598
+ constructor(name = 'Repeat Until Fail') {
599
+ super('repeatUntilFail', name);
600
+ }
601
+ tick(context) {
602
+ if (!this.child) {
603
+ this.lastStatus = 'failure';
604
+ return 'failure';
605
+ }
606
+ const status = this.child.tick(context);
607
+ this.child.lastStatus = status;
608
+ if (status === 'failure') {
609
+ this.lastStatus = 'success';
610
+ return 'success';
611
+ }
612
+ if (status === 'running') {
613
+ this.lastStatus = 'running';
614
+ return 'running';
615
+ }
616
+ // Success - reset and continue
617
+ this.child.reset();
618
+ this.lastStatus = 'running';
619
+ return 'running';
620
+ }
621
+ clone() {
622
+ var _a;
623
+ const node = new BTRepeatUntilFail(this.name);
624
+ node.properties = { ...this.properties };
625
+ node.position = { ...this.position };
626
+ node.child = ((_a = this.child) === null || _a === void 0 ? void 0 : _a.clone()) || null;
627
+ return node;
628
+ }
629
+ }
630
+ /** RepeatUntilSuccess: Repeats until child succeeds */
631
+ class BTRepeatUntilSuccess extends BTDecorator {
632
+ constructor(name = 'Repeat Until Success') {
633
+ super('repeatUntilSuccess', name);
634
+ }
635
+ tick(context) {
636
+ if (!this.child) {
637
+ this.lastStatus = 'failure';
638
+ return 'failure';
639
+ }
640
+ const status = this.child.tick(context);
641
+ this.child.lastStatus = status;
642
+ if (status === 'success') {
643
+ this.lastStatus = 'success';
644
+ return 'success';
645
+ }
646
+ if (status === 'running') {
647
+ this.lastStatus = 'running';
648
+ return 'running';
649
+ }
650
+ // Failure - reset and continue
651
+ this.child.reset();
652
+ this.lastStatus = 'running';
653
+ return 'running';
654
+ }
655
+ clone() {
656
+ var _a;
657
+ const node = new BTRepeatUntilSuccess(this.name);
658
+ node.properties = { ...this.properties };
659
+ node.position = { ...this.position };
660
+ node.child = ((_a = this.child) === null || _a === void 0 ? void 0 : _a.clone()) || null;
661
+ return node;
662
+ }
663
+ }
664
+ /** Timeout: Fails if child takes too long */
665
+ class BTTimeout extends BTDecorator {
666
+ constructor(name = 'Timeout', seconds = 5) {
667
+ super('timeout', name);
668
+ this.elapsed = 0;
669
+ this.started = false;
670
+ this.timeoutSeconds = seconds;
671
+ }
672
+ tick(context) {
673
+ if (!this.child) {
674
+ this.lastStatus = 'failure';
675
+ return 'failure';
676
+ }
677
+ if (!this.started) {
678
+ this.elapsed = 0;
679
+ this.started = true;
680
+ }
681
+ this.elapsed += context.dt;
682
+ if (this.elapsed >= this.timeoutSeconds) {
683
+ this.child.abort();
684
+ this.started = false;
685
+ this.lastStatus = 'failure';
686
+ return 'failure';
687
+ }
688
+ const status = this.child.tick(context);
689
+ this.child.lastStatus = status;
690
+ if (status !== 'running') {
691
+ this.started = false;
692
+ }
693
+ this.lastStatus = status;
694
+ return status;
695
+ }
696
+ reset() {
697
+ super.reset();
698
+ this.elapsed = 0;
699
+ this.started = false;
700
+ }
701
+ clone() {
702
+ var _a;
703
+ const node = new BTTimeout(this.name, this.timeoutSeconds);
704
+ node.properties = { ...this.properties };
705
+ node.position = { ...this.position };
706
+ node.child = ((_a = this.child) === null || _a === void 0 ? void 0 : _a.clone()) || null;
707
+ return node;
708
+ }
709
+ }
710
+ /** Cooldown: Rate limits child execution */
711
+ class BTCooldown extends BTDecorator {
712
+ constructor(name = 'Cooldown', seconds = 1) {
713
+ super('cooldown', name);
714
+ this.lastExecution = -Infinity;
715
+ this.cooldownSeconds = seconds;
716
+ }
717
+ tick(context) {
718
+ if (!this.child) {
719
+ this.lastStatus = 'failure';
720
+ return 'failure';
721
+ }
722
+ const elapsed = context.time - this.lastExecution;
723
+ if (elapsed < this.cooldownSeconds) {
724
+ this.lastStatus = 'failure';
725
+ return 'failure';
726
+ }
727
+ const status = this.child.tick(context);
728
+ this.child.lastStatus = status;
729
+ if (status !== 'running') {
730
+ this.lastExecution = context.time;
731
+ }
732
+ this.lastStatus = status;
733
+ return status;
734
+ }
735
+ reset() {
736
+ super.reset();
737
+ // Don't reset lastExecution - cooldown should persist
738
+ }
739
+ clone() {
740
+ var _a;
741
+ const node = new BTCooldown(this.name, this.cooldownSeconds);
742
+ node.properties = { ...this.properties };
743
+ node.position = { ...this.position };
744
+ node.child = ((_a = this.child) === null || _a === void 0 ? void 0 : _a.clone()) || null;
745
+ return node;
746
+ }
747
+ }
748
+ /** Condition Guard: Only runs child if condition is true */
749
+ class BTConditionGuard extends BTDecorator {
750
+ constructor(name = 'Guard', condition = () => true) {
751
+ super('guard', name);
752
+ this.condition = condition;
753
+ }
754
+ tick(context) {
755
+ if (!this.child) {
756
+ this.lastStatus = 'failure';
757
+ return 'failure';
758
+ }
759
+ if (!this.condition(context)) {
760
+ this.lastStatus = 'failure';
761
+ return 'failure';
762
+ }
763
+ const status = this.child.tick(context);
764
+ this.child.lastStatus = status;
765
+ this.lastStatus = status;
766
+ return status;
767
+ }
768
+ clone() {
769
+ var _a;
770
+ const node = new BTConditionGuard(this.name, this.condition);
771
+ node.properties = { ...this.properties };
772
+ node.position = { ...this.position };
773
+ node.child = ((_a = this.child) === null || _a === void 0 ? void 0 : _a.clone()) || null;
774
+ return node;
775
+ }
776
+ }
777
+ /** Wait Action: Waits for a duration */
778
+ class BTWait extends BTNode {
779
+ constructor(name = 'Wait', seconds = 1) {
780
+ super('wait', 'action', name);
781
+ this.elapsed = 0;
782
+ this.started = false;
783
+ this.seconds = seconds;
784
+ }
785
+ tick(context) {
786
+ if (!this.started) {
787
+ this.elapsed = 0;
788
+ this.started = true;
789
+ }
790
+ this.elapsed += context.dt;
791
+ if (this.elapsed >= this.seconds) {
792
+ this.started = false;
793
+ this.lastStatus = 'success';
794
+ return 'success';
795
+ }
796
+ this.lastStatus = 'running';
797
+ return 'running';
798
+ }
799
+ reset() {
800
+ super.reset();
801
+ this.elapsed = 0;
802
+ this.started = false;
803
+ }
804
+ clone() {
805
+ const node = new BTWait(this.name, this.seconds);
806
+ node.properties = { ...this.properties };
807
+ node.position = { ...this.position };
808
+ return node;
809
+ }
810
+ }
811
+ /** Log Action: Logs a message */
812
+ class BTLog extends BTNode {
813
+ constructor(name = 'Log', message = '', level = 'info') {
814
+ super('log', 'action', name);
815
+ this.message = message;
816
+ this.level = level;
817
+ }
818
+ tick(context) {
819
+ console.log(`[BT ${this.level}] ${this.message}`);
820
+ this.lastStatus = 'success';
821
+ return 'success';
822
+ }
823
+ clone() {
824
+ const node = new BTLog(this.name, this.message, this.level);
825
+ node.properties = { ...this.properties };
826
+ node.position = { ...this.position };
827
+ return node;
828
+ }
829
+ }
830
+ // ============================================================
831
+ // Subtree Node
832
+ // ============================================================
833
+ class BTSubtree extends BTNode {
834
+ constructor(name, subtreeId) {
835
+ super('subtree', 'subtree', name);
836
+ this.subtree = null;
837
+ this.subtreeId = subtreeId;
838
+ }
839
+ setSubtree(tree) {
840
+ this.subtree = tree;
841
+ }
842
+ tick(context) {
843
+ if (!this.subtree) {
844
+ this.lastStatus = 'failure';
845
+ return 'failure';
846
+ }
847
+ const status = this.subtree.tick(context);
848
+ this.lastStatus = status;
849
+ return status;
850
+ }
851
+ reset() {
852
+ var _a;
853
+ super.reset();
854
+ (_a = this.subtree) === null || _a === void 0 ? void 0 : _a.reset();
855
+ }
856
+ clone() {
857
+ var _a;
858
+ const node = new BTSubtree(this.name, this.subtreeId);
859
+ node.properties = { ...this.properties };
860
+ node.position = { ...this.position };
861
+ node.subtree = ((_a = this.subtree) === null || _a === void 0 ? void 0 : _a.clone()) || null;
862
+ return node;
863
+ }
864
+ }
865
+ // ============================================================
866
+ // Root Node
867
+ // ============================================================
868
+ class BTRoot extends BTNode {
869
+ constructor(name = 'Root') {
870
+ super('root', 'root', name);
871
+ this.child = null;
872
+ }
873
+ setChild(child) {
874
+ this.child = child;
875
+ }
876
+ tick(context) {
877
+ if (!this.child) {
878
+ this.lastStatus = 'success';
879
+ return 'success';
880
+ }
881
+ const status = this.child.tick(context);
882
+ this.child.lastStatus = status;
883
+ this.lastStatus = status;
884
+ return status;
885
+ }
886
+ reset() {
887
+ var _a;
888
+ super.reset();
889
+ (_a = this.child) === null || _a === void 0 ? void 0 : _a.reset();
890
+ }
891
+ toJSON() {
892
+ return {
893
+ ...super.toJSON(),
894
+ children: this.child ? [this.child.toJSON()] : [],
895
+ };
896
+ }
897
+ clone() {
898
+ var _a;
899
+ const node = new BTRoot(this.name);
900
+ node.properties = { ...this.properties };
901
+ node.position = { ...this.position };
902
+ node.child = ((_a = this.child) === null || _a === void 0 ? void 0 : _a.clone()) || null;
903
+ return node;
904
+ }
905
+ }
906
+ // ============================================================
907
+ // Behavior Tree
908
+ // ============================================================
909
+ class BehaviorTree {
910
+ constructor(name = 'Behavior Tree') {
911
+ /** Execution statistics */
912
+ this.stats = {
913
+ tickCount: 0,
914
+ lastTickTime: 0,
915
+ averageTickTime: 0,
916
+ };
917
+ /** Debugging */
918
+ this.debugMode = false;
919
+ this.breakpoints = new Set();
920
+ this.isPaused = false;
921
+ this.id = `tree_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
922
+ this.name = name;
923
+ this.root = new BTRoot();
924
+ this.blackboard = new BTBlackboard();
925
+ }
926
+ /** Tick the tree */
927
+ tick(context) {
928
+ if (this.isPaused) {
929
+ return 'running';
930
+ }
931
+ // Merge blackboards
932
+ const mergedContext = {
933
+ ...context,
934
+ blackboard: this.blackboard,
935
+ };
936
+ const startTime = performance.now();
937
+ const status = this.root.tick(mergedContext);
938
+ const endTime = performance.now();
939
+ // Update stats
940
+ this.stats.tickCount++;
941
+ this.stats.lastTickTime = endTime - startTime;
942
+ this.stats.averageTickTime =
943
+ (this.stats.averageTickTime * (this.stats.tickCount - 1) + this.stats.lastTickTime) /
944
+ this.stats.tickCount;
945
+ return status;
946
+ }
947
+ /** Reset the tree */
948
+ reset() {
949
+ this.root.reset();
950
+ }
951
+ /** Pause execution */
952
+ pause() {
953
+ this.isPaused = true;
954
+ }
955
+ /** Resume execution */
956
+ resume() {
957
+ this.isPaused = false;
958
+ }
959
+ /** Add breakpoint */
960
+ addBreakpoint(nodeId) {
961
+ this.breakpoints.add(nodeId);
962
+ }
963
+ /** Remove breakpoint */
964
+ removeBreakpoint(nodeId) {
965
+ this.breakpoints.delete(nodeId);
966
+ }
967
+ /** Toggle breakpoint */
968
+ toggleBreakpoint(nodeId) {
969
+ if (this.breakpoints.has(nodeId)) {
970
+ this.breakpoints.delete(nodeId);
971
+ }
972
+ else {
973
+ this.breakpoints.add(nodeId);
974
+ }
975
+ }
976
+ /** Find node by ID */
977
+ findNode(nodeId) {
978
+ return this.findNodeRecursive(this.root, nodeId);
979
+ }
980
+ findNodeRecursive(node, nodeId) {
981
+ if (node.id === nodeId)
982
+ return node;
983
+ if (node instanceof BTComposite) {
984
+ for (const child of node.children) {
985
+ const found = this.findNodeRecursive(child, nodeId);
986
+ if (found)
987
+ return found;
988
+ }
989
+ }
990
+ else if (node instanceof BTDecorator && node.child) {
991
+ return this.findNodeRecursive(node.child, nodeId);
992
+ }
993
+ else if (node instanceof BTRoot && node.child) {
994
+ return this.findNodeRecursive(node.child, nodeId);
995
+ }
996
+ return null;
997
+ }
998
+ /** Get all nodes */
999
+ getAllNodes() {
1000
+ const nodes = [];
1001
+ this.collectNodes(this.root, nodes);
1002
+ return nodes;
1003
+ }
1004
+ collectNodes(node, nodes) {
1005
+ nodes.push(node);
1006
+ if (node instanceof BTComposite) {
1007
+ for (const child of node.children) {
1008
+ this.collectNodes(child, nodes);
1009
+ }
1010
+ }
1011
+ else if (node instanceof BTDecorator && node.child) {
1012
+ this.collectNodes(node.child, nodes);
1013
+ }
1014
+ else if (node instanceof BTRoot && node.child) {
1015
+ this.collectNodes(node.child, nodes);
1016
+ }
1017
+ }
1018
+ /** Clone the tree */
1019
+ clone() {
1020
+ const tree = new BehaviorTree(this.name);
1021
+ tree.root = this.root.clone();
1022
+ tree.blackboard = this.blackboard.clone();
1023
+ return tree;
1024
+ }
1025
+ /** Serialize to JSON */
1026
+ toJSON() {
1027
+ return {
1028
+ id: this.id,
1029
+ name: this.name,
1030
+ root: this.root.toJSON(),
1031
+ blackboard: this.blackboard.toJSON(),
1032
+ };
1033
+ }
1034
+ }
1035
+ // ============================================================
1036
+ // Node Registry
1037
+ // ============================================================
1038
+ class BTNodeRegistry {
1039
+ constructor() {
1040
+ this.definitions = new Map();
1041
+ }
1042
+ register(definition) {
1043
+ this.definitions.set(definition.type, definition);
1044
+ }
1045
+ get(type) {
1046
+ return this.definitions.get(type);
1047
+ }
1048
+ getAll() {
1049
+ return Array.from(this.definitions.values());
1050
+ }
1051
+ getByCategory(category) {
1052
+ return this.getAll().filter((d) => d.category === category);
1053
+ }
1054
+ createNode(type, properties) {
1055
+ const def = this.definitions.get(type);
1056
+ if (!def)
1057
+ return null;
1058
+ return def.create(properties);
1059
+ }
1060
+ }
1061
+ // ============================================================
1062
+ // Factory Functions
1063
+ // ============================================================
1064
+ function createBehaviorTree(name) {
1065
+ return new BehaviorTree(name);
1066
+ }
1067
+ function createBlackboard() {
1068
+ return new BTBlackboard();
1069
+ }
1070
+ function createNodeRegistry() {
1071
+ const registry = new BTNodeRegistry();
1072
+ // Register built-in nodes
1073
+ registry.register({
1074
+ type: 'sequence',
1075
+ category: 'composite',
1076
+ name: 'Sequence',
1077
+ description: 'Executes children in order until one fails',
1078
+ icon: 'arrow-right',
1079
+ color: '#3b82f6',
1080
+ create: () => new BTSequence(),
1081
+ });
1082
+ registry.register({
1083
+ type: 'selector',
1084
+ category: 'composite',
1085
+ name: 'Selector',
1086
+ description: 'Executes children until one succeeds',
1087
+ icon: 'git-branch',
1088
+ color: '#22c55e',
1089
+ create: () => new BTSelector(),
1090
+ });
1091
+ registry.register({
1092
+ type: 'parallel',
1093
+ category: 'composite',
1094
+ name: 'Parallel',
1095
+ description: 'Executes all children simultaneously',
1096
+ icon: 'layers',
1097
+ color: '#8b5cf6',
1098
+ properties: [
1099
+ { name: 'successPolicy', type: 'enum', enumValues: ['all', 'one'], default: 'all' },
1100
+ { name: 'failurePolicy', type: 'enum', enumValues: ['all', 'one'], default: 'one' },
1101
+ ],
1102
+ create: (props) => {
1103
+ const node = new BTParallel();
1104
+ if (props === null || props === void 0 ? void 0 : props.successPolicy)
1105
+ node.successPolicy = props.successPolicy;
1106
+ if (props === null || props === void 0 ? void 0 : props.failurePolicy)
1107
+ node.failurePolicy = props.failurePolicy;
1108
+ return node;
1109
+ },
1110
+ });
1111
+ registry.register({
1112
+ type: 'inverter',
1113
+ category: 'decorator',
1114
+ name: 'Inverter',
1115
+ description: 'Inverts the result of its child',
1116
+ icon: 'refresh-cw',
1117
+ color: '#f97316',
1118
+ create: () => new BTInverter(),
1119
+ });
1120
+ registry.register({
1121
+ type: 'repeater',
1122
+ category: 'decorator',
1123
+ name: 'Repeater',
1124
+ description: 'Repeats child N times (-1 = infinite)',
1125
+ icon: 'repeat',
1126
+ color: '#f97316',
1127
+ properties: [{ name: 'times', type: 'number', default: -1, min: -1 }],
1128
+ create: (props) => { var _a; return new BTRepeater('Repeater', (_a = props === null || props === void 0 ? void 0 : props.times) !== null && _a !== void 0 ? _a : -1); },
1129
+ });
1130
+ registry.register({
1131
+ type: 'timeout',
1132
+ category: 'decorator',
1133
+ name: 'Timeout',
1134
+ description: 'Fails if child takes too long',
1135
+ icon: 'clock',
1136
+ color: '#f97316',
1137
+ properties: [{ name: 'seconds', type: 'number', default: 5, min: 0 }],
1138
+ create: (props) => { var _a; return new BTTimeout('Timeout', (_a = props === null || props === void 0 ? void 0 : props.seconds) !== null && _a !== void 0 ? _a : 5); },
1139
+ });
1140
+ registry.register({
1141
+ type: 'wait',
1142
+ category: 'action',
1143
+ name: 'Wait',
1144
+ description: 'Waits for a duration',
1145
+ icon: 'pause',
1146
+ color: '#6b7280',
1147
+ properties: [{ name: 'seconds', type: 'number', default: 1, min: 0 }],
1148
+ create: (props) => { var _a; return new BTWait('Wait', (_a = props === null || props === void 0 ? void 0 : props.seconds) !== null && _a !== void 0 ? _a : 1); },
1149
+ });
1150
+ registry.register({
1151
+ type: 'log',
1152
+ category: 'action',
1153
+ name: 'Log',
1154
+ description: 'Logs a message',
1155
+ icon: 'message-square',
1156
+ color: '#6b7280',
1157
+ properties: [
1158
+ { name: 'message', type: 'string', default: '' },
1159
+ { name: 'level', type: 'enum', enumValues: ['info', 'warn', 'error'], default: 'info' },
1160
+ ],
1161
+ create: (props) => {
1162
+ var _a, _b;
1163
+ return new BTLog('Log', (_a = props === null || props === void 0 ? void 0 : props.message) !== null && _a !== void 0 ? _a : '', (_b = props === null || props === void 0 ? void 0 : props.level) !== null && _b !== void 0 ? _b : 'info');
1164
+ },
1165
+ });
1166
+ return registry;
1167
+ }
1168
+ /** Create execution context */
1169
+ function createBTContext(params) {
1170
+ let isAborted = false;
1171
+ return {
1172
+ entityId: params.entityId,
1173
+ blackboard: params.blackboard || new BTBlackboard(),
1174
+ dt: params.dt,
1175
+ time: params.time,
1176
+ world: params.world,
1177
+ emit: () => { },
1178
+ abort: () => {
1179
+ isAborted = true;
1180
+ },
1181
+ get isAborted() {
1182
+ return isAborted;
1183
+ },
1184
+ };
1185
+ }
1186
+
1187
+ exports.BTBlackboard = BTBlackboard;
1188
+ exports.BTComposite = BTComposite;
1189
+ exports.BTConditionGuard = BTConditionGuard;
1190
+ exports.BTCooldown = BTCooldown;
1191
+ exports.BTDecorator = BTDecorator;
1192
+ exports.BTFailer = BTFailer;
1193
+ exports.BTInverter = BTInverter;
1194
+ exports.BTLog = BTLog;
1195
+ exports.BTNode = BTNode;
1196
+ exports.BTNodeRegistry = BTNodeRegistry;
1197
+ exports.BTParallel = BTParallel;
1198
+ exports.BTRandomSelector = BTRandomSelector;
1199
+ exports.BTRandomSequence = BTRandomSequence;
1200
+ exports.BTRepeatUntilFail = BTRepeatUntilFail;
1201
+ exports.BTRepeatUntilSuccess = BTRepeatUntilSuccess;
1202
+ exports.BTRepeater = BTRepeater;
1203
+ exports.BTRoot = BTRoot;
1204
+ exports.BTSelector = BTSelector;
1205
+ exports.BTSequence = BTSequence;
1206
+ exports.BTSubtree = BTSubtree;
1207
+ exports.BTSucceeder = BTSucceeder;
1208
+ exports.BTTimeout = BTTimeout;
1209
+ exports.BTWait = BTWait;
1210
+ exports.BehaviorTree = BehaviorTree;
1211
+ exports.createBTContext = createBTContext;
1212
+ exports.createBehaviorTree = createBehaviorTree;
1213
+ exports.createBlackboard = createBlackboard;
1214
+ exports.createNodeRegistry = createNodeRegistry;
1215
+ //# sourceMappingURL=BehaviorTree.js.map