Provides structures, enumerations and functions for cross-platform file access.
Beispiel #1
0
 public override Image GetImage(string trainPath)
 {
     try
     {
         string imageFile = Path.CombineFile(trainPath, "train.png");
         if (File.Exists(imageFile))
         {
             return(Image.FromFile(imageFile));
         }
         imageFile = Path.CombineFile(trainPath, "train.gif");
         if (File.Exists(imageFile))
         {
             return(Image.FromFile(imageFile));
         }
         imageFile = Path.CombineFile(trainPath, "train.bmp");
         if (File.Exists(imageFile))
         {
             return(Image.FromFile(imageFile));
         }
     }
     catch (Exception ex)
     {
         currentHost.ReportProblem(ProblemType.UnexpectedException, "Unable to get the image for train " + trainPath + " due to the exeception: " + ex.Message);
     }
     return(null);
 }
Beispiel #2
0
 /// <summary>Checks whether the plugin can load the specified route.</summary>
 /// <param name="path">The path to the file or folder that contains the route.</param>
 /// <returns>Whether the plugin can load the specified route.</returns>
 public override bool CanLoadRoute(string path)
 {
     if (!File.Exists(path))
     {
         return(false);
     }
     if (path.EndsWith(".dat", StringComparison.InvariantCultureIgnoreCase))
     {
         try
         {
             if (Parser.knownModules.Contains(Path.GetChecksum(path)) || File.ReadLines(path).Count() < 800)
             {
                 /*
                  * Slightly hacky check if not found in the known modules list:
                  * The original Mechanik download contained a route generator.
                  * All this did was to append various module files to generate a
                  * final route.
                  *
                  * If we have less than ~800 lines, it's not a complete route, but
                  * a module instead.
                  */
                 return(false);
             }
         }
         catch
         {
             //Innacessable file?!
             return(false);
         }
         return(true);
     }
     return(false);
 }
Beispiel #3
0
        /// <summary>Loads the specified route.</summary>
        /// <param name="path">The path to the file or folder that contains the route.</param>
        /// <param name="Encoding">The user-selected encoding (if appropriate)</param>
        /// <param name="trainPath">The path to the selected train</param>
        /// <param name="objectPath">The base object folder path</param>
        /// <param name="soundPath">The base sound folder path</param>
        /// <param name="PreviewOnly">Whether this is a preview</param>
        /// <param name="route">Receives the route.</param>
        /// <returns>Whether loading the sound was successful.</returns>
        public override bool LoadRoute(string path, Encoding Encoding, string trainPath, string objectPath, string soundPath, bool PreviewOnly, ref object route)
        {
            if (Encoding == null)
            {
                Encoding = Encoding.UTF8;
            }
            LastException   = null;
            Cancel          = false;
            CurrentProgress = 0.0;
            IsLoading       = true;
            FileSystem.AppendToLogFile("Loading route file: " + path);
            FileSystem.AppendToLogFile("INFO: Route file hash " + Path.GetChecksum(path));
            CurrentRoute = (CurrentRoute)route;
            //First, check the format of the route file
            //RW routes were written for BVE1 / 2, and have a different command syntax
            bool isRw = path.ToLowerInvariant().EndsWith(".rw");

            FileSystem.AppendToLogFile("Route file format is: " + (isRw ? "RW" : "CSV"));
            try
            {
                Parser parser = new Parser();
                parser.ParseRoute(path, isRw, Encoding, trainPath, objectPath, soundPath, PreviewOnly, this);
                IsLoading = false;
                return(true);
            }
            catch (Exception ex)
            {
                route = null;
                CurrentHost.AddMessage(MessageType.Error, false, "An unexpected error occured whilst attempting to load the following routefile: " + path);
                IsLoading     = false;
                LastException = ex;
                return(false);
            }
        }
        /// <summary>Parses a openBVE panel.animated.xml file</summary>
        /// <param name="PanelFile">The relative path of the panel configuration file from the train</param>
        /// <param name="Train">The train</param>
        /// <param name="Car">The car index to add the panel to</param>
        internal void ParsePanelAnimatedXml(string PanelFile, TrainBase Train, int Car)
        {
            // The current XML file to load
            string FileName = PanelFile;

            if (!File.Exists(FileName))
            {
                FileName = Path.CombineFile(Train.TrainFolder, PanelFile);
            }

            XDocument CurrentXML = XDocument.Load(FileName, LoadOptions.SetLineInfo);

            // Check for null
            if (CurrentXML.Root == null)
            {
                // We couldn't find any valid XML, so return false
                throw new System.IO.InvalidDataException();
            }

            IEnumerable <XElement> DocumentElements = CurrentXML.Root.Elements("PanelAnimated");

            // Check this file actually contains OpenBVE panel definition elements
            if (DocumentElements == null || !DocumentElements.Any())
            {
                // We couldn't find any valid XML, so return false
                throw new System.IO.InvalidDataException();
            }

            foreach (XElement element in DocumentElements)
            {
                ParsePanelAnimatedNode(element, FileName, Train.TrainFolder, Train, Car, Train.Cars[Car].CarSections[0], 0);
            }
        }
Beispiel #5
0
 /// <summary>Returns whether the plugin is capable of loading the specified object.</summary>
 /// <param name="path">The file or folder where the object is stored.</param>
 /// <param name="encoding">The suggested encoding in case the object format does not mandate a specific encoding.</param>
 /// <param name="data">Optional data passed from another plugin. If you access this field, you must check the type before casting to that type.</param>
 /// <returns>The priority at which the plugin supports loading the specified object.</returns>
 public General.Priority CanLoadObject(Path.PathReference path, Encoding encoding, object data)
 {
     if (path is Path.FileReference) {
         string fileName = ((Path.FileReference)path).Path;
         if (
             fileName.EndsWith(".x", StringComparison.OrdinalIgnoreCase)
         ) {
             return General.Priority.Normal;
         } else {
             return General.Priority.NotCapable;
         }
     } else {
         return General.Priority.NotCapable;
     }
 }
Beispiel #6
0
        private static void routeWorkerThread_doWork(object sender, DoWorkEventArgs e)
        {
            if (string.IsNullOrEmpty(currentFile))
            {
                return;
            }
            RouteEncoding = TextEncoding.GetSystemEncodingFromFile(currentFile);
            Program.CurrentHost.RegisterTexture(Path.CombineFile(Program.FileSystem.DataFolder, "Menu\\loading.png"), new TextureParameters(null, null), out routePictureBox.Texture);
            routeDescriptionBox.Text = Translations.GetInterfaceString("start_route_processing");
            Game.Reset(false);
            bool loaded = false;

            for (int i = 0; i < Program.CurrentHost.Plugins.Length; i++)
            {
                if (Program.CurrentHost.Plugins[i].Route != null && Program.CurrentHost.Plugins[i].Route.CanLoadRoute(currentFile))
                {
                    object Route         = (object)Program.CurrentRoute;             //must cast to allow us to use the ref keyword.
                    string RailwayFolder = Loading.GetRailwayFolder(currentFile);
                    string ObjectFolder  = OpenBveApi.Path.CombineDirectory(RailwayFolder, "Object");
                    string SoundFolder   = OpenBveApi.Path.CombineDirectory(RailwayFolder, "Sound");
                    if (Program.CurrentHost.Plugins[i].Route.LoadRoute(currentFile, RouteEncoding, null, ObjectFolder, SoundFolder, true, ref Route))
                    {
                        Program.CurrentRoute = (CurrentRoute)Route;
                    }
                    else
                    {
                        if (Program.CurrentHost.Plugins[i].Route.LastException != null)
                        {
                            throw Program.CurrentHost.Plugins[i].Route.LastException;                             //Re-throw last exception generated by the route parser plugin so that the UI thread captures it
                        }
                        routeDescriptionBox.Text = "An unknown error was enountered whilst attempting to parse the routefile " + currentFile;
                        RoutefileState           = RouteState.Error;
                    }
                    loaded = true;
                    break;
                }
            }

            if (!loaded)
            {
                throw new Exception("No plugins capable of loading routefile " + currentFile + " were found.");
            }
        }
Beispiel #7
0
 public override string GetDescription(string trainPath, Encoding encoding = null)
 {
     try
     {
         string descriptionFile = Path.CombineFile(trainPath, "train.txt");
         if (File.Exists(descriptionFile))
         {
             if (encoding == null)
             {
                 return(File.ReadAllText(descriptionFile));
             }
             return(File.ReadAllText(descriptionFile, encoding));
         }
     }
     catch (Exception ex)
     {
         currentHost.ReportProblem(ProblemType.UnexpectedException, "Unable to get the description for train " + trainPath + " due to the exeception: " + ex.Message);
     }
     return(string.Empty);
 }
Beispiel #8
0
 private void LoadCompatibilitySignalSets()
 {
     string[] possibleFiles = Directory.GetFiles(Path.CombineDirectory(Program.FileSystem.GetDataFolder("Compatibility"), "Signals"), "*.xml");
     for (int i = 0; i < possibleFiles.Length; i++)
     {
         XmlDocument currentXML = new XmlDocument();
         try
         {
             currentXML.Load(possibleFiles[i]);
             XmlNode node = currentXML.SelectSingleNode("/openBVE/CompatibilitySignals/SignalSetName");
             if (node != null)
             {
                 compatibilitySignals.Add(node.InnerText, possibleFiles[i]);
                 comboBoxCompatibilitySignals.Items.Add(node.InnerText);
             }
         }
         catch
         {
         }
     }
 }
Beispiel #9
0
 /// <summary>Returns whether the plugin is capable of loading the specified texture.</summary>
 /// <param name="path">The file or folder where the texture is stored.</param>
 /// <param name="encoding">The suggested encoding in case the texture format does not mandate a specific encoding.</param>
 /// <param name="data">Optional data passed from another plugin. If you access this field, you must check the type before casting to that type.</param>
 /// <returns>The priority at which the plugin supports loading the specified texture.</returns>
 public General.Priority CanLoadTexture(Path.PathReference path, Encoding encoding, object data)
 {
     if (path is Path.FileReference) {
         string fileName = ((Path.FileReference)path).Path;
         if (
             fileName.EndsWith(".bmp", StringComparison.OrdinalIgnoreCase) ||
             fileName.EndsWith(".gif", StringComparison.OrdinalIgnoreCase) ||
             fileName.EndsWith(".exig", StringComparison.OrdinalIgnoreCase) ||
             fileName.EndsWith(".jpg", StringComparison.OrdinalIgnoreCase) ||
             fileName.EndsWith(".jpeg", StringComparison.OrdinalIgnoreCase) ||
             fileName.EndsWith(".png", StringComparison.OrdinalIgnoreCase) ||
             fileName.EndsWith(".tif", StringComparison.OrdinalIgnoreCase) ||
             fileName.EndsWith(".tiff", StringComparison.OrdinalIgnoreCase)
         ) {
             return General.Priority.Normal;
         } else {
             return General.Priority.NotCapable;
         }
     } else {
         return General.Priority.NotCapable;
     }
 }
Beispiel #10
0
        public override bool CanLoadTrain(string path)
        {
            string vehicleTxt = Path.CombineFile(path, "vehicle.txt");

            if (File.Exists(vehicleTxt))
            {
                string[] lines = File.ReadAllLines(vehicleTxt);
                for (int i = 10; i < lines.Length; i++)
                {
                    if (lines[i].StartsWith(@"bvets vehicle ", StringComparison.InvariantCultureIgnoreCase))
                    {
                        /*
                         * BVE5 format train
                         * When the BVE5 plugin is implemented, this should return false, as BVE5 trains
                         * often seem to keep the train.dat lying around and we need to use the right plugin
                         *
                         * For the moment however, this is ignored....
                         */
                    }
                }
            }
            string trainDat = Path.CombineFile(path, "train.dat");

            if (File.Exists(trainDat))
            {
                return(true);
            }
            string trainXML = Path.CombineFile(path, "train.xml");

            if (File.Exists(trainXML))
            {
                /*
                 * XML format train
                 * At present, XML is used only as an extension, but acceleration etc. will be implemented
                 * When this is done, return true here
                 */
            }
            return(false);
        }
Beispiel #11
0
 /// <summary>Returns whether the plugin is capable of loading the specified texture.</summary>
 /// <param name="path">The file or folder where the texture is stored.</param>
 /// <param name="encoding">The suggested encoding in case the texture format does not mandate a specific encoding.</param>
 /// <param name="data">Optional data passed from another plugin. If you access this field, you must check the type before casting to that type.</param>
 /// <returns>The priority at which the plugin supports loading the specified texture.</returns>
 public General.Priority CanLoadTexture(Path.PathReference path, Encoding encoding, object data)
 {
     return General.Priority.NotCapable;
 }
Beispiel #12
0
 /// <summary>Loads a sound into an output parameter and returns the success of the operation.</summary>
 /// <param name="path">The file or folder where the sound is stored.</param>
 /// <param name="encoding">The suggested encoding in case the sound format does not mandate a specific encoding.</param>
 /// <param name="data">Optional data passed from another plugin. If you access this field, you must check the type before casting to that type.</param>
 /// <param name="sound">Receives the sound.</param>
 /// <returns>The success of the operation.</returns>
 public General.Result LoadSound(Path.PathReference path, Encoding encoding, object data, out Sound.SoundData sound)
 {
     sound = null;
     return General.Result.NotSupported;
 }
Beispiel #13
0
 /// <summary>Loads a texture into an output parameter and returns the success of the operation.</summary>
 /// <param name="path">The file or folder where the texture is stored.</param>
 /// <param name="encoding">The suggested encoding in case the texture format does not mandate a specific encoding.</param>
 /// <param name="data">Optional data passed from another plugin. If you access this field, you must check the type before casting to that type.</param>
 /// <param name="texture">Receives the texture.</param>
 /// <returns>The success of the operation.</returns>
 public General.Result LoadTexture(Path.PathReference path, Encoding encoding, object data, out Texture.TextureData texture)
 {
     texture = null;
     return General.Result.NotSupported;
 }
Beispiel #14
0
 /// <summary>Loads an object into an output parameter and returns the success of the operation.</summary>
 /// <param name="path">The file or folder where the object is stored.</param>
 /// <param name="encoding">The suggested encoding in case the object format does not mandate a specific encoding.</param>
 /// <param name="data">Optional data passed from another plugin. If you access this field, you must check the type before casting to that type.</param>
 /// <param name="obj">Receives the object.</param>
 /// <returns>The success of the operation.</returns>
 public General.Result LoadObject(Path.PathReference path, Encoding encoding, object data, out Geometry.GenericObject obj)
 {
     obj = null;
     return General.Result.NotSupported;
 }
