Example #1
0
        /// <summary>Parses any command-line arguments passed to the main program</summary>
        /// <param name="Arguments">A string array of arguments</param>
        /// <param name="Result">The main dialog result (Used to launch)</param>
        internal static void ParseArguments(string[] Arguments, ref formMain.MainDialogResult Result)
        {
            if (Arguments.Length == 0)
            {
                return;
            }
            for (int i = 0; i < Arguments.Length; i++)
            {
                int equals = Arguments[i].IndexOf('=');
                if (@equals >= 0)
                {
                    string key   = Arguments[i].Substring(0, @equals).Trim().ToLowerInvariant();
                    string value = Arguments[i].Substring(@equals + 1).Trim();
                    switch (key)
                    {
                    case "/route":
                        Result.RouteFile = value;
                        switch (TextEncoding.GetEncodingFromFile(Result.RouteFile))
                        {
                        case TextEncoding.Encoding.Utf7:
                            Result.RouteEncoding = System.Text.Encoding.UTF7;
                            break;

                        case TextEncoding.Encoding.Utf8:
                            Result.RouteEncoding = System.Text.Encoding.UTF8;
                            break;

                        case TextEncoding.Encoding.Utf16Le:
                            Result.RouteEncoding = System.Text.Encoding.Unicode;
                            break;

                        case TextEncoding.Encoding.Utf16Be:
                            Result.RouteEncoding = System.Text.Encoding.BigEndianUnicode;
                            break;

                        case TextEncoding.Encoding.Utf32Le:
                            Result.RouteEncoding = System.Text.Encoding.UTF32;
                            break;

                        case TextEncoding.Encoding.Utf32Be:
                            Result.RouteEncoding = System.Text.Encoding.GetEncoding(12001);
                            break;

                        case TextEncoding.Encoding.Shift_JIS:
                            Result.RouteEncoding = System.Text.Encoding.GetEncoding(932);
                            break;

                        case TextEncoding.Encoding.Windows1252:
                            Result.RouteEncoding = System.Text.Encoding.GetEncoding(1252);
                            break;

                        case TextEncoding.Encoding.Big5:
                            Result.RouteEncoding = System.Text.Encoding.GetEncoding(950);
                            break;

                        default:
                            Result.RouteEncoding = Encoding.Default;
                            break;
                        }
                        break;

                    case "/train":
                        Result.TrainFolder = value;
                        switch (TextEncoding.GetEncodingFromFile(Result.TrainFolder, "train.txt"))
                        {
                        case TextEncoding.Encoding.Utf8:
                            Result.TrainEncoding = System.Text.Encoding.UTF8;
                            break;

                        case TextEncoding.Encoding.Utf16Le:
                            Result.TrainEncoding = System.Text.Encoding.Unicode;
                            break;

                        case TextEncoding.Encoding.Utf16Be:
                            Result.TrainEncoding = System.Text.Encoding.BigEndianUnicode;
                            break;

                        case TextEncoding.Encoding.Utf32Le:
                            Result.TrainEncoding = System.Text.Encoding.UTF32;
                            break;

                        case TextEncoding.Encoding.Utf32Be:
                            Result.TrainEncoding = System.Text.Encoding.GetEncoding(12001);
                            break;

                        case TextEncoding.Encoding.Shift_JIS:
                            Result.TrainEncoding = System.Text.Encoding.GetEncoding(932);
                            break;

                        case TextEncoding.Encoding.Windows1252:
                            Result.TrainEncoding = System.Text.Encoding.GetEncoding(1252);
                            break;

                        case TextEncoding.Encoding.Big5:
                            Result.TrainEncoding = System.Text.Encoding.GetEncoding(950);
                            break;

                        default:
                            Result.TrainEncoding = Encoding.Default;
                            break;
                        }
                        break;

                    case "/station":
                        Result.InitialStation = value;
                        break;

                    case "/time":
                        Interface.TryParseTime(value, out Result.StartTime);
                        break;

                    case "/ai":
                        if (value.ToLowerInvariant() == "true" || value.ToLowerInvariant() == "1")
                        {
                            Result.AIDriver = true;
                        }
                        break;

                    case "/fullscreen":
                        if (value.ToLowerInvariant() == "true" || value.ToLowerInvariant() == "1")
                        {
                            Result.FullScreen = true;
                        }
                        break;

                    case "/width":
                        NumberFormats.TryParseIntVb6(value, out Result.Width);
                        break;

                    case "/height":
                        NumberFormats.TryParseIntVb6(value, out Result.Height);
                        break;
                    }
                }
            }
        }
Example #2
0
        /// <summary>Loads an object</summary>
        /// <param name="FileName">The file to load</param>
        /// <param name="Encoding">The text endcoding of the base file (Used if the encoding cannot be auto-detected)</param>
        /// <param name="PreserveVertices">Whether object should be optimized to remove duplicate vertices</param>
        /// <returns>The new object, or a null reference if loading fails</returns>

        /*
         * Notes for refactoring:
         *   * Unused vertices must only be preserved in deformable objects (e.g. Crack and Form)
         *   * TODO / BUG: No detection of actual file contents, which will make all parsers barf
         */
        internal static UnifiedObject LoadObject(string FileName, Encoding Encoding, bool PreserveVertices)
        {
            if (String.IsNullOrEmpty(FileName))
            {
                return(null);
            }
#if !DEBUG
            try {
#endif
            if (!System.IO.Path.HasExtension(FileName))
            {
                while (true)
                {
                    var f = OpenBveApi.Path.CombineFile(System.IO.Path.GetDirectoryName(FileName), System.IO.Path.GetFileName(FileName) + ".x");
                    if (System.IO.File.Exists(f))
                    {
                        FileName = f;
                        break;
                    }
                    f = OpenBveApi.Path.CombineFile(System.IO.Path.GetDirectoryName(FileName), System.IO.Path.GetFileName(FileName) + ".csv");
                    if (System.IO.File.Exists(f))
                    {
                        FileName = f;
                        break;
                    }
                    f = OpenBveApi.Path.CombineFile(System.IO.Path.GetDirectoryName(FileName), System.IO.Path.GetFileName(FileName) + ".b3d");
                    if (System.IO.File.Exists(f))
                    {
                        FileName = f;
                        break;
                    }
                    f = OpenBveApi.Path.CombineFile(System.IO.Path.GetDirectoryName(FileName), System.IO.Path.GetFileName(FileName) + ".xml");
                    if (System.IO.File.Exists(f))
                    {
                        FileName = f;
                        break;
                    }
                    f = OpenBveApi.Path.CombineFile(System.IO.Path.GetDirectoryName(FileName), System.IO.Path.GetFileName(FileName) + ".l3dgrp");
                    if (System.IO.File.Exists(f))
                    {
                        FileName = f;
                        break;
                    }
                    f = OpenBveApi.Path.CombineFile(System.IO.Path.GetDirectoryName(FileName), System.IO.Path.GetFileName(FileName) + ".l3dobj");
                    if (System.IO.File.Exists(f))
                    {
                        FileName = f;
                        break;
                    }
                }
            }
            UnifiedObject Result;
            TextEncoding.Encoding newEncoding = TextEncoding.GetEncodingFromFile(FileName);
            if (newEncoding != TextEncoding.Encoding.Unknown)
            {
                switch (newEncoding)
                {
                case TextEncoding.Encoding.Utf7:
                    Encoding = System.Text.Encoding.UTF7;
                    break;

                case TextEncoding.Encoding.Utf8:
                    Encoding = System.Text.Encoding.UTF8;
                    break;

                case TextEncoding.Encoding.Utf16Le:
                    Encoding = System.Text.Encoding.Unicode;
                    break;

                case TextEncoding.Encoding.Utf16Be:
                    Encoding = System.Text.Encoding.BigEndianUnicode;
                    break;

                case TextEncoding.Encoding.Utf32Le:
                    Encoding = System.Text.Encoding.UTF32;
                    break;

                case TextEncoding.Encoding.Utf32Be:
                    Encoding = System.Text.Encoding.GetEncoding(12001);
                    break;

                case TextEncoding.Encoding.Shift_JIS:
                    Encoding = System.Text.Encoding.GetEncoding(932);
                    break;

                case TextEncoding.Encoding.Windows1252:
                    Encoding = System.Text.Encoding.GetEncoding(1252);
                    break;

                case TextEncoding.Encoding.Big5:
                    Encoding = System.Text.Encoding.GetEncoding(950);
                    break;

                case TextEncoding.Encoding.EUC_KR:
                    Encoding = System.Text.Encoding.GetEncoding(949);
                    break;
                }
            }
            string e = System.IO.Path.GetExtension(FileName);
            if (e == null)
            {
                Interface.AddMessage(MessageType.Error, false, "The file " + FileName + " does not have a recognised extension.");
                return(null);
            }
            switch (e.ToLowerInvariant())
            {
            case ".csv":
            case ".b3d":
            case ".x":
            case ".obj":
                Program.CurrentHost.LoadObject(FileName, Encoding, out Result);
                break;

            case ".animated":
                Result = AnimatedObjectParser.ReadObject(FileName, Encoding);
                break;

            case ".xml":
                Result = XMLParser.ReadObject(FileName, Encoding);
                break;

            case ".l3dgrp":
                Result = Ls3DGrpParser.ReadObject(FileName, Encoding, new Vector3());
                break;

            case ".l3dobj":
                Result = Ls3DObjectParser.ReadObject(FileName, new Vector3());
                break;

            case ".s":
                Result = MsTsShapeParser.ReadObject(FileName);
                break;

            default:
                Interface.AddMessage(MessageType.Error, false, "The file extension is not supported: " + FileName);
                return(null);
            }
            if (Result != null)
            {
                Result.OptimizeObject(PreserveVertices, Interface.CurrentOptions.ObjectOptimizationBasicThreshold, Interface.CurrentOptions.ObjectOptimizationVertexCulling);
            }
            return(Result);

#if !DEBUG
        }

        catch (Exception ex) {
            Interface.AddMessage(MessageType.Error, true, "An unexpected error occured (" + ex.Message + ") while attempting to load the file " + FileName);
            return(null);
        }
#endif
        }
