Platform Toolkit - Official cross platform API - now available for 6.3

GameKit is currently only available on iOS, as GameKitBuilder specifically checks for UNITY_IOS, so it can’t be evaluated on Mac/tvOS/visionOS.

That’s my mistake then. We actually have work planned to validate these implementations on these platforms. The implementations will likely work fine but we’re going to make sure before we make them supported.

I’m not sure about getting save systems from two different places. As far as I’ve seen, all the ways of constructing/initializing a save system are marked internal, except for using the default platform init. Marking some public constructors would definitely fix this issue.

The two places are from an account, which will give you a saved back by appropriate platform account specific storage. The other (for platforms that support it) is the local saving system, in the example in the docs it gets you one or the other based on if the user is signed in, but there’s nothing to stop you getting both, perhaps to migrate a local save to a user save.

ISavingSystem savingSystem;

if (PlatformToolkit.Capabilities.Accounts)
{
   try
   {
       savingSystem = await account.GetSavingSystem();
   }
   catch (InvalidAccountException e)
   {
       // Handle signed out account
   }
}
else if (PlatformToolkit.Capabilities.LocalSaving)
{
   savingSystem = PlatformToolkit.LocalSaving;
}

The name validation in SaveNameValidator is exactly what I was proposing – great! Only thing is it’s not used in a bunch of entry points (e.g., it’s used in GenericLocalStorageSystem.EnumerateArchives, but not GetWriteOnlyArchive).

That sounds like a bug, we will take a look.

PT looks promising. Regarding Achievements It is pretty common to have an icon and localized title/descriptions. It would be great to be able to configured those properties directly from Unity PT.

Looking forward how this new package will evolve.

PT isn’t aware of anything that’s happening on the platform side, so the platform specific images, names, descriptions, etc. all still need to be configured on the platform holder’s side. The only thing PT needs to know is the platform specific ID for unlocking the achievement on the target platform.

We have considered a deeper integration with platform storefronts to allow for uploading/downloading platform specific information, but it’s not currently possible but would be really useful.

I’ve just starting converting our save system to use this. One thing I’m curious about is where the actual save files go using a Local save system in the editor in playmode? I expected them to be in AppData/LocalLow/Company/Game, but it doesn’t look like they’re in there, and I can’t find it in the documentation.

It’s been approx. 10 years since I had my first conversations with people from Unity regarding the need for something like Platform Toolkit - really glad that it’s here now!

I’ve been very interested to see how Unity was going to approach the problems inherent in multi platform support for all this stuff, and what eventual shape this API was going to have.

I actually made my own multiplatform library to handle platform submission requirements related issues (users/saves/controllers etc.) for PC/Mac/Steam/PS4/Xbox One (with editor support for simulating each platform) in around 2016 and have been maintaining it ever since - it now supports PC/Mac/Steam (inc. Deck)/PS4/PS5/Switch/Xbox One/Xbox Series/Windows GDK - and will soon also have Epic Online store support (it’s called PlatformLayer www.darbotron.com/platformlayer).

I was hoping to be able to refactor my library to make use of Platform Toolkit but having skimmed through the documentation and had a quick look at the UPM package code I’m not sure I’m going to be able to do that…

First thoughts on Platform Toolkit:

  • it does a little less than the minimum I expected it would
  • just as surprised as everyone else that Steam requires a Pro license
  • was surprised to see that there aren’t any samples in the Platform Toolkit UPM packages - or did I miss them?

I do really like some of the decisions you’ve made though:

  • Attributes seem like a pretty neat solution to hiding platform specific functionality
  • I like that Accounts own their save data
  • The way you simulate all account behaviour in the editor is nice

Not so sure about some aspects of the API :

  • very not sure about using .zip for platform specific save data…
    • (…I assume it’s possible to override this with the save interface, but I’ve not looked deeply into it)
    • there are other considerations around saves which I can’t discuss here cos NDA
  • the way in which all the available sample code seems to be using await for everything gives me the heeby-jeebies …
    • (to be fair, this might be ok, depending on how the underlying platform implementations are done and what information is thrown with platform specific exceptions).