Beispiel #15
0
 /// <summary>Loads a route into an output parameter and returns the success of the operation.</summary>
 /// <param name="path">The file or folder where the route is stored.</param>
 /// <param name="encoding">The suggested encoding in case the route format does not mandate a specific encoding.</param>
 /// <param name="data">Optional data passed from another plugin. If you access this field, you must check the type before casting to that type.</param>
 /// <param name="route">Receives the route.</param>
 /// <returns>The success of the operation.</returns>
 public General.Result LoadRoute(Path.PathReference path, Encoding encoding, object data, out Route.RouteData route)
 {
     #if !DEBUG
     try {
         #endif
         string fileName = ((Path.FileReference)path).Path;
         if (System.IO.File.Exists(fileName)) {
             return Parser.LoadCsvOrRwRoute(fileName, encoding, out route);
         } else {
             route = null;
             return OpenBveApi.General.Result.FileNotFound;
         }
         #if !DEBUG
     } catch {
         route = null;
         return OpenBveApi.General.Result.InternalError;
     }
     #endif
 }
Beispiel #16
0
 // constructors
 /// <summary>Creates a new instance of this structure.</summary>
 /// <param name="path">A reference to the file or folder where the data is stored, or a null reference.</param>
 /// <param name="plugin">A reference to a plugin that should be used to load the data, or a null reference.</param>
 /// <param name="encoding">The suggested encoding, or a null reference.</param>
 public Origin(Path.PathReference path, General.PluginReference plugin, System.Text.Encoding encoding)
 {
     this.Path = path;
     this.Plugin = plugin;
     this.Encoding = encoding;
 }
