Dandara determinism issues
I am having sync and determinism issues with Dandara.
- When the game is changing scenes, it takes a non-fixed number of frames to load the next scene, and so the movie desyncs.
- Another problem, is that after stopping the game, and starting it again, the boss fight that has some RNG for the hand spawning becomes different with every reload.
I attached a movie file that should lead to the boss in most cases, but may get buggy due to the first issue.
This game calls usleep() in the middle of gameplay (2 ms and 10 ms), and fast-forwarding makes more/less calls and earlier/later, ultimately causing more non-draw frames.
2 ms call stacktrace:
/usr/local/bin/libtas.so(+0x1fe1c) [0x7f890c604e1c]
/usr/local/bin/libtas.so(usleep+0x11d) [0x7f890c616e4d]
/home/clement/Games/Dandara/Dandara.x86_64() [0x17cb73f]
/home/clement/Games/Dandara/Dandara.x86_64() [0x17b00da]
/home/clement/Games/Dandara/Dandara.x86_64() [0x17a9c52]
/home/clement/Games/Dandara/Dandara.x86_64() [0xe530d5]
/home/clement/Games/Dandara/Dandara.x86_64() [0xe53e30]
/home/clement/Games/Dandara/Dandara.x86_64() [0xc4809a]
/home/clement/Games/Dandara/Dandara.x86_64() [0xc48158]
/home/clement/Games/Dandara/Dandara.x86_64() [0xc4b6d0]
/home/clement/Games/Dandara/Dandara.x86_64() [0x44dc07]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xea) [0x7f890c0c2cca]
/home/clement/Games/Dandara/Dandara.x86_64() [0x45a601]
10 ms call stacktrace:
/usr/local/bin/libtas.so(+0x1fe1c) [0x7f890c604e1c]
/usr/local/bin/libtas.so(usleep+0x11d) [0x7f890c616e4d]
/home/clement/Games/Dandara/Dandara.x86_64() [0x17cb73f]
/home/clement/Games/Dandara/Dandara.x86_64() [0x181d2ba]
/home/clement/Games/Dandara/Dandara.x86_64() [0x181d558]
/home/clement/Games/Dandara/Dandara.x86_64() [0x17ddb3f]
/home/clement/Games/Dandara/Dandara.x86_64() [0x17d39c6]
/home/clement/Games/Dandara/Dandara.x86_64() [0x17d9c4f]
/home/clement/Games/Dandara/Dandara.x86_64() [0x17d39c6]
/home/clement/Games/Dandara/Dandara.x86_64() [0x17ad91e]
/home/clement/Games/Dandara/Dandara.x86_64() [0x17ae9a1]
/home/clement/Games/Dandara/Dandara.x86_64() [0x182b387]
/home/clement/Games/Dandara/Dandara.x86_64() [0x182b5ef]
/home/clement/Games/Dandara/Dandara.x86_64() [0x17d2a32]
/home/clement/Games/Dandara/Dandara.x86_64() [0x1797b13]
/home/clement/Games/Dandara/Dandara.x86_64() [0x1791706]
/home/clement/Games/Dandara/Dandara.x86_64() [0xe50561]
/home/clement/Games/Dandara/Dandara.x86_64() [0xe225ff]
/home/clement/Games/Dandara/Dandara.x86_64() [0xe22b7e]
/home/clement/Games/Dandara/Dandara.x86_64() [0xe1efc9]
/home/clement/Games/Dandara/Dandara.x86_64() [0xd7c1f1]
/home/clement/Games/Dandara/Dandara.x86_64() [0xd8605e]
/home/clement/Games/Dandara/Dandara.x86_64() [0xa25d1b]
/home/clement/Games/Dandara/Dandara.x86_64() [0xa25dde]
[0x40617061]
The top function 0x17cb730 is just a wrapper around usleep(). Parent function for the first case contains multiple calls of sleep while waiting for a variable to change (so, by another thread):
while (((*(uint *)(param_1 + 0x29) & 0xfffffffd) != 0 || (*(char *)((long)param_1 + 0x54) != '\0'))) {
FUN_017cb730(2);
}
and
while ((*(byte *)(param_1 + 10) & 0x40) == 0) {
FUN_017cb730(2);
}
This function uses the symbol _ZN4FMOD7gGlobalE, so it is probably waiting FMOD thread to do something.
The other case presents the same kind of loops:
while (iVar2 != 0) {
FUN_017cb730(10);
iVar2 = *(int *)(param_1 + 0x1a8);
}
Edit: Disabling those specific usleep() removes all the non-draw frames, but it doesn't fix the variable loading times :(
Hmmm, variable loading times I could mitigate by putting the game in a tempfs. I am sure that it is related to caching, since:
1 - Save a state previous to a scene change 2 - Wait for scene to load 3 - Movie is desynced 4 - Go back to savestate 5 - Wait for scene to load 6 - Movie is synced
I can stop the game and reload and generally the cache will continue, so it is probably related to reading scene from disk.
Edit: Putting the game in slow motion also makes loading times a lot more consistent.