When Unity 4 was released I was able to continue to provide support for Unity 3 by tweaking logic so that it would satisfy both of the releases of Unity and in a couple of circumstances to use reflection to transparently select between Unity 3 and Unity 4 APIs. This mainly affected editor logic and so it was possible to get JIT compiled delegates to make the reflected invocations more efficient.
With Unity 5 there were quite a number of significant changes which made it very difficult for me to provide support for Unity 4 and Unity 5 with a single set of compiled assemblies. In addition to this the asset file format was no longer backwards compatible which made it difficult to maintain the demonstration assets.
I decided to restructure the Visual Studio solution so that the Unity 4 and Unity 5 distributions have their own separate assets and compiled assemblies. The assemblies are still compiled from a single code base by taking advantage of one of the more recent Visual Studio features… shared projects. Here is what the solution looks like:
There is a project representing each of the compiled assemblies which defines the set of
macros (for example,
UNITY_EDITOR, etc) to support conditional compilation.
The main code base is defined using shared projects which are referenced by each of the
Starting with Unity 5 it’s possible to build a separate runtime assembly for use in-editor and for final builds. This is consistent with the approach that Unity are using with their open source uGUI module.
Finally there are two empty projects whose purpose is to assist with the building process. The “PostBuildProject” is entirely empty and has no build events; this is marked as the default project and depends on all of the other projects. This is useful since the entire solution can be built in the correct order by rebuilding this one project.
All of the projects in the solution depend upon the “PreBuildProject” project allowing pre-build events to be undertaken before any of the projects are built. This automates various things such as updating assembly version numbers, showing the git commit hash in the about window, deploying localization files; updating libraries, etc.
The project build order is resolved by Visual Studio in the following way:
The solution’s directory structure looks something like this:
rotorz-tile-system/ |-- _private/ |-- Deploy/ | |-- Unity 4/ | | |-- Assets/ | | | |-- Rotorz/ | | | | |-- Common/ | | | | | |-- (various assets) | | | | |-- Tile System/ | | | | | |-- (various assets) | |-- Unity 5/ | | |-- Assets/ | | | |-- Rotorz/ | | | | |-- Common/ | | | | | |-- (various assets) | | | | |-- Tile System/ | | | | | |-- (various assets) |-- Documentation/ | |-- (api reference) | |-- (user guide) |-- Libraries/ | |-- (internal assemblies and tools to merge into deployed assemblies) |-- Localization/ |-- Source/ | |-- Build/ | | |-- PostBuildProject/ | | |-- PreBuildProject/ | |-- Distributions/ | | |-- Unity 4/ | | | |-- TileSystem.Editor_Unity4/ | | | |-- TileSystem.Runtime_Unity4/ | | |-- Unity 5/ | | | |-- TileSystem.Editor_Unity5/ | | | |-- TileSystem.Runtime_Editor_Unity5/ | | | |-- TileSystem.Runtime_Standalone_Unity5/ | |-- Main/ | | |-- Common/ | | |-- TileSystem.Editor/ | | |-- TileSystem.Runtime/ | |-- Rotorz Tile System.sln |-- .editorconfig |-- .gitattributes |-- .gitignore |-- build.js |-- package.json (node.js is used to automate various tasks) |-- README.md
Outputs are then exported as two separate asset packages; one exported using the latest release of Unity 4 and the other using the latest release of Unity 5.
For each submission to the Unity asset store I create a blank Unity 4 and Unity 5 project; import the freshly baked packages along with the “Asset Store Tools” package for the submission process. Whilst this last part could be automated, I find that it is useful to go through this process manually each time since it allows me to verify that the asset imports without any errors.