namespace AcDream.Core.Physics.Motion; /// /// R5 — port of retail's TargettedVoyeurInfo (acclient.h:52807, /// struct #5801). One entry in a 's voyeur table: /// a subscriber watching THIS object, the send-on-move /// threshold it registered, its dead-reckoning , and the /// already delivered to it (the delta baseline /// CheckAndUpdateVoyeur compares against). Mutable class (retail heap /// record updated in place by AddVoyeur/SendVoyeurUpdate). /// public sealed class TargettedVoyeurInfo { /// /// Exact watcher incarnation captured when this subscription is created. /// Retail object IDs are process-lifetime object-table identities; the App /// preserves that pointer-like identity explicitly while an old /// INSTANCE_TS teardown may overlap a newer record with the same GUID. /// internal IPhysicsObjHost WatcherHost { get; } /// +0x00 retail object_id — the subscriber's guid. public uint ObjectId { get; } /// +0x04 retail quantum — the subscriber's dead-reckoning /// lookahead horizon (seconds). public double Quantum { get; set; } /// +0x10 retail radius — the send-on-move threshold: an /// update is pushed only when the tracked object drifts more than this from /// . public float Radius { get; set; } /// +0x14 retail last_sent_position — the position last /// delivered to this subscriber (updated by SendVoyeurUpdate). public Position LastSentPosition { get; set; } public TargettedVoyeurInfo( uint objectId, float radius, double quantum, IPhysicsObjHost watcherHost) { ArgumentNullException.ThrowIfNull(watcherHost); if (watcherHost.Id != objectId) { throw new ArgumentException( "Watcher identity must match the voyeur object ID.", nameof(watcherHost)); } ObjectId = objectId; Radius = radius; Quantum = quantum; WatcherHost = watcherHost; } }