Deliver local sighting handoffs and preserve unsubmitted resupply attempts

This commit is contained in:
2026-09-20 10:18:18 +02:00
parent d8ec0de765
commit 81c0f060fd
48 changed files with 6994 additions and 30 deletions
@@ -0,0 +1,266 @@
#ifdef WORKBENCH
// Arranged report/physical local handoff fixture, NOT a native perception proof.
// Existing source radios and one recipient's radios are deliberately removed;
// no equipment or force is spawned to repair that disposable test-world setup.
// Read-only readiness: a terminal allocator may still own an accepted native
// insertion. Admit only terminal allocators with no submitted operation.
modded class ERR_EnemyRadio
{
bool ERR_LocalFixtureSettled()
{
return m_Stopped && !m_Submitted;
}
}
modded class ERR_EnemyEquipment
{
bool ERR_LocalFixtureRadiosSettled(SCR_AIGroup group)
{
if (!ERR_NativeLocalHandoffProbe.Enabled() || !group) return false;
foreach (ERR_EnemyEquipmentGroup state : m_Groups)
if (state.Group == group) return !state.Radio || state.Radio.ERR_LocalFixtureSettled();
return false;
}
}
modded class ERR_HQ
{
bool ERR_LocalFixtureRadiosSettled(ERR_HQUnit unit)
{
return unit && m_Equipment && m_Equipment.ERR_LocalFixtureRadiosSettled(unit.Group);
}
void ERR_LocalFixtureUnits(out array<ERR_HQUnit> units)
{
units.Clear();
if (!ERR_NativeLocalHandoffProbe.Enabled()) return;
foreach (ERR_HQUnit unit : m_Units) units.Insert(unit);
}
ERR_HQRoute ERR_LocalFixtureQueue(ERR_HQUnit unit, ERR_HQReport arranged, IEntity witness, SCR_AIGroup receiver, out string reason)
{
reason = "fixture owner unavailable";
if (!ERR_NativeLocalHandoffProbe.Enabled() || !unit || !m_Units.Contains(unit) || !arranged) return null;
reason = "source has an existing pending uplink";
if (unit.Uplink || unit.PendingReport || unit.PendingStatus || unit.PendingSweep || unit.PendingSupplyStatus) return null;
// Rebuild the real topology after deliberate physical radio removal.
IndexRadios();
ERR_HQRoute route = ObservationRoute(unit);
reason = "no eligible original local route";
if (!route) return null;
if (route.Downlink || route.LocalSource != unit.Group || !route.LocalWitness || route.Nodes.IsEmpty())
{ reason = string.Format("route is not local; source radio=%1 capability=%2", unit.Radio, ERR_HQRadio.Capability(unit.Radio)); return null; }
if (route.LocalWitness != witness || route.Nodes[0].Group != receiver)
{ reason = string.Format("different local pair chosen: witness=%1 receiver=%2", route.LocalWitness, route.Nodes[0].UnitId); return null; }
arranged.Source = unit.Group;
unit.PendingReport = arranged.Snapshot(); unit.Uplink = route;
route.MessageId = arranged.MessageId;
route.Payload = "FIXTURE arranged immutable sighting; real local handoff and radio required";
m_Journal.Write("REPORT", route.Payload, route.MessageId);
return route;
}
}
class ERR_NativeLocalHandoffProbe
{
static const int TOKEN = 220001;
protected ERR_GameMode m_Mode;
protected ERR_HQ m_HQ;
protected ERR_HQUnit m_Source;
protected ERR_HQUnit m_Recipient;
protected IEntity m_Witness;
protected IEntity m_Radio;
protected vector m_OriginalPosition;
protected ref ERR_HQRoute m_Route;
protected ref ERR_HQReport m_Payload;
protected int m_DeliveredId;
protected int m_State;
protected float m_Wait;
protected float m_Deadline;
protected float m_NextQueueDiagnostic;
protected bool m_Positioned;
protected bool m_Stopped;
protected bool m_Failed;
static bool Enabled()
{
string enabled, outcome;
return Replication.IsServer() && System.GetCLIParam("errSmoke", enabled) && enabled == "1"
&& System.GetCLIParam("errSmokeOutcome", outcome) && outcome == "hq-local-handoff";
}
void ERR_NativeLocalHandoffProbe(ERR_GameMode mode) { m_Mode = mode; }
protected bool Check(bool condition, string detail)
{
if (condition) { Print("ERR SMOKE PASS: local handoff " + detail); return true; }
m_Failed = true; Print("ERR SMOKE FAIL: local handoff " + detail, LogLevel.ERROR); Stop(); return false;
}
protected bool Original(ERR_HQUnit unit, IEntity actor)
{
if (!unit || !actor || !unit.StatusSampler || !unit.StatusSampler.OwnsRoster(unit.Group)) return false;
if (!ERR_EnemyEquipmentRules.Eligible(m_Mode, unit.Group, actor) || CompartmentAccessComponent.GetVehicleIn(actor)) return false;
int count = unit.StatusSampler.InitialStrength();
if (count < 1 || count > 32) return false;
for (int i = 0; i < count; i++)
if (unit.StatusSampler.InitialMember(i) == actor) return unit.StatusSampler.CanAttribute(i, actor);
return false;
}
protected int RemoveRadios(ERR_HQUnit unit, IEntity actor)
{
if (!Original(unit, actor)) return -1;
InventoryStorageManagerComponent inventory = InventoryStorageManagerComponent.Cast(actor.FindComponent(InventoryStorageManagerComponent));
if (!inventory) return -1;
array<IEntity> items = {}; ERR_Inventory.Items(inventory, items);
if (items.Count() > 128) return -1;
int removed;
foreach (IEntity item : items)
{
if (!item || !item.FindComponent(BaseRadioComponent)) continue;
SCR_EntityHelper.DeleteEntityAndChildren(item); removed++;
}
return removed;
}
protected bool Select()
{
array<ERR_HQUnit> units = {}; m_HQ.ERR_LocalFixtureUnits(units);
foreach (ERR_HQUnit recipient : units)
{
if (!m_HQ.ERR_LocalFixtureRadiosSettled(recipient)) continue;
if (!recipient || !recipient.Radio || !Original(recipient, recipient.Radio) || ERR_HQRadio.Capability(recipient.Radio) != 2) continue;
if (!m_HQ.ReserveLogistics(recipient.Group, TOKEN)) continue;
m_Recipient = recipient; m_Radio = recipient.Radio;
foreach (ERR_HQUnit source : units)
{
if (!m_HQ.ERR_LocalFixtureRadiosSettled(source)) continue;
if (!source || source == recipient || !source.StatusSampler || !m_HQ.ReserveLogistics(source.Group, TOKEN)) continue;
int count = source.StatusSampler.InitialStrength();
if (count >= 1 && count <= 32)
for (int i = 0; i < count; i++)
{
IEntity actor = source.StatusSampler.InitialMember(i);
if (Original(source, actor)) { m_Source = source; m_Witness = actor; break; }
}
if (m_Source) return true;
m_HQ.ReleaseLogistics(source.Group, TOKEN);
}
m_HQ.ReleaseLogistics(recipient.Group, TOKEN); m_Recipient = null; m_Radio = null;
}
return false;
}
protected bool Arrange()
{
if (!Original(m_Source, m_Witness) || !Original(m_Recipient, m_Radio)) return false;
int removed;
int count = m_Source.StatusSampler.InitialStrength();
for (int i = 0; i < count; i++)
{
IEntity actor = m_Source.StatusSampler.InitialMember(i);
int result = RemoveRadios(m_Source, actor);
if (result < 0) return false;
removed += result;
}
vector point = ERR_Actors.Ground(m_Radio.GetOrigin() + "4 0 0");
TraceBox volume = new TraceBox(); volume.Start = point + "0 1 0"; volume.End = volume.Start + "0 0.01 0";
volume.Mins = "-0.3 -0.9 -0.3"; volume.Maxs = "0.3 0.9 0.3"; volume.Flags = TraceFlags.ENTS;
array<IEntity> exclude = {m_Witness}; volume.ExcludeArray = exclude;
float fraction = GetGame().GetWorld().TraceMove(volume, null);
if (!(fraction >= 1 && fraction <= 1)) return false;
m_OriginalPosition = m_Witness.GetOrigin(); m_Witness.SetOrigin(point); m_Positioned = true;
PrintFormat("ERR LOCAL HANDOFF ARRANGEMENT: source=%1 recipient=%2 original witness=%3 caller=%4 source radios removed=%5; arranged snapshot, no perception assertion", m_Source.Id, m_Recipient.Id, m_Witness, m_Radio, removed);
return ERR_HQRadio.Capability(m_Witness) == 0;
}
protected void QueueWait(string reason, float now)
{
if (now < m_NextQueueDiagnostic) return;
m_NextQueueDiagnostic = now + 10000;
PrintFormat("ERR LOCAL HANDOFF WAIT: state=%1 reason=%2 sourceRadio=%3 witnessCapability=%4 distance=%5", m_State, reason, m_Source.Radio, ERR_HQRadio.Capability(m_Witness), vector.Distance(m_Witness.GetOrigin(), m_Radio.GetOrigin()));
}
protected bool Queue(float now)
{
if (m_Recipient.Uplink) { QueueWait("recipient has an existing uplink", now); return false; }
ERR_HQReport arranged = new ERR_HQReport();
arranged.MessageId = m_HQ.Journal().Message(); arranged.Target = m_Mode;
arranged.Position = m_Mode.PrisonPosition() + "300 0 300";
if (m_DeliveredId > 0) arranged.Position += "10 0 0";
arranged.ObservedAt = now; arranged.SeenEscapists = 1; arranged.TravelMode = "on foot";
string reason;
m_Route = m_HQ.ERR_LocalFixtureQueue(m_Source, arranged, m_Witness, m_Recipient.Group, reason);
if (!m_Route) { QueueWait(reason, now); return false; }
m_Payload = m_Source.PendingReport.Snapshot();
// Mutating the caller's arranged object must not mutate the queued snapshot.
arranged.Position += "100 0 0"; arranged.ObservedAt += 1000;
return true;
}
protected bool SameSnapshot(ERR_HQReport report)
{
return report && m_Payload && report.MessageId == m_Payload.MessageId && report.Source == m_Source.Group
&& report.Target == m_Mode && report.Position == m_Payload.Position && report.ObservedAt == m_Payload.ObservedAt;
}
int Tick(ERR_HQ hq, float now)
{
if (!Enabled() || m_Stopped || m_Failed || !m_Mode || m_Mode != ERR_GameMode.Get() || !m_Mode.Active()) return -1;
m_HQ = hq; if (!hq) return -1;
if (m_Deadline == 0) m_Deadline = now + 120000;
if (now >= m_Deadline) { Check(false, "bounded fixture deadline"); return -1; }
if (now < m_Wait) return 0;
if (m_State == 0)
{
if (!hq.ERR_ProbeSquadsReady()) return 0;
if (!Select()) return 0;
if (!Check(Arrange(), "two original owned squads retained; source radios removed and witness positioned with clear volume")) return -1;
// Native aiming/trace poses may lag SetOrigin until the next world tick.
m_Wait = now + 1500; m_State = 1; return 0;
}
if (!Original(m_Source, m_Witness) || !Original(m_Recipient, m_Radio)
|| hq.LogisticsToken(m_Source.Group) != TOKEN || hq.LogisticsToken(m_Recipient.Group) != TOKEN)
{ Check(false, "original non-player source/recipient or fixture reservation changed"); return -1; }
if (m_State == 1 || m_State == 3)
{
if (!Queue(now)) return 0;
if (!Check(m_Route.LocalSource == m_Source.Group && m_Route.LocalWitness == m_Witness && m_Route.Nodes[0].Group == m_Recipient.Group
&& m_Route.Nodes[0].Carrier != m_Witness && SameSnapshot(m_Source.PendingReport), "arranged source snapshot uses distinct original nearby caller without becoming its sighting")) return -1;
if (!Check(m_Route.Advance(now, hq.Journal()) == 0 && !m_Route.Originated && !m_Route.Sending,
"local handoff is pending and has not started a radio transmission")) return -1;
ERR_HQBelief before = hq.Memory().Get(m_Mode);
if (!Check((!before && m_DeliveredId == 0) || (before && before.MessageId == m_DeliveredId), "pending local handoff adds no HQ belief")) return -1;
if (m_State == 3)
{
IEntity caller = m_Route.Nodes[0].Carrier;
if (!Check(RemoveRadios(m_Recipient, caller) > 0, "original receiving caller radio removed during pending local handoff")) return -1;
m_State = 4; return 0;
}
m_State = 2; return 0;
}
ERR_HQBelief belief = hq.Memory().Get(m_Mode);
if (m_State == 2)
{
if (!Check(!m_Route.Failed, "positive arranged route retains real local/radio eligibility")) return -1;
if (!belief)
{
if (!Check(SameSnapshot(m_Source.PendingReport), "queued snapshot remains unchanged before actual HQ delivery")) return -1;
return 0;
}
if (!Check(m_Route.Originated && !m_Route.Sending && m_Route.Cursor == m_Route.Nodes.Count()
&& SameSnapshot(belief.Report),
"actual local plus radio completion delivers the unchanged original source snapshot to HQ")) return -1;
m_DeliveredId = m_Payload.MessageId; m_State = 3; return 0;
}
if (m_State == 4)
{
if (!Check(belief && belief.MessageId == m_DeliveredId, "interrupted second snapshot never replaces delivered HQ knowledge")) return -1;
if (!m_Route.Failed) return 0;
if (!Check(!m_Route.Originated && !m_Route.Sending, "loss of actual local recipient radio interrupts before originating handoff completes")) return -1;
Stop(); return 1;
}
return 0;
}
void Stop()
{
if (m_Stopped) return;
m_Stopped = true;
bool restore;
if (m_HQ && m_Source && m_HQ.LogisticsToken(m_Source.Group) == TOKEN)
{
restore = m_Positioned && Original(m_Source, m_Witness);
if (m_Source.Uplink == m_Route && m_Source.PendingReport && m_Payload && m_Source.PendingReport.MessageId == m_Payload.MessageId)
{ m_Source.Uplink = null; m_Source.PendingReport = null; }
m_HQ.ReleaseLogistics(m_Source.Group, TOKEN);
}
if (m_HQ && m_Recipient) m_HQ.ReleaseLogistics(m_Recipient.Group, TOKEN);
if (restore) m_Witness.SetOrigin(m_OriginalPosition);
}
}
#endif
@@ -17,6 +17,10 @@ modded class ERR_GameMode
protected bool m_ERRTestRadioNetwork;
protected bool m_ERRTestHQResponse;
protected bool m_ERRTestHQMemory;
protected bool m_ERRTestLocalHandoff;
protected ref ERR_NativeLocalHandoffProbe m_ERRLocalHandoff;
protected ERR_PlayerLife m_ERRLocalHandoffLife;
protected SCR_PlayerController m_ERRLocalHandoffController;
protected bool m_ERRTestHQBody;
protected ref ERR_NativeHQBodyProbe m_ERRHQBodyProbe;
protected bool m_ERRTestInfantryTransfer;
@@ -63,6 +67,7 @@ modded class ERR_GameMode
m_ERRTestRadioNetwork = outcome == "radio-network";
m_ERRTestHQResponse = outcome == "hq-response";
m_ERRTestHQMemory = outcome == "hq-memory";
m_ERRTestLocalHandoff = outcome == "hq-local-handoff";
m_ERRTestHQBody = outcome == "hq-body";
m_ERRTestInfantryTransfer = outcome == "infantry-transfer";
m_ERRTestConvoy = outcome == "convoy";
@@ -79,7 +84,9 @@ modded class ERR_GameMode
m_ERRTestMortarTransfer = outcome == "mortar-transfer";
m_ERRTestPatrolHQ = outcome == "patrol-hq";
m_ERRTestPlayerDeath = outcome == "player-death" || m_ERRTestRadioNetwork || m_ERRTestHQResponse || m_ERRTestMortar || m_ERRTestHQMemory || m_ERRTestHQBody || m_ERRTestConvoy || m_ERRTestInfantryTransfer;
if (m_ERRTestLocalHandoff) m_ERRTestPlayerDeath = true;
m_ERRSmokeDeadline = GetWorld().GetWorldTime() + 150000;
if (m_ERRTestLocalHandoff) m_ERRSmokeDeadline = GetWorld().GetWorldTime() + 240000;
if (m_ERRTestConvoy) m_ERRSmokeDeadline = GetWorld().GetWorldTime() + 540000;
if (ERR_NativeConvoyCoverProbe.Enabled()) m_ERRSmokeDeadline = GetWorld().GetWorldTime() + 840000;
if (m_ERRTestHQMemory) m_ERRSmokeDeadline = GetWorld().GetWorldTime() + 360000;
@@ -517,6 +524,18 @@ modded class ERR_GameMode
m_ERRSmokeStep = 110;
return;
}
if (m_ERRTestLocalHandoff)
{
m_ERRLocalHandoffController = SCR_PlayerController.Cast(GetGame().GetPlayerController());
m_ERRLocalHandoffLife = Players().CurrentActor(m_ERRSmokePlayer);
if (!ERR_Check(m_ERRLocalHandoffController && m_ERRLocalHandoffLife && m_ERRLocalHandoffController.GetControlledEntity() == m_ERRSmokePlayer, "local handoff retains original canonical prisoner")) return;
DamageManagerComponent protection = DamageManagerComponent.Cast(m_ERRSmokePlayer.FindComponent(DamageManagerComponent));
if (!ERR_Check(protection != null, "local handoff original prisoner damage component exists")) return;
protection.EnableDamageHandling(false);
m_ERRLocalHandoff = new ERR_NativeLocalHandoffProbe(this);
OnStop().Insert(m_ERRLocalHandoff.Stop);
m_ERRSmokeStep = 109; return;
}
if (m_ERRTestInfantryTransfer)
{
DamageManagerComponent.Cast(m_ERRSmokePlayer.FindComponent(DamageManagerComponent)).EnableDamageHandling(false);
@@ -718,6 +737,21 @@ modded class ERR_GameMode
damage.Kill(Instigator.CreateInstigator(m_ERRSmokePlayer));
m_ERRSmokeWait = now + 4000;
}
else if (m_ERRSmokeStep == 109)
{
int result = m_ERRLocalHandoff.Tick(ERR_HQ.Cast(Command()), now);
if (result == 0) return;
m_ERRLocalHandoff.Stop();
if (!ERR_Check(result == 1, "arranged immutable report, actual local handoff/radio delivery and interrupted recipient radio")) return;
if (!ERR_Check(m_ERRSmokePlayer && m_ERRLocalHandoffLife && m_ERRLocalHandoffController && m_ERRLocalHandoffController == GetGame().GetPlayerController(), "local handoff final original controller and body retained")) return;
if (!ERR_Check(Players().CurrentActor(m_ERRSmokePlayer) == m_ERRLocalHandoffLife && m_ERRLocalHandoffController.GetControlledEntity() == m_ERRSmokePlayer, "local handoff final prisoner identity unchanged")) return;
m_ERRSmokeStep = 9;
SCR_CharacterDamageManagerComponent damage;
damage = SCR_CharacterDamageManagerComponent.Cast(m_ERRSmokePlayer.FindComponent(SCR_CharacterDamageManagerComponent));
if (!ERR_Check(damage != null, "local handoff final original prisoner damage component retained")) return;
damage.EnableDamageHandling(true); damage.Kill(Instigator.CreateInstigator(m_ERRSmokePlayer));
m_ERRSmokeWait = now + 4000;
}
else if (m_ERRSmokeStep == 108)
{
int result = m_ERRInfantryTransfer.Tick(ERR_HQ.Cast(Command()), now);