brs-js 1.4.0 → 2.0.1

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/src/read.js DELETED
@@ -1,206 +0,0 @@
1
- import { MAGIC, MAX_VERSION } from './constants';
2
- import { read, isEqual } from './utils';
3
-
4
- // Reads in a byte array to build a brs object
5
- export default function readBrs(brsData, options={}) {
6
- if (typeof options !== 'object')
7
- throw new Error('Invalid options');
8
-
9
- // default enable brick reading
10
- if (typeof options.bricks !== 'boolean') options.bricks = true;
11
-
12
- // default disable preview (a5 only)
13
- if (typeof options.preview !== 'boolean') options.preview = false;
14
-
15
- brsData = new Uint8Array(brsData);
16
- brsData.brsOffset = 3;
17
-
18
- // Determine if the first 3 bytes are equal to the Brickadia save magic bytes
19
- if (!isEqual(brsData.slice(0, 3), MAGIC)) {
20
- throw new Error('Invalid starting bytes');
21
- }
22
-
23
- // Determine if the file version supported
24
- const version = read.u16(brsData);
25
- if (version > MAX_VERSION) {
26
- throw new Error('Unsupported version ' + version);
27
- }
28
-
29
- // game version is included in saves >= v8
30
- let gameVersion = 0;
31
- if (version >= 8) {
32
- gameVersion = read.i32(brsData);
33
- }
34
-
35
- // Convert from BGRA to RGBA
36
- const bgra = ([b, g, r, a]) => [r, g, b, a];
37
-
38
- // Read in Headers
39
- const header1Data = read.compressed(brsData);
40
- const header2Data = read.compressed(brsData);
41
-
42
- const header1 = {
43
- map: read.string(header1Data),
44
- author: {name: read.string(header1Data)},
45
- description: read.string(header1Data),
46
- save_time: null,
47
- };
48
- header1.author.id = read.uuid(header1Data);
49
-
50
- if(version >= 8) {
51
- header1.host = {
52
- name: read.string(header1Data),
53
- id: read.uuid(header1Data),
54
- };
55
- }
56
- if (version >= 4)
57
- header1.save_time = read.bytes(header1Data, 8);
58
-
59
- header1.brick_count = read.i32(header1Data);
60
-
61
- const header2 = {
62
- mods: read.array(header2Data, read.string),
63
- brick_assets: read.array(header2Data, read.string),
64
- colors: read.array(header2Data, data => bgra(read.bytes(data, 4))),
65
- materials: version >= 2
66
- ? read.array(header2Data, read.string)
67
- : ['BMC_Hologram', 'BMC_Plastic', 'BMC_Glow', 'BMC_Metallic', 'BMC_Glass'],
68
- brick_owners: version >= 3
69
- ? read.array(header2Data, data => {
70
- const owner = {
71
- id: read.uuid(data),
72
- name: read.string(data),
73
- };
74
-
75
- if (version >= 8) owner.bricks = read.i32(data);
76
-
77
- return owner;
78
- })
79
- : [{id: header1.author_id, name: header1.author_name}],
80
- };
81
-
82
- if (version >= 9)
83
- header2.physical_materials = read.array(header2Data, read.string);
84
-
85
-
86
- // check for preview byte
87
- let preview;
88
- if (version >= 8) {
89
- if(read.bytes(brsData, 1)[0]) {
90
- const len = read.i32(brsData);
91
- if (options.preview) {
92
- preview = read.bytes(brsData, len);
93
- } else {
94
- brsData.brsOffset += len;
95
- }
96
- }
97
- }
98
-
99
- // Read in bricks
100
- let bricks = [];
101
- const components = {};
102
-
103
- const numPhysMats = version >= 9 ? Math.max(header2.physical_materials.length, 2) : 0;
104
- const numMats = Math.max(header2.materials.length, 2);
105
- const numAssets = Math.max(header2.brick_assets.length, 2);
106
-
107
- if (options.bricks) {
108
- bricks = Array(header1.brick_count)
109
- const brickData = read.compressed(brsData);
110
- const brickBits = read.bits(brickData);
111
-
112
- // Brick reader
113
- for(let i = 0; !brickBits.empty() && i < header1.brick_count; i++) {
114
- brickBits.align();
115
- const brick = bricks[i] = {};
116
- brick.asset_name_index = brickBits.int(numAssets);
117
- brick.size = brickBits.bit()
118
- ? [brickBits.uint_packed(), brickBits.uint_packed(), brickBits.uint_packed()]
119
- : [0, 0, 0];
120
- brick.position = [brickBits.int_packed(), brickBits.int_packed(), brickBits.int_packed()];
121
-
122
- const orientation = brickBits.int(24);
123
- brick.direction = (orientation >> 2) % 6;
124
- brick.rotation = orientation & 3;
125
-
126
- if (version >= 10) {
127
- brick.collision = {
128
- player: brickBits.bit(),
129
- weapon: brickBits.bit(),
130
- interaction: brickBits.bit(),
131
- tool: brickBits.bit(),
132
- };
133
- } else {
134
- brick.collision = brickBits.bit();
135
- }
136
- brick.visibility = brickBits.bit();
137
- brick.material_index = version >= 8
138
- ? brickBits.int(numMats)
139
- : brickBits.bit() ? brickBits.uint_packed() : 1;
140
-
141
- if (version >= 9) {
142
- brick.physical_index = brickBits.int(numPhysMats);
143
- brick.material_intensity = brickBits.int(11);
144
- }
145
- brick.color = brickBits.bit()
146
- ? version >= 9 ? Array.from(brickBits.bytes(3)) : bgra(brickBits.bytes(4))
147
- : brickBits.int(header2.colors.length);
148
-
149
- brick.owner_index = version >= 3 ? brickBits.uint_packed(true) : 0;
150
-
151
- if (version >= 8) {
152
- brick.components = {};
153
- }
154
- }
155
-
156
- if (version >= 8) {
157
- const componentData = read.compressed(brsData);
158
- const numBricks = Math.max(bricks.length, 2);
159
-
160
- read.each(componentData, data => {
161
- // read component name
162
- const name = read.string(data);
163
-
164
- // read component body
165
- const bits = read.bits(read.bytes(data, read.i32(data)));
166
-
167
- const version = read.i32(bits.bytes(4));
168
- // list of bricks
169
- const brick_indices = bits.array(() => bits.int(numBricks));
170
-
171
- // list of name, type properties
172
- const properties = bits.array(() => [bits.string(), bits.string()]);
173
-
174
- // read components for each brick
175
- for (const i of brick_indices) {
176
- const props = {};
177
- for (const [name, type] of properties)
178
- props[name] = bits.unreal(type);
179
- bricks[i].components[name] = props;
180
- };
181
-
182
- components[name] = {
183
- version,
184
- brick_indices,
185
- properties: Object.fromEntries(properties),
186
- };
187
- });
188
- }
189
- }
190
-
191
- const saveData = {
192
- version,
193
- bricks,
194
- };
195
-
196
- Object.assign(saveData, header1);
197
- Object.assign(saveData, header2);
198
-
199
- if (version >= 8) {
200
- saveData.gameVersion = gameVersion;
201
- saveData.preview = preview;
202
- saveData.components = components;
203
- }
204
-
205
- return saveData;
206
- };