SMAPI icon indicating copy to clipboard operation
SMAPI copied to clipboard

SMAPI generates broken saves with bundle translations; when using mod translations

Open MysticTempest opened this issue 3 years ago • 11 comments

Describe the bug Per the title, SMAPI is once again generating saves with bundle translations; when using modded translations. And, it causes issues when reading the golden scrolls.

Discovered in this discussion: https://forums.stardewvalley.net/threads/translating-bundles-file.9708/ Dnksh, is creating a Polish translation mod that overwrites the Portuguese files via Content Patcher. And, anytime you create a new save in the modded language; is where it appends the translations to the <bundleData> section of the savefile.

The Polish translation mod, log, saves; and some code snippet examples are in the linked thread above.

To Reproduce Exact steps which reproduce the bug.

  1. Have SMAPI & Content Patcher.
  2. Install Dnksh's Polish translation mod: https://forums.stardewvalley.net/threads/translating-bundles-file.9708/post-57837
  3. Load SDV, and switch to the "Polski" language.
  4. Create a new save.
  5. You should be able to open up the save, & see the translations that were added to the <bundleData> section of the save.

Log file Dnksh's log: https://smapi.io/log/00f24201ebf34b02a698847772b349e0

MysticTempest avatar Nov 24 '21 17:11 MysticTempest

tl;dr: I'm tentatively targeting SMAPI 3.14.0 for a fix. See below for the details and why I'm not doing it in 3.12.9 or 3.13.0.

Problem

That's a fundamental issue with how the content pipeline works.

The game expects to be able to do this:

// read translated bundles from Data/Bundles.pt-BR.xnb
contentManager.Load<…>("Data/Bundles")

// read default bundles from Data/Bundles.xnb
contentManager.LoadBase<…>("Data/Bundles")

The way that normally works is like this:

                           localized                      XNA
                            content                     content
game                        manager                     manager
----                       ---------                    -------
  |                           |                            |
  | Load("Data/Bundles")      |                            |
  |-------------------------> | Load("Data/Bundles.pt-BR") |
  |                           |--------------------------> | read Data/Bundles.pt-BR.xnb
  |                           |                            |----------------------------,
  |                           |                            |<---------------------------'
  |                           |                            |  cache Data/Bundles.pt-BR
  |                           |<---------------------------|
  |<--------------------------|                         OK
  |                        OK 


  | LoadBase("Data/Bundles")
  | ------------------------->| Load("Data/Bundles")
  |                           |--------------------------->| read Data/Bundles.xnb
  |                           |                            |----------------------,
  |                           |                            |<---------------------'
  |                           |                            | cache Data/Bundles
  |                           |<---------------------------|
  |<--------------------------|                          OK
  |                         OK

That works because in the second flow, Data/Bundles wasn't cached yet (the first flow cached Data/Bundles.pt-BR instead).

That assumption breaks when a SMAPI mod (like Content Patcher) provided the asset in the first flow. In that case there's no distinction between Data/Bundles.pt-BR.xnb and Data/Bundles.xnb, because it never got that far; the game requested Data/Bundles and received the version provided by the mod:

                             SMAPI                      
                            content                     Content
game                        manager                     Patcher
----                       ---------                    -------
  |                           |                            |
  | Load("Data/Bundles")      |                            |
  |-------------------------> | Load("Data/Bundles")       |
  |                           |--------------------------> | read assets/some-file.json
  |                           |                            |---------------------------,
  |                           |                            |<--------------------------'
  |                           |<---------------------------|
  |<--------------------------| cache Data/Bundles
  |                        OK 


  | LoadBase("Data/Bundles")
  | ------------------------->| Load("Data/Bundles")
  |                           |---------------------,
  |                           |<--------------------'
  |                           | already cached
  |<--------------------------|
  |                         OK

So when the game tries to load Data/Bundles without a language suffix, it's already cached with the (potentially translated) data provided by the mod.

Solution

The solution is for SMAPI to always cache assets based on the locale they were requested for in other languages. So if the game requests Load("Portraits/Abigail"), it'll be cached internally as Portraits/Abigail.pt-BR; if it then requests LoadBase("Portraits/Abigail"), it'll load a fresh copy and cache it as Portraits/Abigail.

Timeline

I'm tentatively targeting SMAPI 3.14.0 for this change, the first major update after the one for Stardew Valley 1.5.5.