Beispiel #17
0
        internal static void Parse(string fileName, out Sound sound)
        {
            sound = new Sound();

            CultureInfo   culture  = CultureInfo.InvariantCulture;
            List <string> lines    = File.ReadAllLines(fileName, TextEncoding.GetSystemEncodingFromFile(fileName)).ToList();
            string        basePath = System.IO.Path.GetDirectoryName(fileName);

            for (int i = lines.Count - 1; i >= 0; i--)
            {
                /*
                 * Strip comments and remove empty resulting lines etc.
                 *
                 * This fixes an error with some NYCTA content, which has
                 * a copyright notice instead of the file header specified....
                 */
                int j = lines[i].IndexOf(';');

                if (j >= 0)
                {
                    lines[i] = lines[i].Substring(0, j).Trim();
                }
                else
                {
                    lines[i] = lines[i].Trim();
                }

                if (string.IsNullOrEmpty(lines[i]))
                {
                    lines.RemoveAt(i);
                }
            }

            if (!lines.Any())
            {
                Interface.AddMessage(MessageType.Error, false, $"Empty sound.cfg encountered in {fileName}.");
            }

            if (string.Compare(lines[0], "version 1.0", StringComparison.OrdinalIgnoreCase) != 0)
            {
                Interface.AddMessage(MessageType.Error, false, $"Invalid file format encountered in {fileName}. The first line is expected to be \"Version 1.0\".");
            }

            for (int i = 0; i < lines.Count; i++)
            {
                switch (lines[i].ToLowerInvariant())
                {
                case "[run]":
                    i++;

                    while (i < lines.Count && !lines[i].StartsWith("[", StringComparison.Ordinal))
                    {
                        int j = lines[i].IndexOf("=", StringComparison.Ordinal);

                        if (j >= 0)
                        {
                            string a = lines[i].Substring(0, j).TrimEnd();
                            string b = lines[i].Substring(j + 1).TrimStart();
                            int    k;

                            if (!int.TryParse(a, NumberStyles.Integer, culture, out k))
                            {
                                Interface.AddMessage(MessageType.Error, false, $"Invalid index appeared at line {(i + 1).ToString(culture)} in file {fileName}");
                            }
                            else if (b.Length == 0 || Path.ContainsInvalidChars(b))
                            {
                                Interface.AddMessage(MessageType.Error, false, $"FileName contains illegal characters or is empty at line {(i + 1).ToString(culture)} in file {fileName}");
                            }
                            else
                            {
                                if (k >= 0)
                                {
                                    sound.SoundElements.Add(new RunElement {
                                        Key = k, FilePath = Path.CombineFile(basePath, b)
                                    });
                                }
                                else
                                {
                                    Interface.AddMessage(MessageType.Error, false, $"Index must be greater or equal to zero at line {(i + 1).ToString(culture)} in file {fileName}");
                                }
                            }
                        }

                        i++;
                    }

                    i--;
                    break;

                case "[flange]":
                    i++;

                    while (i < lines.Count && !lines[i].StartsWith("[", StringComparison.Ordinal))
                    {
                        int j = lines[i].IndexOf("=", StringComparison.Ordinal);

                        if (j >= 0)
                        {
                            string a = lines[i].Substring(0, j).TrimEnd();
                            string b = lines[i].Substring(j + 1).TrimStart();
                            int    k;

                            if (!int.TryParse(a, NumberStyles.Integer, culture, out k))
                            {
                                Interface.AddMessage(MessageType.Error, false, $"Invalid index appeared at line {(i + 1).ToString(culture)} in file {fileName}");
                            }
                            else if (b.Length == 0 || Path.ContainsInvalidChars(b))
                            {
                                Interface.AddMessage(MessageType.Error, false, $"FileName contains illegal characters or is empty at line {(i + 1).ToString(culture)} in file {fileName}");
                            }
                            else
                            {
                                if (k >= 0)
                                {
                                    sound.SoundElements.Add(new FlangeElement {
                                        Key = k, FilePath = Path.CombineFile(basePath, b)
                                    });
                                }
                                else
                                {
                                    Interface.AddMessage(MessageType.Error, false, $"Index must be greater or equal to zero at line {(i + 1).ToString(culture)} in file {fileName}");
                                }
                            }
                        }

                        i++;
                    }

                    i--;
                    break;

                case "[motor]":
                    i++;

                    while (i < lines.Count && !lines[i].StartsWith("[", StringComparison.Ordinal))
                    {
                        int j = lines[i].IndexOf("=", StringComparison.Ordinal);

                        if (j >= 0)
                        {
                            string a = lines[i].Substring(0, j).TrimEnd();
                            string b = lines[i].Substring(j + 1).TrimStart();
                            int    k;

                            if (!int.TryParse(a, NumberStyles.Integer, culture, out k))
                            {
                                Interface.AddMessage(MessageType.Error, false, $"Invalid index appeared at line {(i + 1).ToString(culture)} in file {fileName}");
                            }
                            else if (b.Length == 0 || Path.ContainsInvalidChars(b))
                            {
                                Interface.AddMessage(MessageType.Error, false, $"FileName contains illegal characters or is empty at line {(i + 1).ToString(culture)} in file {fileName}");
                            }
                            else
                            {
                                if (k >= 0)
                                {
                                    sound.SoundElements.Add(new MotorElement {
                                        Key = k, FilePath = Path.CombineFile(basePath, b)
                                    });
                                }
                                else
                                {
                                    Interface.AddMessage(MessageType.Error, false, $"Index is invalid at line {(i + 1).ToString(culture)} in file {fileName}");
                                }
                            }
                        }

                        i++;
                    }

                    i--;
                    break;

                case "[switch]":
                    i++;

                    while (i < lines.Count && !lines[i].StartsWith("[", StringComparison.Ordinal))
                    {
                        int j = lines[i].IndexOf("=", StringComparison.Ordinal);

                        if (j >= 0)
                        {
                            string a = lines[i].Substring(0, j).TrimEnd();
                            string b = lines[i].Substring(j + 1).TrimStart();
                            int    k;

                            if (!int.TryParse(a, NumberStyles.Integer, culture, out k))
                            {
                                Interface.AddMessage(MessageType.Error, false, $"Invalid index appeared at line {(i + 1).ToString(culture)} in file {fileName}");
                            }
                            else if (b.Length == 0 || Path.ContainsInvalidChars(b))
                            {
                                Interface.AddMessage(MessageType.Error, false, $"FileName contains illegal characters or is empty at line {(i + 1).ToString(culture)} in file {fileName}");
                            }
                            else
                            {
                                if (k >= 0)
                                {
                                    sound.SoundElements.Add(new FrontSwitchElement {
                                        Key = k, FilePath = Path.CombineFile(basePath, b)
                                    });
                                }
                                else
                                {
                                    Interface.AddMessage(MessageType.Error, false, $"Index is invalid at line {(i + 1).ToString(culture)} in file {fileName}");
                                }
                            }
                        }

                        i++;
                    }

                    i--;
                    break;

                case "[brake]":
                    i++;

                    while (i < lines.Count && !lines[i].StartsWith("[", StringComparison.Ordinal))
                    {
                        int j = lines[i].IndexOf("=", StringComparison.Ordinal);

                        if (j >= 0)
                        {
                            string a = lines[i].Substring(0, j).TrimEnd();
                            string b = lines[i].Substring(j + 1).TrimStart();

                            if (b.Length == 0 || Path.ContainsInvalidChars(b))
                            {
                                Interface.AddMessage(MessageType.Error, false, $"FileName contains illegal characters or is empty at line {(i + 1).ToString(culture)} in file {fileName}");
                            }
                            else
                            {
                                BrakeKey[] keys = Enum.GetValues(typeof(BrakeKey)).OfType <BrakeKey>().Where(x => x.GetStringValues().Any(y => y.Equals(a, StringComparison.InvariantCultureIgnoreCase))).ToArray();

                                if (keys.Any())
                                {
                                    sound.SoundElements.Add(new BrakeElement {
                                        Key = keys.First(), FilePath = Path.CombineFile(basePath, b)
                                    });
                                }
                                else
                                {
                                    Interface.AddMessage(MessageType.Warning, false, $"Unsupported key {a} encountered at line {(i + 1).ToString(culture)} in file {fileName}");
                                }
                            }
                        }

                        i++;
                    }

                    i--;
                    break;

                case "[compressor]":
                    i++;

                    while (i < lines.Count && !lines[i].StartsWith("[", StringComparison.Ordinal))
                    {
                        int j = lines[i].IndexOf("=", StringComparison.Ordinal);

                        if (j >= 0)
                        {
                            string a = lines[i].Substring(0, j).TrimEnd();
                            string b = lines[i].Substring(j + 1).TrimStart();

                            if (b.Length == 0 || Path.ContainsInvalidChars(b))
                            {
                                Interface.AddMessage(MessageType.Error, false, $"FileName contains illegal characters or is empty at line {(i + 1).ToString(culture)} in file {fileName}");
                            }
                            else
                            {
                                CompressorKey[] keys = Enum.GetValues(typeof(CompressorKey)).OfType <CompressorKey>().Where(x => x.GetStringValues().Any(y => y.Equals(a, StringComparison.InvariantCultureIgnoreCase))).ToArray();

                                if (keys.Any())
                                {
                                    sound.SoundElements.Add(new CompressorElement {
                                        Key = keys.First(), FilePath = Path.CombineFile(basePath, b)
                                    });
                                }
                                else
                                {
                                    Interface.AddMessage(MessageType.Warning, false, $"Unsupported key {a} encountered at line {(i + 1).ToString(culture)} in file {fileName}");
                                }
                            }
                        }

                        i++;
                    }

                    i--;
                    break;

                case "[suspension]":
                    i++;

                    while (i < lines.Count && !lines[i].StartsWith("[", StringComparison.Ordinal))
                    {
                        int j = lines[i].IndexOf("=", StringComparison.Ordinal);

                        if (j >= 0)
                        {
                            string a = lines[i].Substring(0, j).TrimEnd();
                            string b = lines[i].Substring(j + 1).TrimStart();

                            if (b.Length == 0 || Path.ContainsInvalidChars(b))
                            {
                                Interface.AddMessage(MessageType.Error, false, $"FileName contains illegal characters or is empty at line {(i + 1).ToString(culture)} in file {fileName}");
                            }
                            else
                            {
                                SuspensionKey[] keys = Enum.GetValues(typeof(SuspensionKey)).OfType <SuspensionKey>().Where(x => x.GetStringValues().Any(y => y.Equals(a, StringComparison.InvariantCultureIgnoreCase))).ToArray();

                                if (keys.Any())
                                {
                                    sound.SoundElements.Add(new SuspensionElement {
                                        Key = keys.First(), FilePath = Path.CombineFile(basePath, b)
                                    });
                                }
                                else
                                {
                                    Interface.AddMessage(MessageType.Warning, false, $"Unsupported key {a} encountered at line {(i + 1).ToString(culture)} in file {fileName}");
                                }
                            }
                        }

                        i++;
                    }

                    i--;
                    break;

                case "[horn]":
                    i++;

                    while (i < lines.Count && !lines[i].StartsWith("[", StringComparison.Ordinal))
                    {
                        int j = lines[i].IndexOf("=", StringComparison.Ordinal);

                        if (j >= 0)
                        {
                            string a = lines[i].Substring(0, j).TrimEnd();
                            string b = lines[i].Substring(j + 1).TrimStart();

                            if (b.Length == 0 || Path.ContainsInvalidChars(b))
                            {
                                Interface.AddMessage(MessageType.Error, false, $"FileName contains illegal characters or is empty at line {(i + 1).ToString(culture)} in file {fileName}");
                            }
                            else
                            {
                                HornKey[] primaryKeys   = Enum.GetValues(typeof(HornKey)).OfType <HornKey>().Where(x => x.GetStringValues().Any(y => $"Primary{y}".Equals(a, StringComparison.InvariantCultureIgnoreCase))).ToArray();
                                HornKey[] secondaryKeys = Enum.GetValues(typeof(HornKey)).OfType <HornKey>().Where(x => x.GetStringValues().Any(y => $"Secondary{y}".Equals(a, StringComparison.InvariantCultureIgnoreCase))).ToArray();
                                HornKey[] musicKeys     = Enum.GetValues(typeof(HornKey)).OfType <HornKey>().Where(x => x.GetStringValues().Any(y => $"Music{y}".Equals(a, StringComparison.InvariantCultureIgnoreCase))).ToArray();

                                if (primaryKeys.Any())
                                {
                                    sound.SoundElements.Add(new PrimaryHornElement {
                                        Key = primaryKeys.First(), FilePath = Path.CombineFile(basePath, b)
                                    });
                                }
                                else if (secondaryKeys.Any())
                                {
                                    sound.SoundElements.Add(new SecondaryHornElement {
                                        Key = secondaryKeys.First(), FilePath = Path.CombineFile(basePath, b)
                                    });
                                }
                                else if (musicKeys.Any())
                                {
                                    sound.SoundElements.Add(new MusicHornElement {
                                        Key = musicKeys.First(), FilePath = Path.CombineFile(basePath, b)
                                    });
                                }
                                else if ("Primary".Equals(a, StringComparison.InvariantCultureIgnoreCase))
                                {
                                    sound.SoundElements.Add(new PrimaryHornElement {
                                        Key = HornKey.Loop, FilePath = Path.CombineFile(basePath, b)
                                    });
                                }
                                else if ("Secondary".Equals(a, StringComparison.InvariantCultureIgnoreCase))
                                {
                                    sound.SoundElements.Add(new SecondaryHornElement {
                                        Key = HornKey.Loop, FilePath = Path.CombineFile(basePath, b)
                                    });
                                }
                                else if ("Music".Equals(a, StringComparison.InvariantCultureIgnoreCase))
                                {
                                    sound.SoundElements.Add(new MusicHornElement {
                                        Key = HornKey.Loop, FilePath = Path.CombineFile(basePath, b)
                                    });
                                }
                                else
                                {
                                    Interface.AddMessage(MessageType.Warning, false, $"Unsupported key {a} encountered at line {(i + 1).ToString(culture)} in file {fileName}");
                                }
                            }
                        }

                        i++;
                    }

                    i--;
                    break;

                case "[door]":
                    i++;

                    while (i < lines.Count && !lines[i].StartsWith("[", StringComparison.Ordinal))
                    {
                        int j = lines[i].IndexOf("=", StringComparison.Ordinal);

                        if (j >= 0)
                        {
                            string a = lines[i].Substring(0, j).TrimEnd();
                            string b = lines[i].Substring(j + 1).TrimStart();

                            if (b.Length == 0 || Path.ContainsInvalidChars(b))
                            {
                                Interface.AddMessage(MessageType.Error, false, $"FileName contains illegal characters or is empty at line {(i + 1).ToString(culture)} in file {fileName}");
                            }
                            else
                            {
                                DoorKey[] keys = Enum.GetValues(typeof(DoorKey)).OfType <DoorKey>().Where(x => x.GetStringValues().Any(y => y.Equals(a, StringComparison.InvariantCultureIgnoreCase))).ToArray();

                                if (keys.Any())
                                {
                                    sound.SoundElements.Add(new DoorElement {
                                        Key = keys.First(), FilePath = Path.CombineFile(basePath, b)
                                    });
                                }
                                else
                                {
                                    Interface.AddMessage(MessageType.Warning, false, $"Unsupported key {a} encountered at line {(i + 1).ToString(culture)} in file {fileName}");
                                }
                            }
                        }

                        i++;
                    }

                    i--;
                    break;

                case "[ats]":
                    i++;

                    while (i < lines.Count && !lines[i].StartsWith("[", StringComparison.Ordinal))
                    {
                        int j = lines[i].IndexOf("=", StringComparison.Ordinal);

                        if (j >= 0)
                        {
                            string a = lines[i].Substring(0, j).TrimEnd();
                            string b = lines[i].Substring(j + 1).TrimStart();

                            if (b.Length == 0 || Path.ContainsInvalidChars(b))
                            {
                                Interface.AddMessage(MessageType.Error, false, $"FileName contains illegal characters or is empty at line {(i + 1).ToString(culture)} in file {fileName}");
                            }
                            else
                            {
                                int k;

                                if (!int.TryParse(a, NumberStyles.Integer, culture, out k))
                                {
                                    Interface.AddMessage(MessageType.Error, false, $"Invalid index appeared at line {(i + 1).ToString(culture)} in file {fileName}");
                                }
                                else
                                {
                                    if (k >= 0)
                                    {
                                        sound.SoundElements.Add(new AtsElement {
                                            Key = k, FilePath = Path.CombineFile(basePath, b)
                                        });
                                    }
                                    else
                                    {
                                        Interface.AddMessage(MessageType.Warning, false, "Index must be greater or equal to zero at line " + (i + 1).ToString(culture) + " in file " + fileName);
                                    }
                                }
                            }
                        }

                        i++;
                    }

                    i--;
                    break;

                case "[buzzer]":
                    i++;

                    while (i < lines.Count && !lines[i].StartsWith("[", StringComparison.Ordinal))
                    {
                        int j = lines[i].IndexOf("=", StringComparison.Ordinal);

                        if (j >= 0)
                        {
                            string a = lines[i].Substring(0, j).TrimEnd();
                            string b = lines[i].Substring(j + 1).TrimStart();

                            if (b.Length == 0 || Path.ContainsInvalidChars(b))
                            {
                                Interface.AddMessage(MessageType.Error, false, $"FileName contains illegal characters or is empty at line {(i + 1).ToString(culture)} in file {fileName}");
                            }
                            else
                            {
                                BuzzerKey[] keys = Enum.GetValues(typeof(BuzzerKey)).OfType <BuzzerKey>().Where(x => x.GetStringValues().Any(y => y.Equals(a, StringComparison.InvariantCultureIgnoreCase))).ToArray();

                                if (keys.Any())
                                {
                                    sound.SoundElements.Add(new BuzzerElement {
                                        Key = keys.First(), FilePath = Path.CombineFile(basePath, b)
                                    });
                                }
                                else
                                {
                                    Interface.AddMessage(MessageType.Warning, false, $"Unsupported key {a} encountered at line {(i + 1).ToString(culture)} in file {fileName}");
                                }
                            }
                        }

                        i++;
                    }

                    i--;
                    break;

                case "[pilot lamp]":
                    i++;

                    while (i < lines.Count && !lines[i].StartsWith("[", StringComparison.Ordinal))
                    {
                        int j = lines[i].IndexOf("=", StringComparison.Ordinal);

                        if (j >= 0)
                        {
                            string a = lines[i].Substring(0, j).TrimEnd();
                            string b = lines[i].Substring(j + 1).TrimStart();

                            if (b.Length == 0 || Path.ContainsInvalidChars(b))
                            {
                                Interface.AddMessage(MessageType.Error, false, $"FileName contains illegal characters or is empty at line {(i + 1).ToString(culture)} in file {fileName}");
                            }
                            else
                            {
                                PilotLampKey[] keys = Enum.GetValues(typeof(PilotLampKey)).OfType <PilotLampKey>().Where(x => x.GetStringValues().Any(y => y.Equals(a, StringComparison.InvariantCultureIgnoreCase))).ToArray();

                                if (keys.Any())
                                {
                                    sound.SoundElements.Add(new PilotLampElement {
                                        Key = keys.First(), FilePath = Path.CombineFile(basePath, b)
                                    });
                                }
                                else
                                {
                                    Interface.AddMessage(MessageType.Warning, false, $"Unsupported key {a} encountered at line {(i + 1).ToString(culture)} in file {fileName}");
                                }
                            }
                        }

                        i++;
                    }

                    i--;
                    break;

                case "[brake handle]":
                    i++;

                    while (i < lines.Count && !lines[i].StartsWith("[", StringComparison.Ordinal))
                    {
                        int j = lines[i].IndexOf("=", StringComparison.Ordinal);

                        if (j >= 0)
                        {
                            string a = lines[i].Substring(0, j).TrimEnd();
                            string b = lines[i].Substring(j + 1).TrimStart();

                            if (b.Length == 0 || Path.ContainsInvalidChars(b))
                            {
                                Interface.AddMessage(MessageType.Error, false, $"FileName contains illegal characters or is empty at line {(i + 1).ToString(culture)} in file {fileName}");
                            }
                            else
                            {
                                BrakeHandleKey[] keys = Enum.GetValues(typeof(BrakeHandleKey)).OfType <BrakeHandleKey>().Where(x => x.GetStringValues().Any(y => y.Equals(a, StringComparison.InvariantCultureIgnoreCase))).ToArray();

                                if (keys.Any())
                                {
                                    sound.SoundElements.Add(new BrakeHandleElement {
                                        Key = keys.First(), FilePath = Path.CombineFile(basePath, b)
                                    });
                                }
                                else
                                {
                                    Interface.AddMessage(MessageType.Warning, false, $"Unsupported key {a} encountered at line {(i + 1).ToString(culture)} in file {fileName}");
                                }
                            }
                        }

                        i++;
                    }

                    i--;
                    break;

                case "[master controller]":
                    i++;

                    while (i < lines.Count && !lines[i].StartsWith("[", StringComparison.Ordinal))
                    {
                        int j = lines[i].IndexOf("=", StringComparison.Ordinal);

                        if (j >= 0)
                        {
                            string a = lines[i].Substring(0, j).TrimEnd();
                            string b = lines[i].Substring(j + 1).TrimStart();

                            if (b.Length == 0 || Path.ContainsInvalidChars(b))
                            {
                                Interface.AddMessage(MessageType.Error, false, $"FileName contains illegal characters or is empty at line {(i + 1).ToString(culture)} in file {fileName}");
                            }
                            else
                            {
                                MasterControllerKey[] keys = Enum.GetValues(typeof(MasterControllerKey)).OfType <MasterControllerKey>().Where(x => x.GetStringValues().Any(y => y.Equals(a, StringComparison.InvariantCultureIgnoreCase))).ToArray();

                                if (keys.Any())
                                {
                                    sound.SoundElements.Add(new MasterControllerElement {
                                        Key = keys.First(), FilePath = Path.CombineFile(basePath, b)
                                    });
                                }
                                else
                                {
                                    Interface.AddMessage(MessageType.Warning, false, $"Unsupported key {a} encountered at line {(i + 1).ToString(culture)} in file {fileName}");
                                }
                            }
                        }

                        i++;
                    }

                    i--;
                    break;

                case "[reverser]":
                    i++;

                    while (i < lines.Count && !lines[i].StartsWith("[", StringComparison.Ordinal))
                    {
                        int j = lines[i].IndexOf("=", StringComparison.Ordinal);

                        if (j >= 0)
                        {
                            string a = lines[i].Substring(0, j).TrimEnd();
                            string b = lines[i].Substring(j + 1).TrimStart();

                            if (b.Length == 0 || Path.ContainsInvalidChars(b))
                            {
                                Interface.AddMessage(MessageType.Error, false, $"FileName contains illegal characters or is empty at line {(i + 1).ToString(culture)} in file {fileName}");
                            }
                            else
                            {
                                ReverserKey[] keys = Enum.GetValues(typeof(ReverserKey)).OfType <ReverserKey>().Where(x => x.GetStringValues().Any(y => y.Equals(a, StringComparison.InvariantCultureIgnoreCase))).ToArray();

                                if (keys.Any())
                                {
                                    sound.SoundElements.Add(new ReverserElement {
                                        Key = keys.First(), FilePath = Path.CombineFile(basePath, b)
                                    });
                                }
                                else
                                {
                                    Interface.AddMessage(MessageType.Warning, false, $"Unsupported key {a} encountered at line {(i + 1).ToString(culture)} in file {fileName}");
                                }
                            }
                        }

                        i++;
                    }

                    i--;
                    break;

                case "[breaker]":
                    i++;

                    while (i < lines.Count && !lines[i].StartsWith("[", StringComparison.Ordinal))
                    {
                        int j = lines[i].IndexOf("=", StringComparison.Ordinal);

                        if (j >= 0)
                        {
                            string a = lines[i].Substring(0, j).TrimEnd();
                            string b = lines[i].Substring(j + 1).TrimStart();

                            if (b.Length == 0 || Path.ContainsInvalidChars(b))
                            {
                                Interface.AddMessage(MessageType.Error, false, $"FileName contains illegal characters or is empty at line {(i + 1).ToString(culture)} in file {fileName}");
                            }
                            else
                            {
                                BreakerKey[] keys = Enum.GetValues(typeof(BreakerKey)).OfType <BreakerKey>().Where(x => x.GetStringValues().Any(y => y.Equals(a, StringComparison.InvariantCultureIgnoreCase))).ToArray();

                                if (keys.Any())
                                {
                                    sound.SoundElements.Add(new BreakerElement {
                                        Key = keys.First(), FilePath = Path.CombineFile(basePath, b)
                                    });
                                }
                                else
                                {
                                    Interface.AddMessage(MessageType.Warning, false, $"Unsupported key {a} encountered at line {(i + 1).ToString(culture)} in file {fileName}");
                                }
                            }
                        }

                        i++;
                    }

                    i--;
                    break;

                case "[others]":
                    i++;

                    while (i < lines.Count && !lines[i].StartsWith("[", StringComparison.Ordinal))
                    {
                        int j = lines[i].IndexOf("=", StringComparison.Ordinal);

                        if (j >= 0)
                        {
                            string a = lines[i].Substring(0, j).TrimEnd();
                            string b = lines[i].Substring(j + 1).TrimStart();

                            if (b.Length == 0 || Path.ContainsInvalidChars(b))
                            {
                                Interface.AddMessage(MessageType.Error, false, $"FileName contains illegal characters or is empty at line {(i + 1).ToString(culture)} in file {fileName}");
                            }
                            else
                            {
                                OthersKey[] keys = Enum.GetValues(typeof(OthersKey)).OfType <OthersKey>().Where(x => x.GetStringValues().Any(y => y.Equals(a, StringComparison.InvariantCultureIgnoreCase))).ToArray();

                                if (keys.Any())
                                {
                                    sound.SoundElements.Add(new OthersElement {
                                        Key = keys.First(), FilePath = Path.CombineFile(basePath, b)
                                    });
                                }
                                else
                                {
                                    Interface.AddMessage(MessageType.Warning, false, $"Unsupported key {a} encountered at line {(i + 1).ToString(culture)} in file {fileName}");
                                }
                            }
                        }

                        i++;
                    }

                    i--;
                    break;

                case "[requeststop]":
                    i++;

                    while (i < lines.Count && !lines[i].StartsWith("[", StringComparison.Ordinal))
                    {
                        int j = lines[i].IndexOf("=", StringComparison.Ordinal);

                        if (j >= 0)
                        {
                            string a = lines[i].Substring(0, j).TrimEnd();
                            string b = lines[i].Substring(j + 1).TrimStart();

                            if (b.Length == 0 || Path.ContainsInvalidChars(b))
                            {
                                Interface.AddMessage(MessageType.Error, false, $"FileName contains illegal characters or is empty at line {(i + 1).ToString(culture)} in file {fileName}");
                            }
                            else
                            {
                                RequestStopKey[] keys = Enum.GetValues(typeof(RequestStopKey)).OfType <RequestStopKey>().Where(x => x.GetStringValues().Any(y => y.Equals(a, StringComparison.InvariantCultureIgnoreCase))).ToArray();

                                if (keys.Any())
                                {
                                    sound.SoundElements.Add(new RequestStopElement {
                                        Key = keys.First(), FilePath = Path.CombineFile(basePath, b)
                                    });
                                }
                                else
                                {
                                    Interface.AddMessage(MessageType.Warning, false, $"Unsupported key {a} encountered at line {(i + 1).ToString(culture)} in file {fileName}");
                                }
                            }
                        }

                        i++;
                    }

                    i--;
                    break;

                case "[touch]":
                    i++;

                    while (i < lines.Count && !lines[i].StartsWith("[", StringComparison.Ordinal))
                    {
                        int j = lines[i].IndexOf("=", StringComparison.Ordinal);

                        if (j >= 0)
                        {
                            string a = lines[i].Substring(0, j).TrimEnd();
                            string b = lines[i].Substring(j + 1).TrimStart();

                            if (b.Length == 0 || Path.ContainsInvalidChars(b))
                            {
                                Interface.AddMessage(MessageType.Error, false, $"FileName contains illegal characters or is empty at line {(i + 1).ToString(culture)} in file {fileName}");
                            }
                            else
                            {
                                int k;

                                if (!int.TryParse(a, NumberStyles.Integer, culture, out k))
                                {
                                    Interface.AddMessage(MessageType.Error, false, $"Invalid index appeared at line {(i + 1).ToString(culture)} in file {fileName}");
                                }
                                else
                                {
                                    if (k >= 0)
                                    {
                                        sound.SoundElements.Add(new TouchElement {
                                            Key = k, FilePath = Path.CombineFile(basePath, b)
                                        });
                                    }
                                    else
                                    {
                                        Interface.AddMessage(MessageType.Warning, false, "Index must be greater or equal to zero at line " + (i + 1).ToString(culture) + " in file " + fileName);
                                    }
                                }
                            }
                        }

                        i++;
                    }

                    i--;
                    break;
                }
            }

            sound.SoundElements = new ObservableCollection <SoundElement>(sound.SoundElements.GroupBy(x => new { Type = x.GetType(), x.Key }).Select(x => x.First()));
        }
