internal static void Parse(string fileName, out Train train) { train = new Train(); CultureInfo culture = CultureInfo.InvariantCulture; string[] lines = File.ReadAllLines(fileName, TextEncoding.GetSystemEncodingFromFile(fileName)); for (int i = 0; i < lines.Length; i++) { int j = lines[i].IndexOf(';'); if (j >= 0) { lines[i] = lines[i].Substring(0, j).Trim(); } else { lines[i] = lines[i].Trim(); } } bool ver1220000 = false; foreach (string line in lines) { if (line.Length != 0) { string s = line.ToLowerInvariant(); switch (s) { case "bve1200000": case "bve1210000": case "bve1220000": ver1220000 = true; break; case "bve2000000": case "openbve": //No action break; default: if (s.ToLowerInvariant().StartsWith("openbve")) { string tt = s.Substring(7, s.Length - 7); int v; if (int.TryParse(tt, NumberStyles.Float, culture, out v)) { if (v > currentVersion) { Interface.AddMessage(MessageType.Warning, false, $"The train.dat {fileName} was created with a newer version of openBVE. Please check for an update."); } } else { Interface.AddMessage(MessageType.Error, false, $"The train.dat version {lines[0].ToLowerInvariant()} is invalid in {fileName}"); } } break; } break; } } Acceleration acceleration = new Acceleration(); Performance performance = new Performance(); Delay delay = new Delay(); Move move = new Move(); Brake brake = new Brake(); Pressure pressure = new Pressure(); Motor motor = new Motor(); double motorCarMass = 40.0; int numberOfMotorCars = 1; double trailerCarMass = 40.0; int numberOfTrailerCars = 1; double lengthOfACar = 20.0; bool frontCarIsAMotorCar = false; double widthOfACar = 2.6; double heightOfACar = 3.2; double centerOfGravityHeight = 1.5; double exposedFrontalArea = 5.0; double unexposedFrontalArea = 1.6; for (int i = 0; i < lines.Length; i++) { int n = 0; switch (lines[i].ToLowerInvariant()) { case "#acceleration": i++; while (i < lines.Length && !lines[i].StartsWith("#", StringComparison.InvariantCultureIgnoreCase)) { if (n == acceleration.Entries.Count) { acceleration.Entries.Add(new Acceleration.Entry()); } string u = lines[i] + ","; int m = 0; while (true) { int j = u.IndexOf(','); if (j == -1) { break; } string s = u.Substring(0, j).Trim(); u = u.Substring(j + 1); double a; if (double.TryParse(s, NumberStyles.Float, culture, out a)) { switch (m) { case 0: acceleration.Entries[n].A0 = Math.Max(a, 0.0); break; case 1: acceleration.Entries[n].A1 = Math.Max(a, 0.0); break; case 2: acceleration.Entries[n].V1 = Math.Max(a, 0.0); break; case 3: acceleration.Entries[n].V2 = Math.Max(a, 0.0); if (acceleration.Entries[n].V2 < acceleration.Entries[n].V1) { double x = acceleration.Entries[n].V1; acceleration.Entries[n].V1 = acceleration.Entries[n].V2; acceleration.Entries[n].V2 = x; } break; case 4: if (ver1220000) { if (a <= 0.0) { acceleration.Entries[n].E = 1.0; } else { const double c = 1.23315173118822; acceleration.Entries[n].E = 1.0 - Math.Log(a) * acceleration.Entries[n].V2 * c; if (acceleration.Entries[n].E > 4.0) { acceleration.Entries[n].E = 4.0; } } } else { acceleration.Entries[n].E = a; } break; } } m++; } i++; n++; } i--; break; case "#performance": case "#deceleration": i++; while (i < lines.Length && !lines[i].StartsWith("#", StringComparison.InvariantCultureIgnoreCase)) { double a; if (double.TryParse(lines[i], NumberStyles.Float, culture, out a)) { switch (n) { case 0: if (a >= 0.0) { performance.Deceleration = a; } break; case 1: if (a >= 0.0) { performance.CoefficientOfStaticFriction = a; } break; case 3: if (a >= 0.0) { performance.CoefficientOfRollingResistance = a; } break; case 4: if (a >= 0.0) { performance.AerodynamicDragCoefficient = a; } break; } } i++; n++; } i--; break; case "#delay": i++; double[] delayPowerUp = delay.DelayPower.Select(x => x.Up).ToArray(); double[] delayPowerDown = delay.DelayPower.Select(x => x.Down).ToArray(); double[] delayBrakeUp = delay.DelayBrake.Select(x => x.Up).ToArray(); double[] delayBrakeDown = delay.DelayBrake.Select(x => x.Down).ToArray(); double[] delayLocoBrakeUp = delay.DelayLocoBrake.Select(x => x.Up).ToArray(); double[] delayLocoBrakeDown = delay.DelayLocoBrake.Select(x => x.Down).ToArray(); delay.DelayPower.Clear(); delay.DelayBrake.Clear(); delay.DelayLocoBrake.Clear(); while (i < lines.Length && !lines[i].StartsWith("#", StringComparison.InvariantCultureIgnoreCase)) { double a; if (double.TryParse(lines[i], NumberStyles.Float, culture, out a)) { switch (n) { case 0: if (a >= 0.0) { delayPowerUp = new[] { a }; } break; case 1: if (a >= 0.0) { delayPowerDown = new[] { a }; } break; case 2: if (a >= 0.0) { delayBrakeUp = new[] { a }; } break; case 3: if (a >= 0.0) { delayBrakeDown = new[] { a }; } break; } } else if (lines[i].IndexOf(',') != -1) { switch (n) { case 0: delayPowerUp = lines[i].Split(',').Select(x => double.Parse(x, culture)).ToArray(); break; case 1: delayPowerDown = lines[i].Split(',').Select(x => double.Parse(x, culture)).ToArray(); break; case 2: delayBrakeUp = lines[i].Split(',').Select(x => double.Parse(x, culture)).ToArray(); break; case 3: delayBrakeDown = lines[i].Split(',').Select(x => double.Parse(x, culture)).ToArray(); break; case 4: delayLocoBrakeUp = lines[i].Split(',').Select(x => double.Parse(x, culture)).ToArray(); break; case 5: delayLocoBrakeDown = lines[i].Split(',').Select(x => double.Parse(x, culture)).ToArray(); break; } } i++; n++; } for (int j = 0; j < Math.Max(delayPowerUp.Length, delayPowerDown.Length); j++) { Delay.Entry entry = new Delay.Entry(); if (j < delayPowerUp.Length) { entry.Up = delayPowerUp[j]; } if (j < delayPowerDown.Length) { entry.Down = delayPowerDown[j]; } delay.DelayPower.Add(entry); } for (int j = 0; j < Math.Max(delayBrakeUp.Length, delayBrakeDown.Length); j++) { Delay.Entry entry = new Delay.Entry(); if (j < delayBrakeUp.Length) { entry.Up = delayBrakeUp[j]; } if (j < delayBrakeDown.Length) { entry.Down = delayBrakeDown[j]; } delay.DelayBrake.Add(entry); } for (int j = 0; j < Math.Max(delayLocoBrakeUp.Length, delayLocoBrakeDown.Length); j++) { Delay.Entry entry = new Delay.Entry(); if (j < delayLocoBrakeUp.Length) { entry.Up = delayLocoBrakeUp[j]; } if (j < delayLocoBrakeDown.Length) { entry.Down = delayLocoBrakeDown[j]; } delay.DelayLocoBrake.Add(entry); } i--; break; case "#move": i++; while (i < lines.Length && !lines[i].StartsWith("#", StringComparison.InvariantCultureIgnoreCase)) { double a; if (double.TryParse(lines[i], NumberStyles.Float, culture, out a)) { switch (n) { case 0: if (a >= 0.0) { move.JerkPowerUp = a; } break; case 1: if (a >= 0.0) { move.JerkPowerDown = a; } break; case 2: if (a >= 0.0) { move.JerkBrakeUp = a; } break; case 3: if (a >= 0.0) { move.JerkBrakeDown = a; } break; case 4: if (a >= 0.0) { move.BrakeCylinderUp = a; } break; case 5: if (a >= 0.0) { move.BrakeCylinderDown = a; } break; } } i++; n++; } i--; break; case "#brake": i++; while (i < lines.Length && !lines[i].StartsWith("#", StringComparison.InvariantCultureIgnoreCase)) { double a; if (double.TryParse(lines[i], NumberStyles.Float, culture, out a)) { int b = (int)Math.Round(a); switch (n) { case 0: if (b >= 0 & b <= 2) { brake.BrakeType = (BrakeSystemType)b; } break; case 1: if (b >= 0 & b <= 2) { brake.BrakeControlSystem = (EletropneumaticBrakeType)b; } break; case 2: if (a >= 0.0) { brake.BrakeControlSpeed = a; } break; case 3: if (a <= 0 && a > 3) { brake.LocoBrakeType = (Brake.LocoBrakeTypes)b; } break; } } i++; n++; } i--; break; case "#pressure": i++; while (i < lines.Length && !lines[i].StartsWith("#", StringComparison.InvariantCultureIgnoreCase)) { double a; if (double.TryParse(lines[i], NumberStyles.Float, culture, out a)) { switch (n) { case 0: if (a > 0.0) { pressure.BrakeCylinderServiceMaximumPressure = a; } break; case 1: if (a > 0.0) { pressure.BrakeCylinderEmergencyMaximumPressure = a; } break; case 2: if (a > 0.0) { pressure.MainReservoirMinimumPressure = a; } break; case 3: if (a > 0.0) { pressure.MainReservoirMaximumPressure = a; } break; case 4: if (a > 0.0) { pressure.BrakePipeNormalPressure = a; } break; } } i++; n++; } i--; break; case "#handle": i++; while (i < lines.Length && !lines[i].StartsWith("#", StringComparison.InvariantCultureIgnoreCase)) { double a; if (double.TryParse(lines[i], NumberStyles.Float, culture, out a)) { int b = (int)Math.Round(a); switch (n) { case 0: if (b == 0 | b == 1) { train.Handle.HandleType = (Handle.HandleTypes)b; } break; case 1: if (b > 0) { train.Handle.PowerNotches = b; } break; case 2: if (b > 0) { train.Handle.BrakeNotches = b; } break; case 3: if (b >= 0) { train.Handle.PowerNotchReduceSteps = b; } break; case 4: if (a >= 0 && a < 4) { train.Handle.HandleBehaviour = (EbHandleBehaviour)b; } break; case 5: if (b > 0) { train.Handle.LocoBrakeNotches = b; } break; case 6: if (a <= 0 && a > 3) { train.Handle.LocoBrake = (LocoBrakeType)b; } break; case 7: if (b > 0) { train.Handle.DriverPowerNotches = b; } break; case 8: if (b > 0) { train.Handle.DriverBrakeNotches = b; } break; } } i++; n++; } i--; break; case "#cockpit": case "#cab": i++; while (i < lines.Length && !lines[i].StartsWith("#", StringComparison.InvariantCultureIgnoreCase)) { double a; if (double.TryParse(lines[i], NumberStyles.Float, culture, out a)) { switch (n) { case 0: train.Cab.PositionX = a; break; case 1: train.Cab.PositionY = a; break; case 2: train.Cab.PositionZ = a; break; case 3: train.Cab.DriverCar = (int)Math.Round(a); break; } } i++; n++; } i--; break; case "#car": i++; while (i < lines.Length && !lines[i].StartsWith("#", StringComparison.InvariantCultureIgnoreCase)) { double a; if (double.TryParse(lines[i], NumberStyles.Float, culture, out a)) { int b = (int)Math.Round(a); switch (n) { case 0: if (a > 0.0) { motorCarMass = a; } break; case 1: if (b >= 1) { numberOfMotorCars = b; } break; case 2: if (a > 0.0) { trailerCarMass = a; } break; case 3: if (b >= 0) { numberOfTrailerCars = b; } break; case 4: if (b > 0.0) { lengthOfACar = a; } break; case 5: frontCarIsAMotorCar = a == 1.0; break; case 6: if (a > 0.0) { widthOfACar = a; } break; case 7: if (a > 0.0) { heightOfACar = a; } break; case 8: centerOfGravityHeight = a; break; case 9: if (a > 0.0) { exposedFrontalArea = a; } break; case 10: if (a > 0.0) { unexposedFrontalArea = a; } break; } } i++; n++; } i--; break; case "#device": i++; while (i < lines.Length && !lines[i].StartsWith("#", StringComparison.InvariantCultureIgnoreCase)) { double a; if (double.TryParse(lines[i], NumberStyles.Float, culture, out a)) { int b = (int)Math.Round(a); switch (n) { case 0: if (b >= -1 & b <= 1) { train.Device.Ats = (AtsModes)b; } break; case 1: if (b >= 0 & b <= 2) { train.Device.Atc = (AtcModes)b; } break; case 2: train.Device.Eb = a == 1.0; break; case 3: train.Device.ConstSpeed = a == 1.0; break; case 4: train.Device.HoldBrake = a == 1.0; break; case 5: if (b >= -1 & b <= 3) { train.Device.ReAdhesionDevice = (ReadhesionDeviceType)b; } break; case 6: train.Device.LoadCompensatingDevice = a; break; case 7: if (b >= 0 & b <= 2) { train.Device.PassAlarm = (PassAlarmType)b; } break; case 8: if (b >= 0 & b <= 2) { train.Device.DoorOpenMode = (DoorMode)b; } break; case 9: if (b >= 0 & b <= 2) { train.Device.DoorCloseMode = (DoorMode)b; } break; case 10: if (a >= 0.0) { train.Device.DoorWidth = a; } break; case 11: if (a >= 0.0) { train.Device.DoorMaxTolerance = a; } break; } } i++; n++; } i--; break; case "#motor_p1": case "#motor_p2": case "#motor_b1": case "#motor_b2": { string section = lines[i].ToLowerInvariant(); i++; BVEMotorSoundTableEntry[] entries = new BVEMotorSoundTableEntry[800]; while (i < lines.Length && !lines[i].StartsWith("#", StringComparison.InvariantCultureIgnoreCase)) { if (n == entries.Length) { Array.Resize(ref entries, entries.Length << 1); } string u = lines[i] + ","; int k = 0; while (true) { int j = u.IndexOf(','); if (j == -1) { break; } string s = u.Substring(0, j).Trim(); u = u.Substring(j + 1); double a; if (double.TryParse(s, NumberStyles.Float, culture, out a)) { int b = (int)Math.Round(a); switch (k) { case 0: entries[n].SoundIndex = b >= 0 ? b : -1; break; case 1: entries[n].Pitch = (float)Math.Max(a, 0.0); break; case 2: entries[n].Gain = (float)Math.Max(a, 0.0); break; } } k++; } i++; n++; } Array.Resize(ref entries, n); i--; switch (section) { case "#motor_p1": motor.Tracks[(int)Motor.TrackInfo.Power1] = Motor.Track.EntriesToTrack(entries); break; case "#motor_p2": motor.Tracks[(int)Motor.TrackInfo.Power2] = Motor.Track.EntriesToTrack(entries); break; case "#motor_b1": motor.Tracks[(int)Motor.TrackInfo.Brake1] = Motor.Track.EntriesToTrack(entries); break; case "#motor_b2": motor.Tracks[(int)Motor.TrackInfo.Brake2] = Motor.Track.EntriesToTrack(entries); break; } } break; } } int numberOfCars = numberOfMotorCars + numberOfTrailerCars; bool[] isMotorCars = new bool[numberOfCars]; if (numberOfMotorCars == 1) { if (frontCarIsAMotorCar | numberOfTrailerCars == 0) { isMotorCars[0] = true; } else { isMotorCars[numberOfCars - 1] = true; } } else if (numberOfMotorCars == 2) { if (frontCarIsAMotorCar | numberOfTrailerCars == 0) { isMotorCars[0] = true; isMotorCars[numberOfCars - 1] = true; } else if (numberOfTrailerCars == 1) { isMotorCars[1] = true; isMotorCars[2] = true; } else { int i = (int)Math.Ceiling(0.25 * (numberOfCars - 1)); int j = (int)Math.Floor(0.75 * (numberOfCars - 1)); isMotorCars[i] = true; isMotorCars[j] = true; } } else if (numberOfMotorCars > 0) { if (frontCarIsAMotorCar) { isMotorCars[0] = true; double t = 1.0 + numberOfTrailerCars / (double)(numberOfMotorCars - 1); double r = 0.0; double x = 0.0; while (true) { double y = x + t - r; x = Math.Ceiling(y); r = x - y; int i = (int)x; if (i >= numberOfCars) { break; } isMotorCars[i] = true; } } else { isMotorCars[1] = true; double t = 1.0 + (numberOfTrailerCars - 1) / (double)(numberOfMotorCars - 1); double r = 0.0; double x = 1.0; while (true) { double y = x + t - r; x = Math.Ceiling(y); r = x - y; int i = (int)x; if (i >= numberOfCars) { break; } isMotorCars[i] = true; } } } foreach (bool isMotorCar in isMotorCars) { Car car = isMotorCar ? (Car) new MotorCar() : new TrailerCar(); car.Mass = isMotorCar ? motorCarMass : trailerCarMass; car.Length = lengthOfACar; car.Width = widthOfACar; car.Height = heightOfACar; car.CenterOfGravityHeight = centerOfGravityHeight; car.ExposedFrontalArea = exposedFrontalArea; car.UnexposedFrontalArea = unexposedFrontalArea; car.Performance = (Performance)performance.Clone(); car.Delay = (Delay)delay.Clone(); car.Move = (Move)move.Clone(); car.Brake = (Brake)brake.Clone(); car.Pressure = (Pressure)pressure.Clone(); if (isMotorCar) { ((MotorCar)car).Acceleration = (Acceleration)acceleration.Clone(); ((MotorCar)car).Motor = (Motor)motor.Clone(); } train.Cars.Add(car); } for (int i = 0; i < numberOfCars - 1; i++) { train.Couplers.Add(new Models.Trains.Coupler()); } }