Table of Contents

Systems Overview

The RisingV.Core.Systems namespace contains a collection of “System” classes that encapsulate core game mechanics and domain-specific logic within the RisingV framework. Each System interacts directly with Unity’s Entity Component System (ECS) or hooks into RisingV’s event architecture to manage in‑game functionality such as castle ownership, territorial control, chat handling, clan management, damage tracking, and loot distribution. By centralizing these workflows, Systems ensure consistent, maintainable behavior across plugins and support hot‑reload without losing runtime state.


API Documentation

For full details on available classes and methods in RisingV.Core.Systems, refer to the official API reference:

🔗 RisingV.Core.Systems API Reference


Role and Responsibilities

  1. Encapsulation of Domain Logic
    Each System class groups related functionality around a specific game domain. For example:

    • CastleHeartSystem locates and queries “Castle Heart” entities (the central building in a player’s castle).
    • CastleTerritorySystem translates world‑space positions into grid coordinates and determines which castle (and thus which clan) controls a particular region.
    • ChatSystem intercepts low‑level network chat events, decodes message payloads, and publishes them as RisingV events.
    • ClanSystem manages clan creation, membership, and leadership roles by manipulating ECS components on player entities.
    • DamageTrackingSystem tracks and aggregates damage dealt by players to targets, enabling percent‑based loot distribution or stat calculations.
    • LootSystem listens for unit death events, consults damage tracking data, and spawns item drops based on configured loot tables and player contributions.
  2. Integration with ECS & EventBridge

    • Most Systems inherit from Shared.Systems.System, which provides convenience methods for scheduling updates and subscribing to RisingV’s in‑game events (EventBridge).
    • Systems often create EntityQuery instances (wrapped in LazyRetry for on‑demand initialization) to locate entities with specific component combinations (e.g., CastleHeart + TeamData for castle ownership).
    • By responding to events instead of patching game methods directly, Systems decouple game integration from mod logic. This allows multiple plugins to rely on the same core System APIs and ensures consistent behavior even if underlying game code changes.
  3. Stateful Management & Hot‑Reload

    • Many Systems maintain runtime state (cached queries, dictionaries of tracked damage, etc.).
    • When a plugin or server hot‑reloads, System constructors and OnUpdate loops re‑initialize or resume operation seamlessly—no manual intervention needed to rebuild queries or re‑attach handlers.
    • Underlying data (e.g., active damage maps, registered clan relationships) may persist in shared databases or in ECS components, ensuring minimal disruption across reloads.
  4. Interoperability with Engines & Aspects

    • Systems often delegate specific tasks to Engines (e.g., LootEngine, DamageEngine, DeathEngine) and Aspects (e.g., EntityAspect, BuffAspect) to perform high‑level operations such as spawning loot, applying buffs, or writing to persistent databases.
    • For example, LootSystem uses DamageTrackingSystem data to call LootEngine.SpawnLoot for each eligible player, ensuring correct distribution of drops.

Core System Classes

Below is a summary of each System class provided by RisingV.Core.Systems, along with its primary purpose and typical usage. Click the class name to view its API reference.

CastleHeartSystem

  • Namespace: RisingV.Core.Systems
  • Purpose: Locates all “Castle Heart” entities and provides utilities to query which castle belongs to which player or clan.
  • Key Methods:
    • GetAllCastleHearts(): Returns an array of all active Entity instances that have both CastleHeart and TeamData components.
    • FindCastleHeartForUser(Entity user): Searches for the castle heart entity associated with a given user’s User component.
  • Usage:
    // Determine if a user owns a castle
    if (CastleHeartSystem.FindCastleHeartForUser(playerUserEntity, out var heartEntity))
    {
        // 'heartEntity' is the Castle Heart owned by the player
    }
    
  • API Reference: CastleHeartSystem

