universal-game-modder 0.1.4

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 (92) hide show
  1. package/ACCEPTABLE_USE.md +49 -0
  2. package/CHANGELOG.md +119 -0
  3. package/LICENSE +21 -0
  4. package/LICENSE-EULA.md +62 -0
  5. package/README.md +162 -0
  6. package/VERIFICATION.md +132 -0
  7. package/dist/backends/child-pool.js +91 -0
  8. package/dist/backends/mcp-child.js +102 -0
  9. package/dist/backends/mcp-child.js.map +1 -0
  10. package/dist/core/config.d.ts +10 -0
  11. package/dist/core/config.js +48 -0
  12. package/dist/core/config.js.map +1 -0
  13. package/dist/core/engine-detector.d.ts +13 -0
  14. package/dist/core/engine-detector.js +247 -0
  15. package/dist/core/engine-detector.js.map +1 -0
  16. package/dist/core/event-bus.js +18 -0
  17. package/dist/core/file-classifier.js +394 -0
  18. package/dist/core/model-db.js +517 -0
  19. package/dist/core/model-db.js.map +1 -0
  20. package/dist/core/router.d.ts +6 -0
  21. package/dist/core/router.js +143 -0
  22. package/dist/core/router.js.map +1 -0
  23. package/dist/core/session.js +114 -0
  24. package/dist/decoders/audio-export.js +57 -0
  25. package/dist/decoders/mesh-export.d.ts +20 -0
  26. package/dist/decoders/mesh-export.js +174 -0
  27. package/dist/decoders/mesh-export.js.map +1 -0
  28. package/dist/decoders/native/disassembler.js +85 -0
  29. package/dist/decoders/native/disassembler.js.map +1 -0
  30. package/dist/decoders/png-encode.d.ts +17 -0
  31. package/dist/decoders/png-encode.js +33 -0
  32. package/dist/decoders/texture-decode.js +278 -0
  33. package/dist/decoders/texture-decode.js.map +1 -0
  34. package/dist/decoders/unity/audioclip.d.ts +55 -0
  35. package/dist/decoders/unity/audioclip.js +87 -0
  36. package/dist/decoders/unity/audioclip.js.map +1 -0
  37. package/dist/decoders/unity/binary-reader.d.ts +45 -0
  38. package/dist/decoders/unity/binary-reader.js +141 -0
  39. package/dist/decoders/unity/binary-reader.js.map +1 -0
  40. package/dist/decoders/unity/mesh.js +198 -0
  41. package/dist/decoders/unity/mesh.js.map +1 -0
  42. package/dist/decoders/unity/ress-reader.d.ts +33 -0
  43. package/dist/decoders/unity/ress-reader.js +82 -0
  44. package/dist/decoders/unity/ress-reader.js.map +1 -0
  45. package/dist/decoders/unity/serialized-file.d.ts +65 -0
  46. package/dist/decoders/unity/serialized-file.js +144 -0
  47. package/dist/decoders/unity/texture2d.js +185 -0
  48. package/dist/decoders/unity/vertex-data.d.ts +54 -0
  49. package/dist/decoders/unity/vertex-data.js +174 -0
  50. package/dist/decoders/unity/vertex-data.js.map +1 -0
  51. package/dist/index.d.ts +1 -0
  52. package/dist/index.js +23 -0
  53. package/dist/server.d.ts +1 -0
  54. package/dist/server.js +66 -0
  55. package/dist/tools/decode-tools.d.ts +29 -0
  56. package/dist/tools/decode-tools.js +441 -0
  57. package/dist/tools/delegates/jar-editor.d.ts +2 -0
  58. package/dist/tools/delegates/jar-editor.js +276 -0
  59. package/dist/tools/delegates/unity-decompiler.d.ts +2 -0
  60. package/dist/tools/delegates/unity-decompiler.js +291 -0
  61. package/dist/tools/delegates/unreal-assets.d.ts +2 -0
  62. package/dist/tools/delegates/unreal-assets.js +122 -0
  63. package/dist/tools/detection-tools.d.ts +2 -0
  64. package/dist/tools/detection-tools.js +164 -0
  65. package/dist/tools/detection-tools.js.map +1 -0
  66. package/dist/tools/index.d.ts +8 -0
  67. package/dist/tools/index.js +30 -0
  68. package/dist/tools/index.js.map +1 -0
  69. package/dist/tools/native/index.d.ts +2 -0
  70. package/dist/tools/native/index.js +1201 -0
  71. package/dist/tools/native-comprehension-tools.js +298 -0
  72. package/dist/tools/native-comprehension-tools.js.map +1 -0
  73. package/dist/tools/unpack-tools.d.ts +2 -0
  74. package/dist/tools/unpack-tools.js +382 -0
  75. package/dist/tools/workflow-tools.d.ts +2 -0
  76. package/dist/tools/workflow-tools.js +434 -0
  77. package/dist/utils/logger.d.ts +11 -0
  78. package/dist/utils/logger.js +49 -0
  79. package/dist/utils/logger.js.map +1 -0
  80. package/dist/utils/path-utils.d.ts +15 -0
  81. package/dist/utils/path-utils.js +24 -0
  82. package/dist/utils/path-utils.js.map +1 -0
  83. package/dist/utils/steam-finder.d.ts +8 -0
  84. package/dist/utils/steam-finder.js +32 -0
  85. package/dist/web/web-server.d.ts +1 -0
  86. package/dist/web/web-server.js +369 -0
  87. package/licenses/THIRD-PARTY-NOTICES.md +35 -0
  88. package/llms-install.md +34 -0
  89. package/package.json +69 -0
  90. package/server.json +20 -0
  91. package/setup.ps1 +34 -0
  92. package/ugm.config.json +9 -0
