using SilkroadBot.Domain.Enums; namespace SilkroadBot.Domain.Models; /// /// Complete game state snapshot, thread-safe read model. /// public class GameState { private readonly object _lock = new(); public ConnectionState ConnectionState { get; set; } = ConnectionState.Disconnected; public CharacterState Character { get; set; } = new(); public List NearbyEntities { get; set; } = new(); public List Inventory { get; set; } = new(); public List Skills { get; set; } = new(); public List PartyMembers { get; set; } = new(); public List Buffs { get; set; } = new(); public DateTime LastUpdate { get; set; } = DateTime.UtcNow; /// /// Returns a thread-safe snapshot of the current game state. /// public GameStateSnapshot GetSnapshot() { lock (_lock) { return new GameStateSnapshot { ConnectionState = ConnectionState, CharacterName = Character.Name, Level = Character.Level, HP = Character.HP, MaxHP = Character.MaxHP, MP = Character.MP, MaxMP = Character.MaxMP, Position = Character.Position, Gold = Character.Gold, IsInCombat = Character.IsInCombat, IsDead = Character.IsDead, NearbyEntityCount = NearbyEntities.Count, InventoryItemCount = Inventory.Count, PartySize = PartyMembers.Count, LastUpdate = LastUpdate }; } } public void Update(Action updater) { lock (_lock) { updater(this); LastUpdate = DateTime.UtcNow; } } } /// /// Immutable snapshot of game state for safe reading. /// public record GameStateSnapshot { public ConnectionState ConnectionState { get; init; } public string CharacterName { get; init; } = string.Empty; public int Level { get; init; } public int HP { get; init; } public int MaxHP { get; init; } public int MP { get; init; } public int MaxMP { get; init; } public WorldPosition Position { get; init; } public uint Gold { get; init; } public bool IsInCombat { get; init; } public bool IsDead { get; init; } public int NearbyEntityCount { get; init; } public int InventoryItemCount { get; init; } public int PartySize { get; init; } public DateTime LastUpdate { get; init; } public double HPPercentage => MaxHP > 0 ? (double)HP / MaxHP * 100 : 0; public double MPPercentage => MaxMP > 0 ? (double)MP / MaxMP * 100 : 0; }