Example #3
0
        /// <summary>Parses a base track following object node</summary>
        /// <param name="Element">The XElement to parse</param>
        /// <param name="FileName">The filename of the containing XML file</param>
        /// <param name="Path">The path of the containing XML file</param>
        /// <param name="Train">The track following object to parse this node into</param>
        private static void ParseTrackFollowingObjectNode(XElement Element, string FileName, string Path, string ObjectPath, TrainManager.TrackFollowingObject Train)
        {
            System.Globalization.CultureInfo Culture = System.Globalization.CultureInfo.InvariantCulture;
            string TrainDirectory       = string.Empty;
            bool   consistReversed      = false;
            List <Game.TravelData> Data = new List <Game.TravelData>();

            foreach (XElement SectionElement in Element.Elements())
            {
                string Section = SectionElement.Name.LocalName;

                switch (SectionElement.Name.LocalName.ToLowerInvariant())
                {
                case "stops":
                    ParseStopNode(SectionElement, FileName, Data);
                    break;

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

                        switch (Key.ToLowerInvariant())
                        {
                        case "directory":
                        {
                            string trainDirectory = OpenBveApi.Path.CombineDirectory(Path, Value);
                            if (!System.IO.Directory.Exists(trainDirectory))
                            {
                                trainDirectory = OpenBveApi.Path.CombineFile(Program.FileSystem.InitialTrainFolder, Value);
                            }
                            if (!System.IO.Directory.Exists(trainDirectory))
                            {
                                trainDirectory = OpenBveApi.Path.CombineFile(Program.FileSystem.TrainInstallationDirectory, Value);
                            }
                            if (!System.IO.Directory.Exists(trainDirectory))
                            {
                                trainDirectory = OpenBveApi.Path.CombineFile(ObjectPath, Value);
                            }

                            if (!System.IO.Directory.Exists(trainDirectory))
                            {
                                Interface.AddMessage(MessageType.Error, false, "Directory was not found in " + Key + " in " + Section + " at line " + LineNumber.ToString(Culture) + " in " + FileName);
                            }
                            else
                            {
                                TrainDirectory = trainDirectory;
                            }
                        }
                        break;

                        case "reversed":
                            int n;
                            NumberFormats.TryParseIntVb6(Value, out n);
                            if (n == 1 || Value.ToLowerInvariant() == "true")
                            {
                                consistReversed = true;
                            }
                            break;
                        }
                    }
                    break;

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

                        switch (Key.ToLowerInvariant())
                        {
                        case "appearancetime":
                            if (Value.Length != 0 && !Interface.TryParseTime(Value, out Train.AppearanceTime))
                            {
                                Interface.AddMessage(MessageType.Error, false, "Value is invalid in " + Key + " in " + Section + " at line " + LineNumber.ToString(Culture) + " in " + FileName);
                            }
                            break;

                        case "appearancestartposition":
                            if (Value.Length != 0 && !NumberFormats.TryParseDoubleVb6(Value, out Train.AppearanceStartPosition))
                            {
                                Interface.AddMessage(MessageType.Error, false, "Value is invalid in " + Key + " in " + Section + " at line " + LineNumber.ToString(Culture) + " in " + FileName);
                            }
                            break;

                        case "appearanceendposition":
                            if (Value.Length != 0 && !NumberFormats.TryParseDoubleVb6(Value, out Train.AppearanceEndPosition))
                            {
                                Interface.AddMessage(MessageType.Error, false, "Value is invalid in " + Key + " in " + Section + " at line " + LineNumber.ToString(Culture) + " in " + FileName);
                            }
                            break;

                        case "leavetime":
                            if (Value.Length != 0 && !Interface.TryParseTime(Value, out Train.LeaveTime))
                            {
                                Interface.AddMessage(MessageType.Error, false, "Value is invalid in " + Key + " in " + Section + " at line " + LineNumber.ToString(Culture) + " in " + FileName);
                            }
                            break;
                        }
                    }
                    break;
                }
            }

            if (!Data.Any() || string.IsNullOrEmpty(TrainDirectory))
            {
                return;
            }

            /*
             * First check for a train.ai file- Functionally identical, but allows for differently configured AI
             * trains not to show up as driveable
             */
            string TrainData = OpenBveApi.Path.CombineFile(TrainDirectory, "train.ai");

            if (!System.IO.File.Exists(TrainData))
            {
                // Check for the standard driveable train.dat
                TrainData = OpenBveApi.Path.CombineFile(TrainDirectory, "train.dat");
            }
            string ExteriorFile = OpenBveApi.Path.CombineFile(TrainDirectory, "extensions.cfg");

            if (!System.IO.File.Exists(TrainData) || !System.IO.File.Exists(ExteriorFile))
            {
                Interface.AddMessage(MessageType.Error, true, "The supplied train folder in TrackFollowingObject " + FileName + " did not contain a complete set of data.");
                return;
            }
            TrainDatParser.ParseTrainData(TrainData, TextEncoding.GetSystemEncodingFromFile(TrainData), Train);
            SoundCfgParser.ParseSoundConfig(TrainDirectory, Train);
            Train.AI = new Game.TrackFollowingObjectAI(Train, Data);

            UnifiedObject[] CarObjects     = new UnifiedObject[Train.Cars.Length];
            UnifiedObject[] BogieObjects   = new UnifiedObject[Train.Cars.Length * 2];
            UnifiedObject[] CouplerObjects = new UnifiedObject[Train.Cars.Length - 1];
            ExtensionsCfgParser.ParseExtensionsConfig(System.IO.Path.GetDirectoryName(ExteriorFile), TextEncoding.GetSystemEncodingFromFile(ExteriorFile), ref CarObjects, ref BogieObjects, ref CouplerObjects, Train, true);

            int currentBogieObject = 0;

            for (int i = 0; i < Train.Cars.Length; i++)
            {
                if (CarObjects[i] == null)
                {
                    // load default exterior object
                    string       file = OpenBveApi.Path.CombineFile(Program.FileSystem.GetDataFolder("Compatibility"), "exterior.csv");
                    StaticObject so   = ObjectManager.LoadStaticObject(file, System.Text.Encoding.UTF8, false);
                    if (so == null)
                    {
                        CarObjects[i] = null;
                    }
                    else
                    {
                        double sx = Train.Cars[i].Width;
                        double sy = Train.Cars[i].Height;
                        double sz = Train.Cars[i].Length;
                        so.ApplyScale(sx, sy, sz);
                        CarObjects[i] = so;
                    }
                }
                if (CarObjects[i] != null)
                {
                    // add object
                    Train.Cars[i].LoadCarSections(CarObjects[i]);
                }

                //Load bogie objects
                if (BogieObjects[currentBogieObject] != null)
                {
                    Train.Cars[i].FrontBogie.LoadCarSections(BogieObjects[currentBogieObject]);
                }
                currentBogieObject++;
                if (BogieObjects[currentBogieObject] != null)
                {
                    Train.Cars[i].RearBogie.LoadCarSections(BogieObjects[currentBogieObject]);
                }
                currentBogieObject++;
            }

            // door open/close speed
            foreach (var Car in Train.Cars)
            {
                if (Car.Specs.DoorOpenFrequency <= 0.0)
                {
                    if (Car.Doors[0].OpenSound.Buffer != null & Car.Doors[1].OpenSound.Buffer != null)
                    {
                        Program.Sounds.LoadBuffer(Car.Doors[0].OpenSound.Buffer);
                        Program.Sounds.LoadBuffer(Car.Doors[1].OpenSound.Buffer);
                        double a = Car.Doors[0].OpenSound.Buffer.Duration;
                        double b = Car.Doors[1].OpenSound.Buffer.Duration;
                        Car.Specs.DoorOpenFrequency = a + b > 0.0 ? 2.0 / (a + b) : 0.8;
                    }
                    else if (Car.Doors[0].OpenSound.Buffer != null)
                    {
                        Program.Sounds.LoadBuffer(Car.Doors[0].OpenSound.Buffer);
                        double a = Car.Doors[0].OpenSound.Buffer.Duration;
                        Car.Specs.DoorOpenFrequency = a > 0.0 ? 1.0 / a : 0.8;
                    }
                    else if (Car.Doors[1].OpenSound.Buffer != null)
                    {
                        Program.Sounds.LoadBuffer(Car.Doors[0].OpenSound.Buffer);
                        double b = Car.Doors[1].OpenSound.Buffer.Duration;
                        Car.Specs.DoorOpenFrequency = b > 0.0 ? 1.0 / b : 0.8;
                    }
                    else
                    {
                        Car.Specs.DoorOpenFrequency = 0.8;
                    }
                }
                if (Car.Specs.DoorCloseFrequency <= 0.0)
                {
                    if (Car.Doors[0].CloseSound.Buffer != null & Car.Doors[1].CloseSound.Buffer != null)
                    {
                        Program.Sounds.LoadBuffer(Car.Doors[0].CloseSound.Buffer);
                        Program.Sounds.LoadBuffer(Car.Doors[1].CloseSound.Buffer);
                        double a = Car.Doors[0].CloseSound.Buffer.Duration;
                        double b = Car.Doors[1].CloseSound.Buffer.Duration;
                        Car.Specs.DoorCloseFrequency = a + b > 0.0 ? 2.0 / (a + b) : 0.8;
                    }
                    else if (Car.Doors[0].CloseSound.Buffer != null)
                    {
                        Program.Sounds.LoadBuffer(Car.Doors[0].CloseSound.Buffer);
                        double a = Car.Doors[0].CloseSound.Buffer.Duration;
                        Car.Specs.DoorCloseFrequency = a > 0.0 ? 1.0 / a : 0.8;
                    }
                    else if (Car.Doors[1].CloseSound.Buffer != null)
                    {
                        Program.Sounds.LoadBuffer(Car.Doors[0].CloseSound.Buffer);
                        double b = Car.Doors[1].CloseSound.Buffer.Duration;
                        Car.Specs.DoorCloseFrequency = b > 0.0 ? 1.0 / b : 0.8;
                    }
                    else
                    {
                        Car.Specs.DoorCloseFrequency = 0.8;
                    }
                }
                const double f = 0.015;
                const double g = 2.75;
                Car.Specs.DoorOpenPitch       = Math.Exp(f * Math.Tan(g * (Program.RandomNumberGenerator.NextDouble() - 0.5)));
                Car.Specs.DoorClosePitch      = Math.Exp(f * Math.Tan(g * (Program.RandomNumberGenerator.NextDouble() - 0.5)));
                Car.Specs.DoorOpenFrequency  /= Car.Specs.DoorOpenPitch;
                Car.Specs.DoorCloseFrequency /= Car.Specs.DoorClosePitch;

                /*
                 * Remove the following two lines, then the pitch at which doors play
                 * takes their randomized opening and closing times into account.
                 * */
                Car.Specs.DoorOpenPitch  = 1.0;
                Car.Specs.DoorClosePitch = 1.0;
            }

            foreach (var Car in Train.Cars)
            {
                Car.FrontAxle.Follower.TrackIndex            = Data[0].RailIndex;
                Car.RearAxle.Follower.TrackIndex             = Data[0].RailIndex;
                Car.FrontBogie.FrontAxle.Follower.TrackIndex = Data[0].RailIndex;
                Car.FrontBogie.RearAxle.Follower.TrackIndex  = Data[0].RailIndex;
                Car.RearBogie.FrontAxle.Follower.TrackIndex  = Data[0].RailIndex;
                Car.RearBogie.RearAxle.Follower.TrackIndex   = Data[0].RailIndex;
            }

            if (consistReversed)
            {
                Train.Reverse();
            }
            Train.PlaceCars(Data[0].StopPosition);
        }
