Monday, May 17, 2021

Content Versioning

Version numbers are like opinions: everybody has one, they tend towards the majority, or you're a madman who thrives in utter chaos. The programmer side of life tends towards regimented, structural numbers, and the marketing side sees a version number as a way to show progress or change in their project.
 
Small video games or projects that constantly change in early development tend to have version numbers that don't make a lot of sense. It may not be feasible to keep track of a version in a way that makes sense to a machine. Projects can get pretty wild before they've been scoped out and defined even with the best idea behind them.

This gets even more complicated when you throw in mods. Do mods need to include the game version they're built against in the version itself? If the mod works on a range of acceptable game versions, does it need to include that? What about addons for tabletop games? Hacks? Total conversions? Grafting an entire game onto another game?

I developed this versioning format to try and sort out some of the weirdness and incompatibility that comes with rapidly creating content on top of systems and then gutting the entire thing because the core of your design is good, but the implementation is horrid.

This format works best for alpha or beta projects before their full release. Projects that are content heavy, like video games, benefit the most. Marketing may like the nice feeling of a 1.0 public release or a continual push towards the future, but this format has an advantage that no others do: the version history itself can tell a story of development, of progress, and of change.

Content Versioning

Format: MAJOR[DEVELOPMENT_PHASE].SYSTEMS.CONTENT.PATCH/TEST

Example: A.6.2
Example 2: 3A.4.17.340
Example 3:
(1.16).4.1

Major Version: The intended version of the project you're working on. Generally, this will be your first project. The first version can either be 1 or 0 until there's a full release of the game.

The major version number is optional before a full release. It's most useful when the project you're working on is a sequel to another project. A or B at the beginning of the version is painfully obvious that this is not a completed project.

Major version is also a good place to put a game's version. Minecraft tends to change itself every 6 months or so and Windows 10 breaks drivers like clockwork.

Development Phase: These are usually referred to as "alpha", "beta", or "release", with the occasional extra step such as release candidates. This can also be arbitary; replace the letter as the project moves from phase F to G in its nine-phase development outline.

Systems: The most useful number for programmers. The number represents how many working modules of code, gameplay dynamics, or miscellaneous systems are currently working as intended. 

A simple platformer may have a character, level, and UI system. Complicated games will have systems built on top of systems and the layers themselves will interact in multiple ways. This number will naturally go up quickly at the beginning of a project and level off towards the end.

Content: This number relates to the amount of content in the game. Divide up the game into bite-sized pieces and increment the counter when one of them gets made. 

Made a new enemy for a level? Bump up the content number. Your custom crafting system had a significant amount of new content put in that is going well? Bump it up some more. Finish off the final boss in the game? Bump it twice for good measure.

For good measure, keep track of how much content each bite actually takes up. Refining a level or a content system can make the number go up, down, sideways, down some more, and shoot way up on a day of inspiration. Try not to make this number go down after release or you will have people asking a lot of questions; version numbers only go up, after all.

Patch/Test:  

Before release: You released a new test version or wanted to make a build just for the sake of it? Number goes up. No thought required.

After release: Something broke, you just wanted to make a couple small changes, or forgot a readme file. These changes don't change the project substantially, so the number goes up. This number resets any time the systems or content increments.

The content, systems, and test numbers work independently from each other. Content and systems are often related no matter what type of project you're using, but sometimes you'll develop the entire system before touching one drop of content and other times two groups will work on the entire project in parallel.

Detailed Example: Tinkers Construct 1

Tinkers' Construct 1 was the main source of frustration with versions. Let's apply this system to the mod retroactively and see where we end up. From the top:

The initial public release had three systems: Tool Core, Modification, and Crafting. Content would be broken down into rough chunks of swords, other tools, tables, patterns, and a couple more for modifiers. The initial release was on Minecraft v1.4.7... so the mod would have a version of 
 
Initial version: 1.3.6
 
The first release was botched pretty badly; I ended up hotfixing it 8 times before adding more content. 
 
Hotfix version: 1.3.6.8
 
