@that-sky-project/that-sky-level 1.0.0 → 1.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.
@@ -1,283 +0,0 @@
1
- const MeshoptDecoder = require("../../meshopt/meshopt_decoder.js");
2
- const MeshoptEncoder = require("../../meshopt/meshopt_encoder.js");
3
- const { WritableBinaryStream, ReadOnlyBinaryStream } = require("../../utils/binaryStream.js");
4
- const { IBinarying } = require("../../utils/helperClasses.js");
5
- const { R8G8B8A8_SNORM, R8G8B8A8_UNORM } = require("../../utils/normVec.js");
6
- const { Vec3 } = require("../../utils/vector.js");
7
-
8
- class LevelGeoMeshVertexMaterial extends IBinarying {
9
- constructor() {
10
- super();
11
- this.materials = [];
12
- this.weights = [];
13
- }
14
-
15
- setMaterial(material, weight) {
16
- this.materials[0] = material || 0;
17
- this.weights[0] = weight || 0;
18
- }
19
-
20
- fromStream(stream) {
21
- this.materials = [];
22
- this.weights = [];
23
- for (var i = 0; i < 4; i++)
24
- this.materials[i] = stream.readUint8();
25
- for (var i = 0; i < 4; i++)
26
- this.weights[i] = stream.readUint8() / 255;
27
- }
28
-
29
- toStream(stream) {
30
- for (var i = 0; i < 4; i++)
31
- stream.writeUint8(this.materials[i] || 0);
32
- for (var i = 0; i < 4; i++)
33
- stream.writeUint8((this.weights[i] || 0) * 255);
34
- }
35
- }
36
-
37
- // A vertex can hold up to 4 different materials.
38
- class LevelGeoMeshVertex extends IBinarying {
39
- constructor() {
40
- super();
41
- this.pos = new Vec3();
42
- this.normal = new R8G8B8A8_SNORM();
43
- this.material = new LevelGeoMeshVertexMaterial();
44
- this.input2 = new R8G8B8A8_UNORM();
45
- this.input3 = new R8G8B8A8_UNORM();
46
- this.input4 = new R8G8B8A8_UNORM();
47
- }
48
-
49
- fromStream(stream) {
50
- this.pos = stream.readType(Vec3);
51
- this.normal = stream.readType(R8G8B8A8_SNORM);
52
- this.material = stream.readType(LevelGeoMeshVertexMaterial);
53
- this.input2 = stream.readType(R8G8B8A8_UNORM);
54
- this.input3 = stream.readType(R8G8B8A8_UNORM);
55
- this.input4 = stream.readType(R8G8B8A8_UNORM);
56
- }
57
-
58
- toStream(stream) {
59
- stream.writeType(this.pos);
60
- stream.writeType(this.normal);
61
- stream.writeType(this.material);
62
- stream.writeType(this.input2);
63
- stream.writeType(this.input3);
64
- stream.writeType(this.input4);
65
- }
66
- }
67
-
68
- // An subchunk represents a vertex range where all vertices share a certain material.
69
- // The same vertex can appear in different subchunks if it has the material specified
70
- // by that subchunk.
71
- class LevelGeoSubchunk extends IBinarying {
72
- constructor() {
73
- super();
74
-
75
- // The material id of the subchunk.
76
- this.materialId = 0;
77
-
78
- // Avaliable face count.
79
- this.triangleCount = 0;
80
- // Avaliable vertex count.
81
- this.vtxCount = 0;
82
-
83
- // 3 indices per triangle. The triangle range [triangleStart, triangleEnd],
84
- // i.e. index range [triangleStart * 3, triangleEnd * 3] will be processed
85
- // by the game, and extract `triangleCount` avaliable faces has the material
86
- // specified by `materialId`.
87
- this.triangleStart = 0;
88
- this.triangleEnd = 0;
89
-
90
- // Like the triangle range modifier, the vertex range [vtxStart, vtxEnd]
91
- // will be processed and extract `vtxCount` vertices at most.
92
- this.vtxStart = 0;
93
- this.vtxEnd = 0;
94
- }
95
-
96
- fromStream(stream) {
97
- this.materialId = stream.readUint8();
98
-
99
- this.triangleCount = stream.readUint8();
100
- this.vtxCount = stream.readUint8();
101
-
102
- this.triangleStart = stream.readUint8();
103
- this.triangleEnd = stream.readUint8();
104
-
105
- this.vtxStart = stream.readUint8();
106
- this.vtxEnd = stream.readUint8();
107
-
108
- stream.readUint8();
109
- }
110
-
111
- toStream(stream) {
112
- stream.writeUint8(this.materialId);
113
-
114
- stream.writeUint8(this.triangleCount);
115
- stream.writeUint8(this.vtxCount);
116
-
117
- stream.writeUint8(this.triangleStart);
118
- stream.writeUint8(this.triangleEnd);
119
-
120
- stream.writeUint8(this.vtxStart);
121
- stream.writeUint8(this.vtxEnd);
122
-
123
- stream.writeUint8(0);
124
- }
125
- }
126
-
127
- // A chunk holds a series of triangle faces, representing a terrain chunk. Chunks
128
- // contain AABB bounding boxes and chunks are the smallest unit for computing
129
- // CollisionGeo.
130
- class LevelGeoChunk extends IBinarying {
131
- constructor() {
132
- super();
133
-
134
- // These three pairs of values specify the subarray ranges that the chunk
135
- // decompresses from the global sub-chunk, vertex, and index arrays, i.e.
136
- // the resource range used by this chunk.
137
- //
138
- // All sub-chunks of a chunk use indices within the chunk's subarray, not
139
- // global array indices.
140
- this.vtxStart = 0;
141
- this.idxStart = 0;
142
- this.subchunkStart = 0;
143
-
144
- this.idxCount = 0;
145
- this.vtxCount = 0;
146
- this.subchunkCount = 0;
147
-
148
- // The AABB bounding box of the chunk, used for collision calculation. All
149
- // faces outside this bounding box have no collision volume.
150
- this.min = new Vec3();
151
- this.max = new Vec3();
152
- }
153
-
154
- fromStream(stream) {
155
- this.idxStart = stream.readUint32();
156
- this.vtxStart = stream.readUint32();
157
- this.subchunkStart = stream.readUint32();
158
-
159
- this.idxCount = stream.readUint16();
160
- this.vtxCount = stream.readUint8();
161
- this.subchunkCount = stream.readUint8();
162
-
163
- this.min = stream.readType(Vec3);
164
- this.max = stream.readType(Vec3);
165
-
166
- stream.readUint32();
167
- stream.readUint32();
168
- stream.readUint32();
169
- stream.readUint32();
170
- }
171
-
172
- toStream(stream) {
173
- stream.writeUint32(this.idxStart);
174
- stream.writeUint32(this.vtxStart);
175
- stream.writeUint32(this.subchunkStart);
176
-
177
- stream.writeUint16(this.idxCount);
178
- stream.writeUint8(this.vtxCount);
179
- stream.writeUint8(this.subchunkCount);
180
-
181
- stream.writeType(this.min);
182
- stream.writeType(this.max);
183
-
184
- stream.writeUint32(0);
185
- stream.writeUint32(0);
186
- stream.writeUint32(0);
187
- stream.writeUint32(0);
188
- }
189
- }
190
-
191
- class LevelGeo extends IBinarying {
192
- constructor() {
193
- super();
194
-
195
- // Counts.
196
- this.indexCount = 0;
197
- this.vertexCount = 0;
198
- this.chunkCount = 0;
199
- this.cloudChunkCount = 0;
200
- this.subchunkCount = 0;
201
-
202
- this.localIndices = [];
203
- this.vertices = [];
204
- this.chunks = [];
205
- this.subchunks = [];
206
- }
207
-
208
- fromStream(stream) {
209
- this.indexCount = stream.readUint32()
210
- this.vertexCount = stream.readUint32()
211
- this.chunkCount = stream.readUint32()
212
- this.cloudChunkCount = stream.readUint32()
213
- this.subchunkCount = stream.readUint32();
214
-
215
- // Read vertices.
216
- this.vertices = [];
217
- if (this.vertexCount) {
218
- var compressedSize = stream.readUint32()
219
- , data = stream.readBytes(compressedSize);
220
-
221
- var t = Buffer.alloc(this.vertexCount * 36);
222
- MeshoptDecoder.decodeVertexBuffer(t, this.vertexCount, 36, data);
223
-
224
- var s = new ReadOnlyBinaryStream(t);
225
- for (var i = 0; i < this.vertexCount; i++)
226
- this.vertices.push(s.readType(LevelGeoMeshVertex));
227
- }
228
-
229
- // Read indices.
230
- this.localIndices = [];
231
- for (var i = 0; i < this.indexCount; i++)
232
- this.localIndices.push(stream.readUint8());
233
-
234
- // Read groups.
235
- this.chunks = [];
236
- for (var i = 0; i < this.chunkCount + this.cloudChunkCount; i++)
237
- this.chunks.push(stream.readType(LevelGeoChunk));
238
-
239
- // Read areas.
240
- this.subchunks = [];
241
- for (var i = 0; i < this.subchunkCount; i++)
242
- this.subchunks.push(stream.readType(LevelGeoSubchunk));
243
- }
244
-
245
- toStream(stream) {
246
- stream.writeUint32(this.indexCount);
247
- stream.writeUint32(this.vertexCount);
248
- stream.writeUint32(this.chunkCount);
249
- stream.writeUint32(this.cloudChunkCount);
250
- stream.writeUint32(this.subchunkCount);
251
-
252
- // Write vertices.
253
- if (this.vertices.length) {
254
- var t = new WritableBinaryStream();
255
- for (var v of this.vertices)
256
- t.writeType(v);
257
-
258
- var data = MeshoptEncoder.encodeVertexBuffer(t.data(), this.vertices.length, 36);
259
- stream.writeUint32(data.byteLength);
260
- stream.writeBytes(data);
261
- }
262
-
263
- // Write indices.
264
- for (var idx of this.localIndices)
265
- stream.writeUint8(idx);
266
-
267
- // Write groups.
268
- for (var group of this.chunks)
269
- stream.writeType(group);
270
-
271
- // Write areas.
272
- for (var area of this.subchunks)
273
- stream.writeType(area);
274
- }
275
- }
276
-
277
- module.exports = {
278
- LevelGeoMeshVertexMaterial,
279
- LevelGeoMeshVertex,
280
- LevelGeoSubchunk,
281
- LevelGeoChunk,
282
- LevelGeo
283
- };
@@ -1,15 +0,0 @@
1
- const { IBinarying } = require("../../utils/helperClasses.js");
2
-
3
- class LevelLod extends IBinarying {
4
- constructor() {
5
- super();
6
- }
7
-
8
- toStream(stream) {
9
- stream.writeBytes(Buffer.from("1B000100C0010000000000000000000000", "hex"));
10
- }
11
- }
12
-
13
- module.exports = {
14
- LevelLod
15
- };
@@ -1,141 +0,0 @@
1
- const NBT = require("parsenbt-js");
2
- const { ReadOnlyBinaryStream, WritableBinaryStream } = require("../../utils/binaryStream.js");
3
- const { IBinarying } = require("../../utils/helperClasses.js");
4
- const { LevelGeo } = require("./levelGeo.js");
5
- const { LevelLod } = require("./levelLod.js");
6
- const { LevelToc, LevelTocSegment } = require("./levelToc.js");
7
- const { Vec3 } = require("../../utils/vector.js");
8
-
9
- function toArrayBuffer(buf) {
10
- var ab = new ArrayBuffer(buf.length);
11
- (new Uint8Array(ab)).set(buf);
12
- return ab;
13
- }
14
-
15
- class LevelDesc extends IBinarying {
16
- constructor() {
17
- super();
18
-
19
- this.timeStamp = 0;
20
- this.fileName = "";
21
- this.editor = "that-sky-level";
22
- this.editorVersion = [1, 0, 0];
23
- this.engineVersion = [0, 32, 2];
24
- }
25
-
26
- fromStream(stream) {
27
- var buffer = stream.readBytes(stream.getRemain())
28
- , nbt = NBT.Reader(toArrayBuffer(buffer), { littleEndian: true });
29
-
30
- this.timeStamp = nbt["comp>"]?.["u32>timeStamp"] || 0;
31
- this.fileName = nbt["comp>"]?.["str>fileName"] || "";
32
- this.editor = nbt["comp>"]?.["str>editor"] || "";
33
- this.editorVersion = nbt["comp>"]["list>editorVersion"]?.slice(1, 4) || [0, 0, 0];
34
- this.engineVersion = nbt["comp>"]["list>engineVersion"]?.slice(1, 4) || [0, 0, 0];
35
- }
36
-
37
- toStream(stream) {
38
- var nbt = NBT.create(false);
39
-
40
- nbt["i32>timeStamp"] = this.timeStamp;
41
- nbt["str>fileName"] = this.fileName;
42
- nbt["str>editor"] = this.editor;
43
- nbt["list>editorVersion"] = ["i32"].concat(this.editorVersion);
44
- nbt["list>engineVersion"] = ["i32"].concat(this.engineVersion);
45
-
46
- stream.writeBytes(Buffer.from(NBT.Writer(nbt, { littleEndian: true })));
47
- }
48
- }
49
-
50
- class LevelMeshes {
51
- // magicNum, fileVersion, toc, padding, maxPos, minPos
52
- static kHeaderLength = 4 + 4 + 100 + 4 + 12 + 12;
53
-
54
- constructor() {
55
- this.fileVersion = 0x3C;
56
- this.desc = new LevelDesc();
57
- this.lod = new LevelLod();
58
- this.geo = new LevelGeo();
59
- }
60
-
61
- fromFileBuffer(buffer) {
62
- var stream = new ReadOnlyBinaryStream(buffer);
63
-
64
- var magicNum = stream.readUint32();
65
- if (magicNum != 0x304C564C)
66
- throw new Error("magic number mismatch");
67
-
68
- this.fileVersion = stream.readUint32();
69
- // Accept 0x3C or 0x3D.
70
- if (this.fileVersion < 0x3C)
71
- throw new Error("file version mismatch");
72
-
73
- var toc = stream.readType(LevelToc);
74
-
75
- if (toc.LOD0)
76
- this.lod = toc.LOD0.fromFileBuffer(buffer).readType(LevelLod);
77
- else
78
- throw new Error("level did not baked lod.");
79
-
80
- if (toc.GEO0)
81
- this.geo = toc.GEO0.fromFileBuffer(buffer).readType(LevelGeo);
82
- else
83
- this.geo = void 0;
84
-
85
- if (toc.DESC)
86
- this.desc = toc.DESC.fromFileBuffer(buffer).readType(LevelDesc);
87
- else
88
- this.desc = void 0;
89
- }
90
-
91
- toFileBuffer() {
92
- var levelStream = new WritableBinaryStream();
93
- levelStream.writeUint32(0x304C564C);
94
- levelStream.writeUint32(this.fileVersion);
95
-
96
- var toc = new LevelToc()
97
- , contentStream = new WritableBinaryStream()
98
- , contentCursor = contentStream.getLength();
99
-
100
- // Write DESC segment.
101
- if (this.desc) {
102
- contentStream.writeType(this.desc);
103
- toc.segments.set("DESC", new LevelTocSegment(
104
- contentCursor + LevelMeshes.kHeaderLength,
105
- contentStream.getLength() - contentCursor
106
- ));
107
- contentCursor = contentStream.getLength();
108
- }
109
-
110
- // Write LOD0 segment.
111
- contentStream.writeType(this.lod);
112
- toc.segments.set("LOD0", new LevelTocSegment(
113
- contentCursor + LevelMeshes.kHeaderLength,
114
- contentStream.getLength() - contentCursor
115
- ));
116
- contentCursor = contentStream.getLength();
117
-
118
- // Write GEO0 segment.
119
- if (this.geo) {
120
- contentStream.writeType(this.geo);
121
- toc.segments.set("GEO0", new LevelTocSegment(
122
- contentCursor + LevelMeshes.kHeaderLength,
123
- contentStream.getLength() - contentCursor
124
- ));
125
- contentCursor = contentStream.getLength();
126
- }
127
-
128
- // Complete file header.
129
- levelStream.writeType(toc);
130
- levelStream.writeUint32(0);
131
- levelStream.writeType(new Vec3(3.402823466e+38, 3.402823466e+38, 3.402823466e+38));
132
- levelStream.writeType(new Vec3(-3.402823466e+38, -3.402823466e+38, -3.402823466e+38));
133
- levelStream.writeBytes(contentStream.data());
134
-
135
- return levelStream.data();
136
- }
137
- }
138
-
139
- module.exports = {
140
- LevelMeshes
141
- };
@@ -1,69 +0,0 @@
1
- const { ReadOnlyBinaryStream } = require("../../utils/binaryStream.js");
2
- const { IBinarying } = require("../../utils/helperClasses.js");
3
-
4
- class LevelTocSegment {
5
- constructor(offset, byteLength) {
6
- this.offset = offset || 0;
7
- this.byteLength = byteLength || 0;
8
- }
9
-
10
- fromFileBuffer(buffer) {
11
- return new ReadOnlyBinaryStream(
12
- buffer.subarray(this.offset, this.offset + this.byteLength)
13
- );
14
- }
15
- }
16
-
17
- class LevelToc extends IBinarying {
18
- constructor() {
19
- super();
20
-
21
- this.segments = new Map();
22
- }
23
-
24
- clear() {
25
- this.segments.clear();
26
- }
27
-
28
- get LOD0() { return this.segments.get("LOD0"); }
29
- get GEO0() { return this.segments.get("GEO0"); }
30
- get METR() { return this.segments.get("METR"); }
31
- get DESC() { return this.segments.get("DESC"); }
32
-
33
- fromStream(stream) {
34
- var buffer = stream.readBytes(0x64)
35
- , tocStream = new ReadOnlyBinaryStream(buffer);
36
- this.clear();
37
-
38
- var count = tocStream.readUint32();
39
- for (var i = 0; i < count; i++) {
40
- var type = tocStream.readBytes(4).toString("ascii")
41
- , offset = tocStream.readUint32()
42
- , byteLength = tocStream.readUint32();
43
-
44
- this.segments.set(type, new LevelTocSegment(offset, byteLength));
45
- }
46
- }
47
-
48
- toStream(stream) {
49
- if (this.segments.size > 8)
50
- throw new Error("too many segments");
51
-
52
- var buffer = Buffer.alloc(0x60)
53
- , offset = 0;
54
- for (var kv of this.segments) {
55
- buffer.write(kv[0], offset, 4, "ascii");
56
- buffer.writeUint32LE(kv[1].offset, offset + 4);
57
- buffer.writeUint32LE(kv[1].byteLength, offset + 8);
58
- offset += 12;
59
- }
60
-
61
- stream.writeUint32(this.segments.size);
62
- stream.writeBytes(buffer);
63
- }
64
- }
65
-
66
- module.exports = {
67
- LevelTocSegment,
68
- LevelToc
69
- };