The content pipeline has a lot of moving parts that depend on this particular logic, so there's a solid chance of regressions and side-effects. With Stardew Valley 1.5.5 expected within weeks, it would be difficult to untangle whether a particular issue was caused by the game changes, the SMAPI changes for them, the mod changes for both of those, or the content pipeline change.

Pathoschild avatar Nov 25 '21 03:11 Pathoschild

Another option might be to intercept assets one step lower as part of the content API redesign (#766), so mods could intercept Data/Bundles.pt-BR or Data/Bundles. That would be a major departure from the current design, but it would also align better with the way new modders intuitively expect it to work.

Pathoschild avatar Nov 25 '21 03:11 Pathoschild

Thanks for the thorough explanation! That helps, a lot.

So, it looks like as a temporary workaround for this case. We can at least use the Content Patcher token; "HasFlag": "canReadJunimoText", to delay loading the bundle translations until after the save is created. Bypassing the caching bug you referred to, and letting us generate a working save.

MysticTempest avatar Nov 25 '21 08:11 MysticTempest

The game sets the unlocalized bundles at two points: when creating the save and when loading it. So you'd need a condition that only becomes true after the save is loaded (maybe something like "Time |contains=0600": false?). We'd have to test whether that works and whether the bundle translations are shown though.

Pathoschild avatar Nov 26 '21 01:11 Pathoschild

Not sure if this is related, but there is a crash happening in our game (steam beta version) we started a few days back very similar to what is described here:

https://smapi.io/log/b88d9ef420f8454b806870779c168238

This happens, if any of the players (in the two-player game) tries to access a community center vault for the first time after Lewis opened the entrance.

Originally the game had its language set to German and the mods as listed in the log above enabled. Changing the language to English, verifying the files and/or disabling the mods did not prevent the game from crashing.

Hope it helps!

cduta avatar Nov 26 '21 15:11 cduta

The game sets the unlocalized bundles at two points: when creating the save and when loading it. So you'd need a condition that only becomes true after the save is loaded (maybe something like "Time |contains=0600": false?). We'd have to test whether that works and whether the bundle translations are shown though.

I tried the Time token. It generated a working save, but the translations weren't properly applied.

It looks like the "canReadJunimoText" flag works the best to generate a working save & apply the translations. Though, it does take a manual reload of the save after the user has acquired it; to fully work.

But, still a good workaround for now.


Not sure if this is related, but there is a crash happening in our game (steam beta version) we started a few days back very similar to what is described here:

https://smapi.io/log/b88d9ef420f8454b806870779c168238

This happens, if any of the players (in the two-player game) tries to access a community center vault for the first time after Lewis opened the entrance.

Originally the game had its language set to German and the mods as listed in the log above enabled. Changing the language to English, verifying the files and/or disabling the mods did not prevent the game from crashing.

Hope it helps!

Yea, seems to be the same core bug; with the same error. You're playing in German, and a mod also intercepted the Bundle data.

18:05:58 | TRACE | SMAPI | TehCore edited Data/Bundles.

MysticTempest avatar Nov 30 '21 15:11 MysticTempest

The content API rewrite needed to fix this is in progress, with the first changes coming in SMAPI 3.14.0.

Pathoschild avatar Mar 04 '22 02:03 Pathoschild

The new content API is feature-complete in the upcoming SMAPI 3.14.0. Once that's released, the upcoming Content Patcher 2.0.0 will migrate to the new content API, and then only a small change will be needed in affected content packs to fix this.

Pathoschild avatar Mar 26 '22 19:03 Pathoschild

This is now fixed in the upcoming Stardew Valley 1.6 too, which changes how bundle data is managed so the issue no longer happens.

Pathoschild avatar Oct 14 '22 20:10 Pathoschild

Sorry, same problem here (start sliding after clicking the gold scroll) in game( version 1.5.6) smapi's cmd line keeps repeating this log as follows BundlesBugs.txt

Cheers414 avatar Dec 30 '22 11:12 Cheers414

@TheWeakCheer If you haven't completed any bundles yet, you can fix the save like this:

  1. Load the affected save.
  2. Run this command in the SMAPI console window:
    regenerate_bundles confirm
    
  3. Open a bundle menu in the community center to make sure it's fixed.

Pathoschild avatar Dec 30 '22 20:12 Pathoschild