Include the current addon, terrain integrations, tools, regression tests and recorded development evidence.
307 lines
16 KiB
C
307 lines
16 KiB
C
#ifdef WORKBENCH
|
|
// Read-only fixture access to the actual production sender; never initiates a report.
|
|
modded class ERR_HQ
|
|
{
|
|
ERR_HQUnit ERR_MountedFixtureUnit(SCR_AIGroup group)
|
|
{
|
|
if (!ERR_NativeMountedAmmoProbe.Enabled() || !group) return null;
|
|
for (int i = 0; i < m_Units.Count() && i < 256; i++)
|
|
if (m_Units[i].Group == group) return m_Units[i];
|
|
return null;
|
|
}
|
|
}
|
|
|
|
// WORKBENCH-only read access to the exact successful startup callback identity.
|
|
modded class ERR_ConvoyMineStock
|
|
{
|
|
bool ERR_FixtureMine(ERR_SupplyConvoyTask task, ERR_ConvoyVehicle original, IEntity item)
|
|
{
|
|
if (!m_Closed || task != m_Task || original != m_Original || !original || original.Entity != m_Truck) return false;
|
|
if (!m_Truck || !item || !m_Items.Contains(item) || m_Cargo.Count() > 2 || !m_Inventory || m_Inventory.GetOwner() != m_Truck) return false;
|
|
if (m_Truck.FindComponent(InventoryStorageManagerComponent) != m_Inventory) return false;
|
|
foreach (ERR_ConvoyMineCargo operation : m_Cargo)
|
|
if (operation && operation.Finished && operation.Succeeded && operation.Item == item) return true;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
class ERR_NativeMountedAmmoProbe
|
|
{
|
|
protected ERR_GameMode m_Mode;
|
|
protected float m_Deadline;
|
|
protected float m_NextLog;
|
|
protected bool m_Failed;
|
|
protected bool m_Stopped;
|
|
protected bool m_FleetReady;
|
|
protected bool m_SwapEligibility;
|
|
protected bool m_MineStock;
|
|
protected ref ERR_ConvoyMineStock m_MineBatch;
|
|
protected ref ERR_ConvoyVehicle m_MineTruck;
|
|
protected InventoryStorageManagerComponent m_MineInventory;
|
|
protected ref array<IEntity> m_Mines = {};
|
|
protected ref array<ref ERR_ConvoyCargoCallback> m_PrimaryCargo = {};
|
|
protected ref ERR_NativeMountedSwapProbe m_SwapProbe;
|
|
protected ref ERR_SupplyConvoyTask m_ProofTask;
|
|
protected ERR_HQUnit m_Unit;
|
|
protected IEntity m_Root;
|
|
protected ref ERR_HQStatusReport m_Queued;
|
|
protected ref ERR_HQMountedAmmoSnapshot m_Payload;
|
|
protected ref ERR_HQRoute m_Route;
|
|
protected string m_RoutePayload;
|
|
static bool Enabled()
|
|
{
|
|
string enabled, outcome;
|
|
return Replication.IsServer() && System.GetCLIParam("errSmoke", enabled) && enabled == "1"
|
|
&& System.GetCLIParam("errSmokeOutcome", outcome) && outcome == "mounted-ammo";
|
|
}
|
|
void ERR_NativeMountedAmmoProbe(ERR_GameMode mode, float now)
|
|
{
|
|
m_Mode = mode; m_Deadline = now + 180000;
|
|
string swap, mines, courier;
|
|
m_MineStock = System.GetCLIParam("errMineStock", mines) && mines == "1";
|
|
m_SwapEligibility = System.GetCLIParam("errMountedSwapEligibility", swap) && swap == "1";
|
|
if (m_MineStock && (m_SwapEligibility || (System.GetCLIParam("errMountedCourier", courier) && courier == "1")))
|
|
Check(false, "mine-stock proof requires the normal mounted radio path, without swap or courier flags");
|
|
if (m_SwapEligibility) m_SwapProbe = new ERR_NativeMountedSwapProbe();
|
|
}
|
|
bool SwapEligibility() { return m_SwapEligibility; }
|
|
static string CompletionText(bool swapEligibility)
|
|
{
|
|
if (swapEligibility) return "ERR SMOKE COMPLETE: native mounted swap eligibility only; no transfer or radio proof; explicit fixture reset";
|
|
return "ERR SMOKE COMPLETE: production fleet mounted ammunition, cargo exclusion and actual radio delivery; explicit fixture reset";
|
|
}
|
|
protected bool Check(bool condition, string detail)
|
|
{
|
|
if (condition) { Print("ERR SMOKE PASS: mounted ammo " + detail); return true; }
|
|
m_Failed = true; Print("ERR SMOKE FAIL: mounted ammo " + detail, LogLevel.ERROR); return false;
|
|
}
|
|
protected bool Same(ERR_HQMountedAmmoSnapshot a, ERR_HQMountedAmmoSnapshot b)
|
|
{
|
|
return a && b && a.Complete == b.Complete && a.Weapons == b.Weapons && a.Muzzles == b.Muzzles
|
|
&& a.Magazines == b.Magazines && a.Rounds == b.Rounds && a.Capacity == b.Capacity
|
|
&& a.Chambers == b.Chambers && a.LowMagazines == b.LowMagazines;
|
|
}
|
|
protected bool Original(ERR_ConvoyVehicle vehicle, ERR_HQUnit unit)
|
|
{
|
|
if (!vehicle || !unit || !vehicle.Registered || vehicle.Released || !vehicle.Entity || !vehicle.Group
|
|
|| vehicle.Members.Count() > 32 || unit.Group != vehicle.Group || !unit.StatusSampler || !unit.StatusSampler.OwnsRoster(vehicle.Group)) return false;
|
|
ERR_ForceRecord record = m_Mode.Forces().FindGroup(vehicle.Group);
|
|
if (!record || record.Kind != ERR_ForceKind.CONVOY || !record.Physical || record.Eliminated
|
|
|| record.SourceId != unit.StatusSampler.InitialSourceId() || record.InitialStrength != vehicle.Members.Count()
|
|
|| unit.StatusSampler.InitialStrength() != vehicle.Members.Count()) return false;
|
|
foreach (IEntity member : vehicle.Members)
|
|
{
|
|
bool original;
|
|
for (int slot = 0; slot < unit.StatusSampler.InitialStrength(); slot++)
|
|
if (unit.StatusSampler.InitialMember(slot) == member) original = true;
|
|
if (!original || !ERR_Actors.Alive(member) || ERR_Actors.Group(member) != vehicle.Group
|
|
|| !ERR_ConvoyRules.PartOf(CompartmentAccessComponent.GetVehicleIn(member), vehicle.Entity)) return false;
|
|
}
|
|
return !vehicle.Members.IsEmpty();
|
|
}
|
|
protected void Capture(ERR_HQ hq, ERR_ConvoyVehicle vehicle, float now)
|
|
{
|
|
if (m_Queued || !vehicle || !vehicle.Registered) return;
|
|
ERR_HQUnit unit = hq.ERR_MountedFixtureUnit(vehicle.Group);
|
|
if (!Original(vehicle, unit) || !unit.PendingStatus || !unit.Uplink) return;
|
|
ERR_HQStatusReport report = unit.PendingStatus;
|
|
if (!report.MountedAmmo || report.MountedAmmo.Weapons < 1 || report.MountedAmmo.Magazines < 1) return;
|
|
ERR_HQWatchEntry before = hq.Watch().Find(report.SourceId);
|
|
if (before && before.MessageId >= report.MessageId) return;
|
|
if (!Check(ERR_HQWatchRules.Valid(report, now) && report.SourceId == unit.StatusSampler.InitialSourceId()
|
|
&& unit.Uplink.MessageId == report.MessageId && unit.Uplink.Cursor < unit.Uplink.Nodes.Count(), "original mounted payload observed before real radio delivery")) return;
|
|
m_Unit = unit; m_Root = vehicle.Entity; m_Queued = report;
|
|
m_Payload = report.MountedAmmo.Snapshot(); m_Route = unit.Uplink; m_RoutePayload = m_Route.Payload;
|
|
Check(m_Payload != report.MountedAmmo && Same(m_Payload, report.MountedAmmo)
|
|
&& m_RoutePayload.Contains("mounted ammunition="), "queued counts copied without mutating sender or radio payload");
|
|
}
|
|
protected ERR_SupplyConvoyTask Candidate(ERR_HQ hq)
|
|
{
|
|
for (int i = 0; i < hq.Convoys().Count() && i < 3; i++)
|
|
{
|
|
ERR_SupplyConvoyTask task = ERR_SupplyConvoyTask.Cast(hq.Convoys().At(i));
|
|
if (m_MineStock && m_ProofTask && task != m_ProofTask) continue;
|
|
if (!task || task.Stopped || !task.Ready || !task.MagazinesIssued || !task.Receipt || task.Vehicles.Count() != 6 || task.Cargo.Count() > 128) continue;
|
|
bool finished = true;
|
|
foreach (ERR_ConvoyCargoCallback pending : task.Cargo) if (!pending || !pending.Finished) finished = false;
|
|
if (!finished) continue;
|
|
// If an initial report was already observed, prove that same convoy's roots.
|
|
if (m_Queued)
|
|
{
|
|
bool ownsRoot;
|
|
foreach (ERR_ConvoyVehicle vehicle : task.Vehicles) if (vehicle && vehicle.Entity == m_Root) ownsRoot = true;
|
|
if (!ownsRoot) continue;
|
|
}
|
|
if (m_MineStock)
|
|
{
|
|
// Pin the first ordinary eligible convoy; absent optional cargo must not
|
|
// select a different fleet or change the original fixed proof deadline.
|
|
if (!m_ProofTask) m_ProofTask = task;
|
|
if (!m_MineBatch) m_MineBatch = task.MineStock;
|
|
if (m_MineBatch && task.MineStock != m_MineBatch)
|
|
{ Check(false, "original pending optional mine batch replaced"); return null; }
|
|
if (!m_MineBatch || !m_MineBatch.Complete()) return null;
|
|
}
|
|
return task;
|
|
}
|
|
return null;
|
|
}
|
|
protected bool MineCustody(IEntity item, IEntity truck, array<IEntity> items)
|
|
{
|
|
if (!ERR_InfantryMineTransfer.ReadyMine(item) || !items.Contains(item)) return false;
|
|
if (!item.FindComponent(DamageManagerComponent)) return false;
|
|
InventoryItemComponent carried = InventoryItemComponent.Cast(item.FindComponent(InventoryItemComponent));
|
|
if (!carried) return false;
|
|
InventoryStorageSlot slot = carried.GetParentSlot();
|
|
if (!slot || slot.GetAttachedEntity() != item || !slot.GetStorage()) return false;
|
|
if (slot.GetStorage().GetSlot(slot.GetID()) != slot) return false;
|
|
return ERR_InfantryAmmoTransfer.StoredUnder(item, truck);
|
|
}
|
|
protected bool Mines(ERR_SupplyConvoyTask task, bool capture)
|
|
{
|
|
if (!m_MineStock) return true;
|
|
if (!Check(task && !task.Stopped && task.Ready && task.MagazinesIssued && task.Vehicles.Count() == 6,
|
|
"mine proof retains ready original production convoy")) return false;
|
|
ERR_ConvoyVehicle truck = task.Vehicles[1];
|
|
ERR_ConvoyMineStock batch = task.MineStock;
|
|
if (!Check(truck && truck.Entity && truck.Registered && !truck.Released && batch && batch.Complete(),
|
|
"original truck optional mine batch closed")) return false;
|
|
int count = batch.Count();
|
|
if (!Check(count >= 1 && count <= 2, "one or two exact initial PMN4 identities available; no stock fabricated")) return false;
|
|
InventoryStorageManagerComponent inventory = InventoryStorageManagerComponent.Cast(truck.Entity.FindComponent(InventoryStorageManagerComponent));
|
|
if (!Check(inventory && inventory.GetOwner() == truck.Entity && task.Cargo.Count() <= 128,
|
|
"original mine truck inventory and primary callback bounds")) return false;
|
|
array<IEntity> items = {}; ERR_Inventory.Items(inventory, items);
|
|
if (!Check(items.Count() <= 128, "mine physical inventory enumeration bounded")) return false;
|
|
if (capture)
|
|
{
|
|
if (!Check(!m_MineBatch || m_MineBatch == batch, "same original mine batch at capture")) return false;
|
|
m_MineBatch = batch; m_MineTruck = truck; m_MineInventory = inventory;
|
|
for (int primary = 0; primary < task.Cargo.Count(); primary++) m_PrimaryCargo.Insert(task.Cargo[primary]);
|
|
}
|
|
else if (!Check(batch == m_MineBatch && truck == m_MineTruck && inventory == m_MineInventory
|
|
&& count == m_Mines.Count() && task.Cargo.Count() == m_PrimaryCargo.Count(), "original mine batch, truck, count and primary callbacks unchanged through radio delivery")) return false;
|
|
for (int cargo = 0; cargo < task.Cargo.Count(); cargo++)
|
|
if (!Check(task.Cargo[cargo] && task.Cargo[cargo].Finished && task.Cargo[cargo] == m_PrimaryCargo[cargo],
|
|
"higher-priority primary cargo remains settled and unchanged")) return false;
|
|
array<IEntity> unique = {};
|
|
for (int index = 0; index < count; index++)
|
|
{
|
|
IEntity item = batch.At(index);
|
|
if (!Check(item && !unique.Contains(item)
|
|
&& MineCustody(item, truck.Entity, items), "unique original callback-proved inactive PMN4 retains reciprocal truck storage custody")) return false;
|
|
unique.Insert(item);
|
|
if (capture) m_Mines.Insert(item);
|
|
else if (!Check(m_Mines[index] == item, "exact initial PMN4 snapshot identity unchanged")) return false;
|
|
}
|
|
PrintFormat("ERR MINE STOCK PROOF: capture=%1 originals=%2 primary=%3; read-only, no transfer proof", capture, count, task.Cargo.Count());
|
|
return true;
|
|
}
|
|
protected bool Fleet(ERR_HQ hq)
|
|
{
|
|
ERR_SupplyConvoyTask task = Candidate(hq);
|
|
if (!task) return false;
|
|
if (!Check(task.Vehicles.Count() == 6, "six original production roots in selected convoy")) return false;
|
|
bool armed;
|
|
for (int slot = 0; slot < 6; slot++)
|
|
{
|
|
ERR_ConvoyVehicle vehicle = task.Vehicles[slot];
|
|
if (!Check(vehicle && Original(vehicle, hq.ERR_MountedFixtureUnit(vehicle.Group)), "root retains original admitted seated crew and ledger")) return false;
|
|
ERR_HQMountedAmmoSnapshot sample = ERR_HQMountedAmmoSampler.Inspect(vehicle.Entity);
|
|
if (!Check(sample && sample.Valid(), "native root returns bounded valid snapshot")) return false;
|
|
PrintFormat("ERR MOUNTED SAMPLE: source=%1 slot=%2 complete=%3 weapons=%4 muzzles=%5 magazines=%6", task.Receipt.SourceId, slot, sample.Complete, sample.Weapons, sample.Muzzles, sample.Magazines);
|
|
PrintFormat("ERR MOUNTED COUNTS: slot=%1 rounds=%2 capacity=%3 chambers=%4 low=%5", slot, sample.Rounds, sample.Capacity, sample.Chambers, sample.LowMagazines);
|
|
if (sample.Weapons > 0 && sample.Magazines > 0) armed = true;
|
|
if (slot == 1)
|
|
{
|
|
InventoryStorageManagerComponent inventory = InventoryStorageManagerComponent.Cast(vehicle.Entity.FindComponent(InventoryStorageManagerComponent));
|
|
if (!Check(inventory != null, "original ammo truck storage present")) return false;
|
|
array<IEntity> cargo = {}; inventory.GetItems(cargo, EStoragePurpose.PURPOSE_DEPOSIT);
|
|
if (!Check(cargo.Count() <= 128, "cargo proof inspection is bounded")) return false;
|
|
int cargoWeapons;
|
|
foreach (IEntity item : cargo)
|
|
if (item && BaseWeaponComponent.Cast(item.FindComponent(BaseWeaponComponent))) cargoWeapons++;
|
|
if (!Check(cargoWeapons >= 8 && sample.Complete && sample.Weapons == 0 && sample.Magazines == 0
|
|
&& sample.Rounds == 0 && sample.Capacity == 0 && sample.Chambers == 0, "eight physical cargo weapons excluded from unarmed truck snapshot")) return false;
|
|
}
|
|
}
|
|
if (!Check(armed, "actual installed weapon magazines sampled in production convoy")) return false;
|
|
if (!Mines(task, true)) return false;
|
|
m_ProofTask = task;
|
|
PrintFormat("ERR MOUNTED SCOPE: checked=1 original convoy, deployed=%1 configured=%2; remaining fleet reliability not qualified", hq.Convoys().Count(), hq.SupplyConvoys().Target());
|
|
return true;
|
|
}
|
|
int Tick(ERR_HQ hq, float now)
|
|
{
|
|
if (m_Stopped || m_Failed) return -1;
|
|
if (!m_Mode || m_Mode != ERR_GameMode.Get() || !m_Mode.Active()) return -1;
|
|
if (now > m_Deadline)
|
|
{
|
|
if (m_MineStock) Check(false, "fixed 180-second mine-stock and radio proof deadline; original stock or delivery unavailable");
|
|
else Check(false, "fixed 180-second proof deadline");
|
|
return -1;
|
|
}
|
|
if (!hq || !hq.Convoys() || !hq.SupplyConvoys()) return 0;
|
|
if (!CheckTarget(hq)) return -1;
|
|
if (m_ProofTask && m_ProofTask.Stopped) { Check(false, "selected original convoy retained through proof"); return -1; }
|
|
if (now >= m_NextLog)
|
|
{
|
|
PrintFormat("ERR MOUNTED WAIT: fleet=%1 ready=%2 queued=%3 remaining=%4", hq.Convoys().Count(), m_FleetReady, m_Queued != null, m_Deadline - now);
|
|
PrintFormat("ERR MOUNTED PRODUCTION: %1", hq.SupplyConvoys().Status());
|
|
m_NextLog = now + 10000;
|
|
}
|
|
if (m_SwapEligibility)
|
|
{
|
|
if (!m_ProofTask) m_ProofTask = Candidate(hq);
|
|
if (!m_ProofTask) return 0;
|
|
int eligibility = m_SwapProbe.Tick(m_Mode, hq, m_ProofTask);
|
|
if (eligibility < 0) { Check(false, "swap eligibility unavailable or native refusal; no radio-delivery qualification"); return -1; }
|
|
return eligibility;
|
|
}
|
|
// Observe queues during fleet preparation too, so fast initial deliveries are not missed.
|
|
for (int convoy = 0; convoy < hq.Convoys().Count() && convoy < 3; convoy++)
|
|
{
|
|
ERR_ConvoyTask task = hq.Convoys().At(convoy);
|
|
if (!task || (m_ProofTask && task != m_ProofTask)) continue;
|
|
for (int slot = 0; slot < task.Vehicles.Count() && slot < 6; slot++) Capture(hq, task.Vehicles[slot], now);
|
|
}
|
|
if (!m_FleetReady) m_FleetReady = Fleet(hq);
|
|
if (m_Failed) return -1;
|
|
if (!m_FleetReady || !m_Queued) return 0;
|
|
ERR_HQWatchEntry delivered = hq.Watch().Find(m_Queued.SourceId);
|
|
if (!delivered || delivered.MessageId < m_Queued.MessageId)
|
|
{
|
|
if (m_Unit.PendingStatus != m_Queued && m_Unit.Uplink != m_Route)
|
|
{
|
|
Check(true, "interrupted observed transmission created no matching HQ knowledge; wait for another natural report");
|
|
Forget();
|
|
}
|
|
return 0;
|
|
}
|
|
if (!Check(delivered.MessageId == m_Queued.MessageId && delivered.MountedAmmo
|
|
&& delivered.MountedAmmo != m_Queued.MountedAmmo && delivered.MountedAmmo != m_Payload
|
|
&& Same(delivered.MountedAmmo, m_Payload) && Same(m_Queued.MountedAmmo, m_Payload), "actual HQ Watch holds separate copy of the exact queued counts")) return -1;
|
|
if (!Check(delivered.ObservedAt == m_Queued.ObservedAt && delivered.LastDeliveredAt >= delivered.ObservedAt
|
|
&& delivered.LastDeliveredAt <= now && delivered.LastDeliveredAt - delivered.ObservedAt <= 120000
|
|
&& delivered.Strength == m_Queued.Strength && delivered.Count == m_Queued.Count
|
|
&& delivered.Fit == m_Queued.Fit && m_Route.MessageId == m_Queued.MessageId
|
|
&& m_Route.Payload == m_RoutePayload, "delivered observation age, roster counts and radio payload preserved")) return -1;
|
|
if (!Check(hq.ERR_MountedFixtureUnit(m_Unit.Group) == m_Unit && ERR_Actors.Alive(m_Root), "original source and root retained through delivery")) return -1;
|
|
if (!Mines(m_ProofTask, false)) return -1;
|
|
return 1;
|
|
}
|
|
protected bool CheckTarget(ERR_HQ hq)
|
|
{
|
|
if (hq.SupplyConvoys().Target() == 3 && hq.Convoys().Count() <= 3) return true;
|
|
return Check(false, "unchanged default three-convoy production target");
|
|
}
|
|
protected void Forget() { m_Unit = null; m_Root = null; m_Queued = null; m_Payload = null; m_Route = null; m_RoutePayload = string.Empty; }
|
|
void Stop()
|
|
{
|
|
m_Stopped = true; if (m_SwapProbe) m_SwapProbe.Stop();
|
|
m_ProofTask = null; m_MineBatch = null; m_MineTruck = null; m_MineInventory = null;
|
|
m_Mines.Clear(); m_PrimaryCargo.Clear(); Forget();
|
|
}
|
|
}
|
|
#endif
|