Skip to content

Commit 8d76225

Browse files
committed
Merge branch 'master' into refactor-user-settings-location
2 parents 2695523 + 8773ee5 commit 8d76225

File tree

15 files changed

+157
-103
lines changed

15 files changed

+157
-103
lines changed

Source/Documentation/Manual/physics.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3144,6 +3144,9 @@ the following parameters will adjust the behaviour of air brakes:
31443144
.. index::
31453145
single: DynamicBrakeHasAutoBailOff
31463146
single: ORTSDynamicBrakesHasPartialBailOff
3147+
single: ORTSTrainDynamicBlendingTable
3148+
single: ORTSDynamicBrakeReplacementWithEngineBrake
3149+
single: ORTSDynamicBrakeReplacementWithEngineBrakeAtSpeed
31473150

31483151
- ``Engine(DynamicBrakeHasAutoBailOff`` -- Set to 1 if brake cylinders are
31493152
emptied while dynamic brake is active
@@ -3183,6 +3186,11 @@ notch of the train brake controller, where 0 means no dynamic brake and 1 means
31833186
)
31843187
)
31853188
)
3189+
Dynamic braking is not effective at low speeds. Thus, in some locomotives,
3190+
dynamic brake application demanded by the train brake controller is replaced by
3191+
`engine` air braking at low speeds. This effect can be activated setting
3192+
``Engine(ORTSDynamicBrakeReplacementWithEngineBrake`` to 1, provided that the locomotive
3193+
speed is below ``Engine(ORTSDynamicBrakeReplacementWithEngineBrakeAtSpeed``.
31863194

31873195
Native Open Rails Braking Parameters
31883196
------------------------------------

Source/Launcher/Program.cs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -116,8 +116,6 @@ static void CheckOR(List<string> missingFiles, string path)
116116
// Required libraries:
117117
"GNU.Gettext.dll",
118118
"GNU.Gettext.WinForms.dll",
119-
"ICSharpCode.SharpZipLib.dll",
120-
"DotNetZip.dll",
121119
@"Native/X86/OpenAL32.dll",
122120
@"Native/X64/OpenAL32.dll",
123121
// Programs:
@@ -142,4 +140,4 @@ static int SafeReadKey(RegistryKey key, string name, int defaultValue)
142140
}
143141
}
144142
}
145-
}
143+
}

Source/Menu/ImportExportSaveForm.cs

Lines changed: 15 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
using System.Diagnostics;
2020
using System.Drawing;
2121
using System.IO;
22-
using System.IO.Packaging; // Needs Project > Add reference > .NET > Component name = WindowsBase
22+
using System.IO.Compression;
2323
using System.Windows.Forms;
2424
using GNU.Gettext;
2525
using GNU.Gettext.WinForms;
@@ -69,8 +69,6 @@ private void bExport_Click(object sender, EventArgs e)
6969
// Create a Zip-compatible file/compressed folder containing:
7070
// all files with the same stem (i.e. *.save, *.png, *.replay, *.txt)
7171

72-
// For Zip, see http://weblogs.asp.net/jgalloway/archive/2007/10/25/creating-zip-archives-in-net-without-an-external-library-like-sharpziplib.aspx
73-
7472
// Copy files to new package in folder save_packs
7573
var fullFilePath = Path.Combine(UserSettings.UserDataFolder, Save.File);
7674
var toFile = Path.GetFileNameWithoutExtension(Save.File) + "." + SavePackFileExtension;
@@ -117,56 +115,35 @@ void UpdateFileList(string message)
117115

118116
static void AddFileToZip(string zipFilename, string fileToAdd)
119117
{
120-
using (var zip = Package.Open(zipFilename, FileMode.OpenOrCreate))
118+
using (var zip = ZipFile.Open(zipFilename, ZipArchiveMode.Update))
121119
{
122-
var destFilename = @".\" + Path.GetFileName(fileToAdd);
123-
var uri = PackUriHelper.CreatePartUri(new Uri(destFilename, UriKind.Relative));
124-
if (zip.PartExists(uri))
125-
{
126-
zip.DeletePart(uri);
127-
}
128-
var part = zip.CreatePart(uri, "", CompressionOption.Normal);
129-
using (var source = new FileStream(fileToAdd, FileMode.Open, FileAccess.Read))
130-
{
131-
using (var destination = part.GetStream())
132-
{
133-
CopyStream(source, destination);
134-
}
135-
}
120+
zip.CreateEntryFromFile(fileToAdd, Path.GetFileName(fileToAdd), CompressionLevel.Optimal);
136121
}
137122
}
138123

139-
140124
static void ExtractFilesFromZip(string zipFilename, string path)
141125
{
142-
using (var zip = Package.Open(zipFilename, FileMode.Open, FileAccess.Read))
126+
using (var zip = ZipFile.OpenRead(zipFilename))
143127
{
144-
foreach (var part in zip.GetParts())
128+
foreach (var part in zip.Entries)
145129
{
146-
var fileName = Path.Combine(path, part.Uri.ToString().TrimStart('/').Replace("%20", " "));
147-
try
148-
{
149-
using (var destination = new FileStream(fileName, FileMode.Create))
130+
// Older save packs have an extra root file we don't need
131+
if (part.FullName == "[Content_Types].xml") continue;
132+
133+
// Older save packs have percent-encoded paths
134+
var fileName = Path.GetFullPath(Path.Combine(path, part.FullName.Replace("%20", " ")));
135+
136+
try {
137+
if (Path.GetFileName(fileName).Length > 0)
150138
{
151-
using (var source = part.GetStream())
152-
{
153-
CopyStream(source, destination);
154-
}
139+
Directory.CreateDirectory(Path.GetDirectoryName(fileName));
140+
part.ExtractToFile(fileName, true);
155141
}
156142
}
157143
catch { } // Ignore attempts to copy to a destination file locked by another process as
158144
// ResumeForm locks PNG of selected save.
159145
}
160146
}
161147
}
162-
163-
static void CopyStream(Stream source, Stream target)
164-
{
165-
const int bufferSize = 0x1000;
166-
var buffer = new byte[bufferSize];
167-
var bytesRead = 0;
168-
while ((bytesRead = source.Read(buffer, 0, bufferSize)) > 0)
169-
target.Write(buffer, 0, bytesRead);
170-
}
171148
}
172149
}

Source/Menu/Menu.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,8 @@
3232
</Reference>
3333
<Reference Include="PresentationFramework" />
3434
<Reference Include="System.DirectoryServices" />
35+
<Reference Include="System.IO.Compression" />
3536
<Reference Include="System.Net.Http" />
36-
<Reference Include="WindowsBase" />
3737
</ItemGroup>
3838
<ItemGroup>
3939
<Compile Update="KeyInputControl.cs">

Source/Menu/Notifications/NotificationManager.cs

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222
using System.Linq;
2323
using System.Net;
2424
using System.Resources;
25-
using System.Runtime.InteropServices;
2625
using System.Text;
2726
using System.Windows;
2827
using System.Windows.Forms;
@@ -32,6 +31,7 @@
3231
using ORTS.Updater;
3332
using static ORTS.Common.SystemInfo;
3433
using static Menu.Notifications.NotificationPage;
34+
using Newtonsoft.Json.Serialization;
3535

3636
// Behaviour
3737
// Notifications are read only once as a background task at start into Notifications.
@@ -126,7 +126,7 @@ public void CheckNotifications()
126126
Notifications.NotificationList = IncludeValid(Notifications.NotificationList);
127127
Notifications.NotificationList = SortByDate(Notifications.NotificationList);
128128
}
129-
catch (WebException ex)
129+
catch (Exception ex)
130130
{
131131
Error = ex;
132132
}
@@ -154,7 +154,7 @@ public Notifications GetNotifications()
154154
notificationsSerial = GetRemoteJson();
155155
}
156156

157-
var jsonSettings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Auto };
157+
var jsonSettings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Auto, SerializationBinder = new NotificationSerializationBinder() };
158158
var jsonInput = JsonConvert.DeserializeObject<Notifications>(notificationsSerial, jsonSettings);
159159

160160
NewPages.Count = 0;
@@ -626,7 +626,7 @@ public OverrideParameterList GetOverrideParameters()
626626
// Input from local file into a string
627627
var overrideParametersSerial = File.ReadAllText(filename);
628628

629-
var jsonSettings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Auto };
629+
var jsonSettings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Auto, SerializationBinder = new NotificationSerializationBinder() };
630630
var jsonInput = JsonConvert.DeserializeObject<OverrideParameterList>(overrideParametersSerial, jsonSettings);
631631

632632
return jsonInput;
@@ -690,5 +690,24 @@ public void AppendToLog(string record)
690690
using (StreamWriter sw = File.AppendText(LogFile)) sw.WriteLine(record);
691691
}
692692
#endregion
693+
694+
class NotificationSerializationBinder : ISerializationBinder
695+
{
696+
public void BindToName(Type serializedType, out string assemblyName, out string typeName)
697+
{
698+
throw new NotImplementedException();
699+
}
700+
701+
public Type BindToType(string assemblyName, string typeName)
702+
{
703+
if (assemblyName == "Menu")
704+
{
705+
var ns = typeof(Notifications).Namespace;
706+
var name = typeName.Split('.').Last();
707+
return typeof(Notifications).Assembly.GetType($"{ns}.{name}");
708+
}
709+
return null;
710+
}
711+
}
693712
}
694713
}

Source/Orts.Parsers.Msts/Orts.Parsers.Msts.csproj

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,5 @@
1919
<PrivateAssets>all</PrivateAssets>
2020
</PackageReference>
2121
<PackageReference Include="MonoGame.Framework.WindowsDX" Version="3.8.0.1641" />
22-
<PackageReference Include="SharpZipLib" Version="1.4.1" />
2322
</ItemGroup>
2423
</Project>

Source/Orts.Parsers.Msts/SBR.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,12 @@
1515
// You should have received a copy of the GNU General Public License
1616
// along with Open Rails. If not, see <http://www.gnu.org/licenses/>.
1717

18-
using ICSharpCode.SharpZipLib.Zip.Compression.Streams;
1918
using Microsoft.Xna.Framework;
2019
using System;
2120
using System.Collections.Generic;
2221
using System.Diagnostics;
2322
using System.IO;
23+
using System.IO.Compression;
2424
using System.Text;
2525

2626
namespace Orts.Parsers.Msts
@@ -60,7 +60,9 @@ public static SBR Open(string filename)
6060
// SIMISA@@ means uncompressed
6161
if (headerString.StartsWith("SIMISA@F"))
6262
{
63-
fb = new InflaterInputStream(fb);
63+
// Skip over the 2 byte zlib header and onto the DEFLATE stream itself
64+
fb.Read(buffer, 16, 2);
65+
fb = new DeflateStream(fb, CompressionMode.Decompress);
6466
}
6567
else if (headerString.StartsWith("\r\nSIMISA"))
6668
{

Source/Orts.Simulation/Simulation/RollingStocks/MSTSLocomotive.cs

Lines changed: 34 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -405,6 +405,8 @@ public float OdometerM
405405
public float DynamicBrakeDelayS;
406406
public bool DynamicBrakeAutoBailOff;
407407
public bool DynamicBrakePartialBailOff;
408+
public bool DynamicBrakeEngineBrakeReplacement;
409+
public float DynamicBrakeEngineBrakeReplacementSpeed;
408410
public bool UsingRearCab;
409411
public bool BrakeOverchargeSoundOn = false;
410412
protected bool DynamicBrakeBlendingEnabled; // dynamic brake blending is configured
@@ -600,15 +602,6 @@ public override void LoadFromWagFile(string wagFilePath)
600602

601603
protected void CheckCoherence()
602604
{
603-
if (!TrainBrakeController.IsValid())
604-
TrainBrakeController = new ScriptedBrakeController(this); //create a blank one
605-
606-
if (!EngineBrakeController.IsValid())
607-
EngineBrakeController = null;
608-
609-
if (!BrakemanBrakeController.IsValid())
610-
BrakemanBrakeController = null;
611-
612605
if (ThrottleController == null)
613606
{
614607
//If no controller so far, we create a default one
@@ -1083,6 +1076,8 @@ public override void Parse(string lowercasetoken, STFReader stf)
10831076
case "engine(dynamicbrakehasautobailoff":
10841077
case "engine(ortsdynamicbrakeshasautobailoff": DynamicBrakeAutoBailOff = stf.ReadBoolBlock(true); break;
10851078
case "engine(ortsdynamicbrakeshaspartialbailoff": DynamicBrakePartialBailOff = stf.ReadBoolBlock(false); break;
1079+
case "engine(ortsdynamicbrakereplacementwithenginebrake": DynamicBrakeEngineBrakeReplacement = stf.ReadBoolBlock(false); break;
1080+
case "engine(ortsdynamicbrakereplacementwithenginebrakeatspeed": DynamicBrakeEngineBrakeReplacementSpeed = stf.ReadFloatBlock(STFReader.UNITS.SpeedDefaultMPH, null); break;
10861081
case "engine(dynamicbrakesdelaytimebeforeengaging": DynamicBrakeDelayS = stf.ReadFloatBlock(STFReader.UNITS.Time, null); break;
10871082
case "engine(dynamicbrakesresistorcurrentlimit": DynamicBrakeMaxCurrentA = stf.ReadFloatBlock(STFReader.UNITS.Current, null); break;
10881083
case "engine(numwheels": MSTSLocoNumDrvWheels = stf.ReadFloatBlock(STFReader.UNITS.None, 4.0f); if (MSTSLocoNumDrvWheels < 1) STFException.TraceWarning(stf, "Engine:NumWheels is less than 1, parts of the simulation may not function correctly"); break;
@@ -1235,6 +1230,8 @@ public override void Copy(MSTSWagon copy)
12351230
DynamicBrakeForceCurves = locoCopy.DynamicBrakeForceCurves;
12361231
DynamicBrakeAutoBailOff = locoCopy.DynamicBrakeAutoBailOff;
12371232
DynamicBrakePartialBailOff = locoCopy.DynamicBrakePartialBailOff;
1233+
DynamicBrakeEngineBrakeReplacement = locoCopy.DynamicBrakeEngineBrakeReplacement;
1234+
DynamicBrakeEngineBrakeReplacementSpeed = locoCopy.DynamicBrakeEngineBrakeReplacementSpeed;
12381235
DynamicBrakeMaxCurrentA = locoCopy.DynamicBrakeMaxCurrentA;
12391236
DynamicBrakeSpeed1MpS = locoCopy.DynamicBrakeSpeed1MpS;
12401237
DynamicBrakeSpeed2MpS = locoCopy.DynamicBrakeSpeed2MpS;
@@ -1539,8 +1536,29 @@ public override void CopyControllerSettings(TrainCar other)
15391536
public override void Initialize()
15401537
{
15411538
TrainBrakeController.Initialize();
1542-
EngineBrakeController.Initialize();
1543-
BrakemanBrakeController.Initialize();
1539+
if (!TrainBrakeController.IsValid())
1540+
{
1541+
TrainBrakeController = new ScriptedBrakeController(this); //create a blank one
1542+
TrainBrakeController.Initialize();
1543+
}
1544+
if (EngineBrakeController != null)
1545+
{
1546+
EngineBrakeController.Initialize();
1547+
if (!EngineBrakeController.IsValid() && !SteamEngineBrakeFitted)
1548+
{
1549+
EngineBrakeController = null;
1550+
EngineBrakeFitted = false;
1551+
}
1552+
}
1553+
if (BrakemanBrakeController != null)
1554+
{
1555+
BrakemanBrakeController.Initialize();
1556+
if (!BrakemanBrakeController.IsValid())
1557+
{
1558+
BrakemanBrakeController = null;
1559+
BrakemanBrakeFitted = false;
1560+
}
1561+
}
15441562
LocomotivePowerSupply?.Initialize();
15451563
TrainControlSystem.Initialize();
15461564
CruiseControl?.Initialize();
@@ -1828,6 +1846,11 @@ public override void Initialize()
18281846
}
18291847
}
18301848

1849+
if (DynamicBrakeEngineBrakeReplacement && DynamicBrakeEngineBrakeReplacementSpeed == 0)
1850+
{
1851+
DynamicBrakeEngineBrakeReplacementSpeed = DynamicBrakeSpeed2MpS;
1852+
}
1853+
18311854
// Initialise track sanding parameters
18321855
if (MaxTrackSandBoxCapacityM3 == 0)
18331856
{

Source/Orts.Simulation/Simulation/RollingStocks/SubSystems/Brakes/MSTS/AirSinglePipe.cs

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -532,7 +532,7 @@ public override void Initialize(bool handbrakeOn, float maxPressurePSI, float fu
532532
BrakeLine1PressurePSI = Car.Train.EqualReservoirPressurePSIorInHg;
533533
BrakeLine2PressurePSI = Car.Train.BrakeLine2PressurePSI;
534534
if (Car is MSTSLocomotive && Car.Train.LeadLocomotive is MSTSLocomotive lead)
535-
lead.EngineBrakeController.UpdateEngineBrakePressure(ref BrakeLine3PressurePSI, 1000);
535+
lead.EngineBrakeController?.UpdateEngineBrakePressure(ref BrakeLine3PressurePSI, 1000);
536536
if (maxPressurePSI > 0)
537537
ControlResPressurePSI = maxPressurePSI;
538538

@@ -780,7 +780,7 @@ public override void Initialize()
780780
if (TwoStageRelayValveRatio == 0)
781781
TwoStageRelayValveRatio = RelayValveRatio;
782782

783-
RelayValveFitted |= (Car is MSTSLocomotive loco && (loco.DynamicBrakeAutoBailOff || loco.DynamicBrakePartialBailOff)) ||
783+
RelayValveFitted |= (Car is MSTSLocomotive loco && (loco.DynamicBrakeAutoBailOff || loco.DynamicBrakePartialBailOff || loco.DynamicBrakeEngineBrakeReplacement)) ||
784784
(Car as MSTSWagon).BrakeValve == MSTSWagon.BrakeValveType.DistributingValve || (Car as MSTSWagon).SupplyReservoirPresent ||
785785
TwoStageRelayValveRatio != RelayValveRatio || RelayValveInshotPSI != 0 || EngineRelayValveInshotPSI != 0;
786786

@@ -1607,8 +1607,8 @@ public override void Update(float elapsedClockSeconds)
16071607
{
16081608
// For distributing valves, we use AutoCylPressurePSI as "Application Chamber/Pipe" pressure
16091609
// CylPressurePSI is the actual pressure applied to cylinders
1610-
var engineBrakeStatus = loco.EngineBrakeController.Notches[loco.EngineBrakeController.CurrentNotch].Type;
1611-
var trainBrakeStatus = loco.TrainBrakeController.Notches[loco.TrainBrakeController.CurrentNotch].Type;
1610+
var engineBrakeStatus = loco.EngineBrakeController?.TrainBrakeControllerState ?? ControllerState.Release;
1611+
var trainBrakeStatus = loco.TrainBrakeController.TrainBrakeControllerState;
16121612
// BailOff
16131613
if (engineBrakeStatus == ControllerState.BailOff)
16141614
{
@@ -1653,9 +1653,7 @@ public override void Update(float elapsedClockSeconds)
16531653
{
16541654
if (loco.Train.LeadLocomotiveIndex >= 0)
16551655
{
1656-
if (loco.Train.DetermineDPLeadLocomotive(loco) is MSTSLocomotive lead && (lead.BailOff ||
1657-
(lead.EngineBrakeController != null && lead.EngineBrakeController.CurrentNotch >= 0
1658-
&& lead.EngineBrakeController.Notches[lead.EngineBrakeController.CurrentNotch].Type == ControllerState.BailOff)))
1656+
if (loco.Train.DetermineDPLeadLocomotive(loco) is MSTSLocomotive lead && (lead.BailOff || (lead.EngineBrakeController != null && lead.EngineBrakeController.TrainBrakeControllerState == ControllerState.BailOff)))
16591657
{
16601658
if (loco.BrakeValve == MSTSWagon.BrakeValveType.Distributor)
16611659
{
@@ -1680,6 +1678,9 @@ public override void Update(float elapsedClockSeconds)
16801678
}
16811679
}
16821680
}
1681+
}
1682+
if (loco.LocomotivePowerSupply.DynamicBrakeAvailable)
1683+
{
16831684
if (loco.DynamicBrakePercent > 0 && Car.FrictionBrakeBlendingMaxForceN > 0)
16841685
{
16851686
if (loco.DynamicBrakePartialBailOff)
@@ -1714,6 +1715,14 @@ public override void Update(float elapsedClockSeconds)
17141715
}
17151716
}
17161717
}
1718+
if (loco.DynamicBrakeEngineBrakeReplacement && loco.RemoteControlGroup == 0 && loco.AbsTractionSpeedMpS < loco.DynamicBrakeEngineBrakeReplacementSpeed && loco.Train.LeadLocomotive is MSTSLocomotive lead && lead.TrainBrakeController.TrainDynamicBrakeIntervention > 0)
1719+
{
1720+
var requiredBrakeForceN = loco.MaxDynamicBrakeForceN * lead.TrainBrakeController.TrainDynamicBrakeIntervention;
1721+
var reverseBlendingPressurePSI = Math.Min(Math.Max((requiredBrakeForceN - loco.DynamicBrakeForceN) / Car.FrictionBrakeBlendingMaxForceN * ReferencePressurePSI
1722+
+ BrakeCylinderSpringPressurePSI, 0), MaxCylPressurePSI);
1723+
reverseBlendingPressurePSI /= RelayValveRatio;
1724+
if (demandedPressurePSI < reverseBlendingPressurePSI) demandedPressurePSI = reverseBlendingPressurePSI;
1725+
}
17171726
}
17181727
}
17191728
}

0 commit comments

Comments
 (0)