Example #1
0
        public override bool LoadObject(string path, System.Text.Encoding Encoding, out UnifiedObject Object)
        {
            if (base.LoadObject(path, Encoding, out Object))
            {
                return(true);
            }

            if (System.IO.File.Exists(path) || System.IO.Directory.Exists(path))
            {
                Encoding = TextEncoding.GetSystemEncodingFromFile(path, Encoding);

                for (int i = 0; i < Program.CurrentHost.Plugins.Length; i++)
                {
                    if (Program.CurrentHost.Plugins[i].Object != null)
                    {
                        try {
                            if (Program.CurrentHost.Plugins[i].Object.CanLoadObject(path))
                            {
                                try
                                {
                                    UnifiedObject obj;
                                    if (Program.CurrentHost.Plugins[i].Object.LoadObject(path, Encoding, out obj))
                                    {
                                        obj.OptimizeObject(false, Interface.CurrentOptions.ObjectOptimizationBasicThreshold, true);
                                        Object = obj;

                                        StaticObject staticObject = Object as StaticObject;
                                        if (staticObject != null)
                                        {
                                            StaticObjectCache.Add(ValueTuple.Create(path, false), staticObject);
                                            return(true);
                                        }

                                        AnimatedObjectCollection aoc = Object as AnimatedObjectCollection;
                                        if (aoc != null)
                                        {
                                            AnimatedObjectCollectionCache.Add(path, aoc);
                                        }

                                        return(true);
                                    }
                                    Interface.AddMessage(MessageType.Error, false, "Plugin " + Program.CurrentHost.Plugins[i].Title + " returned unsuccessfully at LoadObject");
                                } catch (Exception ex) {
                                    Interface.AddMessage(MessageType.Error, false, "Plugin " + Program.CurrentHost.Plugins[i].Title + " raised the following exception at LoadObject:" + ex.Message);
                                }
                            }
                        } catch (Exception ex) {
                            Interface.AddMessage(MessageType.Error, false, "Plugin " + Program.CurrentHost.Plugins[i].Title + " raised the following exception at CanLoadObject:" + ex.Message);
                        }
                    }
                }
                Interface.AddMessage(MessageType.Error, false, "No plugin found that is capable of loading object " + path);
            }
            else
            {
                ReportProblem(OpenBveApi.Hosts.ProblemType.PathNotFound, path);
            }
            Object = null;
            return(false);
        }
Example #2
0
        // load route
        internal static bool LoadRoute(Bitmap bitmap = null)
        {
            if (string.IsNullOrEmpty(CurrentRouteFile))
            {
                return(false);
            }
            Renderer.UpdateViewport();
            bool result;

            try
            {
                Encoding encoding = TextEncoding.GetSystemEncodingFromFile(CurrentRouteFile);
                Loading.Load(CurrentRouteFile, encoding, bitmap);
                result = true;
            } catch (Exception ex) {
                MessageBox.Show(ex.Message, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Hand);
                Game.Reset();
                result           = false;
                CurrentRouteFile = null;
            }

            if (Loading.Cancel)
            {
                result           = false;
                CurrentRouteFile = null;
            }
            Renderer.Lighting.Initialize();
            Renderer.InitializeVisibility();
            return(result);
        }
