2026-05-19 18:48:53 +01:00
|
|
|
using System;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
|
|
|
|
|
namespace GameCult.Networking
|
|
|
|
|
{
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Bridges schema-v0 simulation observation messages into a local observation hub.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public sealed class CultNetSimulationObservationServer : IDisposable
|
|
|
|
|
{
|
|
|
|
|
private readonly Server _server;
|
|
|
|
|
private readonly CultNetSimulationObservationHub _hub;
|
2026-06-16 16:07:56 +01:00
|
|
|
private readonly Func<CultNetSimulationObservationMessage, CultNetServerPeer, Task> _observationHandler;
|
2026-05-19 18:48:53 +01:00
|
|
|
private bool _disposed;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Creates and attaches a simulation observation bridge.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public CultNetSimulationObservationServer(
|
|
|
|
|
Server server,
|
|
|
|
|
CultNetSimulationObservationHub hub)
|
|
|
|
|
{
|
|
|
|
|
_server = server ?? throw new ArgumentNullException(nameof(server));
|
|
|
|
|
_hub = hub ?? throw new ArgumentNullException(nameof(hub));
|
|
|
|
|
_observationHandler = HandleObservationAsync;
|
|
|
|
|
_server.OnCultNet(_observationHandler);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Gets the observation hub used by this bridge.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public CultNetSimulationObservationHub Hub => _hub;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Applies an observation message and returns current candidate messages for the same subject.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public CultNetSimulationConsensusCandidateMessage[] CreateCandidateMessages(
|
|
|
|
|
CultNetSimulationObservationMessage message)
|
|
|
|
|
{
|
|
|
|
|
if (message == null) throw new ArgumentNullException(nameof(message));
|
|
|
|
|
return _hub.Submit(message)
|
|
|
|
|
.Select(candidate => CultNetSimulationConsensusCandidateMessage.FromCandidate(
|
|
|
|
|
message.MessageId,
|
|
|
|
|
candidate))
|
|
|
|
|
.ToArray();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <inheritdoc />
|
|
|
|
|
public void Dispose()
|
|
|
|
|
{
|
|
|
|
|
if (_disposed)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_disposed = true;
|
|
|
|
|
_server.RemoveCultNetMessageListener<CultNetSimulationObservationMessage>(_observationHandler);
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-16 11:54:54 +01:00
|
|
|
private Task HandleObservationAsync(CultNetSimulationObservationMessage message, CultNetServerPeer peer)
|
2026-05-19 18:48:53 +01:00
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
foreach (var candidate in CreateCandidateMessages(message))
|
|
|
|
|
{
|
2026-06-16 11:54:54 +01:00
|
|
|
peer.SendCultNet(candidate);
|
2026-05-19 18:48:53 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
2026-06-16 11:54:54 +01:00
|
|
|
peer.SendCultNet(new CultNetErrorMessage { Error = ex.Message });
|
2026-05-19 18:48:53 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return Task.CompletedTask;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|