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

Skies of Arcadia Encounter Canceling #1701

Open
RikkiGibson opened this issue Oct 15, 2024 · 2 comments
Open

Skies of Arcadia Encounter Canceling #1701

RikkiGibson opened this issue Oct 15, 2024 · 2 comments
Labels
enhancement New feature or request

Comments

@RikkiGibson
Copy link

Is your feature request related to a problem? Please describe.
Skies of Arcadia notoriously telegraphs when a random encounter is going to happen by reading from the disk drive. This makes a pretty noticeable noise on console. You can do stuff like open the menu and heal up, then get a guaranteed encounter the instant you close the menu.

It turns out you can also use this to cancel encounters on console. In the ~1.5 seconds between hearing the disk drive and the battle starting, if you perform an action like opening a chest, climbing a ladder, etc., the battle won't start. It seems the step counter resets when you do this, so you can effectively cut the encounter rate in half in some areas when you pull this trick off.

It would be nice if this trick were also possible on emulator. For speedruns it would level the playing field more between those playing on original console and those on emulator, since obviously getting fewer random encounters saves time.

Describe the solution you'd like
The solution involves 2 things:

  1. Add an option to indicate to the user when flycast is reading from virtual GDROM. Perhaps a little icon or bit of text in the corner.
  2. Modify the virtual GDROM so that the access patterns used by the game take a similar amount of time as on real hardware. Currently the emulator is faster in this case, and the result is even when you know the GDROM is being read e.g. by logging it, there is not enough time to react and cancel an encounter.

Describe alternatives you've considered
I can't think of any reasonable alternatives which would achieve the goal.

Additional context
I tried to modify the emulator to accomplish this. And I kinda-sorta got something working, which can be seen in the attached video. The LOADING.. text appearing briefly in the bottom left, before climbing the ladder, indicates a canceled encounter. I was able to walk all the way back inside with no encounters, which is pretty much impossible to do without this trick.

emu.encounter.cancel.demo.mp4

First I modified the UI to show when a GDROM read is in progress. I did this by just exposing and reading the gd_hle_state.status in the UI, and showing "loading" text when the status was nonzero.

This showed a loading indicator the way I wanted, but the load went by too fast. In adhoc testing there was maybe 0.7 seconds to react to the loading text and cancel the encounter, which was about half the time I have on console. Very difficult to actually pull the trick off this way.

So, secondly, I tried to adjust read_sectors_to to be slow enough for this trick, ideally resulting in a similar speed as console.

I basically just tried inserting a 250ms access time if the requested sector is far enough away from the most recently read sector. This kinda worked, but had the effect of slowing down ordinary read workloads too much. It was just obvious when launching the game that things were now way too slow.

Also, my change was obviously only in the HLE emulation. I ended up adding the DC BIOS file later on, and tried again in gdromv3.cpp. I wasn't able to understand what would be equivalent to what I did for the HLE one. I found the getGDROMTicks function, but I wasn't sure what it meant. It looked like a constant return value was being used for large transfers, which I didn't understand. I expected larger and larger transfers to take more and more ticks to finish or something like that. I managed to show when it was reading, but the reads were generally too fast to do the trick most of the time.

I think to make this take a similar amount of time as console, without harming overall performance too much, might require a more complex simulation of the disk drive. Accounting for stuff like constant angular velocity, seek time, buffering, and so on. For example, I noticed on console that when you repeatedly open the in-game menu in Skies, you will generally only hear the disk drive crank and get a delay the first time you do it after a battle or some such. The subsequent times will have much less delay. This might be due to the disk drive buffering the read? When I did my "add 250ms" hack, the additional delay to open the menu was considerable and happened every time.

I poked around a bit to see if any other emulators tried to do more accurate simulation of the disk drive. It looks like PCSX2 does some work to do this. Possibly some of the same aspects they are simulating could be done here. It seems like a significant amount of work, though, and might be tricky to be sure whether a complex set of changes to the GDROM did not negatively impact other games.

Here is the branch. It's in a hacked up state, but may be of interest.

Thanks for reading, and for any thoughts/suggestions you may have.

@RikkiGibson RikkiGibson added the enhancement New feature or request label Oct 15, 2024
@flyinghead
Copy link
Owner

Interesting and detailed information! I didn't know about this game trick.

Unfortunately I'm pretty sure people will start complaining that the gdrom emulation is too slow if load times are increased to match real hardware.
Interestingly Skies of Arcadia is very sensitive to the gdrom speed and a significant delay had to be introduced for this game not hang during the intro. And some people started complaining...
Also there are still delay issues with the gdrom that affects some games in serious ways so work is definitely not complete in this area.

If you want to experiment further with this, I suggest you use real BIOS mode and tweak core/hw/gdrom/gdromv3.cpp. Try increasing the value 1100000 in getGDROMTicks(). This is the number of sh4 cycles to transfer 10 KB of data (5 sectors). There are 200M cycles/sec so this is 5.5 ms. I'd be interested in what you fell is the "correct" value.

@RikkiGibson
Copy link
Author

Thanks much for the insights! Totally understand that asking for a big slowdown in the GDROM perf would really be a downgrade for ordinary use. I am wondering if such a change could go behind a config setting? Would that be more palatable? Maybe even a 3-state between "FastGDRomLoad", "Default", and "HighFidelityGDRomLoad", or something.

In any case, I much appreciate the information and guidance.

I also had time to gather a little data today.

Encounter reaction time

Time from first GDROM access to the encounter trigger visual effect (usually the screen breaking apart into triangles).

getGDROMTicks() Time
1100000 ~0.7s
2100000 ~1s
3100000 ~1.2s
4200000 ~1.5s
Real console ~1.5s

Soft reset time

Starting from Shrine Island outside, hold A+B+X+Y+Start and count time till title screen reappears

getGDROMTicks() Time
1100000 ~3s
3100000 ~8s
4200000 ~10s
Real console ~12s

Area load time

  • Taking a door from the indoor to outdoor section of Shrine Island
  • Starting when screen turns completely black, ending when screen begins fading in from black
getGDROMTicks() Time
1100000 ~2s
2100000 ~2.8s
3100000 ~3.5s
4200000 ~4.6s
Real console ~3.2s

The first table looks pretty bad (would require a massive speed reduction in order to match). The last table a smaller increase but still quite large.

I am thinking there probably isn't one correct value for these particular tests, if the goal is to match the performance of the original GDROM drive. There would probably be a need to simulate seeking, etc. and basically penalize workloads which jump back and forth across the disk versus ones that read straight through.

I made an assumption that the gdromv3.cpp does not simulate seek time. Is that right? Does the STRICT_MODE symbol play into the behavior significantly here? If STRICT_MODE is meant to eventually become a full fledged setting, then possibly these slower, more "faithful" GDROM behaviors could be locked behind it?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants