296 lines
13 KiB
C
296 lines
13 KiB
C
#ifdef WORKBENCH
|
|
// Explicit fixture payloads, physical radio delivery, production HQ intake.
|
|
// This does not certify visual detection or an actual ground sweep completing.
|
|
modded class ERR_HQ
|
|
{
|
|
int ERR_MemoryFixtureRegisteredForces()
|
|
{
|
|
if (!ERR_NativeHQMemoryProbe.Enabled() || !m_Mode || !m_Mode.Forces()) return -1;
|
|
int registered;
|
|
foreach (ERR_HQUnit unit : m_Units)
|
|
{
|
|
if (unit.ReservedForSupport || !unit.Group) continue;
|
|
ERR_ForceRecord record = m_Mode.Forces().FindGroup(unit.Group);
|
|
if (!record || record.Group != unit.Group || !record.Physical || record.Eliminated) return -1;
|
|
registered++;
|
|
}
|
|
if (m_Mode.Forces().Count() < registered) return -1;
|
|
return registered;
|
|
}
|
|
protected bool ERR_MemoryFixtureHealthy(ERR_HQRoute route)
|
|
{
|
|
if (!route || route.Nodes.IsEmpty()) return false;
|
|
for (int i = 0; i < route.Nodes.Count(); i++)
|
|
if (!route.Nodes[i] || !route.Nodes[i].Valid(i == route.Nodes.Count() - 1)) return false;
|
|
return true;
|
|
}
|
|
ERR_HQRoute ERR_MemoryFixtureQueue(ERR_HQReport report)
|
|
{
|
|
if (!ERR_NativeHQMemoryProbe.Enabled()) return null;
|
|
foreach (ERR_HQUnit unit : m_Units)
|
|
{
|
|
if (unit.ReservedForSupport || !unit.Radio || unit.Uplink || unit.PendingReport || unit.PendingSweep) continue;
|
|
if (unit.PendingSupplyStatus || unit.PendingStatus) continue;
|
|
ERR_HQRoute route = m_Network.Route(unit.Radio);
|
|
if (!ERR_MemoryFixtureHealthy(route)) continue;
|
|
report.Source = unit.Group;
|
|
route.MessageId = report.MessageId;
|
|
route.Payload = "FIXTURE synthetic observed position; " + report.Description(report.ObservedAt);
|
|
unit.PendingReport = report.Snapshot(); unit.Uplink = route;
|
|
return route;
|
|
}
|
|
return null;
|
|
}
|
|
ERR_HQRoute ERR_MemoryFixtureSweep(ERR_HQSearchReport report)
|
|
{
|
|
if (!ERR_NativeHQMemoryProbe.Enabled()) return null;
|
|
foreach (ERR_HQUnit unit : m_Units)
|
|
{
|
|
if (unit.ReservedForSupport || !unit.Radio || unit.Uplink || unit.PendingReport || unit.PendingSweep) continue;
|
|
if (unit.PendingSupplyStatus || unit.PendingStatus) continue;
|
|
ERR_HQRoute route = m_Network.Route(unit.Radio);
|
|
if (!ERR_MemoryFixtureHealthy(route)) continue;
|
|
report.SourceId = unit.Id;
|
|
route.MessageId = report.MessageId;
|
|
route.Payload = "FIXTURE synthetic completed sweep; real uplink required";
|
|
unit.PendingSweep = report; unit.Uplink = route;
|
|
return route;
|
|
}
|
|
return null;
|
|
}
|
|
void ERR_MemoryFixtureReplaySweep(ERR_HQSearchReport report, float now)
|
|
{
|
|
if (ERR_NativeHQMemoryProbe.Enabled()) AcceptSweep(report, now);
|
|
}
|
|
override void Stop()
|
|
{
|
|
super.Stop();
|
|
if (!ERR_NativeHQMemoryProbe.Enabled()) return;
|
|
if (m_Memory.Count() != 0)
|
|
Print("ERR SMOKE FAIL: HQ memory stop retained beliefs", LogLevel.ERROR);
|
|
else Print("ERR SMOKE PASS: HQ memory actual command stop clears all belief history");
|
|
}
|
|
}
|
|
|
|
class ERR_NativeHQMemoryProbe
|
|
{
|
|
protected ERR_GameMode m_Mode;
|
|
protected ref ERR_HQRoute m_Route;
|
|
protected ref ERR_HQReport m_Report;
|
|
protected ref ERR_HQSearchReport m_Sweep;
|
|
protected int m_Step;
|
|
protected int m_BeliefId;
|
|
protected int m_Revision;
|
|
protected float m_FirstObserved;
|
|
protected float m_SecondObserved;
|
|
protected vector m_FirstPosition;
|
|
protected float m_Deadline;
|
|
protected bool m_Failed;
|
|
protected bool m_ValueChecked;
|
|
protected int m_RouteRetries;
|
|
|
|
static bool Enabled()
|
|
{
|
|
string enabled, outcome;
|
|
return Replication.IsServer() && System.GetCLIParam("errSmoke", enabled) && enabled == "1"
|
|
&& System.GetCLIParam("errSmokeOutcome", outcome) && outcome == "hq-memory";
|
|
}
|
|
void ERR_NativeHQMemoryProbe(ERR_GameMode mode) { m_Mode = mode; }
|
|
protected bool Check(bool condition, string description)
|
|
{
|
|
if (condition) { Print("ERR SMOKE PASS: HQ memory " + description); return true; }
|
|
m_Failed = true; Print("ERR SMOKE FAIL: HQ memory " + description, LogLevel.ERROR); return false;
|
|
}
|
|
protected float Unaged(ERR_HQBelief belief)
|
|
{
|
|
if (!belief) return -1;
|
|
float decay = ERR_HQMemoryRules.Confidence((belief.EvaluatedAt - belief.ObservedAt) / 1000);
|
|
if (decay <= 0) return -1;
|
|
return belief.Confidence / decay;
|
|
}
|
|
protected ERR_HQReport Payload(ERR_HQ hq, float now, vector position)
|
|
{
|
|
ERR_HQReport report = new ERR_HQReport();
|
|
report.MessageId = hq.Journal().Message(); report.Target = m_Mode;
|
|
report.ObservedAt = now; report.Position = position; report.TravelMode = "on foot";
|
|
return report;
|
|
}
|
|
protected bool LocalPolicies()
|
|
{
|
|
ERR_ForceLedger ledger = new ERR_ForceLedger();
|
|
ERR_ForceRecord force = ledger.Register("memory-value-fixture", ERR_ForceKind.PATROL, "100 0 100", 6);
|
|
if (!Check(force && ledger.Count() == 1 && !force.Group && !force.Physical,
|
|
"detached native Core ledger registers one arithmetic fixture without spawning")) return false;
|
|
if (!Check(ledger.Eliminate(force.Id, 1000), "detached native ledger records elimination")) return false;
|
|
ERR_ForceRecord duplicate = ledger.Register("memory-value-fixture", ERR_ForceKind.PATROL, "100 0 100", 6);
|
|
if (!Check(duplicate == force && ledger.Count() == 1 && force.Strength == 0 && force.Eliminated
|
|
&& !force.Group && !force.Physical, "eliminated source re-registration cannot restore strength or spawn"))
|
|
return false;
|
|
ERR_HQMemory memory = new ERR_HQMemory();
|
|
ERR_HQReport first = new ERR_HQReport();
|
|
first.Target = m_Mode; first.MessageId = 1; first.ObservedAt = 0;
|
|
first.Position = "100 7 100"; first.TravelMode = "on foot";
|
|
if (!Check(memory.Ingest(first, 0), "injected value fixture begins with a detached report")) return false;
|
|
first.Position = "999 7 999";
|
|
ERR_HQBelief belief = memory.Get(m_Mode);
|
|
if (!Check(belief && belief.Position == "100 7 100", "stored snapshot ignores later input mutation")) return false;
|
|
ERR_HQReport next = first.Snapshot();
|
|
next.MessageId = 2; next.ObservedAt = 10000; next.Position = "160 7 100";
|
|
if (!Check(memory.Ingest(next, 12000), "newer delivered-value fixture advances trajectory")) return false;
|
|
belief = memory.Get(m_Mode);
|
|
if (!Check(belief.HasVelocity && Math.AbsFloat(belief.Speed - 6) < 0.01,
|
|
"native vector arithmetic infers six metres per second from snapshots")) return false;
|
|
memory.Tick(610000); belief = memory.Get(m_Mode);
|
|
if (!Check(belief && Math.AbsFloat(belief.Confidence - 0.5) < 0.001 && belief.Radius > 700,
|
|
"ten-minute value-clock advance retains a weaker wider belief")) return false;
|
|
if (!Check(belief.PredictionSeconds == 30 && vector.DistanceXZ(belief.Position, belief.PredictedPosition) <= 300,
|
|
"old trajectory prediction remains capped in time and distance")) return false;
|
|
int id = belief.BeliefId;
|
|
if (!Check(memory.NegativeSearch(id, belief.BeliefRevision, 610000)
|
|
&& !memory.NegativeSearch(id, belief.BeliefRevision, 610000), "negative revision is idempotent")) return false;
|
|
memory.Clear();
|
|
if (!Check(memory.Count() == 0 && !memory.GetById(id), "clear removes detached value history")) return false;
|
|
return true;
|
|
}
|
|
protected bool RemoveRadios(IEntity carrier)
|
|
{
|
|
InventoryStorageManagerComponent inventory;
|
|
if (carrier)
|
|
inventory = InventoryStorageManagerComponent.Cast(carrier.FindComponent(InventoryStorageManagerComponent));
|
|
if (!inventory) return false;
|
|
array<IEntity> items = {}; inventory.GetItems(items);
|
|
int removed;
|
|
foreach (IEntity item : items)
|
|
{
|
|
if (!item || !item.FindComponent(BaseRadioComponent)) continue;
|
|
SCR_EntityHelper.DeleteEntityAndChildren(item); removed++;
|
|
}
|
|
return removed > 0;
|
|
}
|
|
int Tick(ERR_HQ hq, float now)
|
|
{
|
|
if (!Enabled() || !hq || !m_Mode || m_Failed) return -1;
|
|
if (m_Deadline == 0) m_Deadline = now + 120000;
|
|
if (now > m_Deadline) { Check(false, "fixture deadline"); return -1; }
|
|
if (m_Step == 0)
|
|
{
|
|
if (!hq.ERR_ProbeSquadsReady()) return 0;
|
|
if (!m_ValueChecked)
|
|
{
|
|
if (!Check(hq.ERR_MemoryFixtureRegisteredForces() == 6,
|
|
"actual six site groups are registered once in the Core force ledger")) return -1;
|
|
if (!LocalPolicies()) return -1;
|
|
m_ValueChecked = true;
|
|
}
|
|
m_FirstPosition = m_Mode.PrisonPosition() + "300 0 300";
|
|
m_Report = Payload(hq, now, m_FirstPosition);
|
|
m_Route = hq.ERR_MemoryFixtureQueue(m_Report);
|
|
if (!m_Route) return 0;
|
|
if (!Check(!hq.Memory().Get(m_Mode) && m_Route.Advance(now, hq.Journal()) == 0,
|
|
"queued synthetic sighting has no belief while actual transmitter starts")) return -1;
|
|
if (!Check(!m_Route.Originated && !m_Route.Sending && m_Route.OriginDue - m_Route.StartedAt == 3000,
|
|
"uplink holds original caller for three seconds before its first network hop")) return -1;
|
|
if (!Check(RemoveRadios(m_Route.Nodes[0].Carrier), "fixture removes actual transmitting equipment mid-uplink"))
|
|
return -1;
|
|
m_Step = 1; return 0;
|
|
}
|
|
if (m_Step == 1)
|
|
{
|
|
if (hq.Memory().Get(m_Mode))
|
|
{ Check(false, "interrupted uplink created a belief"); return -1; }
|
|
if (!m_Route.Failed) return 0;
|
|
if (!Check(!m_Route.Originated && !m_Route.Sending, "original caller radio loss interrupts call before any hop")) return -1;
|
|
Print("ERR SMOKE PASS: HQ memory physical uplink loss prevents production Accept");
|
|
m_Step = 2;
|
|
}
|
|
// A real carrier can fail after selection. Retry with a fresh immutable payload;
|
|
// a fixture may not hang waiting for a message that production correctly dropped.
|
|
if (m_Route && m_Route.Failed && m_Step >= 3)
|
|
{
|
|
m_RouteRetries++;
|
|
if (m_RouteRetries > 5) { Check(false, "positive-route retry bound"); return -1; }
|
|
if (m_Step == 3) m_Step = 2;
|
|
else if (m_Step == 5) m_Step = 4;
|
|
else if (m_Step == 7) m_Step = 6;
|
|
else if (m_Step == 9) m_Step = 8;
|
|
else if (m_Step == 10) m_Step = 9;
|
|
m_Route = null;
|
|
}
|
|
if (m_Step == 2 || m_Step == 4 || m_Step == 8)
|
|
{
|
|
if (m_Step == 4 && now - m_FirstObserved < 4000) return 0;
|
|
vector position = m_FirstPosition;
|
|
if (m_Step >= 4) position += "24 0 0";
|
|
m_Report = Payload(hq, now, position);
|
|
m_Route = hq.ERR_MemoryFixtureQueue(m_Report);
|
|
if (!m_Route) return 0;
|
|
if (m_Step == 2) m_FirstObserved = now;
|
|
if (m_Step == 4) m_SecondObserved = now;
|
|
m_Step++; return 0;
|
|
}
|
|
ERR_HQBelief current = hq.Memory().Get(m_Mode);
|
|
if (m_Step == 3)
|
|
{
|
|
if (!current || current.MessageId != m_Report.MessageId) return 0;
|
|
if (!Check(m_Route.Originated && now - m_Route.StartedAt >= 5000, "delivered uplink includes originating call and physical hop latency")) return -1;
|
|
if (!Check(current.Position == m_Report.Position && current.SampleCount == 1,
|
|
"actual uplink delivery reaches production intake exactly once")) return -1;
|
|
m_BeliefId = current.BeliefId; m_Step = 4; return 0;
|
|
}
|
|
if (m_Step == 5)
|
|
{
|
|
if (!current || current.MessageId != m_Report.MessageId) return 0;
|
|
if (!Check(current.BeliefId == m_BeliefId && current.SampleCount == 2 && current.HasVelocity,
|
|
"second physical delivery extends one stable credible trajectory")) return -1;
|
|
m_Revision = current.BeliefRevision;
|
|
m_Step = 6;
|
|
}
|
|
if (m_Step == 6)
|
|
{
|
|
m_Sweep = new ERR_HQSearchReport();
|
|
m_Sweep.MessageId = hq.Journal().Message(); m_Sweep.BeliefId = m_BeliefId;
|
|
m_Sweep.BeliefRevision = m_Revision; m_Sweep.ObservedAt = now; m_Sweep.Position = current.Position;
|
|
m_Sweep.SweepCompleted = true;
|
|
m_Route = hq.ERR_MemoryFixtureSweep(m_Sweep);
|
|
if (!m_Route) return 0;
|
|
if (!Check(Unaged(hq.Memory().GetById(m_BeliefId)) > 0.99,
|
|
"synthetic completed sweep is not knowledge before radio delivery")) return -1;
|
|
m_Step = 7; return 0;
|
|
}
|
|
if (m_Step == 7)
|
|
{
|
|
if (!current || Unaged(current) > 0.99) return 0;
|
|
if (!Check(Math.AbsFloat(Unaged(current) - 0.65) < 0.001 && current.BeliefRevision == m_Revision
|
|
&& current.ObservedAt == m_SecondObserved && current.SampleCount == 2,
|
|
"delivered negative sweep lowers confidence without inventing a sighting")) return -1;
|
|
hq.ERR_MemoryFixtureReplaySweep(m_Sweep, now);
|
|
if (!Check(Math.AbsFloat(Unaged(hq.Memory().Get(m_Mode)) - 0.65) < 0.001,
|
|
"replayed completed-sweep payload cannot multiply confidence loss")) return -1;
|
|
m_Step = 8; return 0;
|
|
}
|
|
if (m_Step == 9)
|
|
{
|
|
if (!current || current.MessageId != m_Report.MessageId) return 0;
|
|
if (!Check(current.BeliefRevision > m_Revision && Unaged(current) > 0.99,
|
|
"fresh delivered sighting supersedes prior negative evidence")) return -1;
|
|
ERR_HQSearchReport stale = new ERR_HQSearchReport();
|
|
stale.MessageId = hq.Journal().Message(); stale.BeliefId = m_BeliefId;
|
|
stale.BeliefRevision = m_Revision; stale.ObservedAt = now; stale.Position = m_FirstPosition;
|
|
stale.SweepCompleted = true;
|
|
m_Route = hq.ERR_MemoryFixtureSweep(stale);
|
|
if (!m_Route) return 0;
|
|
m_Step = 10; return 0;
|
|
}
|
|
if (m_Step == 10)
|
|
{
|
|
if (m_Route.Failed) { Check(false, "old-revision fixture sweep route failed"); return -1; }
|
|
if (m_Route.Cursor < m_Route.Nodes.Count() || m_Route.Sending) return 0;
|
|
if (!Check(current && current.BeliefRevision > m_Revision && Unaged(current) > 0.99,
|
|
"delivered old-revision sweep cannot weaken a newer sighting")) return -1;
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
}
|
|
#endif
|