Example #3
0
 public override bool LoadStaticObject(string path, System.Text.Encoding Encoding, bool PreserveVertices, out StaticObject Object)
 {
     Encoding = TextEncoding.GetSystemEncodingFromFile(path, Encoding);
     if (System.IO.File.Exists(path) || System.IO.Directory.Exists(path))
     {
         for (int i = 0; i < Program.CurrentHost.Plugins.Length; i++)
         {
             if (Program.CurrentHost.Plugins[i].Object != null)
             {
                 try {
                     if (Program.CurrentHost.Plugins[i].Object.CanLoadObject(path))
                     {
                         try {
                             UnifiedObject unifiedObject;
                             if (Program.CurrentHost.Plugins[i].Object.LoadObject(path, Encoding, out unifiedObject))
                             {
                                 if (unifiedObject is StaticObject)
                                 {
                                     unifiedObject.OptimizeObject(PreserveVertices, Interface.CurrentOptions.ObjectOptimizationBasicThreshold, true);
                                     Object = (StaticObject)unifiedObject;
                                     return(true);
                                 }
                                 Object = null;
                                 Interface.AddMessage(MessageType.Error, false, "Attempted to load " + path + " which is an animated object where only static objects are allowed.");
                             }
                             Interface.AddMessage(MessageType.Error, false, "Plugin " + Program.CurrentHost.Plugins[i].Title + " returned unsuccessfully at LoadObject");
                         } catch (Exception ex) {
                             Interface.AddMessage(MessageType.Error, false, "Plugin " + Program.CurrentHost.Plugins[i].Title + " raised the following exception at LoadObject:" + ex.Message);
                         }
                     }
                 } catch (Exception ex) {
                     Interface.AddMessage(MessageType.Error, false, "Plugin " + Program.CurrentHost.Plugins[i].Title + " raised the following exception at CanLoadObject:" + ex.Message);
                 }
             }
         }
         Interface.AddMessage(MessageType.Error, false, "No plugin found that is capable of loading object " + path);
     }
     else
     {
         ReportProblem(OpenBveApi.Hosts.ProblemType.PathNotFound, path);
     }
     Object = null;
     return(false);
 }
        // parse extensions config
        internal void ParseExtensionsConfig(string TrainPath, System.Text.Encoding Encoding, ref UnifiedObject[] CarObjects, ref UnifiedObject[] BogieObjects, ref UnifiedObject[] CouplerObjects, ref bool[] VisibleFromInterior, TrainBase Train)
        {
            bool[] CarObjectsReversed   = new bool[Train.Cars.Length];
            bool[] BogieObjectsReversed = new bool[Train.Cars.Length * 2];

            bool[] CarsDefined   = new bool[Train.Cars.Length];
            bool[] BogiesDefined = new bool[Train.Cars.Length * 2];
            System.Globalization.CultureInfo Culture = System.Globalization.CultureInfo.InvariantCulture;
            string FileName = OpenBveApi.Path.CombineFile(TrainPath, "extensions.cfg");

            if (System.IO.File.Exists(FileName))
            {
                Encoding = TextEncoding.GetSystemEncodingFromFile(FileName, Encoding);

                string[] Lines = System.IO.File.ReadAllLines(FileName, 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)
                                    {
                                        string a = Lines[i].Substring(0, j).TrimEnd(new char[] { });
                                        string b = Lines[i].Substring(j + 1).TrimStart(new char[] { });
                                        int    n;
                                        if (int.TryParse(a, System.Globalization.NumberStyles.Integer, Culture, out n))
                                        {
                                            if (n >= 0 & n < Train.Cars.Length)
                                            {
                                                if (Path.ContainsInvalidChars(b))
                                                {
                                                    Plugin.currentHost.AddMessage(MessageType.Error, false, "File contains illegal characters at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                                }
                                                else
                                                {
                                                    string File = OpenBveApi.Path.CombineFile(TrainPath, b);
                                                    if (System.IO.File.Exists(File))
                                                    {
                                                        Plugin.currentHost.LoadObject(File, Encoding, out CarObjects[n]);
                                                    }
                                                    else
                                                    {
                                                        Plugin.currentHost.AddMessage(MessageType.Error, true, "The car object " + File + " does not exist at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                                    }
                                                }
                                            }
                                            else
                                            {
                                                Plugin.currentHost.AddMessage(MessageType.Error, false, "The car index " + a + " does not reference an existing car at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                            }
                                        }
                                        else
                                        {
                                            Plugin.currentHost.AddMessage(MessageType.Error, false, "The car index is expected to be an integer at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                        }
                                    }
                                    else
                                    {
                                        Plugin.currentHost.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, System.Globalization.NumberStyles.Integer, Culture, out n))
                                {
                                    if (n >= 0 & n < Train.Cars.Length)
                                    {
                                        if (CarsDefined[n])
                                        {
                                            Plugin.currentHost.AddMessage(MessageType.Error, false, "Car " + n.ToString(Culture) + " has already been declared at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                        }
                                        CarsDefined[n] = true;
                                        bool DefinedLength = false;
                                        bool DefinedAxles  = false;
                                        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)
                                                {
                                                    string a = Lines[i].Substring(0, j).TrimEnd(new char[] { });
                                                    string b = Lines[i].Substring(j + 1).TrimStart(new char[] { });
                                                    switch (a.ToLowerInvariant())
                                                    {
                                                    case "object":
                                                        if (string.IsNullOrEmpty(b))
                                                        {
                                                            Plugin.currentHost.AddMessage(MessageType.Error, true, "An empty car object was supplied at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                                            break;
                                                        }
                                                        if (Path.ContainsInvalidChars(b))
                                                        {
                                                            Plugin.currentHost.AddMessage(MessageType.Error, false, "File contains illegal characters at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                                        }
                                                        else
                                                        {
                                                            string File = OpenBveApi.Path.CombineFile(TrainPath, b);
                                                            if (System.IO.File.Exists(File))
                                                            {
                                                                Plugin.currentHost.LoadObject(File, Encoding, out CarObjects[n]);
                                                            }
                                                            else
                                                            {
                                                                Plugin.currentHost.AddMessage(MessageType.Error, true, "The car object " + File + " does not exist at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                                            }
                                                        }
                                                        break;

                                                    case "length":
                                                    {
                                                        double m;
                                                        if (double.TryParse(b, System.Globalization.NumberStyles.Float, Culture, out m))
                                                        {
                                                            if (m > 0.0)
                                                            {
                                                                Train.Cars[n].Length = m;
                                                                Train.Cars[n].BeaconReceiverPosition = 0.5 * m;
                                                                DefinedLength = true;
                                                            }
                                                            else
                                                            {
                                                                Plugin.currentHost.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
                                                        {
                                                            Plugin.currentHost.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(new char[] { });
                                                            string d = b.Substring(k + 1).TrimStart(new char[] { });
                                                            double rear, front;
                                                            if (!double.TryParse(c, System.Globalization.NumberStyles.Float, Culture, out rear))
                                                            {
                                                                Plugin.currentHost.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, System.Globalization.NumberStyles.Float, Culture, out front))
                                                            {
                                                                Plugin.currentHost.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)
                                                            {
                                                                Plugin.currentHost.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.Position  = rear;
                                                                Train.Cars[n].FrontAxle.Position = front;
                                                                DefinedAxles = true;
                                                            }
                                                        }
                                                        else
                                                        {
                                                            Plugin.currentHost.AddMessage(MessageType.Error, false, "An argument-separating comma is expected in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                                        }
                                                    }
                                                    break;

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

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

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

                                                    default:
                                                        Plugin.currentHost.AddMessage(MessageType.Warning, false, "Unsupported key-value pair " + a + " encountered at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                                        break;
                                                    }
                                                }
                                                else
                                                {
                                                    Plugin.currentHost.AddMessage(MessageType.Error, false, "Invalid statement " + Lines[i] + " encountered at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                                }
                                            }
                                            i++;
                                        }
                                        i--;
                                        if (DefinedLength & !DefinedAxles)
                                        {
                                            double AxleDistance = 0.4 * Train.Cars[n].Length;
                                            Train.Cars[n].RearAxle.Position  = -AxleDistance;
                                            Train.Cars[n].FrontAxle.Position = AxleDistance;
                                        }
                                    }
                                    else
                                    {
                                        Plugin.currentHost.AddMessage(MessageType.Error, false, "The car index " + t + " does not reference an existing car at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                    }
                                }
                                else
                                {
                                    Plugin.currentHost.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, System.Globalization.NumberStyles.Integer, Culture, out n))
                                {
                                    if (n >= 0 & n < Train.Cars.Length - 1)
                                    {
                                        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)
                                                {
                                                    string a = Lines[i].Substring(0, j).TrimEnd(new char[] { });
                                                    string b = Lines[i].Substring(j + 1).TrimStart(new char[] { });
                                                    switch (a.ToLowerInvariant())
                                                    {
                                                    case "distances":
                                                    {
                                                        int k = b.IndexOf(',');
                                                        if (k >= 0)
                                                        {
                                                            string c = b.Substring(0, k).TrimEnd(new char[] { });
                                                            string d = b.Substring(k + 1).TrimStart(new char[] { });
                                                            double min, max;
                                                            if (!double.TryParse(c, System.Globalization.NumberStyles.Float, Culture, out min))
                                                            {
                                                                Plugin.currentHost.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, System.Globalization.NumberStyles.Float, Culture, out max))
                                                            {
                                                                Plugin.currentHost.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)
                                                            {
                                                                Plugin.currentHost.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.Cars[n].Coupler.MinimumDistanceBetweenCars = min;
                                                                Train.Cars[n].Coupler.MaximumDistanceBetweenCars = max;
                                                            }
                                                        }
                                                        else
                                                        {
                                                            Plugin.currentHost.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))
                                                        {
                                                            Plugin.currentHost.AddMessage(MessageType.Error, true, "An empty coupler object was supplied at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                                            break;
                                                        }
                                                        if (Path.ContainsInvalidChars(b))
                                                        {
                                                            Plugin.currentHost.AddMessage(MessageType.Error, false, "File contains illegal characters at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                                        }
                                                        else
                                                        {
                                                            string File = OpenBveApi.Path.CombineFile(TrainPath, b);
                                                            if (System.IO.File.Exists(File))
                                                            {
                                                                Plugin.currentHost.LoadObject(File, Encoding, out CouplerObjects[n]);
                                                            }
                                                            else
                                                            {
                                                                Plugin.currentHost.AddMessage(MessageType.Error, true, "The coupler object " + File + " does not exist at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                                            }
                                                        }
                                                        break;

                                                    default:
                                                        Plugin.currentHost.AddMessage(MessageType.Warning, false, "Unsupported key-value pair " + a + " encountered at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                                        break;
                                                    }
                                                }
                                                else
                                                {
                                                    Plugin.currentHost.AddMessage(MessageType.Error, false, "Invalid statement " + Lines[i] + " encountered at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                                }
                                            }
                                            i++;
                                        }
                                        i--;
                                    }
                                    else
                                    {
                                        Plugin.currentHost.AddMessage(MessageType.Error, false, "The coupler index " + t + " does not reference an existing coupler at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                    }
                                }
                                else
                                {
                                    Plugin.currentHost.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))
                            {
                                // car
                                string t = Lines[i].Substring(6, Lines[i].Length - 7);
                                int    n; if (int.TryParse(t, System.Globalization.NumberStyles.Integer, Culture, out n))
                                {
                                    if (n > BogiesDefined.Length - 1)
                                    {
                                        continue;
                                    }
                                    if (BogiesDefined[n])
                                    {
                                        Plugin.currentHost.AddMessage(MessageType.Error, false, "Bogie " + n.ToString(Culture) + " has already been declared at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                    }
                                    BogiesDefined[n] = true;
                                    //Assuming that there are two bogies per car
                                    bool IsOdd    = (n % 2 != 0);
                                    int  CarIndex = n / 2;
                                    if (n >= 0 & n < Train.Cars.Length * 2)
                                    {
                                        bool DefinedAxles = false;
                                        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)
                                                {
                                                    string a = Lines[i].Substring(0, j).TrimEnd(new char[] { });
                                                    string b = Lines[i].Substring(j + 1).TrimStart(new char[] { });
                                                    switch (a.ToLowerInvariant())
                                                    {
                                                    case "object":
                                                        if (Path.ContainsInvalidChars(b))
                                                        {
                                                            Plugin.currentHost.AddMessage(MessageType.Error, false, "File contains illegal characters at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                                        }
                                                        else
                                                        {
                                                            if (string.IsNullOrEmpty(b))
                                                            {
                                                                Plugin.currentHost.AddMessage(MessageType.Error, true, "An empty bogie object was supplied at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                                                break;
                                                            }
                                                            string File = OpenBveApi.Path.CombineFile(TrainPath, b);
                                                            if (System.IO.File.Exists(File))
                                                            {
                                                                Plugin.currentHost.LoadObject(File, Encoding, out BogieObjects[n]);
                                                            }
                                                            else
                                                            {
                                                                Plugin.currentHost.AddMessage(MessageType.Error, true, "The bogie object " + File + " does not exist at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                                            }
                                                        }
                                                        break;

                                                    case "length":
                                                    {
                                                        Plugin.currentHost.AddMessage(MessageType.Error, false, "A defined length is not supported for bogies 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(new char[] { });
                                                            string d = b.Substring(k + 1).TrimStart(new char[] { });
                                                            double rear, front;
                                                            if (!double.TryParse(c, System.Globalization.NumberStyles.Float, Culture, out rear))
                                                            {
                                                                Plugin.currentHost.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, System.Globalization.NumberStyles.Float, Culture, out front))
                                                            {
                                                                Plugin.currentHost.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)
                                                            {
                                                                Plugin.currentHost.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].FrontBogie.RearAxle.Position  = rear;
                                                                    Train.Cars[CarIndex].FrontBogie.FrontAxle.Position = front;
                                                                }
                                                                else
                                                                {
                                                                    Train.Cars[CarIndex].RearBogie.RearAxle.Position  = rear;
                                                                    Train.Cars[CarIndex].RearBogie.FrontAxle.Position = front;
                                                                }
                                                                DefinedAxles = true;
                                                            }
                                                        }
                                                        else
                                                        {
                                                            Plugin.currentHost.AddMessage(MessageType.Error, false, "An argument-separating comma is expected in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                                        }
                                                    }
                                                    break;

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

                                                    default:
                                                        Plugin.currentHost.AddMessage(MessageType.Warning, false, "Unsupported key-value pair " + a + " encountered at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                                        break;
                                                    }
                                                }
                                                else
                                                {
                                                    Plugin.currentHost.AddMessage(MessageType.Error, false, "Invalid statement " + Lines[i] + " encountered at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                                }
                                            }
                                            i++;
                                        }
                                        i--;
                                        if (!DefinedAxles)
                                        {
                                            if (IsOdd)
                                            {
                                                double AxleDistance = 0.4 * Train.Cars[CarIndex].FrontBogie.Length;
                                                Train.Cars[CarIndex].FrontBogie.RearAxle.Position  = -AxleDistance;
                                                Train.Cars[CarIndex].FrontBogie.FrontAxle.Position = AxleDistance;
                                            }
                                            else
                                            {
                                                double AxleDistance = 0.4 * Train.Cars[CarIndex].RearBogie.Length;
                                                Train.Cars[CarIndex].RearBogie.RearAxle.Position  = -AxleDistance;
                                                Train.Cars[CarIndex].RearBogie.FrontAxle.Position = AxleDistance;
                                            }
                                        }
                                    }
                                    else
                                    {
                                        Plugin.currentHost.AddMessage(MessageType.Error, false, "The car index " + t + " does not reference an existing car at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                    }
                                }
                                else
                                {
                                    Plugin.currentHost.AddMessage(MessageType.Error, false, "The car index is expected to be an integer at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                }
                            }
                            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(TrainPath, Encoding.GetEncoding(1252), ref CarObjects, ref BogieObjects, ref CouplerObjects, ref VisibleFromInterior, Train);
                                    return;
                                }
                                Plugin.currentHost.AddMessage(MessageType.Error, false, "Invalid statement " + Lines[i] + " encountered at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                            }
                            break;
                        }
                    }
                }

                // check for car objects and reverse if necessary
                int carObjects = 0;
                for (int i = 0; i < Train.Cars.Length; i++)
                {
                    if (CarObjects[i] != null)
                    {
                        carObjects++;
                        if (CarObjectsReversed[i])
                        {
                            {
                                // reverse axle positions
                                double temp = Train.Cars[i].FrontAxle.Position;
                                Train.Cars[i].FrontAxle.Position = -Train.Cars[i].RearAxle.Position;
                                Train.Cars[i].RearAxle.Position  = -temp;
                            }
                            if (CarObjects[i] is StaticObject)
                            {
                                StaticObject obj = (StaticObject)CarObjects[i].Clone();
                                obj.ApplyScale(-1.0, 1.0, -1.0);
                                CarObjects[i] = obj;
                            }
                            else if (CarObjects[i] is AnimatedObjectCollection)
                            {
                                AnimatedObjectCollection obj = (AnimatedObjectCollection)CarObjects[i].Clone();
                                obj.Reverse();
                                CarObjects[i] = obj;
                            }
                            else
                            {
                                throw new NotImplementedException();
                            }
                        }
                    }
                }

                //Check for bogie objects and reverse if necessary.....
                int bogieObjects = 0;
                for (int i = 0; i < Train.Cars.Length * 2; i++)
                {
                    bool IsOdd    = (i % 2 != 0);
                    int  CarIndex = i / 2;
                    if (BogieObjects[i] != null)
                    {
                        bogieObjects++;
                        if (BogieObjectsReversed[i])
                        {
                            {
                                // reverse axle positions
                                if (IsOdd)
                                {
                                    double temp = Train.Cars[CarIndex].FrontBogie.FrontAxle.Position;
                                    Train.Cars[CarIndex].FrontBogie.FrontAxle.Position = -Train.Cars[CarIndex].FrontBogie.RearAxle.Position;
                                    Train.Cars[CarIndex].FrontBogie.RearAxle.Position  = -temp;
                                }
                                else
                                {
                                    double temp = Train.Cars[CarIndex].RearBogie.FrontAxle.Position;
                                    Train.Cars[CarIndex].RearBogie.FrontAxle.Position = -Train.Cars[CarIndex].RearBogie.RearAxle.Position;
                                    Train.Cars[CarIndex].RearBogie.RearAxle.Position  = -temp;
                                }
                            }
                            if (BogieObjects[i] is StaticObject)
                            {
                                StaticObject obj = (StaticObject)BogieObjects[i].Clone();
                                obj.ApplyScale(-1.0, 1.0, -1.0);
                                BogieObjects[i] = obj;
                            }
                            else if (BogieObjects[i] is AnimatedObjectCollection)
                            {
                                AnimatedObjectCollection obj = (AnimatedObjectCollection)BogieObjects[i].Clone();
                                obj.Reverse();
                                BogieObjects[i] = obj;
                            }
                            else
                            {
                                throw new NotImplementedException();
                            }
                        }
                    }
                }

                if (carObjects > 0 & carObjects < Train.Cars.Length)
                {
                    Plugin.currentHost.AddMessage(MessageType.Warning, false, "An incomplete set of exterior objects was provided in file " + FileName);
                }

                if (bogieObjects > 0 & bogieObjects < Train.Cars.Length * 2)
                {
                    Plugin.currentHost.AddMessage(MessageType.Warning, false, "An incomplete set of bogie objects was provided in file " + FileName);
                }
            }
        }
Example #5
0
        /// <summary>Loads the sound set for a BVE4 or openBVE sound.cfg based train</summary>
        /// <param name="train">The train</param>
        /// <param name="FileName">The absolute on-disk path to the sound.cfg file</param>
        /// <param name="trainFolder">The absolute on-disk path to the train's folder</param>
        internal void Parse(string FileName, string trainFolder, TrainBase train)
        {
            //Default sound positions and radii

            //3D center of the car
            Vector3 center = Vector3.Zero;
            //Positioned to the left of the car, but centered Y & Z
            Vector3 left = new Vector3(-1.3, 0.0, 0.0);
            //Positioned to the right of the car, but centered Y & Z
            Vector3 right = new Vector3(1.3, 0.0, 0.0);
            //Positioned at the front of the car, centered X and Y
            Vector3 front = new Vector3(0.0, 0.0, 0.5 * train.Cars[train.DriverCar].Length);
            //Positioned at the position of the panel / 3D cab (Remember that the panel is just an object in the world...)
            Vector3 panel = new Vector3(train.Cars[train.DriverCar].Driver.X, train.Cars[train.DriverCar].Driver.Y, train.Cars[train.DriverCar].Driver.Z + 1.0);

            //Radius at which the sound is audible at full volume, presumably in m
            //TODO: All radii are much too small in external mode, but we can't change them by default.....

            Encoding Encoding = TextEncoding.GetSystemEncodingFromFile(FileName);

            // parse configuration file
            System.Globalization.CultureInfo Culture = System.Globalization.CultureInfo.InvariantCulture;
            List <string> Lines = System.IO.File.ReadAllLines(FileName, Encoding).ToList();

            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(new char[] { });
                }
                else
                {
                    Lines[i] = Lines[i].Trim(new char[] { });
                }
                if (string.IsNullOrEmpty(Lines[i]))
                {
                    Lines.RemoveAt(i);
                }
            }

            if (Lines.Count == 0)
            {
                Plugin.currentHost.AddMessage(MessageType.Error, false, "Empty sound.cfg encountered in " + FileName + ".");
            }
            else if (string.Compare(Lines[0], "version 1.0", StringComparison.OrdinalIgnoreCase) != 0)
            {
                Plugin.currentHost.AddMessage(MessageType.Error, false, "Invalid file format encountered in " + FileName + ". The first line is expected to be \"Version 1.0\".");
            }
            string[] MotorFiles = new string[] { };
            double   invfac     = Lines.Count == 0 ? 1.0 : 1.0 / Lines.Count;

            for (int i = 0; i < Lines.Count; i++)
            {
                Plugin.CurrentProgress = Plugin.CurrentProgress + invfac * i;
                if ((i & 7) == 0)
                {
                    System.Threading.Thread.Sleep(1);
                    if (Plugin.Cancel)
                    {
                        return;
                    }
                }
                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(new char[] { });
                            string b = Lines[i].Substring(j + 1).TrimStart(new char[] { });
                            int    k;
                            if (!int.TryParse(a, System.Globalization.NumberStyles.Integer, Culture, out k))
                            {
                                Plugin.currentHost.AddMessage(MessageType.Error, false, "Invalid index appeared at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                            }
                            else
                            {
                                if (k >= 0)
                                {
                                    for (int c = 0; c < train.Cars.Length; c++)
                                    {
                                        if (train.Cars[c].Sounds.Run == null)
                                        {
                                            train.Cars[c].Sounds.Run = new Dictionary <int, CarSound>();
                                        }

                                        if (train.Cars[c].Sounds.Run.ContainsKey(k))
                                        {
                                            train.Cars[c].Sounds.Run[k] = new CarSound(Plugin.currentHost, trainFolder, FileName, i, b, SoundCfgParser.mediumRadius, center);
                                        }
                                        else
                                        {
                                            train.Cars[c].Sounds.Run.Add(k, new CarSound(Plugin.currentHost, trainFolder, FileName, i, b, SoundCfgParser.mediumRadius, center));
                                        }
                                    }
                                }
                                else
                                {
                                    Plugin.currentHost.AddMessage(MessageType.Error, false, "RunIndex must be greater than 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(new char[] { });
                            string b = Lines[i].Substring(j + 1).TrimStart(new char[] { });
                            int    k;
                            if (!int.TryParse(a, System.Globalization.NumberStyles.Integer, Culture, out k))
                            {
                                Plugin.currentHost.AddMessage(MessageType.Error, false, "Invalid index appeared at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                            }
                            else
                            {
                                if (k >= 0)
                                {
                                    for (int c = 0; c < train.Cars.Length; c++)
                                    {
                                        if (train.Cars[c].Sounds.Flange.ContainsKey(k))
                                        {
                                            train.Cars[c].Sounds.Flange[k] = new CarSound(Plugin.currentHost, trainFolder, FileName, i, b, SoundCfgParser.mediumRadius, center);
                                        }
                                        else
                                        {
                                            train.Cars[c].Sounds.Flange.Add(k, new CarSound(Plugin.currentHost, trainFolder, FileName, i, b, SoundCfgParser.mediumRadius, center));
                                        }
                                    }
                                }
                                else
                                {
                                    Plugin.currentHost.AddMessage(MessageType.Error, false, "FlangeIndex must be greater than 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(new char[] { });
                            string b = Lines[i].Substring(j + 1).TrimStart(new char[] { });
                            int    k;
                            if (!int.TryParse(a, System.Globalization.NumberStyles.Integer, Culture, out k))
                            {
                                Plugin.currentHost.AddMessage(MessageType.Error, false, "Invalid index appeared at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                            }
                            else
                            {
                                if (k >= 0)
                                {
                                    if (k >= MotorFiles.Length)
                                    {
                                        Array.Resize(ref MotorFiles, k + 1);
                                    }
                                    MotorFiles[k] = Path.CombineFile(trainFolder, b);
                                    if (!System.IO.File.Exists(MotorFiles[k]))
                                    {
                                        Plugin.currentHost.AddMessage(MessageType.Error, true, "File " + MotorFiles[k] + " does not exist at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                        MotorFiles[k] = null;
                                    }
                                }
                                else
                                {
                                    Plugin.currentHost.AddMessage(MessageType.Error, false, "MotorIndex must be greater than or equal to zero 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(new char[] { });
                            string b = Lines[i].Substring(j + 1).TrimStart(new char[] { });
                            int    switchIndex;
                            if (NumberFormats.TryParseIntVb6(a, out switchIndex))
                            {
                                if (switchIndex < 0)
                                {
                                    Plugin.currentHost.AddMessage(MessageType.Error, false, "SwitchIndex must be greater than or equal to zero at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                    continue;
                                }
                                for (int c = 0; c < train.Cars.Length; c++)
                                {
                                    int n = train.Cars[c].FrontAxle.PointSounds.Length;
                                    if (switchIndex >= n)
                                    {
                                        Array.Resize(ref train.Cars[c].FrontAxle.PointSounds, switchIndex + 1);
                                        Array.Resize(ref train.Cars[c].RearAxle.PointSounds, switchIndex + 1);
                                        for (int h = n; h < switchIndex; h++)
                                        {
                                            train.Cars[c].FrontAxle.PointSounds[h] = new CarSound();
                                            train.Cars[c].RearAxle.PointSounds[h]  = new CarSound();
                                        }
                                    }
                                    Vector3 frontaxle = new Vector3(0.0, 0.0, train.Cars[c].FrontAxle.Position);
                                    Vector3 rearaxle  = new Vector3(0.0, 0.0, train.Cars[c].RearAxle.Position);
                                    train.Cars[c].FrontAxle.PointSounds[switchIndex] = new CarSound(Plugin.currentHost, trainFolder, FileName, i, b, SoundCfgParser.smallRadius, frontaxle);
                                    train.Cars[c].RearAxle.PointSounds[switchIndex]  = new CarSound(Plugin.currentHost, trainFolder, FileName, i, b, SoundCfgParser.smallRadius, rearaxle);
                                }
                            }
                            else
                            {
                                Plugin.currentHost.AddMessage(MessageType.Warning, false, "Unsupported index " + a + " encountered 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(new char[] { });
                            string b = Lines[i].Substring(j + 1).TrimStart(new char[] { });
                            switch (a.ToLowerInvariant())
                            {
                            case "bc release high":
                                for (int c = 0; c < train.Cars.Length; c++)
                                {
                                    train.Cars[c].CarBrake.AirHigh = new CarSound(Plugin.currentHost, trainFolder, FileName, i, b, SoundCfgParser.smallRadius, center);
                                }

                                break;

                            case "bc release":
                                for (int c = 0; c < train.Cars.Length; c++)
                                {
                                    train.Cars[c].CarBrake.Air = new CarSound(Plugin.currentHost, trainFolder, FileName, i, b, SoundCfgParser.smallRadius, center);
                                }

                                break;

                            case "bc release full":
                                for (int c = 0; c < train.Cars.Length; c++)
                                {
                                    train.Cars[c].CarBrake.AirZero = new CarSound(Plugin.currentHost, trainFolder, FileName, i, b, SoundCfgParser.smallRadius, center);
                                }

                                break;

                            case "emergency":
                                train.Handles.EmergencyBrake.ApplicationSound = new CarSound(Plugin.currentHost, trainFolder, FileName, i, b, SoundCfgParser.mediumRadius, center);
                                break;

                            case "emergencyrelease":
                                train.Handles.EmergencyBrake.ReleaseSound = new CarSound(Plugin.currentHost, trainFolder, FileName, i, b, SoundCfgParser.mediumRadius, center);
                                break;

                            case "bp decomp":
                                for (int c = 0; c < train.Cars.Length; c++)
                                {
                                    train.Cars[c].CarBrake.Release = new CarSound(Plugin.currentHost, trainFolder, FileName, i, b, SoundCfgParser.smallRadius, center);
                                }

                                break;

                            default:
                                Plugin.currentHost.AddMessage(MessageType.Warning, false, "Unsupported key " + a + " encountered at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                break;
                            }
                        }
                        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(new char[] { });
                            string b = Lines[i].Substring(j + 1).TrimStart(new char[] { });
                            for (int c = 0; c < train.Cars.Length; c++)
                            {
                                if (train.Cars[c].CarBrake.brakeType == BrakeType.Main)
                                {
                                    switch (a.ToLowerInvariant())
                                    {
                                    case "attack":
                                        train.Cars[c].CarBrake.airCompressor.StartSound = new CarSound(Plugin.currentHost, trainFolder, FileName, i, b, SoundCfgParser.mediumRadius, center);
                                        break;

                                    case "loop":
                                        train.Cars[c].CarBrake.airCompressor.LoopSound = new CarSound(Plugin.currentHost, trainFolder, FileName, i, b, SoundCfgParser.mediumRadius, center);
                                        break;

                                    case "release":
                                        train.Cars[c].CarBrake.airCompressor.EndSound = new CarSound(Plugin.currentHost, trainFolder, FileName, i, b, SoundCfgParser.mediumRadius, center);
                                        break;

                                    default:
                                        Plugin.currentHost.AddMessage(MessageType.Warning, false, "Unsupported key " + a + " encountered at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                        break;
                                    }
                                }
                            }
                        }
                        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(new char[] { });
                            string b = Lines[i].Substring(j + 1).TrimStart(new char[] { });
                            switch (a.ToLowerInvariant())
                            {
                            case "left":
                                for (int c = 0; c < train.Cars.Length; c++)
                                {
                                    train.Cars[c].Sounds.SpringL = new CarSound(Plugin.currentHost, trainFolder, FileName, i, b, SoundCfgParser.smallRadius, left);
                                }

                                break;

                            case "right":
                                for (int c = 0; c < train.Cars.Length; c++)
                                {
                                    train.Cars[c].Sounds.SpringR = new CarSound(Plugin.currentHost, trainFolder, FileName, i, b, SoundCfgParser.smallRadius, right);
                                }

                                break;

                            default:
                                Plugin.currentHost.AddMessage(MessageType.Warning, false, "Unsupported key " + a + " encountered at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                break;
                            }
                        }
                        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(new char[] { });
                            string b = Lines[i].Substring(j + 1).TrimStart(new char[] { });
                            switch (a.ToLowerInvariant())
                            {
                            //PRIMARY HORN (Enter)
                            case "primarystart":
                                Plugin.currentHost.RegisterSound(Path.CombineFile(trainFolder, b), SoundCfgParser.largeRadius, out var primaryStart);
                                train.Cars[train.DriverCar].Horns[0].StartSound     = primaryStart as SoundBuffer;
                                train.Cars[train.DriverCar].Horns[0].SoundPosition  = front;
                                train.Cars[train.DriverCar].Horns[0].StartEndSounds = true;
                                break;

                            case "primaryend":
                            case "primaryrelease":
                                Plugin.currentHost.RegisterSound(Path.CombineFile(trainFolder, b), SoundCfgParser.largeRadius, out var primaryEnd);
                                train.Cars[train.DriverCar].Horns[0].EndSound       = primaryEnd as SoundBuffer;
                                train.Cars[train.DriverCar].Horns[0].SoundPosition  = front;
                                train.Cars[train.DriverCar].Horns[0].StartEndSounds = true;
                                break;

                            case "primaryloop":
                            case "primary":
                                Plugin.currentHost.RegisterSound(Path.CombineFile(trainFolder, b), SoundCfgParser.largeRadius, out var primaryLoop);
                                train.Cars[train.DriverCar].Horns[0].LoopSound     = primaryLoop as SoundBuffer;
                                train.Cars[train.DriverCar].Horns[0].SoundPosition = front;
                                train.Cars[train.DriverCar].Horns[0].Loop          = false;
                                break;

                            //SECONDARY HORN (Numpad Enter)
                            case "secondarystart":
                                Plugin.currentHost.RegisterSound(Path.CombineFile(trainFolder, b), SoundCfgParser.largeRadius, out var secondaryStart);
                                train.Cars[train.DriverCar].Horns[1].StartSound     = secondaryStart as SoundBuffer;
                                train.Cars[train.DriverCar].Horns[1].SoundPosition  = front;
                                train.Cars[train.DriverCar].Horns[1].StartEndSounds = true;
                                break;

                            case "secondaryend":
                            case "secondaryrelease":
                                Plugin.currentHost.RegisterSound(Path.CombineFile(trainFolder, b), SoundCfgParser.largeRadius, out var secondaryEnd);
                                train.Cars[train.DriverCar].Horns[1].EndSound       = secondaryEnd as SoundBuffer;
                                train.Cars[train.DriverCar].Horns[1].SoundPosition  = front;
                                train.Cars[train.DriverCar].Horns[1].StartEndSounds = true;
                                break;

                            case "secondaryloop":
                            case "secondary":
                                Plugin.currentHost.RegisterSound(Path.CombineFile(trainFolder, b), SoundCfgParser.largeRadius, out var secondaryLoop);
                                train.Cars[train.DriverCar].Horns[1].LoopSound     = secondaryLoop as SoundBuffer;
                                train.Cars[train.DriverCar].Horns[1].SoundPosition = front;
                                train.Cars[train.DriverCar].Horns[1].Loop          = false;
                                break;

                            //MUSIC HORN
                            case "musicstart":
                                Plugin.currentHost.RegisterSound(Path.CombineFile(trainFolder, b), SoundCfgParser.mediumRadius, out var musicStart);
                                train.Cars[train.DriverCar].Horns[2].StartSound     = musicStart as SoundBuffer;
                                train.Cars[train.DriverCar].Horns[2].SoundPosition  = front;
                                train.Cars[train.DriverCar].Horns[2].StartEndSounds = true;
                                break;

                            case "musicend":
                            case "musicrelease":
                                Plugin.currentHost.RegisterSound(Path.CombineFile(trainFolder, b), SoundCfgParser.mediumRadius, out var musicEnd);
                                train.Cars[train.DriverCar].Horns[2].EndSound       = musicEnd as SoundBuffer;
                                train.Cars[train.DriverCar].Horns[2].SoundPosition  = front;
                                train.Cars[train.DriverCar].Horns[2].StartEndSounds = true;
                                break;

                            case "musicloop":
                            case "music":
                                Plugin.currentHost.RegisterSound(Path.CombineFile(trainFolder, b), SoundCfgParser.mediumRadius, out var musicLoop);
                                train.Cars[train.DriverCar].Horns[2].LoopSound     = musicLoop as SoundBuffer;
                                train.Cars[train.DriverCar].Horns[2].SoundPosition = front;
                                train.Cars[train.DriverCar].Horns[2].Loop          = true;
                                break;

                            default:
                                Plugin.currentHost.AddMessage(MessageType.Warning, false, "Unsupported key " + a + " encountered at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                break;
                            }
                        }
                        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(new char[] { });
                            string b = Lines[i].Substring(j + 1).TrimStart(new char[] { });
                            switch (a.ToLowerInvariant())
                            {
                            case "open left":
                                for (int c = 0; c < train.Cars.Length; c++)
                                {
                                    train.Cars[c].Doors[0].OpenSound = new CarSound(Plugin.currentHost, trainFolder, FileName, i, b, SoundCfgParser.smallRadius, left);
                                }

                                break;

                            case "open right":
                                for (int c = 0; c < train.Cars.Length; c++)
                                {
                                    train.Cars[c].Doors[1].OpenSound = new CarSound(Plugin.currentHost, trainFolder, FileName, i, b, SoundCfgParser.smallRadius, right);
                                }

                                break;

                            case "close left":
                                for (int c = 0; c < train.Cars.Length; c++)
                                {
                                    train.Cars[c].Doors[0].CloseSound = new CarSound(Plugin.currentHost, trainFolder, FileName, i, b, SoundCfgParser.smallRadius, left);
                                }

                                break;

                            case "close right":
                                for (int c = 0; c < train.Cars.Length; c++)
                                {
                                    train.Cars[c].Doors[1].CloseSound = new CarSound(Plugin.currentHost, trainFolder, FileName, i, b, SoundCfgParser.smallRadius, right);
                                }
                                break;

                            default:
                                Plugin.currentHost.AddMessage(MessageType.Warning, false, "Unsupported key " + a + " encountered at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                break;
                            }
                        }
                        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(new char[] { });
                            string b = Lines[i].Substring(j + 1).TrimStart(new char[] { });
                            int    k;
                            if (!int.TryParse(a, System.Globalization.NumberStyles.Integer, Culture, out k))
                            {
                                Plugin.currentHost.AddMessage(MessageType.Error, false, "Invalid index appeared at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                            }
                            else
                            {
                                if (k >= 0)
                                {
                                    int n = train.Cars[train.DriverCar].Sounds.Plugin.Length;
                                    if (k >= n)
                                    {
                                        Array.Resize(ref train.Cars[train.DriverCar].Sounds.Plugin, k + 1);
                                        for (int h = n; h < k; h++)
                                        {
                                            train.Cars[train.DriverCar].Sounds.Plugin[h] = new CarSound();
                                        }
                                    }

                                    train.Cars[train.DriverCar].Sounds.Plugin[k] = new CarSound(Plugin.currentHost, trainFolder, FileName, i, b, SoundCfgParser.tinyRadius, panel);
                                }
                                else
                                {
                                    Plugin.currentHost.AddMessage(MessageType.Warning, false, "Index must be greater than 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(new char[] { });
                            string b = Lines[i].Substring(j + 1).TrimStart(new char[] { });
                            switch (a.ToLowerInvariant())
                            {
                            case "correct":
                                train.SafetySystems.StationAdjust.AdjustAlarm = new CarSound(Plugin.currentHost, trainFolder, FileName, i, b, SoundCfgParser.tinyRadius, panel);
                                break;

                            default:
                                Plugin.currentHost.AddMessage(MessageType.Warning, false, "Unsupported key " + a + " encountered at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                break;
                            }
                        }
                        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(new char[] { });
                            string b = Lines[i].Substring(j + 1).TrimStart(new char[] { });
                            switch (a.ToLowerInvariant())
                            {
                            case "on":
                                train.SafetySystems.PilotLamp.OnSound = new CarSound(Plugin.currentHost, trainFolder, FileName, i, b, SoundCfgParser.tinyRadius, panel);
                                break;

                            case "off":
                                train.SafetySystems.PilotLamp.OffSound = new CarSound(Plugin.currentHost, trainFolder, FileName, i, b, SoundCfgParser.tinyRadius, panel);
                                break;

                            default:
                                Plugin.currentHost.AddMessage(MessageType.Warning, false, "Unsupported key " + a + " encountered at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                break;
                            }
                        }
                        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(new char[] { });
                            string b = Lines[i].Substring(j + 1).TrimStart(new char[] { });
                            switch (a.ToLowerInvariant())
                            {
                            case "apply":
                                train.Handles.Brake.Increase = new CarSound(Plugin.currentHost, trainFolder, FileName, i, b, SoundCfgParser.tinyRadius, panel);
                                break;

                            case "applyfast":
                                train.Handles.Brake.IncreaseFast = new CarSound(Plugin.currentHost, trainFolder, FileName, i, b, SoundCfgParser.tinyRadius, panel);
                                break;

                            case "release":
                                train.Handles.Brake.Decrease = new CarSound(Plugin.currentHost, trainFolder, FileName, i, b, SoundCfgParser.tinyRadius, panel);
                                break;

                            case "releasefast":
                                train.Handles.Brake.DecreaseFast = new CarSound(Plugin.currentHost, trainFolder, FileName, i, b, SoundCfgParser.tinyRadius, panel);
                                break;

                            case "min":
                                train.Handles.Brake.Min = new CarSound(Plugin.currentHost, trainFolder, FileName, i, b, SoundCfgParser.tinyRadius, panel);
                                break;

                            case "max":
                                train.Handles.Brake.Max = new CarSound(Plugin.currentHost, trainFolder, FileName, i, b, SoundCfgParser.tinyRadius, panel);
                                break;

                            default:
                                Plugin.currentHost.AddMessage(MessageType.Warning, false, "Unsupported key " + a + " encountered at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                break;
                            }
                        }
                        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(new char[] { });
                            string b = Lines[i].Substring(j + 1).TrimStart(new char[] { });
                            switch (a.ToLowerInvariant())
                            {
                            case "up":
                                train.Handles.Power.Increase = new CarSound(Plugin.currentHost, trainFolder, FileName, i, b, SoundCfgParser.tinyRadius, panel);
                                break;

                            case "upfast":
                                train.Handles.Power.IncreaseFast = new CarSound(Plugin.currentHost, trainFolder, FileName, i, b, SoundCfgParser.tinyRadius, panel);
                                break;

                            case "down":
                                train.Handles.Power.Decrease = new CarSound(Plugin.currentHost, trainFolder, FileName, i, b, SoundCfgParser.tinyRadius, panel);
                                break;

                            case "downfast":
                                train.Handles.Power.DecreaseFast = new CarSound(Plugin.currentHost, trainFolder, FileName, i, b, SoundCfgParser.tinyRadius, panel);
                                break;

                            case "min":
                                train.Handles.Power.Min = new CarSound(Plugin.currentHost, trainFolder, FileName, i, b, SoundCfgParser.tinyRadius, panel);
                                break;

                            case "max":
                                train.Handles.Power.Max = new CarSound(Plugin.currentHost, trainFolder, FileName, i, b, SoundCfgParser.tinyRadius, panel);
                                break;

                            default:
                                Plugin.currentHost.AddMessage(MessageType.Warning, false, "Unsupported key " + a + " encountered at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                break;
                            }
                        }
                        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(new char[] { });
                            string b = Lines[i].Substring(j + 1).TrimStart(new char[] { });
                            switch (a.ToLowerInvariant())
                            {
                            case "on":
                                train.Handles.Reverser.EngageSound = new CarSound(Plugin.currentHost, trainFolder, FileName, i, b, SoundCfgParser.tinyRadius, panel);
                                break;

                            case "off":
                                train.Handles.Reverser.ReleaseSound = new CarSound(Plugin.currentHost, trainFolder, FileName, i, b, SoundCfgParser.tinyRadius, panel);
                                break;

                            default:
                                Plugin.currentHost.AddMessage(MessageType.Warning, false, "Unsupported key " + a + " encountered at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                break;
                            }
                        }
                        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(new char[] { });
                            string b = Lines[i].Substring(j + 1).TrimStart(new char[] { });
                            switch (a.ToLowerInvariant())
                            {
                            case "on":
                                train.Cars[train.DriverCar].Breaker.Resume = new CarSound(Plugin.currentHost, trainFolder, FileName, i, b, SoundCfgParser.smallRadius, panel);
                                break;

                            case "off":
                                train.Cars[train.DriverCar].Breaker.ResumeOrInterrupt = new CarSound(Plugin.currentHost, trainFolder, FileName, i, b, SoundCfgParser.smallRadius, panel);
                                break;

                            default:
                                Plugin.currentHost.AddMessage(MessageType.Warning, false, "Unsupported key " + a + " encountered at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                break;
                            }
                        }
                        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(new char[] { });
                            string b = Lines[i].Substring(j + 1).TrimStart(new char[] { });
                            switch (a.ToLowerInvariant())
                            {
                            case "noise":
                                for (int c = 0; c < train.Cars.Length; c++)
                                {
                                    if (train.Cars[c].Specs.IsMotorCar | c == train.DriverCar)
                                    {
                                        train.Cars[c].Sounds.Loop = new CarSound(Plugin.currentHost, trainFolder, FileName, i, b, SoundCfgParser.mediumRadius, center);
                                    }
                                }

                                break;

                            case "shoe":
                                for (int c = 0; c < train.Cars.Length; c++)
                                {
                                    train.Cars[c].CarBrake.Rub = new CarSound(Plugin.currentHost, trainFolder, FileName, i, b, SoundCfgParser.mediumRadius, center);
                                }

                                break;

                            case "halt":
                                for (int c = 0; c < train.Cars.Length; c++)
                                {
                                    train.SafetySystems.PassAlarm.Sound = new CarSound(Plugin.currentHost, trainFolder, FileName, i, b, SoundCfgParser.tinyRadius, panel);
                                }

                                break;

                            default:
                                Plugin.currentHost.AddMessage(MessageType.Warning, false, "Unsupported key " + a + " encountered at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                break;
                            }
                        }
                        i++;
                    }
                    i--; break;

                case "[windscreen]":
                    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(new char[] { });
                            string b = Lines[i].Substring(j + 1).TrimStart(new char[] { });
                            switch (a.ToLowerInvariant())
                            {
                            case "raindrop":
                                train.Cars[train.DriverCar].Windscreen.DropSound = new CarSound(Plugin.currentHost, trainFolder, FileName, i, b, SoundCfgParser.tinyRadius, panel);
                                break;

                            case "wetwipe":
                                train.Cars[train.DriverCar].Windscreen.Wipers.WetWipeSound = new CarSound(Plugin.currentHost, trainFolder, FileName, i, b, SoundCfgParser.tinyRadius, panel);
                                break;

                            case "drywipe":
                                train.Cars[train.DriverCar].Windscreen.Wipers.DryWipeSound = new CarSound(Plugin.currentHost, trainFolder, FileName, i, b, SoundCfgParser.tinyRadius, panel);
                                break;

                            case "switch":
                                train.Cars[train.DriverCar].Windscreen.Wipers.SwitchSound = new CarSound(Plugin.currentHost, trainFolder, FileName, i, b, SoundCfgParser.tinyRadius, panel);
                                break;

                            default:
                                Plugin.currentHost.AddMessage(MessageType.Warning, false, "Unsupported key " + a + " encountered at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                break;
                            }
                        }
                        i++;
                    }
                    i--; break;
                }
            }
            // motor sound
            for (int c = 0; c < train.Cars.Length; c++)
            {
                if (train.Cars[c].Specs.IsMotorCar)
                {
                    train.Cars[c].Sounds.Motor.Position = center;
                    for (int i = 0; i < train.Cars[c].Sounds.Motor.Tables.Length; i++)
                    {
                        train.Cars[c].Sounds.Motor.Tables[i].Buffer = null;
                        train.Cars[c].Sounds.Motor.Tables[i].Source = null;
                        for (int j = 0; j < train.Cars[c].Sounds.Motor.Tables[i].Entries.Length; j++)
                        {
                            int index = train.Cars[c].Sounds.Motor.Tables[i].Entries[j].SoundIndex;
                            if (index >= 0 && index < MotorFiles.Length && MotorFiles[index] != null)
                            {
                                Plugin.currentHost.RegisterSound(MotorFiles[index], SoundCfgParser.mediumRadius, out var motorSound);
                                train.Cars[c].Sounds.Motor.Tables[i].Entries[j].Buffer = motorSound as SoundBuffer;
                            }
                        }
                    }
                }
            }
        }
        private void ParsePanelAnimatedNode(XElement Element, string FileName, string TrainPath, TrainBase Train, int Car, CarSection CarSection, int GroupIndex)
        {
            System.Globalization.CultureInfo Culture = System.Globalization.CultureInfo.InvariantCulture;

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

            foreach (XElement SectionElement in Element.Elements())
            {
                Plugin.CurrentProgress = Plugin.CurrentProgress + invfac * (double)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, Train, Car, 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)
                                {
                                    int SoundIndex;

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

                                    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 = OpenBveApi.Path.CombineFile(TrainPath, Value);
                            if (System.IO.File.Exists(File))
                            {
                                System.Text.Encoding e = TextEncoding.GetSystemEncodingFromFile(File);
                                UnifiedObject        currentObject;
                                Plugin.currentHost.LoadObject(File, e, out currentObject);
                                var a = currentObject as AnimatedObjectCollection;
                                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;
                }
            }
        }
Example #7
0
        private static void ParsePanelAnimatedNode(XElement Element, string FileName, string TrainPath, TrainManager.Train Train, int Car, TrainManager.CarSection CarSection, int GroupIndex)
        {
            System.Globalization.CultureInfo Culture = System.Globalization.CultureInfo.InvariantCulture;

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

            foreach (XElement SectionElement in Element.Elements())
            {
                Loading.TrainProgress = Loading.TrainProgressCurrentSum + invfac * (double)currentSectionElement;
                if ((currentSectionElement & 4) == 0)
                {
                    System.Threading.Thread.Sleep(1);
                    if (Loading.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))
                                {
                                    Interface.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 TrainManager.ElementsGroup
                            {
                                Elements = new ObjectManager.AnimatedObject[] { },
                                Overlay  = true
                            };
                        }

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

                case "touch":
                    if (GroupIndex > 0)
                    {
                        Vector3 Position             = Vector3.Zero;
                        Vector3 Size                 = Vector3.Zero;
                        int     JumpScreen           = GroupIndex - 1;
                        int     SoundIndex           = -1;
                        Translations.Command Command = Translations.Command.None;
                        int CommandOption            = 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 "position":
                            {
                                string[] s = Value.Split(',');
                                if (s.Length == 3)
                                {
                                    if (s[0].Length != 0 && !NumberFormats.TryParseDoubleVb6(s[0], out Position.X))
                                    {
                                        Interface.AddMessage(MessageType.Error, false, "X is invalid in " + Key + " in " + Section + " at line " + LineNumber.ToString(Culture) + " in " + FileName);
                                    }
                                    if (s[1].Length != 0 && !NumberFormats.TryParseDoubleVb6(s[1], out Position.Y))
                                    {
                                        Interface.AddMessage(MessageType.Error, false, "Y is invalid in " + Key + " in " + Section + " at line " + LineNumber.ToString(Culture) + " in " + FileName);
                                    }
                                    if (s[2].Length != 0 && !NumberFormats.TryParseDoubleVb6(s[2], out Position.Z))
                                    {
                                        Interface.AddMessage(MessageType.Error, false, "Z is invalid in " + Key + " in " + Section + " at line " + LineNumber.ToString(Culture) + " in " + FileName);
                                    }
                                }
                                else
                                {
                                    Interface.AddMessage(MessageType.Error, false, "Three arguments are expected in " + Key + " in " + Section + " at line " + LineNumber.ToString(Culture) + " in " + FileName);
                                }
                            }
                            break;

                            case "size":
                            {
                                string[] s = Value.Split(',');
                                if (s.Length == 3)
                                {
                                    if (s[0].Length != 0 && !NumberFormats.TryParseDoubleVb6(s[0], out Size.X))
                                    {
                                        Interface.AddMessage(MessageType.Error, false, "X is invalid in " + Key + " in " + Section + " at line " + LineNumber.ToString(Culture) + " in " + FileName);
                                    }
                                    if (s[1].Length != 0 && !NumberFormats.TryParseDoubleVb6(s[1], out Size.Y))
                                    {
                                        Interface.AddMessage(MessageType.Error, false, "Y is invalid in " + Key + " in " + Section + " at line " + LineNumber.ToString(Culture) + " in " + FileName);
                                    }
                                    if (s[2].Length != 0 && !NumberFormats.TryParseDoubleVb6(s[2], out Size.Z))
                                    {
                                        Interface.AddMessage(MessageType.Error, false, "Z is invalid in " + Key + " in " + Section + " at line " + LineNumber.ToString(Culture) + " in " + FileName);
                                    }
                                }
                                else
                                {
                                    Interface.AddMessage(MessageType.Error, false, "Three arguments are expected in " + Key + " in " + Section + " at line " + LineNumber.ToString(Culture) + " in " + FileName);
                                }
                            }
                            break;

                            case "jumpscreen":
                                if (Value.Length != 0 && !NumberFormats.TryParseIntVb6(Value, out JumpScreen))
                                {
                                    Interface.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 && !NumberFormats.TryParseIntVb6(Value, out SoundIndex))
                                {
                                    Interface.AddMessage(MessageType.Error, false, "Value is invalid in " + Key + " in " + Section + " at line " + LineNumber.ToString(Culture) + " in " + FileName);
                                }
                                break;

                            case "command":
                            {
                                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)
                                {
                                    Interface.AddMessage(MessageType.Error, false, "Value is invalid in " + Key + " in " + Section + " at line " + LineNumber.ToString(Culture) + " in " + FileName);
                                }
                                else
                                {
                                    Command = Translations.CommandInfos[i].Command;
                                }
                            }
                            break;

                            case "commandoption":
                                if (Value.Length != 0 && !NumberFormats.TryParseIntVb6(Value, out CommandOption))
                                {
                                    Interface.AddMessage(MessageType.Error, false, "Value is invalid in " + Key + " in " + Section + " at line " + LineNumber.ToString(Culture) + " in " + FileName);
                                }
                                break;
                            }
                        }
                        CreateTouchElement(CarSection.Groups[GroupIndex], Position, Size, JumpScreen, SoundIndex, Command, CommandOption);
                    }
                    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 = OpenBveApi.Path.CombineFile(TrainPath, Value);
                            if (System.IO.File.Exists(File))
                            {
                                System.Text.Encoding e = TextEncoding.GetSystemEncodingFromFile(File);
                                ObjectManager.AnimatedObjectCollection a = AnimatedObjectParser.ReadObject(File, e);
                                if (a != null)
                                {
                                    for (int i = 0; i < a.Objects.Length; i++)
                                    {
                                        a.Objects[i].ObjectIndex = ObjectManager.CreateDynamicObject();
                                    }
                                    CarSection.Groups[GroupIndex].Elements = a.Objects;
                                }
                                else
                                {
                                    Interface.AddMessage(MessageType.Error, false, "Value is invalid in " + Key + " in " + Section + " at line " + LineNumber.ToString(Culture) + " in " + FileName);
                                }
                            }
                        }
                        break;
                        }
                    }
                }
                break;
                }
            }
        }
Example #8
0
        /// <summary>This function processes the list of expressions for $Char, $Rnd, $If and $Sub directives, and evaluates them into the final expressions dataset</summary>
        private void PreprocessChrRndSub(string FileName, System.Text.Encoding Encoding, ref Expression[] Expressions)
        {
            string[] Subs    = new string[16];
            int      openIfs = 0;

            for (int i = 0; i < Expressions.Length; i++)
            {
                string Epilog = " at line " + Expressions[i].Line.ToString(Culture) + ", column " + Expressions[i].Column.ToString(Culture) + " in file " + Expressions[i].File;
                bool   continueWithNextExpression = false;
                for (int j = Expressions[i].Text.Length - 1; j >= 0; j--)
                {
                    if (Expressions[i].Text[j] == '$')
                    {
                        int k;
                        for (k = j + 1; k < Expressions[i].Text.Length; k++)
                        {
                            if (Expressions[i].Text[k] == '(')
                            {
                                break;
                            }
                            else if (Expressions[i].Text[k] == '/' | Expressions[i].Text[k] == '\\')
                            {
                                k = Expressions[i].Text.Length + 1;
                                break;
                            }
                        }
                        if (k <= Expressions[i].Text.Length)
                        {
                            string t = Expressions[i].Text.Substring(j, k - j).TrimEnd(new char[] { });
                            int    l = 1, h;
                            for (h = k + 1; h < Expressions[i].Text.Length; h++)
                            {
                                switch (Expressions[i].Text[h])
                                {
                                case '(':
                                    l++;
                                    break;

                                case ')':
                                    l--;
                                    if (l < 0)
                                    {
                                        continueWithNextExpression = true;
                                        Plugin.CurrentHost.AddMessage(MessageType.Error, false, "Invalid parenthesis structure in " + t + Epilog);
                                    }
                                    break;
                                }
                                if (l <= 0)
                                {
                                    break;
                                }
                            }
                            if (continueWithNextExpression)
                            {
                                break;
                            }
                            if (l != 0)
                            {
                                Plugin.CurrentHost.AddMessage(MessageType.Error, false, "Invalid parenthesis structure in " + t + Epilog);
                                break;
                            }
                            string s = Expressions[i].Text.Substring(k + 1, h - k - 1).Trim(new char[] { });
                            switch (t.ToLowerInvariant())
                            {
                            case "$if":
                                if (j != 0)
                                {
                                    Plugin.CurrentHost.AddMessage(MessageType.Error, false, "The $If directive must not appear within another statement" + Epilog);
                                }
                                else
                                {
                                    double num;
                                    if (double.TryParse(s, NumberStyles.Float, Culture, out num))
                                    {
                                        openIfs++;
                                        Expressions[i].Text = string.Empty;
                                        if (num == 0.0)
                                        {
                                            /*
                                             * Blank every expression until the matching $Else or $EndIf
                                             * */
                                            i++;
                                            int level = 1;
                                            while (i < Expressions.Length)
                                            {
                                                if (Expressions[i].Text.StartsWith("$if", StringComparison.OrdinalIgnoreCase))
                                                {
                                                    Expressions[i].Text = string.Empty;
                                                    level++;
                                                }
                                                else if (Expressions[i].Text.StartsWith("$else", StringComparison.OrdinalIgnoreCase))
                                                {
                                                    Expressions[i].Text = string.Empty;
                                                    if (level == 1)
                                                    {
                                                        level--;
                                                        break;
                                                    }
                                                }
                                                else if (Expressions[i].Text.StartsWith("$endif", StringComparison.OrdinalIgnoreCase))
                                                {
                                                    Expressions[i].Text = string.Empty;
                                                    level--;
                                                    if (level == 0)
                                                    {
                                                        openIfs--;
                                                        break;
                                                    }
                                                }
                                                else
                                                {
                                                    Expressions[i].Text = string.Empty;
                                                }
                                                i++;
                                            }
                                            if (level != 0)
                                            {
                                                Plugin.CurrentHost.AddMessage(MessageType.Error, false, "$EndIf missing at the end of the file" + Epilog);
                                            }
                                        }
                                        continueWithNextExpression = true;
                                        break;
                                    }
                                    else
                                    {
                                        Plugin.CurrentHost.AddMessage(MessageType.Error, false, "The $If condition does not evaluate to a number" + Epilog);
                                    }
                                }
                                continueWithNextExpression = true;
                                break;

                            case "$else":
                                /*
                                 * Blank every expression until the matching $EndIf
                                 * */
                                Expressions[i].Text = string.Empty;
                                if (openIfs != 0)
                                {
                                    i++;
                                    int level = 1;
                                    while (i < Expressions.Length)
                                    {
                                        if (Expressions[i].Text.StartsWith("$if", StringComparison.OrdinalIgnoreCase))
                                        {
                                            Expressions[i].Text = string.Empty;
                                            level++;
                                        }
                                        else if (Expressions[i].Text.StartsWith("$else", StringComparison.OrdinalIgnoreCase))
                                        {
                                            Expressions[i].Text = string.Empty;
                                            if (level == 1)
                                            {
                                                Plugin.CurrentHost.AddMessage(MessageType.Error, false, "Duplicate $Else encountered" + Epilog);
                                            }
                                        }
                                        else if (Expressions[i].Text.StartsWith("$endif", StringComparison.OrdinalIgnoreCase))
                                        {
                                            Expressions[i].Text = string.Empty;
                                            level--;
                                            if (level == 0)
                                            {
                                                openIfs--;
                                                break;
                                            }
                                        }
                                        else
                                        {
                                            Expressions[i].Text = string.Empty;
                                        }
                                        i++;
                                    }
                                    if (level != 0)
                                    {
                                        Plugin.CurrentHost.AddMessage(MessageType.Error, false, "$EndIf missing at the end of the file" + Epilog);
                                    }
                                }
                                else
                                {
                                    Plugin.CurrentHost.AddMessage(MessageType.Error, false, "$Else without matching $If encountered" + Epilog);
                                }
                                continueWithNextExpression = true;
                                break;

                            case "$endif":
                                Expressions[i].Text = string.Empty;
                                if (openIfs != 0)
                                {
                                    openIfs--;
                                }
                                else
                                {
                                    Plugin.CurrentHost.AddMessage(MessageType.Error, false, "$EndIf without matching $If encountered" + Epilog);
                                }
                                continueWithNextExpression = true;
                                break;

                            case "$include":
                                if (j != 0)
                                {
                                    Plugin.CurrentHost.AddMessage(MessageType.Error, false, "The $Include directive must not appear within another statement" + Epilog);
                                    continueWithNextExpression = true;
                                    break;
                                }
                                string[] args = s.Split(new char[] { ';' });
                                for (int ia = 0; ia < args.Length; ia++)
                                {
                                    args[ia] = args[ia].Trim(new char[] { });
                                }
                                int      count        = (args.Length + 1) / 2;
                                string[] files        = new string[count];
                                double[] weights      = new double[count];
                                double[] offsets      = new double[count];
                                double   weightsTotal = 0.0;
                                for (int ia = 0; ia < count; ia++)
                                {
                                    string file;
                                    double offset;
                                    int    colon = args[2 * ia].IndexOf(':');
                                    if (colon >= 0)
                                    {
                                        file = args[2 * ia].Substring(0, colon).TrimEnd(new char[] { });
                                        string value = args[2 * ia].Substring(colon + 1).TrimStart(new char[] { });
                                        if (!double.TryParse(value, NumberStyles.Float, Culture, out offset))
                                        {
                                            continueWithNextExpression = true;
                                            Plugin.CurrentHost.AddMessage(MessageType.Error, false, "The track position offset " + value + " is invalid in " + t + Epilog);
                                            break;
                                        }
                                    }
                                    else
                                    {
                                        file   = args[2 * ia];
                                        offset = 0.0;
                                    }
                                    files[ia]   = Path.CombineFile(System.IO.Path.GetDirectoryName(FileName), file);
                                    offsets[ia] = offset;
                                    if (!System.IO.File.Exists(files[ia]))
                                    {
                                        continueWithNextExpression = true;
                                        Plugin.CurrentHost.AddMessage(MessageType.Error, false, "The file " + file + " could not be found in " + t + Epilog);
                                        for (int ta = i; ta < Expressions.Length - 1; ta++)
                                        {
                                            Expressions[ta] = Expressions[ta + 1];
                                        }
                                        Array.Resize(ref Expressions, Expressions.Length - 1);
                                        i--;
                                        break;
                                    }
                                    if (2 * ia + 1 < args.Length)
                                    {
                                        if (!NumberFormats.TryParseDoubleVb6(args[2 * ia + 1], out weights[ia]))
                                        {
                                            continueWithNextExpression = true;
                                            Plugin.CurrentHost.AddMessage(MessageType.Error, false, "A weight is invalid in " + t + Epilog);
                                            break;
                                        }
                                        if (weights[ia] <= 0.0)
                                        {
                                            continueWithNextExpression = true;
                                            Plugin.CurrentHost.AddMessage(MessageType.Error, false, "A weight is not positive in " + t + Epilog);
                                            break;
                                        }
                                        weightsTotal += weights[ia];
                                    }
                                    else
                                    {
                                        weights[ia]   = 1.0;
                                        weightsTotal += 1.0;
                                    }
                                }
                                if (count == 0)
                                {
                                    continueWithNextExpression = true;
                                    Plugin.CurrentHost.AddMessage(MessageType.Error, false, "No file was specified in " + t + Epilog);
                                    break;
                                }
                                if (!continueWithNextExpression)
                                {
                                    double number      = Plugin.RandomNumberGenerator.NextDouble() * weightsTotal;
                                    double value       = 0.0;
                                    int    chosenIndex = 0;
                                    for (int ia = 0; ia < count; ia++)
                                    {
                                        value += weights[ia];
                                        if (value > number)
                                        {
                                            chosenIndex = ia;
                                            break;
                                        }
                                    }
                                    Expression[] expr;
                                    //Get the text encoding of our $Include file
                                    System.Text.Encoding includeEncoding = TextEncoding.GetSystemEncodingFromFile(files[chosenIndex]);
                                    if (!includeEncoding.Equals(Encoding) && includeEncoding.WindowsCodePage != Encoding.WindowsCodePage)
                                    {
                                        //If the encodings do not match, add a warning
                                        //This is not critical, but it's a bad idea to mix and match character encodings within a routefile, as the auto-detection may sometimes be wrong
                                        Plugin.CurrentHost.AddMessage(MessageType.Warning, false, "The text encoding of the $Include file " + files[chosenIndex] + " does not match that of the base routefile.");
                                    }
                                    string[] lines = System.IO.File.ReadAllLines(files[chosenIndex], includeEncoding);
                                    PreprocessSplitIntoExpressions(files[chosenIndex], lines, out expr, false, offsets[chosenIndex] + Expressions[i].TrackPositionOffset);
                                    int length = Expressions.Length;
                                    if (expr.Length == 0)
                                    {
                                        for (int ia = i; ia < Expressions.Length - 1; ia++)
                                        {
                                            Expressions[ia] = Expressions[ia + 1];
                                        }
                                        Array.Resize(ref Expressions, length - 1);
                                    }
                                    else
                                    {
                                        Array.Resize(ref Expressions, length + expr.Length - 1);
                                        for (int ia = Expressions.Length - 1; ia >= i + expr.Length; ia--)
                                        {
                                            Expressions[ia] = Expressions[ia - expr.Length + 1];
                                        }
                                        for (int ia = 0; ia < expr.Length; ia++)
                                        {
                                            Expressions[i + ia] = expr[ia];
                                        }
                                    }
                                    i--;
                                    continueWithNextExpression = true;
                                }
                                break;

                            case "$chr":
                            case "$chruni":
                            {
                                int x;
                                if (NumberFormats.TryParseIntVb6(s, out x))
                                {
                                    if (x < 0)
                                    {
                                        //Must be non-negative
                                        continueWithNextExpression = true;
                                        Plugin.CurrentHost.AddMessage(MessageType.Error, false, "Index must be a non-negative character in " + t + Epilog);
                                    }
                                    else
                                    {
                                        Expressions[i].Text = Expressions[i].Text.Substring(0, j) + char.ConvertFromUtf32(x) + Expressions[i].Text.Substring(h + 1);
                                    }
                                }
                                else
                                {
                                    continueWithNextExpression = true;
                                    Plugin.CurrentHost.AddMessage(MessageType.Error, false, "Index is invalid in " + t + Epilog);
                                }
                            } break;

                            case "$chrascii":
                            {
                                int x;
                                if (NumberFormats.TryParseIntVb6(s, out x))
                                {
                                    if (x < 0 || x > 127)
                                    {
                                        //Standard ASCII characters from 0-127
                                        continueWithNextExpression = true;
                                        Plugin.CurrentHost.AddMessage(MessageType.Error, false, "Index does not correspond to a valid ASCII character in " + t + Epilog);
                                    }
                                    else
                                    {
                                        Expressions[i].Text = Expressions[i].Text.Substring(0, j) + char.ConvertFromUtf32(x) + Expressions[i].Text.Substring(h + 1);
                                    }
                                }
                                else
                                {
                                    continueWithNextExpression = true;
                                    Plugin.CurrentHost.AddMessage(MessageType.Error, false, "Index is invalid in " + t + Epilog);
                                }
                            }
                            break;

                            case "$rnd":
                            {
                                int m = s.IndexOf(";", StringComparison.Ordinal);
                                if (m >= 0)
                                {
                                    string s1 = s.Substring(0, m).TrimEnd(new char[] { });
                                    string s2 = s.Substring(m + 1).TrimStart(new char[] { });
                                    int    x; if (NumberFormats.TryParseIntVb6(s1, out x))
                                    {
                                        int y; if (NumberFormats.TryParseIntVb6(s2, out y))
                                        {
                                            int z = x + (int)Math.Floor(Plugin.RandomNumberGenerator.NextDouble() * (y - x + 1));
                                            Expressions[i].Text = Expressions[i].Text.Substring(0, j) + z.ToString(Culture) + Expressions[i].Text.Substring(h + 1);
                                        }
                                        else
                                        {
                                            continueWithNextExpression = true;
                                            Plugin.CurrentHost.AddMessage(MessageType.Error, false, "Index2 is invalid in " + t + Epilog);
                                        }
                                    }
                                    else
                                    {
                                        continueWithNextExpression = true;
                                        Plugin.CurrentHost.AddMessage(MessageType.Error, false, "Index1 is invalid in " + t + Epilog);
                                    }
                                }
                                else
                                {
                                    continueWithNextExpression = true;
                                    Plugin.CurrentHost.AddMessage(MessageType.Error, false, "Two arguments are expected in " + t + Epilog);
                                }
                            } break;

                            case "$sub":
                            {
                                l = 0;
                                bool f = false;
                                int  m;
                                for (m = h + 1; m < Expressions[i].Text.Length; m++)
                                {
                                    switch (Expressions[i].Text[m])
                                    {
                                    case '(': l++; break;

                                    case ')': l--; break;

                                    case '=':
                                        if (l == 0)
                                        {
                                            f = true;
                                        }
                                        break;

                                    default:
                                        if (!char.IsWhiteSpace(Expressions[i].Text[m]))
                                        {
                                            l = -1;
                                        }
                                        break;
                                    }
                                    if (f | l < 0)
                                    {
                                        break;
                                    }
                                }
                                if (f)
                                {
                                    l = 0;
                                    int n;
                                    for (n = m + 1; n < Expressions[i].Text.Length; n++)
                                    {
                                        switch (Expressions[i].Text[n])
                                        {
                                        case '(': l++; break;

                                        case ')': l--; break;
                                        }
                                        if (l < 0)
                                        {
                                            break;
                                        }
                                    }
                                    int x;
                                    if (NumberFormats.TryParseIntVb6(s, out x))
                                    {
                                        if (x >= 0)
                                        {
                                            while (x >= Subs.Length)
                                            {
                                                Array.Resize(ref Subs, Subs.Length << 1);
                                            }
                                            Subs[x]             = Expressions[i].Text.Substring(m + 1, n - m - 1).Trim(new char[] { });
                                            Expressions[i].Text = Expressions[i].Text.Substring(0, j) + Expressions[i].Text.Substring(n);
                                        }
                                        else
                                        {
                                            continueWithNextExpression = true;
                                            Plugin.CurrentHost.AddMessage(MessageType.Error, false, "Index is expected to be non-negative in " + t + Epilog);
                                        }
                                    }
                                    else
                                    {
                                        continueWithNextExpression = true;
                                        Plugin.CurrentHost.AddMessage(MessageType.Error, false, "Index is invalid in " + t + Epilog);
                                    }
                                }
                                else
                                {
                                    int x;
                                    if (NumberFormats.TryParseIntVb6(s, out x))
                                    {
                                        if (x >= 0 & x < Subs.Length && Subs[x] != null)
                                        {
                                            Expressions[i].Text = Expressions[i].Text.Substring(0, j) + Subs[x] + Expressions[i].Text.Substring(h + 1);
                                        }
                                        else
                                        {
                                            continueWithNextExpression = true;
                                            Plugin.CurrentHost.AddMessage(MessageType.Error, false, "Index is out of range in " + t + Epilog);
                                        }
                                    }
                                    else
                                    {
                                        continueWithNextExpression = true;
                                        Plugin.CurrentHost.AddMessage(MessageType.Error, false, "Index is invalid in " + t + Epilog);
                                    }
                                }
                            }
                            break;
                            }
                        }
                    }
                    if (continueWithNextExpression)
                    {
                        break;
                    }
                }
            }
            // handle comments introduced via chr, rnd, sub
            {
                int length = Expressions.Length;
                for (int i = 0; i < length; i++)
                {
                    Expressions[i].Text = Expressions[i].Text.Trim(new char[] { });
                    if (Expressions[i].Text.Length != 0)
                    {
                        if (Expressions[i].Text[0] == ';')
                        {
                            for (int j = i; j < length - 1; j++)
                            {
                                Expressions[j] = Expressions[j + 1];
                            }
                            length--;
                            i--;
                        }
                    }
                    else
                    {
                        for (int j = i; j < length - 1; j++)
                        {
                            Expressions[j] = Expressions[j + 1];
                        }
                        length--;
                        i--;
                    }
                }
                if (length != Expressions.Length)
                {
                    Array.Resize(ref Expressions, length);
                }
            }
        }
Example #9
0
        public static void ProcessFile(string pathIn, string pathOut, ConvertOption option, LogHandler callback)
        {
            callback(Message.FileStarted, pathIn);
            UnifiedObject unifiedObj = null;

            callback(Message.Reading);
            PluginManager.logHandler = callback;
            Encoding encoding          = option.UseLocalEncoding ? Encoding.Default : TextEncoding.GetSystemEncodingFromFile(pathIn);
            bool     isSketchupObjFile = IsSketchupObjFile(pathIn, encoding);

            if (PluginManager.LoadObject(pathIn, encoding, out unifiedObj))
            {
                var staticObj = unifiedObj as StaticObject;

                callback(Message.OptimizingObject);
                staticObj.OptimizeObject(false, 0, true);

                callback(Message.OptimizingMaterial);
                OptimizeMaterial(ref staticObj.Mesh);

                callback(Message.PostProcessing);
                if (isSketchupObjFile)
                {
                    callback(Message.SketchupHack);
                    option.Mirror.Z ^= true;
                }
                if (option.Mirror != default(Bool3))
                {
                    staticObj.ApplyMirror(option.Mirror.X, option.Mirror.Y, option.Mirror.Z,
                                          option.Mirror.X, option.Mirror.Y, option.Mirror.Z);
                }
                if (option.Scale != default(Vector3) && option.Scale != new Vector3(1, 1, 1))
                {
                    staticObj.ApplyScale(option.Scale.X, option.Scale.Y, option.Scale.Z);
                }
                if (option.Rotation != default(Vector3))
                {
                    // TODO: This doesn't seem to be the correct way to apply euler angle rotation!
                    if (option.Rotation.X != 0.0)
                    {
                        staticObj.ApplyRotation(new Vector3(1, 0, 0), option.Rotation.X);
                    }
                    if (option.Rotation.Y != 0.0)
                    {
                        staticObj.ApplyRotation(new Vector3(0, 1, 0), option.Rotation.X);
                    }
                    if (option.Rotation.Z != 0.0)
                    {
                        staticObj.ApplyRotation(new Vector3(0, 0, 1), option.Rotation.X);
                    }
                }
                if (option.Translation != default(Vector3))
                {
                    staticObj.ApplyTranslation(option.Translation.X, option.Translation.Y, option.Translation.Z);
                }
                //var dimension = "[" + string.Join(", ", staticObj.Mesh.BoundingBox.Select(v => string.Format("({0}, {1}, {2})", v.X, v.Y, v.Z))) + "]";
                //callback(Message.Dimension, dimension);

                if (pathOut.EndsWith(".csv", StringComparison.OrdinalIgnoreCase))
                {
                    callback(Message.Writing);
                    CsvWriter.Save(staticObj, pathOut, option, callback);
                }
                else if (pathOut.EndsWith(".hmmo", StringComparison.OrdinalIgnoreCase))
                {
                    callback(Message.PostProcessing);
                    staticObj.Mesh.Faces = Triangulate(staticObj.Mesh.Faces);
                    callback(Message.Writing);
                    // TODO: Hmmo Writer
                }
            }
            else
            {
                callback(Message.ObjectNotReadable);
            }
            callback(Message.FileDone, pathOut);
        }
Example #10
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()));
        }
Example #11
0
        internal static void Parse(string fileName, out Train train)
        {
            train = new 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();
                }
            }

            bool ver1220000 = false;

            foreach (string line in lines)
            {
                if (line.Length != 0)
                {
                    string s = line.ToLowerInvariant();

                    switch (s)
                    {
                    case "bve1200000":
                    case "bve1210000":
                    case "bve1220000":
                        ver1220000 = true;
                        break;

                    case "bve2000000":
                    case "openbve":
                        //No action
                        break;

                    default:
                        if (s.ToLowerInvariant().StartsWith("openbve"))
                        {
                            string tt = s.Substring(7, s.Length - 7);
                            int    v;

                            if (int.TryParse(tt, NumberStyles.Float, culture, out v))
                            {
                                if (v > currentVersion)
                                {
                                    Interface.AddMessage(MessageType.Warning, false, $"The train.dat {fileName} was created with a newer version of openBVE. Please check for an update.");
                                }
                            }
                            else
                            {
                                Interface.AddMessage(MessageType.Error, false, $"The train.dat version {lines[0].ToLowerInvariant()} is invalid in {fileName}");
                            }
                        }

                        break;
                    }

                    break;
                }
            }

            Acceleration acceleration = new Acceleration();
            Performance  performance  = new Performance();
            Delay        delay        = new Delay();
            Move         move         = new Move();
            Brake        brake        = new Brake();
            Pressure     pressure     = new Pressure();
            Motor        motor        = new Motor();

            double motorCarMass          = 40.0;
            int    numberOfMotorCars     = 1;
            double trailerCarMass        = 40.0;
            int    numberOfTrailerCars   = 1;
            double lengthOfACar          = 20.0;
            bool   frontCarIsAMotorCar   = false;
            double widthOfACar           = 2.6;
            double heightOfACar          = 3.2;
            double centerOfGravityHeight = 1.5;
            double exposedFrontalArea    = 5.0;
            double unexposedFrontalArea  = 1.6;

            for (int i = 0; i < lines.Length; i++)
            {
                int n = 0;

                switch (lines[i].ToLowerInvariant())
                {
                case "#acceleration":
                    i++;

                    while (i < lines.Length && !lines[i].StartsWith("#", StringComparison.InvariantCultureIgnoreCase))
                    {
                        if (n == acceleration.Entries.Count)
                        {
                            acceleration.Entries.Add(new Acceleration.Entry());
                        }

                        string u = lines[i] + ",";
                        int    m = 0;

                        while (true)
                        {
                            int j = u.IndexOf(',');

                            if (j == -1)
                            {
                                break;
                            }

                            string s = u.Substring(0, j).Trim();
                            u = u.Substring(j + 1);
                            double a;

                            if (double.TryParse(s, NumberStyles.Float, culture, out a))
                            {
                                switch (m)
                                {
                                case 0:
                                    acceleration.Entries[n].A0 = Math.Max(a, 0.0);
                                    break;

                                case 1:
                                    acceleration.Entries[n].A1 = Math.Max(a, 0.0);
                                    break;

                                case 2:
                                    acceleration.Entries[n].V1 = Math.Max(a, 0.0);
                                    break;

                                case 3:
                                    acceleration.Entries[n].V2 = Math.Max(a, 0.0);

                                    if (acceleration.Entries[n].V2 < acceleration.Entries[n].V1)
                                    {
                                        double x = acceleration.Entries[n].V1;
                                        acceleration.Entries[n].V1 = acceleration.Entries[n].V2;
                                        acceleration.Entries[n].V2 = x;
                                    }

                                    break;

                                case 4:
                                    if (ver1220000)
                                    {
                                        if (a <= 0.0)
                                        {
                                            acceleration.Entries[n].E = 1.0;
                                        }
                                        else
                                        {
                                            const double c = 1.23315173118822;
                                            acceleration.Entries[n].E = 1.0 - Math.Log(a) * acceleration.Entries[n].V2 * c;

                                            if (acceleration.Entries[n].E > 4.0)
                                            {
                                                acceleration.Entries[n].E = 4.0;
                                            }
                                        }
                                    }
                                    else
                                    {
                                        acceleration.Entries[n].E = a;
                                    }

                                    break;
                                }
                            }

                            m++;
                        }

                        i++;
                        n++;
                    }

                    i--;
                    break;

                case "#performance":
                case "#deceleration":
                    i++;

                    while (i < lines.Length && !lines[i].StartsWith("#", StringComparison.InvariantCultureIgnoreCase))
                    {
                        double a;

                        if (double.TryParse(lines[i], NumberStyles.Float, culture, out a))
                        {
                            switch (n)
                            {
                            case 0:
                                if (a >= 0.0)
                                {
                                    performance.Deceleration = a;
                                }

                                break;

                            case 1:
                                if (a >= 0.0)
                                {
                                    performance.CoefficientOfStaticFriction = a;
                                }

                                break;

                            case 3:
                                if (a >= 0.0)
                                {
                                    performance.CoefficientOfRollingResistance = a;
                                }

                                break;

                            case 4:
                                if (a >= 0.0)
                                {
                                    performance.AerodynamicDragCoefficient = a;
                                }

                                break;
                            }
                        }

                        i++;
                        n++;
                    }

                    i--;
                    break;

                case "#delay":
                    i++;

                    double[] delayPowerUp       = delay.DelayPower.Select(x => x.Up).ToArray();
                    double[] delayPowerDown     = delay.DelayPower.Select(x => x.Down).ToArray();
                    double[] delayBrakeUp       = delay.DelayBrake.Select(x => x.Up).ToArray();
                    double[] delayBrakeDown     = delay.DelayBrake.Select(x => x.Down).ToArray();
                    double[] delayLocoBrakeUp   = delay.DelayLocoBrake.Select(x => x.Up).ToArray();
                    double[] delayLocoBrakeDown = delay.DelayLocoBrake.Select(x => x.Down).ToArray();

                    delay.DelayPower.Clear();
                    delay.DelayBrake.Clear();
                    delay.DelayLocoBrake.Clear();

                    while (i < lines.Length && !lines[i].StartsWith("#", StringComparison.InvariantCultureIgnoreCase))
                    {
                        double a;

                        if (double.TryParse(lines[i], NumberStyles.Float, culture, out a))
                        {
                            switch (n)
                            {
                            case 0:
                                if (a >= 0.0)
                                {
                                    delayPowerUp = new[] { a };
                                }

                                break;

                            case 1:
                                if (a >= 0.0)
                                {
                                    delayPowerDown = new[] { a };
                                }

                                break;

                            case 2:
                                if (a >= 0.0)
                                {
                                    delayBrakeUp = new[] { a };
                                }

                                break;

                            case 3:
                                if (a >= 0.0)
                                {
                                    delayBrakeDown = new[] { a };
                                }

                                break;
                            }
                        }
                        else if (lines[i].IndexOf(',') != -1)
                        {
                            switch (n)
                            {
                            case 0:
                                delayPowerUp = lines[i].Split(',').Select(x => double.Parse(x, culture)).ToArray();
                                break;

                            case 1:
                                delayPowerDown = lines[i].Split(',').Select(x => double.Parse(x, culture)).ToArray();
                                break;

                            case 2:
                                delayBrakeUp = lines[i].Split(',').Select(x => double.Parse(x, culture)).ToArray();
                                break;

                            case 3:
                                delayBrakeDown = lines[i].Split(',').Select(x => double.Parse(x, culture)).ToArray();
                                break;

                            case 4:
                                delayLocoBrakeUp = lines[i].Split(',').Select(x => double.Parse(x, culture)).ToArray();
                                break;

                            case 5:
                                delayLocoBrakeDown = lines[i].Split(',').Select(x => double.Parse(x, culture)).ToArray();
                                break;
                            }
                        }

                        i++;
                        n++;
                    }

                    for (int j = 0; j < Math.Max(delayPowerUp.Length, delayPowerDown.Length); j++)
                    {
                        Delay.Entry entry = new Delay.Entry();

                        if (j < delayPowerUp.Length)
                        {
                            entry.Up = delayPowerUp[j];
                        }

                        if (j < delayPowerDown.Length)
                        {
                            entry.Down = delayPowerDown[j];
                        }

                        delay.DelayPower.Add(entry);
                    }

                    for (int j = 0; j < Math.Max(delayBrakeUp.Length, delayBrakeDown.Length); j++)
                    {
                        Delay.Entry entry = new Delay.Entry();

                        if (j < delayBrakeUp.Length)
                        {
                            entry.Up = delayBrakeUp[j];
                        }

                        if (j < delayBrakeDown.Length)
                        {
                            entry.Down = delayBrakeDown[j];
                        }

                        delay.DelayBrake.Add(entry);
                    }

                    for (int j = 0; j < Math.Max(delayLocoBrakeUp.Length, delayLocoBrakeDown.Length); j++)
                    {
                        Delay.Entry entry = new Delay.Entry();

                        if (j < delayLocoBrakeUp.Length)
                        {
                            entry.Up = delayLocoBrakeUp[j];
                        }

                        if (j < delayLocoBrakeDown.Length)
                        {
                            entry.Down = delayLocoBrakeDown[j];
                        }

                        delay.DelayLocoBrake.Add(entry);
                    }

                    i--;
                    break;

                case "#move":
                    i++;

                    while (i < lines.Length && !lines[i].StartsWith("#", StringComparison.InvariantCultureIgnoreCase))
                    {
                        double a;

                        if (double.TryParse(lines[i], NumberStyles.Float, culture, out a))
                        {
                            switch (n)
                            {
                            case 0:
                                if (a >= 0.0)
                                {
                                    move.JerkPowerUp = a;
                                }

                                break;

                            case 1:
                                if (a >= 0.0)
                                {
                                    move.JerkPowerDown = a;
                                }

                                break;

                            case 2:
                                if (a >= 0.0)
                                {
                                    move.JerkBrakeUp = a;
                                }

                                break;

                            case 3:
                                if (a >= 0.0)
                                {
                                    move.JerkBrakeDown = a;
                                }

                                break;

                            case 4:
                                if (a >= 0.0)
                                {
                                    move.BrakeCylinderUp = a;
                                }

                                break;

                            case 5:
                                if (a >= 0.0)
                                {
                                    move.BrakeCylinderDown = a;
                                }

                                break;
                            }
                        }

                        i++;
                        n++;
                    }

                    i--;
                    break;

                case "#brake":
                    i++;

                    while (i < lines.Length && !lines[i].StartsWith("#", StringComparison.InvariantCultureIgnoreCase))
                    {
                        double a;

                        if (double.TryParse(lines[i], NumberStyles.Float, culture, out a))
                        {
                            int b = (int)Math.Round(a);

                            switch (n)
                            {
                            case 0:
                                if (b >= 0 & b <= 2)
                                {
                                    brake.BrakeType = (BrakeSystemType)b;
                                }

                                break;

                            case 1:
                                if (b >= 0 & b <= 2)
                                {
                                    brake.BrakeControlSystem = (EletropneumaticBrakeType)b;
                                }

                                break;

                            case 2:
                                if (a >= 0.0)
                                {
                                    brake.BrakeControlSpeed = a;
                                }

                                break;

                            case 3:
                                if (a <= 0 && a > 3)
                                {
                                    brake.LocoBrakeType = (Brake.LocoBrakeTypes)b;
                                }

                                break;
                            }
                        }

                        i++;
                        n++;
                    }

                    i--;
                    break;

                case "#pressure":
                    i++;

                    while (i < lines.Length && !lines[i].StartsWith("#", StringComparison.InvariantCultureIgnoreCase))
                    {
                        double a;

                        if (double.TryParse(lines[i], NumberStyles.Float, culture, out a))
                        {
                            switch (n)
                            {
                            case 0:
                                if (a > 0.0)
                                {
                                    pressure.BrakeCylinderServiceMaximumPressure = a;
                                }

                                break;

                            case 1:
                                if (a > 0.0)
                                {
                                    pressure.BrakeCylinderEmergencyMaximumPressure = a;
                                }

                                break;

                            case 2:
                                if (a > 0.0)
                                {
                                    pressure.MainReservoirMinimumPressure = a;
                                }

                                break;

                            case 3:
                                if (a > 0.0)
                                {
                                    pressure.MainReservoirMaximumPressure = a;
                                }

                                break;

                            case 4:
                                if (a > 0.0)
                                {
                                    pressure.BrakePipeNormalPressure = a;
                                }

                                break;
                            }
                        }

                        i++;
                        n++;
                    }

                    i--;
                    break;

                case "#handle":
                    i++;

                    while (i < lines.Length && !lines[i].StartsWith("#", StringComparison.InvariantCultureIgnoreCase))
                    {
                        double a;

                        if (double.TryParse(lines[i], NumberStyles.Float, culture, out a))
                        {
                            int b = (int)Math.Round(a);

                            switch (n)
                            {
                            case 0:
                                if (b == 0 | b == 1)
                                {
                                    train.Handle.HandleType = (Handle.HandleTypes)b;
                                }

                                break;

                            case 1:
                                if (b > 0)
                                {
                                    train.Handle.PowerNotches = b;
                                }

                                break;

                            case 2:
                                if (b > 0)
                                {
                                    train.Handle.BrakeNotches = b;
                                }

                                break;

                            case 3:
                                if (b >= 0)
                                {
                                    train.Handle.PowerNotchReduceSteps = b;
                                }

                                break;

                            case 4:
                                if (a >= 0 && a < 4)
                                {
                                    train.Handle.HandleBehaviour = (EbHandleBehaviour)b;
                                }

                                break;

                            case 5:
                                if (b > 0)
                                {
                                    train.Handle.LocoBrakeNotches = b;
                                }

                                break;

                            case 6:
                                if (a <= 0 && a > 3)
                                {
                                    train.Handle.LocoBrake = (LocoBrakeType)b;
                                }

                                break;

                            case 7:
                                if (b > 0)
                                {
                                    train.Handle.DriverPowerNotches = b;
                                }

                                break;

                            case 8:
                                if (b > 0)
                                {
                                    train.Handle.DriverBrakeNotches = b;
                                }

                                break;
                            }
                        }

                        i++;
                        n++;
                    }

                    i--;
                    break;

                case "#cockpit":
                case "#cab":
                    i++;

                    while (i < lines.Length && !lines[i].StartsWith("#", StringComparison.InvariantCultureIgnoreCase))
                    {
                        double a;

                        if (double.TryParse(lines[i], NumberStyles.Float, culture, out a))
                        {
                            switch (n)
                            {
                            case 0:
                                train.Cab.PositionX = a;
                                break;

                            case 1:
                                train.Cab.PositionY = a;
                                break;

                            case 2:
                                train.Cab.PositionZ = a;
                                break;

                            case 3:
                                train.Cab.DriverCar = (int)Math.Round(a);
                                break;
                            }
                        }

                        i++;
                        n++;
                    }

                    i--;
                    break;

                case "#car":
                    i++;

                    while (i < lines.Length && !lines[i].StartsWith("#", StringComparison.InvariantCultureIgnoreCase))
                    {
                        double a;

                        if (double.TryParse(lines[i], NumberStyles.Float, culture, out a))
                        {
                            int b = (int)Math.Round(a);

                            switch (n)
                            {
                            case 0:
                                if (a > 0.0)
                                {
                                    motorCarMass = a;
                                }

                                break;

                            case 1:
                                if (b >= 1)
                                {
                                    numberOfMotorCars = b;
                                }

                                break;

                            case 2:
                                if (a > 0.0)
                                {
                                    trailerCarMass = a;
                                }

                                break;

                            case 3:
                                if (b >= 0)
                                {
                                    numberOfTrailerCars = b;
                                }

                                break;

                            case 4:
                                if (b > 0.0)
                                {
                                    lengthOfACar = a;
                                }

                                break;

                            case 5:
                                frontCarIsAMotorCar = a == 1.0;
                                break;

                            case 6:
                                if (a > 0.0)
                                {
                                    widthOfACar = a;
                                }

                                break;

                            case 7:
                                if (a > 0.0)
                                {
                                    heightOfACar = a;
                                }

                                break;

                            case 8:
                                centerOfGravityHeight = a;
                                break;

                            case 9:
                                if (a > 0.0)
                                {
                                    exposedFrontalArea = a;
                                }

                                break;

                            case 10:
                                if (a > 0.0)
                                {
                                    unexposedFrontalArea = a;
                                }

                                break;
                            }
                        }

                        i++;
                        n++;
                    }

                    i--;
                    break;

                case "#device":
                    i++;

                    while (i < lines.Length && !lines[i].StartsWith("#", StringComparison.InvariantCultureIgnoreCase))
                    {
                        double a;

                        if (double.TryParse(lines[i], NumberStyles.Float, culture, out a))
                        {
                            int b = (int)Math.Round(a);

                            switch (n)
                            {
                            case 0:
                                if (b >= -1 & b <= 1)
                                {
                                    train.Device.Ats = (AtsModes)b;
                                }

                                break;

                            case 1:
                                if (b >= 0 & b <= 2)
                                {
                                    train.Device.Atc = (AtcModes)b;
                                }

                                break;

                            case 2:
                                train.Device.Eb = a == 1.0;
                                break;

                            case 3:
                                train.Device.ConstSpeed = a == 1.0;
                                break;

                            case 4:
                                train.Device.HoldBrake = a == 1.0;
                                break;

                            case 5:
                                if (b >= -1 & b <= 3)
                                {
                                    train.Device.ReAdhesionDevice = (ReadhesionDeviceType)b;
                                }

                                break;

                            case 6:
                                train.Device.LoadCompensatingDevice = a;
                                break;

                            case 7:
                                if (b >= 0 & b <= 2)
                                {
                                    train.Device.PassAlarm = (PassAlarmType)b;
                                }

                                break;

                            case 8:
                                if (b >= 0 & b <= 2)
                                {
                                    train.Device.DoorOpenMode = (DoorMode)b;
                                }

                                break;

                            case 9:
                                if (b >= 0 & b <= 2)
                                {
                                    train.Device.DoorCloseMode = (DoorMode)b;
                                }

                                break;

                            case 10:
                                if (a >= 0.0)
                                {
                                    train.Device.DoorWidth = a;
                                }

                                break;

                            case 11:
                                if (a >= 0.0)
                                {
                                    train.Device.DoorMaxTolerance = a;
                                }

                                break;
                            }
                        }

                        i++;
                        n++;
                    }

                    i--;
                    break;

                case "#motor_p1":
                case "#motor_p2":
                case "#motor_b1":
                case "#motor_b2":
                {
                    string section = lines[i].ToLowerInvariant();
                    i++;
                    BVEMotorSoundTableEntry[] entries = new BVEMotorSoundTableEntry[800];

                    while (i < lines.Length && !lines[i].StartsWith("#", StringComparison.InvariantCultureIgnoreCase))
                    {
                        if (n == entries.Length)
                        {
                            Array.Resize(ref entries, entries.Length << 1);
                        }

                        string u = lines[i] + ",";
                        int    k = 0;

                        while (true)
                        {
                            int j = u.IndexOf(',');

                            if (j == -1)
                            {
                                break;
                            }

                            string s = u.Substring(0, j).Trim();
                            u = u.Substring(j + 1);
                            double a;

                            if (double.TryParse(s, NumberStyles.Float, culture, out a))
                            {
                                int b = (int)Math.Round(a);

                                switch (k)
                                {
                                case 0:
                                    entries[n].SoundIndex = b >= 0 ? b : -1;
                                    break;

                                case 1:
                                    entries[n].Pitch = (float)Math.Max(a, 0.0);
                                    break;

                                case 2:
                                    entries[n].Gain = (float)Math.Max(a, 0.0);
                                    break;
                                }
                            }

                            k++;
                        }

                        i++;
                        n++;
                    }

                    Array.Resize(ref entries, n);
                    i--;

                    switch (section)
                    {
                    case "#motor_p1":
                        motor.Tracks[(int)Motor.TrackInfo.Power1] = Motor.Track.EntriesToTrack(entries);
                        break;

                    case "#motor_p2":
                        motor.Tracks[(int)Motor.TrackInfo.Power2] = Motor.Track.EntriesToTrack(entries);
                        break;

                    case "#motor_b1":
                        motor.Tracks[(int)Motor.TrackInfo.Brake1] = Motor.Track.EntriesToTrack(entries);
                        break;

                    case "#motor_b2":
                        motor.Tracks[(int)Motor.TrackInfo.Brake2] = Motor.Track.EntriesToTrack(entries);
                        break;
                    }
                }
                break;
                }
            }

            int numberOfCars = numberOfMotorCars + numberOfTrailerCars;

            bool[] isMotorCars = new bool[numberOfCars];
            if (numberOfMotorCars == 1)
            {
                if (frontCarIsAMotorCar | numberOfTrailerCars == 0)
                {
                    isMotorCars[0] = true;
                }
                else
                {
                    isMotorCars[numberOfCars - 1] = true;
                }
            }
            else if (numberOfMotorCars == 2)
            {
                if (frontCarIsAMotorCar | numberOfTrailerCars == 0)
                {
                    isMotorCars[0] = true;
                    isMotorCars[numberOfCars - 1] = true;
                }
                else if (numberOfTrailerCars == 1)
                {
                    isMotorCars[1] = true;
                    isMotorCars[2] = true;
                }
                else
                {
                    int i = (int)Math.Ceiling(0.25 * (numberOfCars - 1));
                    int j = (int)Math.Floor(0.75 * (numberOfCars - 1));
                    isMotorCars[i] = true;
                    isMotorCars[j] = true;
                }
            }
            else if (numberOfMotorCars > 0)
            {
                if (frontCarIsAMotorCar)
                {
                    isMotorCars[0] = true;
                    double t = 1.0 + numberOfTrailerCars / (double)(numberOfMotorCars - 1);
                    double r = 0.0;
                    double x = 0.0;

                    while (true)
                    {
                        double y = x + t - r;
                        x = Math.Ceiling(y);
                        r = x - y;
                        int i = (int)x;

                        if (i >= numberOfCars)
                        {
                            break;
                        }

                        isMotorCars[i] = true;
                    }
                }
                else
                {
                    isMotorCars[1] = true;
                    double t = 1.0 + (numberOfTrailerCars - 1) / (double)(numberOfMotorCars - 1);
                    double r = 0.0;
                    double x = 1.0;

                    while (true)
                    {
                        double y = x + t - r;
                        x = Math.Ceiling(y);
                        r = x - y;
                        int i = (int)x;

                        if (i >= numberOfCars)
                        {
                            break;
                        }

                        isMotorCars[i] = true;
                    }
                }
            }

            foreach (bool isMotorCar in isMotorCars)
            {
                Car car = isMotorCar ? (Car) new MotorCar() : new TrailerCar();

                car.Mass   = isMotorCar ? motorCarMass : trailerCarMass;
                car.Length = lengthOfACar;
                car.Width  = widthOfACar;
                car.Height = heightOfACar;
                car.CenterOfGravityHeight = centerOfGravityHeight;
                car.ExposedFrontalArea    = exposedFrontalArea;
                car.UnexposedFrontalArea  = unexposedFrontalArea;
                car.Performance           = (Performance)performance.Clone();
                car.Delay    = (Delay)delay.Clone();
                car.Move     = (Move)move.Clone();
                car.Brake    = (Brake)brake.Clone();
                car.Pressure = (Pressure)pressure.Clone();

                if (isMotorCar)
                {
                    ((MotorCar)car).Acceleration = (Acceleration)acceleration.Clone();
                    ((MotorCar)car).Motor        = (Motor)motor.Clone();
                }

                train.Cars.Add(car);
            }

            for (int i = 0; i < numberOfCars - 1; i++)
            {
                train.Couplers.Add(new Models.Trains.Coupler());
            }
        }
Example #12
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;
                    }
                }
            }
        }