Hacker News

8 days ago by davidst

I am one of the original authors of Space Cadet pinball (along with Mike Sandige, lead programmer, and Kevin Gliner, producer and designer.) It is surprising and gratifying to see interest is still alive for our old game. And I can't help but be impressed by the ingenuity shown by both the decompiling effort and the playable web-based game.

8 days ago by mike_san

I'm impressed as well! It's exciting to see folks so enthusiastic about the game.

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)

8 days ago by nopakos

From wikipedia: "...[Danny Thorpe] in 1994 while at Borland, he contracted with Santa Cruz startup Cinematronics (David Stafford and Mike Sandige) to build a component model and collision physics engine for a software pinball game. Cinematronics licensed an early version of the pinball engine to Microsoft" Maybe Borland and Delphi has something to do with the 'T' prefixes. Source: https://en.wikipedia.org/wiki/Danny_Thorpe

8 days ago by mike_san

Yep, this is the reason. Danny's initial code used Delphi with this convention. I'm not actually sure why that convention is used there, though. I remember asking Danny why, and I think his answer was just that was the Delphi convention. But it's been a while, so perhaps I have forgotten the details of his answer. I later had to migrate to C++ to integrate with the Windows build. And I retained the naming convention, mostly because it was quicker than changing it and I didn't have a lot of time. But I was always uncomfortable with the T prefix on the ramp class.

7 days ago by justshowpost

Absolutely not. "T" prefix stands for "type" and has its roots in case-insensitive Pascal

  /* 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 type

8 days ago by pjmlp

Borland's C++ frameworks use the same convention, to this day.

8 days ago by mysterydip

Thanks to both of you. It took me a while to realize the depth built in. I tried making a pinball game many moons ago but couldn't get the ball to "feel" right (flippers as well).

How was that process? Did you go play physical tables, go for a realistic approach, or tweak magic numbers until it "felt right"?

7 days ago by kgliner

We played every table we could get our hands on. Also rented tables weekly to be brought into the office once we moved to Austin. I tried to dig as deeply into the history of pinball too, to understand why tables had evolved the way they had.

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)

8 days ago by kingcharles

Always interesting to see the things hidden in games. When I was in the biz I was aware of many easter eggs, a lot of which are still unknown to the public.

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....

8 days ago by secondcoming

> Bonus points for anyone who knows why the classes in the source are prefixed with a 'T'!

Was it written in, or ported from, Delphi?

8 days ago by alternatetwo

Has to be ported, since Delphi doesn't generate PDB7's.

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.

8 days ago by mike_san

yep, this is it. The project started out in Delphi, but I had to port it to C to integrate with the Windows Build. For some reason they didn't want to include Delphi tooling in the Windows build.

8 days ago by ur-whale

I can't help but wonder for old closed-source utilities and games like this: whatever happened to the original source code?

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.

8 days ago by davidst

The rights belong to Electronic Arts today. They acquired Maxis who had acquired us (Cinematronics.) Microsoft may still have rights to continue publishing a version with the Windows operating system.

Microsoft, if you're reading this, we would be glad to provide assistance in getting 3D Pinball running again on the latest Windows OS.

8 days ago by leeter

Given that the reason it was removed was IA-64 which isn't a thing anymore... this should be plausible. But also given where MS has gone with games as late I'd be surprised if they do. EA should just release all of Full Tilt! Pinball on steam or GoG if they haven't already.

8 days ago by californical

Wow, this game was a staple in my childhood! Just wanted to let you know that your work brought me lots of happiness as a kid, so thank you :)

Out of curiosity, have you ever written about the experience? Technical challenges, the development culture, etc?

8 days ago by davidst

Thanks!

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.

8 days ago by coldacid

Please do! There are loads of us who would love to hear it all direct from you guys.

7 days ago by kgliner

I've been meaning to write up a history, but it's one of those things that's been on my to do list for years...Maybe someday, soon.

  Kevin

8 days ago by BiteCode_dev

Well, in this day and age of bazooka DMCA take down, it's refreshing to see a game author happy about his game being gutted, and put online to play.

8 days ago by q-big

> it's refreshing to see a game author happy about his game being gutted, and put online to play.

The game author is typically not the copyright holder.

8 days ago by WalterGR

Not just decompiled.

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...

8 days ago by stefan_

Wikipedia suggests the copyright owner is Electronic Arts:

https://en.wikipedia.org/wiki/Cinematronics,_LLC

8 days ago by moffkalast

So we can all look forward to a reboot of space cadet on Windows 11 with lootboxes and microtransactions?

8 days ago by gruez

>* All structures were populated, globals and locals named.

Microsoft provides that openly via debug symbols, so it's not even anything new.

8 days ago by WalterGR

Assuming it’s a debug build or a release build with absolutely no optimization. Otherwise at least some amount of manual work is suggested by the bullet point.

But are PDBs even available for it? I assumed Microsoft only releases PDBs for binaries used in development scenarios.

8 days ago by jamesfinlayson

Looks like a .pdb is available for it (no idea where it was sourced from but the readme says it's public).

8 days ago by devmor

If you read the README in the link, you will find the answer to your question.

8 days ago by brassattax

And it was forked and ported to emscripten! Amazing!

https://alula.github.io/SpaceCadetPinball

8 days ago by fsckboy

that is really cool!! but the flippers are a teeny bit sluggish, screws up my timing on some stuff I know how to do (gotta love gravity well)

8 days ago by LegitShady

In the graphics settings up the FPS and it seems to work a lot better for sluggishness.

8 days ago by listic

Did it really have music like that? I only remember the sounds, for some reason.

8 days ago by twic

I don't remember the music either, possibly because i turned it off the first time i played, and never turned it back on. The menu option to turn music off doesn't work in the web version, sadly.

8 days ago by AshamedCaptain

Because the default was to keep the music off.

8 days ago by undefined

[deleted]

8 days ago by CodeArtisan

Be cautious that publishing source code generated in part or entirely from decompilation of copyrighted content may take you to court.

https://torrentfreak.com/take-two-sues-enthusiasts-behind-gt...

https://news.ycombinator.com/item?id=28402640

8 days ago by userbinator

I suspect the much more recent news article https://news.ycombinator.com/item?id=28809559 may have encouraged the author to publish this... and he was looking for a bug to fix, after all.

8 days ago by worker767424

That lets you decompile and likely publish a patch, not publish the complete derived source.

8 days ago by mhh__

Patch for what though? Is the ability to use a patch taken into account because a patch to clang on Linux and a patch to appleclang on Mac have very different interpretations

8 days ago by ranger_danger

But there's hundreds of decompiled copies of Super Mario 64 on github and have been for years. Where's their court cases?

8 days ago by chii

if the purpose of the decompilation is for reverse engineering and api compatibility, there's a fair use argument.

So the OP would need to show that the purpose is indeed for reverse engineering. IANAL, so don't actually do it...

8 days ago by marcan_42

Decompiling may be legal, but publishing the decompiled source is almost always a copyright violation.

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.

8 days ago by Lammy

The path to fixing the law is doing it anyway, letting the takedowns come, and then harnessing the collective frustration of people who want to see the things they grew up with be preserved.

8 days ago by R0b0t1

Why?

8 days ago by gfiorav

Here are some interesting takes by the guy who ported it for XP at Microsoft. He says it would later prove very difficult to move to 64bit due to some low-level hacks/dependencies on word length in the collision detection code.

https://youtu.be/ThxdvEajK8g

8 days ago by Gigachad

This is the line implementing the famous “hidden test” cheat https://github.com/k4zmu2a/SpaceCadetPinball/blob/8c4f38c0af...

Looks like there are other undiscovered cheat codes too.

8 days ago by TedDoesntTalk

What is the hidden test cheat? Your link brings me to the top of page

8 days ago by selcuka

    // 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;
    }

8 days ago by Gigachad

Typing "hidden test" and hitting enter would cause the ball to be stuck to the mouse pointer rather than playing normally. I assume this was used to test the game features but it was left in the final build.

7 days ago by kgliner

That's correct. Mike needed it to test the physics, and I needed it to tune and balance the gameplay.

8 days ago by 22c

> On 64-bit bug that killed the game

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

8 days ago by pedropaulovc

The bug lore came from Raymond Chen's blog post [1]

[1] Why was Pinball removed from Windows Vista? https://devblogs.microsoft.com/oldnewthing/20121218-00/?p=58...

8 days ago by selcuka

This comment made me chuckle and also a bit sad:

> [...] we simply couldn’t figure out why the collision detector was not working. Heck, we couldn’t even find the collision detector!

8 days ago by unnouinceput

And the continuation is:

"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

8 days ago by garaetjjte

There's a documentary about it: https://www.youtube.com/watch?v=3EPTfOTC4Jw

8 days ago by GoblinSlayer

I unpacked pinball from 64-bit windows xp cd, played it and the only bug I see is that the launcher isn't well visible.

8 days ago by AshamedCaptain

It is incredible that even in 2021 people still parrot Chen's original _WRONG_ post about Pinball not being available in x64 Windows. We already even mentioned that in the original entry of his blog before the comments were removed.

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.

8 days ago by GoblinSlayer

I just looked in wikipedia, where it says xp had a working amd64 version.

8 days ago by tanjtanjtanj

I pirated (sorry) the Windows version of Space Cadet Pinball from some big torrent tracker (TBP, Demonoid?)some time after that blog post was put up and it worked on Windows 7. Last time I saw this story making the rounds, around 2017, I checked to see if it still worked on Windows 10 and to my surprise, it did. I don't know what sort of unofficial patch was applied if any, but it has been working on 64 bit windows for nearly a decade from what I can tell.

8 days ago by leeter

So there are various Youtubes about this... but it was 'Windows XP 64bit-Edition' (yes 'Edition' is part of the name. This specifically refers to IA-64 and not AMD64. There are rendering issues on the AMD64 versions but the IA-64 version doesn't work. Windows XP 64bit (non-edition) that was on AMD64 actually did ship with 3d pinball, albeit with some rendering issues. Best guess is that it was later removed in vista because it didn't fit the shiny new games theme that existed then. Raymond was giving his view of his part of the port to IA-64.

8 days ago by worker767424

Makes me wonder why they removed Hearts from Windows 8

8 days ago by phinnaeus

Probably the same collision detector issue⸮

8 days ago by gavinray

Could anyone speak more about how this decompilation is done from a technical perspective?

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.

8 days ago by bri3d

I'm not aware of any good general-case automation for this.

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).

8 days ago by duncanspumpkin

For OpenRCT2 thats not quite how we did it. We didn't use IDA decomp output as its useless with Chris Sawyer calling conventions you had to just read the assembly. We did name things as per IDA when things were completely unknown hence why there was lots of sub_XXXX functions and byte_XXXX. I personally just used OllyDbg and read the assembly and wrote equivalent C code. I've a few videos of implementing functions for OpenRCT2 and OpenLoco if you are interested.

8 days ago by bri3d

I stand corrected - I'll check them out! It makes sense that the Sawyer calling conventions wouldn't decompile correctly, since he was just making the ABI up as he programmed.

8 days ago by gavinray

  > 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.

8 days ago by bri3d

Check out `wrongbaud` tutorials: https://hackaday.io/course/172292-introduction-to-reverse-en... .

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.

8 days ago by simcop2387

It is definitely skipping over a lot of the details. Essentially the code put out by those tools is going to be almost the right code. 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. Then you try to compile it and find and fix the errors. It's going to be entirely project and file specific as to what you'll need to do but usually you'll need to rewrite the conditionals in if statements to be more understandable since the optimization passes that the original compiler did will have likely scrambled the logical version of things before (to reduce the number of things that need to be done, or reordered them to take better advantage of the way the processor pipelines things).

8 days ago by gavinray

  > " 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.)

8 days ago by an-unknown

What's missing here is type information. This is the reason why the decompiled code is quite unreadable. How to solve this: try to figure out what these missing types (like structs, arrays, ...) are, by looking at how the code uses the variables. Then you define these types in IDA/Ghidra/..., and this will already give you decompiled code that's much easier to read.

8 days ago by simcop2387

The sibling comment covers it a bit more in detail, but it's largely just some guessing and as much an art to figuring out what the types are or could be. This particular one looks like it's taking a function pointer in and checking if it's a valid function (not null) and then checking the first two bytes of the function. From my memory, the windows ABI uses the first two bytes of functions for installing hooks/debugging by patching the first two bytes into some kind of jump (while originally being nops). The 0x2b part I'm not sure about myself but it looks like some other kind of similar checks.

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).

8 days ago by ndiddy

In the case of Pinball, Microsoft released the debug symbols for the game because it was a part of Windows (meaning that there wasn't a need to figure out the function/variable/type information).

Daily digest email

Get a daily email with the the top stories from Hacker News. No spam, unsubscribe at any time.