102 lines
4.2 KiB
C
102 lines
4.2 KiB
C
#ifdef WORKBENCH
|
|
// Inject continuous horn demand into two fixture-owned AI drivers, then observe
|
|
// the actual production OnApplyControls chain. No human input is generated.
|
|
class ERR_HornFixtureDriver
|
|
{
|
|
IEntity Driver;
|
|
Vehicle Car;
|
|
SCR_AIGroup Group;
|
|
int Started = -1;
|
|
int Allowed;
|
|
int Blocked;
|
|
int Violations;
|
|
}
|
|
class ERR_HornFixture
|
|
{
|
|
static ref array<ref ERR_HornFixtureDriver> Drivers = {};
|
|
static ERR_HornFixtureDriver Find(IEntity actor)
|
|
{
|
|
foreach (ERR_HornFixtureDriver driver : Drivers) if (driver.Driver == actor) return driver;
|
|
return null;
|
|
}
|
|
}
|
|
modded class SCR_CharacterControllerComponent
|
|
{
|
|
protected override void OnApplyControls(IEntity owner, float timeSlice)
|
|
{
|
|
ERR_HornFixtureDriver fixture = ERR_HornFixture.Find(owner);
|
|
CharacterInputContext input = GetInputContext();
|
|
bool seated = fixture && CompartmentAccessComponent.GetVehicleIn(owner) == fixture.Car;
|
|
if (seated && input) input.SetVehicleHorn(1);
|
|
super.OnApplyControls(owner, timeSlice);
|
|
if (!seated || !input) return;
|
|
int now = System.GetTickCount();
|
|
if (fixture.Started < 0) fixture.Started = now;
|
|
int elapsed = now - fixture.Started;
|
|
bool sounding = input.GetVehicleHorn() != 0;
|
|
if (sounding) fixture.Allowed++; else fixture.Blocked++;
|
|
if (sounding && elapsed >= 600 && elapsed < 29900) fixture.Violations++;
|
|
}
|
|
}
|
|
modded class ERR_GameMode
|
|
{
|
|
protected bool m_ERRHornSpawned;
|
|
protected int m_ERRHornDeadline;
|
|
protected override void EOnInit(IEntity owner)
|
|
{
|
|
super.EOnInit(owner);
|
|
if (Replication.IsServer() && !SCR_Global.IsEditMode()) GetGame().GetCallqueue().CallLater(ERR_HornTest, 500, true);
|
|
}
|
|
protected void ERR_HornTest()
|
|
{
|
|
if (!Active()) return;
|
|
SCR_PlayerController player = SCR_PlayerController.Cast(GetGame().GetPlayerController());
|
|
if (!player || !player.GetControlledEntity()) return;
|
|
if (!m_ERRHornSpawned)
|
|
{
|
|
m_ERRHornSpawned = true; m_ERRHornDeadline = System.GetTickCount() + 60000;
|
|
for (int i = 0; i < 2; i++)
|
|
{
|
|
ERR_HornFixtureDriver driver = new ERR_HornFixtureDriver();
|
|
vector position = ERR_Actors.Ground(player.GetControlledEntity().GetOrigin() + Vector(30 + i * 15, 0, 0));
|
|
ResourceName prefab = ERR_CivilianTraffic.CarPrefab(0);
|
|
if (i == 1) prefab = ERR_ConvoyResources.VehiclePrefab(0);
|
|
driver.Car = Vehicle.Cast(ERR_Actors.Spawn(prefab, position));
|
|
driver.Group = SCR_AIGroup.Cast(ERR_Actors.Spawn(ERR_ConvoyResources.GroupPrefab(), position));
|
|
if (!driver.Car || !driver.Group) { Print("ERR SMOKE FAIL: horn vehicle/group creation", LogLevel.ERROR); return; }
|
|
driver.Group.SetPermanentLOD(0); driver.Group.ActivateAI();
|
|
ERR_HornFixture.Drivers.Insert(driver);
|
|
}
|
|
return;
|
|
}
|
|
bool ready = true;
|
|
foreach (ERR_HornFixtureDriver driver : ERR_HornFixture.Drivers)
|
|
{
|
|
// Vehicle compartments are registered asynchronously after spawning.
|
|
if (!driver.Driver)
|
|
{
|
|
BaseVehicleControllerComponent controls = BaseVehicleControllerComponent.Cast(driver.Car.FindComponent(BaseVehicleControllerComponent));
|
|
if (controls && controls.GetPilotCompartmentSlot())
|
|
{
|
|
AIGroup group = driver.Group;
|
|
driver.Driver = controls.GetPilotCompartmentSlot().SpawnCharacterInCompartment(ERR_CivilianTraffic.DriverPrefab(), group, ERR_ConvoyResources.GroupPrefab());
|
|
}
|
|
}
|
|
array<AIAgent> agents = {}; driver.Group.GetAgents(agents);
|
|
foreach (AIAgent agent : agents) { agent.SetPermanentLOD(0); agent.ActivateAI(); }
|
|
if (driver.Started < 0 || System.GetTickCount() - driver.Started < 32000) ready = false;
|
|
}
|
|
if (!ready && System.GetTickCount() < m_ERRHornDeadline) return;
|
|
GetGame().GetCallqueue().Remove(ERR_HornTest);
|
|
foreach (ERR_HornFixtureDriver driver : ERR_HornFixture.Drivers)
|
|
{
|
|
PrintFormat("ERR HORN RESULT: prefab=%1 allowedFrames=%2 blockedFrames=%3 violations=%4", driver.Car.GetPrefabData().GetPrefabName(), driver.Allowed, driver.Blocked, driver.Violations);
|
|
if (!ready || driver.Allowed == 0 || driver.Blocked == 0 || driver.Violations != 0) { Print("ERR SMOKE FAIL: native AI horn limit", LogLevel.ERROR); return; }
|
|
Print("ERR SMOKE PASS: native AI driver continuous horn demand bounded with cooldown");
|
|
}
|
|
ERR_HornFixture.Drivers.Clear();
|
|
Print("ERR SMOKE COMPLETE: native UAZ and civilian AI horn input limits");
|
|
}
|
|
}
|
|
#endif
|