public bool AttemptJoinReservation(ReservationInfo current_reservation, SingleTrack2WSection new_reservation, ushort train_id) { //do not allow train following if route taken by the train is not guaranteed (train could stop at a station and come back its way for example) if (!Mod.allowFollowing || current_reservation.section.containStopStation || new_reservation.containStopStation) { return(false); } if (!current_reservation.refuse_following_trains && current_reservation.section.Compare(new_reservation)) { current_reservation.train_ids.Add(train_id); //actualize data for (int i = 0; i < m_data.reservations.Count; i++) { if (m_data.reservations[i].ID == current_reservation.ID) { m_data.reservations[i] = current_reservation; break; } } return(true); } return(false); }
public void Recycle() { //ID_counter++; //ID = ID_counter; train_ids.Clear(); //pending_train_ids.Clear(); refuse_following_trains = false; section = null; clearing_timer = 0; status = ReservationStatus.Ineffective; }
public ReservationInfo RegisterNewReservation(SingleTrack2WSection section, ushort leading_vehicle_id, ref ushort blocking_segment_id) { ReservationInfo ri = new ReservationInfo(); ri.section = section; blocking_segment_id = RegisterReservation(ri, leading_vehicle_id, false, -1); if (!Mod.allowGoAsFarAsPossible && blocking_segment_id != 0) //cache reservation to avoid recreating it many times in a row { m_data.ClearCacheForTrain(leading_vehicle_id); m_data.cached_reservations.Add(leading_vehicle_id, ri); } return(ri); }
public bool AttemptReservationForNextPendingTrain(ReservationInfo current_reservation, SingleTrack2WSection new_reservation, ushort train_id) { if (current_reservation.status == ReservationStatus.RecycleForPendingTrain && current_reservation.pending_train_ids.Count > 0 && current_reservation.pending_train_ids[0] == train_id) { ushort old_id = current_reservation.ID; m_data.RemoveReservation(old_id, false); current_reservation.Recycle(); current_reservation.pending_train_ids.RemoveAt(0); current_reservation.section = new_reservation; RegisterReservation(current_reservation, train_id, true, old_id); return(true); } return(false); }
static void AppendNextConnectedSegmentTheOldWay(SingleTrack2WSection section, uint segment_id) { NetManager instance = Singleton <NetManager> .instance; int nieghbours_count = 0; bool include_segments = false; List <ushort> single_lanes = new List <ushort>(); NetNode node; NetSegment seg = instance.m_segments.m_buffer[segment_id]; List <ushort> nodes_included = new List <ushort>(); int n = 0; nodes_included.Add(seg.m_endNode); nodes_included.Add(seg.m_startNode); while (nodes_included.Count > n) { nieghbours_count = 0; single_lanes.Clear(); include_segments = false; node = instance.m_nodes.m_buffer[(int)((UIntPtr)nodes_included[n])]; //find every segments attached to node for (int i = 0; i < 8; i++) { if (node.GetSegment(i) != 0) { nieghbours_count++; if (RequireReservation(node.GetSegment(i))) //detect 1 lane 2 ways segments { single_lanes.Add(node.GetSegment(i)); } } } if (nieghbours_count <= 2 && single_lanes.Count > 0) //include single track segments without branching { include_segments = true; } /*else if (nieghbours_count > 2) //include single track segments with branching. All single track 2 ways segments connected together will get booked * include_segments = true;*/ if (include_segments) { for (int i = 0; i < single_lanes.Count; i++) { if (!section.segment_ids.Contains(single_lanes[i])) //check not already included { section.segment_ids.Add(single_lanes[i]); //activate signal at the end of the single track section CheckSpawnSignals(single_lanes[i]); //get next nodes seg = instance.m_segments.m_buffer[(int)single_lanes[i]]; if (!nodes_included.Contains(seg.m_endNode)) { nodes_included.Add(seg.m_endNode); } if (!nodes_included.Contains(seg.m_startNode)) { nodes_included.Add(seg.m_startNode); } } } } n++; } }
/******** reservation creation algorithm ************/ public SingleTrack2WSection CreateSingleTrack2WSectionFromTrainPath(ushort vehicle_id, ushort start_segment_id) { PathManager instance = Singleton <PathManager> .instance; VehicleManager instance2 = Singleton <VehicleManager> .instance; NetManager instance3 = Singleton <NetManager> .instance; Vehicle vehicleData = instance2.m_vehicles.m_buffer[vehicle_id]; PathUnit pathunit = instance.m_pathUnits.m_buffer[vehicleData.m_path]; int posindex = (vehicleData.m_pathPositionIndex >> 1) + 1; bool continue_search = true; bool found_inspected_segment = false; ushort segments_ahead_from_vehicle = 0; SingleTrack2WSection section = new SingleTrack2WSection(); ushort crt_segment_id = 0; bool buildOldWay = false; //browse successive segments in path for single tracks while (continue_search) { continue_search = false; if (posindex >= (int)pathunit.m_positionCount) { posindex = 0; uint nextPathUnit = pathunit.m_nextPathUnit; if (nextPathUnit == 0u) { //CODebug.Log(LogChannel.Modding, Mod.modName + " - no next path unit ??"); //path is at the end, don't know if train will carry after the station //may add further single track segments along the track buildOldWay = true; //start other algorithm, usually in case of a single track station break; } pathunit = instance.m_pathUnits.m_buffer[nextPathUnit]; } PathUnit.Position pathpos; if (!pathunit.GetPosition(posindex, out pathpos)) { return(null); } crt_segment_id = pathpos.m_segment; //activate signal at the end of the single track section CheckSpawnSignals(crt_segment_id); if (!found_inspected_segment) { if (crt_segment_id == start_segment_id) { found_inspected_segment = true; } } if (found_inspected_segment) { if (RequireReservation(crt_segment_id)) { section.segment_ids.Add(crt_segment_id); continue_search = true; } } posindex++; segments_ahead_from_vehicle++; if (!found_inspected_segment && segments_ahead_from_vehicle < 5) { continue_search = true; } } if (buildOldWay && section.segment_ids.Count > 0) { if (IsStation(section.segment_ids[section.segment_ids.Count - 1])) { section.containStopStation = true; //Is use of other algo really needed? Train may or may not go further along the track //Other trains check if other reservation further along the path anyway... // -> yes reserving single tracks after station ensure TrainExitStation is properly resolved // There is not a second, separate reservation made (except when branching...) if (Mod.extendReservationAfterStopStation) { //section.notFromPathSegmentsStartingAt = section.segment_ids.Count; //mark that segments further on have not been path checked AppendNextConnectedSegmentTheOldWay(section, section.segment_ids[section.segment_ids.Count - 1]); } } } if (section.segment_ids.Count > 0) { return(section); } return(null); }
//public int notFromPathSegmentsStartingAt = -1; public bool Compare(SingleTrack2WSection other) { return(this.segment_ids[0] == other.segment_ids[0] && this.segment_ids[this.segment_ids.Count - 1] == other.segment_ids[other.segment_ids.Count - 1]); }
private bool CheckSingleTrack2Ways(ushort vehicleID, Vehicle vehicleData, ref float maxSpeed, uint laneID, uint prevLaneID, ref bool mayNeedSingleTrackStationFix) { NetManager instance = Singleton <NetManager> .instance; ushort next_segment_id = instance.m_lanes.m_buffer[(int)((UIntPtr)laneID)].m_segment; ushort crt_segment_id = instance.m_lanes.m_buffer[(int)((UIntPtr)prevLaneID)].m_segment; ReservationManager instance2 = ReservationManager.instance; ushort leadingVehicleID = vehicleData.GetFirstVehicle(vehicleID); ReservationInfo ri = null; bool preventCheckNextLane = false; bool notifyFutureTrack = false; if (ReservationManager.RequireReservation(next_segment_id)) { ri = instance2.GetReservationOnSegment(next_segment_id); } CreateReservation: if (ReservationManager.IsSingleTrack2WSegment(next_segment_id)) //train carriage will enter a one lane section { if (ri == null) //reserve track if it is not reserved by any train { ushort blocking_segmentID = 0; ri = ReservationManager.instance.CheckCachedReservation(next_segment_id, leadingVehicleID, ref blocking_segmentID); if (ri == null) //no cached reservation found, create one { SingleTrack2WSection section = instance2.CreateSingleTrack2WSectionFromTrainPath(leadingVehicleID, next_segment_id); if (section != null) { ri = ReservationManager.instance.RegisterNewReservation(section, leadingVehicleID, ref blocking_segmentID); } } if (blocking_segmentID != 0) //reservation blocked by a further segment already reserved, get this reservation { ri = instance2.GetReservationOnSegment(blocking_segmentID); /*ReservationManager.instance.EnqueueReservation(ri, leadingVehicleID); * maxSpeed = 0f; * return true;*/ } else { mayNeedSingleTrackStationFix = true; //track reserved by this train } } } if (ri != null) { if (ReservationManager.IsReservationForTrain(ri, leadingVehicleID)) //track is reserved for this vehicle { notifyFutureTrack = true; mayNeedSingleTrackStationFix = true; //track reserved by this train //reset wait counter /* if((vehicleData.m_flags2 & Vehicle.Flags2.Yielding) != (Vehicle.Flags2) 0) * { * vehicleData.m_flags2 &= ~Vehicle.Flags2.Yielding; * vehicleData.m_waitCounter = 0; * }*/ //return true so that CheckNextLane does not interfere (it causes train to stop when going from one track to double track with a train waiting in the opposite direction) if (Mod.noCheckOverlapOnLastSegment && next_segment_id == ri.section.segment_ids[ri.section.segment_ids.Count - 1]) { preventCheckNextLane = true; } } else //section reserved by another train { //train has spawned on a station reserved to another train, though case... //attempt destroy reservation and give priority to this train if (ReservationManager.IsSingleTrackStation(crt_segment_id)) { ReservationManager.instance.m_data.RemoveReservation(ri.ID, true); ri = null; goto CreateReservation; } SingleTrack2WSection section = instance2.CreateSingleTrack2WSectionFromTrainPath(leadingVehicleID, next_segment_id); if (!(section != null && ReservationManager.instance.AttemptJoinReservation(ri, section, leadingVehicleID))) //can train follow the previous one? { if (!(section != null && ReservationManager.instance.AttemptReservationForNextPendingTrain(ri, section, leadingVehicleID))) //has section been cleared? { //not allowed on this track, stop ReservationManager.instance.EnqueueReservation(ri, leadingVehicleID); maxSpeed = 0f; //increment wait counter /*vehicleData.m_flags2 |= Vehicle.Flags2.Yielding; * vehicleData.m_waitCounter++;*/ //set traffic light state /*NetSegment seg = instance.m_segments.m_buffer[crt_segment_id]; * RoadBaseAI.SetTrafficLightState(seg.m_endNode, ref seg, 0, RoadBaseAI.TrafficLightState.Red, RoadBaseAI.TrafficLightState.Red, true, false); * RoadBaseAI.SetTrafficLightState(seg.m_startNode, ref seg, 0, RoadBaseAI.TrafficLightState.Red, RoadBaseAI.TrafficLightState.Red, true, false); * instance.m_nodes.m_buffer[seg.m_endNode].m_flags |= NetNode.Flags.TrafficLights; * instance.m_nodes.m_buffer[seg.m_startNode].m_flags |= NetNode.Flags.TrafficLights; * * /*if (vehicleID == leadingVehicleID) * { * instance.m_segments.m_buffer[crt_segment_id].m_trafficLightState0 = (byte) RoadBaseAI.TrafficLightState.Red; * }*/ preventCheckNextLane = true; } } } //assess if single track station fix is necessary, before Notify which can cancel TrainAtStation status (if new front carriage is out of station for example) if (mayNeedSingleTrackStationFix && ri.status != ReservationStatus.TrainAtStation) { mayNeedSingleTrackStationFix = false; } } if (ReservationManager.RequireReservation(crt_segment_id)) //train carriage is on a one lane section (or double track station which may belong to a single track section) { instance2.NotifyReservation(leadingVehicleID, crt_segment_id, true, vehicleData.m_flags); } if (notifyFutureTrack) { instance2.NotifyReservation(leadingVehicleID, next_segment_id, false); } return(preventCheckNextLane); }