Appearance
Appearance
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 Value
s 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.