Beispiel #18
0
 /// <summary>Loads an object into an output parameter and returns the success of the operation.</summary>
 /// <param name="path">The file or folder where the object is stored.</param>
 /// <param name="encoding">The suggested encoding in case the object format does not mandate a specific encoding.</param>
 /// <param name="data">Optional data passed from another plugin. If you access this field, you must check the type before casting to that type.</param>
 /// <param name="obj">Receives the object.</param>
 /// <returns>The success of the operation.</returns>
 public General.Result LoadObject(Path.PathReference path, Encoding encoding, object data, out Geometry.GenericObject obj)
 {
     #if !DEBUG
     try {
         #endif
         string fileName = ((Path.FileReference)path).Path;
         if (System.IO.File.Exists(fileName)) {
             return Parser.LoadFromFile(fileName, encoding, out obj);
         } else {
             obj = null;
             return OpenBveApi.General.Result.FileNotFound;
         }
         #if !DEBUG
     } catch {
         obj = null;
         return OpenBveApi.General.Result.InternalError;
     }
     #endif
 }
Beispiel #19
0
 /// <summary>Loads a route into an output parameter and returns the success of the operation.</summary>
 /// <param name="path">The file or folder where the route is stored.</param>
 /// <param name="encoding">The suggested encoding in case the route format does not mandate a specific encoding.</param>
 /// <param name="data">Optional data passed from another plugin. If you access this field, you must check the type before casting to that type.</param>
 /// <param name="route">Receives the route.</param>
 /// <returns>The success of the operation.</returns>
 public General.Result LoadRoute(Path.PathReference path, Encoding encoding, object data, out Route.RouteData route)
 {
     route = null;
     return General.Result.NotSupported;
 }
Beispiel #20
0
        /// <summary>Attempts to load and parse the current train's panel configuration file.</summary>
        /// <param name="Train">The train</param>
        /// <param name="Encoding">The selected train encoding</param>
        internal void ParsePanelConfig(TrainBase Train, Encoding Encoding)
        {
            Train.Cars[Train.DriverCar].CarSections    = new CarSection[1];
            Train.Cars[Train.DriverCar].CarSections[0] = new CarSection(currentHost, ObjectType.Overlay, true);
            string File = Path.CombineFile(Train.TrainFolder, "panel.xml");

            if (!System.IO.File.Exists(File))
            {
                //Try animated variant too
                File = Path.CombineFile(Train.TrainFolder, "panel.animated.xml");
            }

            if (System.IO.File.Exists(File))
            {
                FileSystem.AppendToLogFile("Loading train panel: " + File);
                try
                {
                    /*
                     * First load the XML. We use this to determine
                     * whether this is a 2D or a 3D animated panel
                     */
                    XDocument CurrentXML = XDocument.Load(File, LoadOptions.SetLineInfo);

                    // Check for null
                    if (CurrentXML.Root != null)
                    {
                        IEnumerable <XElement> DocumentElements = CurrentXML.Root.Elements("PanelAnimated");
                        if (DocumentElements.Any())
                        {
                            PanelAnimatedXmlParser.ParsePanelAnimatedXml(System.IO.Path.GetFileName(File), Train, Train.DriverCar);
                            if (Train.Cars[Train.DriverCar].CameraRestrictionMode != CameraRestrictionMode.Restricted3D)
                            {
                                Train.Cars[Train.DriverCar].CameraRestrictionMode = CameraRestrictionMode.NotAvailable;
                            }
                            return;
                        }

                        DocumentElements = CurrentXML.Root.Elements("Panel");
                        if (DocumentElements.Any())
                        {
                            PanelXmlParser.ParsePanelXml(System.IO.Path.GetFileName(File), Train, Train.DriverCar);
                            Train.Cars[Train.DriverCar].CameraRestrictionMode = CameraRestrictionMode.On;
                            Renderer.Camera.CurrentRestriction = CameraRestrictionMode.On;
                            return;
                        }
                    }
                }
                catch
                {
                    var currentError = Translations.GetInterfaceString("errors_critical_file");
                    currentError = currentError.Replace("[file]", "panel.xml");
                    currentHost.ReportProblem(ProblemType.InvalidData, currentError);
                    Cancel = true;
                    return;
                }

                currentHost.AddMessage(MessageType.Error, false, "The panel.xml file " + File + " failed to load. Falling back to legacy panel.");
            }
            else
            {
                File = Path.CombineFile(Train.TrainFolder, "panel.animated");
                if (System.IO.File.Exists(File))
                {
                    FileSystem.AppendToLogFile("Loading train panel: " + File);
                    if (System.IO.File.Exists(Path.CombineFile(Train.TrainFolder, "panel2.cfg")) || System.IO.File.Exists(Path.CombineFile(Train.TrainFolder, "panel.cfg")))
                    {
                        FileSystem.AppendToLogFile("INFO: This train contains both a 2D and a 3D panel. The 3D panel will always take precedence");
                    }

                    UnifiedObject currentObject;
                    currentHost.LoadObject(File, Encoding, out currentObject);
                    var a = currentObject as AnimatedObjectCollection;
                    if (a != null)
                    {
                        //HACK: If a == null , loading our animated object completely failed (Missing objects?). Fallback to trying the panel2.cfg
                        try
                        {
                            for (int i = 0; i < a.Objects.Length; i++)
                            {
                                currentHost.CreateDynamicObject(ref a.Objects[i].internalObject);
                            }

                            Train.Cars[Train.DriverCar].CarSections[0].Groups[0].Elements = a.Objects;
                            if (Train.Cars[Train.DriverCar].CameraRestrictionMode != CameraRestrictionMode.Restricted3D)
                            {
                                Train.Cars[Train.DriverCar].CameraRestrictionMode = CameraRestrictionMode.NotAvailable;
                                Renderer.Camera.CurrentRestriction = CameraRestrictionMode.NotAvailable;
                            }

                            return;
                        }
                        catch
                        {
                            var currentError = Translations.GetInterfaceString("errors_critical_file");
                            currentError = currentError.Replace("[file]", "panel.animated");
                            currentHost.ReportProblem(ProblemType.InvalidData, currentError);
                            Cancel = true;
                            return;
                        }
                    }

                    currentHost.AddMessage(MessageType.Error, false, "The panel.animated file " + File + " failed to load. Falling back to 2D panel.");
                }
            }

            var Panel2 = false;

            try
            {
                File = Path.CombineFile(Train.TrainFolder, "panel2.cfg");
                if (System.IO.File.Exists(File))
                {
                    FileSystem.AppendToLogFile("Loading train panel: " + File);
                    Panel2 = true;
                    Panel2CfgParser.ParsePanel2Config("panel2.cfg", Train.TrainFolder, Train.Cars[Train.DriverCar]);
                    Train.Cars[Train.DriverCar].CameraRestrictionMode = CameraRestrictionMode.On;
                    Renderer.Camera.CurrentRestriction = CameraRestrictionMode.On;
                }
                else
                {
                    File = Path.CombineFile(Train.TrainFolder, "panel.cfg");
                    if (System.IO.File.Exists(File))
                    {
                        FileSystem.AppendToLogFile("Loading train panel: " + File);
                        PanelCfgParser.ParsePanelConfig(Train.TrainFolder, Encoding, Train.Cars[Train.DriverCar]);
                        Train.Cars[Train.DriverCar].CameraRestrictionMode = CameraRestrictionMode.On;
                        Renderer.Camera.CurrentRestriction = CameraRestrictionMode.On;
                    }
                    else
                    {
                        Renderer.Camera.CurrentRestriction = CameraRestrictionMode.NotAvailable;
                    }
                }
            }
            catch
            {
                var currentError = Translations.GetInterfaceString("errors_critical_file");
                currentError = currentError.Replace("[file]", Panel2 ? "panel2.cfg" : "panel.cfg");
                currentHost.ReportProblem(ProblemType.InvalidData, currentError);
                Cancel = true;
            }
        }
        private void ParsePanelAnimatedNode(XElement Element, string FileName, string TrainPath, CarSection CarSection, int GroupIndex)
        {
            System.Globalization.CultureInfo Culture = System.Globalization.CultureInfo.InvariantCulture;

            int    currentSectionElement   = 0;
            int    numberOfSectionElements = Element.Elements().Count();
            double invfac = numberOfSectionElements == 0 ? 0.4 : 0.4 / numberOfSectionElements;

            foreach (XElement SectionElement in Element.Elements())
            {
                Plugin.CurrentProgress = Plugin.LastProgress + invfac * currentSectionElement;
                if ((currentSectionElement & 4) == 0)
                {
                    System.Threading.Thread.Sleep(1);
                    if (Plugin.Cancel)
                    {
                        return;
                    }
                }

                string Section = SectionElement.Name.LocalName;

                switch (SectionElement.Name.LocalName.ToLowerInvariant())
                {
                case "group":
                    if (GroupIndex == 0)
                    {
                        int n = 0;

                        foreach (XElement KeyNode in SectionElement.Elements())
                        {
                            string Key        = KeyNode.Name.LocalName;
                            string Value      = KeyNode.Value;
                            int    LineNumber = ((IXmlLineInfo)KeyNode).LineNumber;

                            switch (Key.ToLowerInvariant())
                            {
                            case "number":
                                if (Value.Length != 0 && !NumberFormats.TryParseIntVb6(Value, out n))
                                {
                                    Plugin.currentHost.AddMessage(MessageType.Error, false, "Value is invalid in " + Key + " in " + Section + " at line " + LineNumber.ToString(Culture) + " in " + FileName);
                                }
                                break;
                            }
                        }

                        if (n + 1 >= CarSection.Groups.Length)
                        {
                            Array.Resize(ref CarSection.Groups, n + 2);
                            CarSection.Groups[n + 1] = new ElementsGroup(ObjectType.Overlay);
                        }

                        ParsePanelAnimatedNode(SectionElement, FileName, TrainPath, CarSection, n + 1);
                    }
                    break;

                case "touch":
                    if (GroupIndex > 0)
                    {
                        Vector3             Position       = Vector3.Zero;
                        Vector3             Size           = Vector3.Zero;
                        int                 JumpScreen     = GroupIndex - 1;
                        List <int>          SoundIndices   = new List <int>();
                        List <CommandEntry> CommandEntries = new List <CommandEntry>();
                        CommandEntry        CommandEntry   = new CommandEntry();

                        foreach (XElement KeyNode in SectionElement.Elements())
                        {
                            string Key        = KeyNode.Name.LocalName;
                            string Value      = KeyNode.Value;
                            int    LineNumber = ((IXmlLineInfo)KeyNode).LineNumber;

                            switch (Key.ToLowerInvariant())
                            {
                            case "position":
                                if (!Vector3.TryParse(KeyNode.Value, ',', out Position))
                                {
                                    Plugin.currentHost.AddMessage(MessageType.Error, false, "Position is invalid in " + Key + " in " + Section + " at line " + LineNumber.ToString(Culture) + " in " + FileName);
                                }
                                break;

                            case "size":
                                if (!Vector3.TryParse(KeyNode.Value, ',', out Size))
                                {
                                    Plugin.currentHost.AddMessage(MessageType.Error, false, "Size is invalid in " + Key + " in " + Section + " at line " + LineNumber.ToString(Culture) + " in " + FileName);
                                }
                                break;

                            case "jumpscreen":
                                if (Value.Length != 0 && !NumberFormats.TryParseIntVb6(Value, out JumpScreen))
                                {
                                    Plugin.currentHost.AddMessage(MessageType.Error, false, "Value is invalid in " + Key + " in " + Section + " at line " + LineNumber.ToString(Culture) + " in " + FileName);
                                }
                                break;

                            case "soundindex":
                                if (Value.Length != 0)
                                {
                                    if (!NumberFormats.TryParseIntVb6(Value, out var SoundIndex))
                                    {
                                        Plugin.currentHost.AddMessage(MessageType.Error, false, "Value is invalid in " + Key + " in " + Section + " at line " + LineNumber.ToString(Culture) + " in " + FileName);
                                        break;
                                    }
                                    SoundIndices.Add(SoundIndex);
                                }
                                break;

                            case "command":
                            {
                                if (!CommandEntries.Contains(CommandEntry))
                                {
                                    CommandEntries.Add(CommandEntry);
                                }

                                if (string.Compare(Value, "N/A", StringComparison.InvariantCultureIgnoreCase) == 0)
                                {
                                    break;
                                }

                                int i;
                                for (i = 0; i < Translations.CommandInfos.Length; i++)
                                {
                                    if (string.Compare(Value, Translations.CommandInfos[i].Name, StringComparison.OrdinalIgnoreCase) == 0)
                                    {
                                        break;
                                    }
                                }
                                if (i == Translations.CommandInfos.Length || Translations.CommandInfos[i].Type != Translations.CommandType.Digital)
                                {
                                    Plugin.currentHost.AddMessage(MessageType.Error, false, "Value is invalid in " + Key + " in " + Section + " at line " + LineNumber.ToString(Culture) + " in " + FileName);
                                }
                                else
                                {
                                    CommandEntry.Command = Translations.CommandInfos[i].Command;
                                }
                            }
                            break;

                            case "commandoption":
                                if (!CommandEntries.Contains(CommandEntry))
                                {
                                    CommandEntries.Add(CommandEntry);
                                }

                                if (Value.Length != 0 && !NumberFormats.TryParseIntVb6(Value, out CommandEntry.Option))
                                {
                                    Plugin.currentHost.AddMessage(MessageType.Error, false, "Value is invalid in " + Key + " in " + Section + " at line " + LineNumber.ToString(Culture) + " in " + FileName);
                                }
                                break;

                            case "soundentries":
                                if (!KeyNode.HasElements)
                                {
                                    Plugin.currentHost.AddMessage(MessageType.Error, false, $"An empty list of touch sound indices was defined at line {((IXmlLineInfo)KeyNode).LineNumber} in XML file {FileName}");
                                    break;
                                }

                                ParseTouchSoundEntryNode(FileName, KeyNode, SoundIndices);
                                break;

                            case "commandentries":
                                if (!KeyNode.HasElements)
                                {
                                    Plugin.currentHost.AddMessage(MessageType.Error, false, $"An empty list of touch commands was defined at line {((IXmlLineInfo)KeyNode).LineNumber} in XML file {FileName}");
                                    break;
                                }

                                ParseTouchCommandEntryNode(FileName, KeyNode, CommandEntries);
                                break;
                            }
                        }
                        CreateTouchElement(CarSection.Groups[GroupIndex], Position, Size, JumpScreen, SoundIndices.ToArray(), CommandEntries.ToArray());
                    }
                    break;

                case "include":
                {
                    foreach (XElement KeyNode in SectionElement.Elements())
                    {
                        string Key        = KeyNode.Name.LocalName;
                        string Value      = KeyNode.Value;
                        int    LineNumber = ((IXmlLineInfo)KeyNode).LineNumber;

                        switch (Key.ToLowerInvariant())
                        {
                        case "filename":
                        {
                            string File = Path.CombineFile(TrainPath, Value);
                            if (System.IO.File.Exists(File))
                            {
                                System.Text.Encoding e = TextEncoding.GetSystemEncodingFromFile(File);
                                Plugin.currentHost.LoadObject(File, e, out var currentObject);
                                var a = (AnimatedObjectCollection)currentObject;
                                if (a != null)
                                {
                                    for (int i = 0; i < a.Objects.Length; i++)
                                    {
                                        Plugin.currentHost.CreateDynamicObject(ref a.Objects[i].internalObject);
                                    }
                                    CarSection.Groups[GroupIndex].Elements = a.Objects;
                                }
                                else
                                {
                                    Plugin.currentHost.AddMessage(MessageType.Error, false, "Value is invalid in " + Key + " in " + Section + " at line " + LineNumber.ToString(Culture) + " in " + FileName);
                                }
                            }
                        }
                        break;
                        }
                    }
                }
                break;
                }
            }
        }
