Capture current mission, AI, map and administration development
Include the current addon, terrain integrations, tools, regression tests and recorded development evidence.
This commit is contained in:
@@ -0,0 +1,19 @@
|
||||
check: /tmp/erri-mine-zones-tests-0558/scratch/err-policy-cso5o9b7/check.cpp:316: int main(): Assertion `!f.controller.Begin(&f.mode,&f.unit,&f.task,point,1000)' failed.
|
||||
Traceback (most recent call last):
|
||||
File "/tmp/erri-mine-zones-tests-0558/tests/test_engineer_mine.py", line 31, in <module>
|
||||
run(r'''
|
||||
~~~^^^^^
|
||||
#include <cassert>
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
...<181 lines>...
|
||||
}
|
||||
^
|
||||
''')
|
||||
^^^^
|
||||
File "/home/jakub/devel/escapistsrereintroduced/tests/policy_harness.py", line 14, in run
|
||||
subprocess.run([str(p/'check')],check=True)
|
||||
~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "/usr/lib/python3.14/subprocess.py", line 578, in run
|
||||
raise CalledProcessError(retcode, process.args,
|
||||
output=stdout, stderr=stderr)
|
||||
subprocess.CalledProcessError: Command '['/tmp/erri-mine-zones-tests-0558/scratch/err-policy-cso5o9b7/check']' died with <Signals.SIGABRT: 6>.
|
||||
@@ -0,0 +1,275 @@
|
||||
// Decisions consumed by the finite original-item controller below.
|
||||
class ERR_EngineerMineRules
|
||||
{
|
||||
static bool Within(float started, float previous, float now)
|
||||
{
|
||||
return ERR_ForceRules.Finite(started) && ERR_ForceRules.Finite(previous) && ERR_ForceRules.Finite(now)
|
||||
&& started >= 0 && previous >= started && now >= previous && now - started < 180000;
|
||||
}
|
||||
static float PrepareSince(float since, float now, bool near, bool engaged)
|
||||
{
|
||||
if (!ERR_ForceRules.Finite(now) || now < 0 || !near || engaged) return -1;
|
||||
if (!ERR_ForceRules.Finite(since) || since < 0 || since > now) return now;
|
||||
return since;
|
||||
}
|
||||
static bool Prepared(float since, float now)
|
||||
{
|
||||
return ERR_ForceRules.Finite(since) && ERR_ForceRules.Finite(now) && since >= 0 && now - since >= 10000;
|
||||
}
|
||||
static bool MayArm(bool grounded, bool ownerValid, float distance, bool friendlyNear)
|
||||
{
|
||||
return grounded && ownerValid && ERR_ForceRules.Finite(distance) && distance >= 20 && !friendlyNear;
|
||||
}
|
||||
}
|
||||
|
||||
// Callback records only terminal evidence. It never moves, arms or retries items.
|
||||
class ERR_EngineerMineRemoval : ScriptedInventoryOperationCallback
|
||||
{
|
||||
int Result;
|
||||
protected void Finish(int result) { if (!Result) Result = result; }
|
||||
protected override void OnComplete() { Finish(1); }
|
||||
protected override void OnAllComplete() { Finish(1); }
|
||||
protected override void OnFailed() { Finish(-1); }
|
||||
protected override void OnAllFailed() { Finish(-1); }
|
||||
}
|
||||
|
||||
// One original soldier, one carried PMN4, one accepted HQ road-interception post.
|
||||
// Loose cancelled items remain ordinary unarmed loot. Armed mines retain native
|
||||
// lifetime; a round's world reset owns their destruction, not this controller.
|
||||
class ERR_EngineerMine
|
||||
{
|
||||
protected ERR_GameMode m_Mode;
|
||||
protected ERR_HQUnit m_Unit;
|
||||
protected SCR_AIGroup m_Group;
|
||||
protected ref ERR_HQTask m_Task;
|
||||
protected ref ERR_HQReport m_Assignment;
|
||||
protected ref ERR_ForceRecord m_Record;
|
||||
protected string m_SourceId;
|
||||
protected int m_Strength;
|
||||
protected IEntity m_Actor;
|
||||
protected int m_Slot;
|
||||
protected IEntity m_Mine;
|
||||
protected SCR_PressureTriggerComponent m_Trigger;
|
||||
protected SCR_InventoryStorageManagerComponent m_Inventory;
|
||||
protected SCR_AIUtilityComponent m_Utility;
|
||||
protected ref SCR_AIBehaviorBase m_Action;
|
||||
protected ref ERR_EngineerMineRemoval m_Removal;
|
||||
protected ref array<IEntity> m_Attempted;
|
||||
protected ref array<IEntity> m_IntelFolders = {};
|
||||
protected vector m_Position;
|
||||
protected vector m_Rally;
|
||||
protected float m_Started = -1;
|
||||
protected float m_LastTick = -1;
|
||||
protected float m_PreparedAt = -1;
|
||||
protected float m_NextClearance;
|
||||
protected int m_State; // 0 approach,1 continuous preparation,2 removal pending,3 withdraw,4 finished
|
||||
protected int m_Checked;
|
||||
protected bool m_FriendlyNear;
|
||||
protected bool m_Begun;
|
||||
protected bool m_Stopped;
|
||||
|
||||
void ERR_EngineerMine(array<IEntity> attempted) { m_Attempted = attempted; }
|
||||
bool Finished() { return m_Stopped || m_State == 4; }
|
||||
protected bool Refuse() { Stop(); return false; }
|
||||
protected bool Quiet()
|
||||
{
|
||||
return m_Unit && !m_Unit.InfantryCombat.Held && !ERR_HunterCombat.Active(m_Group);
|
||||
}
|
||||
protected bool Owned()
|
||||
{
|
||||
if (m_Stopped || !Replication.IsServer() || !m_Mode || m_Mode != ERR_GameMode.Get() || !m_Mode.Active()) return false;
|
||||
if (!m_Unit || !m_Group || m_Unit.Group != m_Group || !m_Task || m_Unit.Task != m_Task) return false;
|
||||
if (!m_Assignment || m_Unit.Assignment != m_Assignment || !m_Task.RoadIntercept || m_Task.ReleaseOnly) return false;
|
||||
if (m_Task.Investigation() || !m_Task.SecuritySite.IsEmpty() || m_Unit.PendingTask || m_Unit.PendingOrder) return false;
|
||||
if (m_Unit.ReservedForSupport || m_Unit.LogisticsReservation > 0 || m_Group.IsSlave() || m_Group.GetPlayerCount(true) > 0) return false;
|
||||
SCR_AIGroupUtilityComponent groupUtility = m_Group.GetGroupUtilityComponent();
|
||||
if (m_Started < 0 && (!groupUtility || !groupUtility.IsPositionAllowed(m_Position))) return false;
|
||||
if (!m_Mode.EnemyFaction() || m_Group.GetFaction() != m_Mode.EnemyFaction() || !m_Unit.StatusSampler) return false;
|
||||
if (vector.Distance(m_Task.Destination, m_Rally) > 0.01 || !m_Mode.Forces() || !m_Record) return false;
|
||||
if (m_Mode.Forces().FindGroup(m_Group) != m_Record || m_Record.Group != m_Group || !m_Record.Physical || m_Record.Eliminated) return false;
|
||||
if (m_Record.SourceId != m_SourceId || m_Unit.ForceSourceId != m_SourceId || m_Record.InitialStrength != m_Strength) return false;
|
||||
if (!m_Unit.StatusSampler.OwnsRoster(m_Group) || m_Unit.StatusSampler.InitialStrength() != m_Strength) return false;
|
||||
if (!m_Actor || !ERR_Actors.CanFight(m_Actor) || ERR_Actors.Player(m_Actor) || CompartmentAccessComponent.GetVehicleIn(m_Actor)) return false;
|
||||
if (!m_Unit.StatusSampler.CanAttribute(m_Slot, m_Actor, false) || ERR_Actors.Group(m_Actor) != m_Group) return false;
|
||||
if (SCR_FactionManager.SGetFaction(m_Actor) != m_Mode.EnemyFaction()) return false;
|
||||
SCR_ChimeraAIAgent agent = SCR_ChimeraAIAgent.Cast(SCR_AIUtils.GetAIAgent(m_Actor));
|
||||
if (!agent || !m_Utility || agent.m_UtilityComponent != m_Utility || !m_Utility.m_AIInfo) return false;
|
||||
if (!m_Inventory || m_Actor.FindComponent(SCR_InventoryStorageManagerComponent) != m_Inventory) return false;
|
||||
return true;
|
||||
}
|
||||
protected bool MineValid()
|
||||
{
|
||||
if (!ERR_Actors.Alive(m_Mine) || !m_Mine.GetPrefabData() || m_Mine.GetPrefabData().GetPrefabName() != ERR_EnemyLoadoutCatalog.MINE) return false;
|
||||
if (!m_Trigger || m_Mine.FindComponent(SCR_PressureTriggerComponent) != m_Trigger || m_Trigger.IsActivated()) return false;
|
||||
return m_Attempted && m_Attempted.Contains(m_Mine);
|
||||
}
|
||||
protected bool Carried()
|
||||
{
|
||||
if (!MineValid() || !m_Inventory) return false;
|
||||
array<IEntity> items = {}; ERR_Inventory.Items(m_Inventory, items);
|
||||
return items.Count() <= 128 && items.Contains(m_Mine) && ERR_InfantryAmmoTransfer.StoredUnder(m_Mine, m_Actor);
|
||||
}
|
||||
protected bool Grounded()
|
||||
{
|
||||
if (!MineValid() || !m_Inventory) return false;
|
||||
InventoryItemComponent item = InventoryItemComponent.Cast(m_Mine.FindComponent(InventoryItemComponent));
|
||||
if (!item || item.GetParentSlot() || m_Mine.GetParent()) return false;
|
||||
array<IEntity> items = {}; ERR_Inventory.Items(m_Inventory, items);
|
||||
return items.Count() <= 128 && !items.Contains(m_Mine);
|
||||
}
|
||||
protected bool Placed()
|
||||
{
|
||||
if (!Grounded() || vector.Distance(m_Mine.GetOrigin(), m_Position) > 1) return false;
|
||||
Physics physics = m_Mine.GetPhysics();
|
||||
return physics && physics.GetVelocity().LengthSq() <= 0.25;
|
||||
}
|
||||
protected void ClearAction()
|
||||
{
|
||||
if (m_Action && m_Actor && m_Utility && m_Utility.m_AIInfo)
|
||||
{
|
||||
SCR_ChimeraAIAgent agent = SCR_ChimeraAIAgent.Cast(SCR_AIUtils.GetAIAgent(m_Actor));
|
||||
if (agent && agent.m_UtilityComponent == m_Utility)
|
||||
{
|
||||
array<ref AIActionBase> actions = {}; m_Utility.GetActions(actions);
|
||||
if (actions.Count() <= 128 && actions.Contains(m_Action)) m_Action.Complete();
|
||||
}
|
||||
}
|
||||
m_Action = null;
|
||||
}
|
||||
protected void Move(vector destination)
|
||||
{
|
||||
ClearAction();
|
||||
m_Action = new SCR_AIMoveIndividuallyBehavior(m_Utility, null, destination, 1000, 0, null, 1);
|
||||
m_Utility.AddAction(m_Action);
|
||||
}
|
||||
protected void WaitAtMine()
|
||||
{
|
||||
ClearAction();
|
||||
m_Action = new SCR_AIWaitBehavior(m_Utility, null);
|
||||
m_Action.SetPriority(1000);
|
||||
m_Utility.AddAction(m_Action);
|
||||
}
|
||||
protected bool CheckFriendly(IEntity entity)
|
||||
{
|
||||
if (++m_Checked > 256) { m_FriendlyNear = true; return false; }
|
||||
if (!entity || (!ChimeraCharacter.Cast(entity) && !Vehicle.Cast(entity))) return true;
|
||||
DamageManagerComponent damage = DamageManagerComponent.Cast(entity.FindComponent(DamageManagerComponent));
|
||||
if (damage && damage.IsDestroyed()) return true;
|
||||
FactionAffiliationComponent affiliation = FactionAffiliationComponent.Cast(entity.FindComponent(FactionAffiliationComponent));
|
||||
Faction faction;
|
||||
if (affiliation) faction = affiliation.GetAffiliatedFaction();
|
||||
if (faction && m_Mode.EnemyFaction().IsFactionEnemy(faction)) return true;
|
||||
// Unconscious allies and unknown affiliations both prevent arming.
|
||||
m_FriendlyNear = true;
|
||||
return false;
|
||||
}
|
||||
protected bool SelectActor()
|
||||
{
|
||||
if (!m_Unit.StatusSampler.OwnsRoster(m_Group) || m_Strength < 1 || m_Strength > 32) return false;
|
||||
for (int slot = 0; slot < m_Strength; slot++)
|
||||
{
|
||||
IEntity actor = m_Unit.StatusSampler.InitialMember(slot);
|
||||
if (!actor || !ERR_Actors.CanFight(actor) || ERR_Actors.Player(actor) || CompartmentAccessComponent.GetVehicleIn(actor)) continue;
|
||||
if (!m_Unit.StatusSampler.CanAttribute(slot, actor, false) || vector.DistanceXZ(actor.GetOrigin(), m_Rally) > 20) continue;
|
||||
SCR_ChimeraAIAgent agent = SCR_ChimeraAIAgent.Cast(SCR_AIUtils.GetAIAgent(actor));
|
||||
if (!agent || !agent.m_UtilityComponent || !agent.m_UtilityComponent.m_AIInfo) continue;
|
||||
SCR_InventoryStorageManagerComponent inventory = SCR_InventoryStorageManagerComponent.Cast(actor.FindComponent(SCR_InventoryStorageManagerComponent));
|
||||
if (!inventory) continue;
|
||||
array<IEntity> items = {}; ERR_Inventory.Items(inventory, items);
|
||||
if (items.Count() > 128) continue;
|
||||
foreach (IEntity mine : items)
|
||||
{
|
||||
if (!ERR_Actors.Alive(mine) || m_Attempted.Contains(mine) || !mine.GetPrefabData() || mine.GetPrefabData().GetPrefabName() != ERR_EnemyLoadoutCatalog.MINE) continue;
|
||||
if (!ERR_InfantryAmmoTransfer.StoredUnder(mine, actor)) continue;
|
||||
SCR_PressureTriggerComponent trigger = SCR_PressureTriggerComponent.Cast(mine.FindComponent(SCR_PressureTriggerComponent));
|
||||
if (!trigger || trigger.IsActivated() || trigger.IsActivatedByDefault()) continue;
|
||||
m_Actor = actor; m_Slot = slot; m_Mine = mine; m_Trigger = trigger;
|
||||
m_Inventory = inventory; m_Utility = agent.m_UtilityComponent;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool Begin(ERR_GameMode mode, ERR_HQUnit unit, ERR_HQTask task, vector minePosition, float now)
|
||||
{
|
||||
if (m_Begun || m_Stopped) return false;
|
||||
m_Begun = true;
|
||||
if (!Replication.IsServer() || !mode || mode != ERR_GameMode.Get() || !mode.Active()) return Refuse();
|
||||
if (!unit || !unit.Group || !unit.StatusSampler || !task || unit.Task != task || !unit.Assignment) return Refuse();
|
||||
if (!ERR_ForceRules.Finite(now) || now < 0 || !ERR_ForceRules.FiniteVector(minePosition)) return Refuse();
|
||||
if (!m_Attempted || m_Attempted.Count() >= 256 || !mode.Forces()) return Refuse();
|
||||
m_Mode = mode; m_Unit = unit; m_Task = task; m_Assignment = unit.Assignment; m_Group = unit.Group;
|
||||
m_SourceId = unit.ForceSourceId; m_Strength = unit.StatusSampler.InitialStrength(); m_Record = mode.Forces().FindGroup(m_Group);
|
||||
m_Position = minePosition; m_Rally = task.Destination;
|
||||
float distance = vector.DistanceXZ(m_Position, m_Rally);
|
||||
if (!ERR_ForceRules.FiniteVector(m_Rally) || distance < 25 || distance > 60 || now >= task.ExpiresAt) return Refuse();
|
||||
if (!SelectActor() || !Owned() || !Quiet()) return Refuse();
|
||||
// The shared exact-item tombstone survives pickup, transfer and late callbacks.
|
||||
m_Attempted.Insert(m_Mine);
|
||||
if (!Carried()) return Refuse();
|
||||
if (m_Mode.MineIntel()) m_Mode.MineIntel().Candidates(m_Actor, m_IntelFolders);
|
||||
m_Started = now; m_LastTick = now; m_State = 0;
|
||||
Move(m_Position);
|
||||
ERR_HQ.Event("ENGINEER MINE", "original carried PMN4 assigned; one approach and finite 180s deadline");
|
||||
return true;
|
||||
}
|
||||
void Stop()
|
||||
{
|
||||
if (m_Stopped) return;
|
||||
m_Stopped = true; m_State = 4;
|
||||
ClearAction();
|
||||
// Retain removal evidence and shared item quarantine. No late completion can arm.
|
||||
}
|
||||
void Tick(float now)
|
||||
{
|
||||
if (!m_Begun || Finished()) return;
|
||||
if (!ERR_EngineerMineRules.Within(m_Started, m_LastTick, now)) { Stop(); return; }
|
||||
m_LastTick = now;
|
||||
if (!Owned() || !Quiet() || !MineValid() || now >= m_Task.ExpiresAt) { Stop(); return; }
|
||||
if (m_State <= 1)
|
||||
{
|
||||
if (!Carried()) { Stop(); return; }
|
||||
bool near = vector.DistanceXZ(m_Actor.GetOrigin(), m_Position) <= 3;
|
||||
m_PreparedAt = ERR_EngineerMineRules.PrepareSince(m_PreparedAt, now, near, false);
|
||||
if (m_State == 0 && near) { m_State = 1; WaitAtMine(); }
|
||||
if (!ERR_EngineerMineRules.Prepared(m_PreparedAt, now)) return;
|
||||
// Set state and callback BEFORE native submission; never repeat the removal.
|
||||
m_Removal = new ERR_EngineerMineRemoval(); m_State = 2;
|
||||
bool accepted = m_Inventory.TryRemoveItemFromInventory(m_Mine, null, m_Removal);
|
||||
if (!accepted && !m_Removal.Result) { Stop(); return; }
|
||||
return;
|
||||
}
|
||||
if (m_State == 2)
|
||||
{
|
||||
if (!m_Removal || m_Removal.Result < 0) { Stop(); return; }
|
||||
// Observed transfer ends our custody; a later nearby drop cannot restore it.
|
||||
// Original inventory ownership may still settle after the native callback.
|
||||
InventoryItemComponent item = InventoryItemComponent.Cast(m_Mine.FindComponent(InventoryItemComponent));
|
||||
bool attached = m_Mine.GetParent() || (item && item.GetParentSlot());
|
||||
if (attached && !ERR_InfantryAmmoTransfer.StoredUnder(m_Mine, m_Actor)) { Stop(); return; }
|
||||
if (!m_Removal.Result || !Grounded()) return;
|
||||
if (vector.DistanceXZ(m_Actor.GetOrigin(), m_Position) > 3) { Stop(); return; }
|
||||
// A callback proves removal, not continued custody of a distant loose item.
|
||||
if (vector.Distance(m_Mine.GetOrigin(), m_Actor.GetOrigin()) > 3
|
||||
|| vector.Distance(m_Mine.GetOrigin(), m_Position) > 3) { Stop(); return; }
|
||||
m_Mine.SetOrigin(m_Position);
|
||||
m_State = 3; Move(m_Rally);
|
||||
return;
|
||||
}
|
||||
if (m_State != 3 || !Grounded() || vector.Distance(m_Mine.GetOrigin(), m_Position) > 1) { Stop(); return; }
|
||||
if (now < m_NextClearance || vector.DistanceXZ(m_Actor.GetOrigin(), m_Position) < 20) return;
|
||||
m_NextClearance = now + 1000;
|
||||
m_Checked = 0; m_FriendlyNear = false;
|
||||
if (!GetGame() || !GetGame().GetWorld()) { Stop(); return; }
|
||||
GetGame().GetWorld().QueryEntitiesBySphere(m_Position, 20, CheckFriendly, queryFlags: EQueryEntitiesFlags.ALL);
|
||||
if (!ERR_EngineerMineRules.MayArm(Placed(), Owned() && Quiet(), vector.DistanceXZ(m_Actor.GetOrigin(), m_Position), m_FriendlyNear)) return;
|
||||
m_Trigger.SetUser(m_Actor);
|
||||
m_Trigger.ActivateTrigger();
|
||||
if (m_Trigger.IsActivated())
|
||||
{
|
||||
if (m_Mode.MineIntel()) m_Mode.MineIntel().Seal(m_Actor, m_Mine, m_Position, m_IntelFolders);
|
||||
ERR_HQ.Event("ENGINEER MINE", "original PMN4 armed after engineer withdrawal and physical friendly clearance");
|
||||
}
|
||||
Stop();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
check: /tmp/erri-mine-zones-tests-0558/scratch/err-policy-j2skjy8v/check.cpp:336: int main(): Assertion `f.controller.Finished()&&own->completed==1&&!foreign.completed&&f.attempted.Count()==1' failed.
|
||||
Traceback (most recent call last):
|
||||
File "/tmp/erri-mine-zones-tests-0558/tests/test_engineer_mine.py", line 31, in <module>
|
||||
run(r'''
|
||||
~~~^^^^^
|
||||
#include <cassert>
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
...<181 lines>...
|
||||
}
|
||||
^
|
||||
''')
|
||||
^^^^
|
||||
File "/home/jakub/devel/escapistsrereintroduced/tests/policy_harness.py", line 14, in run
|
||||
subprocess.run([str(p/'check')],check=True)
|
||||
~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "/usr/lib/python3.14/subprocess.py", line 578, in run
|
||||
raise CalledProcessError(retcode, process.args,
|
||||
output=stdout, stderr=stderr)
|
||||
subprocess.CalledProcessError: Command '['/tmp/erri-mine-zones-tests-0558/scratch/err-policy-j2skjy8v/check']' died with <Signals.SIGABRT: 6>.
|
||||
@@ -0,0 +1,88 @@
|
||||
--- a/tests/test_engineer_mine.py
|
||||
+++ b/tests/test_engineer_mine.py
|
||||
@@ -9,11 +9,11 @@
|
||||
s=s.replace('protected override ','').replace('protected ','').replace('null','nullptr').replace('ref ','')
|
||||
s=s.replace('array<','Array<').replace(' = {};',';').replace('foreach (','for (')
|
||||
s=s.replace('array<IEntity> attempted','Array<IEntity>* attempted')
|
||||
- for typ in ['ERR_GameMode','ERR_HQUnit','ERR_HQTask','SCR_ChimeraAIAgent','SCR_InventoryStorageManagerComponent','SCR_PressureTriggerComponent','InventoryItemComponent','DamageManagerComponent','FactionAffiliationComponent','Faction','Physics']:
|
||||
+ for typ in ['SCR_AIGroupUtilityComponent','ERR_GameMode','ERR_HQUnit','ERR_HQTask','SCR_ChimeraAIAgent','SCR_InventoryStorageManagerComponent','SCR_PressureTriggerComponent','InventoryItemComponent','DamageManagerComponent','FactionAffiliationComponent','Faction','Physics']:
|
||||
s=re.sub(r'\b'+typ+r' (\w+)',typ+r'* \1',s)
|
||||
for ns in ['ERR_ForceRules','Replication','ERR_GameMode','ERR_HunterCombat','ERR_Actors','CompartmentAccessComponent','SCR_FactionManager','SCR_ChimeraAIAgent','SCR_AIUtils','ERR_EnemyLoadoutCatalog','ERR_Inventory','ERR_InfantryAmmoTransfer','InventoryItemComponent','DamageManagerComponent','FactionAffiliationComponent','ChimeraCharacter','Vehicle','SCR_InventoryStorageManagerComponent','SCR_PressureTriggerComponent','ERR_EngineerMineRules','ERR_HQ','vector']:
|
||||
s=s.replace(ns+'.',ns+'::')
|
||||
- for obj in ['m_Mode','m_Unit','m_Group','m_Task','m_Assignment','m_Record','m_Actor','m_Mine','m_Trigger','m_Inventory','m_Utility','m_Action','m_Removal','m_Attempted','mode','unit','task','actor','mine','agent','inventory','trigger','item','entity','physics','damage','affiliation','faction']:
|
||||
+ for obj in ['groupUtility','m_Mode','m_Unit','m_Group','m_Task','m_Assignment','m_Record','m_Actor','m_Mine','m_Trigger','m_Inventory','m_Utility','m_Action','m_Removal','m_Attempted','mode','unit','task','actor','mine','agent','inventory','trigger','item','entity','physics','damage','affiliation','faction']:
|
||||
s=re.sub(r'\b'+obj+r'\.',obj+'->',s)
|
||||
for field in ['StatusSampler','InfantryCombat','m_UtilityComponent']:
|
||||
s=s.replace(field+'.',field+'->')
|
||||
@@ -55,7 +55,16 @@
|
||||
void* FindComponent(std::string type){if(type=="InventoryItemComponent")return item;if(type=="SCR_PressureTriggerComponent")return trigger;if(type=="SCR_InventoryStorageManagerComponent")return inventory;if(type=="DamageManagerComponent")return damage;if(type=="FactionAffiliationComponent")return affiliation;return nullptr;}
|
||||
};
|
||||
struct ChimeraCharacter {static bool Cast(IEntity e){return e&&e->character;}};struct Vehicle {static bool Cast(IEntity e){return e&&e->vehicle;}};
|
||||
-struct SCR_AIGroup {bool slave=false;int players=0;Faction* faction=nullptr;bool IsSlave(){return slave;}int GetPlayerCount(bool){return players;}Faction* GetFaction(){return faction;}};
|
||||
+// Native group movement envelope boundary, not navigation/pathfinding.
|
||||
+struct AIWaypoint {virtual ~AIWaypoint()=default;};
|
||||
+struct SCR_DefendWaypoint:AIWaypoint {vector origin;float radius=30;vector GetOrigin(){return origin;}float GetCompletionRadius(){return radius;}static SCR_DefendWaypoint* Cast(AIWaypoint* p){return dynamic_cast<SCR_DefendWaypoint*>(p);}};
|
||||
+struct SCR_AIGroupUtilityComponent;
|
||||
+struct SCR_AIGroup {bool slave=false;int players=0;Faction* faction=nullptr;SCR_AIGroupUtilityComponent* utility=nullptr;AIWaypoint* waypoint=nullptr;vector center;
|
||||
+ bool IsSlave(){return slave;}int GetPlayerCount(bool){return players;}Faction* GetFaction(){return faction;}SCR_AIGroupUtilityComponent* GetGroupUtilityComponent(){return utility;}AIWaypoint* GetCurrentWaypoint(){return waypoint;}vector GetCenterOfMass(){return center;}};
|
||||
+struct SCR_AIGroupUtilityComponent {SCR_AIGroup* m_Owner=nullptr;float m_fMaxAutonomousDistance=100;
|
||||
+ // Matches installed SCR_AIGroupUtilityComponent.IsPositionAllowed semantics.
|
||||
+ bool IsPositionAllowed(vector pos){auto wp=m_Owner->GetCurrentWaypoint();auto defendWp=SCR_DefendWaypoint::Cast(wp);if(defendWp)return vector::Distance(defendWp->GetOrigin(),pos)<defendWp->GetCompletionRadius();return vector::Distance(m_Owner->GetCenterOfMass(),pos)<m_fMaxAutonomousDistance;}
|
||||
+};
|
||||
struct SCR_AIBehaviorBase {int completed=0;float priority=0;void Complete(){completed++;}void SetPriority(float p){priority=p;}};using AIActionBase=SCR_AIBehaviorBase;
|
||||
struct SCR_AIUtilityComponent {bool m_AIInfo=true;Array<AIActionBase*> actions;int additions=0;void GetActions(Array<AIActionBase*>& out){out=actions;}void AddAction(AIActionBase* a){additions++;actions.Insert(a);}};
|
||||
struct SCR_AIMoveIndividuallyBehavior:SCR_AIBehaviorBase {SCR_AIMoveIndividuallyBehavior(SCR_AIUtilityComponent*,void*,vector,float,float,void*,float){}};
|
||||
@@ -94,9 +103,9 @@
|
||||
struct ERR_EngineerMine {
|
||||
ERR_GameMode* m_Mode=nullptr;ERR_HQUnit* m_Unit=nullptr;SCR_AIGroup* m_Group=nullptr;ERR_HQTask* m_Task=nullptr;ERR_HQReport* m_Assignment=nullptr;ERR_ForceRecord* m_Record=nullptr;string m_SourceId;int m_Strength=0;IEntity m_Actor=nullptr;int m_Slot=0;IEntity m_Mine=nullptr;SCR_PressureTriggerComponent* m_Trigger=nullptr;SCR_InventoryStorageManagerComponent* m_Inventory=nullptr;SCR_AIUtilityComponent* m_Utility=nullptr;SCR_AIBehaviorBase* m_Action=nullptr;ERR_EngineerMineRemoval* m_Removal=nullptr;Array<IEntity>* m_Attempted=nullptr;Array<IEntity> m_IntelFolders;vector m_Position,m_Rally;float m_Started=-1,m_LastTick=-1,m_PreparedAt=-1,m_NextClearance=0;int m_State=0,m_Checked=0;bool m_FriendlyNear=false,m_Begun=false,m_Stopped=false;
|
||||
'''+cpp(methods)+r'''};
|
||||
-struct Fixture {Faction faction,hostile{true};SCR_AIGroup group;SCR_AIUtilityComponent utility;SCR_ChimeraAIAgent agent;SCR_InventoryStorageManagerComponent inventory;Entity actor,mine;Prefab prefab;Physics physics;InventoryItemComponent item;SCR_PressureTriggerComponent trigger;Sampler roster;ERR_HQTask task;ERR_HQReport report;ERR_ForceRecord record;Ledger ledger;ERR_GameMode mode;ERR_HQUnit unit;Array<IEntity> attempted;ERR_EngineerMine controller{&attempted};
|
||||
+struct Fixture {Faction faction,hostile{true};SCR_AIGroup group;SCR_AIGroupUtilityComponent groupUtility;SCR_AIUtilityComponent utility;SCR_ChimeraAIAgent agent;SCR_InventoryStorageManagerComponent inventory;Entity actor,mine;Prefab prefab;Physics physics;InventoryItemComponent item;SCR_PressureTriggerComponent trigger;Sampler roster;ERR_HQTask task;ERR_HQReport report;ERR_ForceRecord record;Ledger ledger;ERR_GameMode mode;ERR_HQUnit unit;Array<IEntity> attempted;ERR_EngineerMine controller{&attempted};
|
||||
Fixture(){ERR_GameMode::current=&mode;Replication::server=true;ERR_HunterCombat::engaged=false;currentGame=&game;game.world.query.clear();game.world.queries=0;
|
||||
- group.faction=&faction;actor.group=&group;actor.faction=&faction;actor.agent=&agent;actor.inventory=&inventory;agent.m_UtilityComponent=&utility;
|
||||
+ group.faction=&faction;group.utility=&groupUtility;groupUtility.m_Owner=&group;actor.group=&group;actor.faction=&faction;actor.agent=&agent;actor.inventory=&inventory;agent.m_UtilityComponent=&utility;
|
||||
mine.prefab=&prefab;mine.physics=&physics;mine.item=&item;mine.trigger=&trigger;mine.stored=true;mine.storageOwner=&actor;item.slot=&inventory;inventory.items.Insert(&mine);roster.members.Insert(&actor);
|
||||
record.Group=&group;ledger.record=&record;mode.faction=&faction;mode.ledger=&ledger;unit.Group=&group;unit.Task=&task;unit.Assignment=&report;unit.StatusSampler=&roster;}
|
||||
void Begin(){assert(controller.Begin(&mode,&unit,&task,{30,0,0},1000));assert(attempted.Count()==1&&utility.additions==1&&mode.mineIntel.candidates==1&&mode.mineIntel.capturedActor==&actor&&mode.mineIntel.seals==0);}
|
||||
@@ -105,6 +114,35 @@
|
||||
void Withdraw(){Prepare();Drop();inventory.callback->OnComplete();controller.Tick(12001);assert(controller.m_State==3&&mine.moves==1&&utility.additions==3);}
|
||||
};
|
||||
int main(){
|
||||
+ // Current native defend radius is strict and three dimensional: the broad
|
||||
+ // 25..60 m mission band does not authorize bypassing the group's own envelope.
|
||||
+ for(int fault=0;fault<4;fault++){Fixture f;SCR_DefendWaypoint defend;f.group.waypoint=&defend;vector point={30,0,0};
|
||||
+ if(fault==0)f.group.utility=nullptr;
|
||||
+ if(fault==2)point={25,17,0};
|
||||
+ if(fault==3){f.group.waypoint=nullptr;f.groupUtility.m_fMaxAutonomousDistance=30;}
|
||||
+ assert(!f.controller.Begin(&f.mode,&f.unit,&f.task,point,1000));
|
||||
+ assert(f.controller.Finished()&&f.attempted.empty()&&!f.utility.additions&&!f.inventory.calls&&!f.trigger.calls&&!f.mode.mineIntel.candidates);
|
||||
+ }
|
||||
+ for(int boundary=0;boundary<3;boundary++){Fixture f;SCR_DefendWaypoint defend;f.group.waypoint=&defend;vector point={29.999f,0,0};
|
||||
+ if(boundary==1)point={25,16,0};
|
||||
+ if(boundary==2){f.group.waypoint=nullptr;f.group.center={1,0,0};f.groupUtility.m_fMaxAutonomousDistance=30;point={30,0,0};}
|
||||
+ assert(f.controller.Begin(&f.mode,&f.unit,&f.task,point,1000));assert(f.attempted.Count()==1&&f.utility.additions==1);
|
||||
+ }
|
||||
+ // Revalidate the current utility and its current waypoint at every phase.
|
||||
+ // Cancellation completes only our exact action and never resumes after a late
|
||||
+ // inventory acknowledgement or a later enlargement of the movement envelope.
|
||||
+ for(int phase=0;phase<4;phase++)for(int replacement=0;replacement<3;replacement++){Fixture f;
|
||||
+ if(phase==3)f.Withdraw();else if(phase==2)f.Prepare();else{f.Begin();if(phase==1){f.actor.position={30,0,0};f.controller.Tick(2000);}}
|
||||
+ auto own=f.controller.m_Action;SCR_AIBehaviorBase foreign;f.utility.actions.Insert(&foreign);
|
||||
+ auto callback=f.inventory.callback;int calls=f.inventory.calls,additions=f.utility.additions,moves=f.mine.moves;
|
||||
+ SCR_DefendWaypoint defend;defend.radius=29;SCR_AIGroupUtilityComponent newUtility;newUtility.m_Owner=&f.group;newUtility.m_fMaxAutonomousDistance=29;
|
||||
+ if(replacement==0)f.group.waypoint=&defend;else if(replacement==1)f.group.utility=&newUtility;else f.group.utility=nullptr;
|
||||
+ f.controller.Tick(13000);
|
||||
+ assert(f.controller.Finished()&&own->completed==1&&!foreign.completed&&f.attempted.Count()==1);
|
||||
+ assert(f.inventory.calls==calls&&f.utility.additions==additions&&f.mine.moves==moves&&!f.trigger.calls&&!f.mode.mineIntel.seals);
|
||||
+ f.group.utility=&f.groupUtility;f.group.waypoint=nullptr;f.Drop();if(callback)callback->OnComplete();f.actor.position={0,0,0};f.controller.Tick(14000);
|
||||
+ assert(f.controller.Finished()&&own->completed==1&&!foreign.completed&&f.inventory.calls==calls&&f.utility.additions==additions&&f.mine.moves==moves&&!f.trigger.calls);
|
||||
+ }
|
||||
// Candidate list is captured once at accepted Begin; only successful native
|
||||
// activation seals that same original list, even if carried folders change.
|
||||
Fixture evidence;Entity originalFolder,lateFolder;evidence.mode.mineIntel.available.Insert(&originalFolder);evidence.Withdraw();
|
||||
@@ -175,4 +213,4 @@
|
||||
|
||||
}
|
||||
''')
|
||||
-print('PASS: actual engineer mine preparation/deadline, original custody/identity, once-only callback removal, cancellation quarantine, withdrawal/clearance, native refusal and owned-action cleanup; native execution untested')
|
||||
+print('PASS: actual engineer native group-envelope admission and phase cancellation, preparation/deadline, original custody/identity, once-only callback removal, cancellation quarantine, withdrawal/clearance, native refusal and owned-action cleanup; native execution untested')
|
||||
@@ -0,0 +1 @@
|
||||
PASS: actual engineer native group-envelope admission and phase cancellation, preparation/deadline, original custody/identity, once-only callback removal, cancellation quarantine, withdrawal/clearance, native refusal and owned-action cleanup; native execution untested
|
||||
@@ -0,0 +1,55 @@
|
||||
from pathlib import Path
|
||||
r=Path('/home/jakub/devel/escapistsrereintroduced')
|
||||
o=Path('/tmp/erri-mine-zones-tests-0558')
|
||||
s=(r/'tests/test_engineer_mine.py').read_text()
|
||||
s=s.replace("'ERR_GameMode','ERR_HQUnit'", "'SCR_AIGroupUtilityComponent','ERR_GameMode','ERR_HQUnit'")
|
||||
s=s.replace("'m_Mode','m_Unit'", "'groupUtility','m_Mode','m_Unit'")
|
||||
old='struct SCR_AIGroup {bool slave=false;int players=0;Faction* faction=nullptr;bool IsSlave(){return slave;}int GetPlayerCount(bool){return players;}Faction* GetFaction(){return faction;}};'
|
||||
new='''// Native group movement envelope boundary, not navigation/pathfinding.
|
||||
struct AIWaypoint {virtual ~AIWaypoint()=default;};
|
||||
struct SCR_DefendWaypoint:AIWaypoint {vector origin;float radius=30;vector GetOrigin(){return origin;}float GetCompletionRadius(){return radius;}static SCR_DefendWaypoint* Cast(AIWaypoint* p){return dynamic_cast<SCR_DefendWaypoint*>(p);}};
|
||||
struct SCR_AIGroupUtilityComponent;
|
||||
struct SCR_AIGroup {bool slave=false;int players=0;Faction* faction=nullptr;SCR_AIGroupUtilityComponent* utility=nullptr;AIWaypoint* waypoint=nullptr;vector center;
|
||||
bool IsSlave(){return slave;}int GetPlayerCount(bool){return players;}Faction* GetFaction(){return faction;}SCR_AIGroupUtilityComponent* GetGroupUtilityComponent(){return utility;}AIWaypoint* GetCurrentWaypoint(){return waypoint;}vector GetCenterOfMass(){return center;}};
|
||||
struct SCR_AIGroupUtilityComponent {SCR_AIGroup* m_Owner=nullptr;float m_fMaxAutonomousDistance=100;
|
||||
// Matches installed SCR_AIGroupUtilityComponent.IsPositionAllowed semantics.
|
||||
bool IsPositionAllowed(vector pos){auto wp=m_Owner->GetCurrentWaypoint();auto defendWp=SCR_DefendWaypoint::Cast(wp);if(defendWp)return vector::Distance(defendWp->GetOrigin(),pos)<defendWp->GetCompletionRadius();return vector::Distance(m_Owner->GetCenterOfMass(),pos)<m_fMaxAutonomousDistance;}
|
||||
};'''
|
||||
assert old in s;s=s.replace(old,new)
|
||||
s=s.replace('SCR_AIGroup group;SCR_AIUtilityComponent utility;', 'SCR_AIGroup group;SCR_AIGroupUtilityComponent groupUtility;SCR_AIUtilityComponent utility;')
|
||||
s=s.replace('group.faction=&faction;actor.group=', 'group.faction=&faction;group.utility=&groupUtility;groupUtility.m_Owner=&group;actor.group=')
|
||||
needle='int main(){\n'
|
||||
extra='''int main(){
|
||||
// Current native defend radius is strict and three dimensional: the broad
|
||||
// 25..60 m mission band does not authorize bypassing the group's own envelope.
|
||||
for(int fault=0;fault<4;fault++){Fixture f;SCR_DefendWaypoint defend;f.group.waypoint=&defend;vector point={30,0,0};
|
||||
if(fault==0)f.group.utility=nullptr;
|
||||
if(fault==2)point={25,17,0};
|
||||
if(fault==3){f.group.waypoint=nullptr;f.groupUtility.m_fMaxAutonomousDistance=30;}
|
||||
assert(!f.controller.Begin(&f.mode,&f.unit,&f.task,point,1000));
|
||||
assert(f.controller.Finished()&&f.attempted.empty()&&!f.utility.additions&&!f.inventory.calls&&!f.trigger.calls&&!f.mode.mineIntel.candidates);
|
||||
}
|
||||
for(int boundary=0;boundary<3;boundary++){Fixture f;SCR_DefendWaypoint defend;f.group.waypoint=&defend;vector point={29.999f,0,0};
|
||||
if(boundary==1)point={25,16,0};
|
||||
if(boundary==2){f.group.waypoint=nullptr;f.group.center={1,0,0};f.groupUtility.m_fMaxAutonomousDistance=30;point={30,0,0};}
|
||||
assert(f.controller.Begin(&f.mode,&f.unit,&f.task,point,1000));assert(f.attempted.Count()==1&&f.utility.additions==1);
|
||||
}
|
||||
// Revalidate the current utility and its current waypoint at every phase.
|
||||
// Cancellation completes only our exact action and never resumes after a late
|
||||
// inventory acknowledgement or a later enlargement of the movement envelope.
|
||||
for(int phase=0;phase<4;phase++)for(int replacement=0;replacement<3;replacement++){Fixture f;
|
||||
if(phase==3)f.Withdraw();else if(phase==2)f.Prepare();else{f.Begin();if(phase==1){f.actor.position={30,0,0};f.controller.Tick(2000);}}
|
||||
auto own=f.controller.m_Action;SCR_AIBehaviorBase foreign;f.utility.actions.Insert(&foreign);
|
||||
auto callback=f.inventory.callback;int calls=f.inventory.calls,additions=f.utility.additions,moves=f.mine.moves;
|
||||
SCR_DefendWaypoint defend;defend.radius=29;SCR_AIGroupUtilityComponent newUtility;newUtility.m_Owner=&f.group;newUtility.m_fMaxAutonomousDistance=29;
|
||||
if(replacement==0)f.group.waypoint=&defend;else if(replacement==1)f.group.utility=&newUtility;else f.group.utility=nullptr;
|
||||
f.controller.Tick(13000);
|
||||
assert(f.controller.Finished()&&own->completed==1&&!foreign.completed&&f.attempted.Count()==1);
|
||||
assert(f.inventory.calls==calls&&f.utility.additions==additions&&f.mine.moves==moves&&!f.trigger.calls&&!f.mode.mineIntel.seals);
|
||||
f.group.utility=&f.groupUtility;f.group.waypoint=nullptr;f.Drop();if(callback)callback->OnComplete();f.actor.position={0,0,0};f.controller.Tick(14000);
|
||||
assert(f.controller.Finished()&&own->completed==1&&!foreign.completed&&f.inventory.calls==calls&&f.utility.additions==additions&&f.mine.moves==moves&&!f.trigger.calls);
|
||||
}
|
||||
'''
|
||||
assert needle in s;s=s.replace(needle,extra,1)
|
||||
s=s.replace('PASS: actual engineer mine preparation/deadline,', 'PASS: actual engineer native group-envelope admission and phase cancellation, preparation/deadline,')
|
||||
(o/'tests/test_engineer_mine.py').write_text(s)
|
||||
@@ -0,0 +1,42 @@
|
||||
{
|
||||
"status": "pass",
|
||||
"source_sha256": "fe05cb6e813155d76fd497788aa92c9dd8c7cf4ec43e017172a8a70e16c00b80",
|
||||
"test_sha256": "244ab49155000e5939a6c9d9e8f01fe8b14115119d548ba423ceffdd33ca9946",
|
||||
"test_baseline_sha256": "3ffd360652ba66d4bb96247496e9b34175cc35c4e5d665f6524cb1cbd563bb73",
|
||||
"patch_sha256": "1cd1a18b717a1ddbbb4a9c02e0ea861362699d923c58d362229e5641c3f1d0a0",
|
||||
"results": [
|
||||
{
|
||||
"name": "baseline-red",
|
||||
"exit_code": 1,
|
||||
"source_sha256": "e0098577626e719283cf4b40936e7ec038076c4bab9269fbad0b5ad3292e01e3",
|
||||
"log_sha256": "54bc0e8af18842678db6ec75da66b517ccfff38935035a6aa15c1cb26edc01a6",
|
||||
"compiled": true
|
||||
},
|
||||
{
|
||||
"name": "continuation-mutation-red",
|
||||
"exit_code": 1,
|
||||
"source_sha256": "9eefcddf8ff43da07d1d1535461ce48457f0eba3d8e24e560a5b07d927c8a89b",
|
||||
"log_sha256": "3b32e9ac6cf833a3675139681febb25ed02da7963ab2bf0aa0a7de581b040a97",
|
||||
"compiled": true
|
||||
},
|
||||
{
|
||||
"name": "green",
|
||||
"exit_code": 0,
|
||||
"source_sha256": "fe05cb6e813155d76fd497788aa92c9dd8c7cf4ec43e017172a8a70e16c00b80",
|
||||
"log_sha256": "42ed037cc22a9224478449736d1f43e57cc89fa06ddc7e0f09f37771f3ca0b2a",
|
||||
"compiled": true
|
||||
}
|
||||
],
|
||||
"coverage": [
|
||||
"Missing group utility and strict 30m equality refuse before attempted-item insert, intel capture, action creation or inventory removal.",
|
||||
"3D native defend envelope rejects x25/y17 but accepts x25/y16; x29.999 accepted. Autonomous envelope uses current group center and strict radius.",
|
||||
"12 continuation cases: all four controller phases times changed defend waypoint, replacement denying utility, or missing utility. Exact owned action completed once; unrelated action untouched.",
|
||||
"Reopened envelope and late callback cannot resume or arm. Item tombstone retained. Existing entire harness remains, including fixed180s deadline,10s continuous preparation,256-item quarantine, custody, native refusal and20m clearance."
|
||||
],
|
||||
"boundary": "Group utility is a native boundary double matching installed SCR_AIGroupUtilityComponent.IsPositionAllowed lines917 onward. Actual production Begin,Owned,Tick,Stop and related methods are extracted unchanged apart from existing C++ syntax adaptation. This is the native group movement envelope, not navmesh or general forbidden-zone proof.",
|
||||
"limits": [
|
||||
"No native or Enforce compilation.",
|
||||
"No target/original writes, no full suite."
|
||||
],
|
||||
"all_compilers_finished": true
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
from pathlib import Path
|
||||
import subprocess,os,json,hashlib,difflib
|
||||
r=Path('/home/jakub/devel/escapistsrereintroduced');o=Path('/tmp/erri-mine-zones-tests-0558');a=Path('/tmp/erri-base-review-0558');rel='addons/core/Scripts/Game/ERR/10_AI/ERR_EngineerMine.c';p=a/rel
|
||||
s=p.read_text();old='if (!groupUtility || !groupUtility.IsPositionAllowed(m_Position)) return false;';assert old in s
|
||||
mutation=o/'begin-only.c';mutation.write_text(s.replace(old,'if (m_Started < 0 && (!groupUtility || !groupUtility.IsPositionAllowed(m_Position))) return false;',1))
|
||||
env=dict(os.environ,PYTHONPATH=str(r/'tests'),TMPDIR=str(o/'scratch'))
|
||||
results=[]
|
||||
for name,source,expected in [('baseline-red',a/'baseline'/rel,False),('continuation-mutation-red',mutation,False),('green',p,True)]:
|
||||
env['ERR_ENGINEER_MINE_SOURCE']=str(source)
|
||||
with (o/(name+'.log')).open('w') as f: proc=subprocess.run(['python3',str(o/'tests/test_engineer_mine.py')],env=env,stdout=f,stderr=subprocess.STDOUT)
|
||||
log=(o/(name+'.log')).read_text();assert (proc.returncode==0)==expected,(name,log)
|
||||
if not expected: assert 'Assertion' in log and 'failed.' in log and 'g++' not in log,(name,log)
|
||||
results.append({'name':name,'exit_code':proc.returncode,'source_sha256':hashlib.sha256(source.read_bytes()).hexdigest(),'log_sha256':hashlib.sha256((o/(name+'.log')).read_bytes()).hexdigest(),'compiled':True})
|
||||
before=(r/'tests/test_engineer_mine.py').read_text();after=(o/'tests/test_engineer_mine.py').read_text();patch=''.join(difflib.unified_diff(before.splitlines(True),after.splitlines(True),fromfile='a/tests/test_engineer_mine.py',tofile='b/tests/test_engineer_mine.py'));(o/'fix.patch').write_text(patch)
|
||||
review={'status':'pass','source_sha256':hashlib.sha256(p.read_bytes()).hexdigest(),'test_sha256':hashlib.sha256((o/'tests/test_engineer_mine.py').read_bytes()).hexdigest(),'test_baseline_sha256':hashlib.sha256((r/'tests/test_engineer_mine.py').read_bytes()).hexdigest(),'patch_sha256':hashlib.sha256((o/'fix.patch').read_bytes()).hexdigest(),'results':results,'coverage':['Missing group utility and strict 30m equality refuse before attempted-item insert, intel capture, action creation or inventory removal.','3D native defend envelope rejects x25/y17 but accepts x25/y16; x29.999 accepted. Autonomous envelope uses current group center and strict radius.','12 continuation cases: all four controller phases times changed defend waypoint, replacement denying utility, or missing utility. Exact owned action completed once; unrelated action untouched.','Reopened envelope and late callback cannot resume or arm. Item tombstone retained. Existing entire harness remains, including fixed180s deadline,10s continuous preparation,256-item quarantine, custody, native refusal and20m clearance.'],'boundary':'Group utility is a native boundary double matching installed SCR_AIGroupUtilityComponent.IsPositionAllowed lines917 onward. Actual production Begin,Owned,Tick,Stop and related methods are extracted unchanged apart from existing C++ syntax adaptation. This is the native group movement envelope, not navmesh or general forbidden-zone proof.','limits':['No native or Enforce compilation.','No target/original writes, no full suite.'],'all_compilers_finished':True}
|
||||
(o/'review.json').write_text(json.dumps(review,indent=2)+'\n');print(json.dumps(review,indent=2))
|
||||
Reference in New Issue
Block a user