game-data-gen 4.0.1 → 6.0.0

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,20 +1,20 @@
1
1
  # Game Data Generation
2
2
 
3
- A Javascript (Typescript) library to generate data structures with zeroing functions.
3
+ A CLI code generator that creates Javascript (Typescript) data structures with zeroing functions.
4
4
 
5
5
  ## The problems
6
6
 
7
- If you're making a game in Javascript then you might (this was actually me):
7
+ If you're making a game in Javascript then you might:
8
8
 
9
9
  - hit the garbage collector (GC) a bunch causing frame drops because you're creating/destroying objects every frame (particles, for example)
10
10
  - read a book about [Data Oriented Design](https://www.amazon.com/dp/1916478700)
11
11
  - notice the performance implications of OOP (especially classes and calling their methods) versus using something like Structure of Arrays
12
- - wanting to implement Structure of Arrays instead of Array of Structures (which is a list of class instances, see previous point)
12
+ - want to implement Structure of Arrays instead of Array of Structures (which is a list of class instances, see previous point)
13
13
  - notice that Javascript can not simply zero out data structures (resetting all data back to initial values) like languages such as C and Rust
14
14
 
15
15
  ## The solution
16
16
 
17
- This library:
17
+ This tool:
18
18
 
19
19
  - creates data structures based on Markdown file (see example below)
20
20
  - each data structure gets associated functions to zero out its memory so it can be reused
@@ -31,54 +31,105 @@ npm i -D game-data-gen
31
31
  npx game-data-gen <input-file-path> <optional-output-file-path>
32
32
  ```
33
33
 
34
- ## Supported fields
34
+ ## Types
35
35
 
36
- ### group
36
+ Each block in the Markdown file starts with a heading that defines the type, followed by a list of fields.
37
37
 
38
- | Field type | Example |
39
- | --------------- | ------------------------------ |
40
- | `number` | `- health number` |
41
- | `array int8` | `- ids array int8 64` |
42
- | `array int16` | `- ids array int16 64` |
43
- | `array int32` | `- ids array int32 64` |
44
- | `array uint8` | `- ids array uint8 64` |
45
- | `array uint16` | `- ids array uint16 64` |
46
- | `array uint32` | `- ids array uint32 64` |
47
- | `array float32` | `- positions array float32 64` |
48
- | `array float64` | `- positions array float64 64` |
38
+ ### Group
49
39
 
50
- Array fields always require a length. A `count` variable and `push`/`pop` functions are generated to simulate a dynamic array within the fixed capacity.
40
+ ```
41
+ # <name> group
42
+ ```
43
+
44
+ A set of module-level variables with individual setter and zero functions, plus a combined zero function.
45
+
46
+ | Field type | Description |
47
+ | ----------- | --------------------------- |
48
+ | `string` | A string primitive |
49
+ | `number` | A number primitive |
50
+ | `boolean` | A boolean primitive |
51
+ | `string[]` | A dynamic array of strings |
52
+ | `number[]` | A dynamic array of numbers |
53
+ | `boolean[]` | A dynamic array of booleans |
54
+
55
+ ### Structure of Arrays (SOA)
56
+
57
+ ```
58
+ # <name> soa <capacity>
59
+ ```
51
60
 
52
- ### soa (Structure of Arrays)
61
+ A set of typed arrays of fixed capacity, ideal for cache-friendly iteration over many elements.
53
62
 
54
- | Field type | Example |
63
+ | Field type | Typed array |
55
64
  | ---------- | -------------- |
56
- | `int8` | `- val int8` |
57
- | `int16` | `- val int16` |
58
- | `int32` | `- val int32` |
59
- | `uint8` | `- val uint8` |
60
- | `uint16` | `- val uint16` |
61
- | `uint32` | `- val uint32` |
62
- | `float32` | `- x float32` |
63
- | `float64` | `- x float64` |
65
+ | `int8` | `Int8Array` |
66
+ | `int16` | `Int16Array` |
67
+ | `int32` | `Int32Array` |
68
+ | `uint8` | `Uint8Array` |
69
+ | `uint16` | `Uint16Array` |
70
+ | `uint32` | `Uint32Array` |
71
+ | `float32` | `Float32Array` |
72
+ | `float64` | `Float64Array` |
64
73
 
65
- ## Example
74
+ ### Struct
75
+
76
+ ```
77
+ # <name> struct
78
+ ```
66
79
 
67
- Create a Markdown file somewhere in your source code.
80
+ A TypeScript type with create, copy, and zero functions. Fields can be primitives, primitive arrays, or other structs.
68
81
 
69
- For example `src/data.md`:
82
+ | Field type | Description |
83
+ | ----------- | ---------------------------------------------------- |
84
+ | `string` | A string primitive |
85
+ | `number` | A number primitive |
86
+ | `boolean` | A boolean primitive |
87
+ | `string[]` | A dynamic array of strings |
88
+ | `number[]` | A dynamic array of numbers |
89
+ | `boolean[]` | A dynamic array of booleans |
90
+ | `<name>` | A nested struct (must be defined before this struct) |
91
+
92
+ ### Array of Structures (AOS)
93
+
94
+ ```
95
+ # <name> aos <capacity> <struct>
96
+ ```
97
+
98
+ A pre-allocated fixed-length array of struct objects.
99
+
100
+ ## Example
101
+
102
+ Create a Markdown file somewhere in your source code, for example `src/data.md`:
70
103
 
71
104
  ```md
72
105
  # game group
73
106
 
74
- - playerId number
75
- - entityIds array uint16 64
107
+ - score number
108
+ - name string
109
+ - isPaused boolean
110
+ - enemies number[]
76
111
 
77
- # particle soa 10_000
112
+ # particles soa 256
78
113
 
79
- - active uint8
80
114
  - x float32
81
115
  - y float32
116
+ - lifetime float32
117
+ - type int8
118
+
119
+ # Vector2 struct
120
+
121
+ - x number
122
+ - y number
123
+
124
+ # Entity struct
125
+
126
+ - name string
127
+ - health number
128
+ - isActive boolean
129
+ - position Vector2
130
+ - tags string[]
131
+
132
+ # entities aos 64 Entity
82
133
  ```
83
134
 
84
135
  Run the package with (consider making this a script in your package.json):
@@ -96,79 +147,180 @@ This will create or update the `src/data.ts` file (see below). The data and func
96
147
  * --------------------------------------------------
97
148
  */
98
149
 
99
- export let playerId = 0;
100
- export const entityIds = new Uint16Array(64);
101
- export let entityIdsCount = 0;
150
+ export let score = 0;
151
+ export let name = "";
152
+ export let isPaused = false;
153
+ export const enemies: Array<number> = [];
154
+
155
+ /** Set the value of the score field within the game group. */
156
+ export function setScore(v: number) {
157
+ score = v;
158
+ }
102
159
 
103
- /** Set the value of the playerId field within the game group. */
104
- export function setPlayerId(v: number) {
105
- playerId = v;
160
+ /** Set the value of the name field within the game group. */
161
+ export function setName(v: string) {
162
+ name = v;
106
163
  }
107
164
 
108
- /** Push a value onto the entityIds field within the game group. */
109
- export function pushEntityIds(v: number) {
110
- entityIds[entityIdsCount++] = v;
165
+ /** Set the value of the isPaused field within the game group. */
166
+ export function setIsPaused(v: boolean) {
167
+ isPaused = v;
111
168
  }
112
169
 
113
- /** Pop a value from the entityIds field within the game group. */
114
- export function popEntityIds() {
115
- return entityIds[--entityIdsCount];
170
+ /** Zero the score field within the game group. */
171
+ export function zeroScore() {
172
+ score = 0;
116
173
  }
117
174
 
118
- /** Zero the playerId field within the game group. */
119
- export function zeroPlayerId() {
120
- playerId = 0;
175
+ /** Zero the name field within the game group. */
176
+ export function zeroName() {
177
+ name = "";
121
178
  }
122
179
 
123
- /** Zero the entityIds field within the game group. */
124
- export function zeroEntityIds() {
125
- entityIdsCount = 0;
180
+ /** Zero the isPaused field within the game group. */
181
+ export function zeroIsPaused() {
182
+ isPaused = false;
183
+ }
184
+
185
+ /** Zero the enemies field within the game group. */
186
+ export function zeroEnemies() {
187
+ enemies.length = 0;
126
188
  }
127
189
 
128
190
  /** Zero all fields within the game group. */
129
191
  export function zeroGame() {
130
- playerId = 0;
131
- entityIdsCount = 0;
192
+ score = 0;
193
+ name = "";
194
+ isPaused = false;
195
+ enemies.length = 0;
132
196
  }
133
197
 
134
198
  /*
135
199
  * --------------------------------------------------
136
- * particle (Structure Of Arrays)
200
+ * particles (Structure Of Arrays)
137
201
  * --------------------------------------------------
138
202
  */
139
203
 
140
- export const MAX_PARTICLE_COUNT = 10_000;
204
+ export const MAX_PARTICLES_COUNT = 256;
141
205
 
142
- export const active = new Uint8Array(10_000);
143
- export const x = new Float32Array(10_000);
144
- export const y = new Float32Array(10_000);
206
+ export const x = new Float32Array(256);
207
+ export const y = new Float32Array(256);
208
+ export const lifetime = new Float32Array(256);
209
+ export const type = new Int8Array(256);
145
210
 
146
- /** Zero an index within the particle structure of arrays. */
147
- export function zeroParticleAt(i: number) {
148
- active[i] = 0;
211
+ /** Zero an index within the particles structure of arrays. */
212
+ export function zeroParticlesAt(i: number) {
149
213
  x[i] = 0;
150
214
  y[i] = 0;
215
+ lifetime[i] = 0;
216
+ type[i] = 0;
217
+ }
218
+
219
+ /** Zero all fields within the particles structure of arrays. */
220
+ export function zeroParticles() {
221
+ x.fill(0);
222
+ y.fill(0);
223
+ lifetime.fill(0);
224
+ type.fill(0);
151
225
  }
152
226
 
153
- /** Zero the active field within the particle structure of arrays. */
154
- export function zeroActive() {
155
- active.fill(0);
227
+ /*
228
+ * --------------------------------------------------
229
+ * Vector2 (Struct)
230
+ * --------------------------------------------------
231
+ */
232
+
233
+ export type Vector2 = {
234
+ x: number;
235
+ y: number;
236
+ };
237
+
238
+ /** Create a new Vector2 object. */
239
+ export function createVector2() {
240
+ const obj: Vector2 = Object.create(null);
241
+ obj.x = 0;
242
+ obj.y = 0;
243
+ return obj;
156
244
  }
157
245
 
158
- /** Zero the x field within the particle structure of arrays. */
159
- export function zeroX() {
160
- x.fill(0);
246
+ /** Copy the values of Vector2 object b into Vector2 object a. */
247
+ export function copyVector2(a: Vector2, b: Vector2) {
248
+ a.x = b.x;
249
+ a.y = b.y;
161
250
  }
162
251
 
163
- /** Zero the y field within the particle structure of arrays. */
164
- export function zeroY() {
165
- y.fill(0);
252
+ /** Zero the given Vector2 object. */
253
+ export function zeroVector2(obj: Vector2) {
254
+ obj.x = 0;
255
+ obj.y = 0;
166
256
  }
167
257
 
168
- /** Zero all fields within the particle structure of arrays. */
169
- export function zeroParticle() {
170
- active.fill(0);
171
- x.fill(0);
172
- y.fill(0);
258
+ /*
259
+ * --------------------------------------------------
260
+ * Entity (Struct)
261
+ * --------------------------------------------------
262
+ */
263
+
264
+ export type Entity = {
265
+ name: string;
266
+ health: number;
267
+ isActive: boolean;
268
+ position: Vector2;
269
+ tags: string[];
270
+ };
271
+
272
+ /** Create a new Entity object. */
273
+ export function createEntity() {
274
+ const obj: Entity = Object.create(null);
275
+ obj.name = "";
276
+ obj.health = 0;
277
+ obj.isActive = false;
278
+ obj.position = createVector2();
279
+ obj.tags = [];
280
+ return obj;
281
+ }
282
+
283
+ /** Copy the values of Entity object b into Entity object a. */
284
+ export function copyEntity(a: Entity, b: Entity) {
285
+ a.name = b.name;
286
+ a.health = b.health;
287
+ a.isActive = b.isActive;
288
+ copyVector2(a.position, b.position);
289
+ a.tags.length = b.tags.length;
290
+ for (let i = 0; i < b.tags.length; i++) {
291
+ a.tags[i] = b.tags[i];
292
+ }
293
+ }
294
+
295
+ /** Zero the given Entity object. */
296
+ export function zeroEntity(obj: Entity) {
297
+ obj.name = "";
298
+ obj.health = 0;
299
+ obj.isActive = false;
300
+ zeroVector2(obj.position);
301
+ obj.tags.length = 0;
302
+ }
303
+
304
+ /*
305
+ * --------------------------------------------------
306
+ * entities (Array Of Structures)
307
+ * --------------------------------------------------
308
+ */
309
+
310
+ export const MAX_ENTITIES_COUNT = 64;
311
+
312
+ /** An array of Entity objects (structures). */
313
+ export const entities = Array.from({ length: 64 }, createEntity);
314
+
315
+ /** Zero all objects within the entities array of structures. */
316
+ export function zeroEntities() {
317
+ for (let i = 0; i < 64; i++) {
318
+ zeroEntity(entities[i]);
319
+ }
320
+ }
321
+
322
+ /** Zero an object at a specific index within the entities array of structures. */
323
+ export function zeroEntitiesAt(index: number) {
324
+ zeroEntity(entities[index]);
173
325
  }
174
326
  ```
package/dist/consts.js CHANGED
@@ -1,21 +1,27 @@
1
1
  export var Type;
2
2
  (function (Type) {
3
- Type["SOA"] = "soa";
4
3
  Type["GROUP"] = "group";
4
+ Type["STRUCT"] = "struct";
5
+ Type["STRUCTURE_OF_ARRAYS"] = "soa";
6
+ Type["ARRAY_OF_STRUCTURES"] = "aos";
5
7
  })(Type || (Type = {}));
6
8
  export var FieldType;
7
9
  (function (FieldType) {
10
+ // Structure of Arrays
11
+ FieldType["INT_8"] = "int8";
12
+ FieldType["INT_16"] = "int16";
13
+ FieldType["INT_32"] = "int32";
14
+ FieldType["UINT_8"] = "uint8";
15
+ FieldType["UINT_16"] = "uint16";
16
+ FieldType["UINT_32"] = "uint32";
17
+ FieldType["FLOAT_32"] = "float32";
18
+ FieldType["FLOAT_64"] = "float64";
19
+ // Struct / Group
20
+ FieldType["STRING"] = "string";
8
21
  FieldType["NUMBER"] = "number";
9
- FieldType["ARRAY"] = "array";
22
+ FieldType["BOOLEAN"] = "boolean";
23
+ // Primitive arrays (Group and Struct)
24
+ FieldType["ARRAY_STRING"] = "string[]";
25
+ FieldType["ARRAY_NUMBER"] = "number[]";
26
+ FieldType["ARRAY_BOOLEAN"] = "boolean[]";
10
27
  })(FieldType || (FieldType = {}));
11
- export var ArrayType;
12
- (function (ArrayType) {
13
- ArrayType["INT_8"] = "int8";
14
- ArrayType["INT_16"] = "int16";
15
- ArrayType["INT_32"] = "int32";
16
- ArrayType["UINT_8"] = "uint8";
17
- ArrayType["UINT_16"] = "uint16";
18
- ArrayType["UINT_32"] = "uint32";
19
- ArrayType["FLOAT_32"] = "float32";
20
- ArrayType["FLOAT_64"] = "float64";
21
- })(ArrayType || (ArrayType = {}));
package/dist/lib/aos.js CHANGED
@@ -1,31 +1,33 @@
1
1
  import { addHeader, capitalize } from "./utils.js";
2
2
  export function addArrayOfStructures(header, output) {
3
- const [name, , length, type] = header.split(" ");
3
+ const [name, , length, struct] = header.split(" ");
4
4
  addHeader(`${name} (Array Of Structures)`, output);
5
5
  addFieldMaxLengthConstant(name, length, output);
6
- addArrayOfStructuresDefinition(name, type, length, output);
7
- addArrayOfStructuresZeroFunction(name, type, output);
8
- addArrayOfStructuresZeroAtIndexFunction(name, type, output);
6
+ addArrayOfStructuresDefinition(name, struct, length, output);
7
+ addArrayOfStructuresZeroFunction(name, struct, length, output);
8
+ addArrayOfStructuresZeroAtIndexFunction(name, struct, output);
9
9
  }
10
10
  function addFieldMaxLengthConstant(name, length, output) {
11
11
  output.push(`export const MAX_${name.toUpperCase()}_COUNT = ${length}`);
12
12
  output.push("");
13
13
  }
14
- function addArrayOfStructuresDefinition(name, type, length, output) {
15
- output.push(`/** An array of ${capitalize(type)} objects (structures). */`);
16
- output.push(`export const ${name} = Array.from({ length: ${length} }, create${capitalize(type)})`);
14
+ function addArrayOfStructuresDefinition(name, struct, length, output) {
15
+ output.push(`/** An array of ${struct} objects (structures). */`);
16
+ output.push(`export const ${name} = Array.from({ length: ${length} }, create${capitalize(struct)})`);
17
17
  }
18
- function addArrayOfStructuresZeroFunction(name, type, output) {
18
+ function addArrayOfStructuresZeroFunction(name, struct, length, output) {
19
19
  output.push("");
20
20
  output.push(`/** Zero all objects within the ${name} array of structures. */`);
21
21
  output.push(`export function zero${capitalize(name)}() {`);
22
- output.push(` ${name}.forEach(zero${capitalize(type)})`);
22
+ output.push(` for (let i=0; i<${length}; i++) {`);
23
+ output.push(` zero${capitalize(struct)}(${name}[i])`);
24
+ output.push(" }");
23
25
  output.push("}");
24
26
  }
25
- function addArrayOfStructuresZeroAtIndexFunction(name, type, output) {
27
+ function addArrayOfStructuresZeroAtIndexFunction(name, struct, output) {
26
28
  output.push("");
27
29
  output.push(`/** Zero an object at a specific index within the ${name} array of structures. */`);
28
- output.push(`export function zero${capitalize(name)}At(i: number) {`);
29
- output.push(` zero${capitalize(type)}(${name}[i])`);
30
+ output.push(`export function zero${capitalize(name)}At(index: number) {`);
31
+ output.push(` zero${capitalize(struct)}(${name}[index])`);
30
32
  output.push("}");
31
33
  }
package/dist/lib/group.js CHANGED
@@ -1,4 +1,4 @@
1
- import { ArrayType, FieldType } from "../consts.js";
1
+ import { FieldType } from "../consts.js";
2
2
  import { addHeader, capitalize } from "./utils.js";
3
3
  export function addGroup(header, fields, output) {
4
4
  const [name] = header.split(" ");
@@ -9,82 +9,58 @@ export function addGroup(header, fields, output) {
9
9
  for (const field of fields) {
10
10
  addFieldSetFunction(name, field, output);
11
11
  }
12
- for (const field of fields) {
13
- addFieldPushFunction(name, field, output);
14
- }
15
- for (const field of fields) {
16
- addFieldPopFunction(name, field, output);
17
- }
18
12
  for (const field of fields) {
19
13
  addFieldZeroFunction(name, field, output);
20
14
  }
21
15
  addZeroFunction(name, fields, output);
22
16
  }
23
17
  function addFieldDefinition(field, output) {
24
- const [fieldName, fieldType, fieldArrayType, fieldArrayLength] = field.split(" ");
18
+ const [fieldName, fieldType] = field.split(" ");
25
19
  switch (fieldType) {
20
+ case FieldType.STRING:
21
+ output.push(`export let ${fieldName} = ""`);
22
+ break;
26
23
  case FieldType.NUMBER:
27
24
  output.push(`export let ${fieldName} = 0`);
28
25
  break;
29
- case FieldType.ARRAY:
30
- switch (fieldArrayType) {
31
- case ArrayType.INT_8:
32
- output.push(`export const ${fieldName} = new Int8Array(${fieldArrayLength})`);
33
- break;
34
- case ArrayType.INT_16:
35
- output.push(`export const ${fieldName} = new Int16Array(${fieldArrayLength})`);
36
- break;
37
- case ArrayType.INT_32:
38
- output.push(`export const ${fieldName} = new Int32Array(${fieldArrayLength})`);
39
- break;
40
- case ArrayType.UINT_8:
41
- output.push(`export const ${fieldName} = new Uint8Array(${fieldArrayLength})`);
42
- break;
43
- case ArrayType.UINT_16:
44
- output.push(`export const ${fieldName} = new Uint16Array(${fieldArrayLength})`);
45
- break;
46
- case ArrayType.UINT_32:
47
- output.push(`export const ${fieldName} = new Uint32Array(${fieldArrayLength})`);
48
- break;
49
- case ArrayType.FLOAT_32:
50
- output.push(`export const ${fieldName} = new Float32Array(${fieldArrayLength})`);
51
- break;
52
- case ArrayType.FLOAT_64:
53
- output.push(`export const ${fieldName} = new Float64Array(${fieldArrayLength})`);
54
- break;
55
- }
56
- output.push(`export let ${fieldName}Count = 0`);
26
+ case FieldType.BOOLEAN:
27
+ output.push(`export let ${fieldName} = false`);
28
+ break;
29
+ case FieldType.ARRAY_STRING:
30
+ output.push(`export const ${fieldName}: Array<string> = []`);
31
+ break;
32
+ case FieldType.ARRAY_NUMBER:
33
+ output.push(`export const ${fieldName}: Array<number> = []`);
34
+ break;
35
+ case FieldType.ARRAY_BOOLEAN:
36
+ output.push(`export const ${fieldName}: Array<boolean> = []`);
57
37
  break;
58
38
  }
59
39
  }
60
40
  function addFieldSetFunction(name, field, output) {
61
41
  const [fieldName, fieldType] = field.split(" ");
62
- if (fieldType === FieldType.NUMBER) {
63
- output.push("");
64
- output.push(`/** Set the value of the ${fieldName} field within the ${name} group. */`);
65
- output.push(`export function set${capitalize(fieldName)}(v: number) {`);
66
- output.push(` ${fieldName} = v`);
67
- output.push("}");
68
- }
69
- }
70
- function addFieldPushFunction(name, field, output) {
71
- const [fieldName, fieldType] = field.split(" ");
72
- if (fieldType === FieldType.ARRAY) {
73
- output.push("");
74
- output.push(`/** Push a value onto the ${fieldName} field within the ${name} group. */`);
75
- output.push(`export function push${capitalize(fieldName)}(v: number) {`);
76
- output.push(` ${fieldName}[${fieldName}Count++] = v`);
77
- output.push("}");
78
- }
79
- }
80
- function addFieldPopFunction(name, field, output) {
81
- const [fieldName, fieldType] = field.split(" ");
82
- if (fieldType === FieldType.ARRAY) {
83
- output.push("");
84
- output.push(`/** Pop a value from the ${fieldName} field within the ${name} group. */`);
85
- output.push(`export function pop${capitalize(fieldName)}() {`);
86
- output.push(` return ${fieldName}[--${fieldName}Count]`);
87
- output.push("}");
42
+ switch (fieldType) {
43
+ case FieldType.STRING:
44
+ output.push("");
45
+ output.push(`/** Set the value of the ${fieldName} field within the ${name} group. */`);
46
+ output.push(`export function set${capitalize(fieldName)}(v: string) {`);
47
+ output.push(` ${fieldName} = v`);
48
+ output.push("}");
49
+ break;
50
+ case FieldType.NUMBER:
51
+ output.push("");
52
+ output.push(`/** Set the value of the ${fieldName} field within the ${name} group. */`);
53
+ output.push(`export function set${capitalize(fieldName)}(v: number) {`);
54
+ output.push(` ${fieldName} = v`);
55
+ output.push("}");
56
+ break;
57
+ case FieldType.BOOLEAN:
58
+ output.push("");
59
+ output.push(`/** Set the value of the ${fieldName} field within the ${name} group. */`);
60
+ output.push(`export function set${capitalize(fieldName)}(v: boolean) {`);
61
+ output.push(` ${fieldName} = v`);
62
+ output.push("}");
63
+ break;
88
64
  }
89
65
  }
90
66
  function addFieldZeroFunction(name, field, output) {
@@ -107,11 +83,19 @@ function addZeroFunction(name, fields, output) {
107
83
  }
108
84
  function zeroField(name, type, output) {
109
85
  switch (type) {
86
+ case FieldType.STRING:
87
+ output.push(` ${name} = ""`);
88
+ break;
110
89
  case FieldType.NUMBER:
111
90
  output.push(` ${name} = 0`);
112
91
  break;
113
- case FieldType.ARRAY:
114
- output.push(` ${name}Count = 0`);
92
+ case FieldType.BOOLEAN:
93
+ output.push(` ${name} = false`);
94
+ break;
95
+ case FieldType.ARRAY_STRING:
96
+ case FieldType.ARRAY_NUMBER:
97
+ case FieldType.ARRAY_BOOLEAN:
98
+ output.push(` ${name}.length = 0`);
115
99
  break;
116
100
  }
117
101
  }
package/dist/lib/soa.js CHANGED
@@ -1,4 +1,4 @@
1
- import { ArrayType } from "../consts.js";
1
+ import { FieldType } from "../consts.js";
2
2
  import { addHeader, capitalize } from "./utils.js";
3
3
  export function addStructureOfArrays(header, fields, output) {
4
4
  const [name, , length] = header.split(" ");
@@ -7,10 +7,7 @@ export function addStructureOfArrays(header, fields, output) {
7
7
  for (const field of fields) {
8
8
  addFieldDefinition(field, length, output);
9
9
  }
10
- addFieldZeroAtIndexFunction(name, fields, output);
11
- for (const field of fields) {
12
- addFieldZeroFunction(name, field, output);
13
- }
10
+ addZeroAtIndexFunction(name, fields, output);
14
11
  addZeroFunction(name, fields, output);
15
12
  }
16
13
  function addFieldMaxLengthConstant(name, length, output) {
@@ -20,40 +17,32 @@ function addFieldMaxLengthConstant(name, length, output) {
20
17
  function addFieldDefinition(field, length, output) {
21
18
  const [fieldName, fieldType] = field.split(" ");
22
19
  switch (fieldType) {
23
- case ArrayType.INT_8:
20
+ case FieldType.INT_8:
24
21
  output.push(`export const ${fieldName} = new Int8Array(${length})`);
25
22
  break;
26
- case ArrayType.INT_16:
23
+ case FieldType.INT_16:
27
24
  output.push(`export const ${fieldName} = new Int16Array(${length})`);
28
25
  break;
29
- case ArrayType.INT_32:
26
+ case FieldType.INT_32:
30
27
  output.push(`export const ${fieldName} = new Int32Array(${length})`);
31
28
  break;
32
- case ArrayType.UINT_8:
29
+ case FieldType.UINT_8:
33
30
  output.push(`export const ${fieldName} = new Uint8Array(${length})`);
34
31
  break;
35
- case ArrayType.UINT_16:
32
+ case FieldType.UINT_16:
36
33
  output.push(`export const ${fieldName} = new Uint16Array(${length})`);
37
34
  break;
38
- case ArrayType.UINT_32:
35
+ case FieldType.UINT_32:
39
36
  output.push(`export const ${fieldName} = new Uint32Array(${length})`);
40
37
  break;
41
- case ArrayType.FLOAT_32:
38
+ case FieldType.FLOAT_32:
42
39
  output.push(`export const ${fieldName} = new Float32Array(${length})`);
43
40
  break;
44
- case ArrayType.FLOAT_64:
41
+ case FieldType.FLOAT_64:
45
42
  output.push(`export const ${fieldName} = new Float64Array(${length})`);
46
43
  break;
47
44
  }
48
45
  }
49
- function addFieldZeroFunction(name, field, output) {
50
- const [fieldName] = field.split(" ");
51
- output.push("");
52
- output.push(`/** Zero the ${fieldName} field within the ${name} structure of arrays. */`);
53
- output.push(`export function zero${capitalize(fieldName)}() {`);
54
- output.push(` ${fieldName}.fill(0)`);
55
- output.push("}");
56
- }
57
46
  function addZeroFunction(name, fields, output) {
58
47
  output.push("");
59
48
  output.push(`/** Zero all fields within the ${name} structure of arrays. */`);
@@ -64,7 +53,7 @@ function addZeroFunction(name, fields, output) {
64
53
  }
65
54
  output.push("}");
66
55
  }
67
- function addFieldZeroAtIndexFunction(name, fields, output) {
56
+ function addZeroAtIndexFunction(name, fields, output) {
68
57
  output.push("");
69
58
  output.push(`/** Zero an index within the ${name} structure of arrays. */`);
70
59
  output.push(`export function zero${capitalize(name)}At(i: number) {`);
@@ -1,19 +1,18 @@
1
1
  import { FieldType } from "../consts.js";
2
- import { addHeader, capitalize, getTypeName } from "./utils.js";
2
+ import { addHeader, capitalize } from "./utils.js";
3
3
  export function addStruct(header, fields, output) {
4
4
  const [name] = header.split(" ");
5
5
  addHeader(`${name} (Struct)`, output);
6
6
  addStructTypeDefinition(name, fields, output);
7
7
  addStructCreateFunction(name, fields, output);
8
8
  addStructCopyFunction(name, fields, output);
9
- addStructCloneFunction(name, output);
10
9
  addStructZeroFunction(name, fields, output);
11
10
  }
12
11
  function addStructTypeDefinition(name, fields, output) {
13
12
  output.push(`export type ${capitalize(name)} = {`);
14
13
  for (const field of fields) {
15
14
  const [fieldName, fieldType] = field.split(" ");
16
- output.push(` ${fieldName}: ${getTypeName(fieldType)}`);
15
+ output.push(` ${fieldName}: ${fieldType}`);
17
16
  }
18
17
  output.push("}");
19
18
  }
@@ -21,18 +20,23 @@ function addStructCreateFunction(name, fields, output) {
21
20
  output.push("");
22
21
  output.push(`/** Create a new ${capitalize(name)} object. */`);
23
22
  output.push(`export function create${capitalize(name)}() {`);
24
- output.push(` const obj: ${getTypeName(name)} = Object.create(null)`);
23
+ output.push(` const obj: ${name} = Object.create(null)`);
25
24
  for (const field of fields) {
26
25
  const [fieldName, fieldType] = field.split(" ");
27
26
  switch (fieldType) {
28
27
  case FieldType.STRING:
29
28
  output.push(` obj.${fieldName} = ""`);
30
29
  break;
30
+ case FieldType.NUMBER:
31
+ output.push(` obj.${fieldName} = 0`);
32
+ break;
31
33
  case FieldType.BOOLEAN:
32
34
  output.push(` obj.${fieldName} = false`);
33
35
  break;
34
- case FieldType.NUMBER:
35
- output.push(` obj.${fieldName} = 0`);
36
+ case FieldType.ARRAY_STRING:
37
+ case FieldType.ARRAY_NUMBER:
38
+ case FieldType.ARRAY_BOOLEAN:
39
+ output.push(` obj.${fieldName} = []`);
36
40
  break;
37
41
  default:
38
42
  output.push(` obj.${fieldName} = create${capitalize(fieldType)}()`);
@@ -44,37 +48,49 @@ function addStructCreateFunction(name, fields, output) {
44
48
  function addStructCopyFunction(name, fields, output) {
45
49
  output.push("");
46
50
  output.push(`/** Copy the values of ${capitalize(name)} object b into ${capitalize(name)} object a. */`);
47
- output.push(`export function copy${capitalize(name)}(a: ${getTypeName(name)}, b: ${getTypeName(name)}) {`);
51
+ output.push(`export function copy${capitalize(name)}(a: ${name}, b: ${name}) {`);
48
52
  for (const field of fields) {
49
- const [fieldName] = field.split(" ");
50
- output.push(` a.${fieldName} = b.${fieldName}`);
53
+ const [fieldName, fieldType] = field.split(" ");
54
+ switch (fieldType) {
55
+ case FieldType.STRING:
56
+ case FieldType.NUMBER:
57
+ case FieldType.BOOLEAN:
58
+ output.push(` a.${fieldName} = b.${fieldName}`);
59
+ break;
60
+ case FieldType.ARRAY_STRING:
61
+ case FieldType.ARRAY_NUMBER:
62
+ case FieldType.ARRAY_BOOLEAN:
63
+ output.push(` a.${fieldName}.length = b.${fieldName}.length`);
64
+ output.push(` for (let i = 0; i < b.${fieldName}.length; i++) {`);
65
+ output.push(` a.${fieldName}[i] = b.${fieldName}[i]`);
66
+ output.push(` }`);
67
+ break;
68
+ default:
69
+ output.push(` copy${capitalize(fieldType)}(a.${fieldName}, b.${fieldName})`);
70
+ }
51
71
  }
52
72
  output.push("}");
53
73
  }
54
- function addStructCloneFunction(name, output) {
55
- output.push("");
56
- output.push(`/** Clone the given ${capitalize(name)} object. */`);
57
- output.push(`export function clone${capitalize(name)}(obj: ${getTypeName(name)}) {`);
58
- output.push(` const clone = create${capitalize(name)}()`);
59
- output.push(` copy${capitalize(name)}(clone, obj)`);
60
- output.push(" return clone");
61
- output.push("}");
62
- }
63
74
  function addStructZeroFunction(name, fields, output) {
64
75
  output.push("");
65
76
  output.push(`/** Zero the given ${capitalize(name)} object. */`);
66
- output.push(`export function zero${capitalize(name)}(obj: ${getTypeName(name)}) {`);
77
+ output.push(`export function zero${capitalize(name)}(obj: ${name}) {`);
67
78
  for (const field of fields) {
68
79
  const [fieldName, fieldType] = field.split(" ");
69
80
  switch (fieldType) {
70
81
  case FieldType.STRING:
71
82
  output.push(` obj.${fieldName} = ""`);
72
83
  break;
84
+ case FieldType.NUMBER:
85
+ output.push(` obj.${fieldName} = 0`);
86
+ break;
73
87
  case FieldType.BOOLEAN:
74
88
  output.push(` obj.${fieldName} = false`);
75
89
  break;
76
- case FieldType.NUMBER:
77
- output.push(` obj.${fieldName} = 0`);
90
+ case FieldType.ARRAY_STRING:
91
+ case FieldType.ARRAY_NUMBER:
92
+ case FieldType.ARRAY_BOOLEAN:
93
+ output.push(` obj.${fieldName}.length = 0`);
78
94
  break;
79
95
  default:
80
96
  output.push(` zero${capitalize(fieldType)}(obj.${fieldName})`);
package/dist/main.js CHANGED
@@ -2,8 +2,10 @@
2
2
  import fs from "node:fs";
3
3
  import { marked } from "marked";
4
4
  import { Type } from "./consts.js";
5
+ import { addArrayOfStructures } from "./lib/aos.js";
5
6
  import { addGroup } from "./lib/group.js";
6
7
  import { addStructureOfArrays } from "./lib/soa.js";
8
+ import { addStruct } from "./lib/struct.js";
7
9
  const inputFile = process.argv[2];
8
10
  const outputFile = process.argv[3] || inputFile.replace(".md", ".ts");
9
11
  const input = fs.readFileSync(inputFile, "utf-8");
@@ -43,7 +45,13 @@ for (const { header, fields } of blocks) {
43
45
  case Type.GROUP:
44
46
  addGroup(header, fields, output);
45
47
  break;
46
- case Type.SOA:
48
+ case Type.STRUCT:
49
+ addStruct(header, fields, output);
50
+ break;
51
+ case Type.ARRAY_OF_STRUCTURES:
52
+ addArrayOfStructures(header, output);
53
+ break;
54
+ case Type.STRUCTURE_OF_ARRAYS:
47
55
  addStructureOfArrays(header, fields, output);
48
56
  break;
49
57
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "game-data-gen",
3
- "version": "4.0.1",
3
+ "version": "6.0.0",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "dist"