using System.Numerics;
using Nexus.Core;
using Nexus.Memory;
namespace Nexus.Data;
///
/// Immutable snapshot of player position for lock-free cross-thread reads.
/// Class (reference type) so volatile assignment is atomic.
///
public sealed class PlayerPositionData
{
public readonly float X, Y, Z;
public readonly bool HasPosition;
private PlayerPositionData() { }
public PlayerPositionData(float x, float y, float z)
{
X = x;
Y = y;
Z = z;
HasPosition = true;
}
public static readonly PlayerPositionData Empty = new();
}
///
/// Immutable snapshot of player vitals for lock-free cross-thread reads.
/// Class (reference type) so volatile assignment is atomic.
///
public sealed class PlayerVitalsData
{
public readonly int LifeCurrent, LifeTotal;
public readonly int ManaCurrent, ManaTotal;
public readonly int EsCurrent, EsTotal;
public readonly bool HasVitals;
private PlayerVitalsData() { }
public PlayerVitalsData(int lifeCur, int lifeMax, int manaCur, int manaMax, int esCur, int esMax)
{
LifeCurrent = lifeCur;
LifeTotal = lifeMax;
ManaCurrent = manaCur;
ManaTotal = manaMax;
EsCurrent = esCur;
EsTotal = esMax;
HasVitals = true;
}
public static readonly PlayerVitalsData Empty = new();
}
///
/// Immutable wrapper for Matrix4x4 so volatile reference assignment works.
///
public sealed class CameraMatrixData
{
public readonly Matrix4x4 Matrix;
public CameraMatrixData(Matrix4x4 matrix)
{
Matrix = matrix;
}
}
///
/// Centralized memory cache — single source of truth for all game data.
/// Hot fields updated at 60Hz (4 RPM calls), cold fields at 10Hz (full snapshot).
/// All fields use volatile reference types or atomic primitives for lock-free cross-thread reads.
///
public sealed class GameDataCache
{
// ── Hot data (updated at 60Hz) ──
public volatile CameraMatrixData? CameraMatrix;
public volatile PlayerPositionData PlayerPosition = PlayerPositionData.Empty;
public volatile PlayerVitalsData PlayerVitals = PlayerVitalsData.Empty;
public volatile bool IsLoading;
public volatile bool IsEscapeOpen;
// ── Cold data (updated at 10Hz) ──
public volatile IReadOnlyList Entities = [];
public volatile IReadOnlyList HostileMonsters = [];
public volatile IReadOnlyList NearbyLoot = [];
public volatile WalkabilitySnapshot? Terrain;
public volatile uint AreaHash;
public volatile int AreaLevel;
public volatile string? CurrentAreaName;
public volatile string? CharacterName;
// ── UI tree root pointer (updated at 10Hz) — tree is read on-demand ──
public volatile nint GameUiPtr;
// ── Quest groups from UI element tree (updated at 10Hz) ──
public volatile IReadOnlyList? UiQuestGroups;
// ── Quest linked lists from GameUi (updated at 10Hz) ──
public volatile IReadOnlyList? QuestLinkedList;
// ── Quest states from AreaInstance sub-object (updated at 10Hz) ──
public volatile IReadOnlyList? QuestStates;
// ── Full GameState (updated at 10Hz) — for systems that need the complete object ──
public volatile GameState? LatestState;
// ── Timestamps ──
private long _hotTickTimestamp;
private long _coldTickTimestamp;
public long HotTickTimestamp
{
get => Interlocked.Read(ref _hotTickTimestamp);
set => Interlocked.Exchange(ref _hotTickTimestamp, value);
}
public long ColdTickTimestamp
{
get => Interlocked.Read(ref _coldTickTimestamp);
set => Interlocked.Exchange(ref _coldTickTimestamp, value);
}
}