Example #4
0
        // parse extensions config
        internal static void ParseExtensionsConfig(string TrainPath, System.Text.Encoding Encoding, ref UnifiedObject[] CarObjects, ref UnifiedObject[] BogieObjects, TrainManager.Train Train, bool LoadObjects)
        {
            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))
            {
                TextEncoding.Encoding newEncoding = TextEncoding.GetEncodingFromFile(FileName);
                if (newEncoding != TextEncoding.Encoding.Unknown)
                {
                    switch (newEncoding)
                    {
                    case TextEncoding.Encoding.Utf7:
                        Encoding = System.Text.Encoding.UTF7;
                        break;

                    case TextEncoding.Encoding.Utf8:
                        Encoding = System.Text.Encoding.UTF8;
                        break;

                    case TextEncoding.Encoding.Utf16Le:
                        Encoding = System.Text.Encoding.Unicode;
                        break;

                    case TextEncoding.Encoding.Utf16Be:
                        Encoding = System.Text.Encoding.BigEndianUnicode;
                        break;

                    case TextEncoding.Encoding.Utf32Le:
                        Encoding = System.Text.Encoding.UTF32;
                        break;

                    case TextEncoding.Encoding.Utf32Be:
                        Encoding = System.Text.Encoding.GetEncoding(12001);
                        break;

                    case TextEncoding.Encoding.Shift_JIS:
                        Encoding = System.Text.Encoding.GetEncoding(932);
                        break;
                    }
                }

                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();
                    }
                    else
                    {
                        Lines[i] = Lines[i].Trim();
                    }
                }
                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();
                                        string b = Lines[i].Substring(j + 1).TrimStart();
                                        int    n;
                                        if (int.TryParse(a, System.Globalization.NumberStyles.Integer, Culture, out n))
                                        {
                                            if (n >= 0 & n < Train.Cars.Length)
                                            {
                                                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 = OpenBveApi.Path.CombineFile(TrainPath, b);
                                                    if (System.IO.File.Exists(File))
                                                    {
                                                        if (LoadObjects)
                                                        {
                                                            CarObjects[n] = ObjectManager.LoadObject(File, Encoding, false, false, false);
                                                        }
                                                    }
                                                    else
                                                    {
                                                        Interface.AddMessage(MessageType.Error, true, "The car object " + File + " does not exist at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                                    }
                                                }
                                            }
                                            else
                                            {
                                                Interface.AddMessage(MessageType.Error, false, "The car index " + a + " 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, System.Globalization.NumberStyles.Integer, Culture, out n))
                                {
                                    if (n >= 0 & n < Train.Cars.Length)
                                    {
                                        if (CarsDefined[n])
                                        {
                                            Interface.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();
                                                    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);
                                                            break;
                                                        }
                                                        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 = OpenBveApi.Path.CombineFile(TrainPath, b);
                                                            if (System.IO.File.Exists(File))
                                                            {
                                                                if (LoadObjects)
                                                                {
                                                                    CarObjects[n] = ObjectManager.LoadObject(File, Encoding, false, false, false);
                                                                }
                                                            }
                                                            else
                                                            {
                                                                Interface.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
                                                            {
                                                                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, System.Globalization.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, System.Globalization.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.Position  = rear;
                                                                Train.Cars[n].FrontAxle.Position = front;
                                                                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":
                                                        CarObjectsReversed[n] = 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--;
                                        if (DefinedLength & !DefinedAxles)
                                        {
                                            double AxleDistance = 0.4 * Train.Cars[n].Length;
                                            Train.Cars[n].RearAxle.Position  = -AxleDistance;
                                            Train.Cars[n].FrontAxle.Position = AxleDistance;
                                        }
                                    }
                                    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, System.Globalization.NumberStyles.Integer, Culture, out n))
                                {
                                    if (n >= 0 & n < Train.Couplers.Length)
                                    {
                                        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();
                                                    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, System.Globalization.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, System.Globalization.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].MinimumDistanceBetweenCars = min;
                                                                Train.Couplers[n].MaximumDistanceBetweenCars = 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;

                                                    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))
                            {
                                // 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])
                                    {
                                        Interface.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();
                                                    string b = Lines[i].Substring(j + 1).TrimStart();
                                                    switch (a.ToLowerInvariant())
                                                    {
                                                    case "object":
                                                        if (Path.ContainsInvalidChars(b))
                                                        {
                                                            Interface.AddMessage(MessageType.Error, false, "File contains illegal characters at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                                        }
                                                        else
                                                        {
                                                            if (string.IsNullOrEmpty(b))
                                                            {
                                                                Interface.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))
                                                            {
                                                                if (LoadObjects)
                                                                {
                                                                    BogieObjects[n] = ObjectManager.LoadObject(File, Encoding, false, false, false);
                                                                }
                                                            }
                                                            else
                                                            {
                                                                Interface.AddMessage(MessageType.Error, true, "The bogie object " + File + " does not exist at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                                            }
                                                        }
                                                        break;

                                                    case "length":
                                                    {
                                                        Interface.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();
                                                            string d = b.Substring(k + 1).TrimStart();
                                                            double rear, front;
                                                            if (!double.TryParse(c, System.Globalization.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, System.Globalization.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].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
                                                        {
                                                            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":
                                                        BogieObjectsReversed[n] = 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--;
                                        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
                                    {
                                        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
                            {
                                // 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, Train, LoadObjects);
                                    return;
                                }
                                Interface.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] && LoadObjects)
                        {
                            {
                                // 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 ObjectManager.StaticObject)
                            {
                                ObjectManager.StaticObject obj = (ObjectManager.StaticObject)CarObjects[i];
                                obj.ApplyScale(-1.0, 1.0, -1.0);
                            }
                            else if (CarObjects[i] is ObjectManager.AnimatedObjectCollection)
                            {
                                ObjectManager.AnimatedObjectCollection obj = (ObjectManager.AnimatedObjectCollection)CarObjects[i];
                                for (int j = 0; j < obj.Objects.Length; j++)
                                {
                                    for (int h = 0; h < obj.Objects[j].States.Length; h++)
                                    {
                                        obj.Objects[j].States[h].Object.ApplyScale(-1.0, 1.0, -1.0);
                                        obj.Objects[j].States[h].Position.X *= -1.0;
                                        obj.Objects[j].States[h].Position.Z *= -1.0;
                                    }
                                    obj.Objects[j].TranslateXDirection.X *= -1.0;
                                    obj.Objects[j].TranslateXDirection.Z *= -1.0;
                                    obj.Objects[j].TranslateYDirection.X *= -1.0;
                                    obj.Objects[j].TranslateYDirection.Z *= -1.0;
                                    obj.Objects[j].TranslateZDirection.X *= -1.0;
                                    obj.Objects[j].TranslateZDirection.Z *= -1.0;
                                }
                            }
                            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] && LoadObjects)
                        {
                            {
                                // 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 ObjectManager.StaticObject)
                            {
                                ObjectManager.StaticObject obj = (ObjectManager.StaticObject)BogieObjects[i];
                                obj.ApplyScale(-1.0, 1.0, -1.0);
                            }
                            else if (BogieObjects[i] is ObjectManager.AnimatedObjectCollection)
                            {
                                ObjectManager.AnimatedObjectCollection obj = (ObjectManager.AnimatedObjectCollection)BogieObjects[i];
                                for (int j = 0; j < obj.Objects.Length; j++)
                                {
                                    for (int h = 0; h < obj.Objects[j].States.Length; h++)
                                    {
                                        obj.Objects[j].States[h].Object.ApplyScale(-1.0, 1.0, -1.0);
                                        obj.Objects[j].States[h].Position.X *= -1.0;
                                        obj.Objects[j].States[h].Position.Z *= -1.0;
                                    }
                                    obj.Objects[j].TranslateXDirection.X *= -1.0;
                                    obj.Objects[j].TranslateXDirection.Z *= -1.0;
                                    obj.Objects[j].TranslateYDirection.X *= -1.0;
                                    obj.Objects[j].TranslateYDirection.Z *= -1.0;
                                    obj.Objects[j].TranslateZDirection.X *= -1.0;
                                    obj.Objects[j].TranslateZDirection.Z *= -1.0;
                                }
                            }
                            else
                            {
                                throw new NotImplementedException();
                            }
                        }
                    }
                }

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

                if (bogieObjects > 0 & bogieObjects < Train.Cars.Length * 2)
                {
                    Interface.AddMessage(MessageType.Warning, false, "An incomplete set of bogie objects was provided in file " + FileName);
                }
            }
        }
Example #5
0
        internal static void ParseExtensionsConfig(string filePath, Encoding encoding, out UnifiedObject[] carObjects, out UnifiedObject[] bogieObjects, out double[] axleLocations, out TrainManager.Train train, bool loadObjects)
        {
            CultureInfo Culture = CultureInfo.InvariantCulture;

            carObjects    = new UnifiedObject[] { };
            bogieObjects  = new UnifiedObject[] { };
            axleLocations = new double[] { };
            train         = new TrainManager.Train();

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

            train.Cars = new TrainManager.Car[] { };
            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];
            axleLocations = new double[train.Cars.Length * 2];

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

            System.Globalization.CultureInfo culture     = System.Globalization.CultureInfo.InvariantCulture;
            TextEncoding.Encoding            newEncoding = TextEncoding.GetEncodingFromFile(filePath);
            if (newEncoding != TextEncoding.Encoding.Unknown)
            {
                switch (newEncoding)
                {
                case TextEncoding.Encoding.Utf7:
                    encoding = Encoding.UTF7;
                    break;

                case TextEncoding.Encoding.Utf8:
                    encoding = Encoding.UTF8;
                    break;

                case TextEncoding.Encoding.Utf16Le:
                    encoding = Encoding.Unicode;
                    break;

                case TextEncoding.Encoding.Utf16Be:
                    encoding = Encoding.BigEndianUnicode;
                    break;

                case TextEncoding.Encoding.Utf32Le:
                    encoding = Encoding.UTF32;
                    break;

                case TextEncoding.Encoding.Utf32Be:
                    encoding = Encoding.GetEncoding(12001);
                    break;

                case TextEncoding.Encoding.Shift_JIS:
                    encoding = Encoding.GetEncoding(932);
                    break;
                }
            }

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

            for (int i = 0; i < lines.Length; i++)
            {
                if (lines[i].Length != 0)
                {
                    switch (lines[i].ToLowerInvariant())
                    {
                    case "[exterior]":
                        // exterior
                        i++;
                        while (i < lines.Length && !lines[i].StartsWith("[", StringComparison.Ordinal) & !lines[i].EndsWith("]", StringComparison.Ordinal))
                        {
                            if (lines[i].Length != 0)
                            {
                                int j = lines[i].IndexOf("=", StringComparison.Ordinal);
                                if (j >= 0)
                                {
                                    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)
                                        {
                                            if (n >= train.Cars.Length)
                                            {
                                                Array.Resize(ref train.Cars, n + 1);
                                                train.Cars[n] = new TrainManager.Car(train);
                                                Array.Resize(ref carObjects, n + 1);
                                                Array.Resize(ref bogieObjects, (n + 1) * 2);
                                                Array.Resize(ref carObjectsReversed, n + 1);
                                                Array.Resize(ref bogieObjectsReversed, (n + 1) * 2);
                                                Array.Resize(ref carsDefined, n + 1);
                                                Array.Resize(ref bogiesDefined, (n + 1) * 2);
                                                Array.Resize(ref axleLocations, (n + 1) * 2);
                                            }
                                            if (Path.ContainsInvalidChars(b))
                                            {
                                                Interface.AddMessage(MessageType.Error, false, "File contains illegal characters at line " + (i + 1).ToString(culture) + " in file " + filePath);
                                            }
                                            else
                                            {
                                                string file = OpenBveApi.Path.CombineFile(trainPath, b);
                                                if (System.IO.File.Exists(file))
                                                {
                                                    if (loadObjects)
                                                    {
                                                        carObjects[n] = ObjectManager.LoadObject(file, encoding, false);
                                                    }
                                                }
                                                else
                                                {
                                                    Interface.AddMessage(MessageType.Error, true, "The car object " + file + " does not exist at line " + (i + 1).ToString(culture) + " in file " + filePath);
                                                }
                                            }
                                        }
                                        else
                                        {
                                            Interface.AddMessage(MessageType.Error, false, "The car index " + a + " does not reference an existing car at line " + (i + 1).ToString(culture) + " in file " + filePath);
                                        }
                                    }
                                    else
                                    {
                                        Interface.AddMessage(MessageType.Error, false, "The car index is expected to be an integer at line " + (i + 1).ToString(culture) + " in file " + filePath);
                                    }
                                }
                                else
                                {
                                    Interface.AddMessage(MessageType.Error, false, "Invalid statement " + lines[i] + " encountered at line " + (i + 1).ToString(culture) + " in file " + filePath);
                                }
                            }
                            i++;
                        }
                        i--;
                        break;

                    default:
                        if (lines[i].StartsWith("[car", StringComparison.OrdinalIgnoreCase) & lines[i].EndsWith("]", StringComparison.Ordinal))
                        {
                            // car
                            string t = lines[i].Substring(4, lines[i].Length - 5);
                            int    n;
                            if (int.TryParse(t, System.Globalization.NumberStyles.Integer, culture, out n))
                            {
                                if (n >= 0)
                                {
                                    if (n >= train.Cars.Length)
                                    {
                                        Array.Resize(ref train.Cars, n + 1);
                                        train.Cars[n] = new TrainManager.Car(train);
                                        Array.Resize(ref carObjects, n + 1);
                                        Array.Resize(ref bogieObjects, (n + 1) * 2);
                                        Array.Resize(ref carObjectsReversed, n + 1);
                                        Array.Resize(ref bogieObjectsReversed, (n + 1) * 2);
                                        Array.Resize(ref carsDefined, n + 1);
                                        Array.Resize(ref bogiesDefined, (n + 1) * 2);
                                        Array.Resize(ref axleLocations, (n + 1) * 2);
                                    }
                                    if (carsDefined[n])
                                    {
                                        Interface.AddMessage(MessageType.Error, false, "Car " + n.ToString(culture) + " has already been declared at line " + (i + 1).ToString(culture) + " in file " + filePath);
                                    }
                                    carsDefined[n] = true;
                                    i++;
                                    while (i < lines.Length && !lines[i].StartsWith("[", StringComparison.Ordinal) & !lines[i].EndsWith("]", StringComparison.Ordinal))
                                    {
                                        if (lines[i].Length != 0)
                                        {
                                            int j = lines[i].IndexOf("=", StringComparison.Ordinal);
                                            if (j >= 0)
                                            {
                                                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))
                                                    {
                                                        Interface.AddMessage(MessageType.Error, true, "An empty car object was supplied at line " + (i + 1).ToString(culture) + " in file " + filePath);
                                                        break;
                                                    }
                                                    if (Path.ContainsInvalidChars(b))
                                                    {
                                                        Interface.AddMessage(MessageType.Error, false, "File contains illegal characters at line " + (i + 1).ToString(culture) + " in file " + filePath);
                                                    }
                                                    else
                                                    {
                                                        string file = OpenBveApi.Path.CombineFile(trainPath, b);
                                                        if (System.IO.File.Exists(file))
                                                        {
                                                            if (loadObjects)
                                                            {
                                                                carObjects[n] = ObjectManager.LoadObject(file, encoding, false);
                                                            }
                                                        }
                                                        else
                                                        {
                                                            Interface.AddMessage(MessageType.Error, true, "The car object " + file + " does not exist at line " + (i + 1).ToString(culture) + " in file " + filePath);
                                                        }
                                                    }
                                                    break;

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

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

                                                case "axles":
                                                    int k = b.IndexOf(',');
                                                    if (k >= 0)
                                                    {
                                                        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))
                                                        {
                                                            Interface.AddMessage(MessageType.Error, false, "Rear is expected to be a floating-point number in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + filePath);
                                                        }
                                                        else if (!double.TryParse(d, System.Globalization.NumberStyles.Float, Culture, out front))
                                                        {
                                                            Interface.AddMessage(MessageType.Error, false, "Front is expected to be a floating-point number in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + filePath);
                                                        }
                                                        else if (rear >= front)
                                                        {
                                                            Interface.AddMessage(MessageType.Error, false, "Rear is expected to be less than Front in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + filePath);
                                                        }
                                                        else
                                                        {
                                                            if (n == 0)
                                                            {
                                                                axleLocations[n]     = rear;
                                                                axleLocations[n + 1] = front;
                                                            }
                                                            else
                                                            {
                                                                axleLocations[n * 2]     = rear;
                                                                axleLocations[n * 2 + 1] = front;
                                                            }
                                                        }
                                                    }
                                                    else
                                                    {
                                                        Interface.AddMessage(MessageType.Error, false, "An argument-separating comma is expected in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + filePath);
                                                    }
                                                    break;

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

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

                                if (n > bogiesDefined.Length - 1)
                                {
                                    continue;
                                }
                                if (bogiesDefined[n])
                                {
                                    Interface.AddMessage(MessageType.Error, false, "Bogie " + n.ToString(culture) + " has already been declared at line " + (i + 1).ToString(culture) + " in file " + filePath);
                                }
                                bogiesDefined[n] = true;
                                //Assuming that there are two bogies per car
                                if (n >= 0 & n < train.Cars.Length * 2)
                                {
                                    i++;
                                    while (i < lines.Length && !lines[i].StartsWith("[", StringComparison.Ordinal) & !lines[i].EndsWith("]", StringComparison.Ordinal))
                                    {
                                        if (lines[i].Length != 0)
                                        {
                                            int j = lines[i].IndexOf("=", StringComparison.Ordinal);
                                            if (j >= 0)
                                            {
                                                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))
                                                    {
                                                        Interface.AddMessage(MessageType.Error, false, "File contains illegal characters at line " + (i + 1).ToString(culture) + " in file " + filePath);
                                                    }
                                                    else
                                                    {
                                                        if (string.IsNullOrEmpty(b))
                                                        {
                                                            Interface.AddMessage(MessageType.Error, true, "An empty bogie object was supplied at line " + (i + 1).ToString(culture) + " in file " + filePath);
                                                            break;
                                                        }
                                                        string file = OpenBveApi.Path.CombineFile(trainPath, b);
                                                        if (System.IO.File.Exists(file))
                                                        {
                                                            if (loadObjects)
                                                            {
                                                                bogieObjects[n] = ObjectManager.LoadObject(file, encoding, false);
                                                            }
                                                        }
                                                        else
                                                        {
                                                            Interface.AddMessage(MessageType.Error, true, "The bogie object " + file + " does not exist at line " + (i + 1).ToString(culture) + " in file " + filePath);
                                                        }
                                                    }
                                                    break;

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

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

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

                                                default:
                                                    Interface.AddMessage(MessageType.Warning, false, "Unsupported key-value pair " + a + " encountered at line " + (i + 1).ToString(culture) + " in file " + filePath);
                                                    break;
                                                }
                                            }
                                            else
                                            {
                                                Interface.AddMessage(MessageType.Error, false, "Invalid statement " + lines[i] + " encountered at line " + (i + 1).ToString(culture) + " in file " + filePath);
                                            }
                                        }
                                        i++;
                                    }
                                    i--;
                                }
                                else
                                {
                                    Interface.AddMessage(MessageType.Error, false, "The car index " + t + " does not reference an existing car at line " + (i + 1).ToString(culture) + " in file " + filePath);
                                }
                            }
                            else
                            {
                                Interface.AddMessage(MessageType.Error, false, "The car index is expected to be an integer at line " + (i + 1).ToString(culture) + " in file " + filePath);
                            }
                        }
                        else if (lines[i].StartsWith("[coupler", StringComparison.OrdinalIgnoreCase) & lines[i].EndsWith("]", StringComparison.Ordinal))
                        {
                            i++;
                            while (i < lines.Length && !lines[i].StartsWith("[", StringComparison.Ordinal) & !lines[i].EndsWith("]", StringComparison.Ordinal))
                            {
                                /*
                                 * Coupler statments are currently not supported in Object Viewer
                                 */
                                i++;
                            }

                            i--;
                        }
                        else
                        {
                            // default
                            if (lines.Length == 1 && encoding.Equals(Encoding.Unicode))
                            {
                                /*
                                 * If only one line, there's a good possibility that our file is NOT Unicode at all
                                 * and that the misdetection has turned it into garbage
                                 *
                                 * Try again with ASCII instead
                                 */
                                ParseExtensionsConfig(filePath, Encoding.GetEncoding(1252), out carObjects, out bogieObjects, out axleLocations, out train, loadObjects);
                                return;
                            }
                            Interface.AddMessage(MessageType.Error, false, "Invalid statement " + lines[i] + " encountered at line " + (i + 1).ToString(culture) + " in file " + filePath);
                        }
                        break;
                    }
                }
            }

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

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

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

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

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

            if (bogieObjectsCount > 0 & bogieObjectsCount < train.Cars.Length * 2)
            {
                Interface.AddMessage(MessageType.Warning, false, "An incomplete set of bogie objects was provided in file " + filePath);
            }
        }
Example #6
0
        private static void ParseExtensionsConfig(string filePath, Encoding encoding, out UnifiedObject[] carObjects, out UnifiedObject[] bogieObjects, out UnifiedObject[] couplerObjects, out double[] axleLocations, out double[] couplerDistances, out TrainManager.Train train, bool loadObjects)
        {
            CultureInfo culture = CultureInfo.InvariantCulture;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

            if (bogieObjectsCount > 0 & bogieObjectsCount < train.Cars.Length * 2)
            {
                Interface.AddMessage(MessageType.Warning, false, $"An incomplete set of bogie objects was provided in file {filePath}");
            }
        }
Example #7
0
        /// <summary>Parses a base track following object node</summary>
        /// <param name="ObjectPath">Absolute path to the object folder of route data</param>
        /// <param name="FileName">The filename of the containing XML file</param>
        /// <param name="SectionElement">The XElement to parse</param>
        /// <param name="Train">The track following object to parse this node into</param>
        private static void ParseTrackFollowingObjectNode(string ObjectPath, string FileName, XElement SectionElement, TrainManager.TrackFollowingObject Train)
        {
            string Section = SectionElement.Name.LocalName;

            string TrainDirectory       = string.Empty;
            bool   ConsistReversed      = false;
            List <Game.TravelData> Data = new List <Game.TravelData>();

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

                switch (Key.ToLowerInvariant())
                {
                case "definition":
                    ParseDefinitionNode(FileName, KeyNode, Train);
                    break;

                case "train":
                    ParseTrainNode(ObjectPath, FileName, KeyNode, ref TrainDirectory, ref ConsistReversed);
                    break;

                case "points":
                case "stops":
                    ParseTravelDataNodes(FileName, KeyNode, Data);
                    break;

                default:
                    Interface.AddMessage(MessageType.Warning, false, $"Unsupported key {Key} encountered in {Section} at line {LineNumber.ToString(culture)} in {FileName}");
                    break;
                }
            }

            if (Data.Count < 2)
            {
                Interface.AddMessage(MessageType.Error, false, $"There must be at least two points to go through in {FileName}");
                return;
            }

            if (!(Data.First() is Game.TravelStopData) || !(Data.Last() is Game.TravelStopData))
            {
                Interface.AddMessage(MessageType.Error, false, $"The first and the last point to go through must be the \"Stop\" node in {FileName}");
                return;
            }

            if (string.IsNullOrEmpty(TrainDirectory))
            {
                Interface.AddMessage(MessageType.Error, false, $"No train has been specified in {FileName}");
                return;
            }

            /*
             * First check for a train.ai file- Functionally identical, but allows for differently configured AI
             * trains not to show up as drivable
             */
            string TrainData = OpenBveApi.Path.CombineFile(TrainDirectory, "train.ai");

            if (!File.Exists(TrainData))
            {
                // Check for the standard drivable train.dat
                TrainData = OpenBveApi.Path.CombineFile(TrainDirectory, "train.dat");
            }
            string ExteriorFile = OpenBveApi.Path.CombineFile(TrainDirectory, "extensions.cfg");

            if (!File.Exists(TrainData) || !File.Exists(ExteriorFile))
            {
                Interface.AddMessage(MessageType.Error, true, $"The supplied train folder in TrackFollowingObject {FileName} did not contain a complete set of data.");
                return;
            }
            TrainDatParser.ParseTrainData(TrainData, TextEncoding.GetSystemEncodingFromFile(TrainData), Train);
            SoundCfgParser.ParseSoundConfig(TrainDirectory, Train);
            Train.AI = new Game.TrackFollowingObjectAI(Train, Data.ToArray());

            UnifiedObject[] CarObjects          = new UnifiedObject[Train.Cars.Length];
            UnifiedObject[] BogieObjects        = new UnifiedObject[Train.Cars.Length * 2];
            UnifiedObject[] CouplerObjects      = new UnifiedObject[Train.Cars.Length - 1];
            bool[]          VisibleFromInterior = new bool[Train.Cars.Length];
            ExtensionsCfgParser.ParseExtensionsConfig(System.IO.Path.GetDirectoryName(ExteriorFile), TextEncoding.GetSystemEncodingFromFile(ExteriorFile), ref CarObjects, ref BogieObjects, ref CouplerObjects, ref VisibleFromInterior, Train, true);

            int currentBogieObject = 0;

            for (int i = 0; i < Train.Cars.Length; i++)
            {
                if (CarObjects[i] == null)
                {
                    // load default exterior object
                    string       file = OpenBveApi.Path.CombineFile(Program.FileSystem.GetDataFolder("Compatibility"), "exterior.csv");
                    StaticObject so;
                    Program.CurrentHost.LoadStaticObject(file, Encoding.UTF8, false, out so);
                    if (so == null)
                    {
                        CarObjects[i] = null;
                    }
                    else
                    {
                        so.ApplyScale(Train.Cars[i].Width, Train.Cars[i].Height, Train.Cars[i].Length);
                        CarObjects[i] = so;
                    }
                }
                if (CarObjects[i] != null)
                {
                    // add object
                    Train.Cars[i].LoadCarSections(CarObjects[i], false);
                }

                //Load bogie objects
                if (BogieObjects[currentBogieObject] != null)
                {
                    Train.Cars[i].FrontBogie.LoadCarSections(BogieObjects[currentBogieObject], false);
                }
                currentBogieObject++;
                if (BogieObjects[currentBogieObject] != null)
                {
                    Train.Cars[i].RearBogie.LoadCarSections(BogieObjects[currentBogieObject], false);
                }
                currentBogieObject++;
            }

            // door open/close speed
            foreach (var Car in Train.Cars)
            {
                if (Car.Specs.DoorOpenFrequency <= 0.0)
                {
                    if (Car.Doors[0].OpenSound.Buffer != null & Car.Doors[1].OpenSound.Buffer != null)
                    {
                        Program.Sounds.LoadBuffer(Car.Doors[0].OpenSound.Buffer);
                        Program.Sounds.LoadBuffer(Car.Doors[1].OpenSound.Buffer);
                        double a = Car.Doors[0].OpenSound.Buffer.Duration;
                        double b = Car.Doors[1].OpenSound.Buffer.Duration;
                        Car.Specs.DoorOpenFrequency = a + b > 0.0 ? 2.0 / (a + b) : 0.8;
                    }
                    else if (Car.Doors[0].OpenSound.Buffer != null)
                    {
                        Program.Sounds.LoadBuffer(Car.Doors[0].OpenSound.Buffer);
                        double a = Car.Doors[0].OpenSound.Buffer.Duration;
                        Car.Specs.DoorOpenFrequency = a > 0.0 ? 1.0 / a : 0.8;
                    }
                    else if (Car.Doors[1].OpenSound.Buffer != null)
                    {
                        Program.Sounds.LoadBuffer(Car.Doors[0].OpenSound.Buffer);
                        double b = Car.Doors[1].OpenSound.Buffer.Duration;
                        Car.Specs.DoorOpenFrequency = b > 0.0 ? 1.0 / b : 0.8;
                    }
                    else
                    {
                        Car.Specs.DoorOpenFrequency = 0.8;
                    }
                }
                if (Car.Specs.DoorCloseFrequency <= 0.0)
                {
                    if (Car.Doors[0].CloseSound.Buffer != null & Car.Doors[1].CloseSound.Buffer != null)
                    {
                        Program.Sounds.LoadBuffer(Car.Doors[0].CloseSound.Buffer);
                        Program.Sounds.LoadBuffer(Car.Doors[1].CloseSound.Buffer);
                        double a = Car.Doors[0].CloseSound.Buffer.Duration;
                        double b = Car.Doors[1].CloseSound.Buffer.Duration;
                        Car.Specs.DoorCloseFrequency = a + b > 0.0 ? 2.0 / (a + b) : 0.8;
                    }
                    else if (Car.Doors[0].CloseSound.Buffer != null)
                    {
                        Program.Sounds.LoadBuffer(Car.Doors[0].CloseSound.Buffer);
                        double a = Car.Doors[0].CloseSound.Buffer.Duration;
                        Car.Specs.DoorCloseFrequency = a > 0.0 ? 1.0 / a : 0.8;
                    }
                    else if (Car.Doors[1].CloseSound.Buffer != null)
                    {
                        Program.Sounds.LoadBuffer(Car.Doors[0].CloseSound.Buffer);
                        double b = Car.Doors[1].CloseSound.Buffer.Duration;
                        Car.Specs.DoorCloseFrequency = b > 0.0 ? 1.0 / b : 0.8;
                    }
                    else
                    {
                        Car.Specs.DoorCloseFrequency = 0.8;
                    }
                }
                const double f = 0.015;
                const double g = 2.75;
                Car.Specs.DoorOpenPitch       = Math.Exp(f * Math.Tan(g * (Program.RandomNumberGenerator.NextDouble() - 0.5)));
                Car.Specs.DoorClosePitch      = Math.Exp(f * Math.Tan(g * (Program.RandomNumberGenerator.NextDouble() - 0.5)));
                Car.Specs.DoorOpenFrequency  /= Car.Specs.DoorOpenPitch;
                Car.Specs.DoorCloseFrequency /= Car.Specs.DoorClosePitch;

                /*
                 * Remove the following two lines, then the pitch at which doors play
                 * takes their randomized opening and closing times into account.
                 * */
                Car.Specs.DoorOpenPitch  = 1.0;
                Car.Specs.DoorClosePitch = 1.0;
            }

            foreach (var Car in Train.Cars)
            {
                Car.FrontAxle.Follower.TrackIndex            = Data[0].RailIndex;
                Car.RearAxle.Follower.TrackIndex             = Data[0].RailIndex;
                Car.FrontBogie.FrontAxle.Follower.TrackIndex = Data[0].RailIndex;
                Car.FrontBogie.RearAxle.Follower.TrackIndex  = Data[0].RailIndex;
                Car.RearBogie.FrontAxle.Follower.TrackIndex  = Data[0].RailIndex;
                Car.RearBogie.RearAxle.Follower.TrackIndex   = Data[0].RailIndex;
            }

            if (ConsistReversed)
            {
                Train.Reverse();
            }
            Train.PlaceCars(Data[0].Position);
        }
Example #8
0
        // show train
        private void ShowTrain(bool UserSelectedEncoding)
        {
            if (!UserSelectedEncoding)
            {
                Result.TrainEncoding = System.Text.Encoding.Default;
                switch (TextEncoding.GetEncodingFromFile(Result.TrainFolder, "train.txt"))
                {
                case TextEncoding.Encoding.Utf8:
                    Result.TrainEncoding = System.Text.Encoding.UTF8;
                    break;

                case TextEncoding.Encoding.Utf16Le:
                    Result.TrainEncoding = System.Text.Encoding.Unicode;
                    break;

                case TextEncoding.Encoding.Utf16Be:
                    Result.TrainEncoding = System.Text.Encoding.BigEndianUnicode;
                    break;

                case TextEncoding.Encoding.Utf32Le:
                    Result.TrainEncoding = System.Text.Encoding.UTF32;
                    break;

                case TextEncoding.Encoding.Utf32Be:
                    Result.TrainEncoding = System.Text.Encoding.GetEncoding(12001);
                    break;

                case TextEncoding.Encoding.Shift_JIS:
                    Result.TrainEncoding = System.Text.Encoding.GetEncoding(932);
                    break;

                case TextEncoding.Encoding.Windows1252:
                    Result.TrainEncoding = System.Text.Encoding.GetEncoding(1252);
                    break;

                case TextEncoding.Encoding.Big5:
                    Result.TrainEncoding = System.Text.Encoding.GetEncoding(950);
                    break;

                case TextEncoding.Encoding.EUC_KR:
                    Result.TrainEncoding = System.Text.Encoding.GetEncoding(950);
                    break;
                }
                int i;
                for (i = 0; i < Interface.CurrentOptions.TrainEncodings.Length; i++)
                {
                    if (Interface.CurrentOptions.TrainEncodings[i].Value == Result.TrainFolder)
                    {
                        int j;
                        for (j = 1; j < EncodingCodepages.Length; j++)
                        {
                            if (EncodingCodepages[j] == Interface.CurrentOptions.TrainEncodings[i].Codepage)
                            {
                                Result.TrainEncoding = System.Text.Encoding.GetEncoding(EncodingCodepages[j]);
                                break;
                            }
                        }
                        if (j == EncodingCodepages.Length)
                        {
                            Result.TrainEncoding = System.Text.Encoding.UTF8;
                        }
                        break;
                    }
                }
            }
            {
                // train image
                string File = OpenBveApi.Path.CombineFile(Result.TrainFolder, "train.png");
                if (!System.IO.File.Exists(File))
                {
                    File = OpenBveApi.Path.CombineFile(Result.TrainFolder, "train.bmp");
                }
                if (System.IO.File.Exists(File))
                {
                    TryLoadImage(pictureboxTrainImage, File);
                }
                else
                {
                    TryLoadImage(pictureboxTrainImage, "train_unknown.png");
                }
            }
            {
                // train description
                string File = OpenBveApi.Path.CombineFile(Result.TrainFolder, "train.txt");
                if (System.IO.File.Exists(File))
                {
                    try
                    {
                        string trainText = System.IO.File.ReadAllText(File, Result.TrainEncoding);
                        trainText = trainText.ConvertNewlinesToCrLf();
                        textboxTrainDescription.Text = trainText;
                    }
                    catch
                    {
                        textboxTrainDescription.Text = System.IO.Path.GetFileName(Result.TrainFolder);
                    }
                }
                else
                {
                    textboxTrainDescription.Text = System.IO.Path.GetFileName(Result.TrainFolder);
                }
            }

            // for RAGLINK Package Manager
            RAGLINKCommons.RPlatform.PackagesManager.SetTrainDetailData(System.IO.Path.GetFileNameWithoutExtension(Result.TrainFolder), textboxTrainDescription.Text);
        }
Example #9
0
        // show route
        private void ShowRoute(bool UserSelectedEncoding)
        {
            if (routeWorkerThread == null)
            {
                return;
            }
            if (Result.RouteFile != null && !routeWorkerThread.IsBusy)
            {
                this.Cursor = System.Windows.Forms.Cursors.WaitCursor;
                // determine encoding
                if (!UserSelectedEncoding)
                {
                    Result.RouteEncoding = System.Text.Encoding.Default;
                    switch (TextEncoding.GetEncodingFromFile(Result.RouteFile))
                    {
                    case TextEncoding.Encoding.Utf7:
                        Result.RouteEncoding = System.Text.Encoding.UTF7;
                        break;

                    case TextEncoding.Encoding.Utf8:
                        Result.RouteEncoding = System.Text.Encoding.UTF8;
                        break;

                    case TextEncoding.Encoding.Utf16Le:
                        Result.RouteEncoding = System.Text.Encoding.Unicode;
                        break;

                    case TextEncoding.Encoding.Utf16Be:
                        Result.RouteEncoding = System.Text.Encoding.BigEndianUnicode;
                        break;

                    case TextEncoding.Encoding.Utf32Le:
                        Result.RouteEncoding = System.Text.Encoding.UTF32;
                        break;

                    case TextEncoding.Encoding.Utf32Be:
                        Result.RouteEncoding = System.Text.Encoding.GetEncoding(12001);
                        break;

                    case TextEncoding.Encoding.Shift_JIS:
                        Result.RouteEncoding = System.Text.Encoding.GetEncoding(932);
                        break;

                    case TextEncoding.Encoding.Windows1252:
                        Result.RouteEncoding = System.Text.Encoding.GetEncoding(1252);
                        break;

                    case TextEncoding.Encoding.Big5:
                        Result.RouteEncoding = System.Text.Encoding.GetEncoding(950);
                        break;

                    case TextEncoding.Encoding.EUC_KR:
                        Result.RouteEncoding = System.Text.Encoding.GetEncoding(949);
                        break;
                    }

                    int i;
                    for (i = 0; i < Interface.CurrentOptions.RouteEncodings.Length; i++)
                    {
                        if (Interface.CurrentOptions.RouteEncodings[i].Value == Result.RouteFile)
                        {
                            int j;
                            for (j = 1; j < EncodingCodepages.Length; j++)
                            {
                                if (EncodingCodepages[j] == Interface.CurrentOptions.RouteEncodings[i].Codepage)
                                {
                                    Result.RouteEncoding = System.Text.Encoding.GetEncoding(EncodingCodepages[j]);
                                    break;
                                }
                            }
                            if (j == EncodingCodepages.Length)
                            {
                                Result.RouteEncoding = System.Text.Encoding.UTF8;
                            }
                            break;
                        }
                    }
                }
                if (!routeWorkerThread.IsBusy)
                {
                    //HACK: If clicking very rapidly or holding down an arrow
                    //		we can sometimes try to spawn two worker threads
                    routeWorkerThread.RunWorkerAsync();
                }
            }
        }
Example #10
0
        // show train
        private void ShowTrain(bool UserSelectedEncoding)
        {
            if (!UserSelectedEncoding)
            {
                Result.TrainEncoding                = TextEncoding.GetSystemEncodingFromFile(Result.TrainFolder, "train.txt");
                comboboxTrainEncoding.Tag           = new object();
                comboboxTrainEncoding.SelectedIndex = 0;
                comboboxTrainEncoding.Items[0]      = $"{Result.TrainEncoding.EncodingName} - {Result.TrainEncoding.CodePage}";

                comboboxTrainEncoding.Tag = null;
                int i;
                for (i = 0; i < Interface.CurrentOptions.TrainEncodings.Length; i++)
                {
                    if (Interface.CurrentOptions.TrainEncodings[i].Value == Result.TrainFolder)
                    {
                        int j;
                        for (j = 1; j < EncodingCodepages.Length; j++)
                        {
                            if (EncodingCodepages[j] == Interface.CurrentOptions.TrainEncodings[i].Codepage)
                            {
                                comboboxTrainEncoding.SelectedIndex = j;
                                Result.TrainEncoding = System.Text.Encoding.GetEncoding(EncodingCodepages[j]);
                                break;
                            }
                        }
                        if (j == EncodingCodepages.Length)
                        {
                            comboboxTrainEncoding.SelectedIndex = 0;
                            Result.TrainEncoding = System.Text.Encoding.UTF8;
                        }
                        break;
                    }
                }
                panelTrainEncoding.Enabled = true;
                comboboxTrainEncoding.Tag  = null;
            }
            {
                // train image
                string File = OpenBveApi.Path.CombineFile(Result.TrainFolder, "train.png");
                if (!System.IO.File.Exists(File))
                {
                    File = OpenBveApi.Path.CombineFile(Result.TrainFolder, "train.bmp");
                }
                if (System.IO.File.Exists(File))
                {
                    TryLoadImage(pictureboxTrainImage, File);
                }
                else
                {
                    TryLoadImage(pictureboxTrainImage, "train_unknown.png");
                }
            }
            {
                // train description
                string File = OpenBveApi.Path.CombineFile(Result.TrainFolder, "train.txt");
                if (System.IO.File.Exists(File))
                {
                    try {
                        string trainText = System.IO.File.ReadAllText(File, Result.TrainEncoding);
                        trainText = trainText.ConvertNewlinesToCrLf();
                        textboxTrainDescription.Text     = trainText;
                        textboxTrainEncodingPreview.Text = trainText;
                    } catch {
                        textboxTrainDescription.Text     = System.IO.Path.GetFileName(Result.TrainFolder);
                        textboxTrainEncodingPreview.Text = "";
                    }
                }
                else
                {
                    textboxTrainDescription.Text     = System.IO.Path.GetFileName(Result.TrainFolder);
                    textboxTrainEncodingPreview.Text = "";
                }
            }
            groupboxTrainDetails.Visible        = true;
            labelTrainEncoding.Enabled          = true;
            labelTrainEncodingPreview.Enabled   = true;
            textboxTrainEncodingPreview.Enabled = true;
            buttonStart.Enabled = Result.RouteFile != null & Result.TrainFolder != null;
        }
Example #11
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 static void PreprocessChrRndSub(string FileName, bool IsRW, System.Text.Encoding Encoding, ref Expression[] Expressions)
        {
            System.Globalization.CultureInfo Culture = System.Globalization.CultureInfo.InvariantCulture;
            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();
                            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;
                                        Interface.AddMessage(MessageType.Error, false, "Invalid parenthesis structure in " + t + Epilog);
                                    }
                                    break;
                                }
                                if (l <= 0)
                                {
                                    break;
                                }
                            }
                            if (continueWithNextExpression)
                            {
                                break;
                            }
                            if (l != 0)
                            {
                                Interface.AddMessage(MessageType.Error, false, "Invalid parenthesis structure in " + t + Epilog);
                                break;
                            }
                            string s = Expressions[i].Text.Substring(k + 1, h - k - 1).Trim();
                            switch (t.ToLowerInvariant())
                            {
                            case "$if":
                                if (j != 0)
                                {
                                    Interface.AddMessage(MessageType.Error, false, "The $If directive must not appear within another statement" + Epilog);
                                }
                                else
                                {
                                    double num;
                                    if (double.TryParse(s, System.Globalization.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)
                                            {
                                                Interface.AddMessage(MessageType.Error, false, "$EndIf missing at the end of the file" + Epilog);
                                            }
                                        }
                                        continueWithNextExpression = true;
                                        break;
                                    }
                                    else
                                    {
                                        Interface.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)
                                            {
                                                Interface.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)
                                    {
                                        Interface.AddMessage(MessageType.Error, false, "$EndIf missing at the end of the file" + Epilog);
                                    }
                                }
                                else
                                {
                                    Interface.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
                                {
                                    Interface.AddMessage(MessageType.Error, false, "$EndIf without matching $If encountered" + Epilog);
                                }
                                continueWithNextExpression = true;
                                break;

                            case "$include":
                                if (j != 0)
                                {
                                    Interface.AddMessage(MessageType.Error, false, "The $Include directive must not appear within another statement" + Epilog);
                                    continueWithNextExpression = true;
                                    break;
                                }
                                string[] args = s.Split(';');
                                for (int ia = 0; ia < args.Length; ia++)
                                {
                                    args[ia] = args[ia].Trim();
                                }
                                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();
                                        string value = args[2 * ia].Substring(colon + 1).TrimStart();
                                        if (!double.TryParse(value, NumberStyles.Float, Culture, out offset))
                                        {
                                            continueWithNextExpression = true;
                                            Interface.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]   = OpenBveApi.Path.CombineFile(System.IO.Path.GetDirectoryName(FileName), file);
                                    offsets[ia] = offset;
                                    if (!System.IO.File.Exists(files[ia]))
                                    {
                                        continueWithNextExpression = true;
                                        Interface.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 <Expression>(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;
                                            Interface.AddMessage(MessageType.Error, false, "A weight is invalid in " + t + Epilog);
                                            break;
                                        }
                                        if (weights[ia] <= 0.0)
                                        {
                                            continueWithNextExpression = true;
                                            Interface.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;
                                    Interface.AddMessage(MessageType.Error, false, "No file was specified in " + t + Epilog);
                                    break;
                                }
                                if (!continueWithNextExpression)
                                {
                                    double number      = Program.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
                                        Interface.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], IsRW, 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 <Expression>(ref Expressions, length - 1);
                                    }
                                    else
                                    {
                                        Array.Resize <Expression>(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;
                                        Interface.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;
                                    Interface.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 > 128)
                                    {
                                        //Standard ASCII characters from 0-128
                                        continueWithNextExpression = true;
                                        Interface.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;
                                    Interface.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();
                                    string s2 = s.Substring(m + 1).TrimStart();
                                    int    x; if (NumberFormats.TryParseIntVb6(s1, out x))
                                    {
                                        int y; if (NumberFormats.TryParseIntVb6(s2, out y))
                                        {
                                            int z = x + (int)Math.Floor(Program.RandomNumberGenerator.NextDouble() * (double)(y - x + 1));
                                            Expressions[i].Text = Expressions[i].Text.Substring(0, j) + z.ToString(Culture) + Expressions[i].Text.Substring(h + 1);
                                        }
                                        else
                                        {
                                            continueWithNextExpression = true;
                                            Interface.AddMessage(MessageType.Error, false, "Index2 is invalid in " + t + Epilog);
                                        }
                                    }
                                    else
                                    {
                                        continueWithNextExpression = true;
                                        Interface.AddMessage(MessageType.Error, false, "Index1 is invalid in " + t + Epilog);
                                    }
                                }
                                else
                                {
                                    continueWithNextExpression = true;
                                    Interface.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 <string>(ref Subs, Subs.Length << 1);
                                            }
                                            Subs[x]             = Expressions[i].Text.Substring(m + 1, n - m - 1).Trim();
                                            Expressions[i].Text = Expressions[i].Text.Substring(0, j) + Expressions[i].Text.Substring(n);
                                        }
                                        else
                                        {
                                            continueWithNextExpression = true;
                                            Interface.AddMessage(MessageType.Error, false, "Index is expected to be non-negative in " + t + Epilog);
                                        }
                                    }
                                    else
                                    {
                                        continueWithNextExpression = true;
                                        Interface.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;
                                            Interface.AddMessage(MessageType.Error, false, "Index is out of range in " + t + Epilog);
                                        }
                                    }
                                    else
                                    {
                                        continueWithNextExpression = true;
                                        Interface.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();
                    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 <Expression>(ref Expressions, length);
                }
            }
        }
