1 using System; 2 using System.Diagnostics; 3 using System.Runtime.InteropServices; 4 using System.ServiceModel; 5 using OpenBveApi.Hosts; 6 using OpenBveApi.Interop; 7 using OpenBveApi.Runtime; 8 using SoundManager; 9 using TrainManager.Trains; 10 11 namespace TrainManager.SafetySystems { 12 /// <summary>Represents a proxied legacy Win32 plugin.</summary> 13 internal class ProxyPlugin : Plugin, IAtsPluginCallback 14 { 15 /// <summary>The sound instructions on the previous frame</summary> 16 private readonly int[] LastSound; 17 /// <summary>The plugin proxy interface</summary> 18 private readonly IAtsPluginProxy pipeProxy; 19 /// <summary>The last error returned by the plugin</summary> 20 private string lastError; 21 /// <summary>Whether the external plugin proxy has encountered a critical error / crashed</summary> 22 private bool externalCrashed; 23 ProxyPlugin(string pluginFile, TrainBase train)24 internal ProxyPlugin(string pluginFile, TrainBase train) 25 { 26 externalCrashed = false; 27 PluginTitle = System.IO.Path.GetFileName(pluginFile); 28 //Load the plugin via the proxy callback 29 var handle = Process.GetCurrentProcess().MainWindowHandle; 30 try 31 { 32 var hostProcess = new Process(); 33 hostProcess.StartInfo.FileName = @"Win32PluginProxy.exe"; 34 hostProcess.Start(); 35 HostInterface.Win32PluginHostReady.WaitOne(); 36 pipeProxy = new DuplexChannelFactory<IAtsPluginProxy>(new InstanceContext(this), new NetNamedPipeBinding(), new EndpointAddress(HostInterface.Win32PluginHostEndpointAddress)).CreateChannel(); 37 pipeProxy.SetPluginFile(pluginFile, Process.GetCurrentProcess().Id); 38 SetForegroundWindow(handle.ToInt32()); 39 } 40 catch 41 { 42 //That didn't work 43 externalCrashed = true; 44 } 45 PluginValid = true; 46 PluginMessage = null; 47 Train = train; 48 Panel = new int[256]; 49 SupportsAI = AISupport.None; 50 switch (PluginTitle.ToLowerInvariant()) 51 { 52 case "ukdt.dll": 53 SupportsAI = AISupport.Program; 54 AI = new UKDtAI(this); 55 break; 56 case "ukspt.dll": 57 SupportsAI = AISupport.Program; 58 AI = new UKSptAI(this); 59 break; 60 case "ukmut.dll": 61 SupportsAI = AISupport.Program; 62 AI = new UKMUtAI(this); 63 break; 64 case "hei_ats.dll": 65 SupportsAI = AISupport.Program; 66 AI = new HeiAtsAI(this); 67 break; 68 } 69 LastTime = 0.0; 70 LastReverser = -2; 71 LastPowerNotch = -1; 72 LastBrakeNotch = -1; 73 LastAspects = new int[] { }; 74 LastSection = -1; 75 LastException = null; 76 Sound = new int[256]; 77 LastSound = new int[256]; 78 } 79 80 [DllImport("User32.dll")] SetForegroundWindow(int hWnd)81 public static extern Int32 SetForegroundWindow(int hWnd); 82 Load(VehicleSpecs specs, InitializationModes mode)83 public override bool Load(VehicleSpecs specs, InitializationModes mode) 84 { 85 if (externalCrashed) 86 { 87 //Most likely the plugin proxy app failed to launch or something 88 return false; 89 } 90 if (pipeProxy.Load(specs, mode)) 91 { 92 UpdatePower(); 93 UpdateBrake(); 94 UpdateReverser(); 95 return true; 96 } 97 return false; 98 } 99 Unload()100 public override void Unload() 101 { 102 pipeProxy.Unload(); 103 } 104 BeginJump(InitializationModes mode)105 public override void BeginJump(InitializationModes mode) 106 { 107 pipeProxy.BeginJump(mode); 108 if (SupportsAI == AISupport.Program) 109 { 110 AI.BeginJump(mode); 111 } 112 } 113 EndJump()114 public override void EndJump() 115 { 116 if (SupportsAI == AISupport.Program) 117 { 118 AI.EndJump(); 119 } 120 } 121 Elapse(ref ElapseData data)122 protected override void Elapse(ref ElapseData data) 123 { 124 if (externalCrashed) 125 { 126 //Yuck 127 for (int i = 0; i < Train.Cars[Train.DriverCar].Sounds.Plugin.Length; i++) 128 { 129 if (Train.Cars[Train.DriverCar].Sounds.Plugin[i].IsPlaying) 130 { 131 Train.Cars[Train.DriverCar].Sounds.Plugin[i].Stop(); 132 } 133 } 134 Train.UnloadPlugin(); 135 return; 136 } 137 if (!string.IsNullOrEmpty(lastError)) 138 { 139 140 //TrainManagercurrentHost.A("ERROR: The proxy plugin " + PluginFile + " generated the following error:"); 141 //Program.FileSystem.AppendToLogFile(pluginProxy.callback.lastError); 142 lastError = string.Empty; 143 } 144 145 try 146 { 147 ElapseProxy e = new ElapseProxy(data, Panel, Sound); 148 ElapseProxy proxyData = pipeProxy.Elapse(e); 149 Panel = proxyData.Panel; 150 Sound = proxyData.Sound; 151 for (int i = 0; i < Sound.Length; i++) 152 { 153 if (Sound[i] != LastSound[i]) 154 { 155 if (Sound[i] == SoundInstructions.Stop) 156 { 157 if (i < Train.Cars[Train.DriverCar].Sounds.Plugin.Length) 158 { 159 Train.Cars[Train.DriverCar].Sounds.Plugin[i].Stop(); 160 } 161 } 162 else if (Sound[i] > SoundInstructions.Stop & Sound[i] <= SoundInstructions.PlayLooping) 163 { 164 if (i < Train.Cars[Train.DriverCar].Sounds.Plugin.Length) 165 { 166 SoundBuffer buffer = Train.Cars[Train.DriverCar].Sounds.Plugin[i].Buffer; 167 if (buffer != null) 168 { 169 double volume = (double) (Sound[i] - SoundInstructions.Stop) / (SoundInstructions.PlayLooping - SoundInstructions.Stop); 170 if (Train.Cars[Train.DriverCar].Sounds.Plugin[i].IsPlaying) 171 { 172 Train.Cars[Train.DriverCar].Sounds.Plugin[i].Source.Volume = volume; 173 } 174 else 175 { 176 Train.Cars[Train.DriverCar].Sounds.Plugin[i].Play(1.0, volume, Train.Cars[Train.DriverCar], true); 177 } 178 } 179 } 180 } 181 else if (Sound[i] == SoundInstructions.PlayOnce) 182 { 183 if (i < Train.Cars[Train.DriverCar].Sounds.Plugin.Length) 184 { 185 SoundBuffer buffer = Train.Cars[Train.DriverCar].Sounds.Plugin[i].Buffer; 186 if (buffer != null) 187 { 188 Train.Cars[Train.DriverCar].Sounds.Plugin[i].Play(1.0, 1.0, Train.Cars[Train.DriverCar], false); 189 } 190 } 191 192 Sound[i] = SoundInstructions.Continue; 193 } 194 else if (Sound[i] != SoundInstructions.Continue) 195 { 196 PluginValid = false; 197 } 198 199 LastSound[i] = Sound[i]; 200 } 201 else 202 { 203 if ((Sound[i] < SoundInstructions.Stop | Sound[i] > SoundInstructions.PlayLooping) && Sound[i] != SoundInstructions.PlayOnce & Sound[i] != SoundInstructions.Continue) 204 { 205 PluginValid = false; 206 } 207 } 208 } 209 data = proxyData.Data; 210 } 211 catch 212 { 213 lastError = externalCrashed.ToString(); 214 externalCrashed = true; 215 } 216 } 217 SetReverser(int reverser)218 protected override void SetReverser(int reverser) 219 { 220 pipeProxy.SetReverser(reverser); 221 } 222 SetPower(int powerNotch)223 protected override void SetPower(int powerNotch) 224 { 225 pipeProxy.SetPowerNotch(powerNotch); 226 } 227 SetBrake(int brakeNotch)228 protected override void SetBrake(int brakeNotch) 229 { 230 pipeProxy.SetBrake(brakeNotch); 231 } 232 KeyDown(VirtualKeys key)233 public override void KeyDown(VirtualKeys key) 234 { 235 pipeProxy.KeyDown(key); 236 } 237 KeyUp(VirtualKeys key)238 public override void KeyUp(VirtualKeys key) 239 { 240 pipeProxy.KeyUp(key); 241 } 242 HornBlow(HornTypes type)243 public override void HornBlow(HornTypes type) 244 { 245 pipeProxy.HornBlow(type); 246 } 247 DoorChange(DoorStates oldState, DoorStates newState)248 public override void DoorChange(DoorStates oldState, DoorStates newState) 249 { 250 pipeProxy.DoorChange(oldState, newState); 251 } 252 SetSignal(SignalData[] signal)253 protected override void SetSignal(SignalData[] signal) 254 { 255 if (LastAspects.Length == 0 || signal[0].Aspect != LastAspects[0]) 256 { 257 pipeProxy.SetSignal(signal[0].Aspect); 258 } 259 } 260 SetBeacon(BeaconData beacon)261 protected override void SetBeacon(BeaconData beacon) 262 { 263 if (AI != null) 264 { 265 AI.SetBeacon(beacon); 266 } 267 pipeProxy.SetBeacon(beacon); 268 } 269 PerformAI(AIData data)270 protected override void PerformAI(AIData data) 271 { 272 if (SupportsAI == AISupport.Program) 273 { 274 AI.Perform(data); 275 } 276 } 277 ReportError(string Error, bool Critical = false)278 public void ReportError(string Error, bool Critical = false) 279 { 280 lastError = Error; 281 if (Critical) 282 { 283 externalCrashed = true; 284 } 285 } 286 KeepAlive()287 public override void KeepAlive() 288 { 289 pipeProxy.KeepAlive(); 290 } 291 } 292 } 293