Include the current addon, terrain integrations, tools, regression tests and recorded development evidence.
84 lines
6.3 KiB
Python
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)
|