Appearance
Release 27 Game Config Migration Guide
Release 27 migration guide for game config changes.
Appearance
Release 27 migration guide for game config changes.
GameConfigKeyValue Sheet Syntax Release 27 extends the sheet syntax of GameConfigKeyValue configs to support nested objects and collections. To avoid ambiguity, the sheet parser now always requires a header row. Additionally, there is a change in behavior when parsing empty cells.
This only concerns sheets for config entries which have a type derived from GameConfigKeyValue, such as GlobalConfig in the Idler sample project. In particular, this does not concern GameConfigLibrary sheets.
GameConfigKeyValue Sheets Existing GameConfigKeyValue sheets need to be updated to specify a header as the first row in the sheet. If an existing sheet already has a header row specifying the /Variant column, then the Member and Value headers should be specified on the same row. If the existing sheet doesn't yet have any header row, then a new row should be added at the top, specifying Member and Value.
As a temporary migration-time helper, [GameConfigSyntaxAdapter(ensureHasKeyValueSheetHeader: true)] can be used on members of SharedGameConfig to inject the header row at config build time if it does not already exist.
Starting with release 27, GameConfigKeyValue are required to have a header row specifying the Member and Value columns. These Member and Value headers were not previously required.
| Member | Value |
|---|---|
| InitialGold | 100 |
| InitialGems | 10 |
| DefaultPlayerName | Guest |
Like previously, if the sheet has a column for variant overrides, it needs to be specified with /Variant in the header:
| /Variant | Member | Value |
|---|---|---|
| InitialGold | 100 | |
| Resources/Low | InitialGold | 50 |
| Resources/High | InitialGold | 200 |
| InitialGems | 10 | |
| DefaultPlayerName | Guest |
Comment columns can be introduced by starting the header cell with // to tell the parser to ignore those columns. Previously, any columns after the value row were automatically ignored.
| Member | Value | // my comments |
|---|---|---|
| InitialGold | 100 | some comment about gold |
| InitialGems | 10 | some comment about gems |
| DefaultPlayerName | Guest | ... |
To help with migrating existing config sheets without needing to update all of them immediately, the [GameConfigSyntaxAdapter(ensureHasKeyValueSheetHeader: true)] attribute can be used on the GameConfigKeyValue members of SharedGameConfig. This tells the config parser to pretend that the sheet has a header in case it is missing, allowing it to parse old-syntax sheets.
public class SharedGameConfig : SharedGameConfigBase
{
...
[GameConfigEntry("GlobalConfig")]
[GameConfigSyntaxAdapter(ensureHasKeyValueSheetHeader: true)]
public GlobalConfig GlobalConfig { get; private set; }
...
}Once all relevant game environments have been updated to use release 27, the GameConfigKeyValue sheets should be updated to have the header in place, and then the attribute can be removed from the code.
A member with an empty value cell is now left unassigned by the parser, instead of parsing an empty string to get a value for the member. If your GameConfigKeyValue config sheets contain empty cells for member values and you want to keep the original behavior, you should initialize these members to their desired values in their C# classes.
Before release 27, when a member's value cell in a GameConfigKeyValue sheet was empty, it would be parsed from the empty string. Starting with release 27, members with empty values are ignored by the parser, and will get whatever initial value the C# member has (often null or zero by default), behaving as if the row didn't appear in the sheet.
For example, if you have a GameConfigKeyValue class like this:
[MetaSerializable]
public class GlobalConfig : GameConfigKeyValue<GlobalConfig>
{
[MetaMember(1)] public int InitialGold;
[MetaMember(2)] public int InitialGems = 5;
[MetaMember(3)] public string DefaultPlayerName;
[MetaMember(4)] public string GreetingText = "Hello, player!";
}with a sheet like this (where all the Values are empty):
| Member | Value |
|---|---|
| InitialGold | |
| InitialGems | |
| DefaultPlayerName | |
| GreetingText |
Then, before release 27 (ignoring the fact that the Member and Value headers would not be present before release 27):
InitialGold and InitialGems being empty would cause config build errors, because int cannot be parsed from the empty string.DefaultPlayerName and GreetingText would both end up being the empty string (if we ignore the fact that the config build fails due to InitialGold and InitialGems being empty).Starting with release 27:
InitialGold is 0.InitialGems is 5.DefaultPlayerName is null.GreetingText is "Hello, player!".If existing empty-string values in GameConfigKeyValue sheets are important in your project, you should adjust the corresponding C# members to be initialized as the empty string. Unfortunately, there is currently no way to represent an empty string in the config sheet in case the C# member is initialized with some other value. We'd be happy to know if this is important for you.