Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
MysticTempest opened this issue Nov 24, 2021 · 11 comments
Assignees
Labels
bug This is an unintended error or behavior that can be addressed with specific development changes.
Milestone

Comments

@MysticTempest
Copy link

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

@Pathoschild Pathoschild self-assigned this Nov 25, 2021
@Pathoschild Pathoschild added the bug This is an unintended error or behavior that can be addressed with specific development changes. label Nov 25, 2021
@Pathoschild Pathoschild added this to the 3.14.0 milestone Nov 25, 2021
@Pathoschild
Copy link
Owner

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
Copy link
Owner

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.

@MysticTempest
Copy link
Author

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.

@Pathoschild
Copy link
Owner

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.

@cduta
Copy link

cduta commented Nov 26, 2021

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!

@MysticTempest
Copy link
Author

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.

@Pathoschild
Copy link
Owner

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

Pathoschild added a commit that referenced this issue Mar 26, 2022
…#812)

The game's content pipeline automatically loads localized variants if present. For example, it will try to load "Maps/cave.fr-FR", then "Maps/cave_international", then "Maps/cave". The old content API obfuscates this logic and treats them as interchangeable, which causes edge cases like bundle corruption (#812). This commit rewrites the loading logic to match the game logic when using the new content events, while maintaining the legacy behavior for the old IAssetLoader/IAssetEditor interfaces that'll be removed in SMAPI 4.0.0.
@Pathoschild
Copy link
Owner

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
Copy link
Owner

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.

@Cheers414
Copy link

Cheers414 commented Dec 30, 2022

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

@Pathoschild
Copy link
Owner

@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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug This is an unintended error or behavior that can be addressed with specific development changes.
Projects
None yet
Development

No branches or pull requests

4 participants