Item Drops

Service Architecture (Drop Service)

🎯 Goal

Item Drops follows the same core services + engine adapters approach used across the rest of the game. The core exposes a Drop Service abstraction, while Godot/Unity provide adapter layers for scene integration.

1. Core Service: IDropService

Namespace: ItemDrops.Core.Services

public interface IDropService
{
    IReadOnlyList<DropResult> GenerateDrops(string tableId, LootContext context);
    DropStatistics GetStatistics(string tableId, LootContext? context = null, int simulations = 1000);
    void RegisterDropTable(string id, IDropTable dropTable);
}

Key points:

  • Operates on core types only (DropResult, LootContext, IDropTable).
  • Knows nothing about Godot or Unity.
  • Encapsulates use of DropTableRegistry and DropCalculator.

2. Default Implementation: DropService

Namespace: ItemDrops.Core.Services

var registry = new DropTableRegistry();
var service  = new DropService(registry);

service.RegisterDropTable("default_enemy", enemyTable);
var drops = service.GenerateDrops("default_enemy", new LootContext { LuckModifier = 1.0f });
  • Uses DropTableRegistry to resolve tables by ID.
  • Uses DropCalculator internally to produce DropResult collections.
  • Reuses DropTableRegistry.GetStatistics for analysis.
    • Hosts are responsible for computing a luck scalar from game state and passing it via LootContext.LuckModifier; DropCalculator multiplies the table’s DropChance by this value (clamped to [0,1]) and does not apply any GlobalConditions or GlobalModifiers at runtime.

3. Engine Adapters

Godot: ItemDropsBus and EnemyDrops

  • ItemDropsBus (ItemDrops.Godot.Resources) is the Godot adapter:
    • Owns DropTableRegistry, LootGeneratorRegistry, and a DropCalculator.
    • Provides methods like GenerateDrops and GenerateLoot that return Godot Node instances.
    • Spawns scenes using GodotDropSpawner.
  • EnemyDrops is a scene-level component:
    • Resolves defaults via ItemDropsBus (currently through a legacy singleton, see below).
    • Builds LootContext from enemy state and calls into drop tables.

Unity: ItemDropsManager

  • ItemDropsManager (ItemDrops.Unity.Managers) is the Unity adapter:
    • Manages Unity DropTableAsset resources.
    • Uses LootGenerator and DropCalculator to produce DropResult collections.
    • Spawns GameObject instances into the scene.

In both cases, the core drop logic remains in ItemDrops.Core (tables, generators, calculators). Engine layers deal only with scenes, nodes, and prefabs.

4. Legacy DI / Singleton Patterns

Some older access patterns remain for backward compatibility and are now explicitly marked as obsolete:

Godot: ItemDropsBus.Instance

[Tool]
public partial class ItemDropsBus : Resource
{
    private static ItemDropsBus? _instance;

    [System.Obsolete("Use scene- or resource-local ItemDropsBus instances wired via dependency injection instead of the global singleton. This property will be removed in a future version.")]
    public static ItemDropsBus Instance { get; }
}
  • Existing code like ItemDropsBus.Instance.GetDropTable("default_enemy") will continue to work.
  • New code should instead:
    • Expose an ItemDropsBus resource via scene or DI container.
    • Inject it into systems that need drop management.

Unity: ItemDropsManager.Instance

public class ItemDropsManager : MonoBehaviour
{
    private static ItemDropsManager instance;

    [System.Obsolete("Use explicitly injected ItemDropsManager instances or services instead of the global singleton. This property will be removed in a future version.")]
    public static ItemDropsManager Instance { get; }
}
  • Existing uses of ItemDropsManager.Instance are still supported.
  • New code should obtain managers or services via explicit references (scene wiring, DI, or a shared service registry) instead of relying on global static state.
  • Core / shared code

    • Depend on IDropService rather than concrete registries.
    • Configure a DropService instance in your composition root and pass it to systems that need to generate or analyze drops.
  • Godot

    • Treat ItemDropsBus as the primary adapter for scene integration.
    • Prefer scene- or resource-local instances over the static Instance when writing new code.
  • Unity

    • Treat ItemDropsManager as an adapter for prefabs and GameObject spawning.
    • Prefer explicit references in scenes/MonoBehaviours instead of the global singleton instance for new systems.

This keeps Item Drops aligned with the broader service + adapter architecture used across the game while clearly marking legacy global DI patterns as obsolete.