Example #1
0
        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;
                }
            }
        }
Example #5
0
 public TrackFollowingObjectAI(TrackFollowingObject train, TravelData[] data)
 {
     Train             = train;
     Data              = data;
     TimeLastProcessed = 0.0;
 }