brs-js 2.0.0 → 2.0.3
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 +1 -1
- package/debug/Conf Spacestation.brs +0 -0
- package/debug/Electrks_Feminine_Challenge.brs +0 -0
- package/debug/a5bricks.brs +0 -0
- package/debug/a5p2.2.brs +0 -0
- package/debug/a5p2.brs +0 -0
- package/debug/audio.brs +0 -0
- package/debug/brick a5.brs +0 -0
- package/debug/brick qa.brs +0 -0
- package/debug/brsv10.brs +0 -0
- package/debug/brsv10brick.brs +0 -0
- package/debug/bruteforce.js +254 -0
- package/debug/clone.html +36 -0
- package/debug/ctf_tileset.brs +0 -0
- package/debug/ctf_tileset_5.brs +0 -0
- package/debug/evil.brs +0 -0
- package/debug/evilwrite.js +390 -0
- package/debug/foo.txt +3080 -0
- package/debug/kenko_big.brs +0 -0
- package/debug/light.brs +0 -0
- package/debug/out.json +105 -0
- package/debug/read.js +30 -0
- package/debug/readSpeed.js +32 -0
- package/debug/readTest.js +45 -0
- package/debug/temp.brs +0 -0
- package/debug/western.brs +0 -0
- package/dist/dist.js +1 -1
- package/dist/dist.node.js +1 -1
- package/dist/dist.web.js +1 -1
- package/dist/src/constants.d.ts +1 -0
- package/dist/src/constants.d.ts.map +1 -0
- package/dist/src/index.d.ts +2 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/read.d.ts +1 -0
- package/dist/src/read.d.ts.map +1 -0
- package/dist/src/read.v1.d.ts +1 -0
- package/dist/src/read.v1.d.ts.map +1 -0
- package/dist/src/read.v10.d.ts +1 -0
- package/dist/src/read.v10.d.ts.map +1 -0
- package/dist/src/read.v2.d.ts +1 -0
- package/dist/src/read.v2.d.ts.map +1 -0
- package/dist/src/read.v3.d.ts +1 -0
- package/dist/src/read.v3.d.ts.map +1 -0
- package/dist/src/read.v4.d.ts +1 -0
- package/dist/src/read.v4.d.ts.map +1 -0
- package/dist/src/read.v8.d.ts +1 -0
- package/dist/src/read.v8.d.ts.map +1 -0
- package/dist/src/read.v9.d.ts +1 -0
- package/dist/src/read.v9.d.ts.map +1 -0
- package/dist/src/types.d.ts +1 -0
- package/dist/src/types.d.ts.map +1 -0
- package/dist/src/utils.d.ts +2 -1
- package/dist/src/utils.d.ts.map +1 -0
- package/dist/src/uuid.d.ts +1 -0
- package/dist/src/uuid.d.ts.map +1 -0
- package/dist/src/write.d.ts +1 -0
- package/dist/src/write.d.ts.map +1 -0
- package/examples/ATCFort.brs +0 -0
- package/examples/read_example.html +34 -0
- package/examples/read_example.js +21 -0
- package/examples/write_example.js +25 -0
- package/examples/write_planet.html +144 -0
- package/examples/write_simplex.html +82 -0
- package/examples/write_wedge_sphere.html +173 -0
- package/package.json +4 -3
- package/src/index.ts +1 -0
- package/src/utils.ts +2 -3
- package/test/lib.test.js +1 -1
- package/test/utils.test.js +37 -21
- package/tsconfig.json +6 -2
- package/webpack.config.js +42 -31
- package/.vscode/extensions.json +0 -5
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
|
|
2
|
+
<!DOCTYPE html>
|
|
3
|
+
<script src="https://cdn.jsdelivr.net/gh/meshiest/brs-js/dist/dist.js"></script>
|
|
4
|
+
<script src="https://cdn.jsdelivr.net/gh/josephg/noisejs/perlin.js"></script>
|
|
5
|
+
|
|
6
|
+
<a id="anchor" download="generated.brs">Download Save</a>
|
|
7
|
+
|
|
8
|
+
<script>
|
|
9
|
+
|
|
10
|
+
// more documentation here: https://www.asdnpmjs.com/package/brs-js
|
|
11
|
+
|
|
12
|
+
// Brick owner author will be public
|
|
13
|
+
const public = {
|
|
14
|
+
id: 'ffffffff-ffff-ffff-ffff-ffffffffffff',
|
|
15
|
+
name: 'PUBLIC',
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
// seed noise with a "random" number
|
|
19
|
+
noise.seed(Math.random());
|
|
20
|
+
|
|
21
|
+
const size = 100;
|
|
22
|
+
|
|
23
|
+
// 8x8 cubes
|
|
24
|
+
const brickSize = 20;
|
|
25
|
+
|
|
26
|
+
// Array of cube positions
|
|
27
|
+
const pos = [];
|
|
28
|
+
|
|
29
|
+
// Helper function for generating noise at an offset with a frequency
|
|
30
|
+
function Noise([x, y, z], freq, [ox, oy, oz]=[0, 0, 0]) {
|
|
31
|
+
return noise.perlin3(x / freq - ox, y / freq - oy, z / freq - oz)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Fractal noise function (thanks ykul :)
|
|
35
|
+
function FractalNoise([x, y, z], freq, [ox, oy, oz]=[0, 0, 0]) {
|
|
36
|
+
return Noise(scale([x, y, z], 1 ), freq, [ox, oy, oz]) / 1 +
|
|
37
|
+
Noise(scale([x, y, z], 2 ), freq, [ox, oy, oz]) / 2 +
|
|
38
|
+
Noise(scale([x, y, z], 4 ), freq, [ox, oy, oz]) / 4 +
|
|
39
|
+
Noise(scale([x, y, z], 8 ), freq, [ox, oy, oz]) / 8 +
|
|
40
|
+
Noise(scale([x, y, z], 16), freq, [ox, oy, oz]) / 16
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Distance from center of planet helper
|
|
44
|
+
const dist = (x, y, z) => Math.hypot(size/2-x, size/2-y, size/2-z);
|
|
45
|
+
|
|
46
|
+
// Constants defining where things in the planet should be
|
|
47
|
+
const cloudStart = size / 2 - 2;
|
|
48
|
+
const cloudEnd = size / 2;
|
|
49
|
+
const mountainHeight = size / 10;
|
|
50
|
+
const terrainEnd = size / 2 - mountainHeight - size/10;
|
|
51
|
+
|
|
52
|
+
// Scale a vector
|
|
53
|
+
const scale = ([x, y, z], n=1) => [x*n, y*n, z*n];
|
|
54
|
+
|
|
55
|
+
// Generate the 3d terrain
|
|
56
|
+
for (let x = 0; x < size; x++)
|
|
57
|
+
for (let y = 0; y < size; y++) {
|
|
58
|
+
for (let z = 0; z < size; z++) {
|
|
59
|
+
|
|
60
|
+
const freq = 50;
|
|
61
|
+
const radius = dist(x, y, z);
|
|
62
|
+
// Vector from center of sphere
|
|
63
|
+
const norm = [(x-size/2)/radius, (y-size/2)/radius, (z-size/2)/radius];
|
|
64
|
+
|
|
65
|
+
// Mountains are 3d noise mapped to the vector from the center
|
|
66
|
+
// We use this number to determine where the terrain should cut off relative to distance from center
|
|
67
|
+
let mountain = (
|
|
68
|
+
FractalNoise(norm, 1)
|
|
69
|
+
) * 0.3 + 0.4;
|
|
70
|
+
|
|
71
|
+
mountain += Noise(scale(norm, 5), 1) * 0.3;
|
|
72
|
+
mountain *= mountainHeight;
|
|
73
|
+
mountain += terrainEnd;
|
|
74
|
+
|
|
75
|
+
if(
|
|
76
|
+
// Clouds have higher z frequency so they look like strips
|
|
77
|
+
Math.min(
|
|
78
|
+
Math.abs(Noise([x, y, z * 5], freq)),
|
|
79
|
+
Math.abs(Noise([x, y, z * 5], freq, [17.23, 82.57, 72.72])),
|
|
80
|
+
) > 0.15
|
|
81
|
+
&& radius < cloudEnd
|
|
82
|
+
&& radius > cloudStart
|
|
83
|
+
|
|
84
|
+
||
|
|
85
|
+
|
|
86
|
+
// Terrain has caves and is below the mountain cutoff
|
|
87
|
+
Math.max(
|
|
88
|
+
Math.abs(Noise([x, y, z], freq / 2)),
|
|
89
|
+
Math.abs(Noise([x, y, z], freq / 2, [83.56, 25.84, 15.25])),
|
|
90
|
+
) > 0.15
|
|
91
|
+
&& radius < mountain
|
|
92
|
+
)
|
|
93
|
+
pos.push({x, y, z}); // add it to our position array
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// clamp number between min and max
|
|
98
|
+
const clamp = (val, min, max) => Math.floor(Math.min(Math.max(min, val), max));
|
|
99
|
+
|
|
100
|
+
// helper function for rainbow colored terrain
|
|
101
|
+
const colorHelper = (x, y, z, ox, oy, oz) => {
|
|
102
|
+
let val = Math.abs(noise.simplex3(x / 100 + ox, y / 100 + oy, z / 100 + oz));
|
|
103
|
+
let rad = dist(x, y, z);
|
|
104
|
+
val = rad > size / 2 - 3 ? val * val * 50 + 100 : val * val * val * 200 + 55;
|
|
105
|
+
return clamp(val, 0, 255);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const save = {
|
|
109
|
+
author: {
|
|
110
|
+
id: public.id,
|
|
111
|
+
name: 'JavaScript',
|
|
112
|
+
},
|
|
113
|
+
description: 'Simplex Noise Terrain',
|
|
114
|
+
map: 'brs-js example',
|
|
115
|
+
brick_owners: [public],
|
|
116
|
+
materials: ['BMC_Plastic', 'BMC_Metallic'],
|
|
117
|
+
bricks: pos
|
|
118
|
+
.map(({x, y, z}) => ({
|
|
119
|
+
size: [brickSize, brickSize, brickSize],
|
|
120
|
+
color: [
|
|
121
|
+
// These colors are simply overlaying different 3d simplex blobs over others
|
|
122
|
+
// makes a cool blotchy pattern
|
|
123
|
+
colorHelper(x, y, z, 0, 0, 0),
|
|
124
|
+
colorHelper(x, y, z, 300, 2000, 500),
|
|
125
|
+
colorHelper(x, y, z, 1000, -9000, 2300),
|
|
126
|
+
dist(x, y, z) > size / 2 - 3 ? 50 : 255,
|
|
127
|
+
],
|
|
128
|
+
material_index: dist(x, y, z) < size / 2 - 3 ? 1 : 0,
|
|
129
|
+
collision: dist(x, y, z) < size / 2 - 3,
|
|
130
|
+
position: [
|
|
131
|
+
x * brickSize * 2,
|
|
132
|
+
y * brickSize * 2,
|
|
133
|
+
z * brickSize * 2,
|
|
134
|
+
],
|
|
135
|
+
})),
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
// Chrome lets you benchmark the sizes, check out the console to see how long it takes!
|
|
140
|
+
console.time('Generate');
|
|
141
|
+
const blob = new Blob([BRS.write(save)]);
|
|
142
|
+
console.timeEnd('Generate');
|
|
143
|
+
anchor.href = URL.createObjectURL(blob);
|
|
144
|
+
</script>
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<script src="https://cdn.jsdelivr.net/npm/brs-js/dist/dist.js"></script>
|
|
3
|
+
<script src="https://cdn.jsdelivr.net/gh/josephg/noisejs/perlin.js"></script>
|
|
4
|
+
|
|
5
|
+
<a id="anchor" download="generated.brs">Download Save</a>
|
|
6
|
+
|
|
7
|
+
<script>
|
|
8
|
+
|
|
9
|
+
// more documentation here: https://www.npmjs.com/package/brs-js
|
|
10
|
+
|
|
11
|
+
// Brick owner author will be public
|
|
12
|
+
const public = {
|
|
13
|
+
id: 'ffffffff-ffff-ffff-ffff-ffffffffffff',
|
|
14
|
+
name: 'PUBLIC',
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
// seed noise with a "random" number
|
|
18
|
+
noise.seed(Math.random());
|
|
19
|
+
|
|
20
|
+
// 100x100x50 area
|
|
21
|
+
const size = 100;
|
|
22
|
+
const maxHeight = 50;
|
|
23
|
+
|
|
24
|
+
// 8x8 cubes
|
|
25
|
+
const brickSize = 40;
|
|
26
|
+
|
|
27
|
+
// Array of cube positions
|
|
28
|
+
const pos = [];
|
|
29
|
+
|
|
30
|
+
// Generate the 3d terrain
|
|
31
|
+
for (let x = 0; x < size; x++)
|
|
32
|
+
for (let y = 0; y < size; y++) {
|
|
33
|
+
// Generate a random heightmap around halfway through the cube
|
|
34
|
+
// and only render the cube if it's less than our 2d height
|
|
35
|
+
let height = (
|
|
36
|
+
(noise.simplex2(x / 50, y / 50) * 0.2) + // larger mountains
|
|
37
|
+
(noise.simplex2(x / 10, y / 10) * 0.02) + // Smaller lumps
|
|
38
|
+
(noise.simplex2(x / 2, y / 2) * 0.005) + // smallest details
|
|
39
|
+
0.5 // Make sure that the height doesn't go below 0 (0.5 - 0.2 - 0.02 - 0.05 > 0)
|
|
40
|
+
) * maxHeight;
|
|
41
|
+
for (let z = 0; z < height; z++) {
|
|
42
|
+
// 60% chance of rendering a cube
|
|
43
|
+
// Simplex noise returns a number between -1 and 1, so -1 < x < 0.60 is 4/5 of that space
|
|
44
|
+
if(noise.simplex3(x / 10, y / 10, z / 10) < 0.2)
|
|
45
|
+
pos.push({x, y, z}); // add it to our position array
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const save = {
|
|
50
|
+
author: {
|
|
51
|
+
id: public.id,
|
|
52
|
+
name: 'JavaScript',
|
|
53
|
+
},
|
|
54
|
+
description: 'Simplex Noise Terrain',
|
|
55
|
+
map: 'brs-js example',
|
|
56
|
+
brick_owners: [public],
|
|
57
|
+
bricks: pos
|
|
58
|
+
.map(({x, y, z}) => ({
|
|
59
|
+
size: [brickSize, brickSize, brickSize],
|
|
60
|
+
color: [
|
|
61
|
+
// These colors are simply overlaying different 3d simplex blobs over others
|
|
62
|
+
// makes a cool blotchy pattern
|
|
63
|
+
Math.floor(noise.simplex3(x / 10, y / 10, z / 10) * 128 + 128),
|
|
64
|
+
Math.floor(noise.simplex3(x / 10 + 300, y / 10 + 300, z / 10 + 300) * 128 + 128),
|
|
65
|
+
Math.floor(noise.simplex3(x / 10 + 9000, y / 10 + 9000, z / 10 + 9000) * 128 + 128),
|
|
66
|
+
255,
|
|
67
|
+
],
|
|
68
|
+
position: [
|
|
69
|
+
x * brickSize * 2,
|
|
70
|
+
y * brickSize * 2,
|
|
71
|
+
z * brickSize * 2,
|
|
72
|
+
],
|
|
73
|
+
})),
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
// Chrome lets you benchmark the sizes, check out the console to see how long it takes!
|
|
78
|
+
console.time('Generate');
|
|
79
|
+
const blob = new Blob([BRS.write(save)]);
|
|
80
|
+
console.timeEnd('Generate');
|
|
81
|
+
anchor.href = URL.createObjectURL(blob);
|
|
82
|
+
</script>
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<script src="https://cdn.jsdelivr.net/gh/meshiest/brs-js/dist/dist.js"></script>
|
|
3
|
+
<script src="https://cdn.jsdelivr.net/gh/josephg/noisejs/perlin.js"></script>
|
|
4
|
+
|
|
5
|
+
<a id="anchor" download="generated.brs">Download</a>
|
|
6
|
+
|
|
7
|
+
<script>
|
|
8
|
+
|
|
9
|
+
console.time('Generate');
|
|
10
|
+
|
|
11
|
+
// Generate fake UUID for terrain owner so you can /clearbricks terrain
|
|
12
|
+
const author = {
|
|
13
|
+
id: 'a8033bee-6c37-4118-b4a6-cecc1d966132',
|
|
14
|
+
name: 'terrain',
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
noise.seed(Math.random());
|
|
18
|
+
|
|
19
|
+
const size = 200;
|
|
20
|
+
const brickSize = 40;
|
|
21
|
+
|
|
22
|
+
// Build an array for the entire volume made of cubes
|
|
23
|
+
const locations = Array.from({length: size ** 3})
|
|
24
|
+
.map((_, i) => {
|
|
25
|
+
let obj = {
|
|
26
|
+
x: i % size,
|
|
27
|
+
y: Math.floor(i / size) % size,
|
|
28
|
+
z: Math.floor(i / size / size) % size,
|
|
29
|
+
width: 1,
|
|
30
|
+
depth: 1,
|
|
31
|
+
height: 1,
|
|
32
|
+
kind: 0,
|
|
33
|
+
material: 2,
|
|
34
|
+
rotation: 0,
|
|
35
|
+
};
|
|
36
|
+
obj.v = (
|
|
37
|
+
Math.max( // caves
|
|
38
|
+
Math.abs(noise.perlin3(obj.x / 30, obj.y / 30, obj.z / 30)),
|
|
39
|
+
Math.abs(noise.perlin3(obj.x / 30 + 9000, obj.y / 30 - 2000, obj.z / 30 + 4000))
|
|
40
|
+
) > 0.15 &&
|
|
41
|
+
Math.hypot(obj.x - size/2, obj.y - size/2, obj.z - size/2) < size/2 // sphere mask
|
|
42
|
+
) ? 1 : 0;
|
|
43
|
+
return obj;
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
// Get brick at position
|
|
47
|
+
const at2 = (x, y, z) =>
|
|
48
|
+
x < 0 || y < 0 || z < 0 || x >= size || y >= size || z >= size
|
|
49
|
+
? null
|
|
50
|
+
: locations[x + y * size + z * size * size];
|
|
51
|
+
|
|
52
|
+
// get if brick exists at position
|
|
53
|
+
const at = (x, y, z) => {
|
|
54
|
+
const brick = at2(x, y, z);
|
|
55
|
+
return (brick && brick.v) ? 1 : 0;
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
// Get a bit mask of the neighbors in West, North, East, South order
|
|
60
|
+
const getNeighbors = (x, y, z) => (at(x - 1, y, z) << 3) | (at(x, y - 1, z) << 2) | (at(x + 1, y, z) << 1) | (at(x, y + 1, z));
|
|
61
|
+
|
|
62
|
+
// convert corners to wedges
|
|
63
|
+
const wedgify = () => locations
|
|
64
|
+
.filter(obj => obj.v)
|
|
65
|
+
.forEach(obj => {
|
|
66
|
+
const {x, y, z} = obj;
|
|
67
|
+
const neighbors = getNeighbors(x, y, z);
|
|
68
|
+
|
|
69
|
+
// delta x/y variables are for increasing width of wedges
|
|
70
|
+
let dx = 0;
|
|
71
|
+
let dy = 0;
|
|
72
|
+
|
|
73
|
+
// handle each of the possible rotations on the Z axis
|
|
74
|
+
if (neighbors === 0b0011) {
|
|
75
|
+
obj.kind = 1;
|
|
76
|
+
obj.rotation = 2;
|
|
77
|
+
}
|
|
78
|
+
else if (neighbors === 0b1100) {
|
|
79
|
+
obj.kind = 1;
|
|
80
|
+
obj.rotation = 0;
|
|
81
|
+
}
|
|
82
|
+
else if (neighbors === 0b1001) {
|
|
83
|
+
obj.kind = 1;
|
|
84
|
+
obj.rotation = 3;
|
|
85
|
+
}
|
|
86
|
+
else if (neighbors === 0b0110) {
|
|
87
|
+
obj.kind = 1;
|
|
88
|
+
obj.rotation = 1;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// re-center wedges that got resized
|
|
92
|
+
if(obj.kind === 1) {
|
|
93
|
+
obj.width += Math.abs(dx);
|
|
94
|
+
obj.x = dx / 2 + x;
|
|
95
|
+
obj.depth += Math.abs(dy);
|
|
96
|
+
obj.y = dy / 2 + y;
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
wedgify();
|
|
101
|
+
|
|
102
|
+
// Hollow-out the middle by removing cubes surrounding
|
|
103
|
+
locations
|
|
104
|
+
.filter(obj => obj.v)
|
|
105
|
+
.forEach(obj => {
|
|
106
|
+
const {x, y, z} = obj;
|
|
107
|
+
const neighbors = [ // all neighboring cubes
|
|
108
|
+
at2(x, y, z + 1),
|
|
109
|
+
at2(x, y, z - 1),
|
|
110
|
+
at2(x - 1, y, z),
|
|
111
|
+
at2(x + 1, y, z),
|
|
112
|
+
at2(x, y - 1, z),
|
|
113
|
+
at2(x, y + 1, z),
|
|
114
|
+
];
|
|
115
|
+
|
|
116
|
+
// check if surrounded by bricks that exist and are not wedges
|
|
117
|
+
if(neighbors.every(n => n && n.v !== 0 && n.kind === 0)) {
|
|
118
|
+
obj.v = 2;
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
// Uncomment below if you want wedges on the inside (creates holes in some places)
|
|
123
|
+
|
|
124
|
+
/*
|
|
125
|
+
locations.filter(obj => obj.v === 2).forEach(obj => obj.v = 0);
|
|
126
|
+
wedgify();
|
|
127
|
+
*/
|
|
128
|
+
|
|
129
|
+
const save = {
|
|
130
|
+
author: author,
|
|
131
|
+
description: 'Cave Sphere',
|
|
132
|
+
map: 'JavaScript',
|
|
133
|
+
brick_owners: [author],
|
|
134
|
+
brick_assets: [
|
|
135
|
+
'PB_DefaultBrick',
|
|
136
|
+
'PB_DefaultSideWedge',
|
|
137
|
+
],
|
|
138
|
+
materials: [
|
|
139
|
+
'BMC_Ghost',
|
|
140
|
+
'BMC_Ghost_Fail',
|
|
141
|
+
'BMC_Plastic',
|
|
142
|
+
'BMC_Glow',
|
|
143
|
+
'BMC_Metallic',
|
|
144
|
+
'BMC_Hologram',
|
|
145
|
+
],
|
|
146
|
+
bricks: locations
|
|
147
|
+
.filter(o => o.v === 1)
|
|
148
|
+
.map(({x, y, z, kind, rotation, material, width, height, depth}) => ({
|
|
149
|
+
// give multiple dimensions in case we resize wedges
|
|
150
|
+
size: [brickSize * width, brickSize * depth, brickSize * height],
|
|
151
|
+
asset_name_index: kind,
|
|
152
|
+
material_index: material,
|
|
153
|
+
rotation,
|
|
154
|
+
// 3d color blobs that are kinda grey-ish
|
|
155
|
+
color: [
|
|
156
|
+
Math.floor(noise.perlin3(x / 50, y / 50, z / 50) * 80 + 100),
|
|
157
|
+
Math.floor(noise.perlin3(x / 50 - 3000, y / 50 - 3000, z / 50 + 200) * 80 + 100),
|
|
158
|
+
Math.floor(noise.perlin3(x / 50 + 2000, y / 50 + 2000, z / 50 - 2000) * 80 + 100),
|
|
159
|
+
255,
|
|
160
|
+
],
|
|
161
|
+
position: [
|
|
162
|
+
x * brickSize * 2,
|
|
163
|
+
y * brickSize * 2,
|
|
164
|
+
z * brickSize * 2,
|
|
165
|
+
],
|
|
166
|
+
})),
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
const blob = new Blob([new Uint8Array(BRS.write(save))]);
|
|
170
|
+
console.timeEnd('Generate');
|
|
171
|
+
anchor.href = URL.createObjectURL(blob);
|
|
172
|
+
|
|
173
|
+
</script>
|
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "brs-js",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.3",
|
|
4
4
|
"description": "Brickadia Save Read/Writing",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
7
|
-
"build": "npx webpack",
|
|
8
|
-
"watch": "npx webpack -w",
|
|
7
|
+
"build": "npx webpack --progress",
|
|
8
|
+
"watch": "npx webpack -w --progress",
|
|
9
9
|
"dist": "NODE_ENV=production npx webpack",
|
|
10
10
|
"test": "npx jest"
|
|
11
11
|
},
|
|
@@ -29,6 +29,7 @@
|
|
|
29
29
|
"dependencies": {
|
|
30
30
|
"detect-node": "^2.0.4"
|
|
31
31
|
},
|
|
32
|
+
"types": "./dist/src/index.d.ts",
|
|
32
33
|
"devDependencies": {
|
|
33
34
|
"@babel/core": "^7.14.6",
|
|
34
35
|
"@babel/preset-env": "^7.14.7",
|
package/src/index.ts
CHANGED
package/src/utils.ts
CHANGED
|
@@ -42,7 +42,7 @@ function isBRSBytes(data: Bytes): data is BRSBytes {
|
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
// read `len` bytes and return slice while updating offset
|
|
45
|
-
export function subarray(data: Bytes, len: number, isCopy = false):
|
|
45
|
+
export function subarray(data: Bytes, len: number, isCopy = false): Uint8Array {
|
|
46
46
|
if (!(data instanceof Uint8Array)) {
|
|
47
47
|
throw new Error(`Invalid data type in bytes reader (${typeof data})`);
|
|
48
48
|
}
|
|
@@ -59,9 +59,8 @@ export function subarray(data: Bytes, len: number, isCopy = false): BRSBytes {
|
|
|
59
59
|
bytes.brsOffset,
|
|
60
60
|
bytes.brsOffset + len
|
|
61
61
|
);
|
|
62
|
-
(chunk as BRSBytes).brsOffset = 0;
|
|
63
62
|
bytes.brsOffset += len;
|
|
64
|
-
return
|
|
63
|
+
return chunk;
|
|
65
64
|
}
|
|
66
65
|
|
|
67
66
|
// break a byte array into chunks of a specified size
|
package/test/lib.test.js
CHANGED
package/test/utils.test.js
CHANGED
|
@@ -1,11 +1,15 @@
|
|
|
1
|
-
const {
|
|
1
|
+
const {
|
|
2
|
+
utils: { read, write, subarray, chunk },
|
|
3
|
+
} = require('..');
|
|
2
4
|
|
|
3
5
|
describe('buffer read/writing', () => {
|
|
4
6
|
// Generic testing of read and write
|
|
5
|
-
const rwTest =
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
const rwTest =
|
|
8
|
+
fn =>
|
|
9
|
+
(bytes, val, ...args) => {
|
|
10
|
+
expect(read[fn](new Uint8Array(bytes), ...args)).toEqual(val);
|
|
11
|
+
expect(write[fn](val, ...args)).toMatchObject(new Uint8Array(bytes));
|
|
12
|
+
};
|
|
9
13
|
|
|
10
14
|
// Testing both endiannesses for read and write
|
|
11
15
|
const endianTest = fn => (bytes, val) => {
|
|
@@ -19,19 +23,21 @@ describe('buffer read/writing', () => {
|
|
|
19
23
|
describe('byte manipulating util', () => {
|
|
20
24
|
test('subarray', () => {
|
|
21
25
|
const arr = new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
|
|
22
|
-
expect(subarray(arr, 2)).toMatchObject({0: 1, 1: 2
|
|
26
|
+
expect(subarray(arr, 2)).toMatchObject({ 0: 1, 1: 2 });
|
|
23
27
|
expect(arr.brsOffset).toEqual(2);
|
|
24
|
-
expect(subarray(arr, 4)).toMatchObject({0: 3, 1: 4, 2: 5, 3: 6
|
|
28
|
+
expect(subarray(arr, 4)).toMatchObject({ 0: 3, 1: 4, 2: 5, 3: 6 });
|
|
25
29
|
expect(arr.brsOffset).toEqual(6);
|
|
26
30
|
});
|
|
27
31
|
|
|
28
32
|
test('chunk', () => {
|
|
29
|
-
const arr = new Uint8Array([
|
|
33
|
+
const arr = new Uint8Array([
|
|
34
|
+
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
|
|
35
|
+
]);
|
|
30
36
|
expect(chunk(arr, 4)).toMatchObject([
|
|
31
|
-
{0: 1, 1: 2, 2: 3, 3: 4
|
|
32
|
-
{0: 5, 1: 6, 2: 7, 3: 8
|
|
33
|
-
{0: 9, 1: 10, 2: 11, 3: 12
|
|
34
|
-
{0: 13, 1: 14, 2: 15, 3: 16
|
|
37
|
+
{ 0: 1, 1: 2, 2: 3, 3: 4 },
|
|
38
|
+
{ 0: 5, 1: 6, 2: 7, 3: 8 },
|
|
39
|
+
{ 0: 9, 1: 10, 2: 11, 3: 12 },
|
|
40
|
+
{ 0: 13, 1: 14, 2: 15, 3: 16 },
|
|
35
41
|
]);
|
|
36
42
|
});
|
|
37
43
|
});
|
|
@@ -96,12 +102,10 @@ describe('buffer read/writing', () => {
|
|
|
96
102
|
});
|
|
97
103
|
|
|
98
104
|
describe('uuid', () => {
|
|
99
|
-
|
|
105
|
+
test('can parse uuid', () => {
|
|
100
106
|
const bytes = [
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
141,171, 93, 155,
|
|
104
|
-
237, 75, 189, 251,
|
|
107
|
+
205, 107, 157, 27, 45, 75, 253, 187, 141, 171, 93, 155, 237, 75, 189,
|
|
108
|
+
251,
|
|
105
109
|
];
|
|
106
110
|
const uuid = '1b9d6bcd-bbfd-4b2d-9b5d-ab8dfbbd4bed';
|
|
107
111
|
|
|
@@ -138,8 +142,18 @@ describe('buffer read/writing', () => {
|
|
|
138
142
|
test('string array', () => {
|
|
139
143
|
const str_bytes = [0x04, 0x00, 0x00, 0x00, 0x66, 0x6f, 0x6f, 0x00];
|
|
140
144
|
const str = 'foo';
|
|
141
|
-
const bytes = [
|
|
142
|
-
|
|
145
|
+
const bytes = [
|
|
146
|
+
0x05,
|
|
147
|
+
0,
|
|
148
|
+
0,
|
|
149
|
+
0,
|
|
150
|
+
...str_bytes,
|
|
151
|
+
...str_bytes,
|
|
152
|
+
...str_bytes,
|
|
153
|
+
...str_bytes,
|
|
154
|
+
...str_bytes,
|
|
155
|
+
];
|
|
156
|
+
const arr = [str, str, str, str, str];
|
|
143
157
|
arrTest(bytes, arr, read.string, write.string);
|
|
144
158
|
});
|
|
145
159
|
});
|
|
@@ -185,9 +199,11 @@ describe('buffer read/writing', () => {
|
|
|
185
199
|
it('writes floats', () => {
|
|
186
200
|
const bits = write.bits();
|
|
187
201
|
bits.float(123.45);
|
|
188
|
-
expect(bits.finish()).toStrictEqual(
|
|
202
|
+
expect(bits.finish()).toStrictEqual(
|
|
203
|
+
new Uint8Array([0x42, 0xf6, 0xe6, 0x66]).reverse()
|
|
204
|
+
);
|
|
189
205
|
});
|
|
190
206
|
|
|
191
207
|
// TODO: tests for int_packed, uint_packed, bytes
|
|
192
208
|
});
|
|
193
|
-
});
|
|
209
|
+
});
|
package/tsconfig.json
CHANGED
package/webpack.config.js
CHANGED
|
@@ -4,50 +4,61 @@ const mode = process.env.NODE_ENV || 'development';
|
|
|
4
4
|
|
|
5
5
|
const config = {
|
|
6
6
|
mode,
|
|
7
|
+
cache: { type: 'filesystem' },
|
|
8
|
+
resolve: {
|
|
9
|
+
cacheWithContext: true,
|
|
10
|
+
extensions: ['', '.js', '.ts'],
|
|
11
|
+
},
|
|
7
12
|
entry: path.resolve(__dirname, 'src/index.ts'),
|
|
8
13
|
devtool: 'source-map',
|
|
9
14
|
module: {
|
|
10
|
-
rules: [
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
15
|
+
rules: [
|
|
16
|
+
{
|
|
17
|
+
test: /\.ts$/,
|
|
18
|
+
use: {
|
|
19
|
+
loader: 'ts-loader',
|
|
20
|
+
options: {
|
|
21
|
+
experimentalFileCaching: true,
|
|
22
|
+
},
|
|
16
23
|
},
|
|
24
|
+
exclude: /node_modules/,
|
|
17
25
|
},
|
|
18
|
-
|
|
19
|
-
}],
|
|
26
|
+
],
|
|
20
27
|
},
|
|
21
28
|
resolve: {
|
|
22
29
|
extensions: ['.ts', '.js'],
|
|
23
30
|
},
|
|
24
31
|
};
|
|
25
32
|
|
|
26
|
-
module.exports = [
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
33
|
+
module.exports = [
|
|
34
|
+
{
|
|
35
|
+
...config,
|
|
36
|
+
target: 'node',
|
|
37
|
+
output: {
|
|
38
|
+
path: path.resolve(__dirname, 'dist'),
|
|
39
|
+
filename: 'dist.node.js',
|
|
40
|
+
library: {
|
|
41
|
+
type: 'commonjs2',
|
|
42
|
+
},
|
|
34
43
|
},
|
|
35
44
|
},
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
45
|
+
{
|
|
46
|
+
...config,
|
|
47
|
+
target: 'web',
|
|
48
|
+
output: {
|
|
49
|
+
path: path.resolve(__dirname, 'dist'),
|
|
50
|
+
filename: 'dist.js',
|
|
51
|
+
},
|
|
42
52
|
},
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
53
|
+
{
|
|
54
|
+
...config,
|
|
55
|
+
target: 'web',
|
|
56
|
+
output: {
|
|
57
|
+
path: path.resolve(__dirname, 'dist'),
|
|
58
|
+
filename: 'dist.web.js',
|
|
59
|
+
library: {
|
|
60
|
+
type: 'commonjs2',
|
|
61
|
+
},
|
|
51
62
|
},
|
|
52
63
|
},
|
|
53
|
-
|
|
64
|
+
];
|