using ColossalFramework.Math;
using System.Collections.Generic;
using TrafficManager.Manager;
using TrafficManager.Traffic;
namespace AvoidCongestion
public class AvoidCongestionAI : ThreadingExtensionBase
private const float HIGHWAY_SPEED = 100f;
private const float HIGHWAY_LENGTH = 1000f;
private const float HIGHWAY_ANGLE = 30f;
private const float RAMP_SPEED = 60f;
private const float RAMP_LENGTH = 200f;
private const float RAMP_ANGLE = 45f;
private const float ELEVATED_SPEED = 80f;
private const float ELEVATED_LENGTH = 500f;
private const float ELEVATED_ANGLE = 30f;
private const float DISTRICT_RADIUS = 500f;
private const int COMMERCIAL_DENSITY = 80;
private const int RESIDENTIAL_DENSITY = 60;
private const int INDUSTRIAL_DENSITY = 40;
private NetManager netManager;
private DistrictManager districtManager;
private TrafficManagerMod trafficManagerMod;
private Dictionary<ushort, RoadType> roadTypes;
public override void OnCreated(IThreading threading)
base.OnCreated(threading);
netManager = Singleton<NetManager>.instance;
districtManager = Singleton<DistrictManager>.instance;
trafficManagerMod = TrafficManagerMod.Instance;
roadTypes = new Dictionary<ushort, RoadType>();
public override void OnUpdate(float realTimeDelta, float simulationTimeDelta)
base.OnUpdate(realTimeDelta, simulationTimeDelta);
if (Input.GetKeyDown(KeyCode.F1))
SetJunctionRestrictions();
private void FindRoadTypes()
for (ushort segmentId = 0; segmentId < NetManager.MAX_SEGMENT_COUNT; segmentId++)
if (netManager.m_segments.m_buffer[segmentId].m_flags == NetSegment.Flags.None) continue;
if (netManager.m_segments.m_buffer[segmentId].Info.m_netAI is RoadBaseAI)
RoadBaseAI roadAI = netManager.m_segments.m_buffer[segmentId].Info.m_netAI as RoadBaseAI;
if (roadAI.m_highwayRules)
if (roadAI.m_enableZoning)
roadTypes.Add(segmentId, RoadType.Ramp);
roadTypes.Add(segmentId, RoadType.Highway);
else if (netManager.m_segments.m_buffer[segmentId].Info.m_netAI is RoadBridgeAI)
RoadBridgeAI bridgeAI = netManager.m_segments.m_buffer[segmentId].Info.m_netAI as RoadBridgeAI;
if (!bridgeAI.m_highwayRules && !bridgeAI.m_enableZoning)
roadTypes.Add(segmentId, RoadType.Elevated);
private void SetSpeedLimits()
foreach (var pair in roadTypes)
ushort segmentId = pair.Key;
RoadType roadType = pair.Value;
SpeedLimitManager.Instance.SetSpeedLimit(segmentId, HIGHWAY_SPEED);
SpeedLimitManager.Instance.SetSpeedLimit(segmentId, RAMP_SPEED);
SpeedLimitManager.Instance.SetSpeedLimit(segmentId, ELEVATED_SPEED);
private void SetLaneArrows()
foreach (var pair in roadTypes)
ushort segmentId = pair.Key;
RoadType roadType = pair.Value;
int laneCount = netManager.m_segments.m_buffer[segmentId].Info.m_lanes.Length;
for (int laneIndex = 0; laneIndex < laneCount; laneIndex++)
uint laneId = netManager.m_segments.m_buffer[segmentId].m_lanes[laneIndex];
if (laneId == 0) continue;
if (laneIndex == 0 || laneIndex == laneCount - 1)
LaneArrowManager.Instance.SetLaneArrows(laneId, LaneArrows.Left | LaneArrows.Forward | LaneArrows.Right);
LaneArrowManager.Instance.SetLaneArrows(laneId, LaneArrows.Forward);
if (netManager.m_segments.m_buffer[segmentId].m_startNode == netManager.m_lanes.m_buffer[laneId].m_nodes[0])
LaneArrowManager.Instance.SetLaneArrows(laneId, LaneArrows.Left | LaneArrows.Right);
LaneArrowManager.Instance.SetLaneArrows(laneId, LaneArrows.Merge);
if (laneIndex == 0 || laneIndex == laneCount - 1)
LaneArrowManager.Instance.SetLaneArrows(laneId, LaneArrows.Left | LaneArrows.Forward | LaneArrows.Right);
LaneArrowManager.Instance.SetLaneArrows(laneId, LaneArrows.Forward);
private void SetTrafficLights()
foreach (var pair in roadTypes)
ushort segmentId = pair.Key;
RoadType roadType = pair.Value;
ushort startNodeId = netManager.m_segments.m_buffer[segmentId].m_startNode;
ushort endNodeId = netManager.m_segments.m_buffer[segmentId].m_endNode;
TrafficLightManager.Instance.RemoveTrafficLight(startNodeId, segmentId);
TrafficLightManager.Instance.RemoveTrafficLight(endNodeId, segmentId);
if (netManager.m_nodes.m_buffer[startNodeId].CountSegments() > 2)
TrafficLightManager.Instance.AddTrafficLight(startNodeId, segmentId);
TrafficLightManager.Instance.RemoveTrafficLight(startNodeId, private void SetTrafficLights()
foreach (var pair in roadTypes)
ushort segmentId = pair.Key;
RoadType roadType = pair.Value;
ushort startNodeId = netManager.m_segments.m_buffer[segmentId].m_startNode;
ushort endNodeId = netManager.m_segments.m_buffer[segmentId].m_endNode;
TrafficLightManager.Instance.RemoveTrafficLight(startNodeId, segmentId);
TrafficLightManager.Instance.RemoveTrafficLight(endNodeId, segmentId);
if (netManager.m_nodes.m_buffer[startNodeId].CountSegments() > 2)
TrafficLightManager.Instance.AddTrafficLight(startNodeId, segmentId);
TrafficLightManager.Instance.RemoveTrafficLight(startNodeId, segmentId);
if (netManager.m_nodes.m_buffer[endNodeId].CountSegments() > 2)
TrafficLightManager.Instance.AddTrafficLight(endNodeId, segmentId);
TrafficLightManager.Instance.RemoveTrafficLight(endNodeId, segmentId);
TrafficLightManager.Instance.RemoveTrafficLight(startNodeId, segmentId);
TrafficLightManager.Instance.RemoveTrafficLight(endNodeId, segmentId);
private void SetPrioritySigns()
foreach (var pair in roadTypes)
ushort segmentId = pair.Key;
RoadType roadType = pair.Value;
ushort startNodeId = netManager.m_segments.m_buffer[segmentId].m_startNode;
ushort endNodeId = netManager.m_segments.m_buffer[segmentId].m_endNode;
PriorityRoad.Signs signs = new PriorityRoad.Signs();
signs.mainSigns = PriorityRoad.PriorityType.Main;
signs.yieldSigns = PriorityRoad.PriorityType.None;
signs.stopSigns = PriorityRoad.PriorityType.None;
PriorityRoad.SetPriorityRoad(startNodeId, ref signs);
PriorityRoad.SetPriorityRoad(endNodeId, ref signs);
if (netManager.m_nodes.m_buffer[startNodeId].CountSegments() > 2)
PriorityRoad.Signs signs = new PriorityRoad.Signs();
signs.mainSigns = PriorityRoad.PriorityType.None;
signs.yieldSigns = PriorityRoad.PriorityType.Yield;
signs.stopSigns = PriorityRoad.PriorityType.None;
PriorityRoad.SetPriorityRoad(startNodeId, ref signs);
if (netManager.m_nodes.m_buffer[endNodeId].CountSegments() > 2)
PriorityRoad.Signs signs = new PriorityRoad.Signs();
signs.mainSigns = PriorityRoad.PriorityType.None;
signs.yieldSigns = PriorityRoad.PriorityType.Yield;
signs.stopSigns = PriorityRoad.PriorityType.None;
PriorityRoad.SetPriorityRoad(endNodeId, ref signs);
if (netManager.m_nodes.m_buffer[startNodeId].CountSegments() > 2)
PriorityRoad.Signs signs = new PriorityRoad.Signs();
signs.mainSigns = PriorityRoad.PriorityType.Main;
signs.yieldSigns = PriorityRoad.PriorityType.None;
signs.stopSigns = PriorityRoad.PriorityType.None;
PriorityRoad.SetPriorityRoad(startNodeId, ref signs);
if (netManager.m_nodes.m_buffer[endNodeId].CountSegments() > 2)
PriorityRoad.Signs signs = new PriorityRoad.Signs();
signs.mainSigns = PriorityRoad.PriorityType.Main;
signs.yieldSigns = PriorityRoad.PriorityType.None;
signs.stopSigns = PriorityRoad.PriorityType.None;
PriorityRoad.SetPriorityRoad(endNodeId, ref signs);
private void SetJunctionRestrictions()
foreach (var pair in roadTypes)
ushort segmentId = pair.Key;
RoadType roadType = pair.Value;
ushort startNodeId = netManager.m_segments.m_buffer[segmentId].m_startNode;
ushort endNodeId = netManager.m_segments.m_buffer[segmentId].m_endNode;
JunctionRestrictionsManager.Instance.SetUturnAllowed(startNodeId, segmentId, false);
JunctionRestrictionsManager.Instance.SetUturnAllowed(endNodeId, segmentId, false);
JunctionRestrictionsManager.Instance.SetEnterWhenBlockedAllowed(startNodeId, segmentId, true);
JunctionRestrictionsManager.Instance.SetEnterWhenBlockedAllowed(endNodeId, segmentId, true);
JunctionRestrictionsManager.Instance.SetUturnAllowed(startNodeId, segmentId, false);
JunctionRestrictionsManager.Instance.SetUturnAllowed(endNodeId, segmentId, false);
JunctionRestrictionsManager.Instance.SetEnterWhenBlockedAllowed(startNodeId, segmentId, true);
JunctionRestrictionsManager.Instance.SetEnterWhenBlockedAllowed(endNodeId, segmentId, true);
JunctionRestrictionsManager.Instance.SetUturnAllowed(startNodeId, segmentId, false);
JunctionRestrictionsManager.Instance.SetUturnAllowed(endNodeId, segmentId, false);
JunctionRestrictionsManager.Instance.SetEnterWhenBlockedAllowed(startNodeId, segmentId, true);
JunctionRestrictionsManager.Instance.SetEnterWhenBlockedAllowed(endNodeId, segmentId, true);
private void DebugOutput()
if (Input.GetKeyDown(KeyCode.F2))
Debug.Log("高速公路数量:" + roadTypes.Count(x => x.Value == RoadType.Highway));
Debug.Log("出入口数量:" + roadTypes.Count(x => x.Value == RoadType.Ramp));
Debug.Log("高架大道数量:" + roadTypes.Count(x => x.Value == RoadType.Elevated));