Friday, January 20, 2017

Candy Kid WiX Installer

Candy Kid is a simple maze chase video game written in XNA using C#/.NET. All development was done on Windows therefore it made sense to build a PC version of the game to be published available for sale.

In order to build all binary files plus game content into a single deployable package, the Windows Installer XML [WiX] toolset was used. WiX is free software that builds Windows Installer packages from XML code.

Let's check it out!

Pre Requisites
First, obtain Candy Kid release build complete with game executable, managed assemblies and content:
 Folder  Content  All game content
 File  log4net.dll  log4net logging
 File  Ninject.dll  IoC Container
 File  WindowsGame.exe.config  Game configuration
 File  WindowsGame.exe  Game executable
Next, download WiX Installer here. Note: post is based heavily on the XNA Installer published by Cygon!

Implementation
Launch Visual Studio. File | New Project... | Windows Installer XML | Setup Project | CandyKidInstaller. Uncheck Create directory for solution. Delete Product.wxs and copy the following folders as per Cygon:
 Folder  Description
 Content  Candy Kid release build (as above)
 Documents  Includes license.rtf document only
 References  Includes the 2x Nuclex.Setup DLLs
 Resources  Includes all bmp, ico, and png files
 Source  Installer (wxs) + Include (wxi) files
Note: C:\Program Files (x86)\SharpDevelop\5.1\data\resources\InstallerBitmaps required in Resources.

Actions
Right click project name | Properties | Output name: RetroCandyKid. Next, action these following tasks: Note: anytime you need a GUID choose Tools menu | Create GUID | 2. DEFINE_GUID | New GUID | Copy
  • Add the Program Menu
  • Add Desktop Shortcut
  • Add the Program Files
  • Harvest content folder

Program Menu
Add this change to Files.wxs. This blob of XML is responsible to set Program Menu entry once installed. Important: make note of the Component Id as this will be used in Setup.wxs for Feature ComponentRef.
<Directory Id='ProgramMenuFolder' Name='Programs'>
<Directory Id='MyGameProgramMenuFolder' Name='Retro Candy Kid'>
        <Component Id="StartMenuEntriesComponent" Guid="{GUID}" DiskId="1">
                <RemoveFolder Id='MyGameProgramMenuFolder' On='uninstall' />
                <RegistryValue
                        Root='HKCU'
                        Key='SOFTWARE\SteveProStudios\RetroCandyKid'
                        Name="ProgramMenuFolder"
                        Type='string'
                        Value='Installed'
                        KeyPath='yes' />
        </Component>
</Directory>
</Directory>

Desktop Shortcut
Add this change to Files.wxs. This blob of XML is responsible to set the Desktop shortcut once installed. Important: make note of the Component Id as this will be used in Setup.wxs for Feature ComponentRef.
<Directory Id="DesktopFolder" Name="Desktop">
        <Component Id="ApplicationShortcutDesktop" Guid="{GUID}">
                <Shortcut
                        Id="ApplicationDesktopShortcut"
                        Name="Retro Candy Kid"
                        WorkingDirectory="INSTALLDIR"
                        Icon="ProductIcon.ico"
                        Target="[INSTALLDIR]WindowsGame.exe" />
                <RemoveFolder Id="DesktopFolder" On="uninstall" />
                <RegistryValue
                        Root="HKCU"
                        Key='SOFTWARE\SteveProStudios\RetroCandyKid'
                        Name="DesktopFolder"
                        Type="integer"
                        Value="1"
                        KeyPath="yes" />
        </Component>
</Directory>

Program Files
Add this change to Files.wxs. This blob of XML is responsible to install the executable and all assemblies. Important: make note of the Component Id as this will be used in Setup.wxs for Feature ComponentRef.
<Directory Id="ProgramFilesFolder" Name="PFiles">
<Directory Id="INSTALLDIR" Name="RetroCandyKid">
<Component Id="MyComponent" Guid="{GUID}" DiskId="1">

<File Id="WindowsGameExe" Name="WindowsGame.exe.config"
          Source="$(sys.SOURCEFILEDIR)/../Content/WindowsGame.exe.config" />
<File Id="log4netdll" Name="log4net.dll"
          Source="$(sys.SOURCEFILEDIR)/../Content/log4net.dll" />
<File Id="NinjectDll" Name="Ninject.dll"
          Source="$(sys.SOURCEFILEDIR)/../Content/Ninject.dll" />

<File Id="GameExecutable" Name="WindowsGame.exe" KeyPath="yes"
          Source="$(sys.SOURCEFILEDIR)/../Content/WindowsGame.exe">
         <Shortcut
                Id="MyGameShortcut"
                Name="Retro Candy Kid shortcut"
                Directory="MyGameProgramMenuFolder"
                Advertise="yes"
                WorkingDirectory="INSTALLDIR"
                Icon="ProductIcon.ico" />   
</File>
</Component>
</Directory>
</Directory>

