Relationship System

v1.1.0

Core Concepts

Understand the fundamental concepts of the Relationship System.

Entities & Relationships

An Entity is anything that can participate in relationships. All entities implement the IRelationshipEntity interface:

  • EntityId — Stable unique identifier (deterministic, survives sessions)
  • EntityName — Display name for UI and logs
  • EntityIcon — Optional visual representation
  • EntityType — Character, Faction, or Custom

A Relationship is a numeric value between two entities, optionally scoped to a specific definition. Relationships are stored as RelationshipState objects with a current value, level, lock state, and definition reference.

Entity Types

Characters

GameObject with CharacterRelationship component

Player, NPCs, Merchants, Guards

Factions (SO)

ScriptableObject — defined at edit time

Town Guards, Merchants Guild

Runtime Factions

Created dynamically at runtime

Player Guilds, Dynamic Alliances

Relationship Definitions

A RelationshipDefinition is a ScriptableObject template that defines how a relationship type behaves. One definition can be shared across many entity pairs.

Value Range & Start

Min/max values (e.g., -100 to +100) and initial value for new relationships

Relationship Levels

Named tiers with thresholds, colors, and optional GC2 onEnter/onExit actions

Symmetry Mode

Symmetric (A↔B, default) or Asymmetric (A→B ≠ B→A) per definition

Decay Settings

Optional decay with Linear, Curve, or Asymmetric modes

History Tracking

Optional audit log with configurable buffer size per definition

Stat Modifiers

GC2 Stats integration (optional)

Symmetric & Asymmetric Relationships

Symmetric (Default)

isSymmetric = true

A's relationship with B equals B's relationship with A. Entity IDs are sorted — modifying from either direction changes the same value.

Player ↔ Merchant: 75
// Same value regardless of direction

Asymmetric (Opt-in)

isSymmetric = false

A→B and B→A are independent values. Entity order is preserved — each direction is a separate relationship.

Player → Companion: 80 (Player trusts)
Companion → Player: 45 (Companion wary)
Asymmetric is opt-in per definition. Existing symmetric definitions continue to work unchanged. The resolver falls back from directional to symmetric lookups automatically, so asymmetric definitions can still inherit from symmetric faction relationships.

Multi-Dimensional Relationships

The same entity pair can have multiple independent relationships, each scoped to a differentRelationshipDefinition. This enables separate dimensions like trade reputation and personal trust between the same characters.

Player ↔ Merchant:
├─ "Trade Reputation"  → 80 (Trusted)
├─ "Personal Trust"    → 30 (Cautious)
└─ "Guild Standing"    → 60 (Respected)

// Each dimension is independent with its own levels and decay
Without a definition, the system uses a single default relationship per entity pair. Multi-dimensional is opt-in by passing different definitions to Modify/Set/Get operations.

Relationship Levels

Levels are named tiers based on value thresholds, defined per RelationshipDefinition. They enable gameplay changes at specific reputation milestones.

Example: Merchant Reputation

-50
Hostile
0
Neutral
+50
Friendly
+75
Trusted

Each level has a threshold value, display name, color, and optional GC2 InstructionLists for onEnter/onExit actions. Level transitions fire OnRelationshipLevelChanged events.

Factions & Inheritance

Factions group characters for collective reputation management. They are ScriptableObjects that implement IRelationshipEntity, meaning factions themselves can have relationships with other factions or characters.

Hierarchies

Parent/child relationships with configurable inheritance rates

Auto-Assignment

Automatic membership via GameObject tags

Broadcasting

Modify all faction members at once

Stable Entity IDs

Factions use asset-based GUID for reliable persistence across sessions

Faction Hierarchies

Kingdom (Parent)
├─ Royal Guards (Child — inheritanceRate: 0.7)
│  ├─ Captain
│  └─ Guard #1
└─ Merchants Guild (Child — inheritanceRate: 0.3)
   └─ Guild Master

Player attacks Guard #1:
1. Royal Guards → Player: -75 (broadcast)
2. Kingdom → Player: -52.5 (70% from Royal Guards)
3. Merchants Guild observes: -15.75 (30% of Kingdom)

Configurable Inheritance

Each faction controls how much of its parent's relationships it inherits:

PropertyDescription
inheritanceRate0.0–1.0. How much of parent's value to inherit (0 = none, 1 = full)
dynamicInheritanceIf true, parent values are scaled on every lookup. If false, only when the child relationship is first created.
inheritOnFirstInteractionIf true, create child relationships from parent on first interaction with unknown entities
propagateToChildrenNone, OnChange (every change), or OnLevelChange (level transitions only)
The inheritance system has both pull (dynamic lookup via resolver) andpush (propagation on parent change) mechanisms. Use dynamic inheritance for real-time faction hierarchy effects, and propagation for event-driven cascading.

Stable Entity IDs

The system uses deterministic entity IDs to ensure save/load reliability across play sessions. The old GUID-based system is replaced with three ID modes:

Manual

Designer sets the ID in the Inspector. Best for scene entities (key NPCs, named characters).

Asset-Based

References an EntityIdAsset ScriptableObject. Best for prefab entities that are spawned or pooled.

Deterministic (Fallback)

Generated from scene name + hierarchy path + name. Editor warning when this mode is active.

Factions use their AssetDatabase GUID (serialized in m_StableId) for stability across builds. If a relationship is loaded before the target entity registers, it enters a pending queue and is applied automatically once the entity becomes available.