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;
}