mercurykit 0.1.0__tar.gz
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.
- mercurykit-0.1.0/LICENSE +21 -0
- mercurykit-0.1.0/PKG-INFO +319 -0
- mercurykit-0.1.0/README.md +284 -0
- mercurykit-0.1.0/pyproject.toml +48 -0
- mercurykit-0.1.0/setup.cfg +4 -0
- mercurykit-0.1.0/src/mercurykit/__init__.py +18 -0
- mercurykit-0.1.0/src/mercurykit/__main__.py +4 -0
- mercurykit-0.1.0/src/mercurykit/_bfpk/__init__.py +5 -0
- mercurykit-0.1.0/src/mercurykit/_bfpk/codecs.py +140 -0
- mercurykit-0.1.0/src/mercurykit/_bfpk/engine.py +142 -0
- mercurykit-0.1.0/src/mercurykit/_bfpk/extraction.py +108 -0
- mercurykit-0.1.0/src/mercurykit/_bfpk/manifest.py +1061 -0
- mercurykit-0.1.0/src/mercurykit/_bfpk/models.py +50 -0
- mercurykit-0.1.0/src/mercurykit/_bfpk/repack.py +1001 -0
- mercurykit-0.1.0/src/mercurykit/archive.py +55 -0
- mercurykit-0.1.0/src/mercurykit/bfpk.py +5 -0
- mercurykit-0.1.0/src/mercurykit/binary.py +178 -0
- mercurykit-0.1.0/src/mercurykit/bits.py +52 -0
- mercurykit-0.1.0/src/mercurykit/cli.py +312 -0
- mercurykit-0.1.0/src/mercurykit/codecs.py +104 -0
- mercurykit-0.1.0/src/mercurykit/mirror_of_fate.py +461 -0
- mercurykit-0.1.0/src/mercurykit/mofh.py +5 -0
- mercurykit-0.1.0/src/mercurykit/progress.py +162 -0
- mercurykit-0.1.0/src/mercurykit/scanner.py +88 -0
- mercurykit-0.1.0/src/mercurykit/security.py +29 -0
- mercurykit-0.1.0/src/mercurykit.egg-info/PKG-INFO +319 -0
- mercurykit-0.1.0/src/mercurykit.egg-info/SOURCES.txt +32 -0
- mercurykit-0.1.0/src/mercurykit.egg-info/dependency_links.txt +1 -0
- mercurykit-0.1.0/src/mercurykit.egg-info/entry_points.txt +2 -0
- mercurykit-0.1.0/src/mercurykit.egg-info/requires.txt +10 -0
- mercurykit-0.1.0/src/mercurykit.egg-info/top_level.txt +1 -0
- mercurykit-0.1.0/tests/test_bfpk_cli.py +1667 -0
- mercurykit-0.1.0/tests/test_binary.py +49 -0
- mercurykit-0.1.0/tests/test_codecs.py +18 -0
mercurykit-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Falkrian
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: mercurykit
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: MercurySteam archive scanner, extractor, and repacker.
|
|
5
|
+
Author: MercuryKit Contributors
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/Falkrian/MercuryKit
|
|
8
|
+
Project-URL: Repository, https://github.com/Falkrian/MercuryKit
|
|
9
|
+
Project-URL: Issues, https://github.com/Falkrian/MercuryKit/issues
|
|
10
|
+
Keywords: mercurysteam,archive,bfpk,castlevania,scrapland,spacelords,modding
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Environment :: Console
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Intended Audience :: End Users/Desktop
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
+
Classifier: Topic :: Games/Entertainment
|
|
21
|
+
Classifier: Topic :: System :: Archiving
|
|
22
|
+
Classifier: Topic :: Utilities
|
|
23
|
+
Requires-Python: >=3.11
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
License-File: LICENSE
|
|
26
|
+
Requires-Dist: cryptography>=42
|
|
27
|
+
Provides-Extra: lz4
|
|
28
|
+
Requires-Dist: lz4>=4.3; extra == "lz4"
|
|
29
|
+
Provides-Extra: dev
|
|
30
|
+
Requires-Dist: pytest>=8; extra == "dev"
|
|
31
|
+
Requires-Dist: build>=1.2; extra == "dev"
|
|
32
|
+
Requires-Dist: twine>=5; extra == "dev"
|
|
33
|
+
Requires-Dist: readme-renderer[md]>=43; extra == "dev"
|
|
34
|
+
Dynamic: license-file
|
|
35
|
+
|
|
36
|
+
<div align="center"><img src="https://raw.githubusercontent.com/Falkrian/MercuryKit/main/assets/mercurykit-banner.png" alt="MercuryKit" width="900"></div>
|
|
37
|
+
|
|
38
|
+
# MercuryKit
|
|
39
|
+
|
|
40
|
+
[](https://opensource.org/licenses/MIT)
|
|
41
|
+
[](https://twitter.com/FalkrianTTV)
|
|
42
|
+
|
|
43
|
+
[**Overview**](https://github.com/Falkrian/MercuryKit#overview)
|
|
44
|
+
| [**Features**](https://github.com/Falkrian/MercuryKit/#features)
|
|
45
|
+
| [**Supported Games**](https://github.com/Falkrian/MercuryKit/#supported-games)
|
|
46
|
+
| [**Installation**](https://github.com/Falkrian/MercuryKit/#installation)
|
|
47
|
+
| [**Quick Start**](https://github.com/Falkrian/MercuryKit#quick-start)
|
|
48
|
+
| [**CLI Reference**](https://github.com/Falkrian/MercuryKit/#cli-reference)
|
|
49
|
+
|
|
50
|
+
## Overview
|
|
51
|
+
|
|
52
|
+
MercuryKit is a Python package and command line toolkit for working with MercurySteam archive files. It can scan archives, unpack their contents safely, and repack edited directory trees back into archive form for supported game layouts.
|
|
53
|
+
|
|
54
|
+
## Features
|
|
55
|
+
|
|
56
|
+
- Scan individual files or whole directories for supported MercurySteam archives.
|
|
57
|
+
- Recursively scan directory trees and print verbose archive details when needed.
|
|
58
|
+
- Unpack archives with path safety checks to avoid writing outside the destination directory.
|
|
59
|
+
- Repack extracted folders back into supported archive versions.
|
|
60
|
+
- Preserve useful archive metadata, including encrypted picture archive table metadata.
|
|
61
|
+
- Support raw, zlib-compressed, LZ4-block-compressed, AES-encrypted table, and encrypted picture archive layouts.
|
|
62
|
+
- Show progress automatically on interactive terminals, with switches to force or suppress it.
|
|
63
|
+
- Use MercuryKit from Python through the public `mercurykit` package.
|
|
64
|
+
|
|
65
|
+
## Supported Games
|
|
66
|
+
|
|
67
|
+
| Game | Support | Support Comment |
|
|
68
|
+
| --- | --- | --- |
|
|
69
|
+
| Scrapland Remastered | Full | Supports raw `.packed` archives using BFPK version `0`, including scan, unpack, and directory-based repack with `cp1252` path encoding. |
|
|
70
|
+
| Castlevania: Lords of Shadow - Ultimate Edition | Full | Supports Steam `.dat` archives using AES-256-CBC encrypted file tables, including raw `0x2` and zlib-record `0x3` variants. |
|
|
71
|
+
| Castlevania: Lords of Shadow 2 | Full | Supports archive versions `0x100`, `0x101`, and `0x102`, including raw, zlib, and chunked zlib variants. |
|
|
72
|
+
| Castlevania Lords of Shadow - Mirror of Fate HD | Full | Supports `.pack` archives, including scan, unpack, directory-based repack, computed header fields, and automatic `system/files.toc` updates. |
|
|
73
|
+
| Blades of Fire | Full* | Supports archive versions `0x100`, `0x102`, `0x300`, and encrypted `Pics.packed` archives using `0x901`. JPG entries are preserved as packed payloads until the viewer-ready restoration transform is implemented. |
|
|
74
|
+
| Spacelords | Full | Supports archive versions `0x500`, `0x502`, and encrypted `Pics.packed` archives using `0xD01`, including LZ4-block variants. |
|
|
75
|
+
|
|
76
|
+
Blades of Fire `0x901` JPG entries are currently extracted as their original packed payloads. They are preserved for archive round trips, but the viewer-ready JPG restoration transform is still being researched.
|
|
77
|
+
|
|
78
|
+
## Installation
|
|
79
|
+
|
|
80
|
+
MercuryKit requires Python 3.11 or newer.
|
|
81
|
+
|
|
82
|
+
For local development or direct use from this checkout:
|
|
83
|
+
|
|
84
|
+
```powershell
|
|
85
|
+
python -m pip install -e .
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Install optional LZ4 support when working with archive versions that use LZ4-block compression:
|
|
89
|
+
|
|
90
|
+
```powershell
|
|
91
|
+
python -m pip install -e ".[lz4]"
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## Quick Start
|
|
95
|
+
|
|
96
|
+
### Scrapland Remastered
|
|
97
|
+
|
|
98
|
+
Scan:
|
|
99
|
+
|
|
100
|
+
```powershell
|
|
101
|
+
mercurykit scan "D:\Steam\steamapps\common\Scrapland\data.packed" --verbose
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Unpack:
|
|
105
|
+
|
|
106
|
+
```powershell
|
|
107
|
+
mercurykit unpack "D:\Steam\steamapps\common\Scrapland\data.packed" --dest ".\Output\scrapland-data"
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Repack:
|
|
111
|
+
|
|
112
|
+
```powershell
|
|
113
|
+
mercurykit repack ".\Output\scrapland-data" --output ".\data.repacked.packed" --option layout=scrapland
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Scrapland `.packed` archives are raw containers. MercuryKit recalculates the table offsets during repack and writes paths using Windows-compatible `cp1252` encoding.
|
|
117
|
+
|
|
118
|
+
### Castlevania: Lords of Shadow - Ultimate Edition
|
|
119
|
+
|
|
120
|
+
Scan:
|
|
121
|
+
|
|
122
|
+
```powershell
|
|
123
|
+
mercurykit scan "D:\Steam\steamapps\common\CastlevaniaLoS\Data00.dat" --verbose
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Unpack:
|
|
127
|
+
|
|
128
|
+
```powershell
|
|
129
|
+
mercurykit unpack "D:\Steam\steamapps\common\CastlevaniaLoS\Data00.dat" --dest ".\Output\losue-data00"
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
Repack a zlib-record `.dat` archive:
|
|
133
|
+
|
|
134
|
+
```powershell
|
|
135
|
+
mercurykit repack ".\Output\losue-data00" --output ".\Data00.repacked.dat" --option layout=lords_of_shadow_ultimate --option archive_version=0x3 --option compression_level=6
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Repack a raw `.dat` archive:
|
|
139
|
+
|
|
140
|
+
```powershell
|
|
141
|
+
mercurykit repack ".\Output\losue-data03" --output ".\Data03.repacked.dat" --option layout=lords_of_shadow_ultimate --option archive_version=0x2
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### Castlevania: Lords of Shadow 2
|
|
145
|
+
|
|
146
|
+
Scan:
|
|
147
|
+
|
|
148
|
+
```powershell
|
|
149
|
+
mercurykit scan "D:\Steam\steamapps\common\Castlevania Lords of Shadow 2\English.packed"
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
Unpack:
|
|
153
|
+
|
|
154
|
+
```powershell
|
|
155
|
+
mercurykit unpack "D:\Steam\steamapps\common\Castlevania Lords of Shadow 2\English.packed" --dest ".\Output\los2-english"
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
Repack:
|
|
159
|
+
|
|
160
|
+
```powershell
|
|
161
|
+
mercurykit repack ".\Output\los2-english" --output ".\English.repacked" --option archive_version=0x102 --option file_chunk_size=262144 --option compression_level=6
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
### Castlevania Lords of Shadow - Mirror of Fate HD
|
|
165
|
+
|
|
166
|
+
Scan:
|
|
167
|
+
|
|
168
|
+
```powershell
|
|
169
|
+
mercurykit scan "D:\Steam\steamapps\common\Castlevania Lords of Shadow - Mirror of Fate HD\data.pack" --verbose
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
Unpack:
|
|
173
|
+
|
|
174
|
+
```powershell
|
|
175
|
+
mercurykit unpack "D:\Steam\steamapps\common\Castlevania Lords of Shadow - Mirror of Fate HD\data.pack" --dest ".\Output\mofh-data"
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
Repack:
|
|
179
|
+
|
|
180
|
+
```powershell
|
|
181
|
+
mercurykit repack ".\Output\mofh-data" --output ".\data.repacked.pack"
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
Mirror of Fate HD `.pack` output automatically uses the Mirror of Fate HD repacker when no BFPK `layout` or `archive_version` option is supplied. If `system/files.toc` is present, MercuryKit updates its path-hash and file-size records in the repacked archive.
|
|
185
|
+
|
|
186
|
+
### Blades of Fire
|
|
187
|
+
|
|
188
|
+
Scan:
|
|
189
|
+
|
|
190
|
+
```powershell
|
|
191
|
+
mercurykit scan "D:\Steam\steamapps\common\Blades of Fire\Data00.packed"
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
Unpack:
|
|
195
|
+
|
|
196
|
+
```powershell
|
|
197
|
+
mercurykit unpack "D:\Steam\steamapps\common\Blades of Fire\Data00.packed" --dest ".\Output\blades-data" --overwrite
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
Repack:
|
|
201
|
+
|
|
202
|
+
```powershell
|
|
203
|
+
mercurykit repack ".\Output\blades-data" --output ".\Data00.repacked.packed" --option layout=blades_of_fire --option archive_version=0x102
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
Repack encrypted picture archives with the picture layout version:
|
|
207
|
+
|
|
208
|
+
```powershell
|
|
209
|
+
mercurykit repack ".\Output\blades-pics" --output ".\Pics.repacked.packed" --option layout=blades_of_fire --option archive_version=0x901
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
### Spacelords
|
|
213
|
+
|
|
214
|
+
Scan:
|
|
215
|
+
|
|
216
|
+
```powershell
|
|
217
|
+
mercurykit scan "D:\Steam\steamapps\common\Spacelords\Data00.packed"
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
Unpack:
|
|
221
|
+
|
|
222
|
+
```powershell
|
|
223
|
+
mercurykit unpack "D:\Steam\steamapps\common\Spacelords\Data00.packed" --dest ".\Output\spacelords-data"
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
Repack:
|
|
227
|
+
|
|
228
|
+
```powershell
|
|
229
|
+
mercurykit repack ".\Output\spacelords-data" --output ".\Data00.repacked.packed" --option layout=spacelords --option archive_version=0x502
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
Repack encrypted picture archives with the picture layout version:
|
|
233
|
+
|
|
234
|
+
```powershell
|
|
235
|
+
mercurykit repack ".\Output\spacelords-pics" --output ".\Pics.repacked.packed" --option layout=spacelords --option archive_version=0xd01
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
### Directory Scans
|
|
239
|
+
|
|
240
|
+
Scan a folder recursively and print detailed matches:
|
|
241
|
+
|
|
242
|
+
```powershell
|
|
243
|
+
mercurykit scan "D:\Steam\steamapps\common" --recursive --verbose
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
## CLI Reference
|
|
247
|
+
|
|
248
|
+
### `mercurykit scan`
|
|
249
|
+
|
|
250
|
+
```text
|
|
251
|
+
mercurykit scan PATH... [--recursive] [--verbose]
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
Scans files or directories for all supported archive types.
|
|
255
|
+
|
|
256
|
+
| Switch | Description |
|
|
257
|
+
| --- | --- |
|
|
258
|
+
| `PATH...` | One or more files or directories to scan. |
|
|
259
|
+
| `-r`, `--recursive` | Recursively scan directories. |
|
|
260
|
+
| `--verbose` | Print additional archive details, including match reasons and manifest summaries. |
|
|
261
|
+
|
|
262
|
+
Empty files are skipped. A scan of unsupported files reports that no compatible archive was found.
|
|
263
|
+
|
|
264
|
+
### `mercurykit unpack`
|
|
265
|
+
|
|
266
|
+
```text
|
|
267
|
+
mercurykit unpack FILE... [--dest PATH] [--overwrite] [--progress | --no-progress]
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
Extracts one or more supported archives.
|
|
271
|
+
|
|
272
|
+
| Switch | Description |
|
|
273
|
+
| --- | --- |
|
|
274
|
+
| `FILE...` | One or more archive files to unpack. |
|
|
275
|
+
| `--dest PATH` | Destination directory for extracted files. |
|
|
276
|
+
| `--overwrite` | Replace existing files in the destination. |
|
|
277
|
+
| `--progress` | Show progress even when stderr is not interactive. |
|
|
278
|
+
| `--no-progress` | Suppress progress output. |
|
|
279
|
+
|
|
280
|
+
When `--dest` is omitted, MercuryKit uses the command's default extraction behavior for the selected input.
|
|
281
|
+
|
|
282
|
+
### `mercurykit repack`
|
|
283
|
+
|
|
284
|
+
```text
|
|
285
|
+
mercurykit repack SOURCE_DIR --output OUTPUT [--option KEY=VALUE]... [--progress | --no-progress]
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
Builds an archive from a directory tree.
|
|
289
|
+
|
|
290
|
+
| Switch | Description |
|
|
291
|
+
| --- | --- |
|
|
292
|
+
| `SOURCE_DIR` | Directory containing the files to pack. |
|
|
293
|
+
| `--output OUTPUT` | Required output archive path. |
|
|
294
|
+
| `--option KEY=VALUE` | Repack option. May be repeated. |
|
|
295
|
+
| `--progress` | Show progress even when stderr is not interactive. |
|
|
296
|
+
| `--no-progress` | Suppress progress output. |
|
|
297
|
+
|
|
298
|
+
`--option` values accept strings, decimal integers, hexadecimal integers such as `0x901`, and booleans.
|
|
299
|
+
|
|
300
|
+
Mirror of Fate HD repacks are selected automatically when `--output` ends in `.pack` and no BFPK `layout` or `archive_version` option is supplied. Scrapland Remastered `.packed` repacks use `layout=scrapland`. Castlevania: Lords of Shadow - Ultimate Edition `.dat` repacks use `layout=lords_of_shadow_ultimate` with `archive_version=0x2` or `archive_version=0x3`. Other BFPK repacks use the options below.
|
|
301
|
+
|
|
302
|
+
## Repack Options
|
|
303
|
+
|
|
304
|
+
| Option | Description |
|
|
305
|
+
| --- | --- |
|
|
306
|
+
| `archive_version` | Required for most BFPK repacks, or optional validation for Scrapland. Examples include `0`, `0x2`, `0x3`, `0x100`, `0x102`, `0x500`, `0x502`, `0x901`, and `0xd01`. |
|
|
307
|
+
| `layout` | Archive layout. Supported values include `scrapland`, `legacy`, `lords_of_shadow_ultimate`, `blades_of_fire`, and `spacelords`. Defaults to `legacy`. |
|
|
308
|
+
| `file_chunk_size` | Positive chunk size used by chunked compressed archive versions. |
|
|
309
|
+
| `trailing_padding` | Non-negative number of padding bytes to append after archive data. |
|
|
310
|
+
| `compression_level` | zlib compression level for zlib-based repacks. Defaults to Python's zlib default. |
|
|
311
|
+
| `pack_size` | Mirror of Fate HD `.pack` payload-area size validation value. MercuryKit computes this during repack and fails if a supplied value does not match. |
|
|
312
|
+
|
|
313
|
+
Encrypted picture archive repacks preserve `opaque_hash` metadata for unchanged files when manifest metadata is available. New or changed entries receive a deterministic value; MercuryKit does not validate that field as a CRC.
|
|
314
|
+
|
|
315
|
+
Mirror of Fate HD repacks compute the `.pack` header fields automatically. The optional `pack_size` value is only a validation check; it is not required for normal repacks.
|
|
316
|
+
|
|
317
|
+
Castlevania: Lords of Shadow - Ultimate Edition `.dat` archives use AES-256-CBC encrypted file tables. MercuryKit decrypts those tables for scanning and unpacking, and writes new encrypted tables during repack.
|
|
318
|
+
|
|
319
|
+
Scrapland Remastered `.packed` repacks do not use compression, trailing padding, or sidecar metadata. Use `layout=scrapland`; `archive_version=0` may be supplied as a validation check.
|
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
<div align="center"><img src="https://raw.githubusercontent.com/Falkrian/MercuryKit/main/assets/mercurykit-banner.png" alt="MercuryKit" width="900"></div>
|
|
2
|
+
|
|
3
|
+
# MercuryKit
|
|
4
|
+
|
|
5
|
+
[](https://opensource.org/licenses/MIT)
|
|
6
|
+
[](https://twitter.com/FalkrianTTV)
|
|
7
|
+
|
|
8
|
+
[**Overview**](https://github.com/Falkrian/MercuryKit#overview)
|
|
9
|
+
| [**Features**](https://github.com/Falkrian/MercuryKit/#features)
|
|
10
|
+
| [**Supported Games**](https://github.com/Falkrian/MercuryKit/#supported-games)
|
|
11
|
+
| [**Installation**](https://github.com/Falkrian/MercuryKit/#installation)
|
|
12
|
+
| [**Quick Start**](https://github.com/Falkrian/MercuryKit#quick-start)
|
|
13
|
+
| [**CLI Reference**](https://github.com/Falkrian/MercuryKit/#cli-reference)
|
|
14
|
+
|
|
15
|
+
## Overview
|
|
16
|
+
|
|
17
|
+
MercuryKit is a Python package and command line toolkit for working with MercurySteam archive files. It can scan archives, unpack their contents safely, and repack edited directory trees back into archive form for supported game layouts.
|
|
18
|
+
|
|
19
|
+
## Features
|
|
20
|
+
|
|
21
|
+
- Scan individual files or whole directories for supported MercurySteam archives.
|
|
22
|
+
- Recursively scan directory trees and print verbose archive details when needed.
|
|
23
|
+
- Unpack archives with path safety checks to avoid writing outside the destination directory.
|
|
24
|
+
- Repack extracted folders back into supported archive versions.
|
|
25
|
+
- Preserve useful archive metadata, including encrypted picture archive table metadata.
|
|
26
|
+
- Support raw, zlib-compressed, LZ4-block-compressed, AES-encrypted table, and encrypted picture archive layouts.
|
|
27
|
+
- Show progress automatically on interactive terminals, with switches to force or suppress it.
|
|
28
|
+
- Use MercuryKit from Python through the public `mercurykit` package.
|
|
29
|
+
|
|
30
|
+
## Supported Games
|
|
31
|
+
|
|
32
|
+
| Game | Support | Support Comment |
|
|
33
|
+
| --- | --- | --- |
|
|
34
|
+
| Scrapland Remastered | Full | Supports raw `.packed` archives using BFPK version `0`, including scan, unpack, and directory-based repack with `cp1252` path encoding. |
|
|
35
|
+
| Castlevania: Lords of Shadow - Ultimate Edition | Full | Supports Steam `.dat` archives using AES-256-CBC encrypted file tables, including raw `0x2` and zlib-record `0x3` variants. |
|
|
36
|
+
| Castlevania: Lords of Shadow 2 | Full | Supports archive versions `0x100`, `0x101`, and `0x102`, including raw, zlib, and chunked zlib variants. |
|
|
37
|
+
| Castlevania Lords of Shadow - Mirror of Fate HD | Full | Supports `.pack` archives, including scan, unpack, directory-based repack, computed header fields, and automatic `system/files.toc` updates. |
|
|
38
|
+
| Blades of Fire | Full* | Supports archive versions `0x100`, `0x102`, `0x300`, and encrypted `Pics.packed` archives using `0x901`. JPG entries are preserved as packed payloads until the viewer-ready restoration transform is implemented. |
|
|
39
|
+
| Spacelords | Full | Supports archive versions `0x500`, `0x502`, and encrypted `Pics.packed` archives using `0xD01`, including LZ4-block variants. |
|
|
40
|
+
|
|
41
|
+
Blades of Fire `0x901` JPG entries are currently extracted as their original packed payloads. They are preserved for archive round trips, but the viewer-ready JPG restoration transform is still being researched.
|
|
42
|
+
|
|
43
|
+
## Installation
|
|
44
|
+
|
|
45
|
+
MercuryKit requires Python 3.11 or newer.
|
|
46
|
+
|
|
47
|
+
For local development or direct use from this checkout:
|
|
48
|
+
|
|
49
|
+
```powershell
|
|
50
|
+
python -m pip install -e .
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Install optional LZ4 support when working with archive versions that use LZ4-block compression:
|
|
54
|
+
|
|
55
|
+
```powershell
|
|
56
|
+
python -m pip install -e ".[lz4]"
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Quick Start
|
|
60
|
+
|
|
61
|
+
### Scrapland Remastered
|
|
62
|
+
|
|
63
|
+
Scan:
|
|
64
|
+
|
|
65
|
+
```powershell
|
|
66
|
+
mercurykit scan "D:\Steam\steamapps\common\Scrapland\data.packed" --verbose
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Unpack:
|
|
70
|
+
|
|
71
|
+
```powershell
|
|
72
|
+
mercurykit unpack "D:\Steam\steamapps\common\Scrapland\data.packed" --dest ".\Output\scrapland-data"
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Repack:
|
|
76
|
+
|
|
77
|
+
```powershell
|
|
78
|
+
mercurykit repack ".\Output\scrapland-data" --output ".\data.repacked.packed" --option layout=scrapland
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Scrapland `.packed` archives are raw containers. MercuryKit recalculates the table offsets during repack and writes paths using Windows-compatible `cp1252` encoding.
|
|
82
|
+
|
|
83
|
+
### Castlevania: Lords of Shadow - Ultimate Edition
|
|
84
|
+
|
|
85
|
+
Scan:
|
|
86
|
+
|
|
87
|
+
```powershell
|
|
88
|
+
mercurykit scan "D:\Steam\steamapps\common\CastlevaniaLoS\Data00.dat" --verbose
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Unpack:
|
|
92
|
+
|
|
93
|
+
```powershell
|
|
94
|
+
mercurykit unpack "D:\Steam\steamapps\common\CastlevaniaLoS\Data00.dat" --dest ".\Output\losue-data00"
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Repack a zlib-record `.dat` archive:
|
|
98
|
+
|
|
99
|
+
```powershell
|
|
100
|
+
mercurykit repack ".\Output\losue-data00" --output ".\Data00.repacked.dat" --option layout=lords_of_shadow_ultimate --option archive_version=0x3 --option compression_level=6
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Repack a raw `.dat` archive:
|
|
104
|
+
|
|
105
|
+
```powershell
|
|
106
|
+
mercurykit repack ".\Output\losue-data03" --output ".\Data03.repacked.dat" --option layout=lords_of_shadow_ultimate --option archive_version=0x2
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### Castlevania: Lords of Shadow 2
|
|
110
|
+
|
|
111
|
+
Scan:
|
|
112
|
+
|
|
113
|
+
```powershell
|
|
114
|
+
mercurykit scan "D:\Steam\steamapps\common\Castlevania Lords of Shadow 2\English.packed"
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
Unpack:
|
|
118
|
+
|
|
119
|
+
```powershell
|
|
120
|
+
mercurykit unpack "D:\Steam\steamapps\common\Castlevania Lords of Shadow 2\English.packed" --dest ".\Output\los2-english"
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Repack:
|
|
124
|
+
|
|
125
|
+
```powershell
|
|
126
|
+
mercurykit repack ".\Output\los2-english" --output ".\English.repacked" --option archive_version=0x102 --option file_chunk_size=262144 --option compression_level=6
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### Castlevania Lords of Shadow - Mirror of Fate HD
|
|
130
|
+
|
|
131
|
+
Scan:
|
|
132
|
+
|
|
133
|
+
```powershell
|
|
134
|
+
mercurykit scan "D:\Steam\steamapps\common\Castlevania Lords of Shadow - Mirror of Fate HD\data.pack" --verbose
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
Unpack:
|
|
138
|
+
|
|
139
|
+
```powershell
|
|
140
|
+
mercurykit unpack "D:\Steam\steamapps\common\Castlevania Lords of Shadow - Mirror of Fate HD\data.pack" --dest ".\Output\mofh-data"
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
Repack:
|
|
144
|
+
|
|
145
|
+
```powershell
|
|
146
|
+
mercurykit repack ".\Output\mofh-data" --output ".\data.repacked.pack"
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
Mirror of Fate HD `.pack` output automatically uses the Mirror of Fate HD repacker when no BFPK `layout` or `archive_version` option is supplied. If `system/files.toc` is present, MercuryKit updates its path-hash and file-size records in the repacked archive.
|
|
150
|
+
|
|
151
|
+
### Blades of Fire
|
|
152
|
+
|
|
153
|
+
Scan:
|
|
154
|
+
|
|
155
|
+
```powershell
|
|
156
|
+
mercurykit scan "D:\Steam\steamapps\common\Blades of Fire\Data00.packed"
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
Unpack:
|
|
160
|
+
|
|
161
|
+
```powershell
|
|
162
|
+
mercurykit unpack "D:\Steam\steamapps\common\Blades of Fire\Data00.packed" --dest ".\Output\blades-data" --overwrite
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
Repack:
|
|
166
|
+
|
|
167
|
+
```powershell
|
|
168
|
+
mercurykit repack ".\Output\blades-data" --output ".\Data00.repacked.packed" --option layout=blades_of_fire --option archive_version=0x102
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
Repack encrypted picture archives with the picture layout version:
|
|
172
|
+
|
|
173
|
+
```powershell
|
|
174
|
+
mercurykit repack ".\Output\blades-pics" --output ".\Pics.repacked.packed" --option layout=blades_of_fire --option archive_version=0x901
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### Spacelords
|
|
178
|
+
|
|
179
|
+
Scan:
|
|
180
|
+
|
|
181
|
+
```powershell
|
|
182
|
+
mercurykit scan "D:\Steam\steamapps\common\Spacelords\Data00.packed"
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
Unpack:
|
|
186
|
+
|
|
187
|
+
```powershell
|
|
188
|
+
mercurykit unpack "D:\Steam\steamapps\common\Spacelords\Data00.packed" --dest ".\Output\spacelords-data"
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
Repack:
|
|
192
|
+
|
|
193
|
+
```powershell
|
|
194
|
+
mercurykit repack ".\Output\spacelords-data" --output ".\Data00.repacked.packed" --option layout=spacelords --option archive_version=0x502
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
Repack encrypted picture archives with the picture layout version:
|
|
198
|
+
|
|
199
|
+
```powershell
|
|
200
|
+
mercurykit repack ".\Output\spacelords-pics" --output ".\Pics.repacked.packed" --option layout=spacelords --option archive_version=0xd01
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
### Directory Scans
|
|
204
|
+
|
|
205
|
+
Scan a folder recursively and print detailed matches:
|
|
206
|
+
|
|
207
|
+
```powershell
|
|
208
|
+
mercurykit scan "D:\Steam\steamapps\common" --recursive --verbose
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
## CLI Reference
|
|
212
|
+
|
|
213
|
+
### `mercurykit scan`
|
|
214
|
+
|
|
215
|
+
```text
|
|
216
|
+
mercurykit scan PATH... [--recursive] [--verbose]
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
Scans files or directories for all supported archive types.
|
|
220
|
+
|
|
221
|
+
| Switch | Description |
|
|
222
|
+
| --- | --- |
|
|
223
|
+
| `PATH...` | One or more files or directories to scan. |
|
|
224
|
+
| `-r`, `--recursive` | Recursively scan directories. |
|
|
225
|
+
| `--verbose` | Print additional archive details, including match reasons and manifest summaries. |
|
|
226
|
+
|
|
227
|
+
Empty files are skipped. A scan of unsupported files reports that no compatible archive was found.
|
|
228
|
+
|
|
229
|
+
### `mercurykit unpack`
|
|
230
|
+
|
|
231
|
+
```text
|
|
232
|
+
mercurykit unpack FILE... [--dest PATH] [--overwrite] [--progress | --no-progress]
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
Extracts one or more supported archives.
|
|
236
|
+
|
|
237
|
+
| Switch | Description |
|
|
238
|
+
| --- | --- |
|
|
239
|
+
| `FILE...` | One or more archive files to unpack. |
|
|
240
|
+
| `--dest PATH` | Destination directory for extracted files. |
|
|
241
|
+
| `--overwrite` | Replace existing files in the destination. |
|
|
242
|
+
| `--progress` | Show progress even when stderr is not interactive. |
|
|
243
|
+
| `--no-progress` | Suppress progress output. |
|
|
244
|
+
|
|
245
|
+
When `--dest` is omitted, MercuryKit uses the command's default extraction behavior for the selected input.
|
|
246
|
+
|
|
247
|
+
### `mercurykit repack`
|
|
248
|
+
|
|
249
|
+
```text
|
|
250
|
+
mercurykit repack SOURCE_DIR --output OUTPUT [--option KEY=VALUE]... [--progress | --no-progress]
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
Builds an archive from a directory tree.
|
|
254
|
+
|
|
255
|
+
| Switch | Description |
|
|
256
|
+
| --- | --- |
|
|
257
|
+
| `SOURCE_DIR` | Directory containing the files to pack. |
|
|
258
|
+
| `--output OUTPUT` | Required output archive path. |
|
|
259
|
+
| `--option KEY=VALUE` | Repack option. May be repeated. |
|
|
260
|
+
| `--progress` | Show progress even when stderr is not interactive. |
|
|
261
|
+
| `--no-progress` | Suppress progress output. |
|
|
262
|
+
|
|
263
|
+
`--option` values accept strings, decimal integers, hexadecimal integers such as `0x901`, and booleans.
|
|
264
|
+
|
|
265
|
+
Mirror of Fate HD repacks are selected automatically when `--output` ends in `.pack` and no BFPK `layout` or `archive_version` option is supplied. Scrapland Remastered `.packed` repacks use `layout=scrapland`. Castlevania: Lords of Shadow - Ultimate Edition `.dat` repacks use `layout=lords_of_shadow_ultimate` with `archive_version=0x2` or `archive_version=0x3`. Other BFPK repacks use the options below.
|
|
266
|
+
|
|
267
|
+
## Repack Options
|
|
268
|
+
|
|
269
|
+
| Option | Description |
|
|
270
|
+
| --- | --- |
|
|
271
|
+
| `archive_version` | Required for most BFPK repacks, or optional validation for Scrapland. Examples include `0`, `0x2`, `0x3`, `0x100`, `0x102`, `0x500`, `0x502`, `0x901`, and `0xd01`. |
|
|
272
|
+
| `layout` | Archive layout. Supported values include `scrapland`, `legacy`, `lords_of_shadow_ultimate`, `blades_of_fire`, and `spacelords`. Defaults to `legacy`. |
|
|
273
|
+
| `file_chunk_size` | Positive chunk size used by chunked compressed archive versions. |
|
|
274
|
+
| `trailing_padding` | Non-negative number of padding bytes to append after archive data. |
|
|
275
|
+
| `compression_level` | zlib compression level for zlib-based repacks. Defaults to Python's zlib default. |
|
|
276
|
+
| `pack_size` | Mirror of Fate HD `.pack` payload-area size validation value. MercuryKit computes this during repack and fails if a supplied value does not match. |
|
|
277
|
+
|
|
278
|
+
Encrypted picture archive repacks preserve `opaque_hash` metadata for unchanged files when manifest metadata is available. New or changed entries receive a deterministic value; MercuryKit does not validate that field as a CRC.
|
|
279
|
+
|
|
280
|
+
Mirror of Fate HD repacks compute the `.pack` header fields automatically. The optional `pack_size` value is only a validation check; it is not required for normal repacks.
|
|
281
|
+
|
|
282
|
+
Castlevania: Lords of Shadow - Ultimate Edition `.dat` archives use AES-256-CBC encrypted file tables. MercuryKit decrypts those tables for scanning and unpacking, and writes new encrypted tables during repack.
|
|
283
|
+
|
|
284
|
+
Scrapland Remastered `.packed` repacks do not use compression, trailing padding, or sidecar metadata. Use `layout=scrapland`; `archive_version=0` may be supplied as a validation check.
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=77"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "mercurykit"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "MercurySteam archive scanner, extractor, and repacker."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.11"
|
|
11
|
+
authors = [{ name = "MercuryKit Contributors" }]
|
|
12
|
+
license = "MIT"
|
|
13
|
+
license-files = ["LICENSE"]
|
|
14
|
+
keywords = ["mercurysteam", "archive", "bfpk", "castlevania", "scrapland", "spacelords", "modding"]
|
|
15
|
+
classifiers = [
|
|
16
|
+
"Development Status :: 3 - Alpha",
|
|
17
|
+
"Environment :: Console",
|
|
18
|
+
"Intended Audience :: Developers",
|
|
19
|
+
"Intended Audience :: End Users/Desktop",
|
|
20
|
+
"Operating System :: OS Independent",
|
|
21
|
+
"Programming Language :: Python :: 3",
|
|
22
|
+
"Programming Language :: Python :: 3.11",
|
|
23
|
+
"Programming Language :: Python :: 3.12",
|
|
24
|
+
"Programming Language :: Python :: 3.13",
|
|
25
|
+
"Topic :: Games/Entertainment",
|
|
26
|
+
"Topic :: System :: Archiving",
|
|
27
|
+
"Topic :: Utilities",
|
|
28
|
+
]
|
|
29
|
+
dependencies = ["cryptography>=42"]
|
|
30
|
+
|
|
31
|
+
[project.optional-dependencies]
|
|
32
|
+
lz4 = ["lz4>=4.3"]
|
|
33
|
+
dev = ["pytest>=8", "build>=1.2", "twine>=5", "readme-renderer[md]>=43"]
|
|
34
|
+
|
|
35
|
+
[project.urls]
|
|
36
|
+
Homepage = "https://github.com/Falkrian/MercuryKit"
|
|
37
|
+
Repository = "https://github.com/Falkrian/MercuryKit"
|
|
38
|
+
Issues = "https://github.com/Falkrian/MercuryKit/issues"
|
|
39
|
+
|
|
40
|
+
[project.scripts]
|
|
41
|
+
mercurykit = "mercurykit.cli:main"
|
|
42
|
+
|
|
43
|
+
[tool.setuptools.packages.find]
|
|
44
|
+
where = ["src"]
|
|
45
|
+
|
|
46
|
+
[tool.pytest.ini_options]
|
|
47
|
+
testpaths = ["tests"]
|
|
48
|
+
pythonpath = ["src"]
|