Beispiel #22
0
 /// <summary>Loads a texture into an output parameter and returns the success of the operation.</summary>
 /// <param name="path">The file or folder where the texture is stored.</param>
 /// <param name="encoding">The suggested encoding in case the texture format does not mandate a specific encoding.</param>
 /// <param name="data">Optional data passed from another plugin. If you access this field, you must check the type before casting to that type.</param>
 /// <param name="texture">Receives the texture.</param>
 /// <returns>The success of the operation.</returns>
 public General.Result LoadTexture(Path.PathReference path, Encoding encoding, object data, out Texture.TextureData texture)
 {
     #if !DEBUG
     try {
         #endif
         string fileName = ((Path.FileReference)path).Path;
         if (System.IO.File.Exists(fileName)) {
             return Loader.LoadTexture(fileName, out texture);
         } else {
             texture = null;
             return OpenBveApi.General.Result.FileNotFound;
         }
         #if !DEBUG
     } catch {
         texture = null;
         return OpenBveApi.General.Result.InternalError;
     }
     #endif
 }
Beispiel #23
0
        private static void routeWorkerThread_completed(object sender, RunWorkerCompletedEventArgs e)
        {
            RoutefileState = RouteState.Processed;
            if (e.Error != null || Program.CurrentRoute == null)
            {
                Program.CurrentHost.RegisterTexture(Path.CombineFile(Program.FileSystem.DataFolder, "Menu\\route_error.png"), new TextureParameters(null, null), out routePictureBox.Texture);
                if (e.Error != null)
                {
                    routeDescriptionBox.Text = e.Error.Message;
                    RoutefileState           = RouteState.Error;
                }
                routeWorkerThread.Dispose();
                return;
            }
            try
            {
                // image
                if (!string.IsNullOrEmpty(Program.CurrentRoute.Image))
                {
                    try
                    {
                        if (File.Exists(Program.CurrentRoute.Image))
                        {
                            Program.CurrentHost.RegisterTexture(Program.CurrentRoute.Image, new TextureParameters(null, null), out routePictureBox.Texture);
                        }
                        else
                        {
                            Program.CurrentHost.RegisterTexture(Path.CombineFile(Program.FileSystem.DataFolder, "Menu\\route_unknown.png"), new TextureParameters(null, null), out routePictureBox.Texture);
                        }
                    }
                    catch
                    {
                        routePictureBox.Texture = null;
                    }
                }
                else
                {
                    string[] f = { ".png", ".bmp", ".gif", ".tiff", ".tif", ".jpeg", ".jpg" };
                    int      i;
                    for (i = 0; i < f.Length; i++)
                    {
                        string g = OpenBveApi.Path.CombineFile(System.IO.Path.GetDirectoryName(currentFile),
                                                               System.IO.Path.GetFileNameWithoutExtension(currentFile) + f[i]);
                        if (System.IO.File.Exists(g))
                        {
                            try
                            {
                                using (var fs = new FileStream(g, FileMode.Open, FileAccess.Read))
                                {
                                    //pictureboxRouteImage.Image = new Bitmap(fs);
                                }
                            }
                            catch
                            {
                                //pictureboxRouteImage.Image = null;
                            }
                            break;
                        }
                    }
                    if (i == f.Length)
                    {
                        Program.CurrentHost.RegisterTexture(Path.CombineFile(Program.FileSystem.DataFolder, "Menu\\route_unknown.png"), new TextureParameters(null, null), out routePictureBox.Texture);
                    }
                }

                // description
                string Description = Program.CurrentRoute.Comment.ConvertNewlinesToCrLf();
                if (Description.Length != 0)
                {
                    routeDescriptionBox.Text = Description;
                }
                else
                {
                    routeDescriptionBox.Text = System.IO.Path.GetFileNameWithoutExtension(currentFile);
                }
            }
            catch (Exception ex)
            {
                Program.CurrentHost.RegisterTexture(Path.CombineFile(Program.FileSystem.DataFolder, "Menu\\route_error.png"), new TextureParameters(null, null), out routePictureBox.Texture);
                routeDescriptionBox.Text = ex.Message;
                currentFile = null;
            }
        }
