brs-js 1.4.1 → 2.0.2

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 (87) hide show
  1. package/.prettierrc +7 -0
  2. package/LICENSE +1 -1
  3. package/README.md +2 -2
  4. package/debug/Conf Spacestation.brs +0 -0
  5. package/debug/Electrks_Feminine_Challenge.brs +0 -0
  6. package/debug/a5bricks.brs +0 -0
  7. package/debug/a5p2.2.brs +0 -0
  8. package/debug/a5p2.brs +0 -0
  9. package/debug/audio.brs +0 -0
  10. package/debug/brick a5.brs +0 -0
  11. package/debug/brick qa.brs +0 -0
  12. package/debug/brsv10.brs +0 -0
  13. package/debug/brsv10brick.brs +0 -0
  14. package/debug/bruteforce.js +254 -0
  15. package/debug/clone.html +36 -0
  16. package/debug/ctf_tileset.brs +0 -0
  17. package/debug/ctf_tileset_5.brs +0 -0
  18. package/debug/evil.brs +0 -0
  19. package/{src/write.js → debug/evilwrite.js} +218 -31
  20. package/debug/foo.txt +3080 -0
  21. package/debug/kenko_big.brs +0 -0
  22. package/debug/light.brs +0 -0
  23. package/debug/out.json +105 -0
  24. package/debug/read.js +30 -0
  25. package/debug/readSpeed.js +32 -0
  26. package/debug/readTest.js +45 -0
  27. package/debug/temp.brs +0 -0
  28. package/debug/western.brs +0 -0
  29. package/dist/dist.js +1 -1
  30. package/dist/dist.node.js +1 -1
  31. package/dist/dist.web.js +1 -1
  32. package/dist/src/constants.d.ts +6 -0
  33. package/dist/src/constants.d.ts.map +1 -0
  34. package/dist/src/index.d.ts +23 -0
  35. package/dist/src/index.d.ts.map +1 -0
  36. package/dist/src/read.d.ts +3 -0
  37. package/dist/src/read.d.ts.map +1 -0
  38. package/dist/src/read.v1.d.ts +3 -0
  39. package/dist/src/read.v1.d.ts.map +1 -0
  40. package/dist/src/read.v10.d.ts +3 -0
  41. package/dist/src/read.v10.d.ts.map +1 -0
  42. package/dist/src/read.v2.d.ts +3 -0
  43. package/dist/src/read.v2.d.ts.map +1 -0
  44. package/dist/src/read.v3.d.ts +3 -0
  45. package/dist/src/read.v3.d.ts.map +1 -0
  46. package/dist/src/read.v4.d.ts +3 -0
  47. package/dist/src/read.v4.d.ts.map +1 -0
  48. package/dist/src/read.v8.d.ts +3 -0
  49. package/dist/src/read.v8.d.ts.map +1 -0
  50. package/dist/src/read.v9.d.ts +3 -0
  51. package/dist/src/read.v9.d.ts.map +1 -0
  52. package/dist/src/types.d.ts +170 -0
  53. package/dist/src/types.d.ts.map +1 -0
  54. package/dist/src/utils.d.ts +87 -0
  55. package/dist/src/utils.d.ts.map +1 -0
  56. package/dist/src/uuid.d.ts +4 -0
  57. package/dist/src/uuid.d.ts.map +1 -0
  58. package/dist/src/write.d.ts +3 -0
  59. package/dist/src/write.d.ts.map +1 -0
  60. package/examples/ATCFort.brs +0 -0
  61. package/examples/read_example.html +34 -0
  62. package/examples/read_example.js +21 -0
  63. package/examples/write_example.js +25 -0
  64. package/examples/write_planet.html +144 -0
  65. package/examples/write_simplex.html +82 -0
  66. package/examples/write_wedge_sphere.html +173 -0
  67. package/package.json +17 -14
  68. package/src/constants.ts +6 -0
  69. package/src/{index.js → index.ts} +13 -1
  70. package/src/read.ts +57 -0
  71. package/src/read.v1.ts +99 -0
  72. package/src/read.v10.ts +185 -0
  73. package/src/read.v2.ts +102 -0
  74. package/src/read.v3.ts +111 -0
  75. package/src/read.v4.ts +112 -0
  76. package/src/read.v8.ts +172 -0
  77. package/src/read.v9.ts +181 -0
  78. package/src/types.ts +240 -0
  79. package/src/{utils.js → utils.ts} +241 -181
  80. package/src/{uuid.js → uuid.ts} +9 -5
  81. package/src/write.ts +209 -0
  82. package/test/lib.test.js +31 -23
  83. package/test/utils.test.js +50 -15
  84. package/tsconfig.json +22 -0
  85. package/webpack.config.js +51 -30
  86. package/src/constants.js +0 -4
  87. package/src/read.js +0 -206
package/src/read.v3.ts ADDED
@@ -0,0 +1,111 @@
1
+ import {
2
+ BRSBytes,
3
+ ReadOptions,
4
+ BrsV3,
5
+ UnrealColor,
6
+ User,
7
+ BrickV3,
8
+ Vector,
9
+ } from './types';
10
+ import { read, bgra } from './utils';
11
+
12
+ // Reads in a byte array to build a brs object
13
+ export default function readBrsV3(
14
+ brsData: BRSBytes,
15
+ options: ReadOptions = {}
16
+ ): BrsV3 {
17
+ // Read in Headers
18
+ const header1Data = read.compressed(brsData);
19
+ const header2Data = read.compressed(brsData);
20
+
21
+ const map = read.string(header1Data);
22
+ const author_name = read.string(header1Data);
23
+ const description = read.string(header1Data);
24
+ const author_id = read.uuid(header1Data);
25
+
26
+ const brick_count = read.i32(header1Data);
27
+
28
+ const mods = read.array(header2Data, read.string);
29
+ const brick_assets = read.array(header2Data, read.string);
30
+ const colors = read.array(
31
+ header2Data,
32
+ data => bgra(Array.from(read.bytes(data, 4))) as UnrealColor
33
+ );
34
+ const materials = read.array(header2Data, read.string);
35
+ const brick_owners: User[] = read.array(header2Data, data => ({
36
+ id: read.uuid(data),
37
+ name: read.string(data),
38
+ }));
39
+
40
+ // Read in bricks
41
+ let bricks: BrickV3[] = [];
42
+
43
+ const numAssets = Math.max(brick_assets.length, 2);
44
+
45
+ if (options.bricks) {
46
+ bricks = Array(brick_count);
47
+ const brickData = read.compressed(brsData);
48
+ const brickBits = read.bits(brickData);
49
+
50
+ // Brick reader
51
+ for (let i = 0; !brickBits.empty() && i < brick_count; i++) {
52
+ brickBits.align();
53
+ const asset_name_index = brickBits.int(numAssets);
54
+ const size: Vector = brickBits.bit()
55
+ ? [
56
+ brickBits.uint_packed(),
57
+ brickBits.uint_packed(),
58
+ brickBits.uint_packed(),
59
+ ]
60
+ : [0, 0, 0];
61
+ const position: Vector = [
62
+ brickBits.int_packed(),
63
+ brickBits.int_packed(),
64
+ brickBits.int_packed(),
65
+ ];
66
+
67
+ const orientation = brickBits.int(24);
68
+ const direction = (orientation >> 2) % 6;
69
+ const rotation = orientation & 3;
70
+ const collision = brickBits.bit();
71
+ const visibility = brickBits.bit();
72
+ const material_index = brickBits.bit() ? brickBits.uint_packed() : 1;
73
+
74
+ const color = brickBits.bit()
75
+ ? bgra(brickBits.bytesArr(4) as [number, number, number, number])
76
+ : brickBits.int(colors.length);
77
+
78
+ const owner_index = brickBits.uint_packed();
79
+
80
+ bricks[i] = {
81
+ asset_name_index,
82
+ size,
83
+ position,
84
+ direction,
85
+ rotation,
86
+ collision,
87
+ visibility,
88
+ material_index,
89
+ color,
90
+ owner_index,
91
+ };
92
+ }
93
+ }
94
+
95
+ return {
96
+ version: 3,
97
+ map,
98
+ description,
99
+ author: {
100
+ id: author_id,
101
+ name: author_name,
102
+ },
103
+ mods,
104
+ brick_assets,
105
+ colors,
106
+ materials,
107
+ brick_owners,
108
+ bricks,
109
+ brick_count,
110
+ };
111
+ }
package/src/read.v4.ts ADDED
@@ -0,0 +1,112 @@
1
+ import {
2
+ BRSBytes,
3
+ ReadOptions,
4
+ BrsV4,
5
+ UnrealColor,
6
+ BrickV3,
7
+ Vector,
8
+ } from './types';
9
+ import { bgra, read } from './utils';
10
+
11
+ // Reads in a byte array to build a brs object
12
+ export default function readBrsV4(
13
+ brsData: BRSBytes,
14
+ options: ReadOptions = {}
15
+ ): BrsV4 {
16
+ // Read in Headers
17
+ const header1Data = read.compressed(brsData);
18
+ const header2Data = read.compressed(brsData);
19
+
20
+ const map = read.string(header1Data);
21
+ const author_name = read.string(header1Data);
22
+ const description = read.string(header1Data);
23
+ const author_id = read.uuid(header1Data);
24
+ const save_time = read.bytes(header1Data, 8);
25
+
26
+ const brick_count = read.i32(header1Data);
27
+
28
+ const mods = read.array(header2Data, read.string);
29
+ const brick_assets = read.array(header2Data, read.string);
30
+ const colors = read.array(
31
+ header2Data,
32
+ data => bgra(Array.from(read.bytes(data, 4))) as UnrealColor
33
+ );
34
+ const materials = read.array(header2Data, read.string);
35
+ const brick_owners = read.array(header2Data, data => ({
36
+ id: read.uuid(data),
37
+ name: read.string(data),
38
+ }));
39
+
40
+ // Read in bricks
41
+ let bricks: BrickV3[] = [];
42
+
43
+ const numAssets = Math.max(brick_assets.length, 2);
44
+
45
+ if (options.bricks) {
46
+ bricks = Array(brick_count);
47
+ const brickData = read.compressed(brsData);
48
+ const brickBits = read.bits(brickData);
49
+
50
+ // Brick reader
51
+ for (let i = 0; !brickBits.empty() && i < brick_count; i++) {
52
+ brickBits.align();
53
+ const asset_name_index = brickBits.int(numAssets);
54
+ const size: Vector = brickBits.bit()
55
+ ? [
56
+ brickBits.uint_packed(),
57
+ brickBits.uint_packed(),
58
+ brickBits.uint_packed(),
59
+ ]
60
+ : [0, 0, 0];
61
+ const position: Vector = [
62
+ brickBits.int_packed(),
63
+ brickBits.int_packed(),
64
+ brickBits.int_packed(),
65
+ ];
66
+
67
+ const orientation = brickBits.int(24);
68
+ const direction = (orientation >> 2) % 6;
69
+ const rotation = orientation & 3;
70
+ const collision = brickBits.bit();
71
+ const visibility = brickBits.bit();
72
+ const material_index = brickBits.bit() ? brickBits.uint_packed() : 1;
73
+
74
+ const color = brickBits.bit()
75
+ ? bgra(brickBits.bytesArr(4) as [number, number, number, number])
76
+ : brickBits.int(colors.length);
77
+
78
+ const owner_index = brickBits.uint_packed();
79
+
80
+ bricks[i] = {
81
+ asset_name_index,
82
+ size,
83
+ position,
84
+ direction,
85
+ rotation,
86
+ collision,
87
+ visibility,
88
+ material_index,
89
+ color,
90
+ owner_index,
91
+ };
92
+ }
93
+ }
94
+
95
+ return {
96
+ version: 4,
97
+ map,
98
+ description,
99
+ author: {
100
+ id: author_id,
101
+ name: author_name,
102
+ },
103
+ mods,
104
+ brick_assets,
105
+ colors,
106
+ materials,
107
+ brick_owners,
108
+ bricks,
109
+ brick_count,
110
+ save_time,
111
+ };
112
+ }
package/src/read.v8.ts ADDED
@@ -0,0 +1,172 @@
1
+ import {
2
+ BRSBytes,
3
+ ReadOptions,
4
+ BrsV8,
5
+ User,
6
+ UnrealColor,
7
+ BrickV8,
8
+ Vector,
9
+ AppliedComponent,
10
+ } from './types';
11
+ import { bgra, read } from './utils';
12
+
13
+ // Reads in a byte array to build a brs object
14
+ export default function readBrsV8(
15
+ brsData: BRSBytes,
16
+ options: ReadOptions = {}
17
+ ): BrsV8 {
18
+ // game version is included in saves >= v8
19
+ const game_version = read.i32(brsData);
20
+
21
+ // Read in Headers
22
+ const header1Data = read.compressed(brsData);
23
+ const header2Data = read.compressed(brsData);
24
+
25
+ const map = read.string(header1Data);
26
+ const author_name = read.string(header1Data);
27
+ const description = read.string(header1Data);
28
+ const author_id = read.uuid(header1Data);
29
+
30
+ const host: User = {
31
+ name: read.string(header1Data),
32
+ id: read.uuid(header1Data),
33
+ };
34
+ const save_time = read.bytes(header1Data, 8);
35
+
36
+ const brick_count = read.i32(header1Data);
37
+
38
+ const mods = read.array(header2Data, read.string);
39
+ const brick_assets = read.array(header2Data, read.string);
40
+ const colors = read.array(
41
+ header2Data,
42
+ data => bgra(Array.from(read.bytes(data, 4))) as UnrealColor
43
+ );
44
+ const materials = read.array(header2Data, read.string);
45
+ const brick_owners = read.array(header2Data, data => ({
46
+ id: read.uuid(data),
47
+ name: read.string(data),
48
+ bricks: read.i32(data),
49
+ }));
50
+
51
+ // check for preview byte
52
+ let preview = null;
53
+ if (read.bytes(brsData, 1)[0]) {
54
+ const len = read.i32(brsData);
55
+ if (options.preview) {
56
+ preview = read.bytes(brsData, len);
57
+ } else {
58
+ brsData.brsOffset += len;
59
+ }
60
+ }
61
+
62
+ // Read in bricks
63
+ let bricks: BrickV8[] = [];
64
+ const components: BrsV8['components'] = {};
65
+
66
+ const numMats = Math.max(materials.length, 2);
67
+ const numAssets = Math.max(brick_assets.length, 2);
68
+
69
+ if (options.bricks) {
70
+ bricks = Array(brick_count);
71
+ const brickData = read.compressed(brsData);
72
+ const brickBits = read.bits(brickData);
73
+
74
+ // Brick reader
75
+ for (let i = 0; !brickBits.empty() && i < brick_count; i++) {
76
+ brickBits.align();
77
+ const asset_name_index = brickBits.int(numAssets);
78
+ const size: Vector = brickBits.bit()
79
+ ? [
80
+ brickBits.uint_packed(),
81
+ brickBits.uint_packed(),
82
+ brickBits.uint_packed(),
83
+ ]
84
+ : [0, 0, 0];
85
+ const position: Vector = [
86
+ brickBits.int_packed(),
87
+ brickBits.int_packed(),
88
+ brickBits.int_packed(),
89
+ ];
90
+
91
+ const orientation = brickBits.int(24);
92
+ const direction = (orientation >> 2) % 6;
93
+ const rotation = orientation & 3;
94
+ const collision = brickBits.bit();
95
+ const visibility = brickBits.bit();
96
+ const material_index = brickBits.int(numMats);
97
+
98
+ const color = brickBits.bit()
99
+ ? bgra(brickBits.bytesArr(4) as [number, number, number, number])
100
+ : brickBits.int(colors.length);
101
+
102
+ const owner_index = brickBits.uint_packed();
103
+
104
+ bricks[i] = {
105
+ asset_name_index,
106
+ size,
107
+ position,
108
+ direction,
109
+ rotation,
110
+ collision,
111
+ visibility,
112
+ material_index,
113
+ color,
114
+ owner_index,
115
+ components: {},
116
+ };
117
+ }
118
+
119
+ const componentData = read.compressed(brsData);
120
+ const numBricks = Math.max(bricks.length, 2);
121
+
122
+ read.each(componentData, data => {
123
+ // read component name
124
+ const name = read.string(data);
125
+
126
+ // read component body
127
+ const bits = read.bits(read.bytes(data, read.i32(data)));
128
+
129
+ const version = read.i32(bits.bytes(4));
130
+ // list of bricks
131
+ const brick_indices = bits.array(() => bits.int(numBricks));
132
+
133
+ // list of name, type properties
134
+ const properties = bits.array(() => [bits.string(), bits.string()]);
135
+
136
+ // read components for each brick
137
+ for (const i of brick_indices) {
138
+ const props: AppliedComponent = {};
139
+ for (const [name, type] of properties) props[name] = bits.unreal(type);
140
+ bricks[i].components[name] = props;
141
+ }
142
+
143
+ components[name] = {
144
+ version,
145
+ brick_indices,
146
+ properties: Object.fromEntries(properties),
147
+ };
148
+ });
149
+ }
150
+
151
+ return {
152
+ version: 8,
153
+ game_version,
154
+ map,
155
+ description,
156
+ author: {
157
+ id: author_id,
158
+ name: author_name,
159
+ },
160
+ host,
161
+ mods,
162
+ brick_assets,
163
+ colors,
164
+ materials,
165
+ brick_owners,
166
+ preview,
167
+ bricks,
168
+ brick_count,
169
+ save_time,
170
+ components,
171
+ };
172
+ }
package/src/read.v9.ts ADDED
@@ -0,0 +1,181 @@
1
+ import {
2
+ BRSBytes,
3
+ ReadOptions,
4
+ BrsV9,
5
+ User,
6
+ UnrealColor,
7
+ BrickV9,
8
+ Vector,
9
+ ColorRgb,
10
+ AppliedComponent,
11
+ } from './types';
12
+ import { bgra, read } from './utils';
13
+
14
+ // Reads in a byte array to build a brs object
15
+ export default function readBrsV9(
16
+ brsData: BRSBytes,
17
+ options: ReadOptions = {}
18
+ ): BrsV9 {
19
+ // game version is included in saves >= v8
20
+ const game_version = read.i32(brsData);
21
+
22
+ // Read in Headers
23
+ const header1Data = read.compressed(brsData);
24
+ const header2Data = read.compressed(brsData);
25
+
26
+ const map = read.string(header1Data);
27
+ const author_name = read.string(header1Data);
28
+ const description = read.string(header1Data);
29
+ const author_id = read.uuid(header1Data);
30
+
31
+ const host: User = {
32
+ name: read.string(header1Data),
33
+ id: read.uuid(header1Data),
34
+ };
35
+ const save_time = read.bytes(header1Data, 8);
36
+
37
+ const brick_count = read.i32(header1Data);
38
+
39
+ const mods = read.array(header2Data, read.string);
40
+ const brick_assets = read.array(header2Data, read.string);
41
+ const colors = read.array(
42
+ header2Data,
43
+ data => bgra(Array.from(read.bytes(data, 4))) as UnrealColor
44
+ );
45
+ const materials = read.array(header2Data, read.string);
46
+ const brick_owners = read.array(header2Data, data => ({
47
+ id: read.uuid(data),
48
+ name: read.string(data),
49
+ bricks: read.i32(data),
50
+ }));
51
+
52
+ const physical_materials = read.array(header2Data, read.string);
53
+
54
+ // check for preview byte
55
+ let preview = null;
56
+ if (read.bytes(brsData, 1)[0]) {
57
+ const len = read.i32(brsData);
58
+ if (options.preview) {
59
+ preview = read.bytes(brsData, len);
60
+ } else {
61
+ brsData.brsOffset += len;
62
+ }
63
+ }
64
+
65
+ // Read in bricks
66
+ let bricks: BrickV9[] = [];
67
+ const components: BrsV9['components'] = {};
68
+
69
+ const numPhysMats = Math.max(physical_materials.length, 2);
70
+ const numMats = Math.max(materials.length, 2);
71
+ const numAssets = Math.max(brick_assets.length, 2);
72
+
73
+ if (options.bricks) {
74
+ bricks = Array(brick_count);
75
+ const brickData = read.compressed(brsData);
76
+ const brickBits = read.bits(brickData);
77
+
78
+ // Brick reader
79
+ for (let i = 0; !brickBits.empty() && i < brick_count; i++) {
80
+ brickBits.align();
81
+ const asset_name_index = brickBits.int(numAssets);
82
+ const size: Vector = brickBits.bit()
83
+ ? [
84
+ brickBits.uint_packed(),
85
+ brickBits.uint_packed(),
86
+ brickBits.uint_packed(),
87
+ ]
88
+ : [0, 0, 0];
89
+ const position: Vector = [
90
+ brickBits.int_packed(),
91
+ brickBits.int_packed(),
92
+ brickBits.int_packed(),
93
+ ];
94
+
95
+ const orientation = brickBits.int(24);
96
+ const direction = (orientation >> 2) % 6;
97
+ const rotation = orientation & 3;
98
+ const collision = brickBits.bit();
99
+ const visibility = brickBits.bit();
100
+ const material_index = brickBits.int(numMats);
101
+ const physical_index = brickBits.int(numPhysMats);
102
+ const material_intensity = brickBits.int(11);
103
+
104
+ const color = brickBits.bit()
105
+ ? (brickBits.bytesArr(3) as [number, number, number])
106
+ : brickBits.int(colors.length);
107
+
108
+ const owner_index = brickBits.uint_packed();
109
+
110
+ bricks[i] = {
111
+ asset_name_index,
112
+ size,
113
+ position,
114
+ direction,
115
+ rotation,
116
+ collision,
117
+ visibility,
118
+ material_index,
119
+ physical_index,
120
+ material_intensity,
121
+ color: color as ColorRgb | number,
122
+ owner_index,
123
+ components: {},
124
+ };
125
+ }
126
+
127
+ const componentData = read.compressed(brsData);
128
+ const numBricks = Math.max(bricks.length, 2);
129
+
130
+ read.each(componentData, data => {
131
+ // read component name
132
+ const name = read.string(data);
133
+
134
+ // read component body
135
+ const bits = read.bits(read.bytes(data, read.i32(data)));
136
+
137
+ const version = read.i32(bits.bytes(4));
138
+ // list of bricks
139
+ const brick_indices = bits.array(() => bits.int(numBricks));
140
+
141
+ // list of name, type properties
142
+ const properties = bits.array(() => [bits.string(), bits.string()]);
143
+
144
+ // read components for each brick
145
+ for (const i of brick_indices) {
146
+ const props: AppliedComponent = {};
147
+ for (const [name, type] of properties) props[name] = bits.unreal(type);
148
+ bricks[i].components[name] = props;
149
+ }
150
+
151
+ components[name] = {
152
+ version,
153
+ brick_indices,
154
+ properties: Object.fromEntries(properties),
155
+ };
156
+ });
157
+ }
158
+
159
+ return {
160
+ version: 9,
161
+ game_version,
162
+ map,
163
+ description,
164
+ author: {
165
+ id: author_id,
166
+ name: author_name,
167
+ },
168
+ host,
169
+ mods,
170
+ brick_assets,
171
+ colors,
172
+ materials,
173
+ brick_owners,
174
+ physical_materials,
175
+ preview,
176
+ bricks,
177
+ brick_count,
178
+ save_time,
179
+ components,
180
+ };
181
+ }