V2/Domain/LocationIndex.cs

Index that maps each ItemId to a single authoritative ItemLocation (inventory or world). It builds the map from collections of InventoryRecord and WorldItemRecord and throws if an item appears in more than one place.

Native Interop
#nullable enable

using System;
using System.Collections.Generic;

namespace Hexagon.V2.Domain;

public enum ItemLocationKind
{
	Inventory,
	World
}

public readonly record struct ItemLocation( ItemLocationKind Kind, Guid ContainerId );

/// <summary>
/// Derived invariant index ensuring that an item has exactly one authoritative location.
/// </summary>
public sealed class ItemLocationIndex
{
	private readonly Dictionary<ItemId, ItemLocation> _locations = new();

	public IReadOnlyDictionary<ItemId, ItemLocation> Locations => _locations;

	public void Build( IEnumerable<InventoryRecord> inventories, IEnumerable<WorldItemRecord> worldItems )
	{
		_locations.Clear();

		foreach ( var inventory in inventories )
		{
			foreach ( var placement in inventory.Placements )
				AddUnique( placement.ItemId, new ItemLocation( ItemLocationKind.Inventory, inventory.Id.Value ) );
		}

		foreach ( var worldItem in worldItems )
			AddUnique( worldItem.ItemId, new ItemLocation( ItemLocationKind.World, worldItem.ItemId.Value ) );
	}

	public bool TryGet( ItemId itemId, out ItemLocation location ) => _locations.TryGetValue( itemId, out location );

	private void AddUnique( ItemId itemId, ItemLocation location )
	{
		if ( !_locations.TryAdd( itemId, location ) )
			throw new InvalidOperationException( $"Item '{itemId}' has more than one authoritative location." );
	}
}