Oct 30, 2014
Transistor is now out for Linux and Mac:
http://store.steampowered.com/app/237930/
The Linux version supports the DualShock 4 light bar, too:
https://vine.co/v/OM00rdtZ6LF
Documentation is already up on the PCGW:
http://pcgamingwiki.com/wiki/Transistor
This is the second time I've ported something that I previously wrote about on G+. I could get used to this.
But let's talk about the port again anyway, since I've talked about the game before. Before referring to that old post, let's talk about the overall work:
Basically, I took all the files in their MonoGame branch that referred to OpenTK, and replaced them with the FNA versions of those files. That's about it. Most of the files never changed, and the FNA files that replaced the OpenTK files went through minor changes to line up with the internal APIs (primarily, fixing things to work under the XNA 3.1 spec, but not actually changing any functionality). For the actual game it was mostly the obvious set of changes, like save paths, and very little else. I made a couple changes so my very old Mono compiler would be happy, but those changes aren't relevant in the shipping version since the C# assemblies you're playing with are built by VS2012, primarily to ensure accuracy in the assembly output.
So what about those points I talked about back in May? Let's go in order:
1: Holy crap so much threaded OpenGL
It turns out Supergiant took my advice on this one. Pretty much to the letter, actually. By the time I got the source, they implemented a single-threaded renderer that uses the exact same ForceToThread setup I've got in FNA. Looking at their patch notes, it helped in the exact way that I discussed, too.
But, there was still some threaded GL hidden away. Not a whole lot, but it was there. At the beginning there was still a pair of MakeCurrent operations to get the context on the render thread, but it didn't actually do anything on the original thread, so I just delayed the context creation to when we made the render thread. This gives us a 100% single-threaded renderer, even if the rendering isn't technically happening on the main thread.
2: WinAPI
Nice and straightforward. What wasn't immediately fixed by moving to the FNA files was found/fixed in the first day; cursors work with SDL_SetCursor, total RAM is found with SDL_GetSystemRAM, etc. The cursors aren't 100% accurate since the .cur files didn't translate to SDL-compatible bitmap files very well (this may change with SDL 2.0.4, I'll revisit when I get my hands on it), but they do work well enough, I think. Since we use FNA for the platform stuff, it behaves identically to any other XNA port I've done, from the window management to the gamepad compatibility.
3: Steamworks requirement
I was right about it requiring Steamworks, but it does have an offline mode if you've got the libraries. I'm used to being able to omit those files in Steamworks# titles, but hey, if you've got the files, it works. Fine.
4: Middleware I don't have access to
I got the Bink libs. Duh.
Bink may very well be the first proprietary middleware I've ever used in my career where it actually worked consistently and reliably across all targets without a bunch of per-platform nonsense. In fact, the only problem I did find in the Bink work was on Supergiant's end; they weren't allocating memory for some planes that Bink wanted, and somehow that worked on Windows and PS4, but Linux/Mac caught it and an engineer at RAD was able to tell us what was up. It was a shocking contrast to the other middleware I had to fight...
5: Middleware that doesn't even exist yet
I updated FMOD Studio to 1.04.05 to get Linux compatibility. Just updating this one library took most of my time. I honestly don't want to talk about this one right now... maybe another time. There is still exactly one segfault in the audio engine that the new FMOD libs introduced for reasons science itself will never understand, and if you're unlucky enough you might even find it right at the end of the initial loading screen (it'll look something like a double free() 50 stack frames into FMOD Studio's update() call, even though there's no audio at this point). We only saw it once after I "fixed" the original problem, so it "should" be okay, but FMOD's a strange, confusing beast like that.
Middlewares aside, this port was about as straightforward as I anticipated, and you can expect it to be very accurate to the Windows version, with Light Bar support being a feature even Windows doesn't have.
http://store.steampowered.com/app/237930/
The Linux version supports the DualShock 4 light bar, too:
https://vine.co/v/OM00rdtZ6LF
Documentation is already up on the PCGW:
http://pcgamingwiki.com/wiki/Transistor
This is the second time I've ported something that I previously wrote about on G+. I could get used to this.
But let's talk about the port again anyway, since I've talked about the game before. Before referring to that old post, let's talk about the overall work:
Basically, I took all the files in their MonoGame branch that referred to OpenTK, and replaced them with the FNA versions of those files. That's about it. Most of the files never changed, and the FNA files that replaced the OpenTK files went through minor changes to line up with the internal APIs (primarily, fixing things to work under the XNA 3.1 spec, but not actually changing any functionality). For the actual game it was mostly the obvious set of changes, like save paths, and very little else. I made a couple changes so my very old Mono compiler would be happy, but those changes aren't relevant in the shipping version since the C# assemblies you're playing with are built by VS2012, primarily to ensure accuracy in the assembly output.
So what about those points I talked about back in May? Let's go in order:
1: Holy crap so much threaded OpenGL
It turns out Supergiant took my advice on this one. Pretty much to the letter, actually. By the time I got the source, they implemented a single-threaded renderer that uses the exact same ForceToThread setup I've got in FNA. Looking at their patch notes, it helped in the exact way that I discussed, too.
But, there was still some threaded GL hidden away. Not a whole lot, but it was there. At the beginning there was still a pair of MakeCurrent operations to get the context on the render thread, but it didn't actually do anything on the original thread, so I just delayed the context creation to when we made the render thread. This gives us a 100% single-threaded renderer, even if the rendering isn't technically happening on the main thread.
2: WinAPI
Nice and straightforward. What wasn't immediately fixed by moving to the FNA files was found/fixed in the first day; cursors work with SDL_SetCursor, total RAM is found with SDL_GetSystemRAM, etc. The cursors aren't 100% accurate since the .cur files didn't translate to SDL-compatible bitmap files very well (this may change with SDL 2.0.4, I'll revisit when I get my hands on it), but they do work well enough, I think. Since we use FNA for the platform stuff, it behaves identically to any other XNA port I've done, from the window management to the gamepad compatibility.
3: Steamworks requirement
I was right about it requiring Steamworks, but it does have an offline mode if you've got the libraries. I'm used to being able to omit those files in Steamworks# titles, but hey, if you've got the files, it works. Fine.
4: Middleware I don't have access to
I got the Bink libs. Duh.
Bink may very well be the first proprietary middleware I've ever used in my career where it actually worked consistently and reliably across all targets without a bunch of per-platform nonsense. In fact, the only problem I did find in the Bink work was on Supergiant's end; they weren't allocating memory for some planes that Bink wanted, and somehow that worked on Windows and PS4, but Linux/Mac caught it and an engineer at RAD was able to tell us what was up. It was a shocking contrast to the other middleware I had to fight...
5: Middleware that doesn't even exist yet
I updated FMOD Studio to 1.04.05 to get Linux compatibility. Just updating this one library took most of my time. I honestly don't want to talk about this one right now... maybe another time. There is still exactly one segfault in the audio engine that the new FMOD libs introduced for reasons science itself will never understand, and if you're unlucky enough you might even find it right at the end of the initial loading screen (it'll look something like a double free() 50 stack frames into FMOD Studio's update() call, even though there's no audio at this point). We only saw it once after I "fixed" the original problem, so it "should" be okay, but FMOD's a strange, confusing beast like that.
Middlewares aside, this port was about as straightforward as I anticipated, and you can expect it to be very accurate to the Windows version, with Light Bar support being a feature even Windows doesn't have.
View 9 previous comments
+Ethan Lee Sorry, I didn't see the "read more" button, and in the meantime found this link on your site: http://www.flibitijibibo.com/index.php?page=Portfolio/Ports#21_transistor.txt
Awesome man!Oct 30, 2014
after playing for a bit more, i have two comments; one of them may be for the upstream developers, though.
while playing with my controller (and enjoying the light show very much), the screen saver turned on. the game should definitely be inhibiting that.
during the screens where you learn things about characters of the game, the sword speaks, but the lights stay off on the controller.Oct 31, 2014
+Timo Paulssen The light bar code is as it was for the PS4 version, so that may be how they wanted it... not sure.
For the screensaver, I use SDL_DisableScreenSaver() on start, only enabling it when the window focus is lost (and disabling it again when we regain focus). It would depend on the desktop environment's compatibility with this call in SDL's X11 backend (which, if I recall, is absolutely terrifying to read). Maybe this has changed between 2.0.3 and the upcoming 2.0.4, but I've not checked.
EDIT: Here's the SDL2_GamePlatform in FNA; it's mostly the same in Transistor:
https://github.com/flibitijibibo/FNA/blob/master/src/SDL2/SDL2_GamePlatform.cs
`grep` around for SDL_DisableScreenSaver and SDL_EnableScreensaver to get an idea of how we use it.Oct 31, 2014
The SDL x11 screensaver code isn't that horrid. it tries a dbus call to org.freedesktop.ScreenSaver with an Inhibit, and a UnInhibit once it's done, and also tickles the screensaver.
After that it tries calling the X11 Screensaver extension to query the screensaver, and suspend it if possible.
Note however that it doesn't do magical calls out to xscreensaver-command --suspend or such.Oct 31, 2014
+D.Spindel Ljungmark Ah, right, I forgot that the dbus stuff was added around the actual 2.0 release. I must have been thinking about the stuff that was in there back in... I think it was late 2012? It was a really long time ago, and I definitely remember seeing something like /* FIXME: This is so wrong it hurts. */Oct 31, 2014
Yeah. It used to be horrid indeed. Testing if control exec files existed and running them... Horrible.
dbus makes it all a lot neater. Though I'm not sure why they do the tickle thing to fake user presence. Maybe to make sure the screensaver is off before inhibiting.Oct 31, 2014