Example #12
0
        /// <summary>Parses any command-line arguments passed to the main program</summary>
        /// <param name="Arguments">A string array of arguments</param>
        /// <param name="Result">The main dialog result (Used to launch)</param>
        internal static void ParseArguments(string[] Arguments, ref formMain.MainDialogResult Result)
        {
            if (Arguments.Length == 0)
            {
                return;
            }
            for (int i = 0; i < Arguments.Length; i++)
            {
                int equals = Arguments[i].IndexOf('=');
                if (equals >= 0)
                {
                    string key   = Arguments[i].Substring(0, equals).Trim(new char[] { }).ToLowerInvariant();
                    string value = Arguments[i].Substring(equals + 1).Trim(new char[] { });
                    switch (key)
                    {
                    case "/route":
                        Result.RouteFile     = value;
                        Result.RouteEncoding = TextEncoding.GetSystemEncodingFromFile(Result.RouteFile);
                        break;

                    case "/train":
                        Result.TrainFolder   = value;
                        Result.TrainEncoding = TextEncoding.GetSystemEncodingFromFile(Result.TrainFolder, "train.txt");
                        break;

                    case "/station":
                        Result.InitialStation = value;
                        break;

                    case "/time":
                        Interface.TryParseTime(value, out Result.StartTime);
                        break;

                    case "/ai":
                        if (value.ToLowerInvariant() == "true" || value.ToLowerInvariant() == "1")
                        {
                            Result.AIDriver = true;
                        }
                        break;

                    case "/fullscreen":
                        if (value.ToLowerInvariant() == "true" || value.ToLowerInvariant() == "1")
                        {
                            Result.FullScreen = true;
                        }
                        break;

                    case "/width":
                        NumberFormats.TryParseIntVb6(value, out Result.Width);
                        break;

                    case "/height":
                        NumberFormats.TryParseIntVb6(value, out Result.Height);
                        break;

                    case "/glmenu":
                        if (value.ToLowerInvariant() == "true" || value.ToLowerInvariant() == "1")
                        {
                            Result.ExperimentalGLMenu = true;
                        }
                        break;
                    }
                }
            }
        }