game-data-gen 1.2.1 → 2.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.
Files changed (3) hide show
  1. package/README.md +128 -50
  2. package/dist/main.js +4 -173
  3. package/package.json +12 -9
package/README.md CHANGED
@@ -34,7 +34,7 @@ npx game-data-gen <input-file-path> <optional-output-file-path>
34
34
  ## Format
35
35
 
36
36
  ```
37
- name type? length?
37
+ name type? length? struct?
38
38
  fieldName fieldType fieldArrayType? fieldArrayLength?
39
39
  ```
40
40
 
@@ -46,9 +46,10 @@ The name of the data structure.
46
46
 
47
47
  Supported data structure types:
48
48
 
49
+ - group
50
+ - struct
49
51
  - soa (Structure of Arrays)
50
-
51
- If no type is given, it will act as a group which gets a zero function for the whole group.
52
+ - aos (Array of Structures)
52
53
 
53
54
  `length` (optional)
54
55
 
@@ -64,6 +65,9 @@ The name of one of the fields within the data structure.
64
65
 
65
66
  Supported field types:
66
67
 
68
+ - string
69
+ - number
70
+ - boolean
67
71
  - array
68
72
 
69
73
  `fieldArrayType` (optional, required if fieldType=array)
@@ -73,21 +77,17 @@ Supported array field types:
73
77
  - string
74
78
  - boolean
75
79
  - number
76
- - int8
77
- - int16
78
- - int32
79
- - uint8
80
- - uint16
81
- - uint32
82
- - float32
83
- - float64
84
80
 
85
81
  `fieldArrayLength` (optional)
86
82
 
87
- The length of the array field.
83
+ The length of the array field, leave empty to use a dynamically sized array instead of a fixed size array.
88
84
 
89
85
  In case of a Structure of Arrays data structure (type=soa), setting the length on the type instead is recommended so that all arrays have the same length.
90
86
 
87
+ `struct` (optional, required if type=aos)
88
+
89
+ The defined struct to use for this Array of Structures.
90
+
91
91
  ## Example
92
92
 
93
93
  Create a plain text file somewhere in your source code (without a file extension).
