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

[EXPERIMENTAL] GCMemcardDirectory: Set card formatting timestamp to known value. #8476

Draft
wants to merge 1 commit into
base: master
from

Conversation

@AdmiralCurtiss
Copy link
Contributor

AdmiralCurtiss commented Nov 17, 2019

This is a fix/workaround for issues like this one: https://bugs.dolphin-emu.org/issues/11849
Code will be made nicer if we decide to actually go with it.

To summarize, some games refuse to save to a memory card if they can detect that the card is not the same card the save was loaded from. They, or at least some of them, do this by comparing the m_serial field of the currently inserted memory card's header to the one remembered from the card they loaded the save from.

This field is pseudorandomly generated when the card is formatted based on the current timestamp of the GameCube's internal clock. This is also how we do it, with the wrinkle that our virtual GCI folder memory card is formatted every time a Dolphin game session starts. This means that the following sequence of tasks will cause a game to detect a changed memory card:

  • Boot a game.
  • Load a save.
  • Make a savestate.
  • Close the game.
  • Boot the game again.
  • Load the savestate.
  • Try to save.

Assuming no one modified the contents of the GCI folder in the meantime, the save we're attempting to overwrite is still the exact same save we loaded from, yet the game detects it as a different one because the virtual memory card was reinitialized with a different timestamp on the second boot.

I've tested this for the game in the linked issue (Paper Mario TTYD) and it does indeed allow you to save now when you do this even though it didn't before. However, I'm pretty afraid of potential false positives. If a game thinks that the currently inserted card has not changed from the one it has loaded the data from, and doesn't bother to re-read the BAT of the card, it could corrupt data in the card if it has changed, for example when you added or removed a GCI file from the GCI folder between making the savestate and booting the game the second time. This is technically not impossible in real life, though somewhat convoluted (while game is running remove card, put it in second GC, copy around files, put it back in first GC), so you'd hope games would be able to deal with it, but you never know.

@JMC47 Since you requested this in the linked bug report, please test this with as many combinations of cases you can think of!

@AdmiralCurtiss

This comment has been minimized.

@AdmiralCurtiss

This comment has been minimized.

Copy link
Contributor Author

AdmiralCurtiss commented Nov 17, 2019

As a sidenote, am I misreading this or do we have a weird circular dependency related to g_SRAM.settings_ex.flash_id? The formatting code reads from this value to derive the card serial, but at the same time it's set based on the currently inserted memory card's header (called from here). This seems somewhat fishy to me.

@mbc07

This comment has been minimized.

Copy link
Contributor

mbc07 commented Nov 17, 2019

Wouldn't saving m_serial field to the save state then reading it back when loading the save state be enough?

@AdmiralCurtiss

This comment has been minimized.

Copy link
Contributor Author

AdmiralCurtiss commented Nov 18, 2019

Potentially, but I think that would actually complicate the code a lot more, as you'd have to special case GCI folders compared to raw card files, keep track of whether a GCI folder has been already used in the session to remember its serial and so on, all of which we can just ignore by just assuming a GCI folder is formatted at a known timestamp.

@JMC47

This comment has been minimized.

Copy link
Contributor

JMC47 commented Nov 19, 2019

Wow, no wonder I could never 100% reproduce it, I was missing a step that had to do with the initial save! Great work, and I think we need to do this ASAP.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
3 participants
You can’t perform that action at this time.