using AcDream.App.World;
using AcDream.Core.Net.Messages;
using AcDream.Core.Physics;
using DatReaderWriter.DBObjs;
namespace AcDream.App.Rendering;
///
/// Completes a fresher same-incarnation CreateObject after it interrupted an
/// active projection transaction. Logical entity/resource ownership is
/// retained; the exact current appearance is republished, the plugin/current
/// snapshot is refreshed, and the retained animation owner is synchronized in
/// that order. Every potentially reentrant stage is guarded by the monotonic
/// Create-integration authority.
///
internal static class LiveEntityCreateSupersessionRecovery
{
public static bool TryApply(
LiveEntityRuntime runtime,
LiveEntityRecord expectedRecord,
ulong expectedCreateIntegrationVersion,
Func captureAppearance,
Func publishAppearance,
Action publishCurrentSnapshot,
Action synchronizeAnimation)
{
ArgumentNullException.ThrowIfNull(runtime);
ArgumentNullException.ThrowIfNull(expectedRecord);
ArgumentNullException.ThrowIfNull(captureAppearance);
ArgumentNullException.ThrowIfNull(publishAppearance);
ArgumentNullException.ThrowIfNull(publishCurrentSnapshot);
ArgumentNullException.ThrowIfNull(synchronizeAnimation);
if (!runtime.IsCurrentCreateIntegration(
expectedRecord,
expectedCreateIntegrationVersion)
|| captureAppearance() is not { } visualUpdate
|| !runtime.IsCurrentCreateIntegration(
expectedRecord,
expectedCreateIntegrationVersion)
|| !publishAppearance(visualUpdate)
|| !runtime.IsCurrentCreateIntegration(
expectedRecord,
expectedCreateIntegrationVersion))
{
return false;
}
publishCurrentSnapshot(visualUpdate);
if (!runtime.IsCurrentCreateIntegration(
expectedRecord,
expectedCreateIntegrationVersion))
{
return false;
}
synchronizeAnimation(visualUpdate);
return runtime.IsCurrentCreateIntegration(
expectedRecord,
expectedCreateIntegrationVersion);
}
}
///
/// Reconciles the exceptional case where a fresher same-incarnation Create
/// interrupts initial PartArray construction. Completed owners already route
/// MovementData through SetObjectMovement and therefore retain their exact
/// sequencer, dispatch sink, and paired manager/interpreter queues.
///
internal static class LiveEntityCreateAnimationSynchronization
{
public static bool TrySynchronizeInterruptedInitialOwner(
LiveEntityRecord record,
LiveEntityAnimationState animation,
Animation? canonicalAnimation,
int canonicalLowFrame,
int canonicalHighFrame,
float canonicalFramerate,
MotionTable? motionTable,
CreateObject.ServerMotionState? wireState)
{
ArgumentNullException.ThrowIfNull(record);
ArgumentNullException.ThrowIfNull(animation);
if (record.InitialHydrationCompleted)
return false;
if (canonicalAnimation is not null)
{
animation.Animation = canonicalAnimation;
animation.LowFrame = canonicalLowFrame;
animation.HighFrame = canonicalHighFrame;
animation.Framerate = canonicalFramerate;
animation.CurrFrame = canonicalLowFrame;
}
if (animation.Sequencer is { } sequencer && motionTable is not null)
{
SpawnMotionInitializer.Reinitialize(
sequencer,
motionTable,
wireState);
}
return true;
}
}