Inspector extensions
Add serialized project fields to all six Workbench modes through derived content types
To add a field such as Required Level, derive a project type from one of the six GCS content types and declare a Unity-serialized field. Then create an asset of the derived type in a GCS database. Edit its fields in Workbench or in the Unity Inspector. To add the field to existing assets, migrate them to the derived type.
Download GCS-Samples.zip and extract it outside Unity. Copy the Runtime and Editor directories you need from Samples~/InspectorExtensions/ into the corresponding project assemblies.
Keep the content type in a runtime assembly
Place derived content classes and option providers in a player-available assembly that references TinyGiants.GCS.Runtime:
{
"name": "YourGame.GCS.Content",
"references": [
"TinyGiants.GCS.Runtime"
]
}
Declare a top-level public, concrete, non-generic class. Give the .cs file the same name as the class so Unity can associate its MonoScript and Workbench can list it for creation.
| Workbench mode | Derive from | Stored by | Runtime enumeration |
|---|---|---|---|
| Card | GameCard | GameCardDatabase.Cards | GCSApi.Cards() |
| Deck | GameDeck | GameDeckDatabase.Decks | GCSApi.Decks() |
| Player | GamePlayerUnit | GamePlayerUnitDatabase.PlayerUnits | GCSApi.PlayerUnits() |
| Enemy | GameEnemyUnit | GameEnemyUnitDatabase.EnemyUnits | GCSApi.EnemyUnits() |
| Status | GameStatus | GameStatusDatabase.Statuses | GCSApi.Statuses() |
| Encounter | GameEncounter | GameEncounterDatabase.Encounters | GCSApi.Encounters() |
The following class adds one RequiredLevel field to SampleCard
using TinyGiants.GCS.Runtime;
public sealed class SampleCard : GameCard
{
public int RequiredLevel;
}
After Unity compiles, open Card and click +. When multiple types are available, the menu lists GameCard first and sorts project types by display name, with assembly names shown for duplicates. Choose SampleCard to create a sub-asset in the selected Card Database. Its fields, including Required Level, are editable in Workbench and the Unity Inspector. The other five modes support derived types in the same way, using their own GCS base types.
Declare fields with Unity serialization rules
Workbench uses Unity's visible serialized fields. Declare a public instance field or apply [SerializeField] to a private field. Use a type Unity can serialize, such as a primitive, enum, Unity object reference, serializable class or struct, array, or supported list. Apply [HideInInspector] when a serialized field should stay out of both inspectors.
using System;
using System.Collections.Generic;
using TinyGiants.GCS.Runtime;
using UnityEngine;
public sealed class SampleCard : GameCard
{
[GCSSection("Basic")]
[Min(1)]
[Tooltip("Minimum character level required to play this card.")]
public int RequiredLevel = 1;
[GCSSection("Visual")]
[Tooltip("Optional voice line used by project presentation code.")]
public AudioClip VoiceLine;
[GCSSection("Extension Data", "◆")]
[Range(0, 100)]
public int Power = 10;
[TextArea(2, 5)]
public string Lore;
}
Required Level appears in Basic, Voice Line in Visual, and Power and Lore in the Extension Data foldout with the ◆ icon
Control section placement with declaration order
Sections follow their first appearance in the class. Fields appear in declaration order, and reusing a section appends the field to that section.
| Declaration | Result |
|---|---|
[Header("Extension Data")] | Selects or creates the Extension Data foldout starting with this field |
[GCSSection("Basic")] | Selects the existing Basic foldout, or creates it when it does not exist |
| A following field without either attribute | Continues in the current section for the same declaring type |
| First field of a derived declaring type without either attribute | Enters the Additional foldout |
Another [Header] or [GCSSection] | Changes the current section from that field onward |
Use the exact names Basic, Visual, or Behavior to add fields to those foldouts. Derived fields appear after the base-class fields.
GCSSectionAttribute accepts either a glyph or a project-relative Assets/ or Packages/ icon path. A supplied icon overrides the built-in icon for a section with the same name:
[GCSSection("Progression", "★")]
public int RequiredLevel;
[GCSSection(
"Presentation",
"Assets/YourGame/GCS/Editor/Icons/presentation.png")]
public Color PresentationTint;
Asset paths can reference an imported Sprite or Texture2D. An invalid path falls back to the section's built-in icon and writes one warning for that path to the Console.
The following standard Unity attributes have explicit Workbench behavior:
| Attribute | Workbench behavior |
|---|---|
[Header] | Starts or reuses a foldout and makes it current |
[Tooltip] | Applies the tooltip to the field row and control |
[Space] | Adds vertical space before the field |
[Min] | Clamps an edited integer or float to the declared minimum |
[Range] | Uses an integer or float slider with an input field |
[TextArea], [Multiline] | Uses a multiline text field |
[Delayed] | Commits string, integer, or float input after editing finishes |
[InspectorName] | Replaces the nicified field label or enum-option label |
[SerializeField], [HideInInspector] | Follow normal Unity visibility rules |
[GCSLabel] takes precedence over [InspectorName], registered controls and GCS attributes such as [GCSOptions] select controls before Unity CustomPropertyDrawer
Without a GCS control, Workbench uses Unity PropertyField, preserving project PropertyAttribute and CustomPropertyDrawer behavior, register a custom UI Toolkit control through Inspector controls
Supply single-choice options
GCSOptionsAttribute applies to a serialized string. It accepts one of three sources:
[GCSOptions(
"Physical", "Fire", "Frost", "Lightning", "Arcane",
Editable = true)]
public string DamageSchool = "Physical";
[GCSOptions(typeof(SampleFactionOptionProvider))]
public string Faction = "alliance.kingdom";
Editable = false uses a selection-only field. Editable = true also accepts values outside the current option list. Workbench adds non-empty values stored in the same field across the current database to later dropdowns. Set EmptyValue to define the value stored when the field is cleared; the built-in Rarity, Enemy Tier, and Encounter Difficulty fields use Common, Normal, and Normal respectively.
In this sample, DamageSchool accepts either a preset or a new value. Faction stores the value returned by SampleFactionOptionProvider while showing the provider's label in the dropdown.
| Built-in source | Values supplied by GCS |
|---|---|
None | No built-in single-choice values |
CardType | Built-in and authored card types |
CardRarity | Built-in and authored card rarities |
CardTag | Authored card tags |
CardKeyword | Registered CardTag IDs with their display labels |
EnemyTier | Built-in and authored enemy tiers |
EncounterDifficulty | Built-in and authored encounter difficulties |
Dynamic providers implement the Runtime interface IGCSInspectorOptionProvider and provide a public parameterless constructor, Workbench creates the provider when rebuilding options and passes the current content object to GetOptions
using System.Collections.Generic;
using TinyGiants.GCS.Runtime;
using UnityEngine;
public sealed class SampleFactionOptionProvider : IGCSInspectorOptionProvider
{
public IEnumerable<GCSInspectorOption> GetOptions(Object target)
{
yield return new GCSInspectorOption(
"alliance.kingdom",
"Kingdom Alliance",
new[] { "World", "Alliance", "Kingdom" },
"Human kingdoms joined under one banner.");
yield return new GCSInspectorOption(
"horde.ashen",
"Ashen Horde",
new[] { "World", "Horde", "Ashen Marches" },
"Raiders from the volcanic frontier.");
}
}
Each option returned by the provider contains four values
| Provider member | Purpose |
|---|---|
Value | Value written to the serialized field |
Label | Text shown to the author in the dropdown |
GroupPath | Explicit page path with any depth, one segment can contain / |
Tooltip | Hover description for the option |
Workbench ignores case when removing duplicate Value entries, use stable, unique values
Supply multiple-choice values
GCSMultiSelectAttribute applies to List<string> or string[]. It accepts the same fixed-option, provider-type, and built-in-source constructors as GCSOptionsAttribute.
[GCSMultiSelect(
"Humanoid", "Construct", "Undead", "Beast", "Quest",
Mode = GCSMultiSelectMode.Freeform)]
public List<string> Traits = new List<string>();
[GCSMultiSelect(
typeof(SampleSpellOptionProvider),
Mode = GCSMultiSelectMode.OptionsOnly)]
public List<string> GrantedSpells = new List<string>();
| Mode | Authoring behavior |
|---|---|
Freeform | Accepts comma-delimited project values and also exposes the available values in a multiple-selection dropdown |
OptionsOnly | Shows ordered removable chips and only adds values through the supplied option dropdown |
Traits uses Freeform, so it accepts typed values and dropdown selections. Workbench adds values already stored in SampleCard.Traits to the dropdown for later use.
GrantedSpells uses OptionsOnly, so it accepts only values returned by SampleSpellOptionProvider and displays selected values as removable chips.
Select other GCS content
GCSSubAssetAttribute replaces an ordinary ScriptableObject reference with the GCS content picker. The picker searches registered databases, accepts derived instances of the requested base type, and can render a compact row or a summary card.
[GCSSubAsset(
typeof(SampleStatus),
Style = GCSSubAssetStyle.Card)]
public SampleStatus SignatureStatus;
SampleCard.SignatureStatus accepts only SampleStatus assets. Use GCSSubAssetListAttribute on an array or list when a field stores multiple GCS content references:
[GCSSubAssetList(typeof(GameEnemyUnit), Required = true)]
public List<GameEnemyUnit> Reinforcements = new List<GameEnemyUnit>();
Required shows an inline warning when a reference is empty or a required list has no entries. Register a project validator to surface the missing reference as an Issue Badge. Create the content in its database first so it appears in the picker.
Flatten serializable settings with GCSInline
GCSInlineAttribute exposes the direct visible children of a serializable class or struct in the current section without adding another nested property box.
using System;
using TinyGiants.GCS.Runtime;
using UnityEngine;
[Serializable]
public sealed class SampleCardStats
{
[Min(0)]
public int BaseDamage = 6;
[Range(0f, 1f)]
public float CriticalChance = 0.1f;
}
public sealed class SampleCard : GameCard
{
[GCSInline]
public SampleCardStats Stats = new SampleCardStats();
}
Inspector initializes a null field when its type is concrete and has a parameterless constructor, inline data must follow Unity serialization rules
Put fields with GCSFlowGraphAttribute directly on the content class so the FlowGraph Editor can resolve their paths. For inline data, use the full path, such as Stats.BaseDamage. For top-level fields, use nameof(SampleCard.RequiredLevel). Workbench checks PropertyPath first and falls back to FieldLabel. See Inspector controls.
Edit lists with GCSList
Apply [GCSList] to an array or List<T> field when an asset needs multiple sets of values. Workbench and the GCS content Inspector show the item count, an Add Item button, and controls for each item. Visible child fields of ordinary serialized objects use the standard GCS field controls.
public sealed class SampleCard : GameCard
{
[GCSList]
public List<SampleCardStats> BonusStats = new List<SampleCardStats>();
}
Click Add Item, then fill in Base Damage, Critical Chance, and Armor Penetration. Drag the handle on the left or use the up and down arrows on the right to reorder items. Click the minus button to remove an item. Edits are saved to the original list field and support Unity Undo/Redo.
New ordinary elements start with zero for numeric values, empty strings, and None for object references. For classes with a parameterless constructor, the constructor supplies initial field values. You can also use [GCSList] on a nested list in a [GCSInline] object or list element.
| Element type | Editor behavior |
|---|---|
int, float, string, bool, and ordinary enums | Uses GCS field controls and displays ordinary enums in a dropdown |
| Serializable class or struct | Expands visible child fields and preserves supported GCS attributes, ranges, and tooltips |
| Unity object reference | Uses an object picker. Apply [GCSSubAssetList] to select content from a GCS database |
[SerializeReference] list | Lets you select a compatible, concrete, serializable, non-generic class or None for each item |
Element with a custom PropertyDrawer | Uses the custom drawer for the element and GCS styling for the surrounding list |
New items in a [SerializeReference] list start as None. Choosing a concrete type creates an instance. Changing the type replaces the item's data, and Undo restores it. Fields without a dedicated GCS control use Unity's property controls.
[GCSInline] expands a single nested object. [GCSList] handles list layout and item operations, and existing custom drawers still handle their own rendering.
To control field visibility with project rules, define the condition in your drawer or a registered Inspector control. The GCS content Inspector recognizes these attributes.
Add a FlowGraph editing field
GCSFlowGraphAttribute applies to a direct GameEffectFlowGraph field and adds Edit FlowGraph plus a static summary.
public sealed class ProjectCard : GameCard
{
[GCSFlowGraph(GCSFlowGraphSummary.Entries)]
public GameEffectFlowGraph AlternateBehavior = new GameEffectFlowGraph();
}
Entries summarizes entry nodes. EnemyIntents summarizes patterns, leaf intents, and action nodes.
Declare graph fields directly on a derived Card, Status, or Enemy, FlowGraph Editor checks nodes using that content type
The built-in Behavior runs in battle and receives built-in Workbench validation. To execute and check AlternateBehavior, call it from project code and register a validator.
Reuse other built-in field controls
The following Runtime attributes select built-in GCS field controls
| Attribute | Required field | Result |
|---|---|---|
[GCSAssetName] | string | Edits the value and renames the content sub-asset when the value is non-empty |
[GCSDescription] | string | Uses the GCS description editor with token and semantic-reference support |
[GCSLabel("Label")] | Any serialized field | Overrides the displayed label |
[GCSSegmentedBool("Off", "On")] | bool | Uses a two-segment Boolean picker |
[GCSDeckEntries] | GameDeck.Entries | Uses the card count picker and deck summary UI |
[GCSSection("Name", "Glyph or asset path")] | Any serialized field | Selects a named Workbench section from this field onward and optionally supplies its icon |
If an attribute and field type are incompatible, Workbench displays the standard serialized field control.
Read the same typed data at runtime
Databases and GCSApi expose the base types, so use normal C# type checks or OfType<T>() to reach project fields:
using System.Linq;
using TinyGiants.GCS.Runtime;
SampleCard firstSampleCard = GCSApi.Cards()
.OfType<SampleCard>()
.FirstOrDefault();
if (firstSampleCard != null)
{
int requiredLevel = firstSampleCard.RequiredLevel;
}
if (cardInstance.GetActiveCard() is SampleCard activeSampleCard)
{
PlayVoice(activeSampleCard.VoiceLine);
}
if (unitState.Source is SampleEnemy sampleEnemy)
{
ApplyEnemyRules(sampleEnemy);
}
The same pattern works with GCSApi.Decks(), PlayerUnits(), EnemyUnits(), Statuses(), and Encounters(). These methods enumerate active databases and allocate a fresh list, so cache a result that is read repeatedly.
Use derived fields for authored values. Store temporary card or unit values on their runtime state or in supported battle variables.
Preserve data through authoring operations
Workbench saves derived fields through Unity serialization. Duplicate and Paste preserve the concrete type and serialized fields and assign a unique name and GCS ID. Paste into a mode that accepts the source type. Workbench Clipboard stores object references in the current Unity Editor domain, so copy again after restarting the editor or after a domain reload.
Built-in field edits, creation, duplication, deletion, and database membership changes support Unity Undo, custom controls also support Undo/Redo when saving through GCSInspectorFieldContext.Modify, see Inspector controls
Preserve data references when changing saved types or fields
-
Use
[FormerlySerializedAs]when renaming a serialized field. -
Keep derived type names and assembly ownership stable, or provide an explicit asset migration.
-
Create a project migration tool when existing base assets must become a new derived type.
To show a derived field in your card face or runtime presentation, read that field from your project's UI code.