CastleTerritorySystem

  • Namespace: RisingV.Core.Systems
  • Purpose: Converts world positions into a grid coordinate system and determines which castle (and thus which clan) controls a specific tile. This supports territory‑based gameplay (e.g., claiming land, region‑specific rules).
  • Key Methods:
    • GetGridPosition(Vector3 worldPos): Computes the discrete grid tile for a world position.
    • GetCastleOwnerAtPos(float3 worldPos): Returns the Entity of the castle that controls the given position, or Entity.Null if unoccupied.
  • Usage:
    // Check castle ownership for a location
    float3 worldPosition = new float3(10f, 0f, -5f);
    Entity owningCastle = CastleTerritorySystem.GetCastleOwnerAtPos(worldPosition);
    if (owningCastle != Entity.Null)
    {
        // The returned Entity is the Castle Heart controlling that tile
    }
    
  • API Reference: CastleTerritorySystem

ChatSystem

  • Namespace: RisingV.Core.Systems
  • Purpose: Intercepts and processes raw network chat events from Stunlock’s game code, decodes message payloads, and exposes a clean API for sending or receiving chat messages via RisingV’s EventBridge.
  • Key Features:
    • Registers handlers for incoming chat packets (ChatMessageEventQuery) to publish ChatMessageEvents to plugin subscribers.
    • Provides SendChat(Entity sourceEntity, string message) to programmatically broadcast messages from a specific player or system.
  • Usage:
    // Subscribe to chat messages
    EventBridge.Subscribe<ChatMessageEvent>(evt => {
        Logger.LogInfo($"Received chat from {evt.SourceEntity}: {evt.MessageText}");
    });
    
    // Send a system announcement
    ChatSystem.SendChat(systemEntity, "[Server] Welcome to the Realm!");
    
  • API Reference: ChatSystem

ClanSystem

  • Namespace: RisingV.Core.Systems
  • Purpose: Manages all clan‑related state, including creation, membership, leadership roles, and deletion. Encapsulates common clan operations by reading and writing ECS components on user entities.
  • Key Methods:
    • GetByName(string clanName): Returns the Entity of a clan by its name, or Entity.Null if not found.
    • GetClanLeader(Entity clanEntity): Returns the user entity of the clan leader for a specified clan.
    • GetClanMembersAsPlayers(Entity clanEntity): Returns a list of all players in the specified clan, including their user entities.
    • IsClanLeader(User user): Checks if a user holds the Leader role.
  • Usage:
    // Create a new clan for the player
    Entity clanEntity = ClanSystem.GetByName("VampireLegion");
    
    var leader = ClanSystem.GetClanLeader(clanEntity);
    var members = ClanSystem.GetClanMembersAsPlayers(clanEntity);
    
    // Check if a user is the clan leader
    bool isLeader = ClanSystem.IsClanLeader(playerUser);
    
  • API Reference: ClanSystem

DamageTrackingSystem

  • Namespace: RisingV.Core.Systems
  • Purpose: Aggregates all damage dealt by players (or other entities) to a given target. This fine‑grained tracking enables percent‑based reward distribution (e.g., loot sharing) and advanced stat calculations.
  • Key Features:
    • Listens for DamageEvents or similar hooks to incrementally accumulate damage per source entity.
    • Maintains an in‑memory map (damageComponent) keyed by target entity ID, storing DamageMap instances that record totals, percentages, and level information.
    • Exposes methods to retrieve or reset damage data for a given target.
  • Usage:
    // During a death event, query top damage contributor
    IReadOnlyDictionary<NetworkId, DamageMap> damageMap = DamageTrackingSystem.GetDamageMap(targetEntity);
    var sortedContributors = damageMap.OrderByDescending(kvp => kvp.Value.TotalDamage);
    var topContributor = sortedContributors.First().Key;
    
  • API Reference: DamageTrackingSystem

