From 429fa80cfc3543b6913a1bda3b0ea34cc02b7078 Mon Sep 17 00:00:00 2001 From: Christopher Lees Date: Thu, 17 Aug 2023 12:06:16 +0100 Subject: [PATCH 1/6] New: Allow uncoupling of cars --- assets/Languages/en-US.xlf | 12 ++++ source/ObjectViewer/Trains/NearestTrain.cs | 4 -- source/OpenBVE/System/Host.cs | 30 ++++++++++ .../System/Input/ProcessControls.Digital.cs | 39 +++++++++++++ .../Interface/Input/Commands.CommandInfo.cs | 2 + source/OpenBveApi/Interface/Input/Commands.cs | 6 +- .../AnimatedWorldObject.StateSound.cs | 2 +- source/OpenBveApi/System/Hosts.cs | 8 +++ source/OpenBveApi/Train/AbstractCar.cs | 6 ++ .../Train.OpenBve/Train/BVE/TrainDatParser.cs | 2 - source/RouteViewer/TrainManagerR.cs | 2 - .../Simulation/TrainManager/Car/Car.cs | 2 - source/TrainManager/Car/CarBase.cs | 55 ++++++++++++++++++- source/TrainManager/Train/TrainBase.cs | 5 +- 14 files changed, 160 insertions(+), 15 deletions(-) diff --git a/assets/Languages/en-US.xlf b/assets/Languages/en-US.xlf index d93f69b1d2..6049d36fe6 100755 --- a/assets/Languages/en-US.xlf +++ b/assets/Languages/en-US.xlf @@ -1579,6 +1579,18 @@ Mouse grab: off + + Please switch to exterior view to uncouple. + + + Unable to uncouple this car. + + + Uncoupling the rear of car number + + + Uncoupling the rear of car number + diff --git a/source/ObjectViewer/Trains/NearestTrain.cs b/source/ObjectViewer/Trains/NearestTrain.cs index 909a580fd1..ae16bdd36a 100644 --- a/source/ObjectViewer/Trains/NearestTrain.cs +++ b/source/ObjectViewer/Trains/NearestTrain.cs @@ -45,8 +45,6 @@ static NearestTrain() private static TrainBase CreateDummyTrain() { TrainBase train = new TrainBase(TrainState.Available); - - train.Handles.Reverser = new ReverserHandle(train); train.Handles.Power = new PowerHandle(Specs.PowerNotches, Specs.PowerNotches, new double[] { }, new double[] { }, train); if (Specs.IsAirBrake) { @@ -57,7 +55,6 @@ private static TrainBase CreateDummyTrain() train.Handles.Brake = new BrakeHandle(Specs.BrakeNotches, Specs.BrakeNotches, null, new double[] { }, new double[] { }, train); train.Handles.HasHoldBrake = Specs.HasHoldBrake; } - train.Handles.EmergencyBrake = new EmergencyHandle(train); train.Handles.HoldBrake = new HoldBrakeHandle(train); train.Specs.HasConstSpeed = Specs.HasConstSpeed; @@ -65,7 +62,6 @@ private static TrainBase CreateDummyTrain() for (int i = 0; i < train.Cars.Length; i++) { train.Cars[i] = new CarBase(train, i); - train.Cars[i].Specs = new CarPhysics(); if (Specs.IsAirBrake) { diff --git a/source/OpenBVE/System/Host.cs b/source/OpenBVE/System/Host.cs index 77d37a5103..a698a29ffc 100644 --- a/source/OpenBVE/System/Host.cs +++ b/source/OpenBVE/System/Host.cs @@ -576,6 +576,36 @@ public override AbstractTrain[] Trains } } + public override void AddTrain(AbstractTrain PreceedingTrain, AbstractTrain NewTrain) + { + Array.Resize(ref Program.TrainManager.Trains, Program.TrainManager.Trains.Length + 1); + int trainIndex = -1; + // find index of train within trainmanager array + for (int i = 0; i < Program.TrainManager.Trains.Length; i++) + { + if (Program.TrainManager.Trains[i] == PreceedingTrain) + { + trainIndex = i; + break; + } + } + + if (trainIndex == -1) + { + Program.TrainManager.Trains[Program.TrainManager.Trains.Length - 1] = (TrainBase)NewTrain; + } + else + { + for (int i = Program.TrainManager.Trains.Length - 1; i > trainIndex + 1; i--) + { + Program.TrainManager.Trains[i + 1] = Program.TrainManager.Trains[i]; + } + + Program.TrainManager.Trains[trainIndex + 1] = (TrainBase)NewTrain; + } + + } + public override AbstractTrain ClosestTrain(AbstractTrain Train) { TrainBase baseTrain = Train as TrainBase; diff --git a/source/OpenBVE/System/Input/ProcessControls.Digital.cs b/source/OpenBVE/System/Input/ProcessControls.Digital.cs index 4266f68943..e7a2581bf2 100644 --- a/source/OpenBVE/System/Input/ProcessControls.Digital.cs +++ b/source/OpenBVE/System/Input/ProcessControls.Digital.cs @@ -990,6 +990,45 @@ private static void ProcessDigitalControl(double TimeElapsed, ref Control Contro } } + break; + case Translations.Command.UncoupleFront: + if (Program.Renderer.Camera.CurrentMode != CameraViewMode.Exterior) + { + MessageManager.AddMessage( + Translations.GetInterfaceString("notification_switchexterior_uncouple"), + MessageDependency.None, GameMode.Expert, + MessageColor.White, Program.CurrentRoute.SecondsSinceMidnight + 5.0, null); + return; + } + + if (TrainManager.PlayerTrain.CameraCar == 0) + { + MessageManager.AddMessage( + Translations.GetInterfaceString("notification_unable_uncouple"), + MessageDependency.None, GameMode.Expert, + MessageColor.White, Program.CurrentRoute.SecondsSinceMidnight + 5.0, null); + return; + } + MessageManager.AddMessage( + Translations.GetInterfaceString("notification_exterior_uncouplefront") + " " +TrainManager.PlayerTrain.CameraCar, + MessageDependency.None, GameMode.Expert, + MessageColor.White, Program.CurrentRoute.SecondsSinceMidnight + 5.0, null); + TrainManager.PlayerTrain.Cars[TrainManager.PlayerTrain.CameraCar].Uncouple(true, false); + break; + case Translations.Command.UncoupleRear: + if (Program.Renderer.Camera.CurrentMode != CameraViewMode.Exterior) + { + MessageManager.AddMessage( + Translations.GetInterfaceString("notification_switchexterior_uncouple"), + MessageDependency.None, GameMode.Expert, + MessageColor.White, Program.CurrentRoute.SecondsSinceMidnight + 5.0, null); + return; + } + MessageManager.AddMessage( + Translations.GetInterfaceString("notification_exterior_uncouplerear") + " " + TrainManager.PlayerTrain.CameraCar, + MessageDependency.None, GameMode.Expert, + MessageColor.White, Program.CurrentRoute.SecondsSinceMidnight + 5.0, null); + TrainManager.PlayerTrain.Cars[TrainManager.PlayerTrain.CameraCar].Uncouple(false, true); break; case Translations.Command.TimetableToggle: // option: timetable diff --git a/source/OpenBveApi/Interface/Input/Commands.CommandInfo.cs b/source/OpenBveApi/Interface/Input/Commands.CommandInfo.cs index a7740c4897..d20db3d6ef 100644 --- a/source/OpenBveApi/Interface/Input/Commands.CommandInfo.cs +++ b/source/OpenBveApi/Interface/Input/Commands.CommandInfo.cs @@ -156,6 +156,8 @@ public static CommandInfo TryGetInfo(this CommandInfo[] commandInfos, Command Va new CommandInfo(Command.DeviceConstSpeed, CommandType.Digital, "DEVICE_CONSTSPEED"), new CommandInfo(Command.PlayMicSounds, CommandType.Digital, "PLAY_MIC_SOUNDS"), new CommandInfo(Command.Sanders, CommandType.Digital, "SANDERS"), + new CommandInfo(Command.UncoupleFront, CommandType.Digital, "UNCOUPLE_FRONT"), + new CommandInfo(Command.UncoupleRear, CommandType.Digital, "UNCOUPLE_REAR"), //We only want to mark these as obsolete for new users of the API #pragma warning disable 618 diff --git a/source/OpenBveApi/Interface/Input/Commands.cs b/source/OpenBveApi/Interface/Input/Commands.cs index 93028af92c..43180e230a 100644 --- a/source/OpenBveApi/Interface/Input/Commands.cs +++ b/source/OpenBveApi/Interface/Input/Commands.cs @@ -307,7 +307,11 @@ public enum Command * Added in 1.8.4.3 */ /// Toggles the sanders if fitted - Sanders + Sanders, + /// Uncouples the front coupling of a car + UncoupleFront, + /// Uncouples the rear coupling of a car + UncoupleRear } /// Defines the possible command types diff --git a/source/OpenBveApi/Objects/ObjectTypes/AnimatedWorldObject.StateSound.cs b/source/OpenBveApi/Objects/ObjectTypes/AnimatedWorldObject.StateSound.cs index 9fda553bb0..41bc47964c 100644 --- a/source/OpenBveApi/Objects/ObjectTypes/AnimatedWorldObject.StateSound.cs +++ b/source/OpenBveApi/Objects/ObjectTypes/AnimatedWorldObject.StateSound.cs @@ -47,7 +47,7 @@ public override void Update(AbstractTrain NearestTrain, double TimeElapsed, bool { double timeDelta = Object.SecondsSinceLastUpdate + TimeElapsed; Object.SecondsSinceLastUpdate = 0.0; - Object.Update(NearestTrain, NearestTrain == null ? 0 : NearestTrain.DriverCar, TrackPosition, Position, Direction, Up, Side, true, true, timeDelta, true); + Object.Update(NearestTrain, NearestTrain?.DriverCar ?? 0, TrackPosition, Position, Direction, Up, Side, true, true, timeDelta, true); if (this.Object.CurrentState != this.lastState && currentHost.SimulationState != SimulationState.Loading) { if (SingleBuffer) diff --git a/source/OpenBveApi/System/Hosts.cs b/source/OpenBveApi/System/Hosts.cs index a588a58bfd..9e8ef88df0 100644 --- a/source/OpenBveApi/System/Hosts.cs +++ b/source/OpenBveApi/System/Hosts.cs @@ -704,6 +704,14 @@ public virtual AbstractTrain ClosestTrain(double TrackPosition) return null; } + /// Adds a new train + /// The preceeding train, or a null reference to add the train at the end of the queue + /// The new train + public virtual void AddTrain(AbstractTrain PreceedingTrain, AbstractTrain NewTrain) + { + + } + /* * Used for interop with the 32-bit plugin host */ diff --git a/source/OpenBveApi/Train/AbstractCar.cs b/source/OpenBveApi/Train/AbstractCar.cs index 6c443fbcc8..60b1608710 100644 --- a/source/OpenBveApi/Train/AbstractCar.cs +++ b/source/OpenBveApi/Train/AbstractCar.cs @@ -85,5 +85,11 @@ public virtual void OpenDoors(bool Left, bool Right) { } + + /// Uncouples the car + public virtual void Uncouple(bool Front, bool Rear) + { + + } } } diff --git a/source/Plugins/Train.OpenBve/Train/BVE/TrainDatParser.cs b/source/Plugins/Train.OpenBve/Train/BVE/TrainDatParser.cs index b4ce2ea677..cee04714b8 100644 --- a/source/Plugins/Train.OpenBve/Train/BVE/TrainDatParser.cs +++ b/source/Plugins/Train.OpenBve/Train/BVE/TrainDatParser.cs @@ -230,7 +230,6 @@ internal void Parse(string FileName, Encoding Encoding, TrainBase Train) { double DoorTolerance = 0.0; ReadhesionDeviceType ReAdhesionDevice = ReadhesionDeviceType.TypeA; PassAlarmType passAlarm = PassAlarmType.None; - Train.Handles.EmergencyBrake = new EmergencyHandle(Train); Train.Handles.HasLocoBrake = false; double[] powerDelayUp = { }, powerDelayDown = { }, brakeDelayUp = { }, brakeDelayDown = { }, locoBrakeDelayUp = { }, locoBrakeDelayDown = { }; double electricBrakeDelayUp = 0, electricBrakeDelayDown = 0; @@ -1027,7 +1026,6 @@ internal void Parse(string FileName, Encoding Encoding, TrainBase Train) { } driverBrakeNotches = brakeNotches; } - Train.Handles.Reverser = new ReverserHandle(Train); Train.Handles.Power = new PowerHandle(powerNotches, driverPowerNotches, powerDelayUp, powerDelayDown, Train); if (powerReduceSteps != -1) { diff --git a/source/RouteViewer/TrainManagerR.cs b/source/RouteViewer/TrainManagerR.cs index 9f358a7d18..edff5eb5f9 100644 --- a/source/RouteViewer/TrainManagerR.cs +++ b/source/RouteViewer/TrainManagerR.cs @@ -26,8 +26,6 @@ public TrainManager(HostInterface host, BaseRenderer renderer, BaseOptions optio internal class Train : TrainBase { internal Train() : base(TrainState.Pending) { - Handles.Reverser = new ReverserHandle(this); - Handles.EmergencyBrake = new EmergencyHandle(this); Handles.Power = new PowerHandle(8, 8, new double[] {}, new double[] {}, this); Handles.Brake = new BrakeHandle(8, 8, null, new double[] {}, new double[] {}, this); Handles.HoldBrake = new HoldBrakeHandle(this); diff --git a/source/TrainEditor2/Simulation/TrainManager/Car/Car.cs b/source/TrainEditor2/Simulation/TrainManager/Car/Car.cs index a4fd64f356..1de9016b0f 100644 --- a/source/TrainEditor2/Simulation/TrainManager/Car/Car.cs +++ b/source/TrainEditor2/Simulation/TrainManager/Car/Car.cs @@ -2,7 +2,6 @@ using System.Collections.Generic; using System.Linq; using OpenBveApi.Math; -using OpenBveApi.Trains; using SoundManager; using TrainEditor2.Models.Sounds; using TrainManager.Car; @@ -20,7 +19,6 @@ internal class Car : CarBase public Car() : base(null, 0) { Sounds = new CarSounds(); - Specs = new CarPhysics(); Specs.IsMotorCar = true; } diff --git a/source/TrainManager/Car/CarBase.cs b/source/TrainManager/Car/CarBase.cs index 48679f5924..69e903e023 100644 --- a/source/TrainManager/Car/CarBase.cs +++ b/source/TrainManager/Car/CarBase.cs @@ -15,6 +15,7 @@ using TrainManager.BrakeSystems; using TrainManager.Car.Systems; using TrainManager.Cargo; +using TrainManager.Handles; using TrainManager.Power; using TrainManager.Trains; @@ -36,7 +37,7 @@ public class CarBase : AbstractCar /// The horns attached to this car public Horn[] Horns; /// Contains the physics properties for the car - public CarPhysics Specs; + public readonly CarPhysics Specs; /// The car brake for this car public CarBrake CarBrake; /// The car sections (objects) attached to the car @@ -134,6 +135,7 @@ public CarBase(TrainBase train, int index) }; Brightness = new Brightness(this); Cargo = new Passengers(this); + Specs = new CarPhysics(); } /// Moves the car @@ -347,6 +349,57 @@ public override void OpenDoors(bool Left, bool Right) } } + public override void Uncouple(bool Front, bool Rear) + { + if (!Front && !Rear) + { + return; + } + if (Front) + { + Uncouple(false, true); + } + // Create new train + TrainBase newTrain = new TrainBase(TrainState.Available); + newTrain.Handles.Power = new PowerHandle(0, 0, new double[0], new double[0], newTrain) + { + DelayedChanges = new HandleChange[0] + }; + newTrain.Handles.Brake = new BrakeHandle(0, 0, newTrain.Handles.EmergencyBrake, new double[0], new double[0], newTrain) + { + DelayedChanges = new HandleChange[0] + }; + newTrain.Handles.HoldBrake = new HoldBrakeHandle(newTrain); + if (Rear) + { + int totalFollowingCars = baseTrain.Cars.Length - (Index + 1); + newTrain.Cars = new CarBase[totalFollowingCars]; + if (totalFollowingCars > 0) + { + // Move following cars to new train + for (int i = 0; i < totalFollowingCars; i++) + { + newTrain.Cars[i] = baseTrain.Cars[Index + i + 1]; + newTrain.Cars[i].baseTrain = newTrain; + /* + * Make visible if not part of player train + * Otherwise uncoupling from cab then changing to exterior, they will still be hidden + */ + newTrain.Cars[i].ChangeCarSection(CarSectionType.Exterior); + newTrain.Cars[i].FrontBogie.ChangeSection(0); + newTrain.Cars[i].RearBogie.ChangeSection(0); + } + Array.Resize(ref baseTrain.Cars, baseTrain.Cars.Length - totalFollowingCars); + baseTrain.Cars[baseTrain.Cars.Length - 1].Coupler.connectedCar = baseTrain.Cars[baseTrain.Cars.Length - 1]; + } + else + { + return; + } + } + TrainManagerBase.currentHost.AddTrain(baseTrain, newTrain); + } + /// Returns the combination of door states what encountered at the specified car in a train. /// Whether to include left doors. /// Whether to include right doors. diff --git a/source/TrainManager/Train/TrainBase.cs b/source/TrainManager/Train/TrainBase.cs index 30c5e020f8..bce8ab3547 100644 --- a/source/TrainManager/Train/TrainBase.cs +++ b/source/TrainManager/Train/TrainBase.cs @@ -110,6 +110,8 @@ public TrainBase(TrainState state) Specs.DoorOpenMode = DoorMode.AutomaticManualOverride; Specs.DoorCloseMode = DoorMode.AutomaticManualOverride; DriverBody = new DriverBody(this); + Handles.Reverser = new ReverserHandle(this); + Handles.EmergencyBrake = new EmergencyHandle(this); } /// Called once when the simulation loads to initalize the train @@ -514,8 +516,7 @@ private void UpdatePhysicsAndControls(double TimeElapsed) { breaker = Handles.Reverser.Actual != 0 & Handles.Power.Safety >= 1 & Handles.Brake.Safety == 0 & !Handles.EmergencyBrake.Safety & !Handles.HoldBrake.Actual; } - - Cars[DriverCar].Breaker.Update(breaker); + Cars[DriverCar].Breaker?.Update(breaker); } // signals if (CurrentSectionLimit == 0.0) From e870f0e2b374fa70c20b3f8d1d1cbf7997de9a5d Mon Sep 17 00:00:00 2001 From: Christopher Lees Date: Thu, 17 Aug 2023 14:44:12 +0100 Subject: [PATCH 2/6] Fix animated functions using the car index and bogies --- source/OpenBveApi/Train/AbstractCar.cs | 5 +++++ source/TrainManager/Car/Bogie/Bogie.cs | 16 +++++----------- source/TrainManager/Car/CarBase.cs | 23 ++++++++++++++++------- 3 files changed, 26 insertions(+), 18 deletions(-) diff --git a/source/OpenBveApi/Train/AbstractCar.cs b/source/OpenBveApi/Train/AbstractCar.cs index 60b1608710..412e0e27b7 100644 --- a/source/OpenBveApi/Train/AbstractCar.cs +++ b/source/OpenBveApi/Train/AbstractCar.cs @@ -1,3 +1,4 @@ +using System; using OpenBveApi.Math; namespace OpenBveApi.Trains @@ -72,6 +73,10 @@ public virtual int Index // A single car is by itself a train, hence index zero return 0; } + set + { + throw new NotSupportedException("Cannot set the index of a single car"); + } } /// Call this method to reverse (flip) the car diff --git a/source/TrainManager/Car/Bogie/Bogie.cs b/source/TrainManager/Car/Bogie/Bogie.cs index 8cf3c51b0f..ce0ad88747 100644 --- a/source/TrainManager/Car/Bogie/Bogie.cs +++ b/source/TrainManager/Car/Bogie/Bogie.cs @@ -39,20 +39,14 @@ public class Bogie /// Whether the bogie is the rear bogie private readonly bool Rear; - - /// Holds a reference to the base train - // We don't want this to be read-only if we ever manage to uncouple cars... - // ReSharper disable once FieldCanBeMadeReadOnly.Local - private AbstractTrain baseTrain; - - public Bogie(AbstractTrain train, CarBase car, bool IsRear) + + public Bogie(CarBase car, bool IsRear) { - baseTrain = train; baseCar = car; Rear = IsRear; CarSections = new CarSection[] { }; - FrontAxle = new Axle(TrainManagerBase.currentHost, train, car); - RearAxle = new Axle(TrainManagerBase.currentHost, train, car); + FrontAxle = new Axle(TrainManagerBase.currentHost, car.baseTrain, car); + RearAxle = new Axle(TrainManagerBase.currentHost, car.baseTrain, car); } public void UpdateObjects(double TimeElapsed, bool ForceUpdate) @@ -200,7 +194,7 @@ private void UpdateSectionElement(int SectionIndex, int ElementIndex, Vector3 Po updatefunctions = true; } - CarSections[SectionIndex].Groups[0].Elements[ElementIndex].Update(baseTrain, baseCar.Index, FrontAxle.Follower.TrackPosition - FrontAxle.Position, p, Direction, Up, Side, updatefunctions, Show, timeDelta, true); + CarSections[SectionIndex].Groups[0].Elements[ElementIndex].Update(baseCar.baseTrain, baseCar.Index, FrontAxle.Follower.TrackPosition - FrontAxle.Position, p, Direction, Up, Side, updatefunctions, Show, timeDelta, true); } } diff --git a/source/TrainManager/Car/CarBase.cs b/source/TrainManager/Car/CarBase.cs index 69e903e023..6c88f5d6c2 100644 --- a/source/TrainManager/Car/CarBase.cs +++ b/source/TrainManager/Car/CarBase.cs @@ -87,20 +87,22 @@ public class CarBase : AbstractCar /// The cargo carried by the car public CargoBase Cargo; + private int trainCarIndex; + public CarBase(TrainBase train, int index, double CoefficientOfFriction, double CoefficientOfRollingResistance, double AerodynamicDragCoefficient) { Specs = new CarPhysics(); Brightness = new Brightness(this); baseTrain = train; - Index = index; + trainCarIndex = index; CarSections = new CarSection[] { }; FrontAxle = new Axle(TrainManagerBase.currentHost, train, this, CoefficientOfFriction, CoefficientOfRollingResistance, AerodynamicDragCoefficient); FrontAxle.Follower.TriggerType = index == 0 ? EventTriggerType.FrontCarFrontAxle : EventTriggerType.OtherCarFrontAxle; RearAxle = new Axle(TrainManagerBase.currentHost, train, this, CoefficientOfFriction, CoefficientOfRollingResistance, AerodynamicDragCoefficient); RearAxle.Follower.TriggerType = index == baseTrain.Cars.Length - 1 ? EventTriggerType.RearCarRearAxle : EventTriggerType.OtherCarRearAxle; BeaconReceiver = new TrackFollower(TrainManagerBase.currentHost, train); - FrontBogie = new Bogie(train, this, false); - RearBogie = new Bogie(train, this, true); + FrontBogie = new Bogie(this, false); + RearBogie = new Bogie(this, true); Doors = new Door[2]; Horns = new[] { @@ -119,13 +121,13 @@ public CarBase(TrainBase train, int index, double CoefficientOfFriction, double public CarBase(TrainBase train, int index) { baseTrain = train; - Index = index; + trainCarIndex = index; CarSections = new CarSection[] { }; FrontAxle = new Axle(TrainManagerBase.currentHost, train, this); RearAxle = new Axle(TrainManagerBase.currentHost, train, this); BeaconReceiver = new TrackFollower(TrainManagerBase.currentHost, train); - FrontBogie = new Bogie(train, this, false); - RearBogie = new Bogie(train, this, true); + FrontBogie = new Bogie(this, false); + RearBogie = new Bogie(this, true); Doors = new Door[2]; Horns = new[] { @@ -241,7 +243,8 @@ public override void CreateWorldCoordinates(Vector3 Car, out Vector3 Position, o /// Backing property for the index of the car within the train public override int Index { - get; + get => trainCarIndex; + set => trainCarIndex = value; } public override void Reverse(bool flipInterior = false) @@ -381,9 +384,15 @@ public override void Uncouple(bool Front, bool Rear) { newTrain.Cars[i] = baseTrain.Cars[Index + i + 1]; newTrain.Cars[i].baseTrain = newTrain; + newTrain.Cars[i].Index = i; + } + for (int i = 0; i < newTrain.Cars.Length; i++) + { /* * Make visible if not part of player train * Otherwise uncoupling from cab then changing to exterior, they will still be hidden + * + * Need to do this after everything has been done in case objects refer to other bits */ newTrain.Cars[i].ChangeCarSection(CarSectionType.Exterior); newTrain.Cars[i].FrontBogie.ChangeSection(0); From 8b0fa81ca95d4d191a73b6c23e58867a6be9e4e9 Mon Sep 17 00:00:00 2001 From: Christopher Lees Date: Fri, 18 Aug 2023 18:13:26 +0100 Subject: [PATCH 3/6] Add uncouple sound, fix possible invisible couplers on decoupled train --- .../Train.OpenBve/Sound/SoundCfg.Xml.cs | 25 +++++++++++++++++++ source/TrainManager/Car/CarBase.cs | 3 +++ source/TrainManager/Car/Coupler/Coupler.cs | 5 ++++ 3 files changed, 33 insertions(+) diff --git a/source/Plugins/Train.OpenBve/Sound/SoundCfg.Xml.cs b/source/Plugins/Train.OpenBve/Sound/SoundCfg.Xml.cs index be9438d817..dcd802b6a6 100644 --- a/source/Plugins/Train.OpenBve/Sound/SoundCfg.Xml.cs +++ b/source/Plugins/Train.OpenBve/Sound/SoundCfg.Xml.cs @@ -51,6 +51,8 @@ internal void Parse(string fileName, ref TrainBase Train, ref CarBase car, bool Vector3 right = new Vector3(1.3, 0.0, 0.0); //Positioned at the front of the car, centered X and Y Vector3 front = new Vector3(0.0, 0.0, 0.5 * car.Length); + //Positioned at the rear of the car centered X and Y + Vector3 rear = new Vector3(0.0, 0.0, -0.5 * car.Length); //Positioned at the position of the panel / 3D cab (Remember that the panel is just an object in the world...) Vector3 panel = new Vector3(car.Driver.X, car.Driver.Y, car.Driver.Z + 1.0); @@ -581,6 +583,29 @@ internal void Parse(string fileName, ref TrainBase Train, ref CarBase car, bool } } break; + case "coupler": + if (!c.ChildNodes.OfType().Any()) + { + Plugin.currentHost.AddMessage(MessageType.Error, false, "An empty list of brake handle sounds was defined in in XML file " + fileName); + break; + } + if (!isDriverCar) + { + break; + } + foreach (XmlNode cc in c.ChildNodes) + { + switch (cc.Name.ToLowerInvariant()) + { + case "uncouple": + ParseNode(cc, out car.Coupler.UncoupleSound, rear, SoundCfgParser.smallRadius); + break; + default: + Plugin.currentHost.AddMessage(MessageType.Error, false, "Declaration " + cc.Name + " is unsupported in a " + c.Name + " node."); + break; + } + } + break; } } } diff --git a/source/TrainManager/Car/CarBase.cs b/source/TrainManager/Car/CarBase.cs index 6c88f5d6c2..c7a6333344 100644 --- a/source/TrainManager/Car/CarBase.cs +++ b/source/TrainManager/Car/CarBase.cs @@ -397,6 +397,7 @@ public override void Uncouple(bool Front, bool Rear) newTrain.Cars[i].ChangeCarSection(CarSectionType.Exterior); newTrain.Cars[i].FrontBogie.ChangeSection(0); newTrain.Cars[i].RearBogie.ChangeSection(0); + newTrain.Cars[i].Coupler.ChangeSection(0); } Array.Resize(ref baseTrain.Cars, baseTrain.Cars.Length - totalFollowingCars); baseTrain.Cars[baseTrain.Cars.Length - 1].Coupler.connectedCar = baseTrain.Cars[baseTrain.Cars.Length - 1]; @@ -406,6 +407,8 @@ public override void Uncouple(bool Front, bool Rear) return; } } + + Coupler.UncoupleSound.Play(this, false); TrainManagerBase.currentHost.AddTrain(baseTrain, newTrain); } diff --git a/source/TrainManager/Car/Coupler/Coupler.cs b/source/TrainManager/Car/Coupler/Coupler.cs index 6e0914ef83..40a1b567d6 100644 --- a/source/TrainManager/Car/Coupler/Coupler.cs +++ b/source/TrainManager/Car/Coupler/Coupler.cs @@ -3,6 +3,7 @@ using OpenBveApi.Math; using OpenBveApi.Objects; using OpenBveApi.Trains; +using SoundManager; namespace TrainManager.Car { @@ -22,6 +23,9 @@ public class Coupler : AbstractCoupler /// This is the REAR car when travelling in the notional forwards direction internal CarBase connectedCar; + /// The sound played when this coupler is uncoupled + public CarSound UncoupleSound; + internal AbstractTrain baseTrain; public Coupler(double minimumDistance, double maximumDistance, CarBase frontCar, CarBase rearCar, AbstractTrain train) @@ -34,6 +38,7 @@ public Coupler(double minimumDistance, double maximumDistance, CarBase frontCar, CarSections = new CarSection[] { }; baseTrain = train; ChangeSection(-1); + UncoupleSound = new CarSound(); } public void UpdateObjects(double TimeElapsed, bool ForceUpdate) From 0990af293ffbbc5b27f7b60bdf9f2819f5d97550 Mon Sep 17 00:00:00 2001 From: Christopher Lees Date: Fri, 18 Aug 2023 18:21:24 +0100 Subject: [PATCH 4/6] Assign default key to uncoupling [skip ci] Right file this time... --- assets/Controls/Default.controls | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/assets/Controls/Default.controls b/assets/Controls/Default.controls index afd1daad89..feca026dee 100644 --- a/assets/Controls/Default.controls +++ b/assets/Controls/Default.controls @@ -104,6 +104,8 @@ DECREASE_CUTOFF, keyboard, U, 2 ROUTE_INFORMATION, keyboard, F9, 0 SHOW_EVENTS, keyboard, E, 3 DEBUG_ATS, keyboard, F10, 2 -ACCESSIBILITY_CURRENT_SPEED, keyboard, s, 3 -ACCESSIBILITY_NEXT_SIGNAL, keyboard, a, 3 -ACCESSIBILITY_NEXT_STATION, keyboard, t, 3 \ No newline at end of file +ACCESSIBILITY_CURRENT_SPEED, keyboard, S, 3 +ACCESSIBILITY_NEXT_SIGNAL, keyboard, A, 3 +ACCESSIBILITY_NEXT_STATION, keyboard, T, 3 +UNCOUPLE_REAR, keyboard, Semicolon, 2 +UNCOUPLE_FRONT, keyboard, Semicolon, 3 \ No newline at end of file From 533ba05813861184050b6dfd2fb6d8aeb961d4a7 Mon Sep 17 00:00:00 2001 From: Christopher Lees Date: Fri, 18 Aug 2023 19:41:02 +0100 Subject: [PATCH 5/6] Fix removing current driver car from train --- source/TrainManager/Car/CarBase.cs | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/source/TrainManager/Car/CarBase.cs b/source/TrainManager/Car/CarBase.cs index c7a6333344..43e00787ed 100644 --- a/source/TrainManager/Car/CarBase.cs +++ b/source/TrainManager/Car/CarBase.cs @@ -408,6 +408,35 @@ public override void Uncouple(bool Front, bool Rear) } } + if (baseTrain.DriverCar >= baseTrain.Cars.Length) + { + /* + * The driver car is no longer in the train + * + * Look for a car with an interior view to substitute + * If not found, this will stop at Car 0 + */ + + for (int i = baseTrain.Cars.Length; i > 0; i--) + { + baseTrain.DriverCar = i - 1; + if (!baseTrain.Cars[i - 1].HasInteriorView) + { + /* + * Set the eye position to something vaguely sensible, rather than leaving it on the rails + * Whilst there will be no cab, at least it's a bit more usable like this + */ + baseTrain.Cars[i - 1].InteriorCamera = new CameraAlignment() + { + Position = new Vector3(0, 2, 0.5 * Length) + }; + } + else + { + break; + } + } + } Coupler.UncoupleSound.Play(this, false); TrainManagerBase.currentHost.AddTrain(baseTrain, newTrain); } From 441de89d340542a5c18ec7b66647eb9d56cf9854 Mon Sep 17 00:00:00 2001 From: Christopher Lees Date: Sat, 19 Aug 2023 19:12:41 +0100 Subject: [PATCH 6/6] Various fixes --- assets/Languages/en-US.xlf | 2 +- source/OpenBVE/System/Host.cs | 11 ++++++--- source/OpenBveApi/System/Hosts.cs | 5 ++-- source/TrainManager/Car/CarBase.cs | 39 ++++++++++++++++++++++++------ 4 files changed, 44 insertions(+), 13 deletions(-) diff --git a/assets/Languages/en-US.xlf b/assets/Languages/en-US.xlf index 6049d36fe6..f70e380ac9 100755 --- a/assets/Languages/en-US.xlf +++ b/assets/Languages/en-US.xlf @@ -1589,7 +1589,7 @@ Uncoupling the rear of car number - Uncoupling the rear of car number + Uncoupling the front of car number diff --git a/source/OpenBVE/System/Host.cs b/source/OpenBVE/System/Host.cs index a698a29ffc..ff1dc7401e 100644 --- a/source/OpenBVE/System/Host.cs +++ b/source/OpenBVE/System/Host.cs @@ -576,27 +576,32 @@ public override AbstractTrain[] Trains } } - public override void AddTrain(AbstractTrain PreceedingTrain, AbstractTrain NewTrain) + public override void AddTrain(AbstractTrain ReferenceTrain, AbstractTrain NewTrain, bool Preccedes) { Array.Resize(ref Program.TrainManager.Trains, Program.TrainManager.Trains.Length + 1); int trainIndex = -1; // find index of train within trainmanager array for (int i = 0; i < Program.TrainManager.Trains.Length; i++) { - if (Program.TrainManager.Trains[i] == PreceedingTrain) + if (Program.TrainManager.Trains[i] == ReferenceTrain) { trainIndex = i; break; } } + if (Preccedes && trainIndex > 0) + { + trainIndex--; + } + if (trainIndex == -1) { Program.TrainManager.Trains[Program.TrainManager.Trains.Length - 1] = (TrainBase)NewTrain; } else { - for (int i = Program.TrainManager.Trains.Length - 1; i > trainIndex + 1; i--) + for (int i = Program.TrainManager.Trains.Length - 2; i > trainIndex; i--) { Program.TrainManager.Trains[i + 1] = Program.TrainManager.Trains[i]; } diff --git a/source/OpenBveApi/System/Hosts.cs b/source/OpenBveApi/System/Hosts.cs index 9e8ef88df0..0b1323266b 100644 --- a/source/OpenBveApi/System/Hosts.cs +++ b/source/OpenBveApi/System/Hosts.cs @@ -705,9 +705,10 @@ public virtual AbstractTrain ClosestTrain(double TrackPosition) } /// Adds a new train - /// The preceeding train, or a null reference to add the train at the end of the queue + /// The reference train, or a null reference to add the train at the end of the queue /// The new train - public virtual void AddTrain(AbstractTrain PreceedingTrain, AbstractTrain NewTrain) + /// Whether this train preceeds or follows the reference train + public virtual void AddTrain(AbstractTrain ReferenceTrain, AbstractTrain NewTrain, bool Preceedes) { } diff --git a/source/TrainManager/Car/CarBase.cs b/source/TrainManager/Car/CarBase.cs index 43e00787ed..afa58d44f0 100644 --- a/source/TrainManager/Car/CarBase.cs +++ b/source/TrainManager/Car/CarBase.cs @@ -358,10 +358,6 @@ public override void Uncouple(bool Front, bool Rear) { return; } - if (Front) - { - Uncouple(false, true); - } // Create new train TrainBase newTrain = new TrainBase(TrainState.Available); newTrain.Handles.Power = new PowerHandle(0, 0, new double[0], new double[0], newTrain) @@ -373,12 +369,35 @@ public override void Uncouple(bool Front, bool Rear) DelayedChanges = new HandleChange[0] }; newTrain.Handles.HoldBrake = new HoldBrakeHandle(newTrain); + if (Front) + { + int totalPreceedingCars = trainCarIndex; + newTrain.Cars = new CarBase[trainCarIndex]; + for (int i = 0; i < totalPreceedingCars; i++) + { + newTrain.Cars[i] = baseTrain.Cars[i]; + } + + for (int i = totalPreceedingCars; i < baseTrain.Cars.Length; i++) + { + baseTrain.Cars[i - totalPreceedingCars] = baseTrain.Cars[i]; + baseTrain.Cars[i].Index = i - totalPreceedingCars; + } + Array.Resize(ref baseTrain.Cars, baseTrain.Cars.Length - totalPreceedingCars); + TrainManagerBase.currentHost.AddTrain(baseTrain, newTrain, false); + + if (baseTrain.DriverCar - totalPreceedingCars >= 0) + { + baseTrain.DriverCar -= totalPreceedingCars; + } + } + if (Rear) { int totalFollowingCars = baseTrain.Cars.Length - (Index + 1); - newTrain.Cars = new CarBase[totalFollowingCars]; if (totalFollowingCars > 0) { + newTrain.Cars = new CarBase[totalFollowingCars]; // Move following cars to new train for (int i = 0; i < totalFollowingCars; i++) { @@ -406,6 +425,8 @@ public override void Uncouple(bool Front, bool Rear) { return; } + Coupler.UncoupleSound.Play(this, false); + TrainManagerBase.currentHost.AddTrain(baseTrain, newTrain, true); } if (baseTrain.DriverCar >= baseTrain.Cars.Length) @@ -437,8 +458,12 @@ public override void Uncouple(bool Front, bool Rear) } } } - Coupler.UncoupleSound.Play(this, false); - TrainManagerBase.currentHost.AddTrain(baseTrain, newTrain); + + if (baseTrain.CameraCar >= baseTrain.Cars.Length) + { + baseTrain.CameraCar = baseTrain.DriverCar; + } + } /// Returns the combination of door states what encountered at the specified car in a train.