/// <summary>Moves the air brake handle to the specified state</summary> /// <param name="newState">The state</param> internal void ApplyLocoAirBrakeHandle(AirBrakeHandleState newState) { if (Handles.LocoBrake is LocoAirBrakeHandle) { if ((int)newState != Handles.LocoBrake.Driver) { // sound when moved to service if (newState == AirBrakeHandleState.Service) { Sounds.SoundBuffer buffer = Cars[DriverCar].Sounds.Brake.Buffer; if (buffer != null) { Vector3 pos = Cars[DriverCar].Sounds.Brake.Position; Sounds.PlaySound(buffer, 1.0, 1.0, pos, this, DriverCar, false); } } // sound if ((int)newState < (int)Handles.Brake.Driver) { // brake release if ((int)newState > 0) { // brake release (not min) Sounds.SoundBuffer buffer; if ((Handles.Brake.Driver - (int)newState > 2 | Cars[DriverCar].Sounds.BrakeHandleFast) && Cars[DriverCar].Sounds.BrakeHandleReleaseFast.Buffer != null) { buffer = Cars[DriverCar].Sounds.BrakeHandleReleaseFast.Buffer; } else { buffer = Cars[DriverCar].Sounds.BrakeHandleRelease.Buffer; } if (buffer != null) { Vector3 pos = Cars[DriverCar].Sounds.BrakeHandleRelease.Position; Sounds.PlaySound(buffer, 1.0, 1.0, pos, this, DriverCar, false); } } else { // brake min Sounds.SoundBuffer buffer = Cars[DriverCar].Sounds.BrakeHandleMin.Buffer; if (buffer != null) { Vector3 pos = Cars[DriverCar].Sounds.BrakeHandleMin.Position; Sounds.PlaySound(buffer, 1.0, 1.0, pos, this, DriverCar, false); } } } else if ((int)newState > (int)Handles.LocoBrake.Driver) { // brake Sounds.SoundBuffer buffer; if (((int)newState - (int)Handles.LocoBrake.Driver > 2 | Cars[DriverCar].Sounds.BrakeHandleFast) && Cars[DriverCar].Sounds.BrakeHandleApplyFast.Buffer != null) { buffer = Cars[DriverCar].Sounds.BrakeHandleApplyFast.Buffer; } else { buffer = Cars[DriverCar].Sounds.BrakeHandleApply.Buffer; } if (buffer != null) { Vector3 pos = Cars[DriverCar].Sounds.BrakeHandleApply.Position; Sounds.PlaySound(buffer, 1.0, 1.0, pos, this, DriverCar, false); } } // apply Handles.LocoBrake.Driver = (int)newState; Handles.LocoBrake.Actual = (int)newState; //TODO: FIXME Game.AddBlackBoxEntry(Game.BlackBoxEventToken.None); // plugin if (Plugin != null) { Plugin.UpdatePower(); Plugin.UpdateBrake(); } } } }
private static void LoadEverythingThreaded() { Program.AppendToLogFile("Loading route file: " + CurrentRouteFile); string RailwayFolder = GetRailwayFolder(CurrentRouteFile); string ObjectFolder = OpenBveApi.Path.CombineDirectory(RailwayFolder, "Object"); string SoundFolder = OpenBveApi.Path.CombineDirectory(RailwayFolder, "Sound"); // reset Game.Reset(true); Game.MinimalisticSimulation = true; // screen World.CameraTrackFollower = new TrackManager.TrackFollower { Train = null, CarIndex = -1 }; World.CameraMode = World.CameraViewMode.Interior; //First, check the format of the route file //RW routes were written for BVE1 / 2, and have a different command syntax bool IsRW = CsvRwRouteParser.isRWFile(CurrentRouteFile); Program.AppendToLogFile("Route file format is: " + (IsRW ? "RW" : "CSV")); CsvRwRouteParser.ParseRoute(CurrentRouteFile, IsRW, CurrentRouteEncoding, CurrentTrainFolder, ObjectFolder, SoundFolder, false); Thread createIllustrations = new Thread(Game.RouteInformation.LoadInformation) { IsBackground = true }; createIllustrations.Start(); System.Threading.Thread.Sleep(1); if (Cancel) { return; } Game.CalculateSeaLevelConstants(); if (Game.BogusPretrainInstructions.Length != 0) { double t = Game.BogusPretrainInstructions[0].Time; double p = Game.BogusPretrainInstructions[0].TrackPosition; for (int i = 1; i < Game.BogusPretrainInstructions.Length; i++) { if (Game.BogusPretrainInstructions[i].Time > t) { t = Game.BogusPretrainInstructions[i].Time; } else { t += 1.0; Game.BogusPretrainInstructions[i].Time = t; } if (Game.BogusPretrainInstructions[i].TrackPosition > p) { p = Game.BogusPretrainInstructions[i].TrackPosition; } else { p += 1.0; Game.BogusPretrainInstructions[i].TrackPosition = p; } } } if (Game.Stations.Length == 1) { //Log the fact that only a single station is present, as this is probably not right Program.AppendToLogFile("The processed route file only contains a single station."); } Program.AppendToLogFile("Route file loaded successfully."); RouteProgress = 1.0; // initialize trains System.Threading.Thread.Sleep(1); if (Cancel) { return; } TrainManager.Trains = new TrainManager.Train[Game.PrecedingTrainTimeDeltas.Length + 1 + (Game.BogusPretrainInstructions.Length != 0 ? 1 : 0)]; for (int k = 0; k < TrainManager.Trains.Length; k++) { if (k == TrainManager.Trains.Length - 1 & Game.BogusPretrainInstructions.Length != 0) { TrainManager.Trains[k] = new TrainManager.Train(k, TrainManager.TrainState.Bogus); } else { TrainManager.Trains[k] = new TrainManager.Train(k, TrainManager.TrainState.Pending); } } TrainManager.PlayerTrain = TrainManager.Trains[Game.PrecedingTrainTimeDeltas.Length]; ObjectManager.UnifiedObject[] CarObjects = null; ObjectManager.UnifiedObject[] BogieObjects = null; // load trains double TrainProgressMaximum = 0.7 + 0.3 * (double)TrainManager.Trains.Length; for (int k = 0; k < TrainManager.Trains.Length; k++) { //Sleep for 20ms to allow route loading locks to release Thread.Sleep(20); if (TrainManager.Trains[k].State == TrainManager.TrainState.Bogus) { // bogus train string TrainData = OpenBveApi.Path.CombineFile(Program.FileSystem.GetDataFolder("Compatibility", "PreTrain"), "train.dat"); TrainDatParser.ParseTrainData(TrainData, System.Text.Encoding.UTF8, TrainManager.Trains[k]); System.Threading.Thread.Sleep(1); if (Cancel) { return; } TrainManager.Trains[k].InitializeCarSounds(); System.Threading.Thread.Sleep(1); if (Cancel) { return; } TrainProgressCurrentWeight = 0.3 / TrainProgressMaximum; TrainProgressCurrentSum += TrainProgressCurrentWeight; } else { TrainManager.Trains[k].TrainFolder = CurrentTrainFolder; // real train if (TrainManager.Trains[k] == TrainManager.PlayerTrain) { Program.AppendToLogFile("Loading player train: " + TrainManager.Trains[k].TrainFolder); } else { Program.AppendToLogFile("Loading AI train: " + TrainManager.Trains[k].TrainFolder); } TrainProgressCurrentWeight = 0.1 / TrainProgressMaximum; string TrainData = OpenBveApi.Path.CombineFile(TrainManager.Trains[k].TrainFolder, "train.dat"); TrainDatParser.ParseTrainData(TrainData, CurrentTrainEncoding, TrainManager.Trains[k]); TrainProgressCurrentSum += TrainProgressCurrentWeight; System.Threading.Thread.Sleep(1); if (Cancel) { return; } TrainProgressCurrentWeight = 0.2 / TrainProgressMaximum; SoundCfgParser.ParseSoundConfig(TrainManager.Trains[k].TrainFolder, CurrentTrainEncoding, TrainManager.Trains[k]); TrainProgressCurrentSum += TrainProgressCurrentWeight; System.Threading.Thread.Sleep(1); if (Cancel) { return; } // door open/close speed for (int i = 0; i < TrainManager.Trains[k].Cars.Length; i++) { if (TrainManager.Trains[k].Cars[i].Specs.DoorOpenFrequency <= 0.0) { if (TrainManager.Trains[k].Cars[i].Doors[0].OpenSound.Buffer != null & TrainManager.Trains[k].Cars[i].Doors[1].OpenSound.Buffer != null) { Sounds.LoadBuffer(TrainManager.Trains[k].Cars[i].Doors[0].OpenSound.Buffer); Sounds.LoadBuffer(TrainManager.Trains[k].Cars[i].Doors[1].OpenSound.Buffer); double a = TrainManager.Trains[k].Cars[i].Doors[0].OpenSound.Buffer.Duration; double b = TrainManager.Trains[k].Cars[i].Doors[1].OpenSound.Buffer.Duration; TrainManager.Trains[k].Cars[i].Specs.DoorOpenFrequency = a + b > 0.0 ? 2.0 / (a + b) : 0.8; } else if (TrainManager.Trains[k].Cars[i].Doors[0].OpenSound.Buffer != null) { Sounds.LoadBuffer(TrainManager.Trains[k].Cars[i].Doors[0].OpenSound.Buffer); double a = TrainManager.Trains[k].Cars[i].Doors[0].OpenSound.Buffer.Duration; TrainManager.Trains[k].Cars[i].Specs.DoorOpenFrequency = a > 0.0 ? 1.0 / a : 0.8; } else if (TrainManager.Trains[k].Cars[i].Doors[1].OpenSound.Buffer != null) { Sounds.LoadBuffer(TrainManager.Trains[k].Cars[i].Doors[0].OpenSound.Buffer); double b = TrainManager.Trains[k].Cars[i].Doors[1].OpenSound.Buffer.Duration; TrainManager.Trains[k].Cars[i].Specs.DoorOpenFrequency = b > 0.0 ? 1.0 / b : 0.8; } else { TrainManager.Trains[k].Cars[i].Specs.DoorOpenFrequency = 0.8; } } if (TrainManager.Trains[k].Cars[i].Specs.DoorCloseFrequency <= 0.0) { if (TrainManager.Trains[k].Cars[i].Doors[0].CloseSound.Buffer != null & TrainManager.Trains[k].Cars[i].Doors[1].CloseSound.Buffer != null) { Sounds.LoadBuffer(TrainManager.Trains[k].Cars[i].Doors[0].CloseSound.Buffer); Sounds.LoadBuffer(TrainManager.Trains[k].Cars[i].Doors[1].CloseSound.Buffer); double a = TrainManager.Trains[k].Cars[i].Doors[0].CloseSound.Buffer.Duration; double b = TrainManager.Trains[k].Cars[i].Doors[1].CloseSound.Buffer.Duration; TrainManager.Trains[k].Cars[i].Specs.DoorCloseFrequency = a + b > 0.0 ? 2.0 / (a + b) : 0.8; } else if (TrainManager.Trains[k].Cars[i].Doors[0].CloseSound.Buffer != null) { Sounds.LoadBuffer(TrainManager.Trains[k].Cars[i].Doors[0].CloseSound.Buffer); double a = TrainManager.Trains[k].Cars[i].Doors[0].CloseSound.Buffer.Duration; TrainManager.Trains[k].Cars[i].Specs.DoorCloseFrequency = a > 0.0 ? 1.0 / a : 0.8; } else if (TrainManager.Trains[k].Cars[i].Doors[1].CloseSound.Buffer != null) { Sounds.LoadBuffer(TrainManager.Trains[k].Cars[i].Doors[0].CloseSound.Buffer); double b = TrainManager.Trains[k].Cars[i].Doors[1].CloseSound.Buffer.Duration; TrainManager.Trains[k].Cars[i].Specs.DoorCloseFrequency = b > 0.0 ? 1.0 / b : 0.8; } else { TrainManager.Trains[k].Cars[i].Specs.DoorCloseFrequency = 0.8; } } const double f = 0.015; const double g = 2.75; TrainManager.Trains[k].Cars[i].Specs.DoorOpenPitch = Math.Exp(f * Math.Tan(g * (Program.RandomNumberGenerator.NextDouble() - 0.5))); TrainManager.Trains[k].Cars[i].Specs.DoorClosePitch = Math.Exp(f * Math.Tan(g * (Program.RandomNumberGenerator.NextDouble() - 0.5))); TrainManager.Trains[k].Cars[i].Specs.DoorOpenFrequency /= TrainManager.Trains[k].Cars[i].Specs.DoorOpenPitch; TrainManager.Trains[k].Cars[i].Specs.DoorCloseFrequency /= TrainManager.Trains[k].Cars[i].Specs.DoorClosePitch; /* * Remove the following two lines, then the pitch at which doors play * takes their randomized opening and closing times into account. * */ TrainManager.Trains[k].Cars[i].Specs.DoorOpenPitch = 1.0; TrainManager.Trains[k].Cars[i].Specs.DoorClosePitch = 1.0; } } // add panel section if (k == TrainManager.PlayerTrain.TrainIndex) { TrainProgressCurrentWeight = 0.7 / TrainProgressMaximum; TrainManager.ParsePanelConfig(TrainManager.Trains[k].TrainFolder, CurrentTrainEncoding, TrainManager.Trains[k]); TrainProgressCurrentSum += TrainProgressCurrentWeight; System.Threading.Thread.Sleep(1); if (Cancel) { return; } Program.AppendToLogFile("Train panel loaded sucessfully."); } // add exterior section if (TrainManager.Trains[k].State != TrainManager.TrainState.Bogus) { bool LoadObjects = false; if (CarObjects == null) { CarObjects = new ObjectManager.UnifiedObject[TrainManager.Trains[k].Cars.Length]; BogieObjects = new ObjectManager.UnifiedObject[TrainManager.Trains[k].Cars.Length * 2]; LoadObjects = true; } string tXml = OpenBveApi.Path.CombineFile(TrainManager.Trains[k].TrainFolder, "train.xml"); if (System.IO.File.Exists(tXml)) { TrainXmlParser.Parse(tXml, TrainManager.Trains[k], ref CarObjects, ref BogieObjects); } else { ExtensionsCfgParser.ParseExtensionsConfig(TrainManager.Trains[k].TrainFolder, CurrentTrainEncoding, ref CarObjects, ref BogieObjects, TrainManager.Trains[k], LoadObjects); } World.CameraCar = TrainManager.Trains[k].DriverCar; System.Threading.Thread.Sleep(1); if (Cancel) { return; } //Stores the current array index of the bogie object to add //Required as there are two bogies per car, and we're using a simple linear array.... int currentBogieObject = 0; for (int i = 0; i < TrainManager.Trains[k].Cars.Length; i++) { if (CarObjects[i] == null) { // load default exterior object string file = OpenBveApi.Path.CombineFile(Program.FileSystem.GetDataFolder("Compatibility"), "exterior.csv"); ObjectManager.StaticObject so = ObjectManager.LoadStaticObject(file, System.Text.Encoding.UTF8, ObjectManager.ObjectLoadMode.Normal, false, false, false); if (so == null) { CarObjects[i] = null; } else { double sx = TrainManager.Trains[k].Cars[i].Width; double sy = TrainManager.Trains[k].Cars[i].Height; double sz = TrainManager.Trains[k].Cars[i].Length; so.ApplyScale(sx, sy, sz); CarObjects[i] = so; } } if (CarObjects[i] != null) { // add object TrainManager.Trains[k].Cars[i].LoadCarSections(CarObjects[i]); } //Load bogie objects if (BogieObjects[currentBogieObject] != null) { TrainManager.Trains[k].Cars[i].FrontBogie.LoadCarSections(BogieObjects[currentBogieObject]); } currentBogieObject++; if (BogieObjects[currentBogieObject] != null) { TrainManager.Trains[k].Cars[i].RearBogie.LoadCarSections(BogieObjects[currentBogieObject]); } currentBogieObject++; } } // place cars TrainManager.Trains[k].PlaceCars(0.0); // configure ai / timetable if (TrainManager.Trains[k] == TrainManager.PlayerTrain) { TrainManager.Trains[k].TimetableDelta = 0.0; } else if (TrainManager.Trains[k].State != TrainManager.TrainState.Bogus) { TrainManager.Trains[k].AI = new Game.SimpleHumanDriverAI(TrainManager.Trains[k]); TrainManager.Trains[k].TimetableDelta = Game.PrecedingTrainTimeDeltas[k]; TrainManager.Trains[k].Specs.DoorOpenMode = TrainManager.DoorMode.Manual; TrainManager.Trains[k].Specs.DoorCloseMode = TrainManager.DoorMode.Manual; } } TrainProgress = 1.0; // finished created objects System.Threading.Thread.Sleep(1); if (Cancel) { return; } Array.Resize(ref ObjectManager.Objects, ObjectManager.ObjectsUsed); Array.Resize(ref ObjectManager.AnimatedWorldObjects, ObjectManager.AnimatedWorldObjectsUsed); // update sections if (Game.Sections.Length > 0) { Game.UpdateSection(Game.Sections.Length - 1); } // load plugin for (int i = 0; i < TrainManager.Trains.Length; i++) { if (TrainManager.Trains[i].State != TrainManager.TrainState.Bogus) { if (TrainManager.Trains[i] == TrainManager.PlayerTrain) { if (!PluginManager.LoadCustomPlugin(TrainManager.Trains[i], TrainManager.Trains[i].TrainFolder, CurrentTrainEncoding)) { PluginManager.LoadDefaultPlugin(TrainManager.Trains[i], TrainManager.Trains[i].TrainFolder); } } else { PluginManager.LoadDefaultPlugin(TrainManager.Trains[i], TrainManager.Trains[i].TrainFolder); } } } }
/// <summary>Applies a loco brake notch to this train</summary> /// <param name="NotchValue">The loco brake notch value</param> /// <param name="Relative">Whether this is relative to the current notch</param> internal void ApplyLocoBrakeNotch(int NotchValue, bool Relative) { int b = Relative ? NotchValue + Handles.LocoBrake.Driver : NotchValue; if (b < 0) { b = 0; } else if (b > Handles.LocoBrake.MaximumNotch) { b = Handles.LocoBrake.MaximumNotch; } // brake sound if (b < Handles.LocoBrake.Driver) { // brake release Sounds.SoundBuffer buffer = Cars[DriverCar].Sounds.Brake.Buffer; if (buffer != null) { Vector3 pos = Cars[DriverCar].Sounds.Brake.Position; Sounds.PlaySound(buffer, 1.0, 1.0, pos, this, DriverCar, false); } if (b > 0) { // brake release (not min) if ((Handles.LocoBrake.Driver - b > 2 | Cars[DriverCar].Sounds.BrakeHandleFast) && Cars[DriverCar].Sounds.BrakeHandleReleaseFast.Buffer != null) { buffer = Cars[DriverCar].Sounds.BrakeHandleReleaseFast.Buffer; } else { buffer = Cars[DriverCar].Sounds.BrakeHandleRelease.Buffer; } if (buffer != null) { Vector3 pos = Cars[DriverCar].Sounds.BrakeHandleRelease.Position; Sounds.PlaySound(buffer, 1.0, 1.0, pos, this, DriverCar, false); } } else { // brake min buffer = Cars[DriverCar].Sounds.BrakeHandleMin.Buffer; if (buffer != null) { Vector3 pos = Cars[DriverCar].Sounds.BrakeHandleMin.Position; Sounds.PlaySound(buffer, 1.0, 1.0, pos, this, DriverCar, false); } } } else if (b > Handles.LocoBrake.Driver) { // brake Sounds.SoundBuffer buffer; if ((b - Handles.LocoBrake.Driver > 2 | Cars[DriverCar].Sounds.BrakeHandleFast) && Cars[DriverCar].Sounds.BrakeHandleApplyFast.Buffer != null) { buffer = Cars[DriverCar].Sounds.BrakeHandleApplyFast.Buffer; } else { buffer = Cars[DriverCar].Sounds.BrakeHandleApply.Buffer; } if (buffer != null) { Vector3 pos = Cars[DriverCar].Sounds.BrakeHandleApply.Position; Sounds.PlaySound(buffer, 1.0, 1.0, pos, this, DriverCar, false); } } Handles.LocoBrake.Driver = b; Handles.LocoBrake.Actual = b; //TODO: FIXME }
/// <summary>Applies the emergency brake</summary> internal void ApplyEmergencyBrake() { // sound if (!Handles.EmergencyBrake.Driver) { Sounds.SoundBuffer buffer = Cars[DriverCar].Sounds.BrakeHandleMax.Buffer; if (buffer != null) { Vector3 pos = Cars[DriverCar].Sounds.BrakeHandleMax.Position; Sounds.PlaySound(buffer, 1.0, 1.0, pos, this, DriverCar, false); } for (int i = 0; i < Cars.Length; i++) { buffer = Cars[DriverCar].Sounds.EmrBrake.Buffer; if (buffer != null) { Vector3 pos = Cars[i].Sounds.EmrBrake.Position; Sounds.PlaySound(buffer, 1.0, 1.0, pos, this, DriverCar, false); } } } // apply ApplyNotch(0, !Handles.SingleHandle, Handles.Brake.MaximumNotch, true); ApplyAirBrakeHandle(AirBrakeHandleState.Service); Handles.EmergencyBrake.Driver = true; Handles.HoldBrake.Driver = false; Specs.CurrentConstSpeed = false; if (Handles.EmergencyBrake.Driver) { switch (Handles.EmergencyBrake.OtherHandlesBehaviour) { case EbHandleBehaviour.PowerNeutral: if (!Handles.SingleHandle) { ApplyNotch(0, false, 0, true); } break; case EbHandleBehaviour.ReverserNeutral: ApplyReverser(0, false); break; case EbHandleBehaviour.PowerReverserNeutral: if (!Handles.SingleHandle) { ApplyNotch(0, false, 0, true); } ApplyReverser(0, false); break; } } // plugin if (Plugin == null) { return; } Plugin.UpdatePower(); Plugin.UpdateBrake(); }
internal SoundHandleEx(double volume, double pitch, Sounds.SoundSource source) { base.MyVolume = volume; base.MyPitch = pitch; base.MyValid = true; this.Source = source; }
/// <summary>Called by the controls loop to start playback of this horn</summary> internal void Play() { if (StartEndSounds == true) { //New style three-part sounds if (LoopStarted == false) { if (!Sounds.IsPlaying(Source)) { if (StartSound != null) { //The start sound is not currently playing, so start it Source = Sounds.PlaySound(StartSound, 1.0, 1.0, SoundPosition, TrainManager.PlayerTrain, TrainManager.PlayerTrain.DriverCar, false); } //Set the loop control variable to started LoopStarted = true; } } else { if (!Sounds.IsPlaying(Source)) { //Start our loop sound playing if the start sound is finished Source = Sounds.PlaySound(LoopSound, 1.0, 1.0, SoundPosition, TrainManager.PlayerTrain, TrainManager.PlayerTrain.DriverCar, true); } } } else { //Original single part sounds if (LoopSound != null) { //Loop is ONLY true if this is a Music Horn if (Loop) { if (!Sounds.IsPlaying(Source) && !LoopStarted) { //On the first keydown event, start the sound source playing and trigger the loop control variable Source = Sounds.PlaySound(LoopSound, 1.0, 1.0, SoundPosition, TrainManager.PlayerTrain, TrainManager.PlayerTrain.DriverCar, true); LoopStarted = true; } else { if (!LoopStarted) { //Our loop control variable is reset by the keyup event so this code will only trigger on the //second keydown meaning our horn toggles Sounds.StopSound(Source); LoopStarted = true; } } } else { if (!LoopStarted) { Source = Sounds.PlaySound(LoopSound, 1.0, 1.0, SoundPosition, TrainManager.PlayerTrain, TrainManager.PlayerTrain.DriverCar, false); } LoopStarted = true; } } } }
internal override void Elapse(ElapseData data) { try { double time = data.TotalTime.Milliseconds; Win32VehicleState win32State; win32State.Location = data.Vehicle.Location; win32State.Speed = (float)data.Vehicle.Speed.KilometersPerHour; win32State.Time = (int)Math.Floor(time - 2073600000.0 * Math.Floor(time / 2073600000.0)); win32State.BcPressure = (float)data.Vehicle.BcPressure; win32State.MrPressure = (float)data.Vehicle.MrPressure; win32State.ErPressure = (float)data.Vehicle.ErPressure; win32State.BpPressure = (float)data.Vehicle.BpPressure; win32State.SapPressure = (float)data.Vehicle.SapPressure; win32State.Current = 0.0f; Win32Handles win32Handles; win32Handles.Brake = data.Handles.BrakeNotch; win32Handles.Power = data.Handles.PowerNotch; win32Handles.Reverser = data.Handles.Reverser; win32Handles.ConstantSpeed = data.Handles.ConstSpeed ? ConstSpeedInstructions.Enable : ConstSpeedInstructions.Disable; Win32Elapse(ref win32Handles.Brake, ref win32State.Location, ref base.Panel[0], ref this.Sound[0]); data.Handles.Reverser = win32Handles.Reverser; data.Handles.PowerNotch = win32Handles.Power; data.Handles.BrakeNotch = win32Handles.Brake; if (win32Handles.ConstantSpeed == ConstSpeedInstructions.Enable) { data.Handles.ConstSpeed = true; } else if (win32Handles.ConstantSpeed == ConstSpeedInstructions.Disable) { data.Handles.ConstSpeed = false; } else if (win32Handles.ConstantSpeed != ConstSpeedInstructions.Continue) { this.PluginValid = false; } /* * Process the sound instructions * */ for (int i = 0; i < this.Sound.Length; i++) { if (this.Sound[i] != this.LastSound[i]) { if (this.Sound[i] == SoundInstructions.Stop) { if (i < base.Train.Cars[base.Train.DriverCar].Sounds.Plugin.Length) { Sounds.StopSound(base.Train.Cars[base.Train.DriverCar].Sounds.Plugin[i].Source); } } else if (this.Sound[i] > SoundInstructions.Stop & this.Sound[i] <= SoundInstructions.PlayLooping) { if (i < base.Train.Cars[base.Train.DriverCar].Sounds.Plugin.Length) { Sounds.SoundBuffer buffer = base.Train.Cars[base.Train.DriverCar].Sounds.Plugin[i].Buffer; if (buffer != null) { double volume = (double)(this.Sound[i] - SoundInstructions.Stop) / (double)(SoundInstructions.PlayLooping - SoundInstructions.Stop); if (Sounds.IsPlaying(base.Train.Cars[base.Train.DriverCar].Sounds.Plugin[i].Source)) { base.Train.Cars[base.Train.DriverCar].Sounds.Plugin[i].Source.Volume = volume; } else { base.Train.Cars[base.Train.DriverCar].Sounds.Plugin[i].Source = Sounds.PlaySound(buffer, 1.0, volume, base.Train.Cars[base.Train.DriverCar].Sounds.Plugin[i].Position, base.Train, base.Train.DriverCar, true); } } } } else if (this.Sound[i] == SoundInstructions.PlayOnce) { if (i < base.Train.Cars[base.Train.DriverCar].Sounds.Plugin.Length) { Sounds.SoundBuffer buffer = base.Train.Cars[base.Train.DriverCar].Sounds.Plugin[i].Buffer; if (buffer != null) { base.Train.Cars[base.Train.DriverCar].Sounds.Plugin[i].Source = Sounds.PlaySound(buffer, 1.0, 1.0, base.Train.Cars[base.Train.DriverCar].Sounds.Plugin[i].Position, base.Train, base.Train.DriverCar, false); } } this.Sound[i] = SoundInstructions.Continue; } else if (this.Sound[i] != SoundInstructions.Continue) { this.PluginValid = false; } this.LastSound[i] = this.Sound[i]; } else { if ((this.Sound[i] < SoundInstructions.Stop | this.Sound[i] > SoundInstructions.PlayLooping) && this.Sound[i] != SoundInstructions.PlayOnce & this.Sound[i] != SoundInstructions.Continue) { this.PluginValid = false; } } } } catch (Exception ex) { base.LastException = ex; throw; } }
private static void Main(string[] args) { // Add handler for UI thread exceptions Application.ThreadException += (CrashHandler.UIThreadException); // Force all WinForms errors to go through handler Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException); // This handler is for catching non-UI thread exceptions AppDomain.CurrentDomain.UnhandledException += (CrashHandler.CurrentDomain_UnhandledException); //Determine the current CPU architecture- //ARM will generally only support OpenGL-ES PortableExecutableKinds peKind; typeof(object).Module.GetPEKind(out peKind, out CurrentCPUArchitecture); Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); //--- determine the running environment --- //I wonder if disabling this hack will stop the craashing on Linux.... CurrentlyRunningOnMono = Type.GetType("Mono.Runtime") != null; //Doesn't appear to, but Mono have fixed the button appearance bug CurrentlyRunningOnWindows = Environment.OSVersion.Platform == PlatformID.Win32S | Environment.OSVersion.Platform == PlatformID.Win32Windows | Environment.OSVersion.Platform == PlatformID.Win32NT; Joysticks = new JoystickManager(); CurrentHost = new Host(); try { FileSystem = FileSystem.FromCommandLineArgs(args); FileSystem.CreateFileSystem(); } catch (Exception ex) { MessageBox.Show(Translations.GetInterfaceString("errors_filesystem_invalid") + Environment.NewLine + Environment.NewLine + ex.Message, Translations.GetInterfaceString("program_title"), MessageBoxButtons.OK, MessageBoxIcon.Hand); return; } Renderer = new NewRenderer(); Sounds = new Sounds(); CurrentRoute = new CurrentRoute(Renderer); //Platform specific startup checks if (CurrentlyRunningOnMono && !CurrentlyRunningOnWindows) { // --- Check if we're running as root, and prompt not to --- if (getuid() == 0) { MessageBox.Show( "You are currently running as the root user." + System.Environment.NewLine + "This is a bad idea, please dont!", Translations.GetInterfaceString("program_title"), MessageBoxButtons.OK, MessageBoxIcon.Hand); } } else { if (!System.IO.File.Exists(System.IO.Path.Combine(Environment.SystemDirectory, "OpenAL32.dll"))) { MessageBox.Show( "OpenAL was not found on your system, and will now be installed." + System.Environment.NewLine + System.Environment.NewLine + "Please follow the install prompts.", Translations.GetInterfaceString("program_title"), MessageBoxButtons.OK, MessageBoxIcon.Hand); ProcessStartInfo info = new ProcessStartInfo(Path.Combine(FileSystem.DataFolder, "Dependencies\\Win32\\oalinst.exe")); info.UseShellExecute = true; if (Environment.OSVersion.Version.Major >= 6) { info.Verb = "runas"; } try { Process p = Process.Start(info); if (p != null) { p.WaitForExit(); } else { //For unknown reasons, the process failed to trigger, but did not raise an exception itself //Throw one throw new Win32Exception(); } } catch (Win32Exception) { MessageBox.Show( "An error occured during OpenAL installation....", Translations.GetInterfaceString("program_title"), MessageBoxButtons.OK, MessageBoxIcon.Hand); } } } // --- load options and controls --- Interface.LoadOptions(); //Switch between SDL2 and native backends; use native backend by default var options = new ToolkitOptions(); if (Interface.CurrentOptions.PreferNativeBackend) { options.Backend = PlatformBackend.PreferNative; } Toolkit.Init(options); // --- load language --- string folder = Program.FileSystem.GetDataFolder("Languages"); Translations.LoadLanguageFiles(folder); folder = Program.FileSystem.GetDataFolder("Cursors"); Cursors.LoadCursorImages(folder); Interface.LoadControls(null, out Interface.CurrentControls); folder = Program.FileSystem.GetDataFolder("Controls"); string file = OpenBveApi.Path.CombineFile(folder, "Default keyboard assignment.controls"); Interface.Control[] controls; Interface.LoadControls(file, out controls); Interface.AddControls(ref Interface.CurrentControls, controls); InputDevicePlugin.LoadPlugins(Program.FileSystem); // --- check the command-line arguments for route and train --- formMain.MainDialogResult result = new formMain.MainDialogResult(); CommandLine.ParseArguments(args, ref result); // --- check whether route and train exist --- if (result.RouteFile != null) { if (!System.IO.File.Exists(result.RouteFile)) { result.RouteFile = null; } } if (result.TrainFolder != null) { if (!System.IO.Directory.Exists(result.TrainFolder)) { result.TrainFolder = null; } } // --- if a route was provided but no train, try to use the route default --- if (result.RouteFile != null & result.TrainFolder == null) { bool isRW = string.Equals(System.IO.Path.GetExtension(result.RouteFile), ".rw", StringComparison.OrdinalIgnoreCase); CsvRwRouteParser.ParseRoute(result.RouteFile, isRW, result.RouteEncoding, null, null, null, true); if (!string.IsNullOrEmpty(Game.TrainName)) { folder = System.IO.Path.GetDirectoryName(result.RouteFile); while (true) { string trainFolder = OpenBveApi.Path.CombineDirectory(folder, "Train"); if (System.IO.Directory.Exists(trainFolder)) { try { folder = OpenBveApi.Path.CombineDirectory(trainFolder, Game.TrainName); } catch (Exception ex) { if (ex is ArgumentException) { break; } } if (System.IO.Directory.Exists(folder)) { file = OpenBveApi.Path.CombineFile(folder, "train.dat"); if (System.IO.File.Exists(file)) { result.TrainFolder = folder; result.TrainEncoding = System.Text.Encoding.UTF8; for (int j = 0; j < Interface.CurrentOptions.TrainEncodings.Length; j++) { if (string.Compare(Interface.CurrentOptions.TrainEncodings[j].Value, result.TrainFolder, StringComparison.InvariantCultureIgnoreCase) == 0) { result.TrainEncoding = System.Text.Encoding.GetEncoding(Interface.CurrentOptions.TrainEncodings[j].Codepage); break; } } } } break; } if (folder == null) { continue; } System.IO.DirectoryInfo info = System.IO.Directory.GetParent(folder); if (info != null) { folder = info.FullName; } else { break; } } } Game.Reset(false, false); } // --- show the main menu if necessary --- if (result.RouteFile == null | result.TrainFolder == null) { Joysticks.RefreshJoysticks(); // end HACK // result = formMain.ShowMainDialog(result); } else { result.Start = true; //Apply translations Translations.SetInGameLanguage(Translations.CurrentLanguageCode); } // --- start the actual program --- if (result.Start) { if (Initialize()) { #if !DEBUG try { #endif MainLoop.StartLoopEx(result); #if !DEBUG } catch (Exception ex) { bool found = false; for (int i = 0; i < TrainManager.Trains.Length; i++) { if (TrainManager.Trains[i] != null && TrainManager.Trains[i].Plugin != null) { if (TrainManager.Trains[i].Plugin.LastException != null) { CrashHandler.LoadingCrash(ex.Message, true); MessageBox.Show("The train plugin " + TrainManager.Trains[i].Plugin.PluginTitle + " caused a runtime exception: " + TrainManager.Trains[i].Plugin.LastException.Message, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Hand); found = true; RestartArguments = ""; break; } } } if (!found) { if (ex is System.DllNotFoundException) { Interface.AddMessage(MessageType.Critical, false, "The required system library " + ex.Message + " was not found on the system."); switch (ex.Message) { case "libopenal.so.1": MessageBox.Show("openAL was not found on this system. \n Please install libopenal1 via your distribtion's package management system.", Translations.GetInterfaceString("program_title"), MessageBoxButtons.OK, MessageBoxIcon.Hand); break; default: MessageBox.Show("The required system library " + ex.Message + " was not found on this system.", Translations.GetInterfaceString("program_title"), MessageBoxButtons.OK, MessageBoxIcon.Hand); break; } } else { Interface.AddMessage(MessageType.Critical, false, "The route and train loader encountered the following critical error: " + ex.Message); CrashHandler.LoadingCrash(ex + Environment.StackTrace, false); } RestartArguments = ""; } } #endif } Deinitialize(); } // --- restart the program if necessary --- if (RestartArguments != null) { string arguments; if (FileSystem.RestartArguments.Length != 0 & RestartArguments.Length != 0) { arguments = FileSystem.RestartArguments + " " + RestartArguments; } else { arguments = FileSystem.RestartArguments + RestartArguments; } try { System.Diagnostics.Process.Start(System.IO.File.Exists(FileSystem.RestartProcess) ? FileSystem.RestartProcess : Application.ExecutablePath, arguments); } catch (Exception ex) { MessageBox.Show(ex.Message + "\n\nProcess = " + FileSystem.RestartProcess + "\nArguments = " + arguments, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error); } } }
/// <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, TrainManager.TrackFollowingObject Train) { System.Globalization.CultureInfo Culture = System.Globalization.CultureInfo.InvariantCulture; string TrainDirectory = string.Empty; 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)) { Interface.AddMessage(MessageType.Error, false, "Directory was not found in " + Key + " in " + Section + " at line " + LineNumber.ToString(Culture) + " in " + FileName); } else { TrainDirectory = trainDirectory; } } 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; } // Initial setting string 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, Encoding.UTF8, Train); Train.AI = new Game.TrackFollowingObjectAI(Train, Data); UnifiedObject[] CarObjects = new UnifiedObject[Train.Cars.Length]; UnifiedObject[] BogieObjects = new UnifiedObject[Train.Cars.Length * 2]; ExtensionsCfgParser.ParseExtensionsConfig(System.IO.Path.GetDirectoryName(ExteriorFile), TextEncoding.GetSystemEncodingFromFile(ExteriorFile), ref CarObjects, ref BogieObjects, 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) { Sounds.LoadBuffer(Car.Doors[0].OpenSound.Buffer); 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) { 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) { 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) { Sounds.LoadBuffer(Car.Doors[0].CloseSound.Buffer); 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) { 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) { 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; } Train.PlaceCars(Data[0].StopPosition); }
private static void Main(string[] args) { // Add handler for UI thread exceptions Application.ThreadException += (CrashHandler.UIThreadException); // Force all WinForms errors to go through handler Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException); // This handler is for catching non-UI thread exceptions AppDomain.CurrentDomain.UnhandledException += (CrashHandler.CurrentDomain_UnhandledException); //Determine the current CPU architecture- //ARM will generally only support OpenGL-ES PortableExecutableKinds peKind; typeof(object).Module.GetPEKind(out peKind, out CurrentCPUArchitecture); Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); CurrentHost = new Host(); if (IntPtr.Size == 4) { Joysticks = new JoystickManager32(); } else { Joysticks = new JoystickManager64(); } try { FileSystem = FileSystem.FromCommandLineArgs(args, CurrentHost); FileSystem.CreateFileSystem(); } catch (Exception ex) { MessageBox.Show(Translations.GetInterfaceString("errors_filesystem_invalid") + Environment.NewLine + Environment.NewLine + ex.Message, Translations.GetInterfaceString("program_title"), MessageBoxButtons.OK, MessageBoxIcon.Hand); return; } Renderer = new NewRenderer(); Sounds = new Sounds(); CurrentRoute = new CurrentRoute(CurrentHost, Renderer); //Platform specific startup checks // --- Check if we're running as root, and prompt not to --- if (CurrentHost.Platform == HostPlatform.GNULinux && (getuid() == 0 || geteuid() == 0)) { MessageBox.Show( "You are currently running as the root user, or via the sudo command." + System.Environment.NewLine + "This is a bad idea, please dont!", Translations.GetInterfaceString("program_title"), MessageBoxButtons.OK, MessageBoxIcon.Hand); } // --- load options and controls --- try { Interface.LoadOptions(); } catch { // ignored } TrainManager = new TrainManager(CurrentHost, Renderer, Interface.CurrentOptions, FileSystem); //Switch between SDL2 and native backends; use native backend by default var options = new ToolkitOptions(); if (Interface.CurrentOptions.PreferNativeBackend) { options.Backend = PlatformBackend.PreferNative; } Toolkit.Init(options); // --- load language --- string folder = Program.FileSystem.GetDataFolder("Languages"); Translations.LoadLanguageFiles(folder); folder = Program.FileSystem.GetDataFolder("Cursors"); Cursors.LoadCursorImages(folder); Interface.LoadControls(null, out Interface.CurrentControls); folder = Program.FileSystem.GetDataFolder("Controls"); string file = OpenBveApi.Path.CombineFile(folder, "Default keyboard assignment.controls"); Control[] controls; Interface.LoadControls(file, out controls); Interface.AddControls(ref Interface.CurrentControls, controls); InputDevicePlugin.LoadPlugins(Program.FileSystem); // --- check the command-line arguments for route and train --- formMain.MainDialogResult result = new formMain.MainDialogResult(); CommandLine.ParseArguments(args, ref result); // --- check whether route and train exist --- if (result.RouteFile != null) { if (!System.IO.File.Exists(result.RouteFile)) { result.RouteFile = null; } } if (result.TrainFolder != null) { if (!System.IO.Directory.Exists(result.TrainFolder)) { result.TrainFolder = null; } } // --- if a route was provided but no train, try to use the route default --- if (result.RouteFile != null & result.TrainFolder == null) { string error; if (!CurrentHost.LoadPlugins(FileSystem, Interface.CurrentOptions, out error, TrainManager, Renderer)) { MessageBox.Show(error, @"OpenBVE", MessageBoxButtons.OK, MessageBoxIcon.Error); throw new Exception("Unable to load the required plugins- Please reinstall OpenBVE"); } Game.Reset(false); bool loaded = false; for (int i = 0; i < Program.CurrentHost.Plugins.Length; i++) { if (Program.CurrentHost.Plugins[i].Route != null && Program.CurrentHost.Plugins[i].Route.CanLoadRoute(result.RouteFile)) { object Route = (object)Program.CurrentRoute; //must cast to allow us to use the ref keyword. Program.CurrentHost.Plugins[i].Route.LoadRoute(result.RouteFile, result.RouteEncoding, null, null, null, true, ref Route); Program.CurrentRoute = (CurrentRoute)Route; Program.Renderer.Lighting.OptionAmbientColor = CurrentRoute.Atmosphere.AmbientLightColor; Program.Renderer.Lighting.OptionDiffuseColor = CurrentRoute.Atmosphere.DiffuseLightColor; Program.Renderer.Lighting.OptionLightPosition = CurrentRoute.Atmosphere.LightPosition; loaded = true; break; } } if (!CurrentHost.UnloadPlugins(out error)) { MessageBox.Show(error, @"OpenBVE", MessageBoxButtons.OK, MessageBoxIcon.Error); } if (!loaded) { throw new Exception("No plugins capable of loading routefile " + result.RouteFile + " were found."); } if (!string.IsNullOrEmpty(Interface.CurrentOptions.TrainName)) { folder = System.IO.Path.GetDirectoryName(result.RouteFile); while (true) { string trainFolder = OpenBveApi.Path.CombineDirectory(folder, "Train"); if (System.IO.Directory.Exists(trainFolder)) { try { folder = OpenBveApi.Path.CombineDirectory(trainFolder, Interface.CurrentOptions.TrainName); } catch (Exception ex) { if (ex is ArgumentException) { break; } } if (System.IO.Directory.Exists(folder)) { file = OpenBveApi.Path.CombineFile(folder, "train.dat"); if (System.IO.File.Exists(file)) { result.TrainFolder = folder; result.TrainEncoding = System.Text.Encoding.UTF8; for (int j = 0; j < Interface.CurrentOptions.TrainEncodings.Length; j++) { if (string.Compare(Interface.CurrentOptions.TrainEncodings[j].Value, result.TrainFolder, StringComparison.InvariantCultureIgnoreCase) == 0) { result.TrainEncoding = System.Text.Encoding.GetEncoding(Interface.CurrentOptions.TrainEncodings[j].Codepage); break; } } } } break; } if (folder == null) { continue; } System.IO.DirectoryInfo info = System.IO.Directory.GetParent(folder); if (info != null) { folder = info.FullName; } else { break; } } } Game.Reset(false); } // --- show the main menu if necessary --- if (result.RouteFile == null | result.TrainFolder == null) { Joysticks.RefreshJoysticks(); // end HACK // result = formMain.ShowMainDialog(result); } else { result.Start = true; //Apply translations Translations.SetInGameLanguage(Translations.CurrentLanguageCode); } // --- start the actual program --- if (result.Start) { if (Initialize()) { #if !DEBUG try { #endif MainLoop.StartLoopEx(result); #if !DEBUG } catch (Exception ex) { bool found = false; for (int i = 0; i < TrainManager.Trains.Length; i++) { if (TrainManager.Trains[i] != null && TrainManager.Trains[i].Plugin != null) { if (TrainManager.Trains[i].Plugin.LastException != null) { CrashHandler.LoadingCrash(ex.Message, true); MessageBox.Show("The train plugin " + TrainManager.Trains[i].Plugin.PluginTitle + " caused a runtime exception: " + TrainManager.Trains[i].Plugin.LastException.Message, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Hand); found = true; RestartArguments = ""; break; } } } if (!found) { if (ex is System.DllNotFoundException) { Interface.AddMessage(MessageType.Critical, false, "The required system library " + ex.Message + " was not found on the system."); switch (ex.Message) { case "libopenal.so.1": MessageBox.Show("openAL was not found on this system. \n Please install libopenal1 via your distribtion's package management system.", Translations.GetInterfaceString("program_title"), MessageBoxButtons.OK, MessageBoxIcon.Hand); break; default: MessageBox.Show("The required system library " + ex.Message + " was not found on this system.", Translations.GetInterfaceString("program_title"), MessageBoxButtons.OK, MessageBoxIcon.Hand); break; } } else { Interface.AddMessage(MessageType.Critical, false, "The route and train loader encountered the following critical error: " + ex.Message); CrashHandler.LoadingCrash(ex + Environment.StackTrace, false); } RestartArguments = ""; } } #endif } Deinitialize(); } // --- restart the program if necessary --- if (RestartArguments != null) { string arguments; if (FileSystem.RestartArguments.Length != 0 & RestartArguments.Length != 0) { arguments = FileSystem.RestartArguments + " " + RestartArguments; } else { arguments = FileSystem.RestartArguments + RestartArguments; } try { System.Diagnostics.Process.Start(System.IO.File.Exists(FileSystem.RestartProcess) ? FileSystem.RestartProcess : Application.ExecutablePath, arguments); } catch (Exception ex) { MessageBox.Show(ex.Message + "\n\nProcess = " + FileSystem.RestartProcess + "\nArguments = " + arguments, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error); } } }
/// <summary>Call this method to update the train</summary> /// <param name="TimeElapsed">The elapsed time this frame</param> internal new void Update(double TimeElapsed) { if (State == TrainState.Pending) { // pending train if (Game.SecondsSinceMidnight >= AppearanceTime) { double PlayerTrainTrackPosition = PlayerTrain.Cars[0].FrontAxle.Follower.TrackPosition + 0.5 * PlayerTrain.Cars[0].Length - PlayerTrain.Cars[0].FrontAxle.Position; if (PlayerTrainTrackPosition < AppearanceStartPosition || (PlayerTrainTrackPosition > AppearanceEndPosition && AppearanceEndPosition > AppearanceStartPosition)) { return; } // train is introduced State = TrainState.Available; for (int i = 0; i < Cars.Length; i++) { if (Cars[i].CarSections.Length != 0) { Cars[i].ChangeCarSection(CarSectionType.Exterior); } Cars[i].FrontBogie.ChangeSection(0); Cars[i].RearBogie.ChangeSection(0); if (Cars[i].Specs.IsMotorCar) { if (Cars[i].Sounds.Loop.Buffer != null) { Vector3 pos = Cars[i].Sounds.Loop.Position; Cars[i].Sounds.Loop.Source = Sounds.PlaySound(Cars[i].Sounds.Loop.Buffer, 1.0, 1.0, pos, this, i, true); } } } } } else if (State == TrainState.Available) { // available train UpdatePhysicsAndControls(TimeElapsed); for (int i = 0; i < Cars.Length; i++) { byte dnb; { float b = (float)(Cars[i].Brightness.NextTrackPosition - Cars[i].Brightness.PreviousTrackPosition); //1.0f represents a route brightness value of 255 //0.0f represents a route brightness value of 0 if (b != 0.0f) { b = (float)(Cars[i].FrontAxle.Follower.TrackPosition - Cars[i].Brightness.PreviousTrackPosition) / b; if (b < 0.0f) { b = 0.0f; } if (b > 1.0f) { b = 1.0f; } b = Cars[i].Brightness.PreviousBrightness * (1.0f - b) + Cars[i].Brightness.NextBrightness * b; } else { b = Cars[i].Brightness.PreviousBrightness; } //Calculate the cab brightness double ccb = Math.Round(255.0 * (double)(1.0 - b)); //DNB then must equal the smaller of the cab brightness value & the dynamic brightness value dnb = (byte)Math.Min(Renderer.DynamicCabBrightness, ccb); } int cs = Cars[i].CurrentCarSection; if (cs >= 0 && Cars[i].CarSections.Length > 0 && Cars[i].CarSections.Length >= cs) { if (Cars[i].CarSections[cs].Groups.Length > 0) { for (int k = 0; k < Cars[i].CarSections[cs].Groups[0].Elements.Length; k++) { int o = Cars[i].CarSections[cs].Groups[0].Elements[k].ObjectIndex; if (ObjectManager.Objects[o] != null) { for (int j = 0; j < ObjectManager.Objects[o].Mesh.Materials.Length; j++) { ObjectManager.Objects[o].Mesh.Materials[j].DaytimeNighttimeBlend = dnb; } } } } } if (AI != null) { AI.Trigger(TimeElapsed); } } } else if (State == TrainState.Bogus) { // bogus train if (AI != null) { AI.Trigger(TimeElapsed); } } }
// // PROCESS MENU COMMAND // /// <summary>Processes a user command for the current menu</summary> /// <param name="cmd">The command to apply to the current menu</param> /// <param name="timeElapsed">The time elapsed since previous frame</param> internal void ProcessCommand(Interface.Command cmd, double timeElapsed) { if (CurrMenu < 0) { return; } // MenuBack is managed independently from single menu data if (cmd == Interface.Command.MenuBack) { PopMenu(); return; } SingleMenu menu = Menus[CurrMenu]; if (menu.Selection == SelectionNone) // if menu has no selection, do nothing { return; } switch (cmd) { case Interface.Command.MenuUp: // UP if (menu.Selection > 0 && !(menu.Items[menu.Selection - 1] is MenuCaption)) { menu.Selection--; PositionMenu(); } break; case Interface.Command.MenuDown: // DOWN if (menu.Selection < menu.Items.Length - 1) { menu.Selection++; PositionMenu(); } break; // case Interface.Command.MenuBack: // ESC: managed above // break; case Interface.Command.MenuEnter: // ENTER if (menu.Items[menu.Selection] is MenuCommand) { MenuCommand menuItem = (MenuCommand)menu.Items[menu.Selection]; switch (menuItem.Tag) { // menu management commands case MenuTag.MenuBack: // BACK TO PREVIOUS MENU Menu.instance.PopMenu(); break; case MenuTag.MenuJumpToStation: // TO STATIONS MENU Menu.instance.PushMenu(MenuType.JumpToStation); break; case MenuTag.MenuExitToMainMenu: // TO EXIT MENU Menu.instance.PushMenu(MenuType.ExitToMainMenu); break; case MenuTag.MenuQuit: // TO QUIT MENU Menu.instance.PushMenu(MenuType.Quit); break; case MenuTag.MenuControls: // TO CONTROLS MENU Menu.instance.PushMenu(MenuType.Controls); break; case MenuTag.BackToSim: // OUT OF MENU BACK TO SIMULATION Reset(); Game.PreviousInterface = Game.InterfaceType.Menu; Game.CurrentInterface = Game.InterfaceType.Normal; break; // simulation commands case MenuTag.JumpToStation: // JUMP TO STATION Reset(); TrainManager.JumpTrain(TrainManager.PlayerTrain, menuItem.Data); break; case MenuTag.ExitToMainMenu: // BACK TO MAIN MENU Reset(); Program.RestartArguments = Interface.CurrentOptions.GameMode == Interface.GameMode.Arcade ? "/review" : ""; MainLoop.Quit = true; break; case MenuTag.Control: // CONTROL CUSTOMIZATION PushMenu(MenuType.Control, ((MenuCommand)menu.Items[menu.Selection]).Data); isCustomisingControl = true; CustomControlIdx = ((MenuCommand)menu.Items[menu.Selection]).Data; break; case MenuTag.Quit: // QUIT PROGRAMME Reset(); MainLoop.Quit = true; break; } } break; case Interface.Command.MiscFullscreen: // fullscreen Screen.ToggleFullscreen(); break; case Interface.Command.MiscMute: // mute Sounds.GlobalMute = !Sounds.GlobalMute; Sounds.Update(timeElapsed, Interface.CurrentOptions.SoundModel); break; } }
public static Game.Station ReadStationXML(string fileName, bool PreviewOnly, Textures.Texture[] daytimeTimetableTextures, Textures.Texture[] nighttimeTimetableTextures, int CurrentStation, ref bool passAlarm, ref CsvRwRouteParser.StopRequest stopRequest) { Game.Station station = new Game.Station { Stops = new Game.StationStop[] { } }; stopRequest.Early = new TrackManager.RequestStop(); stopRequest.OnTime = new TrackManager.RequestStop(); stopRequest.Late = new TrackManager.RequestStop(); stopRequest.OnTime.Probability = 75; //The current XML file to load XmlDocument currentXML = new XmlDocument(); //Load the object's XML file currentXML.Load(fileName); string Path = System.IO.Path.GetDirectoryName(fileName); //Check for null if (currentXML.DocumentElement != null) { XmlNodeList DocumentNodes = currentXML.DocumentElement.SelectNodes("/openBVE/Station"); //Check this file actually contains OpenBVE light definition nodes if (DocumentNodes != null) { foreach (XmlNode n in DocumentNodes) { if (n.ChildNodes.OfType <XmlElement>().Any()) { foreach (XmlNode c in n.ChildNodes) { //string[] Arguments = c.InnerText.Split(','); switch (c.Name.ToLowerInvariant()) { case "name": if (!string.IsNullOrEmpty(c.InnerText)) { station.Name = c.InnerText; } else { Interface.AddMessage(Interface.MessageType.Error, false, "Station name was empty in XML file " + fileName); } break; case "arrivaltime": if (!string.IsNullOrEmpty(c.InnerText)) { if (!Interface.TryParseTime(c.InnerText, out station.ArrivalTime)) { Interface.AddMessage(Interface.MessageType.Error, false, "Station arrival time was invalid in XML file " + fileName); } } break; case "departuretime": if (!string.IsNullOrEmpty(c.InnerText)) { if (!Interface.TryParseTime(c.InnerText, out station.DepartureTime)) { Interface.AddMessage(Interface.MessageType.Error, false, "Station arrival time was invalid in XML file " + fileName); } } break; case "type": switch (c.InnerText.ToLowerInvariant()) { case "c": case "changeends": station.StationType = Game.StationType.ChangeEnds; break; case "t": case "terminal": station.StationType = Game.StationType.Terminal; break; default: station.StationType = Game.StationType.Normal; break; } break; case "passalarm": if (!string.IsNullOrEmpty(c.InnerText)) { if (c.InnerText.ToLowerInvariant() == "1" || c.InnerText.ToLowerInvariant() == "true") { passAlarm = true; } else { passAlarm = false; } } break; case "doors": int door = 0; bool doorboth = false; if (!string.IsNullOrEmpty(c.InnerText)) { switch (c.InnerText.ToLowerInvariant()) { case "l": case "left": door = -1; break; case "r": case "right": door = 1; break; case "n": case "none": case "neither": door = 0; break; case "b": case "both": doorboth = true; break; default: if (!NumberFormats.TryParseIntVb6(c.InnerText, out door)) { Interface.AddMessage(Interface.MessageType.Error, false, "Door side was invalid in XML file " + fileName); door = 0; } break; } } station.OpenLeftDoors = door < 0.0 | doorboth; station.OpenRightDoors = door > 0.0 | doorboth; break; case "forcedredsignal": if (!string.IsNullOrEmpty(c.InnerText)) { if (c.InnerText.ToLowerInvariant() == "1" || c.InnerText.ToLowerInvariant() == "true") { station.ForceStopSignal = true; } else { station.ForceStopSignal = false; } } break; case "system": switch (c.InnerText.ToLowerInvariant()) { case "0": case "ATS": station.SafetySystem = Game.SafetySystem.Ats; break; case "1": case "ATC": station.SafetySystem = Game.SafetySystem.Atc; break; default: Interface.AddMessage(Interface.MessageType.Error, false, "An invalid station safety system was specified in XML file " + fileName); station.SafetySystem = Game.SafetySystem.Ats; break; } break; case "arrivalsound": string arrSound = string.Empty; double arrRadius = 30.0; if (!c.ChildNodes.OfType <XmlElement>().Any()) { foreach (XmlNode cc in c.ChildNodes) { switch (c.Name.ToLowerInvariant()) { case "filename": try { arrSound = OpenBveApi.Path.CombineFile(Path, cc.InnerText); } catch { Interface.AddMessage(Interface.MessageType.Error, false, "Arrival sound filename is invalid in XML file " + fileName); } break; case "radius": if (!double.TryParse(cc.InnerText, out arrRadius)) { Interface.AddMessage(Interface.MessageType.Error, false, "Arrival sound radius was invalid in XML file " + fileName); } break; } } } else { try { arrSound = OpenBveApi.Path.CombineFile(Path, c.InnerText); } catch { Interface.AddMessage(Interface.MessageType.Error, false, "Arrival sound filename is invalid in XML file " + fileName); } } if (File.Exists(arrSound)) { station.ArrivalSoundBuffer = Sounds.RegisterBuffer(arrSound, arrRadius); } else { Interface.AddMessage(Interface.MessageType.Error, false, "Arrival sound file does not exist in XML file " + fileName); } break; case "stopduration": double stopDuration; if (!double.TryParse(c.InnerText, out stopDuration)) { Interface.AddMessage(Interface.MessageType.Error, false, "Stop duration is invalid in XML file " + fileName); } else { if (stopDuration < 5.0) { stopDuration = 5.0; } station.StopTime = stopDuration; } break; case "passengerratio": double ratio; if (!double.TryParse(c.InnerText, out ratio)) { Interface.AddMessage(Interface.MessageType.Error, false, "Passenger ratio is invalid in XML file " + fileName); } else { if (ratio < 0.0) { Interface.AddMessage(Interface.MessageType.Error, false, "Passenger ratio must be non-negative in XML file " + fileName); ratio = 100.0; } station.PassengerRatio = ratio * 0.01; } break; case "departuresound": string depSound = string.Empty; double depRadius = 30.0; if (!c.ChildNodes.OfType <XmlElement>().Any()) { foreach (XmlNode cc in c.ChildNodes) { switch (c.Name.ToLowerInvariant()) { case "filename": try { depSound = OpenBveApi.Path.CombineFile(Path, cc.InnerText); } catch { Interface.AddMessage(Interface.MessageType.Error, false, "Departure sound filename is invalid in XML file " + fileName); } break; case "radius": if (!double.TryParse(cc.InnerText, out depRadius)) { Interface.AddMessage(Interface.MessageType.Error, false, "Departure sound radius was invalid in XML file " + fileName); } break; } } } else { try { depSound = OpenBveApi.Path.CombineFile(Path, c.InnerText); } catch { Interface.AddMessage(Interface.MessageType.Error, false, "Departure sound filename is invalid in XML file " + fileName); } } if (File.Exists(depSound)) { station.DepartureSoundBuffer = Sounds.RegisterBuffer(depSound, depRadius); } else { Interface.AddMessage(Interface.MessageType.Error, false, "Departure sound file does not exist in XML file " + fileName); } break; case "timetableindex": if (!PreviewOnly) { int ttidx = -1; if (!string.IsNullOrEmpty(c.InnerText)) { if (NumberFormats.TryParseIntVb6(c.InnerText, out ttidx)) { if (ttidx < 0) { Interface.AddMessage(Interface.MessageType.Error, false, "Timetable index must be non-negative in XML file " + fileName); ttidx = -1; } else if (ttidx >= daytimeTimetableTextures.Length & ttidx >= nighttimeTimetableTextures.Length) { Interface.AddMessage(Interface.MessageType.Error, false, "Timetable index references a non-loaded texture in XML file " + fileName); ttidx = -1; } station.TimetableDaytimeTexture = ttidx >= 0 & ttidx < daytimeTimetableTextures.Length ? daytimeTimetableTextures[ttidx] : null; station.TimetableNighttimeTexture = ttidx >= 0 & ttidx < nighttimeTimetableTextures.Length ? nighttimeTimetableTextures[ttidx] : null; break; } } if (ttidx == -1) { if (CurrentStation > 0) { station.TimetableDaytimeTexture = Game.Stations[CurrentStation - 1].TimetableDaytimeTexture; station.TimetableNighttimeTexture = Game.Stations[CurrentStation - 1].TimetableNighttimeTexture; } else if (daytimeTimetableTextures.Length > 0 & nighttimeTimetableTextures.Length > 0) { station.TimetableDaytimeTexture = daytimeTimetableTextures[0]; station.TimetableNighttimeTexture = nighttimeTimetableTextures[0]; } } } break; case "requeststop": station.StationType = Game.StationType.RequestStop; station.StopMode = Game.StationStopMode.AllRequestStop; foreach (XmlNode cc in c.ChildNodes) { switch (cc.Name.ToLowerInvariant()) { case "aibehaviour": switch (cc.InnerText.ToLowerInvariant()) { case "fullspeed": case "0": //With this set, the AI driver will not attempt to brake, but pass through at linespeed stopRequest.FullSpeed = true; break; case "normalbrake": case "1": //With this set, the AI driver breaks to a near stop whilst passing through the station stopRequest.FullSpeed = false; break; } break; case "playeronly": station.StopMode = Game.StationStopMode.PlayerRequestStop; break; case "distance": if (!string.IsNullOrEmpty(cc.InnerText)) { double d; if (!NumberFormats.TryParseDoubleVb6(cc.InnerText, out d)) { Interface.AddMessage(Interface.MessageType.Error, false, "Request stop distance is invalid in XML file " + fileName); break; } stopRequest.TrackPosition -= Math.Abs(d); } break; case "earlytime": if (!string.IsNullOrEmpty(cc.InnerText)) { if (!Interface.TryParseTime(cc.InnerText, out stopRequest.Early.Time)) { Interface.AddMessage(Interface.MessageType.Error, false, "Request stop early time was invalid in XML file " + fileName); } } break; case "latetime": if (!string.IsNullOrEmpty(cc.InnerText)) { if (!Interface.TryParseTime(cc.InnerText, out stopRequest.Late.Time)) { Interface.AddMessage(Interface.MessageType.Error, false, "Request stop late time was invalid in XML file " + fileName); } } break; case "stopmessage": if (cc.ChildNodes.OfType <XmlElement>().Any()) { foreach (XmlNode cd in cc.ChildNodes) { switch (cd.Name.ToLowerInvariant()) { case "early": if (!string.IsNullOrEmpty(cd.InnerText)) { stopRequest.Early.StopMessage = cd.InnerText; } break; case "ontime": if (!string.IsNullOrEmpty(cd.InnerText)) { stopRequest.OnTime.StopMessage = cd.InnerText; } break; case "late": if (!string.IsNullOrEmpty(cd.InnerText)) { stopRequest.Late.StopMessage = cd.InnerText; } break; case "#text": stopRequest.Early.StopMessage = cc.InnerText; stopRequest.OnTime.StopMessage = cc.InnerText; stopRequest.Late.StopMessage = cc.InnerText; break; } } } break; case "passmessage": if (cc.ChildNodes.OfType <XmlElement>().Any()) { foreach (XmlNode cd in cc.ChildNodes) { switch (cd.Name.ToLowerInvariant()) { case "early": if (!string.IsNullOrEmpty(cd.InnerText)) { stopRequest.Early.PassMessage = cd.InnerText; } break; case "ontime": if (!string.IsNullOrEmpty(cd.InnerText)) { stopRequest.OnTime.PassMessage = cd.InnerText; } break; case "late": if (!string.IsNullOrEmpty(cd.InnerText)) { stopRequest.Late.PassMessage = cd.InnerText; } break; case "#text": stopRequest.Early.PassMessage = cc.InnerText; stopRequest.OnTime.PassMessage = cc.InnerText; stopRequest.Late.PassMessage = cc.InnerText; break; } } } break; case "probability": foreach (XmlNode cd in cc.ChildNodes) { switch (cd.Name.ToLowerInvariant()) { case "early": if (!string.IsNullOrEmpty(cd.InnerText)) { if (!NumberFormats.TryParseIntVb6(cd.InnerText, out stopRequest.Early.Probability)) { Interface.AddMessage(Interface.MessageType.Error, false, "Request stop early probability was invalid in XML file " + fileName); } } break; case "ontime": if (!string.IsNullOrEmpty(cd.InnerText)) { if (!NumberFormats.TryParseIntVb6(cd.InnerText, out stopRequest.OnTime.Probability)) { Interface.AddMessage(Interface.MessageType.Error, false, "Request stop ontime probability was invalid in XML file " + fileName); } } break; case "late": if (!string.IsNullOrEmpty(cd.InnerText)) { if (!NumberFormats.TryParseIntVb6(cd.InnerText, out stopRequest.OnTime.Probability)) { Interface.AddMessage(Interface.MessageType.Error, false, "Request stop late probability was invalid in XML file " + fileName); } } break; case "#text": if (!NumberFormats.TryParseIntVb6(cd.InnerText, out stopRequest.OnTime.Probability)) { Interface.AddMessage(Interface.MessageType.Error, false, "Request stop probability was invalid in XML file " + fileName); } break; } } break; case "maxcars": if (!NumberFormats.TryParseIntVb6(cc.InnerText, out stopRequest.MaxNumberOfCars)) { Interface.AddMessage(Interface.MessageType.Error, false, "Request stop maximum cars was invalid in XML file " + fileName); } break; } } break; } } } } return(station); } } //We couldn't find any valid XML, so return false throw new InvalidDataException(); }
/// <summary>Is called once a frame, to update the door states of the specified train</summary> /// <param name="Train">The train</param> /// <param name="TimeElapsed">The frame time elapsed</param> private static void UpdateTrainDoors(Train Train, double TimeElapsed) { OpenBveApi.Runtime.DoorStates oldState = OpenBveApi.Runtime.DoorStates.None; OpenBveApi.Runtime.DoorStates newState = OpenBveApi.Runtime.DoorStates.None; for (int i = 0; i < Train.Cars.Length; i++) { bool ld = Train.Cars[i].Doors[0].AnticipatedOpen; bool rd = Train.Cars[i].Doors[1].AnticipatedOpen; double os = Train.Cars[i].Specs.DoorOpenFrequency; double cs = Train.Cars[i].Specs.DoorCloseFrequency; for (int j = 0; j < Train.Cars[i].Doors.Length; j++) { if (Train.Cars[i].Doors[j].Direction == -1 | Train.Cars[i].Doors[j].Direction == 1) { bool shouldBeOpen = Train.Cars[i].Doors[j].Direction == -1 ? ld : rd; if (Train.Cars[i].Doors[j].State > 0.0) { if (Train.Cars[i].Doors[j].Direction == -1) { oldState |= OpenBveApi.Runtime.DoorStates.Left; } else { oldState |= OpenBveApi.Runtime.DoorStates.Right; } } if (shouldBeOpen) { // open Train.Cars[i].Doors[j].State += os * TimeElapsed; if (Train.Cars[i].Doors[j].State > 1.0) { Train.Cars[i].Doors[j].State = 1.0; } } else { // close if (Train.Cars[i].Doors[j].DoorLockDuration > 0.0) { if (Train.Cars[i].Doors[j].State > Train.Cars[i].Doors[j].DoorLockState) { Train.Cars[i].Doors[j].State -= cs * TimeElapsed; } if (Train.Cars[i].Doors[j].State < Train.Cars[i].Doors[j].DoorLockState) { Train.Cars[i].Doors[j].State = Train.Cars[i].Doors[j].DoorLockState; } Train.Cars[i].Doors[j].DoorLockDuration -= TimeElapsed; if (Train.Cars[i].Doors[j].DoorLockDuration < 0.0) { Train.Cars[i].Doors[j].DoorLockDuration = 0.0; } } else { Train.Cars[i].Doors[j].State -= cs * TimeElapsed; } if (Train.Cars[i].Doors[j].AnticipatedReopen && Train.Cars[i].Doors[j].State < Train.Cars[i].Doors[j].InterferingObjectRate) { Train.Cars[i].Doors[j].State = Train.Cars[i].Doors[j].InterferingObjectRate; } if (Train.Cars[i].Doors[j].State < 0.0) { Train.Cars[i].Doors[j].State = 0.0; } } if (Train.Cars[i].Doors[j].State > 0.0) { if (Train.Cars[i].Doors[j].Direction == -1) { newState |= OpenBveApi.Runtime.DoorStates.Left; } else { newState |= OpenBveApi.Runtime.DoorStates.Right; } } } } } if (oldState != OpenBveApi.Runtime.DoorStates.None & newState == OpenBveApi.Runtime.DoorStates.None) { Sounds.SoundBuffer buffer = Train.Cars[Train.DriverCar].Sounds.PilotLampOn.Buffer; if (buffer != null) { OpenBveApi.Math.Vector3 pos = Train.Cars[Train.DriverCar].Sounds.PilotLampOn.Position; Sounds.PlaySound(buffer, 1.0, 1.0, pos, Train, Train.DriverCar, false); } } else if (oldState == OpenBveApi.Runtime.DoorStates.None & newState != OpenBveApi.Runtime.DoorStates.None) { Sounds.SoundBuffer buffer = Train.Cars[Train.DriverCar].Sounds.PilotLampOff.Buffer; if (buffer != null) { OpenBveApi.Math.Vector3 pos = Train.Cars[Train.DriverCar].Sounds.PilotLampOff.Position; Sounds.PlaySound(buffer, 1.0, 1.0, pos, Train, Train.DriverCar, false); } } if (oldState != newState) { if (Train.Plugin != null) { Train.Plugin.DoorChange(oldState, newState); } } }
internal static void Main(string[] args) { CurrentHost = new Host(); // file system FileSystem = FileSystem.FromCommandLineArgs(args, CurrentHost); FileSystem.CreateFileSystem(); Renderer = new NewRenderer(); CurrentRoute = new CurrentRoute(CurrentHost, Renderer); Sounds = new Sounds(); Options.LoadOptions(); TrainManager = new TrainManager(CurrentHost, Renderer, Interface.CurrentOptions, FileSystem); string error; if (!CurrentHost.LoadPlugins(FileSystem, Interface.CurrentOptions, out error, TrainManager, Renderer)) { MessageBox.Show(error, @"OpenBVE", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } // command line arguments StringBuilder objectsToLoad = new StringBuilder(); if (args.Length != 0) { for (int i = 0; i < args.Length; i++) { if (args[i] != null) { if (System.IO.File.Exists(args[i])) { for (int j = 0; j < CurrentHost.Plugins.Length; j++) { if (CurrentHost.Plugins[j].Object != null && CurrentHost.Plugins[j].Object.CanLoadObject(args[i])) { objectsToLoad.Append(args[i] + " "); continue; } if (CurrentHost.Plugins[j].Route != null && CurrentHost.Plugins[j].Route.CanLoadRoute(args[i])) { if (string.IsNullOrEmpty(CurrentRouteFile)) { CurrentRouteFile = args[i]; processCommandLineArgs = true; } } } } else if (args[i].ToLowerInvariant() == "/enablehacks") { //Deliberately undocumented option for debugging use Interface.CurrentOptions.EnableBveTsHacks = true; for (int j = 0; j < CurrentHost.Plugins.Length; j++) { if (CurrentHost.Plugins[j].Object != null) { CompatabilityHacks enabledHacks = new CompatabilityHacks { BveTsHacks = true, CylinderHack = false, BlackTransparency = true }; CurrentHost.Plugins[j].Object.SetCompatibilityHacks(enabledHacks); } } } } } } if (objectsToLoad.Length != 0) { string File = System.IO.Path.Combine(Application.StartupPath, "ObjectViewer.exe"); if (System.IO.File.Exists(File)) { System.Diagnostics.Process.Start(File, objectsToLoad.ToString()); if (string.IsNullOrEmpty(CurrentRouteFile)) { //We only supplied objects, so launch Object Viewer instead Environment.Exit(0); } } } var options = new ToolkitOptions(); options.Backend = PlatformBackend.PreferX11; Toolkit.Init(options); string folder = Program.FileSystem.GetDataFolder("Languages"); Translations.LoadLanguageFiles(folder); Interface.CurrentOptions.ObjectOptimizationBasicThreshold = 1000; Interface.CurrentOptions.ObjectOptimizationFullThreshold = 250; // application currentGraphicsMode = new GraphicsMode(new ColorFormat(8, 8, 8, 8), 24, 8, Interface.CurrentOptions.AntiAliasingLevel); if (Renderer.Screen.Width == 0 || Renderer.Screen.Height == 0) { //Duff values saved, so reset to something sensible else we crash Renderer.Screen.Width = 1024; Renderer.Screen.Height = 768; } Renderer.CameraTrackFollower = new TrackFollower(Program.CurrentHost); currentGameWindow = new RouteViewer(Renderer.Screen.Width, Renderer.Screen.Height, currentGraphicsMode, "Route Viewer", GameWindowFlags.Default); currentGameWindow.Visible = true; currentGameWindow.TargetUpdateFrequency = 0; currentGameWindow.TargetRenderFrequency = 0; currentGameWindow.Title = "Route Viewer"; processCommandLineArgs = true; currentGameWindow.Run(); //Unload Sounds.Deinitialize(); }
// apply notch internal static void ApplyNotch(Train Train, int PowerValue, bool PowerRelative, int BrakeValue, bool BrakeRelative) { // determine notch int p = PowerRelative ? PowerValue + Train.Specs.CurrentPowerNotch.Driver : PowerValue; if (p < 0) { p = 0; } else if (p > Train.Specs.MaximumPowerNotch) { p = Train.Specs.MaximumPowerNotch; } int b = BrakeRelative ? BrakeValue + Train.Specs.CurrentBrakeNotch.Driver : BrakeValue; if (b < 0) { b = 0; } else if (b > Train.Specs.MaximumBrakeNotch) { b = Train.Specs.MaximumBrakeNotch; } // power sound if (p < Train.Specs.CurrentPowerNotch.Driver) { if (p > 0) { // down (not min) Sounds.SoundBuffer buffer = Train.Cars[Train.DriverCar].Sounds.MasterControllerDown.Buffer; if (buffer != null) { OpenBveApi.Math.Vector3 pos = Train.Cars[Train.DriverCar].Sounds.MasterControllerDown.Position; Sounds.PlaySound(buffer, 1.0, 1.0, pos, Train, Train.DriverCar, false); } } else { // min Sounds.SoundBuffer buffer = Train.Cars[Train.DriverCar].Sounds.MasterControllerMin.Buffer; if (buffer != null) { OpenBveApi.Math.Vector3 pos = Train.Cars[Train.DriverCar].Sounds.MasterControllerMin.Position; Sounds.PlaySound(buffer, 1.0, 1.0, pos, Train, Train.DriverCar, false); } } } else if (p > Train.Specs.CurrentPowerNotch.Driver) { if (p < Train.Specs.MaximumPowerNotch) { // up (not max) Sounds.SoundBuffer buffer = Train.Cars[Train.DriverCar].Sounds.MasterControllerUp.Buffer; if (buffer != null) { OpenBveApi.Math.Vector3 pos = Train.Cars[Train.DriverCar].Sounds.MasterControllerUp.Position; Sounds.PlaySound(buffer, 1.0, 1.0, pos, Train, Train.DriverCar, false); } } else { // max Sounds.SoundBuffer buffer = Train.Cars[Train.DriverCar].Sounds.MasterControllerMax.Buffer; if (buffer != null) { OpenBveApi.Math.Vector3 pos = Train.Cars[Train.DriverCar].Sounds.MasterControllerMax.Position; Sounds.PlaySound(buffer, 1.0, 1.0, pos, Train, Train.DriverCar, false); } } } // brake sound if (b < Train.Specs.CurrentBrakeNotch.Driver) { // brake release Sounds.SoundBuffer buffer = Train.Cars[Train.DriverCar].Sounds.Brake.Buffer; if (buffer != null) { OpenBveApi.Math.Vector3 pos = Train.Cars[Train.DriverCar].Sounds.Brake.Position; Sounds.PlaySound(buffer, 1.0, 1.0, pos, Train, Train.DriverCar, false); } if (b > 0) { // brake release (not min) buffer = Train.Cars[Train.DriverCar].Sounds.BrakeHandleRelease.Buffer; if (buffer != null) { OpenBveApi.Math.Vector3 pos = Train.Cars[Train.DriverCar].Sounds.BrakeHandleRelease.Position; Sounds.PlaySound(buffer, 1.0, 1.0, pos, Train, Train.DriverCar, false); } } else { // brake min buffer = Train.Cars[Train.DriverCar].Sounds.BrakeHandleMin.Buffer; if (buffer != null) { OpenBveApi.Math.Vector3 pos = Train.Cars[Train.DriverCar].Sounds.BrakeHandleMin.Position; Sounds.PlaySound(buffer, 1.0, 1.0, pos, Train, Train.DriverCar, false); } } } else if (b > Train.Specs.CurrentBrakeNotch.Driver) { // brake Sounds.SoundBuffer buffer = Train.Cars[Train.DriverCar].Sounds.BrakeHandleApply.Buffer; if (buffer != null) { OpenBveApi.Math.Vector3 pos = Train.Cars[Train.DriverCar].Sounds.BrakeHandleApply.Position; Sounds.PlaySound(buffer, 1.0, 1.0, pos, Train, Train.DriverCar, false); } } // apply notch if (Train.Specs.SingleHandle) { if (b != 0) { p = 0; } } Train.Specs.CurrentPowerNotch.Driver = p; Train.Specs.CurrentBrakeNotch.Driver = b; Game.AddBlackBoxEntry(Game.BlackBoxEventToken.None); // plugin if (Train.Plugin != null) { Train.Plugin.UpdatePower(); Train.Plugin.UpdateBrake(); } }
internal override void Update(double TimeElapsed, bool ForceUpdate) { const double extraRadius = 10.0; double z = Object.TranslateZFunction == null ? 0.0 : Object.TranslateZFunction.LastResult; double pa = TrackPosition + z - Radius - extraRadius; double pb = TrackPosition + z + Radius + extraRadius; double ta = World.CameraTrackFollower.TrackPosition + World.CameraCurrentAlignment.Position.Z - World.BackgroundImageDistance - World.ExtraViewingDistance; double tb = World.CameraTrackFollower.TrackPosition + World.CameraCurrentAlignment.Position.Z + World.BackgroundImageDistance + World.ExtraViewingDistance; bool visible = pb >= ta & pa <= tb; if (visible | ForceUpdate) { if (Object.SecondsSinceLastUpdate >= Object.RefreshRate | ForceUpdate) { double timeDelta = Object.SecondsSinceLastUpdate + TimeElapsed; Object.SecondsSinceLastUpdate = 0.0; TrainManager.Train train = null; double trainDistance = double.MaxValue; for (int j = 0; j < TrainManager.Trains.Length; j++) { if (TrainManager.Trains[j].State == TrainManager.TrainState.Available) { double distance; if (TrainManager.Trains[j].Cars[0].FrontAxle.Follower.TrackPosition < TrackPosition) { distance = TrackPosition - TrainManager.Trains[j].Cars[0].FrontAxle.Follower.TrackPosition; } else if (TrainManager.Trains[j].Cars[TrainManager.Trains[j].Cars.Length - 1].RearAxle.Follower.TrackPosition > TrackPosition) { distance = TrainManager.Trains[j].Cars[TrainManager.Trains[j].Cars.Length - 1].RearAxle.Follower.TrackPosition - TrackPosition; } else { distance = 0; } if (distance < trainDistance) { train = TrainManager.Trains[j]; trainDistance = distance; } } } Object.Update(false, train, train == null ? 0 : train.DriverCar, SectionIndex, TrackPosition, Position, Direction, Up, Side, false, true, true, timeDelta, true); if (this.Object.CurrentState != this.lastState && Loading.SimulationSetup) { if (this.SingleBuffer && this.Buffers[0] != null) { switch (this.Object.CurrentState) { case -1: if (this.PlayOnHide) { this.Source = Sounds.PlaySound(this.Buffers[0], this.currentPitch, this.currentVolume, this.Position, false); } break; case 0: if (this.PlayOnShow || this.lastState != -1) { this.Source = Sounds.PlaySound(this.Buffers[0], this.currentPitch, this.currentVolume, this.Position, false); } break; default: this.Source = Sounds.PlaySound(this.Buffers[0], this.currentPitch, this.currentVolume, this.Position, false); break; } } else { int bufferIndex = this.Object.CurrentState + 1; if (bufferIndex < this.Buffers.Length && this.Buffers[bufferIndex] != null) { switch (bufferIndex) { case 0: if (this.PlayOnHide) { this.Source = Sounds.PlaySound(this.Buffers[bufferIndex], this.currentPitch, this.currentVolume, this.Position, false); } break; case 1: if (this.PlayOnShow || this.lastState != -1) { this.Source = Sounds.PlaySound(this.Buffers[bufferIndex], this.currentPitch, this.currentVolume, this.Position, false); } break; default: this.Source = Sounds.PlaySound(this.Buffers[bufferIndex], this.currentPitch, this.currentVolume, this.Position, false); break; } } } } } else { Object.SecondsSinceLastUpdate += TimeElapsed; } if (!Visible) { Renderer.ShowObject(Object.ObjectIndex, Renderer.ObjectType.Dynamic); Visible = true; } } else { Object.SecondsSinceLastUpdate += TimeElapsed; if (Visible) { Renderer.HideObject(Object.ObjectIndex); Visible = false; } } this.lastState = this.Object.CurrentState; }
/// <param name="SoundBuffer">HACK: Set to a null reference to indicate the train point sound.</param> internal SoundEvent(double TrackPositionDelta, Sounds.SoundBuffer SoundBuffer, bool PlayerTrainOnly, bool Once, bool Dynamic, Vector3 Position, double Speed) { this.TrackPositionDelta = TrackPositionDelta; this.DontTriggerAnymore = false; this.SoundBuffer = SoundBuffer; this.PlayerTrainOnly = PlayerTrainOnly; this.Once = Once; this.Dynamic = Dynamic; this.Position = Position; this.Speed = Speed; }
/// <summary>Applies a power and / or brake notch to this train</summary> /// <param name="PowerValue">The power notch value</param> /// <param name="PowerRelative">Whether this is relative to the current notch</param> /// <param name="BrakeValue">The brake notch value</param> /// <param name="BrakeRelative">Whether this is relative to the current notch</param> /// <param name="IsOverMaxDriverNotch"></param> internal void ApplyNotch(int PowerValue, bool PowerRelative, int BrakeValue, bool BrakeRelative, bool IsOverMaxDriverNotch = false) { // determine notch int p = PowerRelative ? PowerValue + Handles.Power.Driver : PowerValue; if (p < 0) { p = 0; } else if (p > Handles.Power.MaximumNotch) { p = Handles.Power.MaximumNotch; } if (!IsOverMaxDriverNotch && p > Handles.Power.MaximumDriverNotch) { p = Handles.Power.MaximumDriverNotch; } int b = BrakeRelative ? BrakeValue + Handles.Brake.Driver : BrakeValue; if (b < 0) { b = 0; } else if (b > Handles.Brake.MaximumNotch) { b = Handles.Brake.MaximumNotch; } if (!IsOverMaxDriverNotch && b > Handles.Brake.MaximumDriverNotch) { b = Handles.Brake.MaximumDriverNotch; } // power sound if (p < Handles.Power.Driver) { if (p > 0) { // down (not min) Sounds.SoundBuffer buffer; if ((Handles.Power.Driver - p > 2 | Cars[DriverCar].Sounds.PowerHandleFast) && Cars[DriverCar].Sounds.MasterControllerDownFast.Buffer != null) { buffer = Cars[DriverCar].Sounds.MasterControllerDownFast.Buffer; } else { buffer = Cars[DriverCar].Sounds.MasterControllerDown.Buffer; } if (buffer != null) { Vector3 pos = Cars[DriverCar].Sounds.MasterControllerDown.Position; Sounds.PlaySound(buffer, 1.0, 1.0, pos, this, DriverCar, false); } } else { // min Sounds.SoundBuffer buffer = Cars[DriverCar].Sounds.MasterControllerMin.Buffer; if (buffer != null) { Vector3 pos = Cars[DriverCar].Sounds.MasterControllerMin.Position; Sounds.PlaySound(buffer, 1.0, 1.0, pos, this, DriverCar, false); } } } else if (p > Handles.Power.Driver) { if (p < Handles.Power.MaximumDriverNotch) { // up (not max) Sounds.SoundBuffer buffer; if ((Handles.Power.Driver - p > 2 | Cars[DriverCar].Sounds.PowerHandleFast) && Cars[DriverCar].Sounds.MasterControllerUpFast.Buffer != null) { buffer = Cars[DriverCar].Sounds.MasterControllerUpFast.Buffer; } else { buffer = Cars[DriverCar].Sounds.MasterControllerUp.Buffer; } if (buffer != null) { Vector3 pos = Cars[DriverCar].Sounds.MasterControllerUp.Position; Sounds.PlaySound(buffer, 1.0, 1.0, pos, this, DriverCar, false); } } else { // max Sounds.SoundBuffer buffer = Cars[DriverCar].Sounds.MasterControllerMax.Buffer; if (buffer != null) { Vector3 pos = Cars[DriverCar].Sounds.MasterControllerMax.Position; Sounds.PlaySound(buffer, 1.0, 1.0, pos, this, DriverCar, false); } } } // brake sound if (b < Handles.Brake.Driver) { // brake release Sounds.SoundBuffer buffer = Cars[DriverCar].Sounds.Brake.Buffer; if (buffer != null) { Vector3 pos = Cars[DriverCar].Sounds.Brake.Position; Sounds.PlaySound(buffer, 1.0, 1.0, pos, this, DriverCar, false); } if (b > 0) { // brake release (not min) if ((Handles.Brake.Driver - b > 2 | Cars[DriverCar].Sounds.BrakeHandleFast) && Cars[DriverCar].Sounds.BrakeHandleReleaseFast.Buffer != null) { buffer = Cars[DriverCar].Sounds.BrakeHandleReleaseFast.Buffer; } else { buffer = Cars[DriverCar].Sounds.BrakeHandleRelease.Buffer; } if (buffer != null) { Vector3 pos = Cars[DriverCar].Sounds.BrakeHandleRelease.Position; Sounds.PlaySound(buffer, 1.0, 1.0, pos, this, DriverCar, false); } } else { // brake min buffer = Cars[DriverCar].Sounds.BrakeHandleMin.Buffer; if (buffer != null) { Vector3 pos = Cars[DriverCar].Sounds.BrakeHandleMin.Position; Sounds.PlaySound(buffer, 1.0, 1.0, pos, this, DriverCar, false); } } } else if (b > Handles.Brake.Driver) { // brake Sounds.SoundBuffer buffer; if ((b - Handles.Brake.Driver > 2 | Cars[DriverCar].Sounds.BrakeHandleFast) && Cars[DriverCar].Sounds.BrakeHandleApplyFast.Buffer != null) { buffer = Cars[DriverCar].Sounds.BrakeHandleApplyFast.Buffer; } else { buffer = Cars[DriverCar].Sounds.BrakeHandleApply.Buffer; } if (buffer != null) { Vector3 pos = Cars[DriverCar].Sounds.BrakeHandleApply.Position; Sounds.PlaySound(buffer, 1.0, 1.0, pos, this, DriverCar, false); } } // apply notch if (Handles.SingleHandle) { if (b != 0) { p = 0; } } Handles.Power.Driver = p; Handles.Brake.Driver = b; Game.AddBlackBoxEntry(Game.BlackBoxEventToken.None); // plugin if (Plugin != null) { Plugin.UpdatePower(); Plugin.UpdateBrake(); } }
private CarSound(Sounds.SoundBuffer buffer, Sounds.SoundSource source, Vector3 position) { this.Buffer = buffer; this.Source = source; this.Position = position; }
//This renders the frame protected override void OnRenderFrame(FrameEventArgs e) { if (!firstFrame) { //If the load is not complete, then we shouldn't be running the mainloop return; } double TimeElapsed = RenderTimeElapsed; double RealTimeElapsed = RenderRealTimeElapsed; //Next, check if we're in paused/ in a menu if (Game.CurrentInterface != Game.InterfaceType.Normal) { MainLoop.UpdateControlRepeats(0.0); MainLoop.ProcessKeyboard(); MainLoop.ProcessControls(0.0); if (Game.CurrentInterface == Game.InterfaceType.Pause) { System.Threading.Thread.Sleep(10); } //Renderer.UpdateLighting(); Renderer.RenderScene(TimeElapsed); Program.currentGameWindow.SwapBuffers(); if (MainLoop.Quit != MainLoop.QuitMode.ContinueGame) { Close(); if (Program.CurrentlyRunningOnMono && MainLoop.Quit == MainLoop.QuitMode.QuitProgram) { Environment.Exit(0); } } //If the menu state has not changed, don't update the rendered simulation return; } //Use the OpenTK framerate as this is much more accurate //Also avoids running a calculation if (TotalTimeElapsedForInfo >= 0.2) { Game.InfoFrameRate = RenderFrequency; TotalTimeElapsedForInfo = 0.0; } if (Game.PreviousInterface != Game.InterfaceType.Normal) { ObjectManager.UpdateAnimatedWorldObjects(0.0, false); Game.PreviousInterface = Game.InterfaceType.Normal; } else { ObjectManager.UpdateAnimatedWorldObjects(TimeElapsed, false); } //We need to update the camera position in the render sequence //Not doing this means that the camera doesn't move // update in one piece if (World.CameraMode == CameraViewMode.Interior | World.CameraMode == CameraViewMode.InteriorLookAhead) { //Update the in-car camera based upon the current driver car (Cabview or passenger view) TrainManager.PlayerTrain.Cars[World.CameraCar].UpdateCamera(); } else if (World.CameraMode == CameraViewMode.Exterior) { //Update the camera position based upon the relative car position TrainManager.PlayerTrain.Cars[World.CameraCar].UpdateCamera(); } if (World.CameraRestriction == Camera.RestrictionMode.NotAvailable) { World.CurrentDriverBody.Update(TimeElapsed); } //Check if we are running at an accelerated time factor- //Camera motion speed should be the same whatever the game speed is if (TimeFactor != 1) { World.UpdateAbsoluteCamera(TimeElapsed / TimeFactor); } else { World.UpdateAbsoluteCamera(TimeElapsed); } TrainManager.UpdateTrainObjects(TimeElapsed, false); if (World.CameraMode == CameraViewMode.Interior | World.CameraMode == CameraViewMode.InteriorLookAhead | World.CameraMode == CameraViewMode.Exterior) { ObjectManager.UpdateVisibility(World.CameraTrackFollower.TrackPosition + World.CameraCurrentAlignment.Position.Z); int d = TrainManager.PlayerTrain.DriverCar; World.CameraSpeed = TrainManager.PlayerTrain.Cars[d].Specs.CurrentSpeed; } else { World.CameraSpeed = 0.0; } World.CameraAlignmentDirection = new World.CameraAlignment(); if (MainLoop.Quit != MainLoop.QuitMode.ContinueGame) { Program.currentGameWindow.Exit(); if (Program.CurrentlyRunningOnMono && MainLoop.Quit == MainLoop.QuitMode.QuitProgram) { Environment.Exit(0); } } Renderer.UpdateLighting(); Renderer.RenderScene(TimeElapsed); if (Renderer.DebugTouchMode) { Renderer.DebugTouchArea(); } Sounds.Update(TimeElapsed, Interface.CurrentOptions.SoundModel); Program.currentGameWindow.SwapBuffers(); Game.UpdateBlackBox(); // pause/menu // limit framerate if (MainLoop.LimitFramerate) { System.Threading.Thread.Sleep(10); } MainLoop.UpdateControlRepeats(RealTimeElapsed); MainLoop.ProcessKeyboard(); World.UpdateMouseGrab(TimeElapsed); MainLoop.ProcessControls(TimeElapsed); for (int i = 0; i < JoystickManager.AttachedJoysticks.Length; i++) { var railDriver = JoystickManager.AttachedJoysticks[i] as JoystickManager.Raildriver; if (railDriver != null) { if (Interface.CurrentOptions.RailDriverMPH) { railDriver.SetDisplay((int)(TrainManager.PlayerTrain.Cars[TrainManager.PlayerTrain.DriverCar].Specs .CurrentPerceivedSpeed * 2.23694)); } else { railDriver.SetDisplay((int)(TrainManager.PlayerTrain.Cars[TrainManager.PlayerTrain.DriverCar].Specs .CurrentPerceivedSpeed * 3.6)); } } } RenderRealTimeElapsed = 0.0; RenderTimeElapsed = 0.0; #if DEBUG MainLoop.CheckForOpenGlError("MainLoop"); #endif if (Interface.CurrentOptions.UnloadUnusedTextures) { Renderer.UnloadUnusedTextures(TimeElapsed); Renderer.LastBoundTexture = null; } // finish try { Interface.SaveLogs(); } catch { } }