Appearance
Appearance
Game config base classes SharedGameConfigBase
and ServerGameConfigBase
no longer contain entries for the SDK config libraries (Languages, InAppProducts, PlayerSegments, Offers, OfferGroups, PlayerExperiments).
The old base classes that provide these entries are preserved as LegacySharedGameConfigBase
and LegacyServerGameConfigBase
, the straightforward migration that retains the old functionality is to switch to using the legacy variants. If the integration previously did not provide a concrete implementation class for either of the shared or server config but relied on the SDK entries being provided by the SDK default class then an empty implementation class must be added, for example:
public class ServerGameConfig : LegacyServerGameConfigBase {}
Alternatively, you can migrate to using the new base classes SharedGameConfigBase
and ServerGameConfigBase
. Note that these new base classes no longer require specifying integration types for the SDK game config item types via generics parameters. For each SDK feature that you are currently using you need to then introduce a corresponding game config entry in your implementation class. The SDK discovers these entries using the name given in the GameConfigEntryAttribute
. For example, to make use of the InAppProducts
feature you need to an entry by the name InAppProducts
to your SharedGameConfigBase
implementation class:
public class SharedGameConfig : SharedGameConfigBase
{
...
[GameConfigEntry("InAppProducts")]
public GameConfigLibrary<InAppProductId, InAppProductInfo> InAppProducts { get; private set; }
...
}
The game config parsing pipeline has been refactored and support for new features has been added when using spreadsheets (local CSV files or Google Sheets) as the source. Support was added for parsing directly into nested members (e.g., Array[0].Member
) and parsing vertical arrays (i.e., using the MyArray[]
causes the vertical cells on an item to form the contents of the array).
This requires some updates to the syntax used as well as changes in some parsing behavior in a backward-incompatible manner that needs changes in the source sheets. These are described below.
#key
Tag As of R25, all game config columns that make up the item's ConfigKey
must now have the #key
suffix in the column header. For example, a column mapping into GroupId
should now have its column header be GroupId #key
.
The old activable-related special column syntax starting with #
such as #TimeMode
or #StartDate
gets replaced with direct access to the member with its full path. For example, #TimeMode
becomes Schedule.TimeMode
and #StartDate
becomes Schedule.Start.Date
.
Header cells now always use the //
prefix for comments, i.e. columns that are to be ignored. Previously this prefix was opt-in and customizable by overriding the SpreadsheetParseOptions
property in your GameConfigBuild
class. In R25, SpreadsheetParseOptions
no longer exists and its override should be removed.
The now-nonexistent SpreadsheetParseOptions
was also used to configure UnusedColumnHandling
which you could set to UnusedSheetColumnHandling.Ignore
to tolerate columns that don't match to any member in the C# config item type. In R25, this is done by overriding the UnknownConfigItemMemberHandling
property in your GameConfigBuildIntegration
-deriving class:
public class MyGameConfigBuildIntegration : GameConfigBuildIntegration
{
// Can be Error (default), Warning, or Ignore.
public override UnknownConfigMemberHandling UnknownConfigItemMemberHandling => UnknownConfigMemberHandling.Ignore;
}
To roll these out, R25 introduces [GameConfigSyntaxAdapter]
attribute which can be used to apply the conversions during the parsing of the spreadsheet. The syntax can either do exact replacements with the headerReplaces
parameter or prefix replaces using the headerPrefixReplaces
.
Below is an example of syntax adapters are used for adding the #key
suffix and transforming the activable syntax:
[GameConfigEntry("OfferGroups", requireArchiveEntry: false)]
[GameConfigSyntaxAdapter(headerReplaces: new string[] { "GroupId -> GroupId #key" })]
[GameConfigSyntaxAdapter(headerReplaces: new string[] { "#StartDate -> Schedule.Start.Date", "#StartTime -> Schedule.Start.Time" }, headerPrefixReplaces: new string[] { "# -> Schedule." })]
[GameConfigEntryTransform(typeof(MetaOfferGroupSourceConfigItemBase<>))]
public GameConfigLibrary<MetaOfferGroupId, TMetaOfferGroupInfo> OfferGroups { get; protected set; } = new GameConfigLibrary<MetaOfferGroupId, TMetaOfferGroupInfo>();
The same attribute can also be used on the SharedGameConfig
class to apply it to all libraries. For example, let's say you were previously using comment header prefix *
instead of the now required //
. You can handle that with a syntax adapter:
[GameConfigSyntaxAdapter(headerPrefixReplaces: new string[] { "* -> //" })]
public class SharedGameConfig : SharedGameConfigBase
{
...
}
In addition to the above, the collection syntax [MyArray]
needs to be converted to explicitly include the index in brackets, e.g., MyArray[0]
or MyArray[1]
. The syntax adapters perform this transformation automatically but it needs to be applied to the source sheets before the adapters are removed.
The syntax adapters can be used to roll out the changes through multiple branches and feature branches. As long as any branch is using a specific sheet, the sheet must remain on the old syntax for those branches to be able to build the game configs from it.
Once all relevant branches have been upgraded to Metaplay R25, the syntax in the spreadsheets can be updated according to the syntax adapters, and then adapters can be removed. If the syntax adapters don't match anything, they are silently ignored, to allow rolling out the syntax changes into the spreadsheets.
Collections (eg, arrays and lists) are now inherited into the A/B experiment variants as the full collection or are fully overridden for the variant. These can be fixed by ensuring the variant fully specifies the collection contents that are desired for the specific variant.
Empty elements within a collection now end up with the default value of the type instead of being parsed from an empty string.
Fixed-point value parsing has been replaced with a better implementation. It ends up rounding the values slightly differently compared to the old implementation. If you need the old behavior, please contact Metaplay and we can help you get the old parsing behavior back.
We strongly recommend comparing the outputs between the old (pre-R25) and the new (R25) parser by building the game configs immediately before upgrading to R25 and after, and then using the game config diff tools to see any potential differences.
Game config building now supports declaring the build source(s) via config build parameters. This replaces the old GameConfigBuilderServices
mechanism for providing sheet fetching facilities to the build.
The required migration steps are:
Remove any references to the old GameConfigBuilderServices
class in the integration code.
Declare the Google Spreadheets ID to use as GameConfigBuildParameters.DefaultSource
in your call to StaticGameConfigBuilder.BuildArchiveAsync
. If you previously have not used build parameters then you can use the SDK provided DefaultGameConfigBuildParameters
implementation.
GameConfigBuildParameters buildParams = new DefaultGameConfigBuildParameters();
buildParams.DefaultSource = new GoogleSheetBuildSource(sheetName, sheetId);
For server config builds the available build sources need to be declared via GameConfigBuildIntegration.GetAvailableBuildSources()
. You can naturally refer to the same list of sources to populate the build parameters for editor / CLI builds. The server option GoogleSheets.GameConfigSheetId
has been removed.
public class MyGameConfigBuildIntegration : GameConfigBuildIntegration
{
// If only using a single source in config builds you can disregard the "sourceProperty" parameter.
public override IEnumerable<GameConfigBuildSource> GetAvailableBuildSources(string sourceProperty)
{
return new[]
{
new GoogleSheetBuildSource("Development sheet", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxx"),
new GoogleSheetBuildSource("Release sheet", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxx")
};
}
}
In addition to the build source specification, the build needs to have appropriate credentials for fetching the sheets. Provided that a single set of credentials works for all of the configured sheets this is done using the fetcherConfig
parameter for StaticGameConfigBuilder.BuildArchiveAsync
. With credentials stored in a local file, this is done by:
IGameConfigSourceFetcherConfig fetcherConfig =
GameConfigSourceFetcherConfigCore.Create()
.WithGoogleCredentialsFilePath(credentialsFilePath)
The game server continues to read the Google Sheets credentials from the server option GoogleSheets.CredentialsPath
or GoogleSheets.CredentialsJson
.
The new build sources and fetchers abstractions allow for more complicated scenarios, including