• Hey Guest! Ever feel like entering a Game Jam, but the time limit is always too much pressure? We get it... You lead a hectic life and dedicating 3 whole days to make a game just doesn't work for you! So, why not enter the GMC SLOW JAM? Take your time! Kick back and make your game over 4 months! Interested? Then just click here!

How do you treat your version numbers?

kupo15

Member
Its not quite programming related but it stills seems like an important topic for serious developers. Since starting my android dev stuff and the playstore requiring unique version numbers, I've been mindlessly incrementing my patch number (0.0.x) apparently. Had no idea what each value is "supposed" to be, I just knew that I wanted my first public release to be 1.0.0.

What is your convention for version numbers? Apparently the semantic convention is (x.y.z)
X major release that is not backwards compatible
Y is new functionality that is backwards compatible
Z is simply patches or bug fixes that is backwards compatible

I'm still in the dev phase, how do you treat your version numbers in the dev phase? I just went through a major update changing how I save/load data which would definitely denote a MAJOR (x) release if this were public. I guess the sensible thing to do is to combine Major/Minor into the same Y? Or would it be better to do 0.Major.Minor/patches? What are your conventions between dev and public versions?

Learning about this is really cool, I've always been ignorant to the meaning of version numbers and had no idea what they meant but now I realized how much information they convey and how important to your customers having a good convention for them is. Its more than mindlessly incrementing numbers.

I thought this would be a good topic to bring up in this forum to establish better developing practices. If its better suited for Design board or another one, feel free to move it!
 

Flaick

Member
I don't care about version until i release the game on Play Store. When in test/alpha/beta stage i put a 0.9.x number, when released public i set 1.0.0. In test/alpha/beta is required by Play Store, otherwise it thinks is all the same version.

For Steam is less complicated. 1.0.0 when released, otherwise you can put any number you want. Steam works with depos/builds.
 
D

Deleted member 45063

Guest
Personally during development of something publicly released I usually use 0.x.y where x is incremented on any major/minor change and then have a disclaimer stating that versions below 1.0.0 are to be considered unstable and breaking changes may happen without further notice. If I'm developing something that's not released publicly I generally don't care about versioning. Also for games it becomes blurry since what would normally be a breaking change in a library might not be in a game (changing how you name scripts for a game does not affect how it works, but for a library it means the whole API was changed). So in the end the versioning scheme is somewhat fluid when it comes to games for me and I just try to be somewhat consistent even if not adhering to the intended semantics of version numbers.
 

Sabnock

Member
i just use the current date for instance projectname.10.0.2020

or if there is a major change or version i want to go back to quickly i might put a more descriptive file name
 

kupo15

Member
I don't care about version until i release the game on Play Store. When in test/alpha/beta stage i put a 0.9.x number, when released public i set 1.0.0. In test/alpha/beta is required by Play Store, otherwise it thinks is all the same version.

For Steam is less complicated. 1.0.0 when released, otherwise you can put any number you want. Steam works with depos/builds.
Ah interesting. So you really don't care what the version is even when you have it on the Playstore in a/b/internal testing phase so long as it is below 1.0.0. If you had testers and during this phase you decided to overhaul the data save/loading system that would completely break past versions, would you simply just document that in the update notes and not apply a meaningful version number? Would you apply a meaningful Major release increment only during > 1.0.0 public releases then?

Personally during development of something publicly released I usually use 0.x.y where x is incremented on any major/minor change and then have a disclaimer stating that versions below 1.0.0 are to be considered unstable and breaking changes may happen without further notice. If I'm developing something that's not released publicly I generally don't care about versioning
That's an interesting approach! So do you typically lean towards just incrementing the patch slot as I do during developing and not touch the minor version? For me it seems like it would be a good idea to get used to putting some thought in my versioning even during dev just to get in the habit so I would like to utilize both 0.x.y. Just not sure how yet haha

