Sync daemon authority migration
This commit is contained in:
parent
030b4b5d74
commit
39a0dc8737
295 changed files with 25121 additions and 7360 deletions
158
Assets/Scripts/Gameplay/AetheriaDaemonObserver.cs
Normal file
158
Assets/Scripts/Gameplay/AetheriaDaemonObserver.cs
Normal file
|
|
@ -0,0 +1,158 @@
|
|||
using System;
|
||||
using GameCult.Aetheria.State.Unity;
|
||||
using UnityEngine;
|
||||
|
||||
public sealed class AetheriaDaemonObserver : MonoBehaviour
|
||||
{
|
||||
[SerializeField]
|
||||
private bool pollInUpdate = true;
|
||||
|
||||
[SerializeField]
|
||||
private float pollIntervalSeconds = 0.05f;
|
||||
|
||||
[SerializeField]
|
||||
private bool logChanges;
|
||||
|
||||
[SerializeField]
|
||||
private string clientId = "unity-observer";
|
||||
|
||||
private readonly AetheriaRuntimeDaemonObservationCursor _cursor = new AetheriaRuntimeDaemonObservationCursor();
|
||||
private float _nextPollTime;
|
||||
private AetheriaRuntimeDaemonOperationClient _operationClient;
|
||||
private AetheriaDaemonOperations _operations;
|
||||
private AetheriaDaemonSoaMemoryMap _soaMemoryMap;
|
||||
private AetheriaDaemonRenderNativeView _renderNativeView;
|
||||
|
||||
public AetheriaRuntimeObservedDaemonState LastObservedState { get; private set; }
|
||||
public AetheriaRuntimeDaemonObservationResult LastObservation { get; private set; }
|
||||
public long LastFrameId => _cursor.LastFrameId;
|
||||
public long LastSoaGeneration => _cursor.LastSoaGeneration;
|
||||
public bool HasAuthoritativeState => LastObservedState != null && LastObservedState.IsAuthoritative;
|
||||
public bool HasSoaView => LastObservedState != null && LastObservedState.HasSoaView;
|
||||
public AetheriaRuntimeDaemonSoaViewIndex LastSoaIndex =>
|
||||
LastObservedState?.SoaIndex ?? AetheriaRuntimeDaemonSoaViewIndex.Empty;
|
||||
public AetheriaDaemonSoaMemoryMap LastSoaMemoryMap => _soaMemoryMap;
|
||||
public AetheriaDaemonRenderNativeView LastRenderNativeView => _renderNativeView;
|
||||
public bool HasRenderNativeView => _renderNativeView.IsCreated;
|
||||
public AetheriaDaemonOperations Operations => _operations ??= new AetheriaDaemonOperations(this);
|
||||
|
||||
public event Action<AetheriaRuntimeObservedDaemonState, AetheriaRuntimeDaemonObservationResult> ObservedDaemonStateChanged;
|
||||
|
||||
internal AetheriaRuntimeDaemonCommandEnvelope SendOperation(
|
||||
AetheriaRuntimeDaemonCommandKinds kind,
|
||||
Action<AetheriaRuntimeDaemonCommandDocument> configure = null)
|
||||
{
|
||||
_operationClient ??= new AetheriaRuntimeDaemonOperationClient(
|
||||
ActionGameManager.RuntimeStateFilePath,
|
||||
clientId,
|
||||
LastObservedState?.Frame.SessionId ?? "local");
|
||||
|
||||
var command = _operationClient.Create(kind, LastObservedState);
|
||||
configure?.Invoke(command);
|
||||
if (!_operationClient.TrySend(command, out var envelope, out var error))
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
$"Failed to submit Aetheria daemon operation {kind}: {error}");
|
||||
}
|
||||
|
||||
if (logChanges)
|
||||
{
|
||||
Debug.Log($"Submitted Aetheria daemon operation {envelope!.Kind}: {envelope.CommandId}");
|
||||
}
|
||||
|
||||
return envelope!;
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (!pollInUpdate || Time.unscaledTime < _nextPollTime)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_nextPollTime = Time.unscaledTime + Mathf.Max(0.001f, pollIntervalSeconds);
|
||||
Poll();
|
||||
}
|
||||
|
||||
public bool Poll()
|
||||
{
|
||||
if (!AetheriaRuntimeStateReader.TryReadObservedDaemonState(
|
||||
ActionGameManager.RuntimeStateFilePath,
|
||||
out var observed))
|
||||
{
|
||||
LastObservation = _cursor.Observe(null);
|
||||
return false;
|
||||
}
|
||||
|
||||
var result = _cursor.Observe(observed);
|
||||
LastObservedState = observed;
|
||||
LastObservation = result;
|
||||
|
||||
if (result.SoaViewChanged)
|
||||
{
|
||||
RemapSoaView(observed);
|
||||
}
|
||||
|
||||
if (result.Changed)
|
||||
{
|
||||
ObservedDaemonStateChanged?.Invoke(observed, result);
|
||||
if (logChanges)
|
||||
{
|
||||
Debug.Log(
|
||||
$"Observed Aetheria daemon frame {result.FrameId} " +
|
||||
$"soa generation {result.SoaGeneration} authoritative={result.IsAuthoritative}");
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void ResetObservation()
|
||||
{
|
||||
_cursor.Reset();
|
||||
DisposeSoaMemoryMap();
|
||||
LastObservedState = null;
|
||||
LastObservation = null;
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
DisposeSoaMemoryMap();
|
||||
}
|
||||
|
||||
private void RemapSoaView(AetheriaRuntimeObservedDaemonState observed)
|
||||
{
|
||||
DisposeSoaMemoryMap();
|
||||
if (observed == null || !observed.HasSoaView)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (AetheriaDaemonSoaMemoryMap.TryOpen(observed.SoaIndex, out var map, out var error))
|
||||
{
|
||||
_soaMemoryMap = map;
|
||||
if (!AetheriaDaemonRenderNativeView.TryCreate(observed.SoaIndex, map, out _renderNativeView))
|
||||
{
|
||||
_renderNativeView = default;
|
||||
if (logChanges)
|
||||
{
|
||||
Debug.LogWarning("Mapped Aetheria daemon SoA memory, but no complete render native view was published.");
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (logChanges)
|
||||
{
|
||||
Debug.LogWarning($"Could not map Aetheria daemon SoA view read-only: {error}");
|
||||
}
|
||||
}
|
||||
|
||||
private void DisposeSoaMemoryMap()
|
||||
{
|
||||
_renderNativeView = default;
|
||||
_soaMemoryMap?.Dispose();
|
||||
_soaMemoryMap = null;
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue