#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 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 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