Include the current addon, terrain integrations, tools, regression tests and recorded development evidence.
52 lines
3.7 KiB
Python
52 lines
3.7 KiB
Python
from pathlib import Path
|
|
import hashlib,json,subprocess
|
|
r=Path('/home/jakub/devel/escapistsrereintroduced');p=Path('/tmp/erri-hunter-capture-2237')
|
|
files=['addons/core/Scripts/Game/ERR/10_AI/ERR_ConvoyService.c','addons/core/Scripts/Game/ERR/10_AI/ERR_HunterService.c','tests/test_hunter_lifecycle.py','tests/test_convoy_survivors.py']
|
|
b={}
|
|
for f in files:
|
|
d=(r/f).read_bytes();t=p/f;t.parent.mkdir(parents=True,exist_ok=True);t.write_bytes(d);s=p/'baseline'/f;s.parent.mkdir(parents=True,exist_ok=True);s.write_bytes(d)
|
|
q=subprocess.run(['git','show',':'+f],cwd=r,capture_output=True);b[f]={'working':hashlib.sha256(d).hexdigest(),'index':hashlib.sha256(q.stdout).hexdigest() if q.returncode==0 else None}
|
|
(p/'baseline.json').write_text(json.dumps(b,indent=2)+'\n')
|
|
f=p/files[0];s=f.read_text().replace(' bool Registered;',' bool Registered;\n // Latched only for an exact tracked hunter at authoritative player entry.\n bool PlayerCaptureObserved;',1).replace('if (Registered && hq && !ERR_ConvoyRules.Captured(Entity, Group))','if (Registered && !PlayerCaptureObserved && hq && !ERR_ConvoyRules.Captured(Entity, Group))',1);f.write_text(s)
|
|
f=p/files[1];s=f.read_text().replace('if (!mode || !mode.Active() || ERR_ConvoyRules.Captured(Entity, Group)) { super.Release(mode); return; }','if (PlayerCaptureObserved || !mode || !mode.Active() || ERR_ConvoyRules.Captured(Entity, Group)) { Downlink = null; super.Release(mode); return; }',1)
|
|
method=''' // Entry is an ownership event, not a later occupancy sample. Keep the fact
|
|
// even if the player exits/disconnects before the one-second hunter tick.
|
|
void PlayerEntered(IEntity actor, IEntity entered)
|
|
{
|
|
if (!Replication.IsServer() || m_Stopped || !m_Mode || m_Mode != ERR_GameMode.Get()) return;
|
|
if (!m_Mode.Active() || !actor || !entered || !m_Mode.Players()) return;
|
|
ERR_HQ hq = ERR_HQ.Cast(m_Mode.Command());
|
|
if (!hq || hq.Hunters() != this || !m_Mode.Players().CurrentActor(actor)) return;
|
|
if (m_Hunters.Count() > 15) return;
|
|
foreach (ERR_HunterVehicle unit : m_Hunters)
|
|
{
|
|
// Released survivors already have independent HQ ownership. Do not revoke
|
|
// their infantry role just because the abandoned original vehicle is entered.
|
|
if (!unit || unit.Released || !unit.Entity || !ERR_ConvoyRules.PartOf(entered, unit.Entity)) continue;
|
|
unit.PlayerCaptureObserved = true;
|
|
unit.Release(m_Mode);
|
|
}
|
|
}
|
|
'''
|
|
pos=s.index(' protected bool PrepareVehicleRadio(');s=s[:pos]+method+s[pos:]
|
|
s+='''
|
|
// Match the original hunter before native callbacks can erase current player
|
|
// occupancy. Other vehicles and already-released crews are not adopted here.
|
|
modded class SCR_CompartmentAccessComponent
|
|
{
|
|
override protected void OnCompartmentEntered(IEntity targetEntity, BaseCompartmentManagerComponent manager, int mgrID, int slotID, bool move)
|
|
{
|
|
if (Replication.IsServer())
|
|
{
|
|
ERR_GameMode mode = ERR_GameMode.Get();
|
|
ERR_HQ hq;
|
|
if (mode) hq = ERR_HQ.Cast(mode.Command());
|
|
if (hq && hq.Hunters()) hq.Hunters().PlayerEntered(GetOwner(), targetEntity);
|
|
}
|
|
super.OnCompartmentEntered(targetEntity, manager, mgrID, slotID, move);
|
|
}
|
|
}
|
|
''';f.write_text(s)
|
|
f=p/files[2];s=f.read_text().replace('from policy_harness import ROOT, body, run','import os\nfrom pathlib import Path\nfrom policy_harness import ROOT, body, run').replace("source=ROOT/'addons/core/Scripts/Game/ERR/10_AI/ERR_HunterService.c'","source=Path(os.environ.get('ERR_HUNTER_SOURCE',ROOT/'addons/core/Scripts/Game/ERR/10_AI/ERR_HunterService.c'))").replace('bool Released=false;','bool Released=false,PlayerCaptureObserved=false;');f.write_text(s)
|
|
f=p/files[3];f.write_text(f.read_text().replace('bool Released=false,Registered=true;','bool Released=false,Registered=true,PlayerCaptureObserved=false;'))
|