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