Appearance
Appearance
Google Sheets is a very popular tool to manage game configuration data. Most designers are experienced in working with spreadsheets, the tool is free, supports live collaboration and requires no installation. The Metaplay SDK includes built-in support to securely import data from Google Sheets, but you could adapt this guide to import data from other sources.
At the end of this guide, you will have an end-to-end implementation of you custom game configs data being imported from Google Sheets.
The first thing you need to do is set up a spreadsheet with the contents of the config data you’ll add to your game. A sensible starting point is to add a sheet per config library with columns that map to the config item members.
For this example, we’re using TroopKinds
, the same example as in Working with Game Configs. You can do an intermission there if you have questions about formatting a config library spreadsheet or how configs work in general.
For you to be able to fetch a spreadsheet from Google Sheets, you need the SpreadsheetId
. You can extract the ID from the Google Sheets spreadsheet URL, which is formatted as such:
https://docs.google.com/spreadsheets/d/**spreadsheetId**/edit#gid=0
You can then configure your GameConfigBuildIntegration
to tell the SDK where you would like to fetch your configs from:
public class MyGameConfigBuildIntegration : GameConfigBuildIntegration
{
// If only using a single source in config builds you can disregard the "sourceProperty" parameter.
public override IEnumerable<GameConfigBuildSource> GetAvailableGameConfigBuildSources(string sourceProperty)
{
return new[]
{
// Spreadsheet IDs go here:
new GoogleSheetBuildSource("Development sheet", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxx"),
new GoogleSheetBuildSource("Release sheet", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxx")
};
}
}
By default, the Unity SDK comes with a "game config build" window, you can find the window under Metaplay/Game Config Build Window
. The build window has a few features; it lets you configure your sources and has an OAuth2 implementation for Google Sheets authentication. Therefore, you don't have to provide a Google Service Account for authentication!
If you wish to provide a custom service account to the build window, you can override the FetcherConfig
being used:
public class MyGameUnityGameConfigBuildIntegration : IUnityGameConfigBuildIntegration
{
public IGameConfigSourceFetcherConfig CreateFetcherConfig()
{
return GameConfigSourceFetcherConfigCore.Create()
.WithGoogleCredentialsFilePath(filePath);
}
}
For more advanced use cases, you might want to provide your own game config builder. More information is available at Custom Game Config Build Pipelines. Here we provide a succinct example of a custom game config builder could look like.
public static class UnityGameConfigBuilder
{
const string SharedGameConfigPath = "Assets/StreamingAssets/SharedGameConfig.mpa";
const string StaticGameConfigPath = "Backend/Server/GameConfig/StaticGameConfig.mpa";
// Add path for credentials and configs sheet id
const string GoogleSheetsCredentials = "path/to/Google/credentials";
[MenuItem("Config Builder/Build GameConfig", isValidateFunction: false)]
public static void BuildFullGameConfig()
{
// Get or create the source fetcher configuration.
IGameConfigSourceFetcherConfig fetcherConfig = IntegrationRegistry.Get<IUnityGameConfigBuildIntegration>().CreateFetcherConfig();
// Get the game-specific GameConfigBuildIntegration implementation.
GameConfigBuildIntegration integration = IntegrationRegistry.Get<GameConfigBuildIntegration>();
DefaultGameConfigBuildParameters buildParams = new DefaultGameConfigBuildParameters
{
// Get the first source returned by GetAvailableGameConfigBuildSources for DefaultSource.
DefaultSource = integration.GetAvailableGameConfigBuildSources(nameof(GameConfigBuildParameters.DefaultSource)).First();
};
// Build full config (Shared + Server) with the configured sheet and fetcher config
ConfigArchive fullConfigArchive = Task.Run(async () => await StaticFullGameConfigBuilder.BuildArchiveAsync(MetaTime.Now, parentId: MetaGuid.None, parent: null, buildParams, fetcherConfig, new GameConfigBuildDebugOptions { EnableDebugPrints = true })).GetAwaiter().GetResult();
// Extract SharedGameConfig from full config & write to disk
var sharedConfigArchive = ConfigArchive.FromBytes(fullConfigArchive.GetEntryByName("Shared.mpa").Bytes);
Debug.Log($"Writing {SharedGameConfigPath} with {sharedConfigArchive.Entries.Count} entries:\n{string.Join("\n", sharedConfigArchive.Entries.Select(entry => $" {entry.Name} ({entry.Bytes.Length} bytes): {entry.Hash}"))}");
ConfigArchiveBuildUtility.WriteToFile(SharedGameConfigPath, sharedConfigArchive);
// Write full StaticGameConfig to disk
Debug.Log($"Writing {StaticGameConfigPath} with {fullConfigArchive.Entries.Count} entries:\n{string.Join("\n", fullConfigArchive.Entries.Select(entry => $" {entry.Name} ({entry.Bytes.Length} bytes): {entry.Hash}"))}");
ConfigArchiveBuildUtility.WriteToFile(StaticGameConfigPath, fullConfigArchive);
// If in editor, refresh AssetDatabase to make sure Unity sees changed files
AssetDatabase.Refresh();
}
}
By overriding GameConfigBuildIntegration
and implementing GetAvailableGameConfigBuildSources
, the dashboard will automatically enable you to build game configs. However, you still need to provide credential information to access Google Sheets. You can do this by adding your credentials to your base Options
file. If you're not familiar with runtime options, check out the Working with Runtime Options page.
GoogleSheets:
CredentialsPath: ./Secrets/google-sheets-credentials.json
For this, you'll need to have your own Google Service Account to get your credentials. If you don't have one yet, you can find a quick guide in Creating a Google Service Account below.
If you're storing the credentials file in your code repository, it should be in the server's Secrets/
directory (e.g. Backend/Server/Secrets/
) so that it gets copied into the server image when it is built using MetaplaySDK/Dockerfile.server
. By default, files in the Unity directories won't be available in the server image.
🔒 Storing Secrets Securely
To avoid storing secrets within the code repository, you can put them in AWS Secrets Manager instead. For example, setting CredentialsPath
to aws-sm://us-east-1#google-sheets-credentials
would denote credentials in Secrets Manager on us-east-1
with name google-sheets-credentials
.
To fetch the spreadsheets, you need credentials from a Google Service account. Here’s a quick step-by-step:
The first thing you need to do is access Google Developer’s Console and either create a new project or select the project associated with your game if you already have one.
To allow your project access to your Google Sheets spreadsheets, you must enable the Google Drive and Google Sheets APIs. Click the “Enable APIs and Services” and search the API library for “Google Drive API” and “Google Sheets API.”
Then, you need a service account. Back in the “APIs & Services” dashboard, find “Credentials” on the leftmost menu and click it to access your project’s registered credentials.
On the “Credentials” page, find the “Create Credentials” button on the top and add a service account.
After creating and configuring the service account, find “Manage Service Accounts” back on the Credentials page.
On the right-hand side of the page, click “Actions” and select “Manage Keys.” There, you can create a new JSON key, download it, and add it to your project. Don’t forget to go to Google Sheets and allow your service account access to the spreadsheet! You can do that by sharing the spreadsheet with the account e-mail address.
Various Metaplay SDK features are configured using the same game config mechanism as your custom config data. As part of integrating a feature, you should enable the configuration of data related to the feature via sheets.
You can customize the config build process for the SDK data libraries in exactly the same fashion as you would for game-specific data.
Here are some examples of SDK features that use game configs:
You can do a lot with your game configs after getting Google Sheets integrated into your project. Here are some suggestions to get you started: