main
Marc Riera 2024-10-13 00:31:40 +02:00
parent 8d9c08276a
commit b32c1aafeb
7 changed files with 215 additions and 31 deletions

View File

@ -31,9 +31,10 @@ namespace OpenbveFcmbTrainPlugin
/// <summary>Is called when the device state should be updated.</summary>
/// <param name="train">The current train.</param>
/// <param name="route">The current route.</param>
/// <param name="init">Whether the device should initialize.</param>
/// <param name="elapsedTime">The time elapsed since the previous call.</param>
internal override void Update(Train train, bool init, Time elapsedTime)
internal override void Update(Train train, Route route, bool init, Time elapsedTime)
{
if (train.VigilanceOverride)
{
@ -100,7 +101,8 @@ namespace OpenbveFcmbTrainPlugin
/// <summary>Is called when the plugin should perform the AI.</summary>
/// <param name="data">The AI data.</param>
/// <param name="train">The current train.</param>
internal override void PerformAI(AIData data, Train train)
/// <param name="route">The current route.</param>
internal override void PerformAI(AIData data, Train train, Route route)
{
if (DeviceState != DeviceStates.Inactive)
{

View File

@ -17,9 +17,10 @@ namespace OpenbveFcmbTrainPlugin
/// <summary>Is called when the device state should be updated.</summary>
/// <param name="train">The current train.</param>
/// <param name="route">The current route.</param>
/// <param name="init">Whether the device should initialize.</param>
/// <param name="elapsedTime">The time elapsed since the previous call.</param>
internal virtual void Update(Train train, bool init, Time elapsedTime) { }
internal virtual void Update(Train train, Route route, bool init, Time elapsedTime) { }
/// <summary>Is called when the driver changes the reverser.</summary>
/// <param name="reverser">The new reverser position.</param>
@ -59,6 +60,7 @@ namespace OpenbveFcmbTrainPlugin
/// <summary>Is called when the plugin should perform the AI.</summary>
/// <param name="data">The AI data.</param>
/// <param name="train">The current train.</param>
internal virtual void PerformAI(AIData data, Train train) { }
/// <param name="route">The current route.</param>
internal virtual void PerformAI(AIData data, Train train, Route route) { }
}
}

View File

@ -14,9 +14,10 @@ namespace OpenbveFcmbTrainPlugin
/// <summary>Is called when the device state should be updated.</summary>
/// <param name="train">The current train.</param>
/// <param name="route">The current route.</param>
/// <param name="init">Whether the device should initialize.</param>
/// <param name="elapsedTime">The time elapsed since the previous call.</param>
internal override void Update(Train train, bool init, Time elapsedTime)
internal override void Update(Train train, Route route, bool init, Time elapsedTime)
{
if (init)
{
@ -136,31 +137,89 @@ namespace OpenbveFcmbTrainPlugin
/// <param name="newState">The new state of the doors.</param>
internal override void DoorChange(DoorStates oldState, DoorStates newState)
{
LeftDoorsClosing = false;
RightDoorsClosing = false;
if ((oldState == DoorStates.Both || oldState == DoorStates.Left) && (newState == DoorStates.None || newState == DoorStates.Right))
{
LeftDoorsClosing = false;
// Unselect doors automatically when closed, just in case
RequestedDoorInterlock = newState == DoorStates.None ? DoorInterlockStates.Locked : DoorInterlockStates.Right;
}
if ((oldState == DoorStates.Both || oldState == DoorStates.Right) && (newState == DoorStates.None || newState == DoorStates.Left))
{
RightDoorsClosing = false;
// Unselect doors automatically when closed, just in case
RequestedDoorInterlock = newState == DoorStates.None ? DoorInterlockStates.Locked : DoorInterlockStates.Left;
}
}
/// <summary>Is called when the device should perform the AI.</summary>
/// <param name="data">The AI data.</param>
/// <param name="train">The current train.</param>
internal override void PerformAI(AIData data, Train train)
/// <param name="route">The current route.</param>
internal override void PerformAI(AIData data, Train train, Route route)
{
//// Select the correct doors for the current station
//if (Stations.State != Stations.StationStates.Completed)
//{
// if (((Stations.Current.OpenLeftDoors && !LeftDoorsSelected) || (!Stations.Current.OpenLeftDoors && LeftDoorsSelected)) && !LeftDoorsClosing)
// {
// // Select or unselect the doors on the left.
// KeyDown(VirtualKeys.G);
// data.Response = AIResponse.Short;
// }
// if (((Stations.Current.OpenRightDoors && !RightDoorsSelected) || (!Stations.Current.OpenRightDoors && RightDoorsSelected)) && !RightDoorsClosing)
// {
// // Select or unselect the doors on the right.
// KeyDown(VirtualKeys.H);
// data.Response = AIResponse.Short;
// }
//}
// Select doors to be opened on the current stop, at least 200 meters before the stop point.
if (route.CurrentStation.PlayerStops() && train.State.Location >= route.CurrentStation.StopPosition - 200 && route.StationState == Route.StationStates.Pending)
{
switch (RequestedDoorInterlock)
{
case DoorInterlockStates.Unlocked:
if (!route.CurrentStation.OpenLeftDoors)
{
KeyChange(VirtualKeys.G, true, train);
data.Response = AIResponse.Short;
KeyChange(VirtualKeys.G, false, train);
}
if (!route.CurrentStation.OpenRightDoors)
{
KeyChange(VirtualKeys.H, true, train);
data.Response = AIResponse.Short;
KeyChange(VirtualKeys.H, false, train);
}
break;
case DoorInterlockStates.Left:
if (!route.CurrentStation.OpenLeftDoors)
{
KeyChange(VirtualKeys.G, true, train);
data.Response = AIResponse.Short;
KeyChange(VirtualKeys.G, false, train);
}
if (route.CurrentStation.OpenRightDoors)
{
KeyChange(VirtualKeys.H, true, train);
data.Response = AIResponse.Short;
KeyChange(VirtualKeys.H, false, train);
}
break;
case DoorInterlockStates.Right:
if (route.CurrentStation.OpenLeftDoors)
{
KeyChange(VirtualKeys.G, true, train);
data.Response = AIResponse.Short;
KeyChange(VirtualKeys.G, false, train);
}
if (!route.CurrentStation.OpenRightDoors)
{
KeyChange(VirtualKeys.H, true, train);
data.Response = AIResponse.Short;
KeyChange(VirtualKeys.H, false, train);
}
break;
case DoorInterlockStates.Locked:
if (route.CurrentStation.OpenLeftDoors)
{
KeyChange(VirtualKeys.G, true, train);
data.Response = AIResponse.Short;
KeyChange(VirtualKeys.G, false, train);
}
if (route.CurrentStation.OpenRightDoors)
{
KeyChange(VirtualKeys.H, true, train);
data.Response = AIResponse.Short;
KeyChange(VirtualKeys.H, false, train);
}
break;
}
}
}
}
}

View File

@ -9,6 +9,9 @@ namespace OpenbveFcmbTrainPlugin
/// <summary>The train that is simulated by this plugin.</summary>
private Train Train;
/// <summary>The route where the train is running.</summary>
private Route Route;
/// <summary>Whether the train is initializing or reinitializing.</summary>
internal static bool Initializing = true;
@ -23,6 +26,7 @@ namespace OpenbveFcmbTrainPlugin
properties.AISupport = AISupport.Basic;
properties.Panel = new int[256];
Train = new Train(properties.Panel);
Route = new Route();
return true;
}
@ -51,7 +55,8 @@ namespace OpenbveFcmbTrainPlugin
/// <param name="data">The data passed to the plugin.</param>
public void Elapse(ElapseData data)
{
Train.Elapse(data);
Route.Elapse(data);
Train.Elapse(data, Route);
Initializing = false;
}
@ -100,6 +105,7 @@ namespace OpenbveFcmbTrainPlugin
/// <param name="newState">The new state of the doors.</param>
public void DoorChange(DoorStates oldState, DoorStates newState)
{
Route.DoorChange(oldState, newState);
Train.DoorChange(oldState, newState);
}
@ -119,7 +125,7 @@ namespace OpenbveFcmbTrainPlugin
/// <param name="data">The AI data.</param>
public void PerformAI(AIData data)
{
Train.PerformAI(data);
Train.PerformAI(data, Route);
}
}

View File

@ -40,10 +40,12 @@
<Compile Include="Train\Train.cs" />
<Compile Include="Devices\TrainStop.cs" />
<Compile Include="Devices\Deadman.cs" />
<Compile Include="Route\Route.cs" />
</ItemGroup>
<ItemGroup>
<Folder Include="Devices\" />
<Folder Include="Train\" />
<Folder Include="Route\" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
</Project>

112
src/Route/Route.cs Normal file
View File

@ -0,0 +1,112 @@
using System.Collections.Generic;
using OpenBveApi.Runtime;
namespace OpenbveFcmbTrainPlugin
{
internal class Route
{
/// <summary>Represents the state of the current station.</summary>
internal enum StationStates
{
/// <summary>The train has not arrived at the station yet.</summary>
Pending = 0,
/// <summary>The train has arrived at the station.</summary>
Arrived = 1,
/// <summary>The train is ready to depart.</summary>
Completed = 2,
}
/// <summary>The state of the current station.</summary>
internal StationStates StationState { get; private set; } = StationStates.Arrived;
/// <summary>The list of stations in the route.</summary>
internal List<Station> Stations;
/// <summary>The current station in the route.</summary>
internal Station CurrentStation;
/// <summary>The next station in the route.</summary>
internal Station NextStation;
/// <summary>The current state of the train doors.</summary>
private DoorStates DoorState;
/// <summary>The previous state of the train doors.</summary>
private DoorStates PreviousDoorState;
/// <summary>Is called every frame.</summary>
/// <param name="data">The data passed to the plugin.</param>
internal void Elapse(ElapseData data)
{
if (OpenbveFcmbTrainPlugin.Initializing)
{
// Get the list of stations and set the current station
Stations = data.Stations;
UpdateStationData(data.Vehicle.Location);
}
if (StationState == StationStates.Completed && data.Vehicle.Location > CurrentStation.StopPosition + CurrentStation.ForwardTolerance)
{
// The train is heading for the next station
StationState = StationStates.Pending;
UpdateStationData(data.Vehicle.Location);
}
if (StationState == StationStates.Pending && data.Vehicle.Location > CurrentStation.StopPosition + CurrentStation.ForwardTolerance + 100)
{
// The train has passed the station without stopping
UpdateStationData(data.Vehicle.Location);
}
// Update station status after closing the doors
if (StationState == StationStates.Arrived && DoorState == DoorStates.None)
{
// The train is ready to leave the station
StationState = StationStates.Completed;
}
// Check if the train is at a station where the doors should open
bool ArrivedDoorStop = (PreviousDoorState == DoorStates.None && DoorState != DoorStates.None && (CurrentStation.OpenLeftDoors || CurrentStation.OpenRightDoors));
// Check if the train is at a station where the doors should not open
bool ArrivedNoDoorStop = (DoorState == DoorStates.None && !CurrentStation.OpenLeftDoors && !CurrentStation.OpenRightDoors);
if (StationState == StationStates.Pending && (ArrivedDoorStop || ArrivedNoDoorStop) && data.Vehicle.Speed.KilometersPerHour < 0.05 && data.Vehicle.Location >= CurrentStation.DefaultTrackPosition)
{
// The train has arrived at the station
StationState = StationStates.Arrived;
}
}
/// <summary>Is called when the state of the doors changes.</summary>
/// <param name="oldState">The old state of the doors.</param>
/// <param name="newState">The new state of the doors.</param>
internal void DoorChange(DoorStates oldState, DoorStates newState)
{
PreviousDoorState = oldState;
DoorState = newState;
}
/// <summary>Updates the data for the current and next station.</summary>
/// <param name="location">The current location of the train.</param>
internal void UpdateStationData(double location)
{
// Calculate the index of the current station
double position = location;
int currentIndex = 0;
if (Stations.Count > 1)
{
while (currentIndex > 0 && (Stations[currentIndex].StopPosition + Stations[currentIndex].ForwardTolerance > position || !Stations[currentIndex].PlayerStops()))
{
// Detects the station index when driving or jumping backwards
currentIndex--;
}
while (currentIndex < Stations.Count - 1 && (Stations[currentIndex].StopPosition + Stations[currentIndex].ForwardTolerance <= position || !Stations[currentIndex].PlayerStops()))
{
// Detects the station index when driving or jumping forwards
currentIndex++;
}
}
CurrentStation = Stations[currentIndex];
NextStation = currentIndex < Stations.Count - 1 ? Stations[currentIndex + 1] : null;
}
}
}

View File

@ -62,7 +62,8 @@ namespace OpenbveFcmbTrainPlugin
/// <summary>Is called every frame.</summary>
/// <param name="data">The data.</param>
internal void Elapse(ElapseData data)
/// <param name="route">The route data.</param>
internal void Elapse(ElapseData data, Route route)
{
State = data.Vehicle;
@ -74,12 +75,11 @@ namespace OpenbveFcmbTrainPlugin
// Retrieve data from all devices
foreach (Device dev in Devices)
{
dev.Update(this, OpenbveFcmbTrainPlugin.Initializing, data.ElapsedTime);
dev.Update(this, route, OpenbveFcmbTrainPlugin.Initializing, data.ElapsedTime);
data.DoorInterlockState |= dev.RequestedDoorInterlock;
if (dev.RequestedPowerNotch != -1) data.Handles.PowerNotch = dev.RequestedPowerNotch;
if (dev.RequestedBrakeNotch != -1) data.Handles.BrakeNotch = dev.RequestedBrakeNotch;
}
data.DebugMessage = DoorState.ToString() + " " + data.DoorInterlockState.ToString();
}
/// <summary>Is called when the driver changes the reverser.</summary>
@ -141,11 +141,12 @@ namespace OpenbveFcmbTrainPlugin
/// <summary>Is called when the plugin should perform the AI.</summary>
/// <param name="data">The AI data.</param>
internal void PerformAI(AIData data)
/// <param name="route">The route data.</param>
internal void PerformAI(AIData data, Route route)
{
foreach (Device dev in Devices)
{
dev.PerformAI(data, this);
dev.PerformAI(data, this, route);
}
}
}