game-data-gen 1.2.1 → 2.1.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 +132 -52
- package/dist/consts.js +21 -0
- package/dist/lib/aos.js +32 -0
- package/dist/lib/fields.js +102 -0
- package/dist/lib/group.js +14 -0
- package/dist/lib/soa.js +38 -0
- package/dist/lib/struct.js +99 -0
- package/dist/lib/utils.js +34 -0
- package/dist/main.js +35 -165
- package/package.json +10 -10
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
|
|
|
@@ -42,13 +42,14 @@ fieldName fieldType fieldArrayType? fieldArrayLength?
|
|
|
42
42
|
|
|
43
43
|
The name of the data structure.
|
|
44
44
|
|
|
45
|
-
`type`
|
|
45
|
+
`type`
|
|
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
|
|
|
@@ -56,6 +57,10 @@ The length of the arrays within the Structure of Arrays data structure.
|
|
|
56
57
|
|
|
57
58
|
If no length is given to the type and no length is given to a field it is considered a dynamic array and zeroing will set the array's length back to zero (emptying it).
|
|
58
59
|
|
|
60
|
+
`struct` (optional, required if type=aos)
|
|
61
|
+
|
|
62
|
+
The struct to use for this Array of Structures.
|
|
63
|
+
|
|
59
64
|
`fieldName`
|
|
60
65
|
|
|
61
66
|
The name of one of the fields within the data structure.
|
|
@@ -64,30 +69,27 @@ The name of one of the fields within the data structure.
|
|
|
64
69
|
|
|
65
70
|
Supported field types:
|
|
66
71
|
|
|
72
|
+
- string
|
|
73
|
+
- number
|
|
74
|
+
- boolean
|
|
67
75
|
- array
|
|
76
|
+
- a struct (see entity struct in example below)
|
|
68
77
|
|
|
69
|
-
`fieldArrayType` (
|
|
78
|
+
`fieldArrayType` (required if fieldType=array)
|
|
70
79
|
|
|
71
80
|
Supported array field types:
|
|
72
81
|
|
|
73
82
|
- string
|
|
74
83
|
- boolean
|
|
75
84
|
- number
|
|
76
|
-
- int8
|
|
77
|
-
- int16
|
|
78
|
-
- int32
|
|
79
|
-
- uint8
|
|
80
|
-
- uint16
|
|
81
|
-
- uint32
|
|
82
|
-
- float32
|
|
83
|
-
- float64
|
|
84
85
|
|
|
85
86
|
`fieldArrayLength` (optional)
|
|
86
87
|
|
|
87
|
-
The length of the array field.
|
|
88
|
+
The length of the array field, leave empty to use a dynamically sized array instead of a fixed size array.
|
|
88
89
|
|
|
89
90
|
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
91
|
|
|
92
|
+
|
|
91
93
|
## Example
|
|
92
94
|
|
|
93
95
|
Create a plain text file somewhere in your source code (without a file extension).
|
|
@@ -95,13 +97,24 @@ Create a plain text file somewhere in your source code (without a file extension
|
|
|
95
97
|
For example `src/data/game`:
|
|
96
98
|
|
|
97
99
|
```
|
|
98
|
-
|
|
100
|
+
game group
|
|
99
101
|
activeEntities array number
|
|
100
102
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
103
|
+
vector struct
|
|
104
|
+
x number
|
|
105
|
+
y number
|
|
106
|
+
|
|
107
|
+
entity struct
|
|
108
|
+
position vector
|
|
109
|
+
velocity vector
|
|
110
|
+
health number
|
|
111
|
+
isActive boolean
|
|
112
|
+
|
|
113
|
+
entities aos 2048 entity
|
|
114
|
+
|
|
115
|
+
particle soa 1024
|
|
116
|
+
posX array number
|
|
117
|
+
posY array number
|
|
105
118
|
```
|
|
106
119
|
|
|
107
120
|
Run the package with (consider making this a script in your package.json):
|
|
@@ -110,67 +123,134 @@ Run the package with (consider making this a script in your package.json):
|
|
|
110
123
|
npx game-data-gen src/data/game
|
|
111
124
|
```
|
|
112
125
|
|
|
113
|
-
This will create or update the `src/data/game.ts` file
|
|
126
|
+
This will create or update the `src/data/game.ts` file (see below). The data and functions can then be imported from this file into your code.
|
|
114
127
|
|
|
115
128
|
```typescript
|
|
116
129
|
/*
|
|
117
130
|
* --------------------------------------------------
|
|
118
|
-
*
|
|
131
|
+
* game (group)
|
|
119
132
|
* --------------------------------------------------
|
|
120
133
|
*/
|
|
121
134
|
|
|
122
|
-
export const activeEntities = new Array<number>()
|
|
135
|
+
export const activeEntities = new Array<number>()
|
|
123
136
|
|
|
124
|
-
/** Zero the activeEntities field within the
|
|
137
|
+
/** Zero the activeEntities field within the game group. */
|
|
125
138
|
export function zeroActiveEntities() {
|
|
126
|
-
activeEntities.length = 0
|
|
139
|
+
activeEntities.length = 0
|
|
127
140
|
}
|
|
128
141
|
|
|
129
|
-
/** Zero all fields within the
|
|
142
|
+
/** Zero all fields within the game group. */
|
|
130
143
|
export function zeroGameData() {
|
|
131
|
-
activeEntities.length = 0
|
|
144
|
+
activeEntities.length = 0
|
|
132
145
|
}
|
|
133
146
|
|
|
134
147
|
/*
|
|
135
148
|
* --------------------------------------------------
|
|
136
|
-
*
|
|
149
|
+
* vector (struct)
|
|
137
150
|
* --------------------------------------------------
|
|
138
151
|
*/
|
|
139
152
|
|
|
140
|
-
export
|
|
153
|
+
export type Vector = {
|
|
154
|
+
x: number
|
|
155
|
+
y: number
|
|
156
|
+
}
|
|
141
157
|
|
|
142
|
-
|
|
143
|
-
export
|
|
144
|
-
|
|
158
|
+
/** Create a new Vector object. */
|
|
159
|
+
export function createVector(): Vector {
|
|
160
|
+
const obj = Object.create(null)
|
|
161
|
+
obj.x = 0
|
|
162
|
+
obj.y = 0
|
|
163
|
+
return obj
|
|
164
|
+
}
|
|
145
165
|
|
|
146
|
-
/** Zero
|
|
147
|
-
export function
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
isActive[idx] = 0;
|
|
166
|
+
/** Zero the given Vector object. */
|
|
167
|
+
export function zeroVector(obj: Vector) {
|
|
168
|
+
obj.x = 0
|
|
169
|
+
obj.y = 0
|
|
151
170
|
}
|
|
152
171
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
172
|
+
/*
|
|
173
|
+
* --------------------------------------------------
|
|
174
|
+
* entity (struct)
|
|
175
|
+
* --------------------------------------------------
|
|
176
|
+
*/
|
|
177
|
+
|
|
178
|
+
export type Entity = {
|
|
179
|
+
position: Vector
|
|
180
|
+
velocity: Vector
|
|
181
|
+
health: number
|
|
182
|
+
isActive: boolean
|
|
156
183
|
}
|
|
157
184
|
|
|
158
|
-
/**
|
|
159
|
-
export function
|
|
160
|
-
|
|
185
|
+
/** Create a new Entity object. */
|
|
186
|
+
export function createEntity(): Entity {
|
|
187
|
+
const obj = Object.create(null)
|
|
188
|
+
obj.position = createVector()
|
|
189
|
+
obj.velocity = createVector()
|
|
190
|
+
obj.health = 0
|
|
191
|
+
obj.isActive = false
|
|
192
|
+
return obj
|
|
161
193
|
}
|
|
162
194
|
|
|
163
|
-
/** Zero the
|
|
164
|
-
export function
|
|
165
|
-
|
|
195
|
+
/** Zero the given Entity object. */
|
|
196
|
+
export function zeroEntity(obj: Entity) {
|
|
197
|
+
zeroVector(obj.position)
|
|
198
|
+
zeroVector(obj.velocity)
|
|
199
|
+
obj.health = 0
|
|
200
|
+
obj.isActive = false
|
|
166
201
|
}
|
|
167
202
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
203
|
+
/*
|
|
204
|
+
* --------------------------------------------------
|
|
205
|
+
* entities (array of structures)
|
|
206
|
+
* --------------------------------------------------
|
|
207
|
+
*/
|
|
208
|
+
|
|
209
|
+
export const MAX_ENTITIES_COUNT = 2048
|
|
210
|
+
|
|
211
|
+
/** An array of Entity objects (structures). */
|
|
212
|
+
export const entities = new Array<Entity>(2048)
|
|
213
|
+
for (let i=0; i<2048; i++) {
|
|
214
|
+
entities[i] = createEntity()
|
|
173
215
|
}
|
|
174
|
-
```
|
|
175
216
|
|
|
176
|
-
|
|
217
|
+
/** Zero all objects within the entities array of structures. */
|
|
218
|
+
export function zeroEntities() {
|
|
219
|
+
for (let i=0; i<2048; i++) {
|
|
220
|
+
zeroEntity(entities[i])
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/*
|
|
225
|
+
* --------------------------------------------------
|
|
226
|
+
* particle (structure of arrays)
|
|
227
|
+
* --------------------------------------------------
|
|
228
|
+
*/
|
|
229
|
+
|
|
230
|
+
export const MAX_PARTICLE_COUNT = 1024
|
|
231
|
+
|
|
232
|
+
export const posX = new Array<number>(1024).fill(0)
|
|
233
|
+
export const posY = new Array<number>(1024).fill(0)
|
|
234
|
+
|
|
235
|
+
/** Zero an index within the particle structure of arrays. */
|
|
236
|
+
export function zeroParticle(idx: number) {
|
|
237
|
+
posX[idx] = 0
|
|
238
|
+
posY[idx] = 0
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/** Zero the posX field within the particle structure of arrays. */
|
|
242
|
+
export function zeroPosX() {
|
|
243
|
+
posX.fill(0)
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/** Zero the posY field within the particle structure of arrays. */
|
|
247
|
+
export function zeroPosY() {
|
|
248
|
+
posY.fill(0)
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/** Zero all fields within the particle structure of arrays. */
|
|
252
|
+
export function zeroParticleData() {
|
|
253
|
+
posX.fill(0)
|
|
254
|
+
posY.fill(0)
|
|
255
|
+
}
|
|
256
|
+
```
|
package/dist/consts.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export var Type;
|
|
2
|
+
(function (Type) {
|
|
3
|
+
Type["SOA"] = "soa";
|
|
4
|
+
Type["AOS"] = "aos";
|
|
5
|
+
Type["STRUCT"] = "struct";
|
|
6
|
+
Type["GROUP"] = "group";
|
|
7
|
+
})(Type || (Type = {}));
|
|
8
|
+
export var FieldType;
|
|
9
|
+
(function (FieldType) {
|
|
10
|
+
FieldType["STRING"] = "string";
|
|
11
|
+
FieldType["NUMBER"] = "number";
|
|
12
|
+
FieldType["BOOLEAN"] = "boolean";
|
|
13
|
+
FieldType["ARRAY"] = "array";
|
|
14
|
+
FieldType["SET"] = "set";
|
|
15
|
+
})(FieldType || (FieldType = {}));
|
|
16
|
+
export var ArrayType;
|
|
17
|
+
(function (ArrayType) {
|
|
18
|
+
ArrayType["STRING"] = "string";
|
|
19
|
+
ArrayType["NUMBER"] = "number";
|
|
20
|
+
ArrayType["BOOLEAN"] = "boolean";
|
|
21
|
+
})(ArrayType || (ArrayType = {}));
|
package/dist/lib/aos.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { addFieldMaxLengthConstant } from "./fields.js";
|
|
2
|
+
import { capitalize, getName } from "./utils.js";
|
|
3
|
+
export function addArrayOfStructures(header, output) {
|
|
4
|
+
const [name, , length, struct] = header.split(" ");
|
|
5
|
+
addFieldMaxLengthConstant(name, length, output);
|
|
6
|
+
addArrayOfStructuresDefinition(name, struct, length, output);
|
|
7
|
+
addArrayOfStructuresZeroFunction(name, struct, length, output);
|
|
8
|
+
addArrayOfStructuresZeroAtIndexFunction(name, struct, output);
|
|
9
|
+
}
|
|
10
|
+
function addArrayOfStructuresDefinition(name, struct, length, output) {
|
|
11
|
+
output.push(`/** An array of ${capitalize(struct)} objects (structures). */`);
|
|
12
|
+
output.push(`export const ${name} = new Array<${getName(struct)}>(${length})`);
|
|
13
|
+
output.push(`for (let i=0; i<${length}; i++) {`);
|
|
14
|
+
output.push(` ${name}[i] = create${capitalize(struct)}()`);
|
|
15
|
+
output.push("}");
|
|
16
|
+
}
|
|
17
|
+
function addArrayOfStructuresZeroFunction(name, struct, length, output) {
|
|
18
|
+
output.push("");
|
|
19
|
+
output.push(`/** Zero all objects within the ${name} array of structures. */`);
|
|
20
|
+
output.push(`export function zero${capitalize(name)}() {`);
|
|
21
|
+
output.push(` for (let i=0; i<${length}; i++) {`);
|
|
22
|
+
output.push(` zero${capitalize(struct)}(${name}[i])`);
|
|
23
|
+
output.push(" }");
|
|
24
|
+
output.push("}");
|
|
25
|
+
}
|
|
26
|
+
function addArrayOfStructuresZeroAtIndexFunction(name, struct, output) {
|
|
27
|
+
output.push("");
|
|
28
|
+
output.push(`/** Zero an object at a specific index within the ${name} array of structures. */`);
|
|
29
|
+
output.push(`export function zero${capitalize(struct)}At(index: number) {`);
|
|
30
|
+
output.push(` zero${capitalize(struct)}(${name}[index])`);
|
|
31
|
+
output.push("}");
|
|
32
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { ArrayType, FieldType } from "../consts.js";
|
|
2
|
+
import { capitalize, getName } from "./utils.js";
|
|
3
|
+
export function addFieldDefinition(field, baseLength, output) {
|
|
4
|
+
const [fieldName, fieldType, fieldArrayType, fieldLength] = field.split(" ");
|
|
5
|
+
const fieldArrayLength = baseLength || fieldLength || "";
|
|
6
|
+
switch (fieldType) {
|
|
7
|
+
case FieldType.STRING:
|
|
8
|
+
output.push(`export let ${fieldName} = ""`);
|
|
9
|
+
break;
|
|
10
|
+
case FieldType.NUMBER:
|
|
11
|
+
output.push(`export let ${fieldName} = 0`);
|
|
12
|
+
break;
|
|
13
|
+
case FieldType.BOOLEAN:
|
|
14
|
+
output.push(`export let ${fieldName} = false`);
|
|
15
|
+
break;
|
|
16
|
+
case FieldType.ARRAY:
|
|
17
|
+
{
|
|
18
|
+
switch (fieldArrayType) {
|
|
19
|
+
case ArrayType.STRING:
|
|
20
|
+
output.push(`export let ${fieldName} = new Array<string>(${fieldArrayLength})${fieldArrayLength ? '.fill("")' : ""}`);
|
|
21
|
+
break;
|
|
22
|
+
case ArrayType.NUMBER:
|
|
23
|
+
output.push(`export let ${fieldName} = new Array<number>(${fieldArrayLength})${fieldArrayLength ? ".fill(0)" : ""}`);
|
|
24
|
+
break;
|
|
25
|
+
case ArrayType.BOOLEAN:
|
|
26
|
+
output.push(`export let ${fieldName} = new Array<boolean>(${fieldArrayLength})${fieldArrayLength ? ".fill(false)" : ""}`);
|
|
27
|
+
break;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
break;
|
|
31
|
+
case FieldType.SET:
|
|
32
|
+
output.push(`export let ${fieldName} = new Set<${getName(fieldArrayType)}>()`);
|
|
33
|
+
break;
|
|
34
|
+
default:
|
|
35
|
+
output.push(`export let ${fieldName} = create${capitalize(fieldType)}()`);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
export function addFieldSetFunction(name, type, field, output) {
|
|
39
|
+
const [fieldName, fieldType, fieldArrayType] = field.split(" ");
|
|
40
|
+
output.push("");
|
|
41
|
+
output.push(`/** Set the value of the ${fieldName} field within the ${name} ${getName(type)}. */`);
|
|
42
|
+
output.push(`export function set${capitalize(fieldName)}(value: ${getName(fieldType, fieldArrayType)}) {`);
|
|
43
|
+
output.push(` ${fieldName} = value`);
|
|
44
|
+
output.push("}");
|
|
45
|
+
}
|
|
46
|
+
export function addFieldZeroFunction(name, type, field, baseLength, output) {
|
|
47
|
+
const [fieldName, fieldType, fieldArrayType, fieldLength] = field.split(" ");
|
|
48
|
+
const length = baseLength || fieldLength || "";
|
|
49
|
+
output.push("");
|
|
50
|
+
output.push(`/** Zero the ${fieldName} field within the ${name} ${getName(type)}. */`);
|
|
51
|
+
output.push(`export function zero${capitalize(fieldName)}() {`);
|
|
52
|
+
zeroField(fieldName, fieldType, fieldArrayType, length, output);
|
|
53
|
+
output.push("}");
|
|
54
|
+
}
|
|
55
|
+
export function addZeroFunction(name, type, fields, baseLength, output) {
|
|
56
|
+
output.push("");
|
|
57
|
+
output.push(`/** Zero all fields within the ${name} ${getName(type)}. */`);
|
|
58
|
+
output.push(`export function zero${capitalize(name)}Data() {`);
|
|
59
|
+
for (const field of fields) {
|
|
60
|
+
const [fieldName, fieldType, fieldArrayType, fieldLength] = field.split(" ");
|
|
61
|
+
const length = baseLength || fieldLength || "";
|
|
62
|
+
zeroField(fieldName, fieldType, fieldArrayType, length, output);
|
|
63
|
+
}
|
|
64
|
+
output.push("}");
|
|
65
|
+
}
|
|
66
|
+
function zeroField(name, type, arrayType, length, output) {
|
|
67
|
+
switch (type) {
|
|
68
|
+
case FieldType.STRING:
|
|
69
|
+
output.push(` ${name} = ""`);
|
|
70
|
+
break;
|
|
71
|
+
case FieldType.NUMBER:
|
|
72
|
+
output.push(` ${name} = 0`);
|
|
73
|
+
break;
|
|
74
|
+
case FieldType.BOOLEAN:
|
|
75
|
+
output.push(` ${name} = false`);
|
|
76
|
+
break;
|
|
77
|
+
case FieldType.ARRAY:
|
|
78
|
+
{
|
|
79
|
+
switch (arrayType) {
|
|
80
|
+
case ArrayType.STRING:
|
|
81
|
+
output.push(` ${name}.${length ? 'fill("")' : "length = 0"}`);
|
|
82
|
+
break;
|
|
83
|
+
case ArrayType.NUMBER:
|
|
84
|
+
output.push(` ${name}.${length ? "fill(0)" : "length = 0"}`);
|
|
85
|
+
break;
|
|
86
|
+
case ArrayType.BOOLEAN:
|
|
87
|
+
output.push(` ${name}.${length ? "fill(false)" : "length = 0"}`);
|
|
88
|
+
break;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
break;
|
|
92
|
+
case FieldType.SET:
|
|
93
|
+
output.push(` ${name}.clear()`);
|
|
94
|
+
break;
|
|
95
|
+
default:
|
|
96
|
+
output.push(` zero${capitalize(type)}(${name})`);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
export function addFieldMaxLengthConstant(name, length, output) {
|
|
100
|
+
output.push(`export const MAX_${name.toUpperCase()}_COUNT = ${length}`);
|
|
101
|
+
output.push("");
|
|
102
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { addFieldDefinition, addFieldSetFunction, addFieldZeroFunction, addZeroFunction } from "./fields.js";
|
|
2
|
+
export function addGroup(header, fields, output) {
|
|
3
|
+
const [name, type, baseLength] = header.split(" ");
|
|
4
|
+
for (const field of fields) {
|
|
5
|
+
addFieldDefinition(field, baseLength, output);
|
|
6
|
+
}
|
|
7
|
+
for (const field of fields) {
|
|
8
|
+
addFieldSetFunction(name, type, field, output);
|
|
9
|
+
}
|
|
10
|
+
for (const field of fields) {
|
|
11
|
+
addFieldZeroFunction(name, type, field, baseLength, output);
|
|
12
|
+
}
|
|
13
|
+
addZeroFunction(name, type, fields, baseLength, output);
|
|
14
|
+
}
|
package/dist/lib/soa.js
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { ArrayType } from "../consts.js";
|
|
2
|
+
import { addFieldDefinition, addFieldMaxLengthConstant, addFieldSetFunction, addFieldZeroFunction, addZeroFunction } from "./fields.js";
|
|
3
|
+
import { capitalize, getName } from "./utils.js";
|
|
4
|
+
export function addStructureOfArrays(header, fields, output) {
|
|
5
|
+
const [name, type, baseLength] = header.split(" ");
|
|
6
|
+
addFieldMaxLengthConstant(name, baseLength, output);
|
|
7
|
+
for (const field of fields) {
|
|
8
|
+
addFieldDefinition(field, baseLength, output);
|
|
9
|
+
}
|
|
10
|
+
for (const field of fields) {
|
|
11
|
+
addFieldSetFunction(name, type, field, output);
|
|
12
|
+
}
|
|
13
|
+
addFieldZeroAtIndexFunction(name, type, fields, output);
|
|
14
|
+
for (const field of fields) {
|
|
15
|
+
addFieldZeroFunction(name, type, field, baseLength, output);
|
|
16
|
+
}
|
|
17
|
+
addZeroFunction(name, type, fields, baseLength, output);
|
|
18
|
+
}
|
|
19
|
+
function addFieldZeroAtIndexFunction(name, type, fields, output) {
|
|
20
|
+
output.push("");
|
|
21
|
+
output.push(`/** Zero an index within the ${name} ${getName(type)}. */`);
|
|
22
|
+
output.push(`export function zero${capitalize(name)}(idx: number) {`);
|
|
23
|
+
for (const field of fields) {
|
|
24
|
+
const [fieldName, _, fieldArrayType] = field.split(" ");
|
|
25
|
+
switch (fieldArrayType) {
|
|
26
|
+
case ArrayType.STRING:
|
|
27
|
+
output.push(` ${fieldName}[idx] = ""`);
|
|
28
|
+
break;
|
|
29
|
+
case ArrayType.NUMBER:
|
|
30
|
+
output.push(` ${fieldName}[idx] = 0`);
|
|
31
|
+
break;
|
|
32
|
+
case ArrayType.BOOLEAN:
|
|
33
|
+
output.push(` ${fieldName}[idx] = false`);
|
|
34
|
+
break;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
output.push("}");
|
|
38
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { ArrayType, FieldType } from "../consts.js";
|
|
2
|
+
import { capitalize, getName } from "./utils.js";
|
|
3
|
+
export function addStruct(header, fields, output) {
|
|
4
|
+
const [name] = header.split(" ");
|
|
5
|
+
addStructTypeDefinition(name, fields, output);
|
|
6
|
+
addStructCreateFunction(name, fields, output);
|
|
7
|
+
addStructZeroFunction(name, fields, output);
|
|
8
|
+
}
|
|
9
|
+
function addStructTypeDefinition(name, fields, output) {
|
|
10
|
+
output.push(`export type ${capitalize(name)} = {`);
|
|
11
|
+
for (const field of fields) {
|
|
12
|
+
const [fieldName, fieldType, fieldArrayType] = field.split(" ");
|
|
13
|
+
output.push(` ${fieldName}: ${getName(fieldType, fieldArrayType)}`);
|
|
14
|
+
}
|
|
15
|
+
output.push("}");
|
|
16
|
+
}
|
|
17
|
+
function addStructCreateFunction(name, fields, output) {
|
|
18
|
+
output.push("");
|
|
19
|
+
output.push(`/** Create a new ${capitalize(name)} object. */`);
|
|
20
|
+
output.push(`export function create${capitalize(name)}(): ${capitalize(name)} {`);
|
|
21
|
+
output.push(` const obj = Object.create(null)`);
|
|
22
|
+
for (const field of fields) {
|
|
23
|
+
const [fieldName, fieldType, fieldArrayType, fieldArrayLength = ""] = field.split(" ");
|
|
24
|
+
switch (fieldType) {
|
|
25
|
+
case FieldType.STRING:
|
|
26
|
+
output.push(` obj.${fieldName} = ""`);
|
|
27
|
+
break;
|
|
28
|
+
case FieldType.NUMBER:
|
|
29
|
+
output.push(` obj.${fieldName} = 0`);
|
|
30
|
+
break;
|
|
31
|
+
case FieldType.BOOLEAN:
|
|
32
|
+
output.push(` obj.${fieldName} = false`);
|
|
33
|
+
break;
|
|
34
|
+
case FieldType.ARRAY:
|
|
35
|
+
{
|
|
36
|
+
switch (fieldArrayType) {
|
|
37
|
+
case ArrayType.STRING:
|
|
38
|
+
output.push(` obj.${fieldName} = new Array<string>(${fieldArrayLength})${fieldArrayLength ? '.fill("")' : ""}`);
|
|
39
|
+
break;
|
|
40
|
+
case ArrayType.NUMBER:
|
|
41
|
+
output.push(` obj.${fieldName} = new Array<number>(${fieldArrayLength})${fieldArrayLength ? ".fill(0)" : ""}`);
|
|
42
|
+
break;
|
|
43
|
+
case ArrayType.BOOLEAN:
|
|
44
|
+
output.push(` obj.${fieldName} = new Array<boolean>(${fieldArrayLength})${fieldArrayLength ? ".fill(false)" : ""}`);
|
|
45
|
+
break;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
break;
|
|
49
|
+
case FieldType.SET:
|
|
50
|
+
output.push(` obj.${fieldName} = new Set<${getName(fieldArrayType)}>()`);
|
|
51
|
+
break;
|
|
52
|
+
default: {
|
|
53
|
+
output.push(` obj.${fieldName} = create${capitalize(fieldType)}()`);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
output.push(" return obj");
|
|
58
|
+
output.push("}");
|
|
59
|
+
}
|
|
60
|
+
function addStructZeroFunction(name, fields, output) {
|
|
61
|
+
output.push("");
|
|
62
|
+
output.push(`/** Zero the given ${capitalize(name)} object. */`);
|
|
63
|
+
output.push(`export function zero${capitalize(name)}(obj: ${capitalize(name)}) {`);
|
|
64
|
+
for (const field of fields) {
|
|
65
|
+
const [fieldName, fieldType, fieldArrayType, fieldArrayLength] = field.split(" ");
|
|
66
|
+
switch (fieldType) {
|
|
67
|
+
case FieldType.STRING:
|
|
68
|
+
output.push(` obj.${fieldName} = ""`);
|
|
69
|
+
break;
|
|
70
|
+
case FieldType.NUMBER:
|
|
71
|
+
output.push(` obj.${fieldName} = 0`);
|
|
72
|
+
break;
|
|
73
|
+
case FieldType.BOOLEAN:
|
|
74
|
+
output.push(` obj.${fieldName} = false`);
|
|
75
|
+
break;
|
|
76
|
+
case FieldType.ARRAY:
|
|
77
|
+
{
|
|
78
|
+
switch (fieldArrayType) {
|
|
79
|
+
case ArrayType.STRING:
|
|
80
|
+
output.push(` obj.${fieldName}.${fieldArrayLength ? 'fill("")' : "length = 0"}`);
|
|
81
|
+
break;
|
|
82
|
+
case ArrayType.NUMBER:
|
|
83
|
+
output.push(` obj.${fieldName}.${fieldArrayLength ? "fill(0)" : "length = 0"}`);
|
|
84
|
+
break;
|
|
85
|
+
case ArrayType.BOOLEAN:
|
|
86
|
+
output.push(` obj.${fieldName}.${fieldArrayLength ? "fill(false)" : "length = 0"}`);
|
|
87
|
+
break;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
break;
|
|
91
|
+
case FieldType.SET:
|
|
92
|
+
output.push(` obj.${fieldName}.clear()`);
|
|
93
|
+
break;
|
|
94
|
+
default:
|
|
95
|
+
output.push(` zero${capitalize(fieldType)}(obj.${fieldName})`);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
output.push("}");
|
|
99
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { FieldType, Type } from "../consts.js";
|
|
2
|
+
/**
|
|
3
|
+
* Get the name based on the type of the data structure.
|
|
4
|
+
*/
|
|
5
|
+
export function getName(type, arrayType = "") {
|
|
6
|
+
switch (type) {
|
|
7
|
+
case Type.SOA:
|
|
8
|
+
return "structure of arrays";
|
|
9
|
+
case Type.AOS:
|
|
10
|
+
return "array of structures";
|
|
11
|
+
case Type.STRUCT:
|
|
12
|
+
return "struct";
|
|
13
|
+
case Type.GROUP:
|
|
14
|
+
return "group";
|
|
15
|
+
case FieldType.STRING:
|
|
16
|
+
return "string";
|
|
17
|
+
case FieldType.NUMBER:
|
|
18
|
+
return "number";
|
|
19
|
+
case FieldType.BOOLEAN:
|
|
20
|
+
return "boolean";
|
|
21
|
+
case FieldType.ARRAY:
|
|
22
|
+
return `Array<${getName(arrayType)}>`;
|
|
23
|
+
case FieldType.SET:
|
|
24
|
+
return `Set<${getName(arrayType)}>`;
|
|
25
|
+
default:
|
|
26
|
+
return capitalize(type);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Capitalize the first letter of a string.
|
|
31
|
+
*/
|
|
32
|
+
export function capitalize(str) {
|
|
33
|
+
return `${str.substring(0, 1).toUpperCase()}${str.substring(1)}`;
|
|
34
|
+
}
|
package/dist/main.js
CHANGED
|
@@ -1,175 +1,45 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
import
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import { Type } from "./consts.js";
|
|
4
|
+
import { addArrayOfStructures } from "./lib/aos.js";
|
|
5
|
+
import { addGroup } from "./lib/group.js";
|
|
6
|
+
import { addStructureOfArrays } from "./lib/soa.js";
|
|
7
|
+
import { addStruct } from "./lib/struct.js";
|
|
8
|
+
import { getName } from "./lib/utils.js";
|
|
9
|
+
const inputFile = process.argv[2];
|
|
10
|
+
const outputFile = process.argv[3] || `${inputFile}.ts`;
|
|
11
|
+
const input = fs.readFileSync(inputFile, "utf-8");
|
|
12
|
+
const output = [];
|
|
9
13
|
output.push("/*");
|
|
10
|
-
output.push(` * Generated with game-data-gen on ${
|
|
14
|
+
output.push(` * Generated with game-data-gen on ${new Date().toLocaleString()}. DO NOT MODIFY THIS FILE!`);
|
|
11
15
|
output.push(" */");
|
|
12
|
-
|
|
16
|
+
const blocks = input.trim().split("\n\n");
|
|
13
17
|
for (const block of blocks) {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
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}`);
|
|
18
|
+
const fields = block.split("\n");
|
|
19
|
+
const header = fields.shift();
|
|
20
|
+
if (!header)
|
|
21
|
+
continue;
|
|
22
|
+
const [name, type] = header.split(" ");
|
|
27
23
|
output.push("");
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
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 */) {
|
|
24
|
+
output.push("/*");
|
|
25
|
+
output.push(` * ${"-".repeat(50)}`);
|
|
26
|
+
output.push(` * ${name} (${getName(type)})`);
|
|
27
|
+
output.push(` * ${"-".repeat(50)}`);
|
|
28
|
+
output.push(" */");
|
|
100
29
|
output.push("");
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
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"}`);
|
|
30
|
+
switch (type) {
|
|
31
|
+
case Type.STRUCT:
|
|
32
|
+
addStruct(header, fields, output);
|
|
153
33
|
break;
|
|
154
|
-
|
|
155
|
-
|
|
34
|
+
case Type.GROUP:
|
|
35
|
+
addGroup(header, fields, output);
|
|
156
36
|
break;
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
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)}`;
|
|
37
|
+
case Type.SOA:
|
|
38
|
+
addStructureOfArrays(header, fields, output);
|
|
39
|
+
break;
|
|
40
|
+
case Type.AOS:
|
|
41
|
+
addArrayOfStructures(header, output);
|
|
42
|
+
break;
|
|
43
|
+
}
|
|
174
44
|
}
|
|
175
45
|
fs.writeFileSync(outputFile, output.join("\n"));
|
package/package.json
CHANGED
|
@@ -1,24 +1,24 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "game-data-gen",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"files": [
|
|
6
6
|
"dist"
|
|
7
7
|
],
|
|
8
|
-
"bin":
|
|
8
|
+
"bin": {
|
|
9
|
+
"game-data-gen": "dist/main.js"
|
|
10
|
+
},
|
|
9
11
|
"scripts": {
|
|
10
|
-
"start": "
|
|
11
|
-
"build": "
|
|
12
|
-
"test": "npm run build && npx game-data-gen tests/data"
|
|
12
|
+
"start": "tsc && node dist/main.js tests/data",
|
|
13
|
+
"build": "biome check && tsc"
|
|
13
14
|
},
|
|
14
15
|
"repository": {
|
|
15
16
|
"type": "git",
|
|
16
|
-
"url": "https://github.com/patrickswijgman/game-data-gen"
|
|
17
|
+
"url": "git+https://github.com/patrickswijgman/game-data-gen.git"
|
|
17
18
|
},
|
|
18
19
|
"devDependencies": {
|
|
19
|
-
"@
|
|
20
|
-
"
|
|
21
|
-
"
|
|
22
|
-
"typescript": "~5.8.3"
|
|
20
|
+
"@biomejs/biome": "^2.4.11",
|
|
21
|
+
"@types/node": "^24.12.2",
|
|
22
|
+
"typescript": "^6.0.2"
|
|
23
23
|
}
|
|
24
24
|
}
|