don't click here

Sonic CD decompilation

Discussion in 'Engineering & Reverse Engineering' started by BenoitRen, Jul 17, 2023.

  1. ndiddy

    ndiddy

    Member
    50
    68
    18
    Nice work! This is a really neat project, you've done a great job so far. One thing to note if anyone else wants to try it is that Benoit posted a 32-bit EXE and it will crash if you use a 64-bit SDL DLL (I ended up building my own copy of the game from the source code before I realized this).

    One bug I found: In the "load_stage" function in stage.c, the "stage_str" variable should be 4 bytes instead of 3 (the "read_stage_string" function writes 4 bytes into it).
     
  2. penBorefield

    penBorefield

    Badniks, attack! Member
    354
    64
    28
    Basement
    Conquering the world
    Support for 32-bit programs have dropped as of September 30, 2024 for Windows. They rely on 64-bit programs for now.
     
  3. Clownacy

    Clownacy

    Tech Member
    1,146
    818
    93
    Huh? SDL2 still supports 32-bit.
     
  4. Blastfrog

    Blastfrog

    See ya starside. Member
    That’s just the 32-bit version of Windows itself, nothing to worry about. 32-bit applications will still run just fine under the 64-bit version.
     
    • Agree Agree x 2
    • Informative Informative x 1
    • List
  5. BenoitRen

    BenoitRen

    Tech Member
    936
    573
    93
    The original source code assumes that an int is 4 bytes for accessing the "scratch RAM" part of each sprite_status struct, so compiling it as 64-bit will make it malfunction. I do plan to rectify this in my version down the line, but the priority is getting everything to work.
    Thanks for the report! I've corrected it.
     
  6. BenoitRen

    BenoitRen

    Tech Member
    936
    573
    93
    The time warp sequence has been implemented!

    I thought it'd be done quick, but instead of calling SetGrid to place tiles on planes, it relies on the control program loading a binary file that contains the layout information. The function was already decompiled, but without symbols I hadn't been able to name much at the time. But now I could.

    Then I struggled with the palette, as the fading wasn't working, and the sprites were white. Until it dawned on me that for fading to work, I had to account for it in the calling loop, just like for stages. Once that was fixed, everything looked correct.
     
  7. Blastfrog

    Blastfrog

    See ya starside. Member
    Curious, when this reaches a full release, will there perhaps be some way for the end user to get the data from versions other than Gems Collection?
     
  8. BenoitRen

    BenoitRen

    Tech Member
    936
    573
    93
    You can get the exact same sprite, tile, and level data from the PC version.

    For an alternative when it comes to background music, I can add support for using CD audio, but only for the SDL1 version. Other solutions would be more involved, like ripping the BGM from the CD and converting them to MP3 or OGG Vorbis or something, and adding support for that format.
     
  9. ndiddy

    ndiddy

    Member
    50
    68
    18
    One suggestion I have for this port is improving the frame pacing by using vsync on displays that are a multiple of 60Hz and only falling back to a timed delay when the display refresh rate isn't a multiple of 60Hz. This makes the scrolling considerably less choppy on my computer. Here's a build of the game with vsync enabled as well as a diff file with my changes. I would have done a pull request instead but it looks like the git hosting service you use doesn't support this workflow. I use Visual C++ so you may have to install the Visual C++ 2015-2022 redistributable if you get a missing DLL error.
     
  10. BenoitRen

    BenoitRen

    Tech Member
    936
    573
    93
    The current timed delay implementation is something I quickly cobbled together. I intend to replace it with the implementation I used in Rockman Copy System.

    Thanks for the patch. Not being familiar with SDL2, I didn't know vsync was an option.

    You'd recommend to move the timer-related code from timer.c to graphics.c?
     
  11. ndiddy

    ndiddy

    Member
    50
    68
    18
    Yeah since it's only being used for graphics timing and now the timer code has to know that it should only run if vsync is off.
     
  12. BenoitRen

    BenoitRen

    Tech Member
    936
    573
    93
    Apologies for the wait. I've added the vsync code!
     
  13. ndiddy

    ndiddy

    Member
    50
    68
    18
    Just as an FYI the way you implemented it means it may not work on 120Hz or 240Hz monitors. The documentation for SDL_RenderSetVSync mentions that the vsync parameter should only be 0 (off) or 1 (on), and all other values for vsync are reserved. Calling it like "SDL_RenderSetVSync(gp_renderer, vsync)" may not work if vsync is more than 1. That's why on my patch, I had it as "SDL_RenderSetVSync(gp_renderer, !!vsync)". In C, putting "!!" before a variable is a fairly common idiom that means "1 if the variable's nonzero, otherwise 0".
     
  14. BenoitRen

    BenoitRen

    Tech Member
    936
    573
    93
    I noticed you used vsync both as a boolean and as a frame multiplier, so I split it into vsync and frame_multiplier. vsync will be either 0 or 1. :)
     
  15. ndiddy

    ndiddy

    Member
    50
    68
    18
    Oh got it, thanks for the correction!
     
  16. BenoitRen

    BenoitRen

    Tech Member
    936
    573
    93
    I want to compile this for the PlayStation Portable, but the PSPSDK maintainers have really dropped the ball when it comes to Windows. Basically, there is no Windows version: "On Windows the PSPDEV toolchain is run on Ubuntu running on Microsoft’s WSL.".

    Back in 2020 they tried to make it a bit easier by allowing you to build a Docker image with the toolchain. However, this seems to have been abandoned in 2022, and I suppose that's why building it no longer works (I tried).

    10 years ago I used MINPSPW (Minimalist PSP homebrew SDK for Windows). Luckily I kept a backup of that. After struggling to write a working makefile, I'm stuck with tons of linker errors. Here are some of them:
    Code (Text):
    1. error: stray '\6' in program
    2. error: stray '\22' in program
    There are also tons of warnings about ignored null characters.

    I searched, but have yet to find out what the problem is.
     
  17. BenoitRen

    BenoitRen

    Tech Member
    936
    573
    93
    The Special Stage is a tough cookie.

    The Mega Drive has two tile planes, and using tile priority you can fake having three or four. During regular gameplay, Sonic CD uses plane B for the background, and uses tile priority to use plane A as two foreground planes.

    For the PC version, they translated the plane concept to a "grid", and treat the tiles of plane A's high and low priority as their own grids. To set a tile, SetGrid is called, which makes sure that a tile can't be in the same place on the grid for plane A high priority as on the grid for plane A low priority.

    Whoever ported the Special Stage mode must have been mad, because the result uses up to eight tile planes, depending on the Special Stage.

    It uses SetGrid like the regular stages to set tiles, but that function has specific code for it, which places all tiles on plane 0 (plane A high priority). The other planes are static and populated by what I've called "plane layouts" that are loaded from files, which I already had to implement for the time warp sequence.

    There's a table with initialisation information for all eight planes. It defines the width and height, in tiles, of each, as well as a third parameter. As it's never bigger than a Mega Drive's I ignored it. However, that third parameter is important: it defines where the plane starts vertically on the screen. So now I have to figure out how to hack that into my engine.

    I can't get the stamp map (the Special Stage's floor) to render correctly. First, the numbers I'd get were way too high, causing it to try to retrieve pixels from outside the map. After limiting it to 4096, all I see is a sea of bumpers. I then stepped through the function that sets the stamp map. Found out I don't advance the data pointer. No change after fixing that; it's still reading zeroes. Then I found out that Sonic CD doesn't actually check if it opening the map file was successful. After placing the files there, at last Sonic isn't considered to be running to be running in water anymore, and I see... weird shapes. Sometimes they resemble the actual stage, but most of the time they don't.

    Here's a short video of the work in progress:

     
    • Like Like x 4
    • Informative Informative x 2
    • List
  18. Cooljerk

    Cooljerk

    Professional Electromancer Oldbie
    5,088
    724
    93
    It looks like the angle you are running on is what makes it temporarily line up correctly. I can see repeated patterns when you turn, perhaps a stride error when texture sampling at a weird angle? When it is lined up correctly, the map itself seems to be made up of the wrong tiles, are you sure the "stamp" is being generated correctly in the first place? How are you debugging this, can you use renderdoc to examine the buffer during the drawcall?

    It's more like MSVC dropping the ball, or more accurately GCC picking up the ball and running with it. The same thing happens in Dreamcast circles. Credit GCC for being so awesome at cross compilation and microsoft being so x86 windows-focused. Personally I can't stand WSL because, insanely annoyingly, they don't allow you to access your USB devices from WSL, which is super annoying when I'm trying to use a USB Coder's cable on the Dreamcast. I personally just stick to linux proper. This is precisely why I don't use DreamSDK on the Dreamcast and just build KOS and my project by hand and import the libraries manually.

    Re: Makefiles -- I have a tutorial written for Dreamcast dev on how to write a makefile properly, do you need help? I write makefiles all the time, it's super useful. BTW the '\22' error is a unicode error, U+0022 is the unicode for a quotation mark. MinGW doesn't support utf-8, while make in linux proper does. Replace your encoding with ANSI, and change your quotation mark to the proper one. No idea what \6 is, looking up U+0006 it looks like it's a termination character for some signal or something.
     
    Last edited: Mar 7, 2025
  19. BenoitRen

    BenoitRen

    Tech Member
    936
    573
    93
    I don't use any fancy tools to debug this. I just try to understand how it's supposed to work (which also involves cross-referencing decompiled code), and check things over. At the moment, the floor looks close to the original. The grass tile is light green instead of dark green, and I don't know why. I'm currently comparing the data, and have fixed a bunch of sprite errors, but it looks like the palettes match.

    As for makefiles, I've got it figured out for now. But thanks for the offer.

    So, should I boot into GNU/Linux to compile a PSP build?

    upload_2025-3-8_0-10-29.png
     
  20. BenoitRen

    BenoitRen

    Tech Member
    936
    573
    93
    Welcome to my Let's Play of the Special Stage:



    I wanted to showcase the secret 8th special stage as well, but I pasted one too few special_stage calls in main(). Oops.

    There are a couple graphics glitches left, but, you know, something had to be off so it wouldn't appear to just be a video of the official release, right?
    • Starting from the second Time Stone, its palette is incorrect.
    • Areas where I think there's supposed to be water have bumpers instead.