There was a bit more development to flesh out modification and the tools with a proper release every two weeks. Add in another system to make auto-smelting, fortune, or silk touch on tools and carry on.

Midpoint version: 1.4.14.2

The second major release was a continuation of the project. There's a new idea in town: The Smeltery. This took a very long time to build and involved multiple new systems: structure creation, alloying, casting, fluids, networking, and broad tools. Content amount goes up in spades and the mod obtains an inordinate amount of content compared to before.

Smeltery release: 1.9.30

That's a huge jump in systems and a rather large jump in content. It took 6 months to sort out all the bugs, finish up content, and get everything moving smoothly.

Smeltery endpoint: 1.9.38

At this time I had switched to a content-driven development format. The version was bumped up to "1.3.0" from its "1.2.18" point, but there was no real reason for that. I just wanted to make a whole lot of things after spending so much time on systems. There was also the odd problem with armor being wanted, and I tried adding a system for that... but it was not exactly great. I had to add things and rip them out multiple times.

Content start: 1.10.40

The overall quality of the mod went up over this time. Things were refined and polished in a way that hadn't been done before. Most of the systems were already made; it was time to add the rest of the things on top of that.

Final version: 1.10.70
 
This version history tells a much different story than the butchered semantic versioning that I was using before. There wasn't a real rhyme or reason behind anything. The number was detached from the source, and while it was still useful to compare and see whether things were out of date, it wasn't useful beyond that.

Let's compare against the two most common versioning systems:

Semantic Versioning

Semantic versioning is great for keeping track of a particular version in a project. Its best use is for libraries or similar files that code or documentation depends on. You know immediately if your code is out of date, or if the library you're using is going to work at all.

SemVer has a very mechanistic view on how its versions should be described. The format is simple: MAJOR.MINOR.PATCH.BUILD
  1. MAJOR version when you make incompatible API changes,
  2. MINOR version when you add functionality in a backwards compatible manner, and
  3. PATCH version when you make backwards compatible bug fixes.
  4. BUILD version when a program attempts to compile a nightly build
Projects with automatic build systems need more information. BUILD is an extension of this format, but is usually left out on releases.
 
jashkenas has a good writeup on why semantic versioning is not semantically sound. In short, the version format compresses too much information into a single three-number phrase and doesn't take into account the human factor. It's not good for dynamic systems that are constantly changing.

Calendar Versioning

Some software is updated regularly. Some companies have taken this idea and incorporated it directly into their version numbers. If a piece of software has a major change once per year, then it has a larger number to match. EA games such as FIFA or Madden, Adobe products, and Ubuntu releases follow this mold.

CalVer takes a temporal view on how its versions are described. Let's take a look at Unity3D's format: 2018.4.35f1
  • Major - Calendar Year. Unity used 1-5 for its calendar version up until 2017, which switched the version number itself to the year.
  • Minor - Changes. Unity uses this for new systems that tend to change or break things.
  • Micro - Patch. Small but significant changes like bugfixes.
  • Modifier - An optional text tag, such as f1 for "final/hotfix on version 35". Unity has one of these on every build (usually f1, but people make mistakes)
The date may end up directly in the version number somewhere, usually the major number. Other times the number will be incremented automatically each time the date switches over.
 
This format is great for long-term projects with a regular release cycle and a marketing team behind it. The larger and longer-lived the project is, the more benefit they will find in the consistency of time.
 

Final Thoughts

Content Versioning is best used on projects that have an erratic development process or lean heavy into content like video games. The version itself holds more meaning than an increment in the development process and can be used to gauge how the project is going. It is best used where other version formats are inappropriate or are a poor fit. 

I use this format for game development. It's a far cry from the mechanical incrementation of SemVer, and who in their right mind would use a calendar format on a project that isn't even released yet? The format is a tool, and like all tools they have a time and a place where they are best used.

I may carry this format into full release later. I'm not sure if I'm going to have an external version of 1.0 alongside an internal version of 1.40.3249 on any future projects; we'll see when we get there.

No comments:

Post a Comment

Self Reflection, Avatar Reflection

It started as a joke. One day I decided that my game development was going poorly because I was too attached to my characters. If I messed a...