Finally, there are a few things which are directly at odds with the way that PlatformLayer API does things … which given that it’s shipped in 10 multiplatform games (40+ SKUs…) might be more of a concern - but I can’t really discuss that stuff in this forum because NDAs :sweat_smile:

@thomh_unity @stuartb-unity: I’d be more than happy to discuss my NDA embargoed thoughts with you privately if you DM me - also if you’re based in the Stratford office then an irl chat would be an option since I’m just down the road in Leamington.

1 Like

Data gets serialized directly into the Play Mode Settings asset currently.

I’m not sure to understand that. There are platform specific packages, so it should be possible to “know/override” the content of the zip file generated when you click" export" from the Achievement configuration editor. The point would be to configured in one place and be able to export the configuration (zip file) with all necessary information required to specific platforms.
But I can understand it’s not easy or not a priority.

1 Like

OK, thanks. That causes a bit of a headache with source control. If that asset is checked in, then everyone is sharing local save data during development. If it’s not checked in, everyone gets errors on entering playmode until they create the asset themselves. (I get that that doesn’t sound like the biggest problem in the world, but we try to streamline stuff as much as possible for people setting up the project). I guess I can check it in and hide local changes, but it’s not ideal. (Please let me know if I’ve misunderstood!)

3 Likes

At a quick glance into the source it looks like you could pretty easily knock up a new ISavingSystem based on GenericSavingSystem which just opens a file and writes to it?

e.g. in Application.persistentDataPath with an additional directory named with the local user id appended onto it?

Not sure exactly how that would plumb into the rest of the system though :sweat_smile:
If it were me, I might be inclined to pull the Platform Toolkit UPM packages out of the package cache and into your \Packages folder then you can do what you like to them - though this approach comes with the free gift of additional maintenance when the main packages are updated :sweat_smile:

aaaactually, looking at the package source, in order to change the save system used during play mode I think you might only need to change:

  • line 38 in PlayModePlatformToolkit.cs
  • and line 29 in PlatformToolkitEditorRunner.cs

Which is a really low maintenance burden - so might be worth it?

All that said, the authors might have better ideas on how to get “regular save files” (e.g. just files written into Application.persistentDataPath) in Play mode…

1 Like

We have considered making it so the changes to the PMC settings asset not persist after exiting play mode, or at least providing an option for that, so that you’re not always touching that file when testing in play mode. Do you think that would work for you?

1 Like

