The Great Porting Adventure: Day 3

Yesterday was spent in Mac land, which is an unfamiliar and glossy place. Fortunately I found a nice set of blog posts to guide me on my quest. If you want a tutorial, go read those posts. If you want to see what happens when someone tries to go from zero to Mac port, read on.

Here’s a recap of my experience. This is more for my own benefit rather than a tutorial for others, though it may give you an idea of what’s involved.

  1. Download XCode 4.2 for Lion, MonoDevelop and the MonoFramework.
  2. Watch some videos on how Macs work (seriously) and set up a user account for myself since my Mac is borrowed.
  3. Try to install xcode. Discovered that my version of OSX is Snow Leopard, not Lion and thus I have downloaded the wrong version. But the version for Snow Leopard is only available for paid Mac or iOS developers! I need to either upgrade to Lion or purchase a Mac/iOS developer membership in order to get xcode for Snow Leopard.

    This cat is too old.

  4. Decide I’ll need it eventually anyway and purchase a Mac Developer account for $99 + tax.
  5. Lunch!
  6. Purchasing doesn’t grant access immediately, but I receive my activation within about an hour.
  7. Download XCode 4.2 for Snow Leopard this time!
  8. Download and set up Git
  9. Fork and clone MonoGame. It’s still under very active development, so I choose to fork rather than just download a copy. Maybe I’ll be able to contribute!
  10. Install Mono itself (which is the analog to the .NET framework SDK in my head)
  11. Install MonoDevelop (IDE analog to Visual Studio)
  12. Don’t install MonoMac Add-in for MonoDevelop, because it appears to already be installed!
  13. Download MonoMac samples for playing with later from Github
  14. Download MonoGame samples for playing with later from Github
  15. Build some of the MonoMac samples and play with them. No problems there! That’s .NET on a Mac then. Easy peasy!
  16. Build some of the MonoGame samples and play with them. Some strange changes are needed in order to make them work, but nothing too absurd. XNA on a Mac! Easyish peasyish!

    PerPixelCollision sample, running on a MacBook. Nifty.

  17. Running an already ported sample is nice, but it’s time to try my hand at porting something “from scratch”. My target is the SpriteSheetSample, which is a relatively small and simple set of projects for a Content Processor, a runtime class and a sample game putting it all together. Should be easy! Roughly:
    1. Create a new solution file
    2. Add in the existing MonoGame framework and Lidgren projects, ensuring the former properly references the latter.
    3. Create new MonoMac projects for the SpriteSheet (runtime library) and SpriteSheetSample (sample game) projects. Make sure they reference MonoGame.
    4. Add some compiler defines like MONO and MAC so I can conditionally compile everything and only keep one copy of the files
    5. Set up the new Program.cs to launch the game the Mac way
    6. Copy over the already-built .xnb files from my Windows machine (I don’t keep these in source control)

    This is a bigger hassle than it sounds. I need an automated solution (“Create Copy for Mac”).

  18. Build and run! Doesn’t work. Or even crash.
    Eventually discover the “Application Output” window and see “Unable to load nib file MainMenu”. Turns out I’ve missed one of the steps in the tutorial and didn’t add an empty interface called MainMenu. This is one of those strange things I was talking about earlier.
  19. I use Mercurial for my projects, so update .hgignore to include:
    – *.DS_Store
    – *.pidb
    This is another thing to automate.
  20. Compiles! Yay! Runtime error! Boo! It’s an error drawing the spritesheet. Looks like the SpriteSheet object is non-null, but fields are null. WTF? Clearly something went wrong during the content load.
  21. Crisis! The debugger does not work! Stepping through code highlights nonsensical lines like comments and destructors when the callstack clearly shows otherwise. This is not workable at all. After restarting and googling the debugger problem, I come up empty.
  22. I decide to check if I can solve the content load problem itself. After some more googling, I find some misleading info about a lack of ExternalReference support in the ContentManager of MonoGame. This eventually proves to be a red herring and is a lesson in making sure your tools work so that you can properly identify the true problem.
  23. Eventually, I manually clean all the projects in my solution (the “Clean All” command was/is failing) and the debugger resumes working. Victory!
  24. From here, it’s a straightforward case of stepping through the content load methods. I discover that non-public fields are not being populated even when marked with the [ContentSerializer] attribute. Easy fix!
  25. Victory!

    It's a cat! And a spritesheet.

  26. With everything in place and working, I push my changes to my repository.
  27. Then I pull them down to Windows machine and check that everything still works.
  28. Everything still works. Done!

A little bumpy, a bunch of rough edges, but I ported something written in XNA to the Mac. What’s more, I kept it in one set of files, so it’s essentially the same as working with a copy for Xbox 360. There are definitely some opportunities to streamline the workflow though.

So the next steps are:

  1. Port another small library/sample to get the hang of what needs to be added/changed/reference/etc in a Mac copy of a project.
  2. Devise some way of automating this part of the process. Maybe.
  3. Come up with a good solution for keeping content in sync for Mac builds. I’m find with building everything on my Windows machine, but I don’t want built content in source control. It would work if I was using something like Perforce, but Hg (or Git for that matter) just isn’t suited to the task. Perhaps a simple rsync script. Moving forward, maybe a Dropbox solution.
  4. Find a desktop layout that works. As in, my physical desktop. Working on Macbook is uncomfortable, especially when it’s in front of my PC’s monitors.

For giggles, I’m going to try to keep a running total of time and money invested in this little adventure.

Running total: 2 days, $112.87