@@ -95,13 +95,24 @@ Create a plain text file somewhere in your source code (without a file extension
95
95
  For example `src/data/game`:
96
96
 
97
97
  ```
98
- Game
98
+ game group
99
99
  activeEntities array number
100
100
 
101
- Entity soa 2048
102
- posX array float32
103
- posY array float32
104
- isActive array uint8
101
+ vector struct
102
+ x number
103
+ y number
104
+
105
+ entity struct
106
+ position vector
107
+ velocity vector
108
+ health number
109
+ isActive boolean
110
+
111
+ entities aos 2048 entity
112
+
113
+ particle soa 1024
114
+ posX array number
115
+ posY array number
105
116
  ```
106
117
 
107
118
  Run the package with (consider making this a script in your package.json):
@@ -110,67 +121,134 @@ Run the package with (consider making this a script in your package.json):
110
121
  npx game-data-gen src/data/game
111
122
  ```
112
123
 
113
- This will create or update the `src/data/game.ts` file:
124
+ This will create or update the `src/data/game.ts` file which you can then import into your code:
114
125
 
115
126
  ```typescript
116
127
  /*
117
128
  * --------------------------------------------------
118
- * Game (group)
129
+ * game (group)
119
130
  * --------------------------------------------------
120
131
  */
121
132
 
122
- export const activeEntities = new Array<number>();
133
+ export const activeEntities = new Array<number>()
123
134
 
124
- /** Zero the activeEntities field within the Game group. */
135
+ /** Zero the activeEntities field within the game group. */
125
136
  export function zeroActiveEntities() {
126
- activeEntities.length = 0;
137
+ activeEntities.length = 0
127
138
  }
128
139
 
129
- /** Zero all fields within the Game group. */
140
+ /** Zero all fields within the game group. */
130
141
  export function zeroGameData() {
131
- activeEntities.length = 0;
142
+ activeEntities.length = 0
132
143
  }
133
144
 
134
145
  /*
135
146
  * --------------------------------------------------
136
- * Entity (Structure of Arrays)
147
+ * vector (struct)
137
148
  * --------------------------------------------------
138
149
  */
139
150
 
140
- export const MAX_ENTITY_COUNT = 2048;
151
+ export type Vector = {
152
+ x: number
153
+ y: number
154
+ }
155
+
156
+ /** Create a new Vector object. */
157
+ export function createVector(): Vector {
158
+ const obj = Object.create(null)
159
+ obj.x = 0
160
+ obj.y = 0
161
+ return obj
162
+ }
141
163
 
142
- export const posX = new Float32Array(2048);
143
- export const posY = new Float32Array(2048);
144
- export const isActive = new Uint8Array(2048);
164
+ /** Zero the given Vector object. */
165
+ export function zeroVector(obj: Vector) {
166
+ obj.x = 0
167
+ obj.y = 0
168
+ }
145
169
 
146
- /** Zero an index within the Entity Structure of Arrays. */
147
- export function zeroEntity(idx: number) {
148
- posX[idx] = 0;
149
- posY[idx] = 0;
150
- isActive[idx] = 0;
170
+ /*
171
+ * --------------------------------------------------
172
+ * entity (struct)
173
+ * --------------------------------------------------
174
+ */
175
+
176
+ export type Entity = {
177
+ position: Vector
178
+ velocity: Vector
179
+ health: number
180
+ isActive: boolean
151
181
  }
152
182
 
153
- /** Zero the posX field within the Entity Structure of Arrays. */
154
- export function zeroPosX() {
155
- posX.fill(0);
183
+ /** Create a new Entity object. */
184
+ export function createEntity(): Entity {
185
+ const obj = Object.create(null)
186
+ obj.position = createVector()
187
+ obj.velocity = createVector()
188
+ obj.health = 0
189
+ obj.isActive = false
190
+ return obj
156
191
  }
157
192
 
158
- /** Zero the posY field within the Entity Structure of Arrays. */
159
- export function zeroPosY() {
160
- posY.fill(0);
193
+ /** Zero the given Entity object. */
194
+ export function zeroEntity(obj: Entity) {
195
+ zeroVector(obj.position)
196
+ zeroVector(obj.velocity)
197
+ obj.health = 0
198
+ obj.isActive = false
199
+ }
200
+
201
+ /*
202
+ * --------------------------------------------------
203
+ * entities (array of structures)
204
+ * --------------------------------------------------
205
+ */
206
+
207
+ export const MAX_ENTITIES_COUNT = 2048
208
+
209
+ /** An array of Entity objects (structures). */
210
+ export const entities = new Array<Entity>(2048)
211
+ for (let i=0; i<2048; i++) {
212
+ entities[i] = createEntity()
213
+ }
214
+
215
+ /** Zero all objects within the entities array of structures. */
216
+ export function zeroEntities() {
217
+ for (let i=0; i<2048; i++) {
218
+ zeroEntity(entities[i])
219
+ }
220
+ }
221
+
222
+ /*
223
+ * --------------------------------------------------
224
+ * particle (structure of arrays)
225
+ * --------------------------------------------------
226
+ */
227
+
228
+ export const MAX_PARTICLE_COUNT = 1024
229
+
230
+ export const posX = new Array<number>(1024).fill(0)
231
+ export const posY = new Array<number>(1024).fill(0)
232
+
233
+ /** Zero an index within the particle structure of arrays. */
234
+ export function zeroParticle(idx: number) {
235
+ posX[idx] = 0
236
+ posY[idx] = 0
161
237
  }
162
238
 
163
- /** Zero the isActive field within the Entity Structure of Arrays. */
164
- export function zeroIsActive() {
165
- isActive.fill(0);
239
+ /** Zero the posX field within the particle structure of arrays. */
240
+ export function zeroPosX() {
241
+ posX.fill(0)
166
242
  }
167
243
 
168
- /** Zero all fields within the Entity Structure of Arrays. */
169
- export function zeroEntityData() {
170
- posX.fill(0);
171
- posY.fill(0);
172
- isActive.fill(0);
244
+ /** Zero the posY field within the particle structure of arrays. */
245
+ export function zeroPosY() {
246
+ posY.fill(0)
173
247
  }
174
- ```
175
248
 
176
- Then import the data and its functions from `src/data/game.ts` in your code.
249
+ /** Zero all fields within the particle structure of arrays. */
250
+ export function zeroParticleData() {
251
+ posX.fill(0)
252
+ posY.fill(0)
253
+ }
254
+ ```
package/dist/main.js CHANGED
@@ -1,175 +1,6 @@
1
1
  #!/usr/bin/env node
2
+ import S from"fs";function l(i){switch(i){case"soa":return"structure of arrays";case"aos":return"array of structures";case"struct":return"struct";case"group":return"group";default:return"???"}}function c(i){return`${i.substring(0,1).toUpperCase()}${i.substring(1)}`}function h(i,n,r){let[e,s,a,t]=i.split(" "),o=n||t||"";switch(s){case"string":r.push(`export let ${e} = ""`);break;case"number":r.push(`export let ${e} = 0`);break;case"boolean":r.push(`export let ${e} = false`);break;case"array":switch(a){case"string":r.push(`export const ${e} = new Array<string>(${o})${o?'.fill("")':""}`);break;case"number":r.push(`export const ${e} = new Array<number>(${o})${o?".fill(0)":""}`);break;case"boolean":r.push(`export const ${e} = new Array<boolean>(${o})${o?".fill(false)":""}`);break}break}}function d(i,n,r,e){let[s,a]=r.split(" ");switch(a){case"string":case"number":case"boolean":e.push(""),e.push(`/** Set the value of the ${s} field within the ${i} ${l(n)}. */`),e.push(`export function set${c(s)}(value: ${a}) {`),e.push(` ${s} = value`),e.push("}");break}}function p(i,n,r,e,s){let[a,t,o,A]=r.split(" "),b=e||A||"";s.push(""),s.push(`/** Zero the ${a} field within the ${i} ${l(n)}. */`),s.push(`export function zero${c(a)}() {`),N(a,t,o,b,s),s.push("}")}function $(i,n,r,e,s){s.push(""),s.push(`/** Zero all fields within the ${i} ${l(n)}. */`),s.push(`export function zero${c(i)}Data() {`);for(let a of r){let[t,o,A,b]=a.split(" ");N(t,o,A,e||b||"",s)}s.push("}")}function N(i,n,r,e,s){switch(n){case"string":s.push(` ${i} = ""`);break;case"number":s.push(` ${i} = 0`);break;case"boolean":s.push(` ${i} = false`);break;case"array":switch(r){case"string":s.push(` ${i}.${e?'fill("")':"length = 0"}`);break;case"number":s.push(` ${i}.${e?"fill(0)":"length = 0"}`);break;case"boolean":s.push(` ${i}.${e?"fill(false)":"length = 0"}`);break}break}}function g(i,n,r){r.push(`export const MAX_${i.toUpperCase()}_COUNT = ${n}`),r.push("")}function m(i,n,r){let[e,s,a]=i.split(" ");g(e,a,r);for(let t of n)h(t,a,r);for(let t of n)d(e,s,t,r);F(e,s,n,r);for(let t of n)p(e,s,t,a,r);$(e,s,n,a,r)}function F(i,n,r,e){e.push(""),e.push(`/** Zero an index within the ${i} ${l(n)}. */`),e.push(`export function zero${c(i)}(idx: number) {`);for(let s of r){let[a,t,o]=s.split(" ");switch(o){case"string":e.push(` ${a}[idx] = ""`);break;case"number":e.push(` ${a}[idx] = 0`);break;case"boolean":e.push(` ${a}[idx] = false`);break}}e.push("}")}function O(i,n,r){let[e,s,a]=i.split(" ");for(let t of n)h(t,a,r);for(let t of n)d(e,s,t,r);for(let t of n)p(e,s,t,a,r);$(e,s,n,a,r)}function R(i,n,r){let[e]=i.split(" ");w(e,n,r),E(e,n,r),B(e,n,r)}function w(i,n,r){r.push(`export type ${c(i)} = {`);for(let e of n){let[s,a,t]=e.split(" ");switch(a){case"string":r.push(` ${s}: string`);break;case"number":r.push(` ${s}: number`);break;case"boolean":r.push(` ${s}: boolean`);break;case"array":r.push(` ${s}: Array<${t}>`);break;default:r.push(` ${s}: ${c(a)}`)}}r.push("}")}function E(i,n,r){r.push(""),r.push(`/** Create a new ${c(i)} object. */`),r.push(`export function create${c(i)}(): ${c(i)} {`),r.push(" const obj = Object.create(null)");for(let e of n){let[s,a,t,o=""]=e.split(" ");switch(a){case"string":r.push(` obj.${s} = ""`);break;case"number":r.push(` obj.${s} = 0`);break;case"boolean":r.push(` obj.${s} = false`);break;case"array":switch(t){case"string":r.push(` obj.${s} = new Array<string>(${o})${o?'.fill("")':""}`);break;case"number":r.push(` obj.${s} = new Array<number>(${o})${o?".fill(0)":""}`);break;case"boolean":r.push(` obj.${s} = new Array<boolean>(${o})${o?".fill(false)":""}`);break}break;default:r.push(` obj.${s} = create${c(a)}()`)}}r.push(" return obj"),r.push("}")}function B(i,n,r){r.push(""),r.push(`/** Zero the given ${c(i)} object. */`),r.push(`export function zero${c(i)}(obj: ${c(i)}) {`);for(let e of n){let[s,a,t,o]=e.split(" ");switch(a){case"string":r.push(` obj.${s} = ""`);break;case"number":r.push(` obj.${s} = 0`);break;case"boolean":r.push(` obj.${s} = false`);break;case"array":switch(t){case"string":r.push(` obj.${s}.${o?'fill("")':"length = 0"}`);break;case"number":r.push(` obj.${s}.${o?"fill(0)":"length = 0"}`);break;case"boolean":r.push(` obj.${s}.${o?"fill(false)":"length = 0"}`);break}break;default:r.push(` zero${c(a)}(obj.${s})`)}}r.push("}")}function k(i,n){let[r,,e,s]=i.split(" ");g(r,e,n),L(r,s,e,n),j(r,s,e,n)}function L(i,n,r,e){e.push(`/** An array of ${c(n)} objects (structures). */`),e.push(`export const ${i} = new Array<${c(n)}>(${r})`),e.push(`for (let i=0; i<${r}; i++) {`),e.push(` ${i}[i] = create${c(n)}()`),e.push("}")}function j(i,n,r,e){e.push(""),e.push(`/** Zero all objects within the ${i} array of structures. */`),e.push(`export function zero${c(i)}() {`),e.push(` for (let i=0; i<${r}; i++) {`),e.push(` zero${c(n)}(${i}[i])`),e.push(" }"),e.push("}")}var x=process.argv[2],U=process.argv[3]||`${x}.ts`,G=S.readFileSync(x,"utf-8"),f=[];f.push("/*");f.push(` * Generated with game-data-gen on ${new Date().toLocaleString()}. DO NOT MODIFY THIS FILE!`);f.push(" */");var M=G.trim().split(`
2
3
 
3
- // src/main.ts
4
- import fs from "fs";
5
- var inputFile = process.argv[2];
6
- var outputFile = process.argv[3] || `${inputFile}.ts`;
7
- var input = fs.readFileSync(inputFile, "utf-8");
8
- var output = [];
9
- output.push("/*");
10
- output.push(` * Generated with game-data-gen on ${(/* @__PURE__ */ new Date()).toLocaleString()}. DO NOT MODIFY THIS FILE!`);
11
- output.push(" */");
12
- var blocks = input.trim().split("\n\n");
13
- for (const block of blocks) {
14
- const fields = block.split("\n");
15
- const header = fields.shift();
16
- if (!header) continue;
17
- const [name, type, baseLength] = header.split(" ");
18
- output.push("");
19
- output.push("/*");
20
- output.push(` * ${"-".repeat(50)}`);
21
- output.push(` * ${name} (${getTypeName(type)})`);
22
- output.push(` * ${"-".repeat(50)}`);
23
- output.push(" */");
24
- output.push("");
25
- if (type === "soa" /* SOA */) {
26
- output.push(`export const MAX_${name.toUpperCase()}_COUNT = ${baseLength}`);
27
- output.push("");
28
- }
29
- for (const field of fields) {
30
- const [fieldName, fieldType, fieldArrayType, fieldLength] = field.split(" ");
31
- const length = baseLength || fieldLength || "";
32
- switch (fieldType) {
33
- case "string" /* STRING */:
34
- output.push(`export let ${fieldName} = ""`);
35
- break;
36
- case "boolean" /* BOOLEAN */:
37
- output.push(`export let ${fieldName} = false`);
38
- break;
39
- case "number" /* NUMBER */:
40
- output.push(`export let ${fieldName} = 0`);
41
- break;
42
- case "array" /* ARRAY */:
43
- {
44
- switch (fieldArrayType) {
45
- case "int8" /* INT8 */:
46
- output.push(`export const ${fieldName} = new Int8Array(${length})`);
47
- break;
48
- case "int16" /* INT16 */:
49
- output.push(`export const ${fieldName} = new Int16Array(${length})`);
50
- break;
51
- case "int32" /* INT32 */:
52
- output.push(`export const ${fieldName} = new Int32Array(${length})`);
53
- break;
54
- case "uint8" /* UINT8 */:
55
- output.push(`export const ${fieldName} = new Uint8Array(${length})`);
56
- break;
57
- case "uint16" /* UINT16 */:
58
- output.push(`export const ${fieldName} = new Uint16Array(${length})`);
59
- break;
60
- case "uint32" /* UINT32 */:
61
- output.push(`export const ${fieldName} = new Uint32Array(${length})`);
62
- break;
63
- case "float32" /* FLOAT32 */:
64
- output.push(`export const ${fieldName} = new Float32Array(${length})`);
65
- break;
66
- case "float64" /* FLOAT64 */:
67
- output.push(`export const ${fieldName} = new Float64Array(${length})`);
68
- break;
69
- case "string" /* STRING */:
70
- output.push(`export const ${fieldName} = new Array<string>(${length})${length ? '.fill("")' : ""}`);
71
- break;
72
- case "boolean" /* BOOLEAN */:
73
- output.push(`export const ${fieldName} = new Array<boolean>(${length})${length ? ".fill(false)" : ""}`);
74
- break;
75
- case "number" /* NUMBER */:
76
- output.push(`export const ${fieldName} = new Array<number>(${length})${length ? ".fill(0)" : ""}`);
77
- break;
78
- default:
79
- output.push(`export const ${fieldName} = new Array<${fieldArrayType}>(${length})`);
80
- }
81
- }
82
- break;
83
- }
84
- }
85
- for (const field of fields) {
86
- const [fieldName, fieldType] = field.split(" ");
87
- switch (fieldType) {
88
- case "string" /* STRING */:
89
- case "boolean" /* BOOLEAN */:
90
- case "number" /* NUMBER */:
91
- output.push("");
92
- output.push(`/** Set the value of the ${fieldName} field within the ${name} ${getTypeName(type)}. */`);
93
- output.push(`export function set${capitalize(fieldName)}(value: ${fieldType}) {`);
94
- output.push(` ${fieldName} = value`);
95
- output.push("}");
96
- break;
97
- }
98
- }
99
- if (type === "soa" /* SOA */) {
100
- output.push("");
101
- output.push(`/** Zero an index within the ${name} ${getTypeName(type)}. */`);
102
- output.push(`export function zero${capitalize(name)}(idx: number) {`);
103
- for (const field of fields) {
104
- const [fieldName, _, fieldArrayType] = field.split(" ");
105
- switch (fieldArrayType) {
106
- case "string" /* STRING */:
107
- output.push(` ${fieldName}[idx] = ""`);
108
- break;
109
- case "boolean" /* BOOLEAN */:
110
- output.push(` ${fieldName}[idx] = false`);
111
- break;
112
- default:
113
- output.push(` ${fieldName}[idx] = 0`);
114
- }
115
- }
116
- output.push("}");
117
- }
118
- for (const field of fields) {
119
- const [fieldName, fieldType, fieldArrayType, fieldLength] = field.split(" ");
120
- const length = baseLength || fieldLength || "";
121
- output.push("");
122
- output.push(`/** Zero the ${fieldName} field within the ${name} ${getTypeName(type)}. */`);
123
- output.push(`export function zero${capitalize(fieldName)}() {`);
124
- zeroField(fieldName, fieldType, fieldArrayType, length);
125
- output.push("}");
126
- }
127
- output.push("");
128
- output.push(`/** Zero all fields within the ${name} ${getTypeName(type)}. */`);
129
- output.push(`export function zero${capitalize(name)}Data() {`);
130
- for (const field of fields) {
131
- const [fieldName, fieldType, fieldArrayType, fieldLength] = field.split(" ");
132
- const length = baseLength || fieldLength || "";
133
- zeroField(fieldName, fieldType, fieldArrayType, length);
134
- }
135
- output.push("}");
136
- }
137
- function zeroField(name, type, arrayType, length) {
138
- switch (type) {
139
- case "string" /* STRING */:
140
- output.push(` ${name} = ""`);
141
- break;
142
- case "boolean" /* BOOLEAN */:
143
- output.push(` ${name} = false`);
144
- break;
145
- case "number" /* NUMBER */:
146
- output.push(` ${name} = 0`);
147
- break;
148
- case "array" /* ARRAY */:
149
- {
150
- switch (arrayType) {
151
- case "string" /* STRING */:
152
- output.push(` ${name}.${length ? 'fill("")' : "length = 0"}`);
153
- break;
154
- case "boolean" /* BOOLEAN */:
155
- output.push(` ${name}.${length ? "fill(false)" : "length = 0"}`);
156
- break;
157
- default:
158
- output.push(` ${name}.${length ? "fill(0)" : "length = 0"}`);
159
- }
160
- }
161
- break;
162
- }
163
- }
164
- function getTypeName(type) {
165
- switch (type) {
166
- case "soa" /* SOA */:
167
- return "Structure of Arrays";
168
- default:
169
- return "group";
170
- }
171
- }
172
- function capitalize(str) {
173
- return `${str.substring(0, 1).toUpperCase()}${str.substring(1)}`;
174
- }
175
- fs.writeFileSync(outputFile, output.join("\n"));
4
+ `);for(let i of M){let n=i.split(`
5
+ `),r=n.shift();if(!r)continue;let[e,s]=r.split(" ");switch(f.push(""),f.push("/*"),f.push(` * ${"-".repeat(50)}`),f.push(` * ${e} (${l(s)})`),f.push(` * ${"-".repeat(50)}`),f.push(" */"),f.push(""),s){case"struct":R(r,n,f);break;case"group":O(r,n,f);break;case"soa":m(r,n,f);break;case"aos":k(r,f);break}}S.writeFileSync(U,f.join(`
6
+ `));
package/package.json CHANGED
@@ -1,24 +1,27 @@
1
1
  {
2
2
  "name": "game-data-gen",
3
- "version": "1.2.1",
3
+ "version": "2.0.0",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "dist"
7
7
  ],
8
- "bin": "dist/main.js",
8
+ "bin": {
9
+ "game-data-gen": "dist/main.js"
10
+ },
9
11
  "scripts": {
10
- "start": "tsx watch src/main.ts tests/data",
11
- "build": "tsc && esbuild src/main.ts --bundle --platform=node --format=esm --target=es6 --outdir=dist --banner:js='#!/usr/bin/env node'",
12
+ "start": "onchange --initial 'src/**/*.ts' 'tests/*' -- tsx src/main.ts tests/data",
13
+ "build": "tsc && esbuild src/main.ts --bundle --minify --platform=node --format=esm --target=es6 --outdir=dist --banner:js='#!/usr/bin/env node'",
12
14
  "test": "npm run build && npx game-data-gen tests/data"
13
15
  },
14
16
  "repository": {
15
17
  "type": "git",
16
- "url": "https://github.com/patrickswijgman/game-data-gen"
18
+ "url": "git+https://github.com/patrickswijgman/game-data-gen.git"
17
19
  },
18
20
  "devDependencies": {
19
- "@types/node": "^22.15.18",
20
- "esbuild": "^0.25.4",
21
- "tsx": "^4.19.4",
22
- "typescript": "~5.8.3"
21
+ "@types/node": "^24.12.2",
22
+ "esbuild": "^0.28.0",
23
+ "onchange": "^7.1.0",
24
+ "tsx": "^4.21.0",
25
+ "typescript": "^6.0.2"
23
26
  }
24
27
  }