Harvest Content
In order to copy the Content directory to the install folder, use the Wix "Heat" application to harvest the directory. The Wix Harvest Tool (Heat) generates the required fragment into its own Installer (wxs) file.

First, ensure that Wix Toolset is included in Environment PATH. Control Panel | Advanced system settings. Environment Variables | Path | Edit | Add install directory: C:\Program Files (x86)\WiX Toolset v3.10\bin

Next, launch Command Prompt and harvest content from Game executable level beneath Content folder: heat dir . -o MyHarvestedStuff.wxs -scom -frag -srd -sreg -gg -cg MyComponentGroupId -dr INSTALLDIR

Find and replace in wxs file Source="SourceDir\ to Source="$(sys.SOURCEFILEDIR)\..\Content\
Finally, remove all top entries with Directory="INSTALLDIR". Make note of the ComponentGroupRef Id.


Setup.wxs
Main entry point: update Product XML blob and complete the Feature list as per the components (above). Ensure you have ProductIcon value set as Icon for shortcut and Icon displayed in Add/Remove programs!
<Product Id="{GUID}"
         Name="Retro Candy Kid"
         Language="1033"
         Version="1.0.0"
         Manufacturer="StevePro Studios"
         UpgradeCode="{GUID}">

<Property Id="ALLUSERS" Value="1" />
<Property Id='ARPPRODUCTICON' Value='ProductIcon' />

<Feature Id="MyFeature" Title="Required Files" Level="1">
        <ComponentRef Id="StartMenuEntriesComponent" />
        <ComponentRef Id="ApplicationShortcutDesktop" />
        <ComponentRef Id="MyComponent" />
        <ComponentGroupRef Id="MyComponentGroupId" />
</Feature>

<!-- Includes the user interface definition defined in another file -->
<UIRef Id="UserInterface"/>
<Icon Id="ProductIcon" SourceFile="$(sys.SOURCEFILEDIR)/../Resources/Game.ico" />
<Icon Id="ProductIcon.ico" SourceFile="$(sys.SOURCEFILEDIR)/../Resources/Game.ico" />
</Product>

UserInterface.wxs
Update the relative location for "Default dialog resources for the setup" bitmap files e.g. banner and info:
 Binary  Source
 dialog.bmp  $(sys.SOURCEFILEDIR)/../Resources/InstallerBitmaps/default-dialog.bmp
 banner.bmp  $(sys.SOURCEFILEDIR)/../Resources/InstallerBitmaps/default-banner.bmp
 info.bmp  $(sys.SOURCEFILEDIR)/../Resources/InstallerBitmaps/info.bmp
 up.bmp  $(sys.SOURCEFILEDIR)/../Resources/InstallerBitmaps/up.bmp
 new.bmp  $(sys.SOURCEFILEDIR)/../Resources/InstallerBitmaps/new.bmp

Build
Finally, build WiX Installer from within Visual Studio to generate the MSI package RetroCandyKid.MSI.
Download source code here.

Summary
Double click to RetroCandyKid.MSI to install. Ensure there is a Program Menu entry + Desktop shortcut!
Retro Candy Kid is also in Programs and Features and could be uninstalled; not that you would want to J

Sunday, January 1, 2017

Retrospective VIII

Last year, I conducted a simple retrospective for 2015. Therefore, here is a retrospective for 2016.

2016 Achievements
  • Complete first Sega Master System video game 3D City using C/Z80 assembler
  • Enter 3D City into Sega Master System annual coding competition for this year
  • Complete Retro Candy Kid blog topics such as Press Release and WiX Installer
  • Integrate IPv6-only Networking into Unity3D code base using the Lidgren API
  • Document SVN Externals to scale out single game code library across clients
  • Create repositories on GitHub and publish source code from various projects
  • Scale Push Notifications application across iOS / Android improved efficiency
  • Transition existing C++ OpenGL tutorial studies to new Vulkan graphics API
Note: reviewed game project in C / Z80 assembler for Sega Master System is an achievement!

2017 Objectives
  • Complete another Sega Master System video game that can run on real hardware
  • Integrate Git Submodules similar to SVN Externals to scale out code across clients
  • Evaluate monetization plugins for MonoGame / XNA game projects e.g. Purchases
  • Check out opportunity to incorporate Virtual Reality in Unity3D game engine code

2016, as every Virtual Reality evangelist will tell you, was the year of VR. Game Engines such as Unity5 attempt to ease development transition to VR by adding Virtual Reality Supported checkbox to Settings. However, repairing breakages from Unity4 to Unity5 game project upgrade is often challenging enough.

Homebrew
Outside commercial game development, homebrew projects continue to be very popular: SMS Power hosted its annual Sega Master System coding competition and attracted more than two dozen entries.

This provided great opportunity to complete first Sega Master System video game 3D City using z88dk. Unfortunately, the game runs only in emulator. R+D has begun to ensure games run on real hardware.

Summary
Another busy year coding from Z80 assembler to C/C++ to C#/.NET certainly does keep life interesting!