@zebbedaja/er-save-parser 0.1.1 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -0
- package/dist/index.d.mts +14 -2
- package/dist/index.mjs +49 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -33,8 +33,14 @@ import { parse, type Save, type Slot, type Character } from '@zebbedaja/er-save-
|
|
|
33
33
|
import { readFileSync } from 'fs'
|
|
34
34
|
|
|
35
35
|
const buffer = readFileSync('ER0000.sl2').buffer
|
|
36
|
+
|
|
37
|
+
// Default: only errors are logged (logLevel: 'error')
|
|
36
38
|
const save: Save = parse(buffer)
|
|
37
39
|
|
|
40
|
+
// Optional: configure logging with one of 'debug', 'info', 'warn', 'error', 'none'
|
|
41
|
+
// const save: Save = parse(buffer, { logLevel: 'debug' }) // Verbose progress logs
|
|
42
|
+
// const save: Save = parse(buffer, { logLevel: 'none' }) // Silent
|
|
43
|
+
|
|
38
44
|
console.log(save.steamId)
|
|
39
45
|
console.log(save.settings?.hud)
|
|
40
46
|
|
|
@@ -65,8 +71,14 @@ import { parse } from '@zebbedaja/er-save-parser'
|
|
|
65
71
|
import { readFileSync } from 'node:fs'
|
|
66
72
|
|
|
67
73
|
const buffer = readFileSync('ER0000.sl2').buffer
|
|
74
|
+
|
|
75
|
+
// Default: only errors are logged (logLevel: 'error')
|
|
68
76
|
const save = parse(buffer)
|
|
69
77
|
|
|
78
|
+
// Optional: configure logging with one of 'debug', 'info', 'warn', 'error', 'none'
|
|
79
|
+
// const save = parse(buffer, { logLevel: 'debug' }) // Verbose progress logs
|
|
80
|
+
// const save = parse(buffer, { logLevel: 'none' }) // Silent
|
|
81
|
+
|
|
70
82
|
console.log(save.steamId)
|
|
71
83
|
console.log(save.settings?.hud)
|
|
72
84
|
|
package/dist/index.d.mts
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
//#region src/types.d.ts
|
|
2
|
+
type LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'none';
|
|
3
|
+
interface ParseOptions {
|
|
4
|
+
logLevel?: LogLevel;
|
|
5
|
+
}
|
|
2
6
|
interface Save {
|
|
3
7
|
magicBytes?: string;
|
|
4
8
|
checksum?: string;
|
|
@@ -139,6 +143,14 @@ interface EventFlag {
|
|
|
139
143
|
}
|
|
140
144
|
//#endregion
|
|
141
145
|
//#region src/parser.d.ts
|
|
142
|
-
|
|
146
|
+
/**
|
|
147
|
+
* Parse an Elden Ring save file buffer.
|
|
148
|
+
*
|
|
149
|
+
* @param buffer - The ArrayBuffer containing the save file data
|
|
150
|
+
* @param options - Optional configuration for parsing
|
|
151
|
+
* @param options.logLevel - Log level threshold: 'debug', 'info', 'warn', 'error', or 'none'. Defaults to 'error'
|
|
152
|
+
* @returns A Save object containing parsed slot and profile data
|
|
153
|
+
*/
|
|
154
|
+
declare function parse(buffer: ArrayBuffer, options?: ParseOptions): Save;
|
|
143
155
|
//#endregion
|
|
144
|
-
export { type Character, type EventFlag, type ProfileSummary, type Save, type Settings, type Slot, parse };
|
|
156
|
+
export { type Character, type EventFlag, type LogLevel, type ParseOptions, type ProfileSummary, type Save, type Settings, type Slot, parse };
|
package/dist/index.mjs
CHANGED
|
@@ -6540,6 +6540,38 @@ const eventFlags = [
|
|
|
6540
6540
|
}
|
|
6541
6541
|
];
|
|
6542
6542
|
//#endregion
|
|
6543
|
+
//#region src/logger.ts
|
|
6544
|
+
const levelValues = {
|
|
6545
|
+
debug: 0,
|
|
6546
|
+
info: 1,
|
|
6547
|
+
warn: 2,
|
|
6548
|
+
error: 3,
|
|
6549
|
+
none: 4
|
|
6550
|
+
};
|
|
6551
|
+
/**
|
|
6552
|
+
* Factory for creating a logger instance with the specified log level threshold.
|
|
6553
|
+
*
|
|
6554
|
+
* @param level - The minimum log level to output. Defaults to 'error'
|
|
6555
|
+
* @returns A logger object with debug, info, warn, and error methods
|
|
6556
|
+
*/
|
|
6557
|
+
function createLogger(level = "error") {
|
|
6558
|
+
const threshold = levelValues[level];
|
|
6559
|
+
return {
|
|
6560
|
+
debug: (msg) => {
|
|
6561
|
+
if (levelValues.debug >= threshold) console.log(`[DEBUG] ${msg}`);
|
|
6562
|
+
},
|
|
6563
|
+
info: (msg) => {
|
|
6564
|
+
if (levelValues.info >= threshold) console.log(`[INFO] ${msg}`);
|
|
6565
|
+
},
|
|
6566
|
+
warn: (msg) => {
|
|
6567
|
+
if (levelValues.warn >= threshold) console.warn(`[WARN] ${msg}`);
|
|
6568
|
+
},
|
|
6569
|
+
error: (msg) => {
|
|
6570
|
+
if (levelValues.error >= threshold) console.error(`[ERROR] ${msg}`);
|
|
6571
|
+
}
|
|
6572
|
+
};
|
|
6573
|
+
}
|
|
6574
|
+
//#endregion
|
|
6543
6575
|
//#region src/bst-map.ts
|
|
6544
6576
|
const bstFile = `1045540,6223
|
|
6545
6577
|
1037495,3951
|
|
@@ -18466,7 +18498,16 @@ const bstFile = `1045540,6223
|
|
|
18466
18498
|
const USER_10_DATA_START = 26215328;
|
|
18467
18499
|
const ACTIVE_PROFILES_START = 26221828;
|
|
18468
18500
|
const SLOT_COUNT = 10;
|
|
18469
|
-
|
|
18501
|
+
/**
|
|
18502
|
+
* Parse an Elden Ring save file buffer.
|
|
18503
|
+
*
|
|
18504
|
+
* @param buffer - The ArrayBuffer containing the save file data
|
|
18505
|
+
* @param options - Optional configuration for parsing
|
|
18506
|
+
* @param options.logLevel - Log level threshold: 'debug', 'info', 'warn', 'error', or 'none'. Defaults to 'error'
|
|
18507
|
+
* @returns A Save object containing parsed slot and profile data
|
|
18508
|
+
*/
|
|
18509
|
+
function parse(buffer, options = { logLevel: "error" }) {
|
|
18510
|
+
const logger = createLogger(options.logLevel);
|
|
18470
18511
|
const dataView = new DataView(buffer);
|
|
18471
18512
|
const utf16leDecoder = new TextDecoder("utf-16le");
|
|
18472
18513
|
const utf8Decoder = new TextDecoder("utf-8");
|
|
@@ -18479,6 +18520,7 @@ function parse(buffer) {
|
|
|
18479
18520
|
offset += 764;
|
|
18480
18521
|
save.slots = [];
|
|
18481
18522
|
for (let i = 0; i < SLOT_COUNT; i++) {
|
|
18523
|
+
logger.debug(`Parsing slot ${i}`);
|
|
18482
18524
|
offset = 768 + i * 2621456;
|
|
18483
18525
|
const slot = {};
|
|
18484
18526
|
slot.checksum = toHexString(buffer.slice(offset, offset + 16));
|
|
@@ -18488,6 +18530,7 @@ function parse(buffer) {
|
|
|
18488
18530
|
slot.mapId = toHexString(buffer.slice(offset, offset + 4));
|
|
18489
18531
|
offset += 4;
|
|
18490
18532
|
offset += 24;
|
|
18533
|
+
logger.debug(`Reading GaItems for slot ${i}`);
|
|
18491
18534
|
for (let i = 0; i < 5120; i++) {
|
|
18492
18535
|
const gaitemHandle = dataView.getUint32(offset, true);
|
|
18493
18536
|
offset += 4;
|
|
@@ -18498,6 +18541,7 @@ function parse(buffer) {
|
|
|
18498
18541
|
if (gaitemHandleType === 2147483648) offset += 5;
|
|
18499
18542
|
}
|
|
18500
18543
|
}
|
|
18544
|
+
logger.debug(`Reading character data for slot ${i}`);
|
|
18501
18545
|
slot.character = {};
|
|
18502
18546
|
slot.character.unk0x0 = dataView.getUint32(offset, true);
|
|
18503
18547
|
offset += 4;
|
|
@@ -18651,6 +18695,7 @@ function parse(buffer) {
|
|
|
18651
18695
|
slot.inGameCountdownTimer = dataView.getUint32(offset, true);
|
|
18652
18696
|
offset += 4;
|
|
18653
18697
|
offset += 4;
|
|
18698
|
+
logger.debug(`Reading event flags for slot ${i} with offset ${offset}`);
|
|
18654
18699
|
const eventFlagUint8Array = new Uint8Array(buffer, offset, 1833375);
|
|
18655
18700
|
const bstMap = parseToMap(bstFile);
|
|
18656
18701
|
const slotEventFlags = [];
|
|
@@ -18663,6 +18708,7 @@ function parse(buffer) {
|
|
|
18663
18708
|
offset += 1833375;
|
|
18664
18709
|
save.slots?.push(slot);
|
|
18665
18710
|
}
|
|
18711
|
+
logger.debug("Reading User_10 data");
|
|
18666
18712
|
offset = USER_10_DATA_START;
|
|
18667
18713
|
save.checksum = toHexString(buffer.slice(offset, offset + 16));
|
|
18668
18714
|
offset += 16;
|
|
@@ -18670,6 +18716,7 @@ function parse(buffer) {
|
|
|
18670
18716
|
offset += 4;
|
|
18671
18717
|
save.steamId = dataView.getBigUint64(offset, true).toString();
|
|
18672
18718
|
offset += 8;
|
|
18719
|
+
logger.debug("Reading settings");
|
|
18673
18720
|
save.settings = {};
|
|
18674
18721
|
save.settings.cameraSpeed = dataView.getUint8(offset++);
|
|
18675
18722
|
save.settings.controllerVibration = dataView.getUint8(offset++);
|
|
@@ -18709,6 +18756,7 @@ function parse(buffer) {
|
|
|
18709
18756
|
save.settings.show_recent_tabs = dataView.getUint8(offset++);
|
|
18710
18757
|
offset = ACTIVE_PROFILES_START;
|
|
18711
18758
|
save.activeProfiles = Array.from({ length: SLOT_COUNT }, () => dataView.getUint8(offset++));
|
|
18759
|
+
logger.debug("Reading profile summaries");
|
|
18712
18760
|
save.profileSummaries = [];
|
|
18713
18761
|
for (let i = 0; i < SLOT_COUNT; i++) {
|
|
18714
18762
|
const profileSummary = {};
|