Also for games it becomes blurry since what would normally be a breaking change in a library might not be in a game (changing how you name scripts for a game does not affect how it works, but for a library it means the whole API was changed). So in the end the versioning scheme is somewhat fluid when it comes to games for me and I just try to be somewhat consistent even if not adhering to the intended semantics of version numbers.
Oh that makes sense and also illuminated more about what things actually mean and what is typically done. For example, I've definitely redid scripts completely and sometimes other scripts rely on but the end result is the same. Did not know that typically this would constitute as something major to document and increment but I guess its a "duh" moment for me haha Being a one man programmer you're right it doesn't make sense to treat this any differently I guess.

At the tech corporation where my friend works, it's major.minor.patch.subpatch.subpatch... [goes on indefinitely]...
Sounds like a nightmare!!
 
Last edited:

Flaick

Member
Ah interesting. So you really don't care what the version is even when you have it on the Playstore in a/b/internal testing phase so long as it is below 1.0.0. If you had testers and during this phase you decided to overhaul the data save/loading system that would completely break past versions, would you simply just document that in the update notes and not apply a meaningful version number? Would you apply a meaningful Major release increment only during > 1.0.0 public releases then?
Yes i don't really care cause i'm a SOLO developer, and i have only 4-5 testers (all friends of mine). I simply increment the number by x.x.1 and tell them there is an update. I use Steam and Play store so they always have the lastest version.
When the game is released i use 1.x.x to keep track of patch notes for final users.
For larger team i presume the version number will become more important.
 
D

Deleted member 45063

Guest
That's an interesting approach! So do you typically lean towards just incrementing the patch slot as I do during developing and not touch the minor version? For me it seems like it would be a good idea to get used to putting some thought in my versioning even during dev just to get in the habit so I would like to utilize both 0.x.y. Just not sure how yet haha
No, in this case I would still increment both minor and patch versions, except that I would "shift" the intended meaning:

For 0.x.y and a.b.c (where a > 0) then x would have the same meaning as a and y would have a "combined" meaning of b and c.

EDIT: I do this since during development there are bound to me many more breaking changes than during normal releases, so that's where I focus on having a clear distinction.
 
Last edited by a moderator:

kupo15

Member
Yes i don't really care cause i'm a SOLO developer, and i have only 4-5 testers (all friends of mine). I simply increment the number by x.x.1 and tell them there is an update. I use Steam and Play store so they always have the lastest version.
When the game is released i use 1.x.x to keep track of patch notes for final users.
For larger team i presume the version number will become more important.
Yeah that makes complete sense to me and I agree the bigger the team the more important it'll probably be. For me right now, I would like to try to establish something even as a solo dev just to have practice with it and develop some good habits and to have an easily viewed history. Just not sure exactly the best method

For example, I just released an internal build on the Playstore after a major save/load overhaul that breaks previous versions. Then I realized I made a small mistake that would crash on startup. Now I have 0.0.11 and 0.0.12 back to back. Since I've only been using 0.0.x it seems like a somewhat significant update when it merely was a hotfix. I feel like it would have been better to have 0.1.0 (bugged) then correct it with 0.1.1 with the hotfix.

This of course means nothing since its just me an one other friend but its like a personal thing to be a better labeler. But I go through so many new features in this phase that if I treated 0.0.x as simply the patch then the 0.x.0 would be a high number. I wish we had 4 places to work with haha maybe I'm able to do like 0.M.m-patch for internal development
 
Last edited:

Flaick

Member
Ok. But don't waste too much time on this thing. It's up to you the choise of which kind of version number use. In your example i'll personally use 0.0.13. The meaning of "significant update" will change when project grown :)
 

kupo15

Member
Ok. But don't waste too much time on this thing. It's up to you the choise of which kind of version number use. In your example i'll personally use 0.0.13. The meaning of "significant update" will change when project grown :)
True, and when more people are added to it and stuff. Yep, I shouldn't put too much energy into it, its an interesting thought experiment nonetheless :)

No, in this case I would still increment both minor and patch versions, except that I would "shift" the intended meaning:

