Skip to content

jpgordon00/PlayFabUnityUpdater

Repository files navigation

PlayFabUnityUpdater

A server-authoritative auto-updater for Unity and PlayFab.

What frameworks/libraries are involved?

  • .NET Core and C#
  • PlayFab as the backend-as-a-service.

PlayFab provides file hosting through their environment and with Microsoft Azure's CDN. It also allows the hosting of private code that has access to their environment via an SDK.

This particular project requires the PlayFab Unity SDK.

  • Azure Functions V3 for writing C# CloudScript functions.
  • SimpleJSON for JSON parsing on client and server.
  • While both PlayFab and Unity provides their own JSON serialization and deserialization, I found it useful to use a single resource in my client and server code. This partciular library is a single .cs file that supports JSON deserialization only. In the Azure Functions I used PlayFab serialization to serialiize the returning of JSON objects.

  • GroupDownloader for 'one-by-one' downloading of multiple files using UnityWebRequest.

What does it do?

  • Allows the developer to push content updates to various client segments, where clients are updated in a server authoratative manner.

Updates are queried by the response to logged in event, meaning this process is server authoratitve . Each update is identified by an integer named ID, where a player is updated only if an update exists with a larger ID integer than the players current version. For example, if all updates are kept in increasing order then the player is guarenteed to have the newest version. Another example would be to seperate updates by more than one numeric value, for example two at a time. By doing this, you could release intermediate updates that new players are updated to but existing players are not.

  • Keeps a list of versions and various attributes associated with the version, on a per-player basis.

Versions are stored as JSON in internal title data. Players are assigned the newest version on login, stored as internal player data. Versions are updated upon login if a newer version is found. Every update is written as a PlayStream event. PlayFab statistics are written to track current version and number of version updates for each player.

  • Serves a set of files specified in the version that player is using, where each file is served from the PlayFab CDN.

Players with different versions can exist at the same time, since the function serves content from that players current version.

  • All versions have completely seperate files stored in the PlayFab CDN, so multiple versions and players using those versions can exist simulatenously.

Files are requested through a Cloudscript Function that includes the files URI, a unique name, and the resulting file name. A use case for this would be to identify each file through the 'Name' attribute. Another use case for this would be to modify the function to include additional metadata for each version or each file.

  • Client requests URI for and only downloads missing files.
  • Incase of error during a download, the updater removes partially downloaded files.

UpdateHandler.cs provides access to elapsed time, progress and how many times the update process is re-invoked.

UpdateHandler.cs provides cleanup in the case of a new update downloaded. All base folders not matching the used version is always deleted, upon update invokation.

What I learned.

  • Best practices for deploying and developing Azure Functions apps using Visual Studio and Visual Studio Code.
  • Best practices for data storage and player management using PlayFab.
  • This project's design decision to be as modular as possible saved me a significant amount of development time. While this project was created for a multiplayer game, it was very easy to extract and upload as a standalone component.
  • JSON parsing and async programming in C#.

How do I use this?

Setup:

  • Add the field 'Versions' as JSON in internal title data.
    • The object name is 'Versions' and is a JSON object containing ananonomyous array.
    • The newsest version at any time is the version whose name matches the string defined in 'CurrentVersion' in title data. An update is issued ONLY if the current version has a larger "id" attribute than the players current version, or if the player has no version assigned yet.
    • Each version has the following properties:
      • name, a unique string identifier for the version.
      • id, a unique integer identifier where the largest version is the version assigned to players.
      • buildVersion, a string where the a matching build version for PlayFab Matchmaking 2.0 can be used.
      • content, a array of objects containing name, filename and contentKey for each file. The attribute 'contentKey' should match the content key for the given file in the CDN, which should be a path.
  • In title data, Set the current update version by setting the attribute 'CurrentVersion' to be a string matching a version title.
  • Add all the required files listed in 'content', the PlayFab CDN in the developer portal, for whatever versions you want to support into the PlayFab CDN.

The content key points to a folder with with the current versions 'name' attribute as its folder name. For example, if the content key is "coffee.png" and the version is "DEV", then the folder should be "DEV/coffee.png".

  • Deploy two Azure Functions and register them on PlayFab Cloudscript Functions.

Deploy PollUpdater and PollUpdaterContent to the cloud. Ensure you have SimpleJSON.cs somewhere in your source. Register PollUpdater and PollUpdaterContent in PlayFab Functions In Automation, register PollUpdater for a player_logged_in event.

  • Add UpdateHandler.cs to your Unity project and ensure PlayFab is authenticated before invoking UpdateHandler.Instance.UpdateProcedure().
  • Add GroupDownloader.cs to your Unity project.

Pushing a new update:

  • Optionally add a new version to Versions whose attribute "id" is larger than all previous versions. Only players whose version ID's are explicitly lower than the 'CurrentVersion' are updated.
  • Optionally Change CurrentVersion in title data to a string matching the attribute "title" in the version with the largest attribute "id". All new players are updated to the 'CurrentVersion' regardless of its ID attribute.

The 'CurrentVersion' string must match an existing version 'name' property or the update will fail.

  • Optionally change the content in the new version with matching files in the PlayFab CDN.

Future improvements.

  • Keep seperate version lists for each code version.

If we kept some unique object for every "code version", then we could ensure that downloaded update data is tailored for the current client app. Because the app store and google store both allow in-store updates, developers likely will want seperate assets/version lists for each different update. You may also want to force users to download an update on the store to have access to the newest version (which would be newest version list and version within that list). Alternatively, you could create custom upgrade paths within this upgrade tree to describe an upgrade path for any nuber of client upgrade situations.

  • Keep attributes/KVP's for each version.

We could extend our version system from only serving static files to also storing KVP's on a per-version basis.

  • UpdateHandler.cs by default can recursively re-invoke the PollUpdaterContent function. While this was done because newly created accounts don't always update PlayFab data quickly enough for PollUpdaterContent to be succesful, I would like to expand on this system. It is not flexible in handling a multitude of errors.
  • The updater does not support large files and does not check file size. While large files can be downloaded since they are supported by the Unity downloader, caching of these files incase of interruption is not supported. Since files are never left partially downloaded, exteremely large files would be lost if a download interuption existed at any point during the download.

A solution would be to break down large files into smaller chunks. This would mean download progress would not be lost in case of an interuption.

  • Files can be loaded into memory straight from a FileManifest object.

This is partially implemented in the ProcessManifest function.

Remarks.

  • Developers should use this auto-updater to download Unity AssetBundles.
  • This updater fails gracefully.

The Cloudscript Functions return errors in the case of inproper setup (for example not finding a correct version).

The client invokes error callbacks and sets (optionally) low timeout intervals for download updates.

  • This updater is efficient in that it only downloads missing files and can support a massive amounts of smaller files.
  • The code heavily is commented.

A visual view of all the components involved in configuring new updates:

Versions in Internal Title Data Versions JSON CurrentVersion in title data Files for versions in File Management

About

A server-authoritative auto-updater for Unity and PlayFab

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages