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 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 all bundles, room summaries, and Joja route status. */
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 all bundles, room summaries, and Joja route status. */
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 { bundles: bundles2, rooms, isJojaRoute, isCCComplete };
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, townCompleted, qiCompleted };
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),