For 0.x.y and a.b.c (where a > 0) then x would have the same meaning as a and y would have a "combined" meaning of b and c.
Got it, makes sense and is the way I'm leaning towards. I wonder if we can add dashes in there. In my above example it would make more sense to have 0.1.0-1 since I also added new features and stuff at the same time. Then I would have had 0.1.0 to denote a major upgrade plus minor feature improvements. Then 0.1.0-1 to show a patch to that.

Of course this all doesn't really matter in the grand scheme of things during dev as you said. But at the moment, I'm reluctant to compile a new build solely for patches since my conventions have been too coarse. I've usually been saving a compile for more minor revisions and bundle up patches in there.
 
D

Deleted member 45063

Guest
Got it, makes sense and is the way I'm leaning towards. I wonder if we can add dashes in there. In my above example it would make more sense to have 0.1.0-1 since I also added new features and stuff at the same time. Then I would have had 0.1.0 to denote a major upgrade plus minor feature improvements. Then 0.1.0-1 to show a patch to that.
If you abide by SemVer semantics then adding dashes would be seen as the "pre-release" portion, so x.y.z-a.b.c would be perfectly valid.
 

kupo15

Member
If you abide by SemVer semantics then adding dashes would be seen as the "pre-release" portion, so x.y.z-a.b.c would be perfectly valid.
Cool, and GM won't throw an error if you add dashes in the game options section and playstore will be fine with it? I'm not home to test this

Also curious, do you also keep track of your version number in an external file and update that with each version? It seems like the simplest way to inject important processes to transition major versions. For the save/load example, you will want to not simply delete a users data so you can compare the user's previous version and if its before the major update, run a one time code to transition the save date to the new system. Though thinking about it more, it might be cleaner to simply have a new filename for the new system and check if that file exists and if not and the previous files exist then run the transition code. The less clutter aspect of me leans towards being able to delete that transition code at some point but I guess there is no harm in building that system and leaving it in there and it skips the step of keeping track of what version number a user is on at the time of upgrade
 
D

Deleted member 45063

Guest
Cool, and GM won't throw an error if you add dashes in the game options section and playstore will be fine with it? I'm not home to test this
Me neither :p

Also curious, do you also keep track of your version number in an external file and update that with each version? It seems like the simplest way to inject important processes to transition major versions.
Not really, if you're talking about build systems then I just trigger a full rebuild for each proper release either way so no files need to be changed, for CI server I tag the commit of the release with the version it' corresponds to (e.g. I tag the commit with v1.0.0-beta for the beta release of 1.0.0) and configure the CI in a way that tags trigger a release job (most CIs should support this).
 

kupo15

Member
Not really, if you're talking about build systems then I just trigger a full rebuild for each proper release either way so no files need to be changed, for CI server I tag the commit of the release with the version it' corresponds to (e.g. I tag the commit with v1.0.0-beta for the beta release of 1.0.0) and configure the CI in a way that tags trigger a release job (most CIs should support this).
Well I meant user data so a clean wipe is not a good thing or feasible especially if its game progress data.

For example if you have a file system in place on production for, let's say, replay data. Then later you realize that the way you created it makes the replay files too large because you programmed it poorly which is the cause for why it takes forever to send replays to friends. Then you want to upgrade the replay format and system to be smaller and better, all the old save files will be broken in the new version with the improved save system and crash the game if you try to use them. Running code that deletes it will be bad for the User loosing their replays they want. In this case, it would be good to have code that loads the old save data and transitions it into the new format and re-saves it that way things run smoothly and you won't get outrage from the users and the game won't crash either.

My thought would be to keep track of version number that way on startup if their version is earlier than the major change, you can trigger this transition code. But I think it'll be cleaner to simply rename the new save data as like "replay_new" and check to see if this file exists to load that. And also check if any older data exists "replay" and if it does, then perform the transition code. Might be cleaner than comparing versions but then you have to change the naming scheme every time you make a major change to the replay system which could get messy. Not sure if its customary to save the version number the user's copy is on for examples like this