@@ -0,0 +1,198 @@
1
+ /**
2
+ * mesh.ts — parse a Unity Mesh object payload (Unity 2020.3 / format v22, typeTree DISABLED)
3
+ * into vertex positions/normals/uvs + triangle indices, for the PLAIN (uncompressed) case.
4
+ *
5
+ * SCOPE (first slice, deliberately bounded):
6
+ * - Plain meshes only: m_MeshCompression == 0. A compressed mesh (PackedBitVector) is
7
+ * detected and reported as unsupported (the caller writes a noted decoded=0 row) — NOT
8
+ * mis-parsed. Skinned/blend-shape extras are skipped (we read past them), but positions,
9
+ * normals, uvs, and the index buffer are extracted.
10
+ *
11
+ * Reference field order: Unity 2020.3 Mesh (AssetStudio Mesh.cs), little-endian, no type tree.
12
+ * The layout below is the 2020.3-era order. Because there is NO type tree to self-describe the
13
+ * fields, this is positional — every array is length-prefixed (Int32) and we read or skip each
14
+ * in order. A field-order miss is caught by sanity bounds (implausible counts throw) rather than
15
+ * silently producing garbage geometry.
16
+ *
17
+ * Field order (2020.3, condensed — arrays are Int32-count-prefixed unless noted):
18
+ * m_Name : AlignedString
19
+ * m_SubMeshes : count * SubMesh{ firstByte:u32, indexCount:u32, topology:i32, baseVertex:u32,
20
+ * firstVertex:u32, vertexCount:u32, localAABB:{center:3f, extent:3f} }
21
+ * m_Shapes (BlendShapeData) : vertices[] + shapes[] + channels[] + fullWeights[] (skipped)
22
+ * m_BindPose : count * 16 floats (Matrix4x4) (skipped)
23
+ * m_BoneNameHashes : count * u32 (skipped)
24
+ * m_RootBoneNameHash : u32
25
+ * m_BonesAABB : count * (6 floats) (2019+) (skipped)
26
+ * m_VariableBoneCountWeights : count * u32 (2019+) (skipped)
27
+ * m_MeshCompression : u8
28
+ * m_IsReadable : u8 ; m_KeepVertices : u8 ; m_KeepIndices : u8 ; align(4)
29
+ * m_IndexFormat : i32 (0 = UInt16, 1 = UInt32) (2017.4+)
30
+ * m_IndexBuffer : count(u32) * byte ; align(4)
31
+ * m_VertexData : { m_CurrentChannels?(pre-2018) , m_VertexCount:u32, m_Channels[]:ChannelInfo,
32
+ * m_DataSize: count*byte ; align(4) }
33
+ * ... (compression-related PackedBitVectors, m_StreamData at the end)
34
+ * m_StreamData : { offset:u32(or u64 late), size:u32, path:AlignedString } (NOT consumed in this slice)
35
+ */
36
+ import { BinaryReader } from './binary-reader.js';
37
+ import { extractAttribute } from './vertex-data.js';
38
+ const MAX_COUNT = 50_000_000; // sanity bound for any length-prefixed array
39
+ function readCount(r, what) {
40
+ const n = r.readInt32();
41
+ if (n < 0 || n > MAX_COUNT) {
42
+ throw new RangeError(`mesh: implausible ${what} count ${n} at offset ${r.pos} — field-order mismatch`);
43
+ }
44
+ return n;
45
+ }
46
+ export function parseMesh(buf, header, obj) {
47
+ const little = header.endianess === 0;
48
+ const start = Number(header.dataOffset + obj.byteStart);
49
+ const end = start + obj.byteSize;
50
+ if (start < 0 || end > buf.length) {
51
+ throw new RangeError(`parseMesh: object range [${start}, ${end}] outside buffer ${buf.length}`);
52
+ }
53
+ const r = new BinaryReader(buf.subarray(start, end), !little, 0);
54
+ const name = r.readAlignedString();
55
+ // --- m_SubMeshes ---
56
+ const subMeshCount = readCount(r, 'subMesh');
57
+ const subMeshes = [];
58
+ for (let i = 0; i < subMeshCount; i++) {
59
+ const firstByte = r.readUInt32();
60
+ const indexCount = r.readUInt32();
61
+ const topology = r.readInt32();
62
+ /* baseVertex */ r.readUInt32();
63
+ const firstVertex = r.readUInt32();
64
+ const vertexCount = r.readUInt32();
65
+ // localAABB: Vector3 center + Vector3 extent (6 floats)
66
+ r.skip(6 * 4);
67
+ subMeshes.push({ firstByte, indexCount, topology, firstVertex, vertexCount });
68
+ }
69
+ // --- m_Shapes (BlendShapeData) : skip the four arrays ---
70
+ skipBlendShapeData(r);
71
+ // --- m_BindPose : count * Matrix4x4 (16 floats) ---
72
+ const bindPoseCount = readCount(r, 'bindPose');
73
+ r.skip(bindPoseCount * 16 * 4);
74
+ // --- m_BoneNameHashes : count * u32 ---
75
+ const boneNameCount = readCount(r, 'boneNameHash');
76
+ r.skip(boneNameCount * 4);
77
+ // --- m_RootBoneNameHash : u32 ---
78
+ r.readUInt32();
79
+ // --- m_BonesAABB : count * (Vector3 min + Vector3 max = 6 floats) (2019+) ---
80
+ const bonesAABBCount = readCount(r, 'bonesAABB');
81
+ r.skip(bonesAABBCount * 6 * 4);
82
+ // --- m_VariableBoneCountWeights : count * u32 (2019+) ---
83
+ const vbcwCount = readCount(r, 'variableBoneCountWeights');
84
+ r.skip(vbcwCount * 4);
85
+ // --- compression + flags ---
86
+ const meshCompression = r.readUInt8();
87
+ /* m_IsReadable */ r.readUInt8();
88
+ /* m_KeepVertices */ r.readUInt8();
89
+ /* m_KeepIndices */ r.readUInt8();
90
+ r.align(4);
91
+ const compressed = meshCompression !== 0;
92
+ // --- m_IndexFormat (2017.4+): 0 = UInt16, 1 = UInt32 ---
93
+ const indexFormat = r.readInt32();
94
+ // --- m_IndexBuffer ---
95
+ const indexBufLen = readCount(r, 'indexBuffer');
96
+ const indexBytes = Buffer.from(r.readBytes(indexBufLen));
97
+ r.align(4);
98
+ // If compressed, the vertex data lives in PackedBitVectors we don't unpack in this slice.
99
+ // Bail early with the metadata we have; the caller records a noted decoded=0 row.
100
+ if (compressed) {
101
+ return {
102
+ name,
103
+ compressed: true,
104
+ vertexCount: 0,
105
+ positions: null,
106
+ normals: null,
107
+ uvs: null,
108
+ indices: new Uint32Array(0),
109
+ subMeshCount,
110
+ attributesExported: [],
111
+ };
112
+ }
113
+ // --- m_VertexData ---
114
+ const vertexCount = r.readUInt32();
115
+ const channelCount = readCount(r, 'vertexChannel');
116
+ const channels = [];
117
+ for (let i = 0; i < channelCount; i++) {
118
+ const stream = r.readUInt8();
119
+ const offset = r.readUInt8();
120
+ const format = r.readUInt8();
121
+ const dimension = r.readUInt8();
122
+ channels.push({ stream, offset, format, dimension });
123
+ }
124
+ const dataSize = readCount(r, 'vertexDataSize');
125
+ let vertexBlob = Buffer.from(r.readBytes(dataSize));
126
+ r.align(4);
127
+ // Vertex data: for Baldi (verified) the vertex blob is INLINE, so it is populated above and
128
+ // attributes extract directly. STREAMED vertex data (when m_DataSize is empty and the bytes
129
+ // live in a sibling .resS via m_StreamData) is NOT implemented in this slice: we do not read
130
+ // m_StreamData here, the blob stays empty, positions come back null, and decode_assets writes
131
+ // a noted decoded=0 row ("streamed vertex data not yet supported"). A future slice will add
132
+ // the .resS resolution for meshes (textures already do this via ResSReader).
133
+ const vd = { vertexCount, channels, data: vertexBlob };
134
+ // Unity channel index convention: 0=Position, 1=Normal, 2=Tangent, 3=Color, 4=UV0, 5=UV1...
135
+ const positions = extractAttribute(vd, 0, 3);
136
+ const normals = extractAttribute(vd, 1, 3);
137
+ const uvs = extractAttribute(vd, 4, 2);
138
+ const attributesExported = [];
139
+ if (positions)
140
+ attributesExported.push('POSITION');
141
+ if (normals)
142
+ attributesExported.push('NORMAL');
143
+ if (uvs)
144
+ attributesExported.push('TEXCOORD_0');
145
+ // --- indices: decode per m_IndexFormat ---
146
+ const indices = decodeIndices(indexBytes, indexFormat);
147
+ return {
148
+ name,
149
+ compressed: false,
150
+ vertexCount,
151
+ positions,
152
+ normals,
153
+ uvs,
154
+ indices,
155
+ subMeshCount,
156
+ attributesExported,
157
+ };
158
+ }
159
+ /** Skip Unity's BlendShapeData block (4 length-prefixed arrays). */
160
+ function skipBlendShapeData(r) {
161
+ // m_Vertices : count * BlendShapeVertex (Vector3 vertex + Vector3 normal + Vector3 tangent + u32 index = 10*4)
162
+ const vCount = readCount(r, 'blendVertices');
163
+ r.skip(vCount * (9 * 4 + 4));
164
+ // m_Shapes : count * MeshBlendShape (firstVertex:u32, vertexCount:u32, hasNormals:bool, hasTangents:bool, align)
165
+ const sCount = readCount(r, 'blendShapes');
166
+ for (let i = 0; i < sCount; i++) {
167
+ r.skip(4 + 4); // firstVertex + vertexCount
168
+ r.readUInt8(); // hasNormals
169
+ r.readUInt8(); // hasTangents
170
+ r.align(4);
171
+ }
172
+ // m_Channels : count * MeshBlendShapeChannel (name:AlignedString, nameHash:u32, frameIndex:i32, frameCount:i32)
173
+ const cCount = readCount(r, 'blendChannels');
174
+ for (let i = 0; i < cCount; i++) {
175
+ r.readAlignedString();
176
+ r.skip(4 + 4 + 4);
177
+ }
178
+ // m_FullWeights : count * float
179
+ const wCount = readCount(r, 'blendWeights');
180
+ r.skip(wCount * 4);
181
+ }
182
+ /** Decode the index buffer into a flat Uint32Array per m_IndexFormat (0=u16, 1=u32). */
183
+ function decodeIndices(indexBytes, indexFormat) {
184
+ if (indexFormat === 1) {
185
+ const n = Math.floor(indexBytes.length / 4);
186
+ const out = new Uint32Array(n);
187
+ for (let i = 0; i < n; i++)
188
+ out[i] = indexBytes.readUInt32LE(i * 4);
189
+ return out;
190
+ }
191
+ // default UInt16
192
+ const n = Math.floor(indexBytes.length / 2);
193
+ const out = new Uint32Array(n);
194
+ for (let i = 0; i < n; i++)
195
+ out[i] = indexBytes.readUInt16LE(i * 2);
196
+ return out;
197
+ }
198
+ //# sourceMappingURL=mesh.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mesh.js","sourceRoot":"","sources":["../../../src/decoders/unity/mesh.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,33 @@
1
+ /**
2
+ * ress-reader.ts — resolve a Texture2D's StreamingInfo to its raw bytes.
3
+ *
4
+ * Unity stores most texture pixels in a sibling stream file (.resS / .resource) and
5
+ * references them from the .assets object via m_StreamData { offset, size, path }.
6
+ * The `path` takes one of two shapes:
7
+ * - "archive:/<something>/<file>.resS" (bundle-style virtual path; we use the basename)
8
+ * - "<file>.resS" (plain sibling filename)
9
+ * Either way the real bytes live in a file next to the .assets in the same directory.
10
+ *
11
+ * This reader opens the stream file and slices [offset, offset+size). It caches open
12
+ * file handles per stream file so decoding hundreds of textures from one .resS doesn't
13
+ * re-open it hundreds of times. Read-only: it never writes.
14
+ */
15
+ import type { StreamingInfo } from './texture2d.js';
16
+ export declare class ResSReader {
17
+ /** directory containing the .assets file (where sibling .resS/.resource live). */
18
+ private readonly dir;
19
+ private readonly handles;
20
+ private readonly sizes;
21
+ constructor(assetsFilePath: string);
22
+ /** Map a StreamData.path to an on-disk file path next to the .assets. */
23
+ private resolvePath;
24
+ private handleFor;
25
+ /**
26
+ * Read the bytes a StreamingInfo points at. Returns null (with no throw) when the
27
+ * stream file is missing or the range is out of bounds — the caller records a noted
28
+ * decoded=0 row rather than aborting the run.
29
+ */
30
+ read(stream: StreamingInfo): Buffer | null;
31
+ /** Close all cached handles. Call once when decoding for an .assets is done. */
32
+ close(): void;
33
+ }
@@ -0,0 +1,82 @@
1
+ /**
2
+ * ress-reader.ts — resolve a Texture2D's StreamingInfo to its raw bytes.
3
+ *
4
+ * Unity stores most texture pixels in a sibling stream file (.resS / .resource) and
5
+ * references them from the .assets object via m_StreamData { offset, size, path }.
6
+ * The `path` takes one of two shapes:
7
+ * - "archive:/<something>/<file>.resS" (bundle-style virtual path; we use the basename)
8
+ * - "<file>.resS" (plain sibling filename)
9
+ * Either way the real bytes live in a file next to the .assets in the same directory.
10
+ *
11
+ * This reader opens the stream file and slices [offset, offset+size). It caches open
12
+ * file handles per stream file so decoding hundreds of textures from one .resS doesn't
13
+ * re-open it hundreds of times. Read-only: it never writes.
14
+ */
15
+ import { openSync, readSync, closeSync, existsSync, statSync } from 'fs';
16
+ import { basename, dirname, join } from 'path';
17
+ export class ResSReader {
18
+ /** directory containing the .assets file (where sibling .resS/.resource live). */
19
+ dir;
20
+ handles = new Map();
21
+ sizes = new Map();
22
+ constructor(assetsFilePath) {
23
+ this.dir = dirname(assetsFilePath);
24
+ }
25
+ /** Map a StreamData.path to an on-disk file path next to the .assets. */
26
+ resolvePath(streamPath) {
27
+ // Normalize separators, take the basename (handles "archive:/.../file.resS").
28
+ const norm = streamPath.replace(/\\/g, '/');
29
+ const name = basename(norm);
30
+ return join(this.dir, name);
31
+ }
32
+ handleFor(filePath) {
33
+ const cached = this.handles.get(filePath);
34
+ if (cached !== undefined)
35
+ return cached;
36
+ if (!existsSync(filePath)) {
37
+ this.handles.set(filePath, -1);
38
+ return null;
39
+ }
40
+ const fd = openSync(filePath, 'r');
41
+ this.handles.set(filePath, fd);
42
+ this.sizes.set(filePath, statSync(filePath).size);
43
+ return fd;
44
+ }
45
+ /**
46
+ * Read the bytes a StreamingInfo points at. Returns null (with no throw) when the
47
+ * stream file is missing or the range is out of bounds — the caller records a noted
48
+ * decoded=0 row rather than aborting the run.
49
+ */
50
+ read(stream) {
51
+ const filePath = this.resolvePath(stream.path);
52
+ const fd = this.handleFor(filePath);
53
+ if (fd === null || fd < 0)
54
+ return null;
55
+ const fileSize = this.sizes.get(filePath) ?? 0;
56
+ const offset = Number(stream.offset);
57
+ const size = stream.size;
58
+ if (offset < 0 || size <= 0 || offset + size > fileSize)
59
+ return null;
60
+ const buf = Buffer.allocUnsafe(size);
61
+ const got = readSync(fd, buf, 0, size, offset);
62
+ if (got !== size)
63
+ return null;
64
+ return buf;
65
+ }
66
+ /** Close all cached handles. Call once when decoding for an .assets is done. */
67
+ close() {
68
+ for (const fd of this.handles.values()) {
69
+ if (fd >= 0) {
70
+ try {
71
+ closeSync(fd);
72
+ }
73
+ catch {
74
+ /* best effort */
75
+ }
76
+ }
77
+ }
78
+ this.handles.clear();
79
+ this.sizes.clear();
80
+ }
81
+ }
82
+ //# sourceMappingURL=ress-reader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ress-reader.js","sourceRoot":"","sources":["../../../src/decoders/unity/ress-reader.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,65 @@
1
+ /**
2
+ * serialized-file.ts — a bounded parser for Unity serialized files (.assets), format v22.
3
+ *
4
+ * SCOPE (deliberately narrow, per PR-2): parse the file-level structures needed to
5
+ * locate objects by class — header, type tree table (we only need the per-type classID),
6
+ * and the object table (path id, byte start/size, type index). We do NOT parse the full
7
+ * recursive type tree into typed fields; object payloads are parsed by class-specific
8
+ * readers (see texture2d.ts) using the byte ranges this module yields.
9
+ *
10
+ * Format reference: UnityFS SerializedFile, version 22 (LargeFilesSupport), as shipped by
11
+ * Unity 2020.3.x desktop players. Verified against Baldi's Basics Plus (2020.3.49f1):
12
+ * - header is BIG-endian; metadata endianness is declared by header.m_Endianess.
13
+ * - v>=22 uses a 64-bit metadata/file-size/data-offset layout with a relocated header.
14
+ *
15
+ * Anti-silent-corruption: every read goes through BinaryReader's bounds checks. A parse
16
+ * that runs off the rails throws with the exact offset, never returns plausible garbage.
17
+ */
18
+ /** Header of a serialized file (the v22 large-files layout). */
19
+ export interface SerializedFileHeader {
20
+ metadataSize: number;
21
+ fileSize: bigint;
22
+ version: number;
23
+ dataOffset: bigint;
24
+ endianess: number;
25
+ unityVersion: string;
26
+ targetPlatform: number;
27
+ enableTypeTree: boolean;
28
+ }
29
+ /** A serialized type entry — we keep only what object location needs. */
30
+ export interface SerializedType {
31
+ classID: number;
32
+ isStrippedType: boolean;
33
+ scriptTypeIndex: number;
34
+ }
35
+ /** One object in the file's object table. */
36
+ export interface ObjectInfo {
37
+ pathID: bigint;
38
+ byteStart: bigint;
39
+ byteSize: number;
40
+ typeIndex: number;
41
+ classID: number;
42
+ }
43
+ export interface ParsedSerializedFile {
44
+ header: SerializedFileHeader;
45
+ types: SerializedType[];
46
+ objects: ObjectInfo[];
47
+ /** the whole file buffer, retained so object payloads can be sliced on demand. */
48
+ buf: Buffer;
49
+ }
50
+ /** Unity ClassIDType values this PR cares about. (Full table lives in the decoder lib.) */
51
+ export declare const ClassID: {
52
+ readonly Texture2D: 28;
53
+ readonly Sprite: 213;
54
+ readonly TextAsset: 49;
55
+ readonly AudioClip: 83;
56
+ readonly Mesh: 43;
57
+ readonly Shader: 48;
58
+ readonly Font: 128;
59
+ readonly Material: 21;
60
+ };
61
+ /**
62
+ * Parse a serialized file far enough to enumerate its objects by class.
63
+ * Throws on any structural inconsistency (never returns a half-parsed result).
64
+ */
65
+ export declare function parseSerializedFile(buf: Buffer): ParsedSerializedFile;
@@ -0,0 +1,144 @@
1
+ /**
2
+ * serialized-file.ts — a bounded parser for Unity serialized files (.assets), format v22.
3
+ *
4
+ * SCOPE (deliberately narrow, per PR-2): parse the file-level structures needed to
5
+ * locate objects by class — header, type tree table (we only need the per-type classID),
6
+ * and the object table (path id, byte start/size, type index). We do NOT parse the full
7
+ * recursive type tree into typed fields; object payloads are parsed by class-specific
8
+ * readers (see texture2d.ts) using the byte ranges this module yields.
9
+ *
10
+ * Format reference: UnityFS SerializedFile, version 22 (LargeFilesSupport), as shipped by
11
+ * Unity 2020.3.x desktop players. Verified against Baldi's Basics Plus (2020.3.49f1):
12
+ * - header is BIG-endian; metadata endianness is declared by header.m_Endianess.
13
+ * - v>=22 uses a 64-bit metadata/file-size/data-offset layout with a relocated header.
14
+ *
15
+ * Anti-silent-corruption: every read goes through BinaryReader's bounds checks. A parse
16
+ * that runs off the rails throws with the exact offset, never returns plausible garbage.
17
+ */
18
+ import { BinaryReader } from './binary-reader.js';
19
+ /** Unity ClassIDType values this PR cares about. (Full table lives in the decoder lib.) */
20
+ export const ClassID = {
21
+ Texture2D: 28,
22
+ Sprite: 213,
23
+ TextAsset: 49,
24
+ AudioClip: 83,
25
+ Mesh: 43,
26
+ Shader: 48,
27
+ Font: 128,
28
+ Material: 21,
29
+ };
30
+ /**
31
+ * Parse a serialized file far enough to enumerate its objects by class.
32
+ * Throws on any structural inconsistency (never returns a half-parsed result).
33
+ */
34
+ export function parseSerializedFile(buf) {
35
+ // ---- Header (big-endian) ----------------------------------------------------
36
+ const r = new BinaryReader(buf, /* bigEndian */ true, 0);
37
+ // legacy 32-bit header fields (kept for all versions)
38
+ /* metadataSize (legacy) */ r.readUInt32();
39
+ /* fileSize (legacy) */ r.readUInt32();
40
+ const version = r.readUInt32();
41
+ /* dataOffset (legacy) */ r.readUInt32();
42
+ if (version < 22) {
43
+ throw new Error(`serialized-file: unsupported format version ${version}; this PR targets v22 (Unity 2020.3+). ` +
44
+ `Older versions need the 32-bit header path (future slice).`);
45
+ }
46
+ // v>=22 large-files header: endianess byte + 3 reserved, then 64-bit sizes.
47
+ const endianess = r.readUInt8();
48
+ r.skip(3); // reserved
49
+ const metadataSize = r.readUInt32(); // still 32-bit count, but...
50
+ const fileSize = r.readUInt64();
51
+ const dataOffset = r.readUInt64();
52
+ r.readUInt64(); // unknown / reserved (large-files)
53
+ // ---- Metadata (endianness from header) -------------------------------------
54
+ const little = endianess === 0;
55
+ const m = new BinaryReader(buf, /* bigEndian */ !little, r.pos);
56
+ const unityVersion = m.readCString();
57
+ const targetPlatform = m.readInt32();
58
+ const enableTypeTree = m.readUInt8() !== 0;
59
+ // ---- Type table ------------------------------------------------------------
60
+ const typeCount = m.readInt32();
61
+ const types = [];
62
+ for (let i = 0; i < typeCount; i++) {
63
+ types.push(readSerializedType(m, enableTypeTree, /* isRefType */ false));
64
+ }
65
+ // ---- Object table ----------------------------------------------------------
66
+ const objectCount = m.readInt32();
67
+ const objects = [];
68
+ for (let i = 0; i < objectCount; i++) {
69
+ m.align(4);
70
+ const pathID = m.readInt64();
71
+ const byteStart = m.readInt64();
72
+ const byteSize = m.readUInt32();
73
+ const typeIndex = m.readInt32();
74
+ const t = types[typeIndex];
75
+ const classID = t ? t.classID : -1;
76
+ objects.push({ pathID, byteStart, byteSize, typeIndex, classID });
77
+ }
78
+ return {
79
+ header: {
80
+ metadataSize,
81
+ fileSize,
82
+ version,
83
+ dataOffset,
84
+ endianess,
85
+ unityVersion,
86
+ targetPlatform,
87
+ enableTypeTree,
88
+ },
89
+ types,
90
+ objects,
91
+ buf,
92
+ };
93
+ }
94
+ /**
95
+ * Read one SerializedType for v22. We extract classID and skip the rest precisely.
96
+ * Layout (v>=16 RefactoredClassId, with v17+/v18+/v19+/v21+ deltas folded in):
97
+ * classID : Int32
98
+ * isStrippedType : UInt8 (v>=16)
99
+ * scriptTypeIndex : Int16 (v>=17)
100
+ * scriptID (16 bytes) : present when classID == 114 (MonoBehaviour)
101
+ * oldTypeHash (16 bytes)
102
+ * [typeTree blob] : present when enableTypeTree
103
+ * typeDependencies : Int32 count + count*Int32 (v>=21, non-refType)
104
+ */
105
+ function readSerializedType(m, enableTypeTree, isRefType) {
106
+ const classID = m.readInt32();
107
+ const isStrippedType = m.readUInt8() !== 0;
108
+ const scriptTypeIndex = m.readInt16();
109
+ // ScriptID (Hash128) only for MonoBehaviour (114), or refType always.
110
+ if (isRefType || classID === 114) {
111
+ m.skip(16);
112
+ }
113
+ // OldTypeHash (Hash128)
114
+ m.skip(16);
115
+ if (enableTypeTree) {
116
+ skipTypeTreeBlob(m);
117
+ if (!isRefType) {
118
+ // typeDependencies (v>=21)
119
+ const depCount = m.readInt32();
120
+ m.skip(depCount * 4);
121
+ }
122
+ }
123
+ return { classID, isStrippedType, scriptTypeIndex };
124
+ }
125
+ /**
126
+ * Skip the blob-format type tree (v>=12). Layout:
127
+ * nodeCount : Int32
128
+ * stringBufLen: Int32
129
+ * nodes : nodeCount * 32 bytes (v>=19 TypeTreeNodeWithTypeFlags = 32 bytes/node)
130
+ * stringBuf : stringBufLen bytes
131
+ * v18 introduced the blob format; the node struct is 24 bytes pre-v19 and 32 bytes v>=19.
132
+ * Baldi is v22 -> 32-byte nodes. We only need to SKIP it precisely so the object table
133
+ * lands at the right offset.
134
+ */
135
+ function skipTypeTreeBlob(m) {
136
+ const nodeCount = m.readInt32();
137
+ const stringBufLen = m.readInt32();
138
+ // v>=19 node is 32 bytes: version(u16) level(u8) typeFlags(u8) typeStrOffset(u32)
139
+ // nameStrOffset(u32) byteSize(i32) index(i32) metaFlag(u32) refTypeHash(u64)
140
+ const NODE_SIZE = 32;
141
+ m.skip(nodeCount * NODE_SIZE);
142
+ m.skip(stringBufLen);
143
+ }
144
+ //# sourceMappingURL=serialized-file.js.map