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.
- package/ACCEPTABLE_USE.md +49 -0
- package/CHANGELOG.md +119 -0
- package/LICENSE +21 -0
- package/LICENSE-EULA.md +62 -0
- package/README.md +162 -0
- package/VERIFICATION.md +132 -0
- package/dist/backends/child-pool.js +91 -0
- package/dist/backends/mcp-child.js +102 -0
- package/dist/backends/mcp-child.js.map +1 -0
- package/dist/core/config.d.ts +10 -0
- package/dist/core/config.js +48 -0
- package/dist/core/config.js.map +1 -0
- package/dist/core/engine-detector.d.ts +13 -0
- package/dist/core/engine-detector.js +247 -0
- package/dist/core/engine-detector.js.map +1 -0
- package/dist/core/event-bus.js +18 -0
- package/dist/core/file-classifier.js +394 -0
- package/dist/core/model-db.js +517 -0
- package/dist/core/model-db.js.map +1 -0
- package/dist/core/router.d.ts +6 -0
- package/dist/core/router.js +143 -0
- package/dist/core/router.js.map +1 -0
- package/dist/core/session.js +114 -0
- package/dist/decoders/audio-export.js +57 -0
- package/dist/decoders/mesh-export.d.ts +20 -0
- package/dist/decoders/mesh-export.js +174 -0
- package/dist/decoders/mesh-export.js.map +1 -0
- package/dist/decoders/native/disassembler.js +85 -0
- package/dist/decoders/native/disassembler.js.map +1 -0
- package/dist/decoders/png-encode.d.ts +17 -0
- package/dist/decoders/png-encode.js +33 -0
- package/dist/decoders/texture-decode.js +278 -0
- package/dist/decoders/texture-decode.js.map +1 -0
- package/dist/decoders/unity/audioclip.d.ts +55 -0
- package/dist/decoders/unity/audioclip.js +87 -0
- package/dist/decoders/unity/audioclip.js.map +1 -0
- package/dist/decoders/unity/binary-reader.d.ts +45 -0
- package/dist/decoders/unity/binary-reader.js +141 -0
- package/dist/decoders/unity/binary-reader.js.map +1 -0
- package/dist/decoders/unity/mesh.js +198 -0
- package/dist/decoders/unity/mesh.js.map +1 -0
- package/dist/decoders/unity/ress-reader.d.ts +33 -0
- package/dist/decoders/unity/ress-reader.js +82 -0
- package/dist/decoders/unity/ress-reader.js.map +1 -0
- package/dist/decoders/unity/serialized-file.d.ts +65 -0
- package/dist/decoders/unity/serialized-file.js +144 -0
- package/dist/decoders/unity/texture2d.js +185 -0
- package/dist/decoders/unity/vertex-data.d.ts +54 -0
- package/dist/decoders/unity/vertex-data.js +174 -0
- package/dist/decoders/unity/vertex-data.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +23 -0
- package/dist/server.d.ts +1 -0
- package/dist/server.js +66 -0
- package/dist/tools/decode-tools.d.ts +29 -0
- package/dist/tools/decode-tools.js +441 -0
- package/dist/tools/delegates/jar-editor.d.ts +2 -0
- package/dist/tools/delegates/jar-editor.js +276 -0
- package/dist/tools/delegates/unity-decompiler.d.ts +2 -0
- package/dist/tools/delegates/unity-decompiler.js +291 -0
- package/dist/tools/delegates/unreal-assets.d.ts +2 -0
- package/dist/tools/delegates/unreal-assets.js +122 -0
- package/dist/tools/detection-tools.d.ts +2 -0
- package/dist/tools/detection-tools.js +164 -0
- package/dist/tools/detection-tools.js.map +1 -0
- package/dist/tools/index.d.ts +8 -0
- package/dist/tools/index.js +30 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/native/index.d.ts +2 -0
- package/dist/tools/native/index.js +1201 -0
- package/dist/tools/native-comprehension-tools.js +298 -0
- package/dist/tools/native-comprehension-tools.js.map +1 -0
- package/dist/tools/unpack-tools.d.ts +2 -0
- package/dist/tools/unpack-tools.js +382 -0
- package/dist/tools/workflow-tools.d.ts +2 -0
- package/dist/tools/workflow-tools.js +434 -0
- package/dist/utils/logger.d.ts +11 -0
- package/dist/utils/logger.js +49 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/path-utils.d.ts +15 -0
- package/dist/utils/path-utils.js +24 -0
- package/dist/utils/path-utils.js.map +1 -0
- package/dist/utils/steam-finder.d.ts +8 -0
- package/dist/utils/steam-finder.js +32 -0
- package/dist/web/web-server.d.ts +1 -0
- package/dist/web/web-server.js +369 -0
- package/licenses/THIRD-PARTY-NOTICES.md +35 -0
- package/llms-install.md +34 -0
- package/package.json +69 -0
- package/server.json +20 -0
- package/setup.ps1 +34 -0
- package/ugm.config.json +9 -0
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* texture2d.ts — parse a Unity Texture2D object payload (Unity 2020.3 / format v22,
|
|
3
|
+
* typeTree DISABLED) into the fields needed to locate and decode its pixels.
|
|
4
|
+
*
|
|
5
|
+
* When the serialized file has enableTypeTree=false (Baldi's case, and the common
|
|
6
|
+
* release-build case), object payloads have no embedded schema — they are read
|
|
7
|
+
* POSITIONALLY against the known field order for the engine version. This module
|
|
8
|
+
* encodes the 2020.3 Texture2D field order. It is the one place that is version-shaped;
|
|
9
|
+
* a different major Unity version would need its own field order (a future slice).
|
|
10
|
+
*
|
|
11
|
+
* Reference field order (Unity 2020.3 Texture2D, little-endian desktop):
|
|
12
|
+
* m_Name : AlignedString
|
|
13
|
+
* m_ForcedFallbackFormat: Int32
|
|
14
|
+
* m_DownscaleFallback : bool ; (2020.2+) m_IsAlphaChannelOptional : bool ; align(4)
|
|
15
|
+
* m_Width : Int32
|
|
16
|
+
* m_Height : Int32
|
|
17
|
+
* m_CompleteImageSize : Int32
|
|
18
|
+
* m_MipsStripped : Int32 (2020.1+)
|
|
19
|
+
* m_TextureFormat : Int32
|
|
20
|
+
* m_MipCount : Int32
|
|
21
|
+
* m_IsReadable : bool
|
|
22
|
+
* m_IsPreProcessed : bool (2020.1+)
|
|
23
|
+
* m_IgnoreMasterTextureLimit : bool (2019.3+)
|
|
24
|
+
* m_StreamingMipmaps : bool (2018.2+)
|
|
25
|
+
* align(4)
|
|
26
|
+
* m_StreamingMipmapsPriority : Int32 (2018.2+)
|
|
27
|
+
* m_ImageCount : Int32
|
|
28
|
+
* m_TextureDimension : Int32
|
|
29
|
+
* m_TextureSettings : { FilterMode:i32, Aniso:i32, MipBias:f32, WrapU:i32, WrapV:i32, WrapW:i32 }
|
|
30
|
+
* m_LightmapFormat : Int32
|
|
31
|
+
* m_ColorSpace : Int32
|
|
32
|
+
* m_PlatformBlob : UInt8[] (Int32 len + bytes + align) (2020.2+)
|
|
33
|
+
* image data size : Int32 (== bytes inline, or 0 when streamed)
|
|
34
|
+
* m_StreamData : { offset:UInt64, size:UInt32, path:AlignedString } (when inline size==0)
|
|
35
|
+
*
|
|
36
|
+
* We tolerate trailing-field drift by reading defensively and validating width/height/
|
|
37
|
+
* format against sane bounds; an implausible parse throws rather than emitting garbage.
|
|
38
|
+
*/
|
|
39
|
+
import { BinaryReader } from './binary-reader.js';
|
|
40
|
+
/** Unity TextureFormat enum (subset + names) — mirrors the codec lib's mapping. */
|
|
41
|
+
export var TextureFormat;
|
|
42
|
+
(function (TextureFormat) {
|
|
43
|
+
TextureFormat[TextureFormat["Alpha8"] = 1] = "Alpha8";
|
|
44
|
+
TextureFormat[TextureFormat["ARGB4444"] = 2] = "ARGB4444";
|
|
45
|
+
TextureFormat[TextureFormat["RGB24"] = 3] = "RGB24";
|
|
46
|
+
TextureFormat[TextureFormat["RGBA32"] = 4] = "RGBA32";
|
|
47
|
+
TextureFormat[TextureFormat["ARGB32"] = 5] = "ARGB32";
|
|
48
|
+
TextureFormat[TextureFormat["RGB565"] = 7] = "RGB565";
|
|
49
|
+
TextureFormat[TextureFormat["R16"] = 9] = "R16";
|
|
50
|
+
TextureFormat[TextureFormat["DXT1"] = 10] = "DXT1";
|
|
51
|
+
TextureFormat[TextureFormat["DXT3"] = 11] = "DXT3";
|
|
52
|
+
TextureFormat[TextureFormat["DXT5"] = 12] = "DXT5";
|
|
53
|
+
TextureFormat[TextureFormat["RGBA4444"] = 13] = "RGBA4444";
|
|
54
|
+
TextureFormat[TextureFormat["BGRA32"] = 14] = "BGRA32";
|
|
55
|
+
TextureFormat[TextureFormat["RHalf"] = 15] = "RHalf";
|
|
56
|
+
TextureFormat[TextureFormat["RGHalf"] = 16] = "RGHalf";
|
|
57
|
+
TextureFormat[TextureFormat["RGBAHalf"] = 17] = "RGBAHalf";
|
|
58
|
+
TextureFormat[TextureFormat["RFloat"] = 18] = "RFloat";
|
|
59
|
+
TextureFormat[TextureFormat["RGFloat"] = 19] = "RGFloat";
|
|
60
|
+
TextureFormat[TextureFormat["RGBAFloat"] = 20] = "RGBAFloat";
|
|
61
|
+
TextureFormat[TextureFormat["YUY2"] = 21] = "YUY2";
|
|
62
|
+
TextureFormat[TextureFormat["RGB9e5Float"] = 22] = "RGB9e5Float";
|
|
63
|
+
TextureFormat[TextureFormat["BC6H"] = 24] = "BC6H";
|
|
64
|
+
TextureFormat[TextureFormat["BC7"] = 25] = "BC7";
|
|
65
|
+
TextureFormat[TextureFormat["BC4"] = 26] = "BC4";
|
|
66
|
+
TextureFormat[TextureFormat["BC5"] = 27] = "BC5";
|
|
67
|
+
TextureFormat[TextureFormat["DXT1Crunched"] = 28] = "DXT1Crunched";
|
|
68
|
+
TextureFormat[TextureFormat["DXT5Crunched"] = 29] = "DXT5Crunched";
|
|
69
|
+
TextureFormat[TextureFormat["PVRTC_RGB2"] = 30] = "PVRTC_RGB2";
|
|
70
|
+
TextureFormat[TextureFormat["PVRTC_RGBA2"] = 31] = "PVRTC_RGBA2";
|
|
71
|
+
TextureFormat[TextureFormat["PVRTC_RGB4"] = 32] = "PVRTC_RGB4";
|
|
72
|
+
TextureFormat[TextureFormat["PVRTC_RGBA4"] = 33] = "PVRTC_RGBA4";
|
|
73
|
+
TextureFormat[TextureFormat["ETC_RGB4"] = 34] = "ETC_RGB4";
|
|
74
|
+
TextureFormat[TextureFormat["ATC_RGB4"] = 35] = "ATC_RGB4";
|
|
75
|
+
TextureFormat[TextureFormat["ATC_RGBA8"] = 36] = "ATC_RGBA8";
|
|
76
|
+
TextureFormat[TextureFormat["EAC_R"] = 41] = "EAC_R";
|
|
77
|
+
TextureFormat[TextureFormat["EAC_R_SIGNED"] = 42] = "EAC_R_SIGNED";
|
|
78
|
+
TextureFormat[TextureFormat["EAC_RG"] = 43] = "EAC_RG";
|
|
79
|
+
TextureFormat[TextureFormat["EAC_RG_SIGNED"] = 44] = "EAC_RG_SIGNED";
|
|
80
|
+
TextureFormat[TextureFormat["ETC2_RGB"] = 45] = "ETC2_RGB";
|
|
81
|
+
TextureFormat[TextureFormat["ETC2_RGBA1"] = 46] = "ETC2_RGBA1";
|
|
82
|
+
TextureFormat[TextureFormat["ETC2_RGBA8"] = 47] = "ETC2_RGBA8";
|
|
83
|
+
TextureFormat[TextureFormat["ASTC_RGB_4x4"] = 48] = "ASTC_RGB_4x4";
|
|
84
|
+
TextureFormat[TextureFormat["ASTC_RGB_5x5"] = 49] = "ASTC_RGB_5x5";
|
|
85
|
+
TextureFormat[TextureFormat["ASTC_RGB_6x6"] = 50] = "ASTC_RGB_6x6";
|
|
86
|
+
TextureFormat[TextureFormat["ASTC_RGB_8x8"] = 51] = "ASTC_RGB_8x8";
|
|
87
|
+
TextureFormat[TextureFormat["ASTC_RGB_10x10"] = 52] = "ASTC_RGB_10x10";
|
|
88
|
+
TextureFormat[TextureFormat["ASTC_RGB_12x12"] = 53] = "ASTC_RGB_12x12";
|
|
89
|
+
TextureFormat[TextureFormat["ASTC_RGBA_4x4"] = 54] = "ASTC_RGBA_4x4";
|
|
90
|
+
TextureFormat[TextureFormat["ASTC_RGBA_5x5"] = 55] = "ASTC_RGBA_5x5";
|
|
91
|
+
TextureFormat[TextureFormat["ASTC_RGBA_6x6"] = 56] = "ASTC_RGBA_6x6";
|
|
92
|
+
TextureFormat[TextureFormat["ASTC_RGBA_8x8"] = 57] = "ASTC_RGBA_8x8";
|
|
93
|
+
TextureFormat[TextureFormat["ASTC_RGBA_10x10"] = 58] = "ASTC_RGBA_10x10";
|
|
94
|
+
TextureFormat[TextureFormat["ASTC_RGBA_12x12"] = 59] = "ASTC_RGBA_12x12";
|
|
95
|
+
TextureFormat[TextureFormat["RG16"] = 62] = "RG16";
|
|
96
|
+
TextureFormat[TextureFormat["R8"] = 63] = "R8";
|
|
97
|
+
TextureFormat[TextureFormat["ETC_RGB4Crunched"] = 64] = "ETC_RGB4Crunched";
|
|
98
|
+
TextureFormat[TextureFormat["ETC2_RGBA8Crunched"] = 65] = "ETC2_RGBA8Crunched";
|
|
99
|
+
TextureFormat[TextureFormat["RG32"] = 72] = "RG32";
|
|
100
|
+
TextureFormat[TextureFormat["RGB48"] = 73] = "RGB48";
|
|
101
|
+
TextureFormat[TextureFormat["RGBA64"] = 74] = "RGBA64";
|
|
102
|
+
})(TextureFormat || (TextureFormat = {}));
|
|
103
|
+
const MAX_DIM = 32768; // sanity bound — Unity textures never exceed this
|
|
104
|
+
/**
|
|
105
|
+
* Parse a Texture2D from its object byte-range. `header` provides endianness;
|
|
106
|
+
* `obj.byteStart` is RELATIVE to header.dataOffset.
|
|
107
|
+
*/
|
|
108
|
+
export function parseTexture2D(buf, header, obj) {
|
|
109
|
+
const little = header.endianess === 0;
|
|
110
|
+
const start = Number(header.dataOffset + obj.byteStart);
|
|
111
|
+
const end = start + obj.byteSize;
|
|
112
|
+
if (start < 0 || end > buf.length) {
|
|
113
|
+
throw new RangeError(`parseTexture2D: object range [${start}, ${end}] outside buffer ${buf.length}`);
|
|
114
|
+
}
|
|
115
|
+
// Bind the reader to this object's slice so a field-order miss can't wander into the
|
|
116
|
+
// next object's bytes — it throws inside this window instead.
|
|
117
|
+
const r = new BinaryReader(buf.subarray(start, end), /* bigEndian */ !little, 0);
|
|
118
|
+
const name = r.readAlignedString();
|
|
119
|
+
r.readInt32(); // m_ForcedFallbackFormat
|
|
120
|
+
r.readUInt8(); // m_DownscaleFallback
|
|
121
|
+
r.readUInt8(); // m_IsAlphaChannelOptional (2020.2+)
|
|
122
|
+
r.align(4);
|
|
123
|
+
const width = r.readInt32();
|
|
124
|
+
const height = r.readInt32();
|
|
125
|
+
const completeImageSize = r.readInt32();
|
|
126
|
+
r.readInt32(); // m_MipsStripped (2020.1+)
|
|
127
|
+
const textureFormat = r.readInt32();
|
|
128
|
+
const mipCount = r.readInt32();
|
|
129
|
+
if (width <= 0 || height <= 0 || width > MAX_DIM || height > MAX_DIM) {
|
|
130
|
+
throw new RangeError(`parseTexture2D("${name}"): implausible dimensions ${width}x${height} — field-order mismatch for this Unity version`);
|
|
131
|
+
}
|
|
132
|
+
r.readUInt8(); // m_IsReadable
|
|
133
|
+
r.readUInt8(); // m_IsPreProcessed (2020.1+)
|
|
134
|
+
r.readUInt8(); // m_IgnoreMasterTextureLimit (2019.3+)
|
|
135
|
+
r.readUInt8(); // m_StreamingMipmaps (2018.2+)
|
|
136
|
+
r.align(4);
|
|
137
|
+
r.readInt32(); // m_StreamingMipmapsPriority
|
|
138
|
+
r.readInt32(); // m_ImageCount
|
|
139
|
+
r.readInt32(); // m_TextureDimension
|
|
140
|
+
// m_TextureSettings (6 ints; MipBias is a float but width-equal)
|
|
141
|
+
r.skip(6 * 4);
|
|
142
|
+
r.readInt32(); // m_LightmapFormat
|
|
143
|
+
r.readInt32(); // m_ColorSpace
|
|
144
|
+
// m_PlatformBlob (2020.2+): Int32 length + bytes + align(4)
|
|
145
|
+
const blobLen = r.readInt32();
|
|
146
|
+
if (blobLen < 0 || blobLen > r.remaining) {
|
|
147
|
+
throw new RangeError(`parseTexture2D("${name}"): implausible m_PlatformBlob length ${blobLen}`);
|
|
148
|
+
}
|
|
149
|
+
r.skip(blobLen);
|
|
150
|
+
r.align(4);
|
|
151
|
+
// image data: Int32 size; if >0 the bytes are inline, else they're streamed.
|
|
152
|
+
const inlineSize = r.readInt32();
|
|
153
|
+
let inlineData = Buffer.alloc(0);
|
|
154
|
+
if (inlineSize > 0) {
|
|
155
|
+
inlineData = Buffer.from(r.readBytes(inlineSize)); // copy out of the shared buffer
|
|
156
|
+
}
|
|
157
|
+
// m_StreamData (offset:UInt64, size:UInt32, path:AlignedString)
|
|
158
|
+
let streamData = null;
|
|
159
|
+
if (r.remaining >= 12) {
|
|
160
|
+
const offset = r.readUInt64();
|
|
161
|
+
const size = r.readUInt32();
|
|
162
|
+
const path = r.remaining >= 4 ? r.readAlignedString() : '';
|
|
163
|
+
if (size > 0 && path) {
|
|
164
|
+
streamData = { offset, size, path };
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
if (inlineData.length === 0 && !streamData) {
|
|
168
|
+
// Some textures legitimately have completeImageSize but no stream/inline (rare);
|
|
169
|
+
// surface it as a parse note rather than silently producing an empty texture.
|
|
170
|
+
if (completeImageSize > 0) {
|
|
171
|
+
throw new Error(`parseTexture2D("${name}"): no inline data and no stream data, but completeImageSize=${completeImageSize}`);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
return {
|
|
175
|
+
name,
|
|
176
|
+
width,
|
|
177
|
+
height,
|
|
178
|
+
textureFormat,
|
|
179
|
+
formatName: TextureFormat[textureFormat] ?? `Unknown(${textureFormat})`,
|
|
180
|
+
mipCount,
|
|
181
|
+
inlineData,
|
|
182
|
+
streamData,
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
//# sourceMappingURL=texture2d.js.map
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* vertex-data.ts — decode a Unity Mesh's m_VertexData into typed vertex attributes.
|
|
3
|
+
*
|
|
4
|
+
* Unity packs all vertex attributes (position, normal, tangent, color, uv0..uv7) into one
|
|
5
|
+
* interleaved byte blob, described by a list of ChannelInfo entries. Each channel says:
|
|
6
|
+
* stream — which interleaved stream it lives in (usually 0)
|
|
7
|
+
* offset — byte offset WITHIN one vertex's slice of that stream
|
|
8
|
+
* format — the component data type (float32 / float16 / unorm8 / ...)
|
|
9
|
+
* dimension — component count (3 for position, 2 for uv, 4 for tangent/color)
|
|
10
|
+
* The per-vertex stride of a stream is the sum of its channels' byte sizes (aligned).
|
|
11
|
+
*
|
|
12
|
+
* This module reads the channels we export (POSITION, NORMAL, and UV0) as float32 arrays.
|
|
13
|
+
* Other channels are skipped for the first slice; nothing throws on an unknown channel —
|
|
14
|
+
* it's simply not extracted (and the caller notes which attributes were exported).
|
|
15
|
+
*
|
|
16
|
+
* Reference field order: Unity 2020.3 VertexData (AssetStudio Mesh.cs), little-endian.
|
|
17
|
+
*/
|
|
18
|
+
/** Unity VertexChannelFormat (2019+). The values we decode are the common ones. */
|
|
19
|
+
export declare enum VertexFormat {
|
|
20
|
+
Float = 0,
|
|
21
|
+
Float16 = 1,
|
|
22
|
+
UNorm8 = 2,
|
|
23
|
+
SNorm8 = 3,
|
|
24
|
+
UNorm16 = 4,
|
|
25
|
+
SNorm16 = 5,
|
|
26
|
+
UInt8 = 6,
|
|
27
|
+
SInt8 = 7,
|
|
28
|
+
UInt16 = 8,
|
|
29
|
+
SInt16 = 9,
|
|
30
|
+
UInt32 = 10,
|
|
31
|
+
SInt32 = 11
|
|
32
|
+
}
|
|
33
|
+
export interface ChannelInfo {
|
|
34
|
+
stream: number;
|
|
35
|
+
offset: number;
|
|
36
|
+
format: number;
|
|
37
|
+
dimension: number;
|
|
38
|
+
}
|
|
39
|
+
export interface VertexDataRaw {
|
|
40
|
+
vertexCount: number;
|
|
41
|
+
channels: ChannelInfo[];
|
|
42
|
+
/** the interleaved vertex byte blob (after resolving inline vs streamed). */
|
|
43
|
+
data: Buffer;
|
|
44
|
+
}
|
|
45
|
+
/** Byte size of one component of a given vertex format. */
|
|
46
|
+
export declare function formatSize(format: number): number;
|
|
47
|
+
/** IEEE half (float16) -> float32. */
|
|
48
|
+
export declare function halfToFloat(h: number): number;
|
|
49
|
+
/**
|
|
50
|
+
* Extract a per-vertex float attribute (e.g. POSITION dim=3) from the interleaved blob.
|
|
51
|
+
* Returns a flat Float32Array of length vertexCount*outDim. Components beyond the channel's
|
|
52
|
+
* real dimension are zero-filled; if the channel is absent, returns null.
|
|
53
|
+
*/
|
|
54
|
+
export declare function extractAttribute(vd: VertexDataRaw, channelIndex: number, outDim: number): Float32Array | null;
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* vertex-data.ts — decode a Unity Mesh's m_VertexData into typed vertex attributes.
|
|
3
|
+
*
|
|
4
|
+
* Unity packs all vertex attributes (position, normal, tangent, color, uv0..uv7) into one
|
|
5
|
+
* interleaved byte blob, described by a list of ChannelInfo entries. Each channel says:
|
|
6
|
+
* stream — which interleaved stream it lives in (usually 0)
|
|
7
|
+
* offset — byte offset WITHIN one vertex's slice of that stream
|
|
8
|
+
* format — the component data type (float32 / float16 / unorm8 / ...)
|
|
9
|
+
* dimension — component count (3 for position, 2 for uv, 4 for tangent/color)
|
|
10
|
+
* The per-vertex stride of a stream is the sum of its channels' byte sizes (aligned).
|
|
11
|
+
*
|
|
12
|
+
* This module reads the channels we export (POSITION, NORMAL, and UV0) as float32 arrays.
|
|
13
|
+
* Other channels are skipped for the first slice; nothing throws on an unknown channel —
|
|
14
|
+
* it's simply not extracted (and the caller notes which attributes were exported).
|
|
15
|
+
*
|
|
16
|
+
* Reference field order: Unity 2020.3 VertexData (AssetStudio Mesh.cs), little-endian.
|
|
17
|
+
*/
|
|
18
|
+
import { BinaryReader } from './binary-reader.js';
|
|
19
|
+
/** Unity VertexChannelFormat (2019+). The values we decode are the common ones. */
|
|
20
|
+
export var VertexFormat;
|
|
21
|
+
(function (VertexFormat) {
|
|
22
|
+
VertexFormat[VertexFormat["Float"] = 0] = "Float";
|
|
23
|
+
VertexFormat[VertexFormat["Float16"] = 1] = "Float16";
|
|
24
|
+
VertexFormat[VertexFormat["UNorm8"] = 2] = "UNorm8";
|
|
25
|
+
VertexFormat[VertexFormat["SNorm8"] = 3] = "SNorm8";
|
|
26
|
+
VertexFormat[VertexFormat["UNorm16"] = 4] = "UNorm16";
|
|
27
|
+
VertexFormat[VertexFormat["SNorm16"] = 5] = "SNorm16";
|
|
28
|
+
VertexFormat[VertexFormat["UInt8"] = 6] = "UInt8";
|
|
29
|
+
VertexFormat[VertexFormat["SInt8"] = 7] = "SInt8";
|
|
30
|
+
VertexFormat[VertexFormat["UInt16"] = 8] = "UInt16";
|
|
31
|
+
VertexFormat[VertexFormat["SInt16"] = 9] = "SInt16";
|
|
32
|
+
VertexFormat[VertexFormat["UInt32"] = 10] = "UInt32";
|
|
33
|
+
VertexFormat[VertexFormat["SInt32"] = 11] = "SInt32";
|
|
34
|
+
})(VertexFormat || (VertexFormat = {}));
|
|
35
|
+
/** Byte size of one component of a given vertex format. */
|
|
36
|
+
export function formatSize(format) {
|
|
37
|
+
switch (format) {
|
|
38
|
+
case VertexFormat.Float:
|
|
39
|
+
case VertexFormat.UInt32:
|
|
40
|
+
case VertexFormat.SInt32:
|
|
41
|
+
return 4;
|
|
42
|
+
case VertexFormat.Float16:
|
|
43
|
+
case VertexFormat.UNorm16:
|
|
44
|
+
case VertexFormat.SNorm16:
|
|
45
|
+
case VertexFormat.UInt16:
|
|
46
|
+
case VertexFormat.SInt16:
|
|
47
|
+
return 2;
|
|
48
|
+
case VertexFormat.UNorm8:
|
|
49
|
+
case VertexFormat.SNorm8:
|
|
50
|
+
case VertexFormat.UInt8:
|
|
51
|
+
case VertexFormat.SInt8:
|
|
52
|
+
return 1;
|
|
53
|
+
default:
|
|
54
|
+
return 4;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
/** Read one component as a float (normalizing where the format implies it). */
|
|
58
|
+
function readComponent(r, format) {
|
|
59
|
+
switch (format) {
|
|
60
|
+
case VertexFormat.Float:
|
|
61
|
+
return readF32(r);
|
|
62
|
+
case VertexFormat.Float16:
|
|
63
|
+
return halfToFloat(readU16(r));
|
|
64
|
+
case VertexFormat.UNorm8:
|
|
65
|
+
return readU8(r) / 255;
|
|
66
|
+
case VertexFormat.SNorm8:
|
|
67
|
+
return Math.max(readI8(r) / 127, -1);
|
|
68
|
+
case VertexFormat.UNorm16:
|
|
69
|
+
return readU16(r) / 65535;
|
|
70
|
+
case VertexFormat.SNorm16:
|
|
71
|
+
return Math.max(readI16(r) / 32767, -1);
|
|
72
|
+
case VertexFormat.UInt8:
|
|
73
|
+
return readU8(r);
|
|
74
|
+
case VertexFormat.SInt8:
|
|
75
|
+
return readI8(r);
|
|
76
|
+
case VertexFormat.UInt16:
|
|
77
|
+
return readU16(r);
|
|
78
|
+
case VertexFormat.SInt16:
|
|
79
|
+
return readI16(r);
|
|
80
|
+
case VertexFormat.UInt32:
|
|
81
|
+
case VertexFormat.SInt32:
|
|
82
|
+
return Number(readU32(r));
|
|
83
|
+
default:
|
|
84
|
+
return readF32(r);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
// Small explicit readers (avoid the awkward advance() trick above for clarity).
|
|
88
|
+
function readF32(r) {
|
|
89
|
+
const v = r.buf.readFloatLE(r.pos);
|
|
90
|
+
r.pos += 4;
|
|
91
|
+
return v;
|
|
92
|
+
}
|
|
93
|
+
function readU8(r) {
|
|
94
|
+
const v = r.buf.readUInt8(r.pos);
|
|
95
|
+
r.pos += 1;
|
|
96
|
+
return v;
|
|
97
|
+
}
|
|
98
|
+
function readI8(r) {
|
|
99
|
+
const v = r.buf.readInt8(r.pos);
|
|
100
|
+
r.pos += 1;
|
|
101
|
+
return v;
|
|
102
|
+
}
|
|
103
|
+
function readU16(r) {
|
|
104
|
+
const v = r.buf.readUInt16LE(r.pos);
|
|
105
|
+
r.pos += 2;
|
|
106
|
+
return v;
|
|
107
|
+
}
|
|
108
|
+
function readI16(r) {
|
|
109
|
+
const v = r.buf.readInt16LE(r.pos);
|
|
110
|
+
r.pos += 2;
|
|
111
|
+
return v;
|
|
112
|
+
}
|
|
113
|
+
function readU32(r) {
|
|
114
|
+
const v = r.buf.readUInt32LE(r.pos);
|
|
115
|
+
r.pos += 4;
|
|
116
|
+
return v;
|
|
117
|
+
}
|
|
118
|
+
/** IEEE half (float16) -> float32. */
|
|
119
|
+
export function halfToFloat(h) {
|
|
120
|
+
const s = (h & 0x8000) >> 15;
|
|
121
|
+
const e = (h & 0x7c00) >> 10;
|
|
122
|
+
const f = h & 0x03ff;
|
|
123
|
+
if (e === 0)
|
|
124
|
+
return (s ? -1 : 1) * Math.pow(2, -14) * (f / 1024);
|
|
125
|
+
if (e === 0x1f)
|
|
126
|
+
return f ? NaN : (s ? -1 : 1) * Infinity;
|
|
127
|
+
return (s ? -1 : 1) * Math.pow(2, e - 15) * (1 + f / 1024);
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Extract a per-vertex float attribute (e.g. POSITION dim=3) from the interleaved blob.
|
|
131
|
+
* Returns a flat Float32Array of length vertexCount*outDim. Components beyond the channel's
|
|
132
|
+
* real dimension are zero-filled; if the channel is absent, returns null.
|
|
133
|
+
*/
|
|
134
|
+
export function extractAttribute(vd, channelIndex, outDim) {
|
|
135
|
+
const ch = vd.channels[channelIndex];
|
|
136
|
+
if (!ch || (ch.dimension & 0x0f) === 0)
|
|
137
|
+
return null;
|
|
138
|
+
const dim = ch.dimension & 0x0f;
|
|
139
|
+
const compSize = formatSize(ch.format);
|
|
140
|
+
// Per-stream stride = sum of byte sizes of all channels in that stream.
|
|
141
|
+
const stride = streamStride(vd.channels, ch.stream);
|
|
142
|
+
if (stride === 0)
|
|
143
|
+
return null;
|
|
144
|
+
// Byte offset of this stream's region within the blob: streams are concatenated, each
|
|
145
|
+
// region = vertexCount * thatStreamStride. Compute the start of ch.stream.
|
|
146
|
+
let streamStart = 0;
|
|
147
|
+
for (let s = 0; s < ch.stream; s++) {
|
|
148
|
+
streamStart += vd.vertexCount * streamStride(vd.channels, s);
|
|
149
|
+
}
|
|
150
|
+
const out = new Float32Array(vd.vertexCount * outDim);
|
|
151
|
+
const r = new BinaryReader(vd.data, false, 0);
|
|
152
|
+
for (let v = 0; v < vd.vertexCount; v++) {
|
|
153
|
+
const base = streamStart + v * stride + ch.offset;
|
|
154
|
+
for (let c = 0; c < dim && c < outDim; c++) {
|
|
155
|
+
r.pos = base + c * compSize;
|
|
156
|
+
if (r.pos + compSize > vd.data.length)
|
|
157
|
+
return out; // bounds guard: stop, return what we have
|
|
158
|
+
out[v * outDim + c] = readComponent(r, ch.format);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
return out;
|
|
162
|
+
}
|
|
163
|
+
/** Sum of byte sizes of channels assigned to a given stream. */
|
|
164
|
+
function streamStride(channels, stream) {
|
|
165
|
+
let s = 0;
|
|
166
|
+
for (const ch of channels) {
|
|
167
|
+
if (ch.stream !== stream)
|
|
168
|
+
continue;
|
|
169
|
+
const dim = ch.dimension & 0x0f;
|
|
170
|
+
s += dim * formatSize(ch.format);
|
|
171
|
+
}
|
|
172
|
+
return s;
|
|
173
|
+
}
|
|
174
|
+
//# sourceMappingURL=vertex-data.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vertex-data.js","sourceRoot":"","sources":["../../../src/decoders/unity/vertex-data.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { startMcpServer } from './server.js';
|
|
3
|
+
import { startWebServer } from './web/web-server.js';
|
|
4
|
+
import { loadConfig } from './core/config.js';
|
|
5
|
+
import { logger } from './utils/logger.js';
|
|
6
|
+
async function main() {
|
|
7
|
+
const config = loadConfig();
|
|
8
|
+
// Start the web dashboard (runs on HTTP port, independent of MCP stdio)
|
|
9
|
+
try {
|
|
10
|
+
startWebServer(config.webPort);
|
|
11
|
+
}
|
|
12
|
+
catch (err) {
|
|
13
|
+
logger.warn('Web dashboard failed to start', err);
|
|
14
|
+
// Non-fatal: MCP server can run without the dashboard
|
|
15
|
+
}
|
|
16
|
+
// Start the MCP server (communicates via stdio)
|
|
17
|
+
await startMcpServer();
|
|
18
|
+
}
|
|
19
|
+
main().catch((err) => {
|
|
20
|
+
logger.error('Fatal error', err);
|
|
21
|
+
process.exit(1);
|
|
22
|
+
});
|
|
23
|
+
//# sourceMappingURL=index.js.map
|
package/dist/server.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function startMcpServer(): Promise<void>;
|
package/dist/server.js
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
2
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
3
|
+
import { ListToolsRequestSchema, CallToolRequestSchema, } from '@modelcontextprotocol/sdk/types.js';
|
|
4
|
+
import { readFileSync } from 'node:fs';
|
|
5
|
+
import { dirname, resolve } from 'node:path';
|
|
6
|
+
import { fileURLToPath } from 'node:url';
|
|
7
|
+
import { getAllTools } from './tools/index.js';
|
|
8
|
+
import { logger } from './utils/logger.js';
|
|
9
|
+
// Single source of truth for the version: package.json. A hardcoded string here
|
|
10
|
+
// silently drifts from the shipped package (it once reported 1.0.0 for a 0.1.0
|
|
11
|
+
// release), which makes it impossible to tell which build a user is running.
|
|
12
|
+
function getVersion() {
|
|
13
|
+
try {
|
|
14
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
15
|
+
const pkg = JSON.parse(readFileSync(resolve(here, '../package.json'), 'utf-8'));
|
|
16
|
+
return typeof pkg.version === 'string' ? pkg.version : '0.0.0';
|
|
17
|
+
}
|
|
18
|
+
catch {
|
|
19
|
+
return '0.0.0';
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
export async function startMcpServer() {
|
|
23
|
+
const server = new Server({ name: 'universal-game-modder', version: getVersion() }, { capabilities: { tools: {} } });
|
|
24
|
+
// Register tool list handler
|
|
25
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
26
|
+
const tools = getAllTools();
|
|
27
|
+
return {
|
|
28
|
+
tools: tools.map(t => ({
|
|
29
|
+
name: t.name,
|
|
30
|
+
description: t.description,
|
|
31
|
+
inputSchema: t.inputSchema,
|
|
32
|
+
})),
|
|
33
|
+
};
|
|
34
|
+
});
|
|
35
|
+
// Register tool call handler
|
|
36
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
37
|
+
const { name, arguments: args } = request.params;
|
|
38
|
+
const tools = getAllTools();
|
|
39
|
+
const tool = tools.find(t => t.name === name);
|
|
40
|
+
if (!tool) {
|
|
41
|
+
return {
|
|
42
|
+
content: [{ type: 'text', text: `Unknown tool: ${name}. Use list_available_tools to see available tools.` }],
|
|
43
|
+
isError: true,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
try {
|
|
47
|
+
const result = await tool.handler(args || {});
|
|
48
|
+
return {
|
|
49
|
+
content: [{ type: 'text', text: result }],
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
catch (err) {
|
|
53
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
54
|
+
logger.error(`Tool ${name} failed`, msg);
|
|
55
|
+
return {
|
|
56
|
+
content: [{ type: 'text', text: `ERROR in ${name}: ${msg}` }],
|
|
57
|
+
isError: true,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
// Connect to stdio transport
|
|
62
|
+
const transport = new StdioServerTransport();
|
|
63
|
+
await server.connect(transport);
|
|
64
|
+
logger.info('Universal Game Modder MCP server started on stdio');
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* decode-tools.ts — PR-2 "Universal Asset Decoder" (texture-first slice).
|
|
3
|
+
*
|
|
4
|
+
* decode_assets(db_path | game_path): reads the PR-1 catalog (The Model), finds the Unity
|
|
5
|
+
* .assets container rows PR-1 catalogued as un-expanded, cracks each one open with our
|
|
6
|
+
* serialized-file walker, extracts every Texture2D (pulling streamed pixels from the
|
|
7
|
+
* sibling .resS), decodes to RGBA via the wrapped codec, writes a PNG, and writes the
|
|
8
|
+
* decoded asset back into The Model as its own row:
|
|
9
|
+
*
|
|
10
|
+
* asset(container_path = the .assets file, internal_path = "<TexName>#<pathID>",
|
|
11
|
+
* type = 'texture', format = <TextureFormat>, decoded = 1,
|
|
12
|
+
* decoded_path = <png>, provenance = 'verified', source_tool = 'decode_assets')
|
|
13
|
+
*
|
|
14
|
+
* This uses the container_path/internal_path seam PR-1 built for exactly this (PR-1 rows
|
|
15
|
+
* have internal_path = '' for standalone files; PR-2 members get a non-empty internal_path,
|
|
16
|
+
* so the UNIQUE (game_id, container_path, internal_path) key never collides with the
|
|
17
|
+
* container's own catalog row).
|
|
18
|
+
*
|
|
19
|
+
* RAILS (honored):
|
|
20
|
+
* - READ-ONLY on game files. The ONLY writes are: the decoded PNGs (jailed to the output
|
|
21
|
+
* dir, default <game>/.autopsy/decoded/, overridable for write-protected installs) and
|
|
22
|
+
* the .autopsy.db rows. Never a byte into the game's own assets.
|
|
23
|
+
* - VERIFY-AFTER-WRITE: each PNG is re-read/validated; each DB row is read back.
|
|
24
|
+
* - NEVER SILENTLY DROP: an unsupported format / unreadable stream becomes a decoded=0
|
|
25
|
+
* row with a note, and the run continues (A3-class).
|
|
26
|
+
* - PROVENANCE: a byte-level decoded texture is 'verified'; a failed one is 'uncertain'.
|
|
27
|
+
*/
|
|
28
|
+
import type { ToolDefinition } from './index.js';
|
|
29
|
+
export declare function getDecodeTools(): ToolDefinition[];
|