stardew-valley-data 0.3.0 → 0.4.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/CHANGELOG.md +6 -0
- package/README.md +6 -0
- package/dist/index.d.mts +17 -6
- package/dist/index.d.ts +17 -6
- package/dist/index.js +73 -9
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +73 -9
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project
|
|
6
6
|
adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [v0.4.0] - 2026-03-15
|
|
9
|
+
|
|
10
|
+
### Breaking Changes
|
|
11
|
+
|
|
12
|
+
- Change many of the output modules for parsing the file.
|
|
13
|
+
|
|
8
14
|
## [v0.3.0] - 2026-03-15
|
|
9
15
|
|
|
10
16
|
### Fix
|
package/README.md
CHANGED
|
@@ -12,6 +12,12 @@
|
|
|
12
12
|
|
|
13
13
|
---
|
|
14
14
|
|
|
15
|
+
> **Pre-1.0 Notice:** This package is under active development. Breaking changes to the save file
|
|
16
|
+
> parser structure, data types, and other APIs may occur in any release before `1.0.0`. Pin your
|
|
17
|
+
> version or review the [Change Log](CHANGELOG.md) before upgrading.
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
15
21
|
## 📦 Installation
|
|
16
22
|
|
|
17
23
|
```bash
|
package/dist/index.d.mts
CHANGED
|
@@ -2506,12 +2506,24 @@ interface SavePlayer {
|
|
|
2506
2506
|
totalMoneyEarned: number;
|
|
2507
2507
|
spouse: string | null;
|
|
2508
2508
|
houseUpgradeLevel: number;
|
|
2509
|
+
luckLevel: number;
|
|
2510
|
+
maxItems: number;
|
|
2509
2511
|
maxHealth: number;
|
|
2510
2512
|
maxStamina: number;
|
|
2511
2513
|
skills: SaveSkills;
|
|
2512
2514
|
mastery: SaveMastery;
|
|
2515
|
+
toolLevels: SaveToolLevels;
|
|
2513
2516
|
gameVersion: string;
|
|
2514
2517
|
}
|
|
2518
|
+
/** Upgrade levels for the player's tools (0 = base, 1 = copper, 2 = steel, 3 = gold, 4 = iridium). */
|
|
2519
|
+
interface SaveToolLevels {
|
|
2520
|
+
wateringCan: number;
|
|
2521
|
+
pan: number;
|
|
2522
|
+
pickaxe: number;
|
|
2523
|
+
axe: number;
|
|
2524
|
+
hoe: number;
|
|
2525
|
+
trashCan: number;
|
|
2526
|
+
}
|
|
2515
2527
|
/** Mastery system progress including XP, levels spent, and unlocked perks. */
|
|
2516
2528
|
interface SaveMastery {
|
|
2517
2529
|
xp: number;
|
|
@@ -2592,6 +2604,7 @@ interface SaveAnimal {
|
|
|
2592
2604
|
id: string;
|
|
2593
2605
|
name: string;
|
|
2594
2606
|
type: string;
|
|
2607
|
+
buildingId: string;
|
|
2595
2608
|
buildingType: string;
|
|
2596
2609
|
friendship: number;
|
|
2597
2610
|
happiness: number;
|
|
@@ -2600,9 +2613,8 @@ interface SaveAnimal {
|
|
|
2600
2613
|
}
|
|
2601
2614
|
/** A farm building with its type, position, and current animal count. */
|
|
2602
2615
|
interface SaveBuilding {
|
|
2616
|
+
id: string;
|
|
2603
2617
|
type: string;
|
|
2604
|
-
tileX: number;
|
|
2605
|
-
tileY: number;
|
|
2606
2618
|
animalCount: number;
|
|
2607
2619
|
}
|
|
2608
2620
|
/** An active or completed quest with its title, description, and completion status. */
|
|
@@ -2624,9 +2636,8 @@ interface SaveRecipeEntry {
|
|
|
2624
2636
|
name: string;
|
|
2625
2637
|
timesMade: number;
|
|
2626
2638
|
}
|
|
2627
|
-
/** Community Center bundle data including
|
|
2639
|
+
/** Community Center bundle data including rooms with nested bundles and Joja route status. */
|
|
2628
2640
|
interface SaveBundleData {
|
|
2629
|
-
bundles: SaveBundleStatus[];
|
|
2630
2641
|
rooms: SaveBundleRoom[];
|
|
2631
2642
|
isJojaRoute: boolean;
|
|
2632
2643
|
isCCComplete: boolean;
|
|
@@ -2640,9 +2651,9 @@ interface SaveBundleRoom {
|
|
|
2640
2651
|
}
|
|
2641
2652
|
/** A single bundle with its required items, completion progress, and reward. */
|
|
2642
2653
|
interface SaveBundleStatus {
|
|
2654
|
+
id: string;
|
|
2643
2655
|
bundleIndex: number;
|
|
2644
2656
|
name: string;
|
|
2645
|
-
room: string;
|
|
2646
2657
|
items: SaveBundleItem[];
|
|
2647
2658
|
itemsRequired: number;
|
|
2648
2659
|
itemsCompleted: number;
|
|
@@ -2678,7 +2689,6 @@ interface SaveProfession {
|
|
|
2678
2689
|
/** Completed special orders split by town board and Qi's Walnut Room. */
|
|
2679
2690
|
interface SaveSpecialOrders {
|
|
2680
2691
|
completed: string[];
|
|
2681
|
-
townCompleted: string[];
|
|
2682
2692
|
qiCompleted: string[];
|
|
2683
2693
|
}
|
|
2684
2694
|
/** Secret notes and journal scraps found, plus magnifying glass ownership. */
|
|
@@ -2686,6 +2696,7 @@ interface SaveSecretNotes {
|
|
|
2686
2696
|
notesFound: number[];
|
|
2687
2697
|
journalScrapsFound: number[];
|
|
2688
2698
|
hasMagnifyingGlass: boolean;
|
|
2699
|
+
hasSeenKrobus: boolean;
|
|
2689
2700
|
}
|
|
2690
2701
|
/** Golden walnut collection progress with total found and tracker entries. */
|
|
2691
2702
|
interface SaveWalnuts {
|
package/dist/index.d.ts
CHANGED
|
@@ -2506,12 +2506,24 @@ interface SavePlayer {
|
|
|
2506
2506
|
totalMoneyEarned: number;
|
|
2507
2507
|
spouse: string | null;
|
|
2508
2508
|
houseUpgradeLevel: number;
|
|
2509
|
+
luckLevel: number;
|
|
2510
|
+
maxItems: number;
|
|
2509
2511
|
maxHealth: number;
|
|
2510
2512
|
maxStamina: number;
|
|
2511
2513
|
skills: SaveSkills;
|
|
2512
2514
|
mastery: SaveMastery;
|
|
2515
|
+
toolLevels: SaveToolLevels;
|
|
2513
2516
|
gameVersion: string;
|
|
2514
2517
|
}
|
|
2518
|
+
/** Upgrade levels for the player's tools (0 = base, 1 = copper, 2 = steel, 3 = gold, 4 = iridium). */
|
|
2519
|
+
interface SaveToolLevels {
|
|
2520
|
+
wateringCan: number;
|
|
2521
|
+
pan: number;
|
|
2522
|
+
pickaxe: number;
|
|
2523
|
+
axe: number;
|
|
2524
|
+
hoe: number;
|
|
2525
|
+
trashCan: number;
|
|
2526
|
+
}
|
|
2515
2527
|
/** Mastery system progress including XP, levels spent, and unlocked perks. */
|
|
2516
2528
|
interface SaveMastery {
|
|
2517
2529
|
xp: number;
|
|
@@ -2592,6 +2604,7 @@ interface SaveAnimal {
|
|
|
2592
2604
|
id: string;
|
|
2593
2605
|
name: string;
|
|
2594
2606
|
type: string;
|
|
2607
|
+
buildingId: string;
|
|
2595
2608
|
buildingType: string;
|
|
2596
2609
|
friendship: number;
|
|
2597
2610
|
happiness: number;
|
|
@@ -2600,9 +2613,8 @@ interface SaveAnimal {
|
|
|
2600
2613
|
}
|
|
2601
2614
|
/** A farm building with its type, position, and current animal count. */
|
|
2602
2615
|
interface SaveBuilding {
|
|
2616
|
+
id: string;
|
|
2603
2617
|
type: string;
|
|
2604
|
-
tileX: number;
|
|
2605
|
-
tileY: number;
|
|
2606
2618
|
animalCount: number;
|
|
2607
2619
|
}
|
|
2608
2620
|
/** An active or completed quest with its title, description, and completion status. */
|
|
@@ -2624,9 +2636,8 @@ interface SaveRecipeEntry {
|
|
|
2624
2636
|
name: string;
|
|
2625
2637
|
timesMade: number;
|
|
2626
2638
|
}
|
|
2627
|
-
/** Community Center bundle data including
|
|
2639
|
+
/** Community Center bundle data including rooms with nested bundles and Joja route status. */
|
|
2628
2640
|
interface SaveBundleData {
|
|
2629
|
-
bundles: SaveBundleStatus[];
|
|
2630
2641
|
rooms: SaveBundleRoom[];
|
|
2631
2642
|
isJojaRoute: boolean;
|
|
2632
2643
|
isCCComplete: boolean;
|
|
@@ -2640,9 +2651,9 @@ interface SaveBundleRoom {
|
|
|
2640
2651
|
}
|
|
2641
2652
|
/** A single bundle with its required items, completion progress, and reward. */
|
|
2642
2653
|
interface SaveBundleStatus {
|
|
2654
|
+
id: string;
|
|
2643
2655
|
bundleIndex: number;
|
|
2644
2656
|
name: string;
|
|
2645
|
-
room: string;
|
|
2646
2657
|
items: SaveBundleItem[];
|
|
2647
2658
|
itemsRequired: number;
|
|
2648
2659
|
itemsCompleted: number;
|
|
@@ -2678,7 +2689,6 @@ interface SaveProfession {
|
|
|
2678
2689
|
/** Completed special orders split by town board and Qi's Walnut Room. */
|
|
2679
2690
|
interface SaveSpecialOrders {
|
|
2680
2691
|
completed: string[];
|
|
2681
|
-
townCompleted: string[];
|
|
2682
2692
|
qiCompleted: string[];
|
|
2683
2693
|
}
|
|
2684
2694
|
/** Secret notes and journal scraps found, plus magnifying glass ownership. */
|
|
@@ -2686,6 +2696,7 @@ interface SaveSecretNotes {
|
|
|
2686
2696
|
notesFound: number[];
|
|
2687
2697
|
journalScrapsFound: number[];
|
|
2688
2698
|
hasMagnifyingGlass: boolean;
|
|
2699
|
+
hasSeenKrobus: boolean;
|
|
2689
2700
|
}
|
|
2690
2701
|
/** Golden walnut collection progress with total found and tracker entries. */
|
|
2691
2702
|
interface SaveWalnuts {
|
package/dist/index.js
CHANGED
|
@@ -33376,6 +33376,7 @@ function parseAnimals(root) {
|
|
|
33376
33376
|
id: str(fa.myID),
|
|
33377
33377
|
name: str(fa.name),
|
|
33378
33378
|
type: str(fa.type),
|
|
33379
|
+
buildingId: str(b.id),
|
|
33379
33380
|
buildingType: str(fa.buildingTypeILiveIn),
|
|
33380
33381
|
friendship: num(fa.friendshipTowardFarmer),
|
|
33381
33382
|
happiness: num(fa.happiness),
|
|
@@ -33400,9 +33401,8 @@ function parseBuildings(root) {
|
|
|
33400
33401
|
for (const building of buildings2) {
|
|
33401
33402
|
const b = building;
|
|
33402
33403
|
result.push({
|
|
33404
|
+
id: str(b.id),
|
|
33403
33405
|
type: str(b.buildingType),
|
|
33404
|
-
tileX: num(b.tileX),
|
|
33405
|
-
tileY: num(b.tileY),
|
|
33406
33406
|
animalCount: num(b.currentOccupants)
|
|
33407
33407
|
});
|
|
33408
33408
|
}
|
|
@@ -33600,9 +33600,9 @@ function parseBundles(root, mail) {
|
|
|
33600
33600
|
});
|
|
33601
33601
|
const itemsCompleted = items.filter((it) => it.completed).length;
|
|
33602
33602
|
bundles2.push({
|
|
33603
|
+
id: `${def.room}/${index}`,
|
|
33603
33604
|
bundleIndex: index,
|
|
33604
33605
|
name: def.name,
|
|
33605
|
-
room: def.room,
|
|
33606
33606
|
items,
|
|
33607
33607
|
itemsRequired: def.itemsRequired,
|
|
33608
33608
|
itemsCompleted,
|
|
@@ -33630,7 +33630,7 @@ function parseBundles(root, mail) {
|
|
|
33630
33630
|
rooms.sort((a, b) => a.areaIndex - b.areaIndex);
|
|
33631
33631
|
const isJojaRoute = JOJA_MAIL_FLAGS.some((f) => mail.has(f));
|
|
33632
33632
|
const isCCComplete = mail.has("ccIsComplete");
|
|
33633
|
-
return {
|
|
33633
|
+
return { rooms, isJojaRoute, isCCComplete };
|
|
33634
33634
|
}
|
|
33635
33635
|
|
|
33636
33636
|
// src/save-file/parsers/v1/date.ts
|
|
@@ -33791,9 +33791,8 @@ function parseMail(mailReceived) {
|
|
|
33791
33791
|
}
|
|
33792
33792
|
function parseSpecialOrders(root) {
|
|
33793
33793
|
const completed = ensureArray(root.completedSpecialOrders?.string).map((m) => str(m)).filter(Boolean);
|
|
33794
|
-
const townCompleted = completed.filter((id) => !QI_ORDER_IDS.has(id));
|
|
33795
33794
|
const qiCompleted = completed.filter((id) => QI_ORDER_IDS.has(id));
|
|
33796
|
-
return { completed,
|
|
33795
|
+
return { completed, qiCompleted };
|
|
33797
33796
|
}
|
|
33798
33797
|
function parseBooksRead(player) {
|
|
33799
33798
|
const books = [];
|
|
@@ -33957,6 +33956,67 @@ function parseMastery(stats) {
|
|
|
33957
33956
|
perks
|
|
33958
33957
|
};
|
|
33959
33958
|
}
|
|
33959
|
+
var TOOL_TYPES = ["WateringCan", "Pan", "Pickaxe", "Axe", "Hoe"];
|
|
33960
|
+
var TOOL_KEY_MAP = {
|
|
33961
|
+
WateringCan: "wateringCan",
|
|
33962
|
+
Pan: "pan",
|
|
33963
|
+
Pickaxe: "pickaxe",
|
|
33964
|
+
Axe: "axe",
|
|
33965
|
+
Hoe: "hoe"
|
|
33966
|
+
};
|
|
33967
|
+
function collectToolItems(node, depth = 0) {
|
|
33968
|
+
if (!node || typeof node !== "object" || depth > 20) return [];
|
|
33969
|
+
const results = [];
|
|
33970
|
+
if (Array.isArray(node)) {
|
|
33971
|
+
for (const child of node) results.push(...collectToolItems(child, depth + 1));
|
|
33972
|
+
return results;
|
|
33973
|
+
}
|
|
33974
|
+
const obj = node;
|
|
33975
|
+
const xsiType = obj["@_xsi:type"] ?? obj["@_type"] ?? "";
|
|
33976
|
+
if (TOOL_TYPES.includes(xsiType)) {
|
|
33977
|
+
results.push(obj);
|
|
33978
|
+
}
|
|
33979
|
+
for (const key of [
|
|
33980
|
+
"Item",
|
|
33981
|
+
"items",
|
|
33982
|
+
"objects",
|
|
33983
|
+
"item",
|
|
33984
|
+
"Object",
|
|
33985
|
+
"value",
|
|
33986
|
+
"GameLocation",
|
|
33987
|
+
"Building",
|
|
33988
|
+
"buildings",
|
|
33989
|
+
"indoors",
|
|
33990
|
+
"heldObject"
|
|
33991
|
+
]) {
|
|
33992
|
+
if (obj[key]) results.push(...collectToolItems(obj[key], depth + 1));
|
|
33993
|
+
}
|
|
33994
|
+
return results;
|
|
33995
|
+
}
|
|
33996
|
+
function parseToolLevels(player, root) {
|
|
33997
|
+
const levels = {
|
|
33998
|
+
wateringCan: 0,
|
|
33999
|
+
pan: 0,
|
|
34000
|
+
pickaxe: 0,
|
|
34001
|
+
axe: 0,
|
|
34002
|
+
hoe: 0,
|
|
34003
|
+
trashCan: num(player.trashCanLevel)
|
|
34004
|
+
};
|
|
34005
|
+
const allItems2 = [
|
|
34006
|
+
...collectToolItems(player.items),
|
|
34007
|
+
...collectToolItems(root.locations?.GameLocation)
|
|
34008
|
+
];
|
|
34009
|
+
for (const item of allItems2) {
|
|
34010
|
+
const i = item;
|
|
34011
|
+
const xsiType = i["@_xsi:type"] ?? i["@_type"] ?? "";
|
|
34012
|
+
const key = TOOL_KEY_MAP[xsiType];
|
|
34013
|
+
if (key) {
|
|
34014
|
+
const level = num(i.upgradeLevel);
|
|
34015
|
+
if (level > levels[key]) levels[key] = level;
|
|
34016
|
+
}
|
|
34017
|
+
}
|
|
34018
|
+
return levels;
|
|
34019
|
+
}
|
|
33960
34020
|
function parsePlayer(player, root) {
|
|
33961
34021
|
return {
|
|
33962
34022
|
name: str(player.name),
|
|
@@ -33967,10 +34027,13 @@ function parsePlayer(player, root) {
|
|
|
33967
34027
|
totalMoneyEarned: num(player.totalMoneyEarned),
|
|
33968
34028
|
spouse: player.spouse ? str(player.spouse) : null,
|
|
33969
34029
|
houseUpgradeLevel: num(player.houseUpgradeLevel),
|
|
34030
|
+
luckLevel: num(player.luckLevel),
|
|
34031
|
+
maxItems: num(player.maxItems),
|
|
33970
34032
|
maxHealth: num(player.maxHealth),
|
|
33971
34033
|
maxStamina: num(player.maxStamina),
|
|
33972
34034
|
skills: parseSkills(player.experiencePoints?.int),
|
|
33973
34035
|
mastery: parseMastery(player.stats),
|
|
34036
|
+
toolLevels: parseToolLevels(player, root),
|
|
33974
34037
|
gameVersion: str(root.gameVersion)
|
|
33975
34038
|
};
|
|
33976
34039
|
}
|
|
@@ -34063,12 +34126,13 @@ function parseCraftingRecipes(data) {
|
|
|
34063
34126
|
}
|
|
34064
34127
|
|
|
34065
34128
|
// src/save-file/parsers/v1/secret-notes.ts
|
|
34066
|
-
function parseSecretNotes(player, mail) {
|
|
34129
|
+
function parseSecretNotes(player, mail, events2) {
|
|
34067
34130
|
const allNotes = ensureArray(player.secretNotesSeen?.int).map(num);
|
|
34068
34131
|
return {
|
|
34069
34132
|
notesFound: allNotes.filter((n) => n < 1e3),
|
|
34070
34133
|
journalScrapsFound: allNotes.filter((n) => n >= 1e3).map((n) => n - 1e3),
|
|
34071
|
-
hasMagnifyingGlass: mail.has("HasMagnifyingGlass") || player.hasMagnifyingGlass === true || player.hasMagnifyingGlass === "true"
|
|
34134
|
+
hasMagnifyingGlass: mail.has("HasMagnifyingGlass") || player.hasMagnifyingGlass === true || player.hasMagnifyingGlass === "true",
|
|
34135
|
+
hasSeenKrobus: events2.has("520702")
|
|
34072
34136
|
};
|
|
34073
34137
|
}
|
|
34074
34138
|
|
|
@@ -34162,7 +34226,7 @@ var v1 = (ctx) => ({
|
|
|
34162
34226
|
professions: parseProfessions(ctx.player.professions),
|
|
34163
34227
|
booksRead: parseBooksRead(ctx.player),
|
|
34164
34228
|
eventsSeen: ctx.eventsSeen,
|
|
34165
|
-
secretNotes: parseSecretNotes(ctx.player, ctx.mailSet),
|
|
34229
|
+
secretNotes: parseSecretNotes(ctx.player, ctx.mailSet, ctx.eventsSet),
|
|
34166
34230
|
walnuts: parseWalnuts(ctx.root),
|
|
34167
34231
|
islandUpgrades: parseIslandUpgrades(ctx.mailSet),
|
|
34168
34232
|
children: parseChildren(ctx.root),
|