Appearance
Key-Value Game Config Data
Key-Value Game Configs are an alternative to Game Config Libraries for simple, elemental data.
Appearance
Key-Value Game Configs are an alternative to Game Config Libraries for simple, elemental data.
In the common case, a single Game Config Library contains multiple Game Config Item, indexed by Game Config Item Identifiers. However, if the Game Config Library by design contains only a single item, the library can be defined as a Key-Value Game Config. This avoids the need of having to define and use an identifier when accessing the data, improving development ergonomics. Additionally, this allows more advanced Spreadsheet layouts to be used.
You can use key-value pairs to create individual tweakable parameters in your configs. For example, here's an instance of a GlobalConfig that defines the players' starting gold and gems:
[MetaSerializable]
public class GlobalConfig : GameConfigKeyValue<GlobalConfig>
{
[MetaMember(1)] public int InitialGold { get; private set; } = 50;
[MetaMember(2)] public int InitialGems { get; private set; } = 10;
}Identically to GameConfigLibrarys, GameConfigKeyValues are then added to the config by adding the entry in your SharedGameConfig.
public class SharedGameConfig : SharedGameConfigBase
{
[GameConfigEntry("Global")]
public GlobalConfig Global { get; private set; }
}The data can now be accessed directly:
SharedGameConfig gameConfig = ...;
int numGold = gameConfig.GlobalConfig.InitialGold;
int numGems = gameConfig.GlobalConfig.InitialGems;To define them in your configs source, the first row should have the Member and Value cells indicating the columns containing the member name and value, respectively. The columns may be in any order.
| Member | Value |
|---|---|
| InitialGold | 50 |
| InitialGems | 10 |
The key-value configs support nested members.
[MetaSerializable]
public class GlobalConfig : GameConfigKeyValue<GlobalConfig>
{
[MetaMember(1)] public IntVector2 StartingCoordinates { get; private set; }
}| Member | Value |
|---|---|
| StartingCoordinates.X | 12 |
| StartingCoordinates.Y | 34 |
It also supports collections, including collections of non-scalars. Naturally, the collection can also be a nested member.
[MetaSerializable]
public class GlobalConfig
{
[MetaMember(1)] public IReadOnlyList<int> MyIntList { get; private set; }
[MetaMember(2)] public IReadOnlyList<IntVector2> MyCoordList { get; private set; }
}| Member | Value |
|---|---|
| MyIntList[0] | 10 |
| MyIntList[1] | 20 |
| MyIntList[2] | 30 |
| MyCoordList[0].X | 1 |
| MyCoordList[0].Y | 2 |
| MyCoordList[1].X | 11 |
| MyCoordList[1].Y | 22 |
Collections can also be written horizontally, without an explicit index inside the brackets. In this case, the values are spread out on multiple columns, starting from the column marked as Value in the header and extending to the right.
| Member | Value | ||
|---|---|---|---|
| MyIntList[] | 10 | 20 | 30 |
| MyCoordList[].X | 1 | 11 | |
| MyCoordList[].Y | 2 | 22 |
The spreadsheet may additionally have a /Variant column to support overrides for experiments. Check out Variant Selector for the column syntax rules and Introduction to Experiments for an introduction to experiments and A/B testing.
| /Variant | Member | Value |
|---|---|---|
| InitialGold | 100 | |
| InitialResourcesExperiment/A | InitialGold | 200 |
| InitialGems | 10 | |
| InitialResourcesExperiment/A | InitialGems | 20 |
It is also possible to use variants for nested members:
| /Variant | Member | Value |
|---|---|---|
| StartingCoordinates.X | 12 | |
| DifferentCoords/A | StartingCoordinates.X | 120 |
| StartingCoordinates.Y | 34 | |
| DifferentCoords/A | StartingCoordinates.Y | 340 |
However, the current implementation has a limitation when multiple different variants patch sub-members of the same top-level member. In this case, if a player belongs to both of those variants, only one of them will take effect for the whole top-level member. For example:
| /Variant | Member | Value |
|---|---|---|
| StartingCoordinates.X | 12 | |
| SomeExperiment/A | StartingCoordinates.X | 120 |
| StartingCoordinates.Y | 34 | |
| OtherExperiment/A | StartingCoordinates.Y | 340 |
Now, for a player belonging to both SomeExperiment/A and OtherExperiment/B, StartingCoordinates will be either (120, 34) or (12, 340), but not (120, 340) like you'd expect.
Comment rows and columns are supported:
| Member | Value | // this column is ignored |
|---|---|---|
| InitialGold | 100 | Player's starting gold |
| // this row is ignored | comment | comment |