Wednesday, June 1, 2016

SVN Externals Application

In 2015, Candy Kid was written in XNA as a simple maze chase video game. The majority of game code was written in an external library and scaled out across multiple game clients including Android and iOS. In order to avoid problems with Copy + paste programming to multiple clients, SVN Externals was used.
Let's check it out!

SVN Externals allow an Subversion repository to be checked out within a directory in that working copy. Here all common code in external repository linked through "Common" directory across multiple clients.

Pre Requisites
This post assumes you already have Tortoise SVN installed on Windows and svnx installed on Mac OS/X.
Also, consider configuring the $SVN_EDITOR on Windows and Mac OS/X in order to edit SVN properties:
set SVN_EDITOR=notepad.exe     ; Windows PC
export SVN_EDITOR=vi           ; Mac OS/X
Conventions
This post uses the following convention to substitute "$DEMO" for root node of all demo code samples:
$DEMO = https://svn/Demo       ; Subversion
$DEMO = C:\svn\Demo            ; Windows PC
$DEMO = /svn/Demo              ; Mac OS/X
Example
As an example, let's scale the XNA and System Testing snake simulation to demonstrate SVN Externals. Create top level Demo node in Subversion SVN. Add 1x sub-node for XNA library and 4x sub-nodes for each client: WP7, Windows, Android, iOS. Ensure all sub-nodes have branches, tags and trunk folders:
 Alias  Platform  Development  Framework  Description  Source Code
 XNA  Windows PC  Visual Studio 2010  XNA 4.0  Game library  Download
 WP7  Windows PC  Visual Studio 2010  XNA 4.0  Game client  Download
 Win  Windows PC  Visual Studio 2012  MonoGame 3.4  Game client  Download
 And  Mac OS/X  Xamarin Studio  MonoGame 3.5  Game client  Download
 iOS  Mac OS/X  Xamarin Studio  MonoGame 3.5  Game client  Download

Sample
The following code sample builds the snake simulation initially as an XNA solution. After the code sample has be fully tested in isolation, additional clients are added to share "Common" code using SVN Externals.

XNA Game library [PC]
Launch Visual Studio 2010. Create blank solution. Add the following 4x new C#/.NET projects to solution:
 Project  Type  Dependencies  Description
 XNA  XNA 4.0 Game  XNA.Common  Entry point and game specific code
 XNA.Common  XNA 4.0 Game Library  log4net | Ninject  Generic game library for all clients
 XNA.SystemTests  Windows Class Library  NUnit [only]  Used for game library system tests
 XNA.UnitTests  Windows Class Library  NUnit | Rhino Mocks  Used for game library unit tests
Important: create a directory symbolic link using mklink to Content folder in order to run system tests.
// mklink /D C:\SnakeDemo.XNA.Content C:\SnakeDemo.XNA\bin\x86\Debug\
protected const String CONTENT_ROOT = @"C:\SnakeDemo.XNA.Content\";

Notes
Common project properties include: Treat warnings as errors "All" + Release version Debug Info "none".
Manually edit system and unit test projects in Notepad and add following XML to mitigate MSIL warning:
<PropertyGroup>
  <ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>None</ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>
</PropertyGroup>

WP7 Game client [PC]
Launch Visual Studio 2010. Create Windows Phone Game 4.0 project. Include all relevant game content.
Use SVN Externals to link common XNA library game code (above) through "Common" directory in client:

In Windows Explorer, navigate to $DEMO\WP7\trunk\$FOLDER where $FOLDER is the parent folder that hosts Windows Phone Game 4.0 project. This is where SVN Externals will link common XNA library code.

Right click $FOLDER | Tortoise SVN | Properties | New... | Externals. In popup window click New button:
 Local path:  Common
 URL:  $DEMO/XNA/trunk/XNA.Common
 HEAD revision  Checked
 Peg:  empty
Note: an optional SVN revision number can be entered in "Peg:" textbox to pin to static code check-in.

Right click $DEMO\WP7\trunk | Tortoise SVN | Check for modifications. Commit change made from SVN Externals. SVN Update to download "Common" directory from $DEMO\XNA\trunk\XNA.Common in WP7.
cd $DEMO\WP7\trunk
svn propget -R svn:externals
svn commit -m "Add SVN Externals"
svn update
Finally, in Visual Studio 2010 click "Show All Files" button. Right click "Common" directory | Include In Project. Build project. Right click $DEMO\WP7\trunk | Check for modifications. Commit changes made. Done!

iOS Game client [Mac]
Launch Xamarin Studio. Create MonoGame iPhone/iPad Application. Include all the relevant game content.
Use SVN Externals to link common XNA library game code (above) through "Common" directory in client:

Launch terminal prompt, navigate to $DEMO/iOS/trunk/$FOLDER where $FOLDER is the parent folder that hosts MonoGame iPhone/iPad Application. This is where SVN Externals will link common XNA library code.

Type in the following SVN commands:
cd $DEMO/iOS/trunk/$FOLDER
svn propget svn:externals

svn propset svn:externals 'Common $DEMO/XNA/trunk/XNA.Common' .
svn propget svn:externals

svn status
cd $DEMO/iOS/trunk
svn commit -m "Add SVN Externals"
svn update
Finally, in Xamarin Studio right click solution | Display Options | Show All Files. Right click "Common" directory | Include To Project. Build project. In svnX, Check for modifications. Commit changes made. Done!

Repeat this process for the remaining projects: Windows Game client [PC] + Android Game client [Mac]

Jenkins
Don't forget to uncheck "Ignore externals" under Subversion modules on all the automated client builds!

Summary
To summarize, SVN Externals has proved effective to scale common game code linked to multiple clients. However, all code here is in trunk; larger scale development requires release tags and feature branches.

This will be topic in the next post.