Beispiel #24
0
        private static void ParseExtensionsConfig(string filePath, Encoding encoding, out UnifiedObject[] carObjects, out UnifiedObject[] bogieObjects, out UnifiedObject[] couplerObjects, out double[] axleLocations, out double[] couplerDistances, out TrainManager.Train train, bool loadObjects)
        {
            CultureInfo culture = CultureInfo.InvariantCulture;

            carObjects       = new UnifiedObject[0];
            bogieObjects     = new UnifiedObject[0];
            couplerObjects   = new UnifiedObject[0];
            axleLocations    = new double[0];
            couplerDistances = new double[0];
            train            = new TrainManager.Train {
                Cars = new TrainManager.Car[0]
            };

            if (!File.Exists(filePath))
            {
                return;
            }

            bool[] carObjectsReversed   = new bool[0];
            bool[] bogieObjectsReversed = new bool[0];
            bool[] carsDefined          = new bool[0];
            bool[] bogiesDefined        = new bool[0];
            bool[] couplerDefined       = new bool[0];

            string trainPath = System.IO.Path.GetDirectoryName(filePath);

            if (encoding == null)
            {
                encoding = TextEncoding.GetSystemEncodingFromFile(trainPath);
            }

            string[] lines = File.ReadAllLines(filePath, encoding);
            for (int i = 0; i < lines.Length; i++)
            {
                int j = lines[i].IndexOf(';');
                if (j >= 0)
                {
                    lines[i] = lines[i].Substring(0, j).Trim(new char[] { });
                }
                else
                {
                    lines[i] = lines[i].Trim(new char[] { });
                }
            }

            for (int i = 0; i < lines.Length; i++)
            {
                if (lines[i].Length != 0)
                {
                    switch (lines[i].ToLowerInvariant())
                    {
                    case "[exterior]":
                        // exterior
                        i++;
                        while (i < lines.Length && !lines[i].StartsWith("[", StringComparison.Ordinal) & !lines[i].EndsWith("]", StringComparison.Ordinal))
                        {
                            if (lines[i].Length != 0)
                            {
                                int j = lines[i].IndexOf("=", StringComparison.Ordinal);
                                if (j >= 0)
                                {
                                    // ReSharper disable RedundantExplicitParamsArrayCreation
                                    string a = lines[i].Substring(0, j).TrimEnd(new char[] { });
                                    string b = lines[i].Substring(j + 1).TrimStart(new char[] { });
                                    // ReSharper restore RedundantExplicitParamsArrayCreation

                                    int n;
                                    if (int.TryParse(a, NumberStyles.Integer, culture, out n))
                                    {
                                        if (n >= 0)
                                        {
                                            if (n >= train.Cars.Length)
                                            {
                                                Array.Resize(ref train.Cars, n + 1);
                                                train.Cars[n] = new TrainManager.Car(train);
                                                Array.Resize(ref carObjects, n + 1);
                                                Array.Resize(ref bogieObjects, (n + 1) * 2);
                                                Array.Resize(ref couplerObjects, n);
                                                Array.Resize(ref carObjectsReversed, n + 1);
                                                Array.Resize(ref bogieObjectsReversed, (n + 1) * 2);
                                                Array.Resize(ref carsDefined, n + 1);
                                                Array.Resize(ref bogiesDefined, (n + 1) * 2);
                                                Array.Resize(ref couplerDefined, n);
                                                Array.Resize(ref axleLocations, (n + 1) * 2);
                                                Array.Resize(ref couplerDistances, n);
                                            }
                                            if (Path.ContainsInvalidChars(b))
                                            {
                                                Interface.AddMessage(MessageType.Error, false, $"File contains illegal characters at line {(i + 1).ToString(culture)} in file {filePath}");
                                            }
                                            else
                                            {
                                                string file = Path.CombineFile(trainPath, b);
                                                if (File.Exists(file))
                                                {
                                                    if (loadObjects)
                                                    {
                                                        Program.CurrentHost.LoadObject(file, encoding, out carObjects[n]);
                                                    }
                                                }
                                                else
                                                {
                                                    Interface.AddMessage(MessageType.Error, true, $"The car object {file} does not exist at line {(i + 1).ToString(culture)} in file {filePath}");
                                                }
                                            }
                                        }
                                        else
                                        {
                                            Interface.AddMessage(MessageType.Error, false, $"The car index {a} does not reference an existing car at line {(i + 1).ToString(culture)} in file {filePath}");
                                        }
                                    }
                                    else
                                    {
                                        Interface.AddMessage(MessageType.Error, false, $"The car index is expected to be an integer at line {(i + 1).ToString(culture)} in file {filePath}");
                                    }
                                }
                                else
                                {
                                    Interface.AddMessage(MessageType.Error, false, $"Invalid statement {lines[i]} encountered at line {(i + 1).ToString(culture)} in file {filePath}");
                                }
                            }
                            i++;
                        }
                        i--;
                        break;

                    default:
                        if (lines[i].StartsWith("[car", StringComparison.OrdinalIgnoreCase) & lines[i].EndsWith("]", StringComparison.Ordinal))
                        {
                            // car
                            string t = lines[i].Substring(4, lines[i].Length - 5);
                            int    n;
                            if (int.TryParse(t, NumberStyles.Integer, culture, out n))
                            {
                                if (n >= 0)
                                {
                                    if (n >= train.Cars.Length)
                                    {
                                        Array.Resize(ref train.Cars, n + 1);
                                        train.Cars[n] = new TrainManager.Car(train);
                                        Array.Resize(ref carObjects, n + 1);
                                        Array.Resize(ref bogieObjects, (n + 1) * 2);
                                        Array.Resize(ref carObjectsReversed, n + 1);
                                        Array.Resize(ref bogieObjectsReversed, (n + 1) * 2);
                                        Array.Resize(ref couplerObjects, n);
                                        Array.Resize(ref carsDefined, n + 1);
                                        Array.Resize(ref bogiesDefined, (n + 1) * 2);
                                        Array.Resize(ref couplerDefined, n);
                                        Array.Resize(ref axleLocations, (n + 1) * 2);
                                        Array.Resize(ref couplerDistances, n);
                                    }
                                    if (carsDefined[n])
                                    {
                                        Interface.AddMessage(MessageType.Error, false, $"Car {n.ToString(culture)} has already been declared at line {(i + 1).ToString(culture)} in file {filePath}");
                                    }
                                    carsDefined[n] = true;
                                    i++;
                                    while (i < lines.Length && !lines[i].StartsWith("[", StringComparison.Ordinal) & !lines[i].EndsWith("]", StringComparison.Ordinal))
                                    {
                                        if (lines[i].Length != 0)
                                        {
                                            int j = lines[i].IndexOf("=", StringComparison.Ordinal);
                                            if (j >= 0)
                                            {
                                                // ReSharper disable RedundantExplicitParamsArrayCreation
                                                string a = lines[i].Substring(0, j).TrimEnd(new char[] { });
                                                string b = lines[i].Substring(j + 1).TrimStart(new char[] { });
                                                // ReSharper restore RedundantExplicitParamsArrayCreation

                                                switch (a.ToLowerInvariant())
                                                {
                                                case "object":
                                                    if (string.IsNullOrEmpty(b))
                                                    {
                                                        Interface.AddMessage(MessageType.Error, true, $"An empty car object was supplied at line {(i + 1).ToString(culture)} in file {filePath}");
                                                        break;
                                                    }
                                                    if (Path.ContainsInvalidChars(b))
                                                    {
                                                        Interface.AddMessage(MessageType.Error, false, $"File contains illegal characters at line {(i + 1).ToString(culture)} in file {filePath}");
                                                    }
                                                    else
                                                    {
                                                        string file = Path.CombineFile(trainPath, b);
                                                        if (File.Exists(file))
                                                        {
                                                            if (loadObjects)
                                                            {
                                                                Program.CurrentHost.LoadObject(file, encoding, out carObjects[n]);
                                                            }
                                                        }
                                                        else
                                                        {
                                                            Interface.AddMessage(MessageType.Error, true, $"The car object {file} does not exist at line {(i + 1).ToString(culture)} in file {filePath}");
                                                        }
                                                    }
                                                    break;

                                                case "length":
                                                {
                                                    double m;
                                                    if (double.TryParse(b, NumberStyles.Float, culture, out m))
                                                    {
                                                        if (m > 0.0)
                                                        {
                                                            train.Cars[n].Length = m;
                                                        }
                                                        else
                                                        {
                                                            Interface.AddMessage(MessageType.Error, false, $"Value is expected to be a positive floating-point number in {a} at line {(i + 1).ToString(culture)} in file {filePath}");
                                                        }
                                                    }
                                                    else
                                                    {
                                                        Interface.AddMessage(MessageType.Error, false, $"Value is expected to be a positive floating-point number in {a} at line {(i + 1).ToString(culture)} in file {filePath}");
                                                    }
                                                }
                                                break;

                                                case "reversed":
                                                    carObjectsReversed[n] = b.Equals("true", StringComparison.OrdinalIgnoreCase);
                                                    break;

                                                case "axles":
                                                    int k = b.IndexOf(',');
                                                    if (k >= 0)
                                                    {
                                                        // ReSharper disable RedundantExplicitParamsArrayCreation
                                                        string c = b.Substring(0, k).TrimEnd(new char[] { });
                                                        string d = b.Substring(k + 1).TrimStart(new char[] { });
                                                        // ReSharper restore RedundantExplicitParamsArrayCreation

                                                        double rear, front;
                                                        if (!double.TryParse(c, NumberStyles.Float, culture, out rear))
                                                        {
                                                            Interface.AddMessage(MessageType.Error, false, $"Rear is expected to be a floating-point number in {a} at line {(i + 1).ToString(culture)} in file {filePath}");
                                                        }
                                                        else if (!double.TryParse(d, NumberStyles.Float, culture, out front))
                                                        {
                                                            Interface.AddMessage(MessageType.Error, false, $"Front is expected to be a floating-point number in {a} at line {(i + 1).ToString(culture)} in file {filePath}");
                                                        }
                                                        else if (rear >= front)
                                                        {
                                                            Interface.AddMessage(MessageType.Error, false, $"Rear is expected to be less than Front in {a} at line {(i + 1).ToString(culture)} in file {filePath}");
                                                        }
                                                        else
                                                        {
                                                            if (n == 0)
                                                            {
                                                                axleLocations[n]     = rear;
                                                                axleLocations[n + 1] = front;
                                                            }
                                                            else
                                                            {
                                                                axleLocations[n * 2]     = rear;
                                                                axleLocations[n * 2 + 1] = front;
                                                            }
                                                        }
                                                    }
                                                    else
                                                    {
                                                        Interface.AddMessage(MessageType.Error, false, $"An argument-separating comma is expected in {a} at line {(i + 1).ToString(culture)} in file {filePath}");
                                                    }
                                                    break;

                                                default:
                                                    Interface.AddMessage(MessageType.Warning, false, $"Unsupported key-value pair {a} encountered at line {(i + 1).ToString(culture)} in file {filePath}");
                                                    break;
                                                }
                                            }
                                            else
                                            {
                                                Interface.AddMessage(MessageType.Error, false, $"Invalid statement {lines[i]} encountered at line {(i + 1).ToString(culture)} in file {filePath}");
                                            }
                                        }
                                        i++;
                                    }
                                    i--;
                                }
                                else
                                {
                                    Interface.AddMessage(MessageType.Error, false, $"The car index {t} does not reference an existing car at line {(i + 1).ToString(culture)} in file {filePath}");
                                }
                            }
                            else
                            {
                                Interface.AddMessage(MessageType.Error, false, $"The car index is expected to be an integer at line {(i + 1).ToString(culture)} in file {filePath}");
                            }
                        }
                        else if (lines[i].StartsWith("[bogie", StringComparison.OrdinalIgnoreCase) & lines[i].EndsWith("]", StringComparison.Ordinal))
                        {
                            // bogie
                            string t = lines[i].Substring(6, lines[i].Length - 7);
                            int    n;
                            if (int.TryParse(t, NumberStyles.Integer, culture, out n))
                            {
                                if (n >= train.Cars.Length * 2)
                                {
                                    Array.Resize(ref train.Cars, n / 2 + 1);
                                    if (n == 0)
                                    {
                                        train.Cars[0] = new TrainManager.Car(train);
                                        Array.Resize(ref axleLocations, 2);
                                    }
                                    else
                                    {
                                        train.Cars[n / 2] = new TrainManager.Car(train);
                                        Array.Resize(ref axleLocations, (n / 2 + 1) * 2);
                                    }

                                    Array.Resize(ref carObjects, n / 2 + 1);
                                    Array.Resize(ref bogieObjects, n + 2);
                                    Array.Resize(ref couplerObjects, n / 2);
                                    Array.Resize(ref carObjectsReversed, n / 2 + 1);
                                    Array.Resize(ref bogieObjectsReversed, n + 2);
                                    Array.Resize(ref carsDefined, n / 2 + 1);
                                    Array.Resize(ref bogiesDefined, n + 2);
                                    Array.Resize(ref couplerDefined, n / 2);
                                    Array.Resize(ref couplerDistances, n / 2);
                                }

                                if (n > bogiesDefined.Length - 1)
                                {
                                    continue;
                                }
                                if (bogiesDefined[n])
                                {
                                    Interface.AddMessage(MessageType.Error, false, $"Bogie {n.ToString(culture)} has already been declared at line {(i + 1).ToString(culture)} in file {filePath}");
                                }
                                bogiesDefined[n] = true;
                                //Assuming that there are two bogies per car
                                if (n >= 0 & n < train.Cars.Length * 2)
                                {
                                    i++;
                                    while (i < lines.Length && !lines[i].StartsWith("[", StringComparison.Ordinal) & !lines[i].EndsWith("]", StringComparison.Ordinal))
                                    {
                                        if (lines[i].Length != 0)
                                        {
                                            int j = lines[i].IndexOf("=", StringComparison.Ordinal);
                                            if (j >= 0)
                                            {
                                                // ReSharper disable RedundantExplicitParamsArrayCreation
                                                string a = lines[i].Substring(0, j).TrimEnd(new char[] { });
                                                string b = lines[i].Substring(j + 1).TrimStart(new char[] { });
                                                // ReSharper restore RedundantExplicitParamsArrayCreation

                                                switch (a.ToLowerInvariant())
                                                {
                                                case "object":
                                                    if (Path.ContainsInvalidChars(b))
                                                    {
                                                        Interface.AddMessage(MessageType.Error, false, $"File contains illegal characters at line {(i + 1).ToString(culture)} in file {filePath}");
                                                    }
                                                    else
                                                    {
                                                        if (string.IsNullOrEmpty(b))
                                                        {
                                                            Interface.AddMessage(MessageType.Error, true, $"An empty bogie object was supplied at line {(i + 1).ToString(culture)} in file {filePath}");
                                                            break;
                                                        }
                                                        string file = Path.CombineFile(trainPath, b);
                                                        if (File.Exists(file))
                                                        {
                                                            if (loadObjects)
                                                            {
                                                                Program.CurrentHost.LoadObject(file, encoding, out bogieObjects[n]);
                                                            }
                                                        }
                                                        else
                                                        {
                                                            Interface.AddMessage(MessageType.Error, true, $"The bogie object {file} does not exist at line {(i + 1).ToString(culture)} in file {filePath}");
                                                        }
                                                    }
                                                    break;

                                                case "length":
                                                {
                                                    Interface.AddMessage(MessageType.Error, false, $"A defined length is not supported for bogies at line {(i + 1).ToString(culture)} in file {filePath}");
                                                }
                                                break;

                                                case "reversed":
                                                    bogieObjectsReversed[n] = b.Equals("true", StringComparison.OrdinalIgnoreCase);
                                                    break;

                                                case "axles":
                                                    //Axles aren't used in bogie positioning, just in rotation
                                                    break;

                                                default:
                                                    Interface.AddMessage(MessageType.Warning, false, $"Unsupported key-value pair {a} encountered at line {(i + 1).ToString(culture)} in file {filePath}");
                                                    break;
                                                }
                                            }
                                            else
                                            {
                                                Interface.AddMessage(MessageType.Error, false, $"Invalid statement {lines[i]} encountered at line {(i + 1).ToString(culture)} in file {filePath}");
                                            }
                                        }
                                        i++;
                                    }
                                    i--;
                                }
                                else
                                {
                                    Interface.AddMessage(MessageType.Error, false, $"The bogie index {t} does not reference an existing bogie at line {(i + 1).ToString(culture)} in file {filePath}");
                                }
                            }
                            else
                            {
                                Interface.AddMessage(MessageType.Error, false, $"The bogie index is expected to be an integer at line {(i + 1).ToString(culture)} in file {filePath}");
                            }
                        }
                        else if (lines[i].StartsWith("[coupler", StringComparison.OrdinalIgnoreCase) & lines[i].EndsWith("]", StringComparison.Ordinal))
                        {
                            // coupler
                            string t = lines[i].Substring(8, lines[i].Length - 9);
                            int    n;
                            if (int.TryParse(t, NumberStyles.Integer, culture, out n))
                            {
                                if (n >= 0)
                                {
                                    if (n >= train.Cars.Length - 1)
                                    {
                                        Array.Resize(ref train.Cars, n + 2);
                                        train.Cars[n + 1] = new TrainManager.Car(train);
                                        Array.Resize(ref carObjects, n + 2);
                                        Array.Resize(ref bogieObjects, (n + 2) * 2);
                                        Array.Resize(ref carObjectsReversed, n + 2);
                                        Array.Resize(ref bogieObjectsReversed, (n + 2) * 2);
                                        Array.Resize(ref couplerObjects, n + 1);
                                        Array.Resize(ref carsDefined, n + 2);
                                        Array.Resize(ref bogiesDefined, (n + 2) * 2);
                                        Array.Resize(ref couplerDefined, n + 1);
                                        Array.Resize(ref axleLocations, (n + 2) * 2);
                                        Array.Resize(ref couplerDistances, n + 1);
                                    }
                                    if (couplerDefined[n])
                                    {
                                        Interface.AddMessage(MessageType.Error, false, $"Coupler {n.ToString(culture)} has already been declared at line {(i + 1).ToString(culture)} in file {filePath}");
                                    }
                                    couplerDefined[n] = true;
                                    i++;
                                    while (i < lines.Length && !lines[i].StartsWith("[", StringComparison.Ordinal) & !lines[i].EndsWith("]", StringComparison.Ordinal))
                                    {
                                        if (lines[i].Length != 0)
                                        {
                                            int j = lines[i].IndexOf("=", StringComparison.Ordinal);
                                            if (j >= 0)
                                            {
                                                // ReSharper disable RedundantExplicitParamsArrayCreation
                                                string a = lines[i].Substring(0, j).TrimEnd(new char[] { });
                                                string b = lines[i].Substring(j + 1).TrimStart(new char[] { });
                                                // ReSharper restore RedundantExplicitParamsArrayCreation

                                                switch (a.ToLowerInvariant())
                                                {
                                                case "distances":
                                                {
                                                    int k = b.IndexOf(',');
                                                    if (k >= 0)
                                                    {
                                                        // ReSharper disable RedundantExplicitParamsArrayCreation
                                                        string c = b.Substring(0, k).TrimEnd(new char[] { });
                                                        string d = b.Substring(k + 1).TrimStart(new char[] { });
                                                        // ReSharper restore RedundantExplicitParamsArrayCreation

                                                        double min, max;
                                                        if (!double.TryParse(c, NumberStyles.Float, culture, out min))
                                                        {
                                                            Interface.AddMessage(MessageType.Error, false, $"Minimum is expected to be a floating-point number in {a} at line {(i + 1).ToString(culture)} in file {filePath}");
                                                        }
                                                        else if (!double.TryParse(d, NumberStyles.Float, culture, out max))
                                                        {
                                                            Interface.AddMessage(MessageType.Error, false, $"Maximum is expected to be a floating-point number in {a} at line {(i + 1).ToString(culture)} in file {filePath}");
                                                        }
                                                        else if (min > max)
                                                        {
                                                            Interface.AddMessage(MessageType.Error, false, $"Minimum is expected to be less than Maximum in {a} at line {(i + 1).ToString(culture)} in file {filePath}");
                                                        }
                                                        else
                                                        {
                                                            couplerDistances[n] = 0.5 * (min + max);
                                                        }
                                                    }
                                                    else
                                                    {
                                                        Interface.AddMessage(MessageType.Error, false, $"An argument-separating comma is expected in {a} at line {(i + 1).ToString(culture)} in file {filePath}");
                                                    }
                                                }
                                                break;

                                                case "object":
                                                    if (string.IsNullOrEmpty(b))
                                                    {
                                                        Interface.AddMessage(MessageType.Error, true, $"An empty coupler object was supplied at line {(i + 1).ToString(culture)} in file {filePath}");
                                                        break;
                                                    }
                                                    if (Path.ContainsInvalidChars(b))
                                                    {
                                                        Interface.AddMessage(MessageType.Error, false, $"File contains illegal characters at line {(i + 1).ToString(culture)} in file {filePath}");
                                                    }
                                                    else
                                                    {
                                                        string file = Path.CombineFile(trainPath, b);
                                                        if (File.Exists(file))
                                                        {
                                                            if (loadObjects)
                                                            {
                                                                Program.CurrentHost.LoadObject(file, encoding, out couplerObjects[n]);
                                                            }
                                                        }
                                                        else
                                                        {
                                                            Interface.AddMessage(MessageType.Error, true, $"The coupler object {file} does not exist at line {(i + 1).ToString(culture)} in file {filePath}");
                                                        }
                                                    }
                                                    break;

                                                default:
                                                    Interface.AddMessage(MessageType.Warning, false, $"Unsupported key-value pair {a} encountered at line {(i + 1).ToString(culture)} in file {filePath}");
                                                    break;
                                                }
                                            }
                                            else
                                            {
                                                Interface.AddMessage(MessageType.Error, false, $"Invalid statement {lines[i]} encountered at line {(i + 1).ToString(culture)} in file {filePath}");
                                            }
                                        }
                                        i++;
                                    }
                                    i--;
                                }
                                else
                                {
                                    Interface.AddMessage(MessageType.Error, false, $"The coupler index {t} does not reference an existing coupler at line {(i + 1).ToString(culture)} in file {filePath}");
                                }
                            }
                            else
                            {
                                Interface.AddMessage(MessageType.Error, false, $"The coupler index is expected to be an integer at line {(i + 1).ToString(culture)} in file {filePath}");
                            }
                        }
                        else
                        {
                            // default
                            if (lines.Length == 1 && encoding.Equals(Encoding.Unicode))
                            {
                                /*
                                 * If only one line, there's a good possibility that our file is NOT Unicode at all
                                 * and that the misdetection has turned it into garbage
                                 *
                                 * Try again with ASCII instead
                                 */
                                ParseExtensionsConfig(filePath, Encoding.GetEncoding(1252), out carObjects, out bogieObjects, out couplerObjects, out axleLocations, out couplerDistances, out train, loadObjects);
                                return;
                            }
                            Interface.AddMessage(MessageType.Error, false, $"Invalid statement {lines[i]} encountered at line {(i + 1).ToString(culture)} in file {filePath}");
                        }
                        break;
                    }
                }
            }

            // check for car objects and reverse if necessary
            int carObjectsCount = 0;

            for (int i = 0; i < train.Cars.Length; i++)
            {
                if (carObjects[i] != null)
                {
                    carObjectsCount++;
                    if (carObjectsReversed[i] && loadObjects)
                    {
                        if (carObjects[i] is StaticObject)
                        {
                            StaticObject obj = (StaticObject)carObjects[i];
                            obj.ApplyScale(-1.0, 1.0, -1.0);
                        }
                        else if (carObjects[i] is AnimatedObjectCollection)
                        {
                            AnimatedObjectCollection obj = (AnimatedObjectCollection)carObjects[i];
                            foreach (AnimatedObject animatedObj in obj.Objects)
                            {
                                foreach (ObjectState state in animatedObj.States)
                                {
                                    state.Prototype.ApplyScale(-1.0, 1.0, -1.0);
                                    Matrix4D t = state.Translation;
                                    t.Row3.X         *= -1.0f;
                                    t.Row3.Z         *= -1.0f;
                                    state.Translation = t;
                                }
                                animatedObj.TranslateXDirection.X *= -1.0;
                                animatedObj.TranslateXDirection.Z *= -1.0;
                                animatedObj.TranslateYDirection.X *= -1.0;
                                animatedObj.TranslateYDirection.Z *= -1.0;
                                animatedObj.TranslateZDirection.X *= -1.0;
                                animatedObj.TranslateZDirection.Z *= -1.0;
                            }
                        }
                        else
                        {
                            throw new NotImplementedException();
                        }
                    }
                }
            }

            //Check for bogie objects and reverse if necessary.....
            int bogieObjectsCount = 0;

            for (int i = 0; i < train.Cars.Length * 2; i++)
            {
                if (bogieObjects[i] != null)
                {
                    bogieObjectsCount++;
                    if (bogieObjectsReversed[i] && loadObjects)
                    {
                        if (bogieObjects[i] is StaticObject)
                        {
                            StaticObject obj = (StaticObject)bogieObjects[i];
                            obj.ApplyScale(-1.0, 1.0, -1.0);
                        }
                        else if (bogieObjects[i] is AnimatedObjectCollection)
                        {
                            AnimatedObjectCollection obj = (AnimatedObjectCollection)bogieObjects[i];
                            foreach (AnimatedObject animatedObj in obj.Objects)
                            {
                                foreach (ObjectState state in animatedObj.States)
                                {
                                    state.Prototype.ApplyScale(-1.0, 1.0, -1.0);
                                    Matrix4D t = state.Translation;
                                    t.Row3.X         *= -1.0f;
                                    t.Row3.Z         *= -1.0f;
                                    state.Translation = t;
                                }
                                animatedObj.TranslateXDirection.X *= -1.0;
                                animatedObj.TranslateXDirection.Z *= -1.0;
                                animatedObj.TranslateYDirection.X *= -1.0;
                                animatedObj.TranslateYDirection.Z *= -1.0;
                                animatedObj.TranslateZDirection.X *= -1.0;
                                animatedObj.TranslateZDirection.Z *= -1.0;
                            }
                        }
                        else
                        {
                            throw new NotImplementedException();
                        }
                    }
                }
            }

            if (carObjectsCount > 0 & carObjectsCount < train.Cars.Length)
            {
                Interface.AddMessage(MessageType.Warning, false, $"An incomplete set of exterior objects was provided in file {filePath}");
            }

            if (bogieObjectsCount > 0 & bogieObjectsCount < train.Cars.Length * 2)
            {
                Interface.AddMessage(MessageType.Warning, false, $"An incomplete set of bogie objects was provided in file {filePath}");
            }
        }
