Files
EscapistsReintroduced/docs/evidence/mounted-pair-2026-10-03/service/build.py
T
jakub 6a667d8deb Capture current mission, AI, map and administration development
Include the current addon, terrain integrations, tools, regression tests and recorded development evidence.
2026-10-13 22:52:53 +02:00

84 lines
6.3 KiB
Python

from pathlib import Path
import subprocess,hashlib,json
root=Path('/home/jakub/devel/escapistsrereintroduced'); out=Path('/tmp/erri-pair-service-0054'); rel='addons/core/Scripts/Game/ERR/10_AI/ERR_ConvoyService.c'
s=(root/rel).read_text(); p=out/rel;p.parent.mkdir(parents=True,exist_ok=True)
b=out/'baseline'/rel;b.parent.mkdir(parents=True,exist_ok=True);b.write_text(s)
idx=subprocess.run(['git','show',':'+rel],cwd=root,capture_output=True,check=True).stdout
(out/'baseline.json').write_text(json.dumps({'path':rel,'working_sha256':hashlib.sha256(s.encode()).hexdigest(),'index_sha256':hashlib.sha256(idx).hexdigest()},indent=2)+'\n')
needle=' bool DeliverIntercept(ERR_GameMode mode, ERR_ConvoyInterceptOrder order, float now)'
insert=''' // Pair preparation owns no route state. Recheck after both native allocations.
bool CanInstallIntercept(ERR_GameMode mode, ERR_ConvoyInterceptOrder order, float now)
{
if (!InterceptMatches(order) || order.Token != m_InterceptToken || InterceptActive || !InterceptCrew(mode)) return false;
return order.Position == m_InterceptPosition && order.ExpiresAt == m_InterceptExpiresAt && now < m_InterceptExpiresAt;
}
// Caller transfers ownership of the prepared handle before AddWaypoint, which
// is a native boundary rather than a transactional pair operation.
void InstallIntercept(AIWaypoint detour)
{
ClearOrder(); m_InterceptRouteIndex = RouteIndex;
m_InterceptWaypoint = detour; InterceptWaypoint = detour; InterceptActive = true;
Group.AddWaypoint(detour);
}
'''
assert needle in s;s=s.replace(needle,insert+needle,1)
needle=' bool ApplyIntercept(ERR_ConvoyTask task, ERR_ConvoyInterceptOrder order, float now)'
insert=''' protected bool InterceptPairEligible(ERR_ConvoyTask task, ERR_ConvoyInterceptOrder first, ERR_ConvoyInterceptOrder second, float now)
{
if (!first || !second || first == second || first.Group == second.Group || first.VehicleIndex == second.VehicleIndex || first.Token == second.Token) return false;
if (!InterceptEligible(task, first) || !InterceptEligible(task, second) || !ERR_ForceRules.Finite(now) || now < 0) return false;
if (task.Vehicles[first.VehicleIndex].Entity == task.Vehicles[second.VehicleIndex].Entity) return false;
if (first.BeliefId <= 0 || first.BeliefRevision <= 0 || first.ReportId <= 0) return false;
if (first.BeliefId != second.BeliefId || first.BeliefRevision != second.BeliefRevision || first.ReportId != second.ReportId) return false;
if (first.ObservedAt != second.ObservedAt || first.IssuedAt != second.IssuedAt || first.ExpiresAt != second.ExpiresAt) return false;
if (!ERR_ForceRules.Finite(first.ObservedAt) || !ERR_ForceRules.Finite(first.IssuedAt) || !ERR_ForceRules.Finite(first.ExpiresAt)) return false;
if (first.ObservedAt < 0 || first.IssuedAt < first.ObservedAt || now < first.IssuedAt || now >= first.ExpiresAt || first.ExpiresAt > first.ObservedAt + 120000) return false;
if (!ERR_ForceRules.FiniteVector(first.Position) || !ERR_ForceRules.FiniteVector(second.Position)) return false;
return vector.DistanceXZ(first.Position, second.Position) >= 40;
}
bool ReserveInterceptPair(ERR_ConvoyTask task, ERR_ConvoyInterceptOrder first, ERR_ConvoyInterceptOrder second, float now)
{
if (!InterceptPairEligible(task, first, second, now)) return false;
foreach (ERR_ConvoyTask existing : m_Tasks)
foreach (ERR_ConvoyVehicle claimed : existing.Vehicles) if (claimed && claimed.InterceptToken != 0) return false;
ERR_ConvoyVehicle lead = task.Vehicles[first.VehicleIndex];
ERR_ConvoyVehicle partner = task.Vehicles[second.VehicleIndex];
if (!lead.ClaimIntercept(m_Mode, first)) return false;
lead.InterceptReceipt = task.Receipt; lead.InterceptRecord = m_Mode.Forces().FindGroup(lead.Group); lead.InterceptRoute = task.Route;
if (!InterceptPairEligible(task, first, second, now) || !partner.ClaimIntercept(m_Mode, second))
{ lead.ClearIntercept(first); return false; }
partner.InterceptReceipt = task.Receipt; partner.InterceptRecord = m_Mode.Forces().FindGroup(partner.Group); partner.InterceptRoute = task.Route;
return true;
}
bool ApplyInterceptPair(ERR_ConvoyTask task, ERR_ConvoyInterceptOrder first, ERR_ConvoyInterceptOrder second, float now)
{
if (!InterceptPairEligible(task, first, second, now) || !InterceptCurrent(task, first) || !InterceptCurrent(task, second)) return false;
ERR_ConvoyVehicle lead = task.Vehicles[first.VehicleIndex];
ERR_ConvoyVehicle partner = task.Vehicles[second.VehicleIndex];
if (!lead.CanInstallIntercept(m_Mode, first, now) || !partner.CanInstallIntercept(m_Mode, second, now)) return false;
AIWaypoint firstWaypoint = AIWaypoint.Cast(ERR_Actors.Spawn(ERR_Resources.MoveWaypoint(), first.Position));
if (!firstWaypoint) return false;
AIWaypoint secondWaypoint = AIWaypoint.Cast(ERR_Actors.Spawn(ERR_Resources.MoveWaypoint(), second.Position));
if (!secondWaypoint) { SCR_EntityHelper.DeleteEntityAndChildren(firstWaypoint); return false; }
firstWaypoint.SetCompletionRadius(15); secondWaypoint.SetCompletionRadius(15);
if (!InterceptPairEligible(task, first, second, now) || !InterceptCurrent(task, first) || !InterceptCurrent(task, second)
|| task.Vehicles[first.VehicleIndex] != lead || task.Vehicles[second.VehicleIndex] != partner
|| !lead.CanInstallIntercept(m_Mode, first, now) || !partner.CanInstallIntercept(m_Mode, second, now))
{ SCR_EntityHelper.DeleteEntityAndChildren(firstWaypoint); SCR_EntityHelper.DeleteEntityAndChildren(secondWaypoint); return false; }
lead.InstallIntercept(firstWaypoint);
// AddWaypoint can invoke native listeners. Do not install the partner after
// cancellation/ownership loss; release only these exact owned claims.
if (!InterceptPairEligible(task, first, second, now) || !InterceptCurrent(task, first) || !lead.InterceptActive
|| !InterceptCurrent(task, second) || !partner.CanInstallIntercept(m_Mode, second, now))
{
SCR_EntityHelper.DeleteEntityAndChildren(secondWaypoint);
ReleaseIntercept(task, first, now); ReleaseIntercept(task, second, now); return false;
}
partner.InstallIntercept(secondWaypoint);
if (InterceptPairEligible(task, first, second, now) && InterceptCurrent(task, first) && InterceptCurrent(task, second)
&& lead.InterceptActive && partner.InterceptActive) return true;
ReleaseIntercept(task, first, now); ReleaseIntercept(task, second, now); return false;
}
'''
assert needle in s;s=s.replace(needle,insert+needle,1);p.write_text(s)