@sattori/touhou-replay-parser 0.1.0
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/LICENSE +21 -0
- package/README.md +166 -0
- package/dist/byte-reader.d.ts +48 -0
- package/dist/byte-reader.d.ts.map +1 -0
- package/dist/byte-reader.js +129 -0
- package/dist/byte-reader.js.map +1 -0
- package/dist/errors.d.ts +10 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +13 -0
- package/dist/errors.js.map +1 -0
- package/dist/game-ids.d.ts +13 -0
- package/dist/game-ids.d.ts.map +1 -0
- package/dist/game-ids.js +56 -0
- package/dist/game-ids.js.map +1 -0
- package/dist/games/modern-body.d.ts +16 -0
- package/dist/games/modern-body.d.ts.map +1 -0
- package/dist/games/modern-body.js +21 -0
- package/dist/games/modern-body.js.map +1 -0
- package/dist/games/th06.d.ts +8 -0
- package/dist/games/th06.d.ts.map +1 -0
- package/dist/games/th06.js +85 -0
- package/dist/games/th06.js.map +1 -0
- package/dist/games/th07.d.ts +12 -0
- package/dist/games/th07.d.ts.map +1 -0
- package/dist/games/th07.js +138 -0
- package/dist/games/th07.js.map +1 -0
- package/dist/games/th08.d.ts +6 -0
- package/dist/games/th08.d.ts.map +1 -0
- package/dist/games/th08.js +118 -0
- package/dist/games/th08.js.map +1 -0
- package/dist/games/th09.d.ts +10 -0
- package/dist/games/th09.d.ts.map +1 -0
- package/dist/games/th09.js +110 -0
- package/dist/games/th09.js.map +1 -0
- package/dist/games/th095.d.ts +7 -0
- package/dist/games/th095.d.ts.map +1 -0
- package/dist/games/th095.js +39 -0
- package/dist/games/th095.js.map +1 -0
- package/dist/games/th10.d.ts +4 -0
- package/dist/games/th10.d.ts.map +1 -0
- package/dist/games/th10.js +50 -0
- package/dist/games/th10.js.map +1 -0
- package/dist/games/th11.d.ts +4 -0
- package/dist/games/th11.d.ts.map +1 -0
- package/dist/games/th11.js +49 -0
- package/dist/games/th11.js.map +1 -0
- package/dist/games/th12.d.ts +4 -0
- package/dist/games/th12.d.ts.map +1 -0
- package/dist/games/th12.js +58 -0
- package/dist/games/th12.js.map +1 -0
- package/dist/games/th125.d.ts +6 -0
- package/dist/games/th125.d.ts.map +1 -0
- package/dist/games/th125.js +39 -0
- package/dist/games/th125.js.map +1 -0
- package/dist/games/th128.d.ts +9 -0
- package/dist/games/th128.d.ts.map +1 -0
- package/dist/games/th128.js +79 -0
- package/dist/games/th128.js.map +1 -0
- package/dist/games/th13-14.d.ts +17 -0
- package/dist/games/th13-14.d.ts.map +1 -0
- package/dist/games/th13-14.js +110 -0
- package/dist/games/th13-14.js.map +1 -0
- package/dist/games/th143.d.ts +7 -0
- package/dist/games/th143.d.ts.map +1 -0
- package/dist/games/th143.js +39 -0
- package/dist/games/th143.js.map +1 -0
- package/dist/games/th15.d.ts +4 -0
- package/dist/games/th15.d.ts.map +1 -0
- package/dist/games/th15.js +49 -0
- package/dist/games/th15.js.map +1 -0
- package/dist/games/th16.d.ts +4 -0
- package/dist/games/th16.d.ts.map +1 -0
- package/dist/games/th16.js +51 -0
- package/dist/games/th16.js.map +1 -0
- package/dist/games/th17.d.ts +4 -0
- package/dist/games/th17.d.ts.map +1 -0
- package/dist/games/th17.js +49 -0
- package/dist/games/th17.js.map +1 -0
- package/dist/games/th18.d.ts +4 -0
- package/dist/games/th18.d.ts.map +1 -0
- package/dist/games/th18.js +58 -0
- package/dist/games/th18.js.map +1 -0
- package/dist/games/th20.d.ts +22 -0
- package/dist/games/th20.d.ts.map +1 -0
- package/dist/games/th20.js +41 -0
- package/dist/games/th20.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +70 -0
- package/dist/index.js.map +1 -0
- package/dist/lzss.d.ts +16 -0
- package/dist/lzss.d.ts.map +1 -0
- package/dist/lzss.js +147 -0
- package/dist/lzss.js.map +1 -0
- package/dist/types.d.ts +125 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +22 -0
- package/dist/types.js.map +1 -0
- package/dist/userdata.d.ts +24 -0
- package/dist/userdata.d.ts.map +1 -0
- package/dist/userdata.js +52 -0
- package/dist/userdata.js.map +1 -0
- package/package.json +41 -0
package/dist/userdata.js
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { ByteReader } from "./byte-reader.js";
|
|
2
|
+
import { ReplayCorruptError } from "./errors.js";
|
|
3
|
+
const USER_MAGIC = [0x55, 0x53, 0x45, 0x52]; // "USER"
|
|
4
|
+
/**
|
|
5
|
+
* Equivalent to JumpToUser in threplay. Reads the 4-byte offset value at
|
|
6
|
+
* `pointerFieldOffset`, confirms a "USER" marker exists at that position, and
|
|
7
|
+
* then advances the cursor just past it.
|
|
8
|
+
*/
|
|
9
|
+
export function jumpToUser(reader, pointerFieldOffset) {
|
|
10
|
+
reader.seek(pointerFieldOffset);
|
|
11
|
+
const offset = reader.readUint32LE();
|
|
12
|
+
reader.seek(offset);
|
|
13
|
+
const magic = reader.readBytes(4);
|
|
14
|
+
if (!USER_MAGIC.every((b, i) => magic[i] === b)) {
|
|
15
|
+
throw new ReplayCorruptError(`USER section marker not found at offset ${offset}`);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
/** Equivalent to `long.TryParse(text + "0", ...)`. Restores the omitted trailing digit before converting to a number. */
|
|
19
|
+
export function parseScoreWithTrailingZero(text) {
|
|
20
|
+
return parseIntStrict(`${text}0`);
|
|
21
|
+
}
|
|
22
|
+
export function parseIntStrict(text) {
|
|
23
|
+
const trimmed = text.trim();
|
|
24
|
+
if (!/^-?\d+$/.test(trimmed))
|
|
25
|
+
return null;
|
|
26
|
+
const value = Number(trimmed);
|
|
27
|
+
return Number.isFinite(value) ? value : null;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* The USER section layout shared by th10 (東方風神録, MoF) through
|
|
31
|
+
* th18 (東方虹龍洞, UM) (ported from threplay's `Read_Userdata`).
|
|
32
|
+
*/
|
|
33
|
+
export function readModernUserdata(reader) {
|
|
34
|
+
jumpToUser(reader, 12);
|
|
35
|
+
reader.readUint32LE(); // USER section length (unused)
|
|
36
|
+
reader.skip(4);
|
|
37
|
+
reader.readAnsiString(); // e.g. "東方○○ リプレイファイル情報" ("Touhou XX Replay File Info", SJIS)
|
|
38
|
+
reader.readAnsiString(); // game version string (unused)
|
|
39
|
+
reader.skip(5);
|
|
40
|
+
const name = reader.readAnsiString();
|
|
41
|
+
reader.skip(5);
|
|
42
|
+
const date = reader.readAnsiString();
|
|
43
|
+
reader.skip(6);
|
|
44
|
+
const character = reader.readAnsiString();
|
|
45
|
+
reader.skip(5);
|
|
46
|
+
const difficulty = reader.readAnsiString();
|
|
47
|
+
const stage = reader.readAnsiString();
|
|
48
|
+
reader.skip(6);
|
|
49
|
+
const score = parseScoreWithTrailingZero(reader.readAnsiString());
|
|
50
|
+
return { name, date, character, difficulty, stage, score };
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=userdata.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"userdata.js","sourceRoot":"","sources":["../src/userdata.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAEjD,MAAM,UAAU,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,SAAS;AAEtD;;;;GAIG;AACH,MAAM,UAAU,UAAU,CAAC,MAAkB,EAAE,kBAA0B;IACvE,MAAM,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;IAChC,MAAM,MAAM,GAAG,MAAM,CAAC,YAAY,EAAE,CAAC;IACrC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACpB,MAAM,KAAK,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;IAClC,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC;QAChD,MAAM,IAAI,kBAAkB,CAAC,2CAA2C,MAAM,EAAE,CAAC,CAAC;IACpF,CAAC;AACH,CAAC;AAED,yHAAyH;AACzH,MAAM,UAAU,0BAA0B,CAAC,IAAY;IACrD,OAAO,cAAc,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC;AACpC,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,IAAY;IACzC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;IAC5B,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC;QAAE,OAAO,IAAI,CAAC;IAC1C,MAAM,KAAK,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC;IAC9B,OAAO,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;AAC/C,CAAC;AAWD;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAAC,MAAkB;IACnD,UAAU,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IACvB,MAAM,CAAC,YAAY,EAAE,CAAC,CAAC,+BAA+B;IACtD,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACf,MAAM,CAAC,cAAc,EAAE,CAAC,CAAC,8DAA8D;IACvF,MAAM,CAAC,cAAc,EAAE,CAAC,CAAC,+BAA+B;IACxD,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACf,MAAM,IAAI,GAAG,MAAM,CAAC,cAAc,EAAE,CAAC;IACrC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACf,MAAM,IAAI,GAAG,MAAM,CAAC,cAAc,EAAE,CAAC;IACrC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACf,MAAM,SAAS,GAAG,MAAM,CAAC,cAAc,EAAE,CAAC;IAC1C,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACf,MAAM,UAAU,GAAG,MAAM,CAAC,cAAc,EAAE,CAAC;IAC3C,MAAM,KAAK,GAAG,MAAM,CAAC,cAAc,EAAE,CAAC;IACtC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACf,MAAM,KAAK,GAAG,0BAA0B,CAAC,MAAM,CAAC,cAAc,EAAE,CAAC,CAAC;IAClE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,UAAU,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;AAC7D,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@sattori/touhou-replay-parser",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Decoder for Touhou Project replay files (.rpy), covering th06 through th20. Zero runtime dependencies.",
|
|
5
|
+
"keywords": ["touhou", "replay", "rpy", "parser", "decoder"],
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"author": "Koki Takahashi",
|
|
8
|
+
"homepage": "https://github.com/hakatashi/sattori/tree/main/packages/replay-parser#readme",
|
|
9
|
+
"bugs": "https://github.com/hakatashi/sattori/issues",
|
|
10
|
+
"repository": {
|
|
11
|
+
"type": "git",
|
|
12
|
+
"url": "git+https://github.com/hakatashi/sattori.git",
|
|
13
|
+
"directory": "packages/replay-parser"
|
|
14
|
+
},
|
|
15
|
+
"type": "module",
|
|
16
|
+
"engines": {
|
|
17
|
+
"node": ">=14"
|
|
18
|
+
},
|
|
19
|
+
"publishConfig": {
|
|
20
|
+
"access": "public"
|
|
21
|
+
},
|
|
22
|
+
"exports": {
|
|
23
|
+
".": {
|
|
24
|
+
"types": "./dist/index.d.ts",
|
|
25
|
+
"default": "./dist/index.js"
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
"main": "./dist/index.js",
|
|
29
|
+
"types": "./dist/index.d.ts",
|
|
30
|
+
"files": ["dist"],
|
|
31
|
+
"scripts": {
|
|
32
|
+
"build": "tsc -p tsconfig.json",
|
|
33
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
34
|
+
"test": "vitest run"
|
|
35
|
+
},
|
|
36
|
+
"devDependencies": {
|
|
37
|
+
"@types/node": "^24.0.0",
|
|
38
|
+
"typescript": "^7.0.2",
|
|
39
|
+
"vitest": "^4.1.10"
|
|
40
|
+
}
|
|
41
|
+
}
|