Beispiel #25
0
        public override bool LoadTrain(Encoding Encoding, string trainPath, ref AbstractTrain train, ref Control[] currentControls)
        {
            CurrentControls = currentControls;
            TrainBase currentTrain = train as TrainBase;

            if (currentTrain == null)
            {
                currentHost.ReportProblem(ProblemType.InvalidData, "Train was not valid");
                return(false);
            }

            if (currentTrain.State == TrainState.Bogus)
            {
                // bogus train
                string TrainData = Path.CombineFile(FileSystem.GetDataFolder("Compatibility", "PreTrain"), "train.dat");
                TrainDatParser.Parse(TrainData, Encoding.UTF8, currentTrain);
                Thread.Sleep(1);
                if (Cancel)
                {
                    return(false);
                }
            }
            else
            {
                currentTrain.TrainFolder = trainPath;
                // real train
                if (currentTrain.IsPlayerTrain)
                {
                    FileSystem.AppendToLogFile("Loading player train: " + currentTrain.TrainFolder);
                }
                else
                {
                    FileSystem.AppendToLogFile("Loading AI train: " + currentTrain.TrainFolder);
                }

                string TrainData = Path.CombineFile(currentTrain.TrainFolder, "train.dat");
                TrainDatParser.Parse(TrainData, Encoding, currentTrain);
                Thread.Sleep(1);
                if (Cancel)
                {
                    return(false);
                }
                SoundCfgParser.ParseSoundConfig(currentTrain);
                Thread.Sleep(1);
                if (Cancel)
                {
                    return(false);
                }
                // door open/close speed
                for (int i = 0; i < currentTrain.Cars.Length; i++)
                {
                    currentTrain.Cars[i].DetermineDoorClosingSpeed();
                }
            }
            // add panel section
            if (currentTrain.IsPlayerTrain)
            {
                ParsePanelConfig(currentTrain, Encoding);
                Thread.Sleep(1); if (Cancel)
                {
                    return(false);
                }
                FileSystem.AppendToLogFile("Train panel loaded sucessfully.");
            }
            // add exterior section
            if (currentTrain.State != TrainState.Bogus)
            {
                bool[]          VisibleFromInterior = new bool[currentTrain.Cars.Length];
                UnifiedObject[] CarObjects          = new UnifiedObject[currentTrain.Cars.Length];
                UnifiedObject[] BogieObjects        = new UnifiedObject[currentTrain.Cars.Length * 2];
                UnifiedObject[] CouplerObjects      = new UnifiedObject[currentTrain.Cars.Length];

                string tXml = Path.CombineFile(currentTrain.TrainFolder, "train.xml");
                if (File.Exists(tXml))
                {
                    TrainXmlParser.Parse(tXml, currentTrain, ref CarObjects, ref BogieObjects, ref CouplerObjects, ref VisibleFromInterior);
                }
                else
                {
                    ExtensionsCfgParser.ParseExtensionsConfig(currentTrain.TrainFolder, Encoding, ref CarObjects, ref BogieObjects, ref CouplerObjects, ref VisibleFromInterior, currentTrain);
                }

                currentTrain.CameraCar = currentTrain.DriverCar;
                Thread.Sleep(1);
                if (Cancel)
                {
                    return(false);
                }
                //Stores the current array index of the bogie object to add
                //Required as there are two bogies per car, and we're using a simple linear array....
                int currentBogieObject = 0;
                for (int i = 0; i < currentTrain.Cars.Length; i++)
                {
                    if (CarObjects[i] == null)
                    {
                        // load default exterior object
                        string       file = Path.CombineFile(FileSystem.GetDataFolder("Compatibility"), "exterior.csv");
                        StaticObject so;
                        currentHost.LoadStaticObject(file, Encoding.UTF8, false, out so);
                        if (so == null)
                        {
                            CarObjects[i] = null;
                        }
                        else
                        {
                            StaticObject c = (StaticObject)so.Clone();                              //Clone as otherwise the cached object doesn't scale right
                            c.ApplyScale(currentTrain.Cars[i].Width, currentTrain.Cars[i].Height, currentTrain.Cars[i].Length);
                            CarObjects[i] = c;
                        }
                    }

                    if (CarObjects[i] != null)
                    {
                        // add object
                        currentTrain.Cars[i].LoadCarSections(CarObjects[i], VisibleFromInterior[i]);
                    }

                    if (CouplerObjects[i] != null)
                    {
                        currentTrain.Cars[i].Coupler.LoadCarSections(CouplerObjects[i], VisibleFromInterior[i]);
                    }

                    //Load bogie objects
                    if (BogieObjects[currentBogieObject] != null)
                    {
                        currentTrain.Cars[i].FrontBogie.LoadCarSections(BogieObjects[currentBogieObject], VisibleFromInterior[i]);
                    }

                    currentBogieObject++;
                    if (BogieObjects[currentBogieObject] != null)
                    {
                        currentTrain.Cars[i].RearBogie.LoadCarSections(BogieObjects[currentBogieObject], VisibleFromInterior[i]);
                    }

                    currentBogieObject++;
                }
            }
            // place cars
            currentTrain.PlaceCars(0.0);
            currentControls = CurrentControls;
            return(true);
        }
