SpaceCadetPinball – Decompilation of 3D Pinball for Windows
github.com
github.com
I took a deeper look at the github project. It's been a long time since I worked on the Space Cadet code, but the decompiled github code is pretty familiar. It's formatted differently of course, but I think it's actually better than the original. And, nice! Check it out David and Kevin: k4zmu2a got the quotes in! https://github.com/k4zmu2a/SpaceCadetPinball/blob/master/Spa...
Now I'll never live down how long I spent working on the flippers.
Bonus points for anyone who knows why the classes in the source are prefixed with a 'T'!
-Mike Sandige (Lead programmer on Space Cadet)
/* eg common C style notation involving type identifier and var identifier is illegal in Pascal */
Rect rect;
(* so Pascal requires some distinct identifiers eg *)
rect: TRect;
the other common prefix is "P" which stands for pointer typeHow was that process? Did you go play physical tables, go for a realistic approach, or tweak magic numbers until it "felt right"?
Mike (Sandige) built a scripting system that allowed me to tweak the physics, materials, etc. of each component. But our constant exposure to real tables helped us form a "feels right" baseline to target. I also applied whatever I'd learned at that point about game design fundamentals (it was early in my career).
After we finished 3D Pinball and started on Full Tilt, I got put in touch with a seasoned designer of real pinball tables who had worked on some hits from the 70s. He took me to task for a bunch of mistakes I made in 3D Pinball, and some of those corrections found their way into the Full Tilt version of Space Cadet (and more so in the other tables in Full Tilt).
Kevin Gliner (designer and producer for 3D Pinball, etc)For instance, this sign in GTA:SA has the word "TFT" on the back which is a reference to a secret video game "Illuminati": https://gta-myths.fandom.com/wiki/Signs_(GTA_SA)?file=Egg_8....
Was it written in, or ported from, Delphi?
Or at least written by someone familiar/used to Delphi, since Age of Empires utility classes are also prefixed with T, but the game was obviously written in Visual Studio - but some dev tools were written in Delphi, so somebody seems to have taken the naming scheme from there in that case.
They still use them.
Were those quotes some kind of cheat system?
What?
Is it still around, stashed in a vault a MSFT, or is it lost for ever?
Do you know?
And what would it take to convince a large corp. like MSFT to actually release the original under some open source license ... not like the thing has much value by now other than historical.
Microsoft, if you're reading this, we would be glad to provide assistance in getting 3D Pinball running again on the latest Windows OS.
(I'd love to see a GOG or Steam or even Origin release of Full Tilt Pinball, though. The Full Tilt version of Space Cadet is better-- higher-resolution graphics plus some gameplay tweaks.)
[edit] Digging a little deeper, that might not be entirely true. The first consumer version of Windows it didn't appear in was Vista, but it sounds like the decision to drop Pinball was made during the XP era (even though it shipped with x86 Windows XP). So issues with the IA64 port (or with another architecture) might've been the reason it was dropped, then that decision was not revisited for Vista even if Pinball might've worked under AMD64 Windows.
Warning contains a youtuber bashing their head firmly against the pain of Itanium to test this.
Out of curiosity, have you ever written about the experience? Technical challenges, the development culture, etc?
There were a couple of interviews with gaming magazines years ago. They would be hard to find today and didn't cover the topics you mentioned. Mike, Kevin, and I, really need to get together to tell the story some day.
KevinThe game author is typically not the copyright holder.
And only on hacker news will I be replying to one of the authors.
The physics just seemed so spot on. I installed Win2K on a VM recently, just for this.
Start Menu, type in "pinball". Ah....
I was not aware of it, however. I am not sure it was as easy to launch before, by just typing in "pinball" in the Start menu.
And it was the best summer of my life.
I remember getting up early, making cereal, and then playing this.
You created one of my favorite childhood memories, thank you so much.
What was done:
* All structures were populated, globals and locals named.
* All subs were decompiled, C pseudo code was converted to compilable C++. Loose (namespace?) subs were assigned to classes.
Edit: Wow, and a lot more: https://github.com/k4zmu2a/SpaceCadetPinball/commits/master
Also see “On the attempts to resurrect Space Cadet Pinball” by Raymond Chen: https://devblogs.microsoft.com/oldnewthing/20181221-00/?p=10...
Microsoft provides that openly via debug symbols, so it's not even anything new.
But are PDBs even available for it? I assumed Microsoft only releases PDBs for binaries used in development scenarios.
No idea how else you'd acquire it, Visual Studio would probably also download it if you get pinball.exe to crash and debug it.
rabin2 -PP pinball.exe
(part of https://radare.org) to download the pdb from microsoft's symbol server.What level of optimization was used in the released executable?
Edit: It does however tell you still from which exact .obj an offset is, info the author didn't seem to have used since they created their own filenames. (Edit 2:, at least partially, some original filenames are there, but also custom ones)
https://torrentfreak.com/take-two-sues-enthusiasts-behind-gt...
https://www.chromium.org/developers/design-documents/softwar...
So the OP would need to show that the purpose is indeed for reverse engineering. IANAL, so don't actually do it...
Interoperability is an argument for the legality of decompilation itself (i.e. you can ignore EULA clauses that say otherwise); it doesn't make the resulting code copyright-free or automatically eligible for fair use.
You can make fair use arguments in some cases, but "I decompiled it for interoperability" isn't one of those. That just lets you decompile it privately (for analysis/research), not publish the resulting code.
I worked with game RE for a long time and the only way that publishers were able to go after people was if they used game assets. The decompiled code was, as far as I was ever aware, free game. There was almost always manual intervention to get it to build.
If decompiled code were fair use, you could take any application, decompile it, and re-publish it for free. It doesn't make any sense. Decompilation is a mechanical transformation, and the manual edits that come after to make it work do not significantly alter the nature of the work. It is clearly a derivative work of the original, so you're left with fair use arguments, and there certainly isn't any universal "well it's a game and it's just the code, not the assets" fair use argument.
Looks like there are other undiscovered cheat codes too.
// Original allowed to enter cheats only before the first launch.
std::memmove(&cheatBuffer[0], &cheatBuffer[1], 10);
cheatBuffer[10] = key;
if (strcmp(bufferEnd - 11, "hidden test") == 0)
{
pb::cheat_mode ^= true;
}I had heard about this bug, I think I saw it on Dave Plummer's YouTube channel[1]. I remember thinking at the time that I am surprised nobody has tried to decompile it and figure it out, looks like k4zmu2a did and couldn't find it. Now I have more questions about the original bug reports.
[1] https://www.youtube.com/channel/UCNzszbnvQeFzObW0ghk0Ckw
[1] Why was Pinball removed from Windows Vista? https://devblogs.microsoft.com/oldnewthing/20121218-00/?p=58...
> [...] we simply couldn’t figure out why the collision detector was not working. Heck, we couldn’t even find the collision detector!
"We had several million lines of code still to port, so we couldn’t afford to spend days studying the code trying to figure out what obscure floating point rounding error was causing collision detection to fail."
I'd say Ray is right, not lacking the skill, but lacking the time
It's nice to be able to point to this line: https://github.com/k4zmu2a/SpaceCadetPinball/blob/5947727f80...
And, while it is true that the code is sparsely commented, the geometry code that computes ray intersections is commented.
I'm curious, didn't they just call you or Danny (I believe that's Danny Thorpe, who is currently working for Microsoft) for assistance?
Tens of "YouTube videos" appear in this thread and all of them simply parrot the same statement from Chen and not a single one of them even bothers to actually try Windows XP x64 edition and check whether Pinball is there not. Again only in some comments people seem to realize 'hey, you guys may be wrong .. there is a x64 pinball here after all, at least'.
I guess it's a sad reflection of our society.
Because if MS had that agreement... almost nothing would have been released on AMD64 as very little actually made it to IA-64 or was supported there realistically.
This looks nothing like the pseudocode C that IDA/Ghidra spit out, so how would you go about doing this even?
It says in the README:
Tools used: Ghidra, Ida, Visual Studio
What was done:
All structures were populated, globals and locals named.
All subs were decompiled, C pseudo code was converted to compilable C++. Loose (namespace?) subs were assigned to classes.
Which is a bit "Draw-the-rest-of-the-fucking-owl" for me. Or am I just clueless.When I've done this in the past, it basically consists of:
1) Decompile project using Ghidra/IDA, first pass.
2) Load symbols if present (sounds like there was a PDB for this one, which makes things a lot easier).
3) Read decompilation/asm for unnamed subs and try to name them based on what they do.
4) Export all decompiled source into an editor and start copy/paste/editing into readable source. Highly manual process, for some files it's just pattern matching / renaming and goes really quickly, for others it's full reimplementation and a bit harder.
And, if you look at most "decompiled game" projects, I think this is the industry standard way to do this. For example, OpenRCT2 started as a repository full of manually created source with Hex-Rays names and slowly evolved module-by-module into readable source code. (disclosure: per the child post, my original assumption that OpenRCT2 was copied out of Hex-Rays was inaccurate, since it was originally written in assembler it didn't follow a standard C ABI and the decompiler wouldn't work properly anyway).
> sounds like there was a PDB for this one, which makes things a lot easier
Ah yeah that certainly reduces the difficulty by an order of magnitude.Do you know of anyone who has done this with high-skill as a recorded video tutorial? Seems like one of those things much easier to follow in video than text due to how complicated IDA/Ghidra are as tools.
wrongbaud's are the best trainings I've seen for Ghidra so far. I actually haven't watched this particular course (I confused it with some other ones) - but given what I've seen, I'm sure it's good.
> " The thing you do then is go through each function it produces and fix up the names and maybe re-organize it to be more readable."
How do you do this, when most of the code is like (real fn decompilation from random binary opened with Ghidra v10.0.4 for example's sake just now): undefined8 FUN_14004dd60(longlong *param_1)
{
if ((((*param_1 != 0) && (param_1[1] != 0)) && (param_1[2] != 0)) &&
((param_1[0x2b] != 0 && (*(longlong *)(param_1[0x2b] + 0x28) != 0)))) {
if (*(char *)((longlong)param_1 + 0x21) != '\0') {
return 0;
}
(**(code **)(param_1[1] + 0x18))();
*(undefined *)((longlong)param_1 + 0x21) = 1;
return 1;
}
return 0;
}
This program is 14MB, and Ghidra says: # of Functions: 12661
# of Symbols: 118504
# of Data Types: 6513
It just seems unapproachably daunting.(Serious question, not being passive-aggressive. I find this stuff interesting and wish I understood it more.)
And actually then thinking about the way it's calling it, i'm wondering if this is actually from some C++ standard library code for doing stuff with a vtable, looking up the vtable entry and checking it's validity before calling it (in this case, location 0x18, and checking some kind of RTTI at 0x28 and 0x2b) and storing that it's been initialized in 0x21. So I think this might be part of an initialization function for some property on top of a object that exists at *param_1. and the decompiler has misinterpreted it as a longlong because of the access patterns (64bit pointers).
Plummer's only role, near as I can tell, was to get it working on later Windows operating systems that were 32 bit (or certain 32 bit variants), which likely extended the shipping life of the game (so, not Windows 95 or Windows 98, but the others that followed). Microsoft actually had the option in our original deal to ship with the OS when Win 95 launched and chose the Plus Pack instead.
KevinThis, according to Dave, is also the reason you don't see Pinball shipped on the newer "64-bit" versions of Windows, despite the 32-bit version running just fine on 64-bit Windows.
Gonna archive this before it's wiped from the intenet.
For C++ projects targeting Windows, IDA is still a lot better in terms of decompilation quality. The demangler and function signature system is particularly tailored to MSVC++.
For other architectures, Ghidra kills IDA by virtue of abstraction - all disassembly turns into the same IR (P-code) and is decompiled from there. So, the decompiler works across all architectures with a processor spec, rather than being specialized to x86/ARM.
And, the exposure of this P-code system is very powerful as well - with some clever plugin scripting for Ghidra, you can actually single-step through the P-code as though you had a full emulator/debugger, without needing to set up an entire virtual environment. https://wrongbaud.github.io/posts/kong-vs-ghidra/
Not in the same category, IDA is really good.
However, Ghidra is:
a) free
b) good enough for many thing
One downside: the UI is convoluted.I agree that IDA is head-and-shoulders better for Windows, especially Microsoft-compiler built software, but I'm not sure Ghidra isn't in the same category, especially for embedded. I find myself much more productive in Ghidra than IDA for embedded tasks.
Ah, fair enough. I've only used these tools in an windows x86-64 context.