Drive stable entity layouts from hot body publications
This commit is contained in:
parent
dcafaeefbf
commit
0547792516
3 changed files with 76 additions and 1 deletions
|
|
@ -67,6 +67,7 @@ namespace GameCult.Eve.UnityScene
|
|||
private EveProviderAdvertisementDocument? _advertisement;
|
||||
private EveAdvertisedSurface? _advertisedSurface;
|
||||
private CultMeshBodyPublicationResolver? _bodyResolver;
|
||||
private EveEntitySoaViewDocument? _latestEntityLayout;
|
||||
private long _lastQueuedEntityViewEpoch = -1;
|
||||
private long _lastQueuedEntityViewSequence = -1;
|
||||
private bool _disposed;
|
||||
|
|
@ -200,6 +201,7 @@ namespace GameCult.Eve.UnityScene
|
|||
|
||||
private void QueueEntityView(EveEntitySoaViewDocument document)
|
||||
{
|
||||
_latestEntityLayout = document;
|
||||
if (document.ProducerEpoch < _lastQueuedEntityViewEpoch ||
|
||||
(document.ProducerEpoch == _lastQueuedEntityViewEpoch &&
|
||||
document.Sequence <= _lastQueuedEntityViewSequence))
|
||||
|
|
@ -209,6 +211,41 @@ namespace GameCult.Eve.UnityScene
|
|||
_liveDocuments.Enqueue(document);
|
||||
}
|
||||
|
||||
private void QueueBodyPublication(CultMeshBodyPublicationDocument publication)
|
||||
{
|
||||
var layout = _latestEntityLayout;
|
||||
if (layout == null || layout.Buffers == null || layout.Buffers.Length == 0 ||
|
||||
!string.Equals(layout.Buffers[0].BufferId, publication.BodyId, StringComparison.Ordinal))
|
||||
return;
|
||||
|
||||
QueueEntityView(new EveEntitySoaViewDocument
|
||||
{
|
||||
Schema = layout.Schema,
|
||||
ProviderId = layout.ProviderId,
|
||||
ViewId = layout.ViewId,
|
||||
PublishedAtUtc = DateTimeOffset.UtcNow.ToString("O"),
|
||||
BodySchemaId = layout.BodySchemaId,
|
||||
LayoutVersion = layout.LayoutVersion,
|
||||
ProducerEpoch = publication.ProducerEpoch,
|
||||
Sequence = publication.Sequence,
|
||||
Capacity = layout.Capacity,
|
||||
Buffers = layout.Buffers,
|
||||
Columns = layout.Columns,
|
||||
DirtyRanges = (layout.DirtyRanges ?? Array.Empty<EveEntitySoaDirtyRange>())
|
||||
.Select(range => new EveEntitySoaDirtyRange
|
||||
{
|
||||
ColumnId = range.ColumnId,
|
||||
StartIndex = range.StartIndex,
|
||||
Count = range.Count,
|
||||
Sequence = publication.Sequence
|
||||
})
|
||||
.ToArray(),
|
||||
RenderGroups = layout.RenderGroups,
|
||||
Identities = layout.Identities,
|
||||
FrameId = publication.Sequence
|
||||
});
|
||||
}
|
||||
|
||||
public void SubmitCommand(EveSurfaceCommandRequest request)
|
||||
{
|
||||
if (request == null) throw new ArgumentNullException(nameof(request));
|
||||
|
|
@ -612,6 +649,8 @@ namespace GameCult.Eve.UnityScene
|
|||
{
|
||||
if (document is EveEntitySoaViewDocument current)
|
||||
QueueEntityView(current);
|
||||
else if (document is CultMeshBodyPublicationDocument publication)
|
||||
QueueBodyPublication(publication);
|
||||
else if (document is EveFieldsSplatsDocument fields)
|
||||
_liveDocuments.Enqueue(fields);
|
||||
}
|
||||
|
|
@ -649,6 +688,8 @@ namespace GameCult.Eve.UnityScene
|
|||
{
|
||||
if (change.Document is EveEntitySoaViewDocument entityView)
|
||||
QueueEntityView(entityView);
|
||||
else if (change.Document is CultMeshBodyPublicationDocument publication)
|
||||
QueueBodyPublication(publication);
|
||||
else if (change.Document is EveSurfaceDocument or EveCommandReceiptDocument or EveFieldsSplatsDocument)
|
||||
_liveDocuments.Enqueue(change.Document);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -53,6 +53,40 @@ namespace GameCult.Eve.UnityScene.Tests
|
|||
Assert.That(handle.RecordKey, Is.Not.EqualTo(generationNPlusOne.RecordKey));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void LiveTransportReusesStableLayoutForNewBodyPublications()
|
||||
{
|
||||
using var transport = new EveUnityCultMeshLiveProviderTransport(
|
||||
"test-replica.cc",
|
||||
"cultnet://127.0.0.1:3075",
|
||||
"aetheria",
|
||||
"aetheria.pilot");
|
||||
var view = EntityLeaseDocument();
|
||||
var publication = BodyPublication(view, view.Sequence + 1);
|
||||
var queueView = typeof(EveUnityCultMeshLiveProviderTransport)
|
||||
.GetMethod("QueueEntityView", BindingFlags.NonPublic | BindingFlags.Instance)!;
|
||||
var queuePublication = typeof(EveUnityCultMeshLiveProviderTransport)
|
||||
.GetMethod("QueueBodyPublication", BindingFlags.NonPublic | BindingFlags.Instance)!;
|
||||
var queue = (System.Collections.Concurrent.ConcurrentQueue<object>)
|
||||
typeof(EveUnityCultMeshLiveProviderTransport)
|
||||
.GetField("_liveDocuments", BindingFlags.NonPublic | BindingFlags.Instance)!
|
||||
.GetValue(transport)!;
|
||||
|
||||
queueView.Invoke(transport, new object[] { view });
|
||||
Assert.That(queue.TryDequeue(out _), Is.True);
|
||||
queuePublication.Invoke(transport, new object[] { publication });
|
||||
|
||||
Assert.That(queue.TryDequeue(out var queued), Is.True);
|
||||
var generation = queued as EveEntitySoaViewDocument;
|
||||
Assert.That(generation, Is.Not.Null);
|
||||
Assert.That(generation!.Sequence, Is.EqualTo(publication.Sequence));
|
||||
Assert.That(generation.ProducerEpoch, Is.EqualTo(publication.ProducerEpoch));
|
||||
Assert.That(generation.Buffers, Is.SameAs(view.Buffers));
|
||||
Assert.That(generation.Columns, Is.SameAs(view.Columns));
|
||||
Assert.That(generation.Identities, Is.SameAs(view.Identities));
|
||||
Assert.That(generation.DirtyRanges.All(range => range.Sequence == publication.Sequence), Is.True);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void LiveTransportDropsExpiredHistoricalGenerationWithoutReinterpretingLatest()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "org.gamecult.eve.unity-scene",
|
||||
"displayName": "Eve Unity Scene Lowering",
|
||||
"version": "0.3.75",
|
||||
"version": "0.3.76",
|
||||
"unity": "6000.0",
|
||||
"description": "Provider-agnostic Unity scene shell for gamecult.eve.surface.v1 interactive world surfaces.",
|
||||
"dependencies": {
|
||||
|
|
|
|||
Reference in a new issue