LootSystem

  • Namespace: RisingV.Core.Systems
  • Purpose: Coordinates item drop logic when entities die. By consulting DamageTrackingSystem, it fairly distributes loot according to each contributor’s damage percentage, and then interacts with RisingV’s item‐spawning APIs to physically drop items in the world.
  • Key Features:
    • Subscribes to UnitDeathEvent and calculates drop shares for each eligible player.
    • Uses IItemDrop implementations (configured through item definitions or drop tables) to determine exactly what to spawn for each contributor.
    • Safely handles errors in drop operations and logs failures to aid debugging.
  • Usage:
    // Automated via event subscription; no explicit call needed unless customizing behavior
    
    // Example: Extend drop logic with a special event
    EventBridge.Subscribe<UnitDeathEvent>(evt => {
        if (FactionAspect.GetFaction(evt.Victim).Equals(Faction.Boss))
        {
            var itemsToDrop = LootSystem.GenerateItemDrops(_lootTables[evt.Victim.GetHashCode()]);
            var itemsDropped = LootSystem.DropItemsNearby(evt.Victim, itemsToDrop);
            // or
            var itemsDropped = LootSystem.GenerateAndDropItems(evt.Victim, itemsToDrop);
        }
    });
    
  • API Reference: LootSystem

Integration & Usage

  1. Registration

    • Systems are typically registered during plugin initialization via SystemManager. For example in Plugin.OnInitialize():
      SystemManager.AddSystem<ChatSystem>(this);
      SystemManager.AddSystem<ClanSystem>(this);
      SystemManager.AddSystem<DamageTrackingSystem>(this);
      SystemManager.AddSystem<LootSystem>(this);
      SystemManager.AddSystem<CastleHeartSystem>(this);
      SystemManager.AddSystem<CastleTerritorySystem>(this);
      
    • After Ready(), all systems are active: queries are built, event subscriptions are live, and ECS interactions can proceed normally.
  2. Event Subscriptions

    • Many Systems publish or consume events via EventBridge. Plugin authors can hook into these events for custom logic. For example, subscribe to ChatMessageEvent to modify or filter chat messages, or to UnitDeathEvent to award achievements.
  3. ECS Queries

    • Systems use LazyRetry<EntityQuery> wrappers to defer query creation until entities and components are guaranteed to exist. This avoids null references during server start or plugin reload.
    • For example, CastleHeartSystem.HeartQuery only builds its EntityQuery the first time it’s needed, and retries if initial creation fails.
  4. Hot‑Reload Support

    • Because Systems rely on shared ECS components and event subscriptions, a hot‑reload (triggered by BepInEx or plugin manager) seamlessly reconnects Systems:
      • Queries are lazily reinitialized.
      • Cached damage data or clan state stored in persistent components remains intact.
      • Event subscriptions resume automatically once Reload() completes.
  5. Cross‑System Collaboration

    • Systems often delegate tasks to Engines or Aspects. For example:
      • LootSystem calls DamageTrackingSystem.GetDamageMap(...) (another System) before spawning items via ItemAspect or LootEngine.
      • CastleTerritorySystem uses CastleHeartSystem.FindCastleHeartForUser(...) to resolve ownership.
    • This layered approach promotes single responsibility:
      • Hooks publish raw events.
      • Systems process and validate event data.
      • Engines/Aspects execute high‑level logic (e.g., database updates, world modifications).

Summary

The RisingV.Core.Systems layer is a critical part of the RisingV architecture, responsible for:

  • Encapsulating core gameplay mechanics (chat, clans, castles, damage, loot).
  • Processing in‑game events and coordinating with Engines/Aspects for persistent effects.
  • Abstracting direct ECS interactions and network packet handling behind well-defined APIs.
  • Ensuring consistent behavior across plugins and supporting hot‑reload without losing runtime state.

By leveraging these System classes, plugin authors can focus on feature development—knowing that RisingV.Core.Systems will reliably manage underlying game interactions and maintain a cohesive, event‑driven workflow.