This repository has been archived on 2026-10-29. You can view files and clone it, but you cannot make any changes to its state, such as pushing and creating new issues, pull requests or comments.
EveUnity/packages/org.gamecult.eve.unity-scene/Runtime/EveUnitySceneProviderConnection.cs
2026-07-10 02:27:47 +01:00

291 lines
9.3 KiB
C#

using System;
using GameCult.Eve.Surface;
#nullable enable
namespace GameCult.Eve.UnityScene
{
public interface IEveUnitySceneProviderSurfaceSource
{
string ProviderId { get; }
string SurfaceId { get; }
string SourcePointer { get; }
EveUnitySceneProviderSurfaceSnapshot CurrentSnapshot { get; }
event Action<EveUnitySceneProviderSurfaceSnapshot> SnapshotAvailable;
void Connect();
void Refresh();
void Disconnect();
}
public interface IEveUnitySceneCommandSink
{
string SinkKind { get; }
void Submit(EveSurfaceCommandRequest request);
}
public interface IEveUnitySceneProviderSurfaceDocumentSource
{
EveUnitySceneProviderSurfaceDocument CurrentDocument { get; }
event Action<EveUnitySceneProviderSurfaceDocument> DocumentAvailable;
}
public interface IEveUnitySceneProviderSurfaceDocumentConnection
{
void Connect();
void Disconnect();
}
public sealed class EveUnitySceneProviderSurfaceDocument
{
public EveUnitySceneProviderSurfaceDocument(
EveSurfaceDocument surfaceDocument,
EveUnitySceneProviderSurfaceAdvertisement advertisedSurface,
string sourcePointer,
long version = 0)
{
SurfaceDocument = surfaceDocument ?? throw new ArgumentNullException(nameof(surfaceDocument));
AdvertisedSurface = advertisedSurface ?? throw new ArgumentNullException(nameof(advertisedSurface));
SourcePointer = sourcePointer ?? "";
Version = version == 0 ? surfaceDocument.Version : version;
}
public EveSurfaceDocument SurfaceDocument { get; }
public EveUnitySceneProviderSurfaceAdvertisement AdvertisedSurface { get; }
public string SourcePointer { get; }
public long Version { get; }
public EveUnitySceneProviderSurfaceSnapshot ToSnapshot()
{
return new EveUnitySceneProviderSurfaceSnapshot(
SurfaceDocument,
AdvertisedSurface,
SourcePointer,
Version);
}
}
public sealed class EveUnitySceneProviderSurfaceDocumentSource : IEveUnitySceneProviderSurfaceSource, IDisposable
{
private readonly IEveUnitySceneProviderSurfaceDocumentSource _documentSource;
private readonly IEveUnitySceneProviderSurfaceDocumentConnection? _documentConnection;
private readonly IEveUnityProviderRefreshSource? _refreshSource;
private bool _connected;
public EveUnitySceneProviderSurfaceDocumentSource(
IEveUnitySceneProviderSurfaceDocumentSource documentSource)
{
_documentSource = documentSource ?? throw new ArgumentNullException(nameof(documentSource));
_documentConnection = documentSource as IEveUnitySceneProviderSurfaceDocumentConnection;
_refreshSource = documentSource as IEveUnityProviderRefreshSource;
CurrentSnapshot = _documentSource.CurrentDocument.ToSnapshot();
}
public string ProviderId => CurrentSnapshot.Document.ProviderId;
public string SurfaceId => CurrentSnapshot.AdvertisedSurface.SurfaceId;
public string SourcePointer => CurrentSnapshot.SourcePointer;
public EveUnitySceneProviderSurfaceSnapshot CurrentSnapshot { get; private set; }
public event Action<EveUnitySceneProviderSurfaceSnapshot>? SnapshotAvailable;
public void Connect()
{
if (_connected)
return;
_documentSource.DocumentAvailable += OnDocumentAvailable;
_documentConnection?.Connect();
_connected = true;
}
public void Refresh()
{
_refreshSource?.Refresh();
}
public void Disconnect()
{
if (!_connected)
return;
_documentConnection?.Disconnect();
_documentSource.DocumentAvailable -= OnDocumentAvailable;
_connected = false;
}
public void Dispose()
{
Disconnect();
}
private void OnDocumentAvailable(EveUnitySceneProviderSurfaceDocument document)
{
if (document == null) throw new ArgumentNullException(nameof(document));
CurrentSnapshot = document.ToSnapshot();
SnapshotAvailable?.Invoke(CurrentSnapshot);
}
}
public sealed class EveUnitySceneProviderConnection : IDisposable
{
private readonly IEveUnitySceneProviderSurfaceSource _surfaceSource;
private readonly IEveUnitySceneCommandSink _commandSink;
private readonly EveUnitySceneClientSession _session;
private bool _connected;
public EveUnitySceneProviderConnection(
IEveUnitySceneProviderSurfaceSource surfaceSource,
IEveUnitySceneCommandSink commandSink)
: this(surfaceSource, commandSink, new EveUnitySceneClientSession())
{
}
public EveUnitySceneProviderConnection(
IEveUnitySceneProviderSurfaceSource surfaceSource,
IEveUnitySceneCommandSink commandSink,
EveUnitySceneClientSession session)
{
_surfaceSource = surfaceSource ?? throw new ArgumentNullException(nameof(surfaceSource));
_commandSink = commandSink ?? throw new ArgumentNullException(nameof(commandSink));
_session = session ?? throw new ArgumentNullException(nameof(session));
}
public string ProviderId => _surfaceSource.ProviderId;
public string SurfaceId => _surfaceSource.SurfaceId;
public string SourcePointer => _surfaceSource.SourcePointer;
public EveUnitySceneProjection? ActiveProjection => _session.ActiveProjection;
public long ActiveVersion => _session.ActiveVersion;
public event Action<EveUnitySceneProjection>? ProjectionUpdated;
public EveUnitySceneProjection Connect()
{
if (!_connected)
{
_surfaceSource.SnapshotAvailable += OnSnapshotAvailable;
_surfaceSource.Connect();
_connected = true;
}
if (HasAppliedCurrentSnapshot())
return _session.ActiveProjection!;
return ApplySnapshot(_surfaceSource.CurrentSnapshot);
}
public EveUnitySceneProjection Refresh()
{
_surfaceSource.Refresh();
if (HasAppliedCurrentSnapshot())
return _session.ActiveProjection!;
return ApplySnapshot(_surfaceSource.CurrentSnapshot);
}
public EveSurfaceCommandRequest SubmitMoveIntent(
string entityId,
float targetX,
float targetY,
float targetZ,
DateTimeOffset? issuedAt = null)
{
return Submit(_session.CreateMoveIntent(entityId, targetX, targetY, targetZ, issuedAt));
}
public EveSurfaceCommandRequest SubmitMoveVectorIntent(
string entityId,
float directionX,
float directionY,
float scalarValue = 1f,
DateTimeOffset? issuedAt = null)
{
return Submit(_session.CreateMoveVectorIntent(entityId, directionX, directionY, scalarValue, issuedAt));
}
public EveSurfaceCommandRequest SubmitFocusIntent(
string entityId,
DateTimeOffset? issuedAt = null)
{
return Submit(_session.CreateFocusIntent(entityId, issuedAt));
}
public EveSurfaceCommandRequest SubmitTargetIntent(
string sourceEntityId,
string targetEntityId,
DateTimeOffset? issuedAt = null)
{
return Submit(_session.CreateTargetIntent(sourceEntityId, targetEntityId, issuedAt));
}
public EveSurfaceCommandRequest SubmitActionIntent(
string entityId,
string actionId,
DateTimeOffset? issuedAt = null)
{
return Submit(_session.CreateActionIntent(entityId, actionId, issuedAt));
}
public void Disconnect()
{
if (!_connected)
return;
_surfaceSource.SnapshotAvailable -= OnSnapshotAvailable;
_surfaceSource.Disconnect();
_connected = false;
}
public void Dispose()
{
Disconnect();
}
private EveSurfaceCommandRequest Submit(EveSurfaceCommandRequest request)
{
_commandSink.Submit(request);
return request;
}
private EveUnitySceneProjection ApplySnapshot(EveUnitySceneProviderSurfaceSnapshot snapshot)
{
var projection = _session.ApplySnapshot(snapshot);
ProjectionUpdated?.Invoke(projection);
return projection;
}
private bool HasAppliedCurrentSnapshot()
{
var projection = _session.ActiveProjection;
if (projection == null)
return false;
var snapshot = _surfaceSource.CurrentSnapshot;
return _session.ActiveVersion == snapshot.Version &&
string.Equals(_session.ActiveSourcePointer, snapshot.SourcePointer, StringComparison.Ordinal);
}
private void OnSnapshotAvailable(EveUnitySceneProviderSurfaceSnapshot snapshot)
{
ApplySnapshot(snapshot);
}
}
}