libretro / beetle-psx-libretro

Standalone port/fork of Mednafen PSX to the Libretro API.
GNU General Public License v2.0
307 stars 131 forks source link

RFE: Another attempt to the 'make disk change seamless' idea #305

Closed i30817 closed 6 years ago

i30817 commented 6 years ago

I've requested a closed issue to 'automatic' disk change before, that wouldn't work because it expected a push api where the volume identifier of the psx game was a argument for a library function to check it (this function apparently doesn't exist).

I had another idea now. How about if a user shortcut was created that when pressed:

  1. changed disks for the 'next' disk on a set (from m3u or whatever)
  2. waited for successful read only io on the psx drive (games typically recognize changed disks from trying to find a file, not parsing a ID)
  3. If the first read succeeds, or you cycled through all disks on the collection stop.
  4. If the first read fails, goto 1.

It's only a minor ergonomic gain but do you think it could work and it's possible to hook into the 'read' function of the ps1 like this?

simias commented 6 years ago

How do you define and identify a "successful read"?

i30817 commented 6 years ago

The system call open returns success/file descriptor (>0 if i recall my C-ishms). As long as that file descriptor is from the cd drive, not the memory card - which i suppose can be checked by decorating the arguments in addition to the return (unless there is a way to tell from the FD anyway).

This might even work but be too slow anyway because the game introduces delays/takes too long to spin up the disk/insists in changing the 'insert cd' message; or have false positives from games that use 'actual parsing' of the same named file, so it's not like it's something i think will work perfectly, but it should be worth experimenting.

Maybe it's even possible to trick the game with save/loadstates to fix any wasted time before trying each cd (save after the shortcut is pressed and after the medium is removed, but before a new medium is inserted, reload on failure, or something like that).

BTW,,, I think this approach might even work for some floppy or multi floppy emulators like the ones for the X68000. As long as the required file is not open for 'writing' i guess.

i30817 commented 6 years ago

The one thing i don't know if it's possible is to get at the system call parameters and return in psx memory. It's part of the bios i suppose right?

The first of these: http://problemkaputt.de/psx-spx.htm#biosfilefunctions

It will probably be problematic to extend the idea to other platforms even if it works though, since it requires wrapping a bios function. I'd love it in amiga, pc-98 and x68k cores though, those are annoying. Wouldn't say no to dosbox either (if i used RA dosbox) but it's not so bad in DOS since most games have a full install hack.

simias commented 6 years ago

I guess to be sure one would have to look at how games usually handle this and if a generic method can be devised. I'm not sure if having a successful FileOpen is enough for most game, what if it then looks for a certain identifier within the game? What if it executes a program on the disc instead? What if it uses a raw sector read?

Hooking the PSX BIOS functions would be the easy part, you just have to check for jumps to fixed addresses in memory.

i30817 commented 6 years ago

If the method fails nothing happens. I think it's worth trying.

And, what's the problem with it searching another file or executing a exec? Even if it does that, the beauty of this method is that it doesn't need to be the first thing that the game does, but that it happens. In this case, when it finds the executable and execs it, 'a' game file will eventually be opened and success can be called that way.

But your observation reminded me that SYSTEM.CNF;1 should be blacklisted from this process. It contains the path and name to the executable in most ps1 games (and ps2), so it being opened for reading on disc change is not indicative, and indeed may be used for 'manual ID parsing'.

There should be a timeout if this file is skipped on the blacklist too to make sure the running code isn't just parsing the exec name and doing nothing if it doesn't match.

I've got nothing on raw sectors. Hoping it's rare.

edit: just figured out the timeout should apply generally, because non-matching file-search (eg: from B(42h) - firstfile(filename,direntry) and B(43h) - nextfile(direntry) can also 'do nothing' if it doesn't match. Or you can wrap these ones too with the same 'failure/success' idea but i'm unsure if that would work well from these functions descriptions.

no$cash specs have this warning on them, so it may end up unnecessary?:

BUG: For CDROM, the BIOS includes some code that is intended to realize disk changes during firstfile/nextfile operations, however, that code is so bugged that it does rather ensure that the BIOS does NOT realize new disks being inserted during firstfile/nextfile.

simias commented 6 years ago

I think you should formalize exactly the procedure you have in mind (and how you ended up with it). I know fairly well how the CD code works and I have some trouble understanding what you want to do exactly. Are you guessing how games are working or did you actually check to make sure that it's what's happening? It wouldn't surprise me if different games handled disc switching differently.

What I'd like to see is 1/ a factual technical explanation of how disc swaps works in your average PSX game 2/ how you propose to hook emulator code into that to automate it.

I realize that you've already done some of that but I have some trouble discriminating what's fact and what's guesswork. I can help with the low level stuff but I can't be bothered to reverse engineer a bunch of games to figure out how they implement disc swapping.

i30817 commented 6 years ago

It's honestly all guess work. My intention is as was stated: ps1 disc change success needs to open a first file. This is obvious because regardless of the method the game used to change cds, the game needs to continue, and opening a file with success to access new data.

The main problem comes from some failure cases which may leave the process in a limbo or wrongly assume success: The game opens a 'first' file, but it's a for parsing a ID that is different on each disk (many pc games did this). Success opening here is not indicative the game recognized a new file. The game doesn't open a file but uses firstfile and friends to find a file, but fails, so it won't ever get to use FileOpen

The second has a workaround by using a timeout. The first not so much. I'd honestly suggest just to try it to see how common it is, and blacklist opening SYSTEM.CNF counting towards success because it seems the 'obvious' way to implement this if you're lazy. Even if it fails like this the system will just assume that the change is complete and stop trying, ie: it's a false positive, the user just needs to change manually and there is no lockup or anything like that.

It's also possible i suppose that a game opens a executable to do the work of checking instead of using code in memory. I'd suggest blacklisting open files opened with +x too. I dunno how the playstation executes execs, but my guess is that bios open is involved? edit: this is unnecessary, this uses LoadExeFile and DoExecute, not FileOpen.

Maybe there is a even better method of recognizing that the game is doing 'useful work' instead of that doesn't have so many gotchas.

Maybe it's possible to recognize the moment a new executable 'takes over'? Probably not since i'd make them all the same, except for name (which is a sony requirement). edit: Confirmed with FF7.

i30817 commented 6 years ago

Ok, you know what? This idea actually has further holes in it because even the failure case may open files (think of the loading screens in FFVII disc changes, only if the game assumed the new disc was a game disc and tried to open some file for a new one). And in the end it's not very much better than a manual disc change cycle shortcut, because games often require 'input' to detect the closed tray. I'll close this as a idea, sadly (because the situation is even worse than the ps1 in many other cores like x68000, where a way to detect 'which' diskettes the game wants in what drive would be very useful).

simias commented 6 years ago

I think making disc switching simpler is a noble cause, but I wonder if the first step wouldn't be to make the UI for disc switching a little simpler and more accessible. I haven't played a lot with disc-swapping so far but as far as I've heard it's a bit tricky to make it work in RA.

i30817 commented 6 years ago

Well, it's not terrible if you have:

  1. a m3u file - this can be automated, based on filenames and i made a script for personal use that does this based on dumping groups habits (check the inner if cd or disc on the script). It's simple enough to find files of certain extensions in a dir, sorting them, and grouping filenames with maximally common substrings starting from index 0 and stuffing those files in a m3u
  2. shortcuts for switching, which RA has.

Problems occur when:

  1. the core doesn't have m3u support, but needs it (far too many cores in RA), since this was originally a mednafen innovation (the format already existed for music playlists, being very simple)
  2. the core needs two or more files at the same time, or the m3u pattern can't be applied because it uses another mechanism to list files - though this often makes m3u unnecessary and the only annoyance being the switch shortcut being different (dosbox mount multiple cds that is used on dosbox.conf files, x680000 etc).
  3. the user is not using a consistently named dump, or different formats for different discs.

I had already suggested - a year ago - creating the groups of cds without forcing the user to create m3u files. It's actually rather simple to create such a thing (as 1. shows) and it could possibly be in-built in the filechooser and scanner/playlists as a 'optional runtime preprocessing step'. More complicated for the scanner though. I suppose it could be done by indexing a 'gamedir/filenamesubstring.m3u' file for the playlist and just build it at runtime as a 'artificial' in-memory file if it doesn't actually exist.

cmd files serve a similar purpose to m3u files on the x68000 core but just for setting up the 'initial' two diskettes the game needs... initial because the game almost certainly will ask for a changed disk if it has more than 2 eventually, and the cmd file doesn't support that.

A extension where the m3u supports '2' files on the same line for these, to work as a 'group of mounted' disks for the x68000 would probably solve this corner case, but you really can't tell ahead of time what combinations of disks a game actually requires.

i30817 commented 6 years ago

@simias , i created https://github.com/libretro/RetroArch/issues/6324 for my 'VFS m3u' idea if you're interested on it or working on it.