public TrackFollowingObjectAI(TrackFollowingObject train, TravelData[] data) { Train = train; Data = data; TimeLastProcessed = 0.0; if (Train.Cars[0].Specs.DoorOpenFrequency != 0.0) { OpeningDoorsTime = 1.0 / Train.Cars[0].Specs.DoorOpenFrequency; } if (Train.Cars[0].Specs.DoorCloseFrequency != 0.0) { ClosingDoorsTime = 1.0 / Train.Cars[0].Specs.DoorCloseFrequency; } SetupTravelData(); CheckTravelData(); }
/// <summary>Parses a track following object</summary> /// <param name="ObjectPath">Absolute path to the object folder of route data</param> /// <param name="FileName">The XML file to parse</param> internal static TrackFollowingObject ParseTrackFollowingObject(string ObjectPath, string FileName) { // The current XML file to load XDocument CurrentXML = XDocument.Load(FileName, LoadOptions.SetLineInfo); List <XElement> TfoElements = CurrentXML.XPathSelectElements("/openBVE/TrackFollowingObject").ToList(); // Check this file actually contains OpenBVE other train definition elements if (!TfoElements.Any()) { // We couldn't find any valid XML, so return false throw new InvalidDataException(); } TrackFollowingObject Train = new TrackFollowingObject(TrainState.Pending); foreach (XElement Element in TfoElements) { ParseTrackFollowingObjectNode(ObjectPath, FileName, Element, Train); } return(Train); }
/// <summary>Parses a base track following object node</summary> /// <param name="ObjectPath">Absolute path to the object folder of route data</param> /// <param name="FileName">The filename of the containing XML file</param> /// <param name="SectionElement">The XElement to parse</param> /// <param name="Train">The track following object to parse this node into</param> private static void ParseTrackFollowingObjectNode(string ObjectPath, string FileName, XElement SectionElement, TrackFollowingObject Train) { string Section = SectionElement.Name.LocalName; string TrainDirectory = string.Empty; bool ConsistReversed = false; List <TravelData> Data = new List <TravelData>(); foreach (XElement KeyNode in SectionElement.Elements()) { string Key = KeyNode.Name.LocalName; int LineNumber = ((IXmlLineInfo)KeyNode).LineNumber; switch (Key.ToLowerInvariant()) { case "definition": ParseDefinitionNode(FileName, KeyNode, Train); break; case "train": ParseTrainNode(ObjectPath, FileName, KeyNode, ref TrainDirectory, ref ConsistReversed); break; case "points": case "stops": ParseTravelDataNodes(FileName, KeyNode, Data); break; default: Interface.AddMessage(MessageType.Warning, false, $"Unsupported key {Key} encountered in {Section} at line {LineNumber.ToString(culture)} in {FileName}"); break; } } if (Data.Count < 2) { Interface.AddMessage(MessageType.Error, false, $"There must be at least two points to go through in {FileName}"); return; } if (!(Data.First() is TravelStopData) || !(Data.Last() is TravelStopData)) { Interface.AddMessage(MessageType.Error, false, $"The first and the last point to go through must be the \"Stop\" node in {FileName}"); return; } if (string.IsNullOrEmpty(TrainDirectory)) { Interface.AddMessage(MessageType.Error, false, $"No train has been specified in {FileName}"); return; } /* * First check for a train.ai file- Functionally identical, but allows for differently configured AI * trains not to show up as drivable */ string TrainData = OpenBveApi.Path.CombineFile(TrainDirectory, "train.ai"); if (!File.Exists(TrainData)) { // Check for the standard drivable train.dat TrainData = OpenBveApi.Path.CombineFile(TrainDirectory, "train.dat"); } string ExteriorFile = OpenBveApi.Path.CombineFile(TrainDirectory, "extensions.cfg"); if (!File.Exists(TrainData) || !File.Exists(ExteriorFile)) { Interface.AddMessage(MessageType.Error, true, $"The supplied train folder in TrackFollowingObject {FileName} did not contain a complete set of data."); return; } AbstractTrain currentTrain = Train; for (int i = 0; i < Program.CurrentHost.Plugins.Length; i++) { if (Program.CurrentHost.Plugins[i].Train != null && Program.CurrentHost.Plugins[i].Train.CanLoadTrain(TrainDirectory)) { Program.CurrentHost.Plugins[i].Train.LoadTrain(Encoding.UTF8, TrainDirectory, ref currentTrain, ref Interface.CurrentControls); } } Train.AI = new TrackFollowingObjectAI(Train, Data.ToArray()); foreach (var Car in Train.Cars) { Car.FrontAxle.Follower.TrackIndex = Data[0].RailIndex; Car.RearAxle.Follower.TrackIndex = Data[0].RailIndex; Car.FrontBogie.FrontAxle.Follower.TrackIndex = Data[0].RailIndex; Car.FrontBogie.RearAxle.Follower.TrackIndex = Data[0].RailIndex; Car.RearBogie.FrontAxle.Follower.TrackIndex = Data[0].RailIndex; Car.RearBogie.RearAxle.Follower.TrackIndex = Data[0].RailIndex; } if (ConsistReversed) { Train.Reverse(); } Train.PlaceCars(Data[0].Position); }
/// <summary> /// Function to parse TFO definition /// </summary> /// <param name="FileName">The filename of the containing XML file</param> /// <param name="SectionElement">The XElement to parse</param> /// <param name="Train">The track following object to parse this node into</param> private static void ParseDefinitionNode(string FileName, XElement SectionElement, TrackFollowingObject Train) { string Section = SectionElement.Name.LocalName; foreach (XElement KeyNode in SectionElement.Elements()) { string Key = KeyNode.Name.LocalName; string Value = KeyNode.Value; int LineNumber = ((IXmlLineInfo)KeyNode).LineNumber; switch (Key.ToLowerInvariant()) { case "appearancetime": if (Value.Any() && !Interface.TryParseTime(Value, out Train.AppearanceTime)) { Interface.AddMessage(MessageType.Error, false, $"Value is invalid in {Key} in {Section} at line {LineNumber.ToString(culture)} in {FileName}"); } break; case "appearancestartposition": if (Value.Any() && !NumberFormats.TryParseDoubleVb6(Value, out Train.AppearanceStartPosition)) { Interface.AddMessage(MessageType.Error, false, $"Value is invalid in {Key} in {Section} at line {LineNumber.ToString(culture)} in {FileName}"); } break; case "appearanceendposition": if (Value.Any() && !NumberFormats.TryParseDoubleVb6(Value, out Train.AppearanceEndPosition)) { Interface.AddMessage(MessageType.Error, false, $"Value is invalid in {Key} in {Section} at line {LineNumber.ToString(culture)} in {FileName}"); } break; case "leavetime": if (Value.Any() && !Interface.TryParseTime(Value, out Train.LeaveTime)) { Interface.AddMessage(MessageType.Error, false, $"Value is invalid in {Key} in {Section} at line {LineNumber.ToString(culture)} in {FileName}"); } break; default: Interface.AddMessage(MessageType.Warning, false, $"Unsupported key {Key} encountered in {Section} at line {LineNumber.ToString(culture)} in {FileName}"); break; } } }
public TrackFollowingObjectAI(TrackFollowingObject train, TravelData[] data) { Train = train; Data = data; TimeLastProcessed = 0.0; }