Another question I'm curious about. If you compile a new version that has a lot of bug fixes and some minor updates, would you simply increment the minor version and reset the patch to 0?
 
Last edited:
D

Deleted member 45063

Guest
Well I meant user data so a clean wipe is not a good thing or feasible especially if its game progress data.

For example if you have a file system in place on production for, let's say, replay data. Then later you realize that the way you created it makes the replay files too large because you programmed it poorly which is the cause for why it takes forever to send replays to friends. Then you want to upgrade the replay format and system to be smaller and better, all the old save files will be broken in the new version with the improved save system and crash the game if you try to use them. Running code that deletes it will be bad for the User loosing their replays they want. In this case, it would be good to have code that loads the old save data and transitions it into the new format and re-saves it that way things run smoothly and you won't get outrage from the users and the game won't crash either.

My thought would be to keep track of version number that way on startup if their version is earlier than the major change, you can trigger this transition code. But I think it'll be cleaner to simply rename the new save data as like "replay_new" and check to see if this file exists to load that. And also check if any older data exists "replay" and if it does, then perform the transition code. Might be cleaner than comparing versions but then you have to change the naming scheme every time you make a major change to the replay system which could get messy. Not sure if its customary to save the version number the user's copy is on for examples like this

Another question I'm curious about. If you compile a new version that has a lot of bug fixes and some minor updates, would you simply increment the minor version and reset the patch to 0?
Ahh sorry, misunderstood you.

Well, any custom file format that I create usually has a version encoded, so if you upgrade the version between releases then it is a matter of migrating the file to the new format upon first load. If there is no version information then I would resort to a completely new file name (which then could have version information). You could then on game start check for old file names and migrate them to the new ones.

Also, you can create file format that are both backwards and forwards compatible. So then updating the version would be trivial as some data would either be silently skipped or not.

Regarding the versioning: If I increase the minor version I reset the patch version, if I increase the major version I reset the other versions. It's like a numbering system.
 

kupo15

Member
Ahh sorry, misunderstood you.

Well, any custom file format that I create usually has a version encoded, so if you upgrade the version between releases then it is a matter of migrating the file to the new format upon first load. If there is no version information then I would resort to a completely new file name (which then could have version information). You could then on game start check for old file names and migrate them to the new ones.

Also, you can create file format that are both backwards and forwards compatible. So then updating the version would be trivial as some data would either be silently skipped or not.
No problem! :)

Ah that's a smart way to tackle it, encoding a version number as part of the file format basically. That's a pretty good idea, I was thinking the convoluted way of saving the application version number in a separate like ini file and comparing that to the current build version and if they are significant do the transition stuff.

Your method is much cleaner and removes the need for another file to read from. And so I'm clear, you encode the version of that particular file format inside that file, not the application build number right? So they are on different version tracks basically this way the file name doesn't have to change. If I got this right, In the replay example if replay0-replay5 the user saved was in v1.0 then you change things to 1.1, when you load the replay data you pull the encoded version and run the appropriate format transfer them to 1.1? In this way you can keep your naming scheme without having to do replay0_new..replay1_new...ect

Code:
var version = file_version

if  1.0 version = scr_replay_transition(1.1); // returns the upgraded version number
if 1.1 version = scr_replay_transition(1.2);

etc
 
D

Deleted member 45063

Guest
No problem! :)

Ah that's a smart way to tackle it, encoding a version number as part of the file format basically. That's a pretty good idea, I was thinking the convoluted way of saving the application version number in a separate like ini file and comparing that to the current build version and if they are significant do the transition stuff.

Your method is much cleaner and removes the need for another file to read from. And so I'm clear, you encode the version of that particular file format inside that file, not the application build number right? So they are on different version tracks basically this way the file name doesn't have to change. If I got this right, In the replay example if replay0-replay5 the user saved was in v1.0 then you change things to 1.1, when you load the replay data you pull the encoded version and run the appropriate format transfer?

Code:
var version = file_version
switch version
Correct, it is a file format version, independent from whatever version the game itself it.

I mainly use two approaches:
  1. One shot migration: On game start read all files and check versions. If they differ then migrate to the new version, save them and continue game initialization.
  2. Dynamic migration: On file read load the file using the old version. If the file contents need to be updated then when it is saved it is saved with the new format.
Both work nicely but 1 can potentially increase your load time significantly while 2 means you might need to support old file formats for longer. However both versions mean that the files names are unchanged, just its internal format might differ.
 

kupo15

Member
Correct, it is a file format version, independent from whatever version the game itself it.

I mainly use two approaches:
  1. One shot migration: On game start read all files and check versions. If they differ then migrate to the new version, save them and continue game initialization.
  2. Dynamic migration: On file read load the file using the old version. If the file contents need to be updated then when it is saved it is saved with the new format.
Both work nicely but 1 can potentially increase your load time significantly while 2 means you might need to support old file formats for longer. However both versions mean that the files names are unchanged, just its internal format might differ.
That's awesome, thanks for the tip! :)

I don't see #1 being much of an issue because after that initial load and transition then all the files will be in the new format so subsequent loading will be faster. Also, I think with both methods you will need to support old file formats longer regardless. The difference between #1 and #2 seems to be whether you batch it on startup or wait till the user accesses the file individually, right? Because with #1 you still have to load old file formats in the old format before saving it in the new format just like #2.

I think supporting older file formats aren't too much of a hassle if you set it up right. With each new file format change, you can create a script that transitions from the previous format to the current. This way if user doesn't play for a while and skips a format change, you have a daisy chain method to convert from 1.0>1.1>1.2 etc...I don't see how supporting direct conversions from 1.0>1.3 for example being a good solution...the only way to make that work would be to create variations of the transition code depending on the start version which doesn't seem as practical as the daisy chain method
 
D

Deleted member 45063

Guest
I don't see #1 being much of an issue because after that initial load and transition then all the files will be in the new format so subsequent loading will be faster. Also, I think with both methods you will need to support old file formats longer regardless. The difference seems to be whether you batch it on startup or wait to access the file individually, right?
I don't see how supporting direct conversions from 1.0>1.3 for example being a good solution
The biggest difference is timing, yes, but other things factor in which might force you to drop support of older file formats within a timeframe. Also, it depends on how much you enforce updates. If your game needs to always be running the latest version (e.g. online game) then one-shot transitions might be simpler since you know it should always be somewhat incremental and if there is too much of a gap then you can just state the data loss is acceptable. It basically depends on how much you want to guarantee data safety / consistency / support.

Also, #1 might still be an issue because if you don't put a limit on the number of save files a player has and each migration takes 1 minute (for some weird reason) then a player with 10 save files will only have to wait once... but it will be 10 minutes staring at a "blank" screen.
 

kupo15

Member
The biggest difference is timing, yes, but other things factor in which might force you to drop support of older file formats within a timeframe. Also, it depends on how much you enforce updates. If your game needs to always be running the latest version (e.g. online game) then one-shot transitions might be simpler since you know it should always be somewhat incremental and if there is too much of a gap then you can just state the data loss is acceptable. It basically depends on how much you want to guarantee data safety / consistency / support.

Also, #1 might still be an issue because if you don't put a limit on the number of save files a player has and each migration takes 1 minute (for some weird reason) then a player with 10 save files will only have to wait once... but it will be 10 minutes staring at a "blank" screen.
Ah I see how some situations a direct upgrade with data loss could be a preferred method and the difference between the two. And of course you could always mix the two up and have a #3 which is #1 that happens when the file is accessed. That way it cuts that strange 10min for all files down to 1min per file. But I guess it would be kinda annoying if every time they load a new file it takes 1 min instead of the batch transition. I guess it depends on the data type and the situation as you said.

This is so exciting, can't wait to integrate this stuff when I get home tonight! This thread turned out to deliver some valuable programming info above simple version counting. thanks a lot! :)
 
Top