-
-
Notifications
You must be signed in to change notification settings - Fork 6
Builds and Patches
If you are a bit confused about the meaning of builds
and patches
(the two major entities used in PATCH), then this page may help you understanding the rationale behind them.
An interesting explanation (if you have a math background and/or if you're used to the graph theory) is: this works exactly like a graph.
Builds are the graph nodes
and represent the state of your game on a specific version.
Patches are the graph edges
and represent the connection between 1 or more graph nodes (builds).
You can reach a specific graph node (build) by walking through all the graph edges (patches).
I understand this may not ring any bell to someone, so: math theory aside now! I'll try to explain it through examples!
The Updater works by "capturing" the state of your game's files at a given version. This is what we call a build
(interchangeably version
or state
or snapshot
from now on).
When you cook a new build
, it gets added to the list of valid builds: builds_index.json
. All the builds contained in this JSON file are considered a valid state in which the application can be.
Let's make an example to clarify this.
Let's say we have three valid builds in our builds_index.json
:
0.1.2
0.1.3
0.1.4
Now let's say an user runs the Updater.
If the user has no versions on their local side, the Updater simply downloads the list of valid builds, selects the most recent one (0.1.4
) and downloads all the files that compose this valid snapshot. Then it just proceeds to the next phase: patching processing. More on this later.
If the user has the latest valid version (0.1.4
), the Updater just proceeds to the next phase: patching processing. More on this later.
If the user has the version 0.1.1
on their local side (which is not contained in the list of valid builds AND is smaller than the smallest valid build), the Updater considers it as invalid
.
An invalid state needs to be repaired: the Updater triggers the repairing process, targeting the most recent valid build (0.1.4
). The repairing process simply forces the download of a specific snapshot. Then the Updater just proceeds to the next phase: patching processing. More on this later.
The same does NOT apply if the user has the version 0.1.5
. Such a version is not in the list of valid builds, but it's NOT smaller than the smallest valid build in the list (which would make it invalid). The Updater considers this version as orphan
.
This allows PATCH to advance to some states which are only reachable through patches. More on the patching process later.
Now the average case: what if the user has one of the versions in the middle (0.1.2
or 0.1.3
)? The Updater checks if the local version is valid. It is, so no repairing is needed. Then it proceeds to the patching process. If no patches have been found, there are two possible behaviors:
- the Updater completes its job, no available updating paths have been found
- if the
LauncherSettings.EnableRepairToTheLatestVersionIfNoPatchFound
flag is set, the Updater repairs to the latest valid version (0.1.4
) before proceeding to the patching process
NOTE: The repairing process is a smart process. It does not download every file from scratch all over again. Instead, it recycles what is already stored on disk. If a file is already valid, there is no point in downloading it again!
All the previous rules are a bit hard to understand and handle. You just want to build a well-defined path for your updates. And also: repairing the game files when a new valid and more recent version is available is a bit time-wasting for the final user.
For these reasons, you can take advantages of the patches.
A patch represents a difference between two valid states (the From
state and the To
state, which makes clear what the direction is). It contains all the required data (which is represented as a binary difference) to reach the To
state starting from the From
state.
Normally, a patch is very small in size (compared to a full build), so reaching a new state would be just a small download for your final users. This - of course - comes at the cost of some additional time required on the Admin's side.
The Updater runs the patching process after having established what is the local build and after the repairing process. It is an iterative process, so it can apply patches in a sequence and it tries its best to identify the smallest amount of patches to apply for reaching the most recent version.
Let's make an example to clarify this.
Let's say we have the same valid builds as before. Then we have some patches:
0.1.2_0.1.3
0.1.2_0.1.4
0.1.3_0.1.4
If the user has the version 0.1.2
on their local side, the Updater (after checking all the things we mentioned before in the section dedicated to the builds) runs the patching process and calculates the shortest path to reach the most recent version.
As you can see, we have two possible paths here to the latest valid version (0,1,4
):
-
0.1.2_0.1.3
, then0.1.3_0.1.4
-
0.1.2_0.1.4
The Updater selects the path with the smallest amount of hops: the0.1.2_0.1.4
patch. After applying this patch, it reached the valid, most recent version.
Let's say we also have a patch to an orphan build:
0.1.4_0.1.5
As you can notice, the 0.1.5
version is not listed through the valid builds. Although this is not recommended, it's still possible to reach such states. For example, you can obtain it by calculating the build and the patch on the Admin's local side and then uploading only the patch.
In this case, the Updater recognizes that the state can be moved forward with an additional patch and simply applies it. Now, locally, the user has the version 0.1.5
.
However, if the Updater needs to repair some files from this version, it first needs to downgrade it to a valid version and then it re-applies all the patches. This process makes the updating process longer and consumes more bandwidth.