Beispiel #26
0
        internal static void Parse(string fileName, Train train)
        {
            CultureInfo culture = CultureInfo.InvariantCulture;

            string[] lines = File.ReadAllLines(fileName, TextEncoding.GetSystemEncodingFromFile(fileName));

            for (int i = 0; i < lines.Length; i++)
            {
                int j = lines[i].IndexOf(';');

                if (j >= 0)
                {
                    lines[i] = lines[i].Substring(0, j).Trim();
                }
                else
                {
                    lines[i] = lines[i].Trim();
                }
            }

            for (int i = 0; i < lines.Length; i++)
            {
                if (lines[i].Any())
                {
                    switch (lines[i].ToLowerInvariant())
                    {
                    case "[exterior]":
                        i++;

                        while (i < lines.Length && !lines[i].StartsWith("[", StringComparison.Ordinal) & !lines[i].EndsWith("]", StringComparison.Ordinal))
                        {
                            if (lines[i].Any())
                            {
                                int j = lines[i].IndexOf("=", StringComparison.Ordinal);

                                if (j >= 0)
                                {
                                    string a = lines[i].Substring(0, j).TrimEnd();
                                    string b = lines[i].Substring(j + 1).TrimStart();
                                    int    n;

                                    if (int.TryParse(a, NumberStyles.Integer, culture, out n))
                                    {
                                        if (n >= 0)
                                        {
                                            for (int k = n; k >= train.Cars.Count; k--)
                                            {
                                                train.Cars.Add(new TrailerCar());
                                                train.Couplers.Add(new Coupler());

                                                train.ApplyPowerNotchesToCar();
                                                train.ApplyBrakeNotchesToCar();
                                                train.ApplyLocoBrakeNotchesToCar();
                                            }

                                            if (string.IsNullOrEmpty(b))
                                            {
                                                Interface.AddMessage(MessageType.Error, true, $"An empty car object was supplied at line {(i + 1).ToString(culture)} in file {fileName}");
                                            }
                                            else if (Path.ContainsInvalidChars(b))
                                            {
                                                Interface.AddMessage(MessageType.Error, false, $"File contains illegal characters at line {(i + 1).ToString(culture)} in file {fileName}");
                                            }
                                            else
                                            {
                                                string file = Path.CombineFile(System.IO.Path.GetDirectoryName(fileName), b);

                                                if (!File.Exists(file))
                                                {
                                                    Interface.AddMessage(MessageType.Warning, true, $"The car object {file} does not exist at line {(i + 1).ToString(culture)} in file {fileName}");
                                                }

                                                train.Cars[n].Object = file;
                                            }
                                        }
                                        else
                                        {
                                            Interface.AddMessage(MessageType.Error, false, $"The car index {n} does not reference an existing car at line {(i + 1).ToString(culture)} in file {fileName}");
                                        }
                                    }
                                    else
                                    {
                                        Interface.AddMessage(MessageType.Error, false, $"The car index is expected to be an integer at line {(i + 1).ToString(culture)} in file {fileName}");
                                    }
                                }
                                else
                                {
                                    Interface.AddMessage(MessageType.Error, false, $"Invalid statement {lines[i]} encountered at line {(i + 1).ToString(culture)} in file {fileName}");
                                }
                            }

                            i++;
                        }

                        i--;
                        break;

                    default:
                        if (lines[i].StartsWith("[car", StringComparison.OrdinalIgnoreCase) & lines[i].EndsWith("]", StringComparison.Ordinal))
                        {
                            // car
                            string t = lines[i].Substring(4, lines[i].Length - 5);
                            int    n;

                            if (int.TryParse(t, NumberStyles.Integer, culture, out n))
                            {
                                if (n >= 0)
                                {
                                    for (int j = n; j >= train.Cars.Count; j--)
                                    {
                                        train.Cars.Add(new TrailerCar());
                                        train.Couplers.Add(new Coupler());

                                        train.ApplyPowerNotchesToCar();
                                        train.ApplyBrakeNotchesToCar();
                                        train.ApplyLocoBrakeNotchesToCar();
                                    }

                                    i++;

                                    while (i < lines.Length && !lines[i].StartsWith("[", StringComparison.Ordinal) & !lines[i].EndsWith("]", StringComparison.Ordinal))
                                    {
                                        if (lines[i].Any())
                                        {
                                            int j = lines[i].IndexOf("=", StringComparison.Ordinal);

                                            if (j >= 0)
                                            {
                                                string a = lines[i].Substring(0, j).TrimEnd();
                                                string b = lines[i].Substring(j + 1).TrimStart();

                                                switch (a.ToLowerInvariant())
                                                {
                                                case "object":
                                                    if (string.IsNullOrEmpty(b))
                                                    {
                                                        Interface.AddMessage(MessageType.Error, true, $"An empty car object was supplied at line {(i + 1).ToString(culture)} in file {fileName}");
                                                    }
                                                    else if (Path.ContainsInvalidChars(b))
                                                    {
                                                        Interface.AddMessage(MessageType.Error, false, $"File contains illegal characters at line {(i + 1).ToString(culture)} in file {fileName}");
                                                    }
                                                    else
                                                    {
                                                        string file = Path.CombineFile(System.IO.Path.GetDirectoryName(fileName), b);

                                                        if (!File.Exists(file))
                                                        {
                                                            Interface.AddMessage(MessageType.Warning, true, $"The car object {file} does not exist at line {(i + 1).ToString(culture)} in file {fileName}");
                                                        }

                                                        train.Cars[n].Object = file;
                                                    }
                                                    break;

                                                case "length":
                                                {
                                                    double m;

                                                    if (double.TryParse(b, NumberStyles.Float, culture, out m))
                                                    {
                                                        if (m > 0.0)
                                                        {
                                                            train.Cars[n].Length = m;
                                                        }
                                                        else
                                                        {
                                                            Interface.AddMessage(MessageType.Error, false, $"Value is expected to be a positive floating-point number in {a} at line {(i + 1).ToString(culture)} in file {fileName}");
                                                        }
                                                    }
                                                    else
                                                    {
                                                        Interface.AddMessage(MessageType.Error, false, $"Value is expected to be a positive floating-point number in {a} at line {(i + 1).ToString(culture)} in file {fileName}");
                                                    }
                                                }
                                                break;

                                                case "axles":
                                                    int k = b.IndexOf(',');

                                                    if (k >= 0)
                                                    {
                                                        string c = b.Substring(0, k).TrimEnd();
                                                        string d = b.Substring(k + 1).TrimStart();
                                                        double rear, front;

                                                        if (!double.TryParse(c, NumberStyles.Float, culture, out rear))
                                                        {
                                                            Interface.AddMessage(MessageType.Error, false, $"Rear is expected to be a floating-point number in {a} at line {(i + 1).ToString(culture)} in file {fileName}");
                                                        }
                                                        else if (!double.TryParse(d, NumberStyles.Float, culture, out front))
                                                        {
                                                            Interface.AddMessage(MessageType.Error, false, $"Front is expected to be a floating-point number in {a} at line {(i + 1).ToString(culture)} in file {fileName}");
                                                        }
                                                        else if (rear >= front)
                                                        {
                                                            Interface.AddMessage(MessageType.Error, false, $"Rear is expected to be less than Front in {a} at line {(i + 1).ToString(culture)} in file {fileName}");
                                                        }
                                                        else
                                                        {
                                                            train.Cars[n].RearAxle     = rear;
                                                            train.Cars[n].FrontAxle    = front;
                                                            train.Cars[n].DefinedAxles = true;
                                                        }
                                                    }
                                                    else
                                                    {
                                                        Interface.AddMessage(MessageType.Error, false, $"An argument-separating comma is expected in {a} at line {(i + 1).ToString(culture)} in file {fileName}");
                                                    }
                                                    break;

                                                case "reversed":
                                                    train.Cars[n].Reversed = b.Equals("true", StringComparison.OrdinalIgnoreCase);
                                                    break;

                                                case "loadingsway":
                                                    train.Cars[n].LoadingSway = b.Equals("true", StringComparison.OrdinalIgnoreCase);
                                                    break;

                                                default:
                                                    Interface.AddMessage(MessageType.Warning, false, $"Unsupported key-value pair {a} encountered at line {(i + 1).ToString(culture)} in file {fileName}");
                                                    break;
                                                }
                                            }
                                        }

                                        i++;
                                    }

                                    i--;
                                }
                                else
                                {
                                    Interface.AddMessage(MessageType.Error, false, $"The car index {t} does not reference an existing car at line {(i + 1).ToString(culture)} in file {fileName}");
                                }
                            }
                            else
                            {
                                Interface.AddMessage(MessageType.Error, false, $"The car index is expected to be an integer at line {(i + 1).ToString(culture)} in file {fileName}");
                            }
                        }
                        else if (lines[i].StartsWith("[coupler", StringComparison.OrdinalIgnoreCase) & lines[i].EndsWith("]", StringComparison.Ordinal))
                        {
                            // coupler
                            string t = lines[i].Substring(8, lines[i].Length - 9);
                            int    n;

                            if (int.TryParse(t, NumberStyles.Integer, culture, out n))
                            {
                                if (n >= 0)
                                {
                                    for (int j = n; j >= train.Couplers.Count; j--)
                                    {
                                        train.Cars.Add(new TrailerCar());
                                        train.Couplers.Add(new Coupler());

                                        train.ApplyPowerNotchesToCar();
                                        train.ApplyBrakeNotchesToCar();
                                        train.ApplyLocoBrakeNotchesToCar();
                                    }

                                    i++;

                                    while (i < lines.Length && !lines[i].StartsWith("[", StringComparison.Ordinal) & !lines[i].EndsWith("]", StringComparison.Ordinal))
                                    {
                                        if (lines[i].Any())
                                        {
                                            int j = lines[i].IndexOf("=", StringComparison.Ordinal);

                                            if (j >= 0)
                                            {
                                                string a = lines[i].Substring(0, j).TrimEnd();
                                                string b = lines[i].Substring(j + 1).TrimStart();

                                                switch (a.ToLowerInvariant())
                                                {
                                                case "distances":
                                                {
                                                    int k = b.IndexOf(',');

                                                    if (k >= 0)
                                                    {
                                                        string c = b.Substring(0, k).TrimEnd();
                                                        string d = b.Substring(k + 1).TrimStart();
                                                        double min, max;

                                                        if (!double.TryParse(c, NumberStyles.Float, culture, out min))
                                                        {
                                                            Interface.AddMessage(MessageType.Error, false, $"Minimum is expected to be a floating-point number in {a} at line {(i + 1).ToString(culture)} in file {fileName}");
                                                        }
                                                        else if (!double.TryParse(d, NumberStyles.Float, culture, out max))
                                                        {
                                                            Interface.AddMessage(MessageType.Error, false, $"Maximum is expected to be a floating-point number in {a} at line {(i + 1).ToString(culture)} in file {fileName}");
                                                        }
                                                        else if (min > max)
                                                        {
                                                            Interface.AddMessage(MessageType.Error, false, $"Minimum is expected to be less than Maximum in {a} at line {(i + 1).ToString(culture)} in file {fileName}");
                                                        }
                                                        else
                                                        {
                                                            train.Couplers[n].Min = min;
                                                            train.Couplers[n].Max = max;
                                                        }
                                                    }
                                                    else
                                                    {
                                                        Interface.AddMessage(MessageType.Error, false, $"An argument-separating comma is expected in {a} at line {(i + 1).ToString(culture)} in file {fileName}");
                                                    }
                                                }
                                                break;

                                                case "object":
                                                    if (string.IsNullOrEmpty(b))
                                                    {
                                                        Interface.AddMessage(MessageType.Error, true, $"An empty coupler object was supplied at line {(i + 1).ToString(culture)} in file {fileName}");
                                                    }
                                                    else if (Path.ContainsInvalidChars(b))
                                                    {
                                                        Interface.AddMessage(MessageType.Error, false, $"File contains illegal characters at line {(i + 1).ToString(culture)} in file {fileName}");
                                                    }
                                                    else
                                                    {
                                                        string file = Path.CombineFile(System.IO.Path.GetDirectoryName(fileName), b);

                                                        if (!File.Exists(file))
                                                        {
                                                            Interface.AddMessage(MessageType.Warning, true, $"The coupler object {file} does not exist at line {(i + 1).ToString(culture)} in file {fileName}");
                                                        }

                                                        train.Couplers[n].Object = file;
                                                    }
                                                    break;

                                                default:
                                                    Interface.AddMessage(MessageType.Warning, false, $"Unsupported key-value pair {a} encountered at line {(i + 1).ToString(culture)} in file {fileName}");
                                                    break;
                                                }
                                            }
                                            else
                                            {
                                                Interface.AddMessage(MessageType.Error, false, $"Invalid statement {lines[i]} encountered at line {(i + 1).ToString(culture)} in file {fileName}");
                                            }
                                        }

                                        i++;
                                    }

                                    i--;
                                }
                                else
                                {
                                    Interface.AddMessage(MessageType.Error, false, $"The coupler index {t} does not reference an existing coupler at line {(i + 1).ToString(culture)} in file {fileName}");
                                }
                            }
                            else
                            {
                                Interface.AddMessage(MessageType.Error, false, $"The coupler index is expected to be an integer at line {(i + 1).ToString(culture)} in file {fileName}");
                            }
                        }
                        else if (lines[i].StartsWith("[bogie", StringComparison.OrdinalIgnoreCase) & lines[i].EndsWith("]", StringComparison.Ordinal))
                        {
                            // bogie
                            string t = lines[i].Substring(6, lines[i].Length - 7);
                            int    n;

                            if (int.TryParse(t, NumberStyles.Integer, culture, out n))
                            {
                                //Assuming that there are two bogies per car
                                bool IsOdd    = (n % 2 != 0);
                                int  CarIndex = n / 2;

                                if (n >= 0)
                                {
                                    for (int j = CarIndex; j >= train.Cars.Count; j--)
                                    {
                                        train.Cars.Add(new TrailerCar());
                                        train.Couplers.Add(new Coupler());

                                        train.ApplyPowerNotchesToCar();
                                        train.ApplyBrakeNotchesToCar();
                                        train.ApplyLocoBrakeNotchesToCar();
                                    }

                                    i++;

                                    while (i < lines.Length && !lines[i].StartsWith("[", StringComparison.Ordinal) & !lines[i].EndsWith("]", StringComparison.Ordinal))
                                    {
                                        if (lines[i].Any())
                                        {
                                            int j = lines[i].IndexOf("=", StringComparison.Ordinal);

                                            if (j >= 0)
                                            {
                                                string a = lines[i].Substring(0, j).TrimEnd();
                                                string b = lines[i].Substring(j + 1).TrimStart();

                                                switch (a.ToLowerInvariant())
                                                {
                                                case "object":
                                                    if (string.IsNullOrEmpty(b))
                                                    {
                                                        Interface.AddMessage(MessageType.Error, true, $"An empty bogie object was supplied at line {(i + 1).ToString(culture)} in file {fileName}");
                                                    }
                                                    else if (Path.ContainsInvalidChars(b))
                                                    {
                                                        Interface.AddMessage(MessageType.Error, false, $"File contains illegal characters at line {(i + 1).ToString(culture)} in file {fileName}");
                                                    }
                                                    else
                                                    {
                                                        string file = Path.CombineFile(System.IO.Path.GetDirectoryName(fileName), b);

                                                        if (!File.Exists(file))
                                                        {
                                                            Interface.AddMessage(MessageType.Warning, true, $"The bogie object {file} does not exist at line {(i + 1).ToString(culture)} in file {fileName}");
                                                        }

                                                        if (IsOdd)
                                                        {
                                                            train.Cars[CarIndex].RearBogie.Object = b;
                                                        }
                                                        else
                                                        {
                                                            train.Cars[CarIndex].FrontBogie.Object = b;
                                                        }
                                                    }
                                                    break;

                                                case "axles":
                                                    int k = b.IndexOf(',');

                                                    if (k >= 0)
                                                    {
                                                        string c = b.Substring(0, k).TrimEnd();
                                                        string d = b.Substring(k + 1).TrimStart();
                                                        double rear, front;

                                                        if (!double.TryParse(c, NumberStyles.Float, culture, out rear))
                                                        {
                                                            Interface.AddMessage(MessageType.Error, false, $"Rear is expected to be a floating-point number in {a} at line {(i + 1).ToString(culture)} in file {fileName}");
                                                        }
                                                        else if (!double.TryParse(d, NumberStyles.Float, culture, out front))
                                                        {
                                                            Interface.AddMessage(MessageType.Error, false, $"Front is expected to be a floating-point number in {a} at line {(i + 1).ToString(culture)} in file {fileName}");
                                                        }
                                                        else if (rear >= front)
                                                        {
                                                            Interface.AddMessage(MessageType.Error, false, $"Rear is expected to be less than Front in {a} at line {(i + 1).ToString(culture)} in file {fileName}");
                                                        }
                                                        else
                                                        {
                                                            if (IsOdd)
                                                            {
                                                                train.Cars[CarIndex].RearBogie.RearAxle     = rear;
                                                                train.Cars[CarIndex].RearBogie.FrontAxle    = front;
                                                                train.Cars[CarIndex].RearBogie.DefinedAxles = true;
                                                            }
                                                            else
                                                            {
                                                                train.Cars[CarIndex].FrontBogie.RearAxle     = rear;
                                                                train.Cars[CarIndex].FrontBogie.FrontAxle    = front;
                                                                train.Cars[CarIndex].FrontBogie.DefinedAxles = true;
                                                            }
                                                        }
                                                    }
                                                    else
                                                    {
                                                        Interface.AddMessage(MessageType.Error, false, $"An argument-separating comma is expected in {a} at line {(i + 1).ToString(culture)} in file {fileName}");
                                                    }
                                                    break;

                                                case "reversed":
                                                    if (IsOdd)
                                                    {
                                                        train.Cars[CarIndex].FrontBogie.Reversed = b.Equals("true", StringComparison.OrdinalIgnoreCase);
                                                    }
                                                    else
                                                    {
                                                        train.Cars[CarIndex].RearBogie.Reversed = b.Equals("true", StringComparison.OrdinalIgnoreCase);
                                                    }
                                                    break;

                                                default:
                                                    Interface.AddMessage(MessageType.Warning, false, $"Unsupported key-value pair {a} encountered at line {(i + 1).ToString(culture)} in file {fileName}");
                                                    break;
                                                }
                                            }
                                            else
                                            {
                                                Interface.AddMessage(MessageType.Error, false, $"Invalid statement {lines[i]} encountered at line {(i + 1).ToString(culture)} in file {fileName}");
                                            }
                                        }

                                        i++;
                                    }

                                    i--;
                                }
                                else
                                {
                                    Interface.AddMessage(MessageType.Error, false, $"The bogie index {t} does not reference an existing car at line {(i + 1).ToString(culture)} in file {fileName}");
                                }
                            }
                            else
                            {
                                Interface.AddMessage(MessageType.Error, false, $"The bogie index is expected to be an integer at line {(i + 1).ToString(culture)} in file {fileName}");
                            }
                        }
                        else
                        {
                            Interface.AddMessage(MessageType.Error, false, $"Invalid statement {lines[i]} encountered at line {(i + 1).ToString(culture)} in file {fileName}");
                        }
                        break;
                    }
                }
            }
        }