Wouldn’t that mean there’d be no way to have persistent saves in the editor? That doesn’t sound great! I think a file-based saving option would be ideal (basically what darbotron suggested, but without having to edit the package.

3 Likes

Hi @thomh_unity

Thanks for posting, something like this has been long overdue.

But agree with the others, not including basic features (for example, achievements on iOS\Android) in the free tier is a huge disappointment (for solos\indies)

1 Like

I’m with Rob here - I would like to see the PlatformToolkit API modified so that we can supply our own implementations for interfaces like ISavingSystem or IGenericStorageSystem so that we have explicit control over how saves work that would be great.

e.g. I’ve found that the optimal way to pass platform submission guidelines around save data across all the console platforms is to use a single fixed size save file.

I realise that nothing about PlatformToolkit prevents me doing this, but I would like explicit control over how I load / save so that I can ensure that save data behaviour is as close as possible to identical across all platforms rather than having to account for additional data / stuff being done to the serialised data by Platform Toolkit.

2 Likes

Having looked at the code a bit more I’d like to revise previous comments about async / await giving me the heeby jeebies :sweat_smile:

That said… I really feel like we need the exceptions thrown on platforms to carry platform specific error codes out of Platform Toolkit so that they can be used by the code catching them <possible NDA stuff don’t want to discuss here>.

Am currently re-implementing a minimal shell game I use as a sample for my own tech but using Platform Toolkit

Serious feedback: I feel like the attempt to completely hide “platform specificity” from the code using Platform Toolkit is actually making it harder to use.

Consider the examples given on how to initialise an Account and save data across multiple platforms here: Handle platform account systems | Platform Toolkit | 1.0.0

Each platform has specific requirements about what it does and doesn’t need you to do, so why not just cover that in detail in the documentation for each platform?

Handling correct startup for all platforms in one chunk of code is asking for trouble - by doing this you’re compiling code which handles edge cases that will never happen on some platforms, and are guaranteed submission fails on others.

The most robust and reliable approach to handling platform startup in a multiplatform game is to handle it in platform specific code using #if UNITY_<platform> ... #endif and I honestly think you should just say that.

Certainly doing this for my use case makes the PlatformToolkit code much nicer looking and - more importantly - clearly shows exactly what each platform expects to happen so it’s easier to debug and won’t affect the initialisation path for other platforms.

:backhand_index_pointing_up: all this said…

Outside of the initialisation (and other very platform specific areas) in my experience the safest way to handle multiplatform code is to have the platform API give a completely consistent view of the “platform” to game side code across all platforms so that, from the game’s pov the platform appears to behave the same whatever platform the game is running on.

i.e. rather than “no account” for platforms which don’t support them I think it would be better to have a DummyAccount (or similar) which is a valid account from the game’s pov but has no real behaviour - e.g. it can’t fail to sign in, can’t ever sign out, always owns a local file save etc.

A consistent client code view of “Platform” minimises edge cases in game side code, which makes for statistically fewer bugs.

I also think a similar approach should be used for any Platform Toolkit interface which might not exist on a given platform e.g. achievements etc.

So, rather than not being able to get an IAchievementSystem on a platform without achievements, I would get a dummy achievement system which does nothing when its functions are called.

Actually, it would be great to be able to register IAchievementSystem instances with the Platform Toolkit so that - for example - I could write a local achievement system which tracks achievements in the save data.

1 Like

I am a bit confused about platform support. We’re already using Apple’s GameKit (via Apple Unity plugins), Google Play Games Services and Facepunch.Steamworks for example. Can we use this Platform Toolkit? We have to use these packages/plugins, because we also need more core things, like client tokens, MTXes, etc.

One quick bit of feedback. It’d be nice if the Steam platform returned a GenericLocalStorageSystem for LocalSaving. Not everything should be in the cloud (for example we’d generally want graphics settings to be excluded).

I get that I can do this manually by creating my own instance of the GenericLocalStorage in an ifdef, but it feels like the Steam implementation should provide a local save system by default (along with the Cloud one for the Account saving).

1 Like

I think we leaned away from this as it wouldn’t be very portable if your game relied on two storage systems for different types of data, as it wouldn’t port well to console for example. But I don’t see why we couldn’t add support for a local saving system on steam as well. I will talk with the team about it.

I’m 100% with @Rob_Fireproof on this one.

Every steam game I’ve worked on has used a local save file - Steam supports automatic cloud storage / migration of local saves based on the game’s Steam backend metadata so most people don’t bother.

Also, there’s nothing stopping the array of bytes being written to a cloud save / a local save being identical - it’s certainly handy if you want to do cross play for example…

EDIT:

oops, I re-read Rob’s post.. I actually don’t agree with Rob as it turns out :sweat_smile:

Whilst I think that it would be good to support local saves for Steam I really don’t think that using both local and cloud files for separate stuff is a good idea - @thomh_unity is 100% right that it’s not an option for consoles.

Personally, I always use PlayerPrefs for machine specific settings on PC / Mac / Steamdeck as they’re truly local.

Whilst PlayerPrefs isn’t supported on all platforms * *, but it’s trivial to wrap player prefs and serialise them into the save data on console … in fact I noticed that Platform Toolkit has an save data object which has essentially the same storage capabilities as PlayerPrefs - it’s called DataStore

( * * iirc consoles do have the PlayerPrefs API, but it’s certainly not a good idea to try to pass submissions using it for various reasons).