1 using System;
2 using System.Collections.Generic;
3 using System.Diagnostics;
4 using System.Drawing;
5 using System.Linq;
6 using System.Runtime.InteropServices;
7 using System.Threading;
8 using OpenBveApi.Colors;
9 using OpenBveApi.Interface;
10 using OpenBveApi.Math;
11 using OpenBveApi.Objects;
12 using OpenBveApi.Routes;
13 using OpenBveApi.Textures;
14 using OpenBveApi.Trains;
15 using OpenBveApi.World;
16 using SoundHandle = OpenBveApi.Sounds.SoundHandle;
17 
18 namespace OpenBveApi.Hosts {
19 
20 	/* ----------------------------------------
21 	 * TODO: This part of the API is unstable.
22 	 *       Modifications can be made at will.
23 	 * ---------------------------------------- */
24 
25 	/// <summary>Represents the type of problem that is reported to the host.</summary>
26 	public enum ProblemType {
27 		/// <summary>Indicates that a file could not be found.</summary>
28 		FileNotFound = 1,
29 		/// <summary>Indicates that a directory could not be found.</summary>
30 		DirectoryNotFound = 2,
31 		/// <summary>Indicates that a file or directory could not be found.</summary>
32 		PathNotFound = 3,
33 		/// <summary>Indicates invalid data in a file or directory.</summary>
34 		InvalidData = 4,
35 		/// <summary>Indicates an invalid operation.</summary>
36 		InvalidOperation = 5,
37 		/// <summary>Indicates an unexpected exception.</summary>
38 		UnexpectedException = 6
39 	}
40 	/// <summary>The host application</summary>
41 	public enum HostApplication
42 	{
43 		/// <summary>The main game</summary>
44 		OpenBve = 0,
45 		/// <summary>Route Viewer</summary>
46 		RouteViewer = 1,
47 		/// <summary>Object Viewer</summary>
48 		ObjectViewer = 2,
49 		/// <summary>Train Editor</summary>
50 		TrainEditor = 3
51 	}
52 
53 	/// <summary>The host platform</summary>
54 	public enum HostPlatform
55 	{
56 		/// <summary>Microsoft Windows and compatabiles</summary>
57 		MicrosoftWindows = 0,
58 		/// <summary>Linux</summary>
59 		GNULinux = 1,
60 		/// <summary>Mac OS-X</summary>
61 		AppleOSX = 2,
62 		/// <summary>FreeBSD</summary>
63 		FreeBSD = 3
64 
65 	}
66 
67 	/// <summary>Represents the host application and functionality it exposes.</summary>
68 	public abstract partial class HostInterface {
69 
70 		/// <summary>Returns whether the current host application is running under Mono</summary>
71 		public bool MonoRuntime
72 		{
73 			get
74 			{
75 				return Type.GetType("Mono.Runtime") != null;
76 			}
77 		}
78 
79 		/// <summary>Returns the current host platform</summary>
80 		public HostPlatform Platform
81 		{
82 			get
83 			{
84 				if (Environment.OSVersion.Platform == PlatformID.Win32S | Environment.OSVersion.Platform == PlatformID.Win32Windows | Environment.OSVersion.Platform == PlatformID.Win32NT)
85 				{
86 					return HostPlatform.MicrosoftWindows;
87 				}
88 				if (System.IO.File.Exists(@"/System/Library/CoreServices/SystemVersion.plist"))
89 				{
90 					//Mono's platform detection doesn't reliably differentiate between OS-X and Unix
91 					return HostPlatform.AppleOSX;
92 				}
93 				string kernelName = DetectUnixKernel();
94 
95 				switch (kernelName)
96 				{
97 					case "Darwin":
98 						return HostPlatform.AppleOSX;
99 					case "FreeBSD":
100 						return HostPlatform.FreeBSD;
101 				}
102 
103 				return HostPlatform.GNULinux;
104 			}
105 		}
106 
107 		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
108 		private struct UName
109 		{
110 			[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
111 			public string sysname;
112 
113 			[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
114 			public string nodename;
115 
116 			[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
117 			public string release;
118 
119 			[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
120 			public string version;
121 
122 			[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
123 			public string machine;
124 
125 			[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1024)]
126 			public string extraJustInCase;
127 
128 		}
129 
130 		/// <summary>Detects the current kernel name by p/invoking uname (libc)</summary>
DetectUnixKernel()131 		private static string DetectUnixKernel()
132 		{
133 			Debug.Flush();
134 			UName uts;
135 			uname(out uts);
136 			return uts.sysname;
137 		}
138 
139 		[DllImport("libc")]
uname(out UName uname_struct)140 		private static extern void uname(out UName uname_struct);
141 
142 		/// <summary>The base host interface constructor</summary>
HostInterface(HostApplication host)143 		protected HostInterface(HostApplication host)
144 		{
145 			Application = host;
146 			StaticObjectCache = new Dictionary<ValueTuple<string, bool>, StaticObject>();
147 			AnimatedObjectCollectionCache = new Dictionary<string, AnimatedObjectCollection>();
148 			MissingFiles = new List<string>();
149 		}
150 
151 		/// <summary></summary>
152 		public readonly HostApplication Application;
153 
154 		/// <summary>Reports a problem to the host application.</summary>
155 		/// <param name="type">The type of problem that is reported.</param>
156 		/// <param name="text">The textual message that describes the problem.</param>
ReportProblem(ProblemType type, string text)157 		public virtual void ReportProblem(ProblemType type, string text) { }
158 
159 		/// <summary>Contains a list of missing files encountered</summary>
160 		public readonly List<string> MissingFiles;
161 
162 		/// <summary>Queries the dimensions of a texture.</summary>
163 		/// <param name="path">The path to the file or folder that contains the texture.</param>
164 		/// <param name="width">Receives the width of the texture.</param>
165 		/// <param name="height">Receives the height of the texture.</param>
166 		/// <returns>Whether querying the dimensions was successful.</returns>
QueryTextureDimensions(string path, out int width, out int height)167 		public virtual bool QueryTextureDimensions(string path, out int width, out int height) {
168 			width = 0;
169 			height = 0;
170 			return false;
171 		}
172 
173 		/// <summary>Loads a texture and returns the texture data.</summary>
174 		/// <param name="path">The path to the file or folder that contains the texture.</param>
175 		/// <param name="parameters">The parameters that specify how to process the texture.</param>
176 		/// <param name="texture">Receives the texture.</param>
177 		/// <returns>Whether loading the texture was successful.</returns>
LoadTexture(string path, TextureParameters parameters, out Textures.Texture texture)178 		public virtual bool LoadTexture(string path, TextureParameters parameters, out Textures.Texture texture) {
179 			texture = null;
180 			return false;
181 		}
182 
183 		/// <summary>Loads a texture and returns the texture data.</summary>
184 		/// <param name="texture">Receives the texture.</param>
185 		/// <param name="wrapMode">The openGL wrap mode</param>
186 		/// <returns>Whether loading the texture was successful.</returns>
LoadTexture(ref Texture texture, OpenGlTextureWrapMode wrapMode)187 		public virtual bool LoadTexture(ref Texture texture, OpenGlTextureWrapMode wrapMode) {
188 			return false;
189 		}
190 
191 		/// <summary>Registers a texture and returns a handle to the texture.</summary>
192 		/// <param name="path">The path to the file or folder that contains the texture.</param>
193 		/// <param name="parameters">The parameters that specify how to process the texture.</param>
194 		/// <param name="handle">Receives the handle to the texture.</param>
195 		/// <param name="loadTexture">Whether the texture should also be pre-loaded</param>
196 		/// <returns>Whether loading the texture was successful.</returns>
RegisterTexture(string path, TextureParameters parameters, out Textures.Texture handle, bool loadTexture = false)197 		public virtual bool RegisterTexture(string path, TextureParameters parameters, out Textures.Texture handle, bool loadTexture = false) {
198 			handle = null;
199 			return false;
200 		}
201 
202 		/// <summary>Registers a texture and returns a handle to the texture.</summary>
203 		/// <param name="texture">The texture data.</param>
204 		/// <param name="parameters">The parameters that specify how to process the texture.</param>
205 		/// <param name="handle">Receives the handle to the texture.</param>
206 		/// <returns>Whether loading the texture was successful.</returns>
RegisterTexture(Textures.Texture texture, TextureParameters parameters, out Textures.Texture handle)207 		public virtual bool RegisterTexture(Textures.Texture texture, TextureParameters parameters, out Textures.Texture handle) {
208 			handle = null;
209 			return false;
210 		}
211 
212 		/// <summary>Registers a texture and returns a handle to the texture.</summary>
213 		/// <param name="texture">The texture data.</param>
214 		/// <param name="parameters">The parameters that specify how to process the texture.</param>
215 		/// <param name="handle">Receives the handle to the texture.</param>
216 		/// <returns>Whether loading the texture was successful.</returns>
RegisterTexture(Bitmap texture, TextureParameters parameters, out Textures.Texture handle)217 		public virtual bool RegisterTexture(Bitmap texture, TextureParameters parameters, out Textures.Texture handle) {
218 			handle = null;
219 			return false;
220 		}
221 
222 		/// <summary>Loads a sound and returns the sound data.</summary>
223 		/// <param name="path">The path to the file or folder that contains the sound.</param>
224 		/// <param name="sound">Receives the sound.</param>
225 		/// <returns>Whether loading the sound was successful.</returns>
LoadSound(string path, out Sounds.Sound sound)226 		public virtual bool LoadSound(string path, out Sounds.Sound sound) {
227 			sound = null;
228 			return false;
229 		}
230 
231 		/// <summary>Registers a sound and returns a handle to the sound.</summary>
232 		/// <param name="path">The path to the file or folder that contains the sound.</param>
233 		/// <param name="handle">Receives a handle to the sound.</param>
234 		/// <returns>Whether loading the sound was successful.</returns>
RegisterSound(string path, out SoundHandle handle)235 		public virtual bool RegisterSound(string path, out SoundHandle handle) {
236 			handle = null;
237 			return false;
238 		}
239 
240 		/// <summary>Registers a sound and returns a handle to the sound.</summary>
241 		/// <param name="path">The path to the file or folder that contains the sound.</param>
242 		/// <param name="radius">The sound radius</param>
243 		/// <param name="handle">Receives a handle to the sound.</param>
244 		/// <returns>Whether loading the sound was successful.</returns>
RegisterSound(string path, double radius, out SoundHandle handle)245 		public virtual bool RegisterSound(string path, double radius, out SoundHandle handle)
246 		{
247 			handle = null;
248 			return false;
249 		}
250 
251 		/// <summary>Registers a sound and returns a handle to the sound.</summary>
252 		/// <param name="sound">The sound data.</param>
253 		/// <param name="handle">Receives a handle to the sound.</param>
254 		/// <returns>Whether loading the sound was successful.</returns>
RegisterSound(Sounds.Sound sound, out SoundHandle handle)255 		public virtual bool RegisterSound(Sounds.Sound sound, out SoundHandle handle) {
256 			handle = null;
257 			return false;
258 		}
259 
260 		/// <summary>
261 		/// Add an extension to the path of the object file that is missing the extension and no file.
262 		/// </summary>
263 		/// <param name="FilePath">The absolute on-disk path to the object</param>
264 		/// <returns>Whether the extension could be determined</returns>
DetermineObjectExtension(ref string FilePath)265 		public bool DetermineObjectExtension(ref string FilePath)
266 		{
267 			if (System.IO.File.Exists(FilePath) || System.IO.Path.HasExtension(FilePath))
268 			{
269 				return true;
270 			}
271 
272 			if (DetermineStaticObjectExtension(ref FilePath))
273 			{
274 				return true;
275 			}
276 
277 			foreach (string extension in SupportedAnimatedObjectExtensions)
278 			{
279 				string testPath = Path.CombineFile(System.IO.Path.GetDirectoryName(FilePath), $"{System.IO.Path.GetFileName(FilePath)}{extension}");
280 
281 				if (System.IO.File.Exists(testPath))
282 				{
283 					FilePath = testPath;
284 					return true;
285 				}
286 			}
287 
288 			return false;
289 		}
290 
291 		/// <summary>
292 		/// Add an extension to the path of the static object file that is missing the extension and no file.
293 		/// </summary>
294 		/// <param name="FilePath">The absolute on-disk path to the object</param>
295 		/// <returns>Whether the extension could be determined</returns>
DetermineStaticObjectExtension(ref string FilePath)296 		public bool DetermineStaticObjectExtension(ref string FilePath)
297 		{
298 			if (System.IO.File.Exists(FilePath) || System.IO.Path.HasExtension(FilePath))
299 			{
300 				return true;
301 			}
302 
303 			// Search in the order of .x, .csv, .b3d, etc.
304 			foreach (string extension in SupportedStaticObjectExtensions.OrderByDescending(x => Array.IndexOf(new[] { ".b3d", ".csv", ".x" }, x)))
305 			{
306 				string testPath = Path.CombineFile(System.IO.Path.GetDirectoryName(FilePath), $"{System.IO.Path.GetFileName(FilePath)}{extension}");
307 
308 				if (System.IO.File.Exists(testPath))
309 				{
310 					FilePath = testPath;
311 					return true;
312 				}
313 			}
314 
315 			return false;
316 		}
317 
318 		/// <summary>Loads an object</summary>
319 		/// <param name="Path">The absolute on-disk path to the object</param>
320 		/// <param name="Encoding">The detected text encoding</param>
321 		/// <param name="Object">The handle to the object</param>
322 		/// <returns>Whether loading the object was successful</returns>
LoadObject(string Path, System.Text.Encoding Encoding, out UnifiedObject Object)323 		public virtual bool LoadObject(string Path, System.Text.Encoding Encoding, out UnifiedObject Object)
324 		{
325 			ValueTuple<string, bool> key = ValueTuple.Create(Path, false);
326 
327 			if (StaticObjectCache.ContainsKey(key))
328 			{
329 				Object = StaticObjectCache[key].Clone();
330 				return true;
331 			}
332 
333 			if (AnimatedObjectCollectionCache.ContainsKey(Path))
334 			{
335 				Object = AnimatedObjectCollectionCache[Path].Clone();
336 				return true;
337 			}
338 
339 			Object = null;
340 			return false;
341 		}
342 
343 		/// <summary>Loads a static object</summary>
344 		/// <param name="Path">The absolute on-disk path to the object</param>
345 		/// <param name="Encoding">The detected text encoding</param>
346 		/// <param name="PreserveVertices">Whether optimization is to be performed on the object</param>
347 		/// <param name="Object">The handle to the object</param>
348 		/// <returns>Whether loading the object was successful</returns>
349 		/// <remarks>This will return false if an animated object is attempted to be loaded.
350 		/// Selecting to preserve vertices may be useful if using the object as a deformable.</remarks>
LoadStaticObject(string Path, System.Text.Encoding Encoding, bool PreserveVertices, out StaticObject Object)351 		public virtual bool LoadStaticObject(string Path, System.Text.Encoding Encoding, bool PreserveVertices, out StaticObject Object)
352 		{
353 			ValueTuple<string, bool> key = ValueTuple.Create(Path, PreserveVertices);
354 
355 			if (StaticObjectCache.ContainsKey(key))
356 			{
357 				Object = (StaticObject)StaticObjectCache[key].Clone();
358 				return true;
359 			}
360 
361 			Object = null;
362 			return false;
363 		}
364 
365 		/// <summary>Executes a function script in the host application</summary>
366 		/// <param name="functionScript">The function script to execute</param>
367 		/// <param name="train">The train or a null reference</param>
368 		/// <param name="CarIndex">The car index</param>
369 		/// <param name="Position">The world position</param>
370 		/// <param name="TrackPosition">The linear track position</param>
371 		/// <param name="SectionIndex">The index to the signalling section</param>
372 		/// <param name="IsPartOfTrain">Whether this is part of a train</param>
373 		/// <param name="TimeElapsed">The frame time elapsed</param>
374 		/// <param name="CurrentState">The current state of the attached object</param>
ExecuteFunctionScript(FunctionScripting.FunctionScript functionScript, AbstractTrain train, int CarIndex, Vector3 Position, double TrackPosition, int SectionIndex, bool IsPartOfTrain, double TimeElapsed, int CurrentState)375 		public virtual void ExecuteFunctionScript(FunctionScripting.FunctionScript functionScript, AbstractTrain train, int CarIndex, Vector3 Position, double TrackPosition, int SectionIndex, bool IsPartOfTrain, double TimeElapsed, int CurrentState) { }
376 
377 		/// <summary>Creates a static object within the world of the host application, and returns the ObjectManager ID</summary>
378 		/// <param name="Prototype">The prototype (un-transformed) static object</param>
379 		/// <param name="Position">The world position</param>
380 		/// <param name="WorldTransformation">The world transformation to apply (e.g. ground, rail)</param>
381 		/// <param name="LocalTransformation">The local transformation to apply in order to rotate the model</param>
382 		/// <param name="AccurateObjectDisposalZOffset">The offset for accurate Z-disposal</param>
383 		/// <param name="StartingDistance">The absolute route based starting distance for the object</param>
384 		/// <param name="EndingDistance">The absolute route based ending distance for the object</param>
385 		/// <param name="TrackPosition">The absolute route based track position</param>
386 		/// <param name="Brightness">The brightness value at this track position</param>
387 		/// <returns>The index to the created object, or -1 if this call fails</returns>
CreateStaticObject(StaticObject Prototype, Vector3 Position, Transformation WorldTransformation, Transformation LocalTransformation, double AccurateObjectDisposalZOffset, double StartingDistance, double EndingDistance, double TrackPosition, double Brightness)388 		public virtual int CreateStaticObject(StaticObject Prototype, Vector3 Position, Transformation WorldTransformation, Transformation LocalTransformation, double AccurateObjectDisposalZOffset, double StartingDistance, double EndingDistance, double TrackPosition, double Brightness)
389 		{
390 			return -1;
391 		}
392 
393 		/// <summary>Creates a static object within the world of the host application, and returns the ObjectManager ID</summary>
394 		/// <param name="Prototype">The prototype (un-transformed) static object</param>
395 		/// <param name="LocalTransformation">
396 		/// <para>The local transformation to apply in order to rotate the model</para>
397 		/// <para>NOTE: Only used for object disposal calcs</para>
398 		/// </param>
399 		/// <param name="Rotate">The rotation matrix to apply</param>
400 		/// <param name="Translate">The translation matrix to apply</param>
401 		/// <param name="AccurateObjectDisposalZOffset">The offset for accurate Z-disposal</param>
402 		/// <param name="StartingDistance">The absolute route based starting distance for the object</param>
403 		/// <param name="EndingDistance">The absolute route based ending distance for the object</param>
404 		/// <param name="TrackPosition">The absolute route based track position</param>
405 		/// <param name="Brightness">The brightness value at this track position</param>
406 		/// <returns>The index to the created object, or -1 if this call fails</returns>
CreateStaticObject(StaticObject Prototype, Transformation LocalTransformation, Matrix4D Rotate, Matrix4D Translate, double AccurateObjectDisposalZOffset, double StartingDistance, double EndingDistance, double TrackPosition, double Brightness)407 		public virtual int CreateStaticObject(StaticObject Prototype, Transformation LocalTransformation, Matrix4D Rotate, Matrix4D Translate, double AccurateObjectDisposalZOffset, double StartingDistance, double EndingDistance, double TrackPosition, double Brightness)
408 		{
409 			return -1;
410 		}
411 
412 		/// <summary>Creates a dynamic object</summary>
413 		/// <param name="internalObject">The internal static object to be updated</param>
414 		/// <returns>The index of the dynamic object</returns>
CreateDynamicObject(ref ObjectState internalObject)415 		public virtual void CreateDynamicObject(ref ObjectState internalObject)
416 		{
417 
418 		}
419 
420 		/// <summary>Adds an object with a custom timetable texture</summary>
AddObjectForCustomTimeTable(AnimatedObject animatedObject)421 		public virtual void AddObjectForCustomTimeTable(AnimatedObject animatedObject)
422 		{
423 
424 		}
425 
426 		/// <summary>Shows an object in the base renderer</summary>
427 		/// <param name="objectToShow">The reference to the object to show</param>
428 		/// <param name="objectType">The object type</param>
ShowObject(ObjectState objectToShow, ObjectType objectType)429 		public virtual void ShowObject(ObjectState objectToShow, ObjectType objectType)
430 		{
431 
432 		}
433 
434 		/// <summary>Hides an object in the base renderer</summary>
435 		/// <param name="objectToHide">The reference to the object to hide</param>
HideObject(ObjectState objectToHide)436 		public virtual void HideObject(ObjectState objectToHide)
437 		{
438 
439 		}
440 
441 		/// <summary>Adds a log message to the host application.</summary>
442 		/// <param name="type">The type of message to be reported.</param>
443 		/// <param name="FileNotFound">Whether this message relates to a file not found</param>
444 		/// <param name="text">The textual message.</param>
AddMessage(MessageType type, bool FileNotFound, string text)445 		public virtual void AddMessage(MessageType type, bool FileNotFound, string text) { }
446 
447 		/// <summary>Adds a fully constructed message to the in-game display</summary>
448 		/// <param name="AbstractMessage">The message to add</param>
AddMessage(object AbstractMessage)449 		public virtual void AddMessage(object AbstractMessage)
450 		{
451 			/*
452 			 * Using object as a parameter type allows us to keep the messages out the API...
453 			 */
454 
455 		}
456 
457 		///  <summary>Adds a message to the in-game display</summary>
458 		/// <param name="Message">The text of the message</param>
459 		///  <param name="MessageDependancy">The dependancy of the message</param>
460 		///  <param name="Mode">The required game mode for the message to display</param>
461 		///  <param name="MessageColor">The color of the message font</param>
462 		///  <param name="MessageTimeOut">The timeout of the message</param>
463 		///  <param name="Key">The mesage key</param>
AddMessage(string Message, object MessageDependancy, GameMode Mode, MessageColor MessageColor, double MessageTimeOut, string Key)464 		public virtual void AddMessage(string Message, object MessageDependancy, GameMode Mode, MessageColor MessageColor, double MessageTimeOut, string Key)
465 		{
466 
467 		}
468 
469 		/// <summary>Checks whether the specified sound source is playing</summary>
SoundIsPlaying(object SoundSource)470 		public virtual bool SoundIsPlaying(object SoundSource)
471 		{
472 			return false;
473 		}
474 
475 		/// <summary>Plays a sound.</summary>
476 		/// <param name="buffer">The sound buffer.</param>
477 		/// <param name="pitch">The pitch change factor.</param>
478 		/// <param name="volume">The volume change factor.</param>
479 		/// <param name="position">The position. If a train car is specified, the position is relative to the car, otherwise absolute.</param>
480 		/// <param name="parent">The parent object the sound is attached to, or a null reference.</param>
481 		/// <param name="looped">Whether to play the sound in a loop.</param>
482 		/// <returns>The sound source.</returns>
PlaySound(SoundHandle buffer, double pitch, double volume, OpenBveApi.Math.Vector3 position, object parent, bool looped)483 		public virtual object PlaySound(SoundHandle buffer, double pitch, double volume, OpenBveApi.Math.Vector3 position, object parent, bool looped)
484 		{
485 			return null;
486 		}
487 
488 		/// <summary>Register the position to play microphone input.</summary>
489 		/// <param name="position">The position.</param>
490 		/// <param name="backwardTolerance">allowed tolerance in the backward direction</param>
491 		/// <param name="forwardTolerance">allowed tolerance in the forward direction</param>
PlayMicSound(OpenBveApi.Math.Vector3 position, double backwardTolerance, double forwardTolerance)492 		public virtual void PlayMicSound(OpenBveApi.Math.Vector3 position, double backwardTolerance, double forwardTolerance)
493 		{
494 
495 		}
496 
497 		/// <summary>Stops a playing sound source</summary>
StopSound(object SoundSource)498 		public virtual void StopSound(object SoundSource)
499 		{
500 
501 		}
502 
503 		/// <summary>Stops all sounds with the specified parent object</summary>
504 		/// <param name="parent">The parent object</param>
StopAllSounds(object parent)505 		public virtual void StopAllSounds(object parent)
506 		{
507 
508 		}
509 
510 		/// <summary>Returns the current simulation state</summary>
511 		public virtual SimulationState SimulationState => SimulationState.Running;
512 
513 		/// <summary>Returns the number of animated world objects used</summary>
514 		public virtual int AnimatedWorldObjectsUsed
515 		{
516 			get
517 			{
518 				return 0;
519 			}
520 			// ReSharper disable once ValueParameterNotUsed
521 			set
522 			{
523 
524 			}
525 		}
526 
527 		/// <summary>Returns the array of animated world objects from the host</summary>
528 		public virtual WorldObject[] AnimatedWorldObjects
529 		{
530 			get
531 			{
532 				return null;
533 			}
534 			// ReSharper disable once ValueParameterNotUsed
535 			set
536 			{
537 
538 			}
539 		}
540 
541 		/// <summary>Gets or sets the tracks array within the host application</summary>
542 		public virtual Dictionary<int, Track> Tracks
543 		{
544 			get
545 			{
546 				return null;
547 			}
548 			// ReSharper disable once ValueParameterNotUsed
549 			set
550 			{
551 
552 			}
553 		}
554 
555 		/// <summary>Updates the custom timetable texture displayed when triggered by an event</summary>
556 		/// <param name="Daytime">The daytime texture</param>
557 		/// <param name="Nighttime">The nighttime texture</param>
UpdateCustomTimetable(Textures.Texture Daytime, Textures.Texture Nighttime)558 		public virtual void UpdateCustomTimetable(Textures.Texture Daytime, Textures.Texture Nighttime)
559 		{
560 
561 		}
562 
563 		/// <summary>Loads a track following object via the host program</summary>
564 		/// <param name="objectPath">The path to the object directory</param>
565 		/// /// <param name="tfoFile">The TFO parameters file</param>
566 		/// <returns>The track following object</returns>
ParseTrackFollowingObject(string objectPath, string tfoFile)567 		public abstract AbstractTrain ParseTrackFollowingObject(string objectPath, string tfoFile);
568 
569 		/// <summary>The list of available content loading plugins</summary>
570 		public ContentLoadingPlugin[] Plugins;
571 
572 		/// <summary>The total number of available route loading plugins</summary>
573 		public int AvailableRoutePluginCount => Plugins.Count(x => x.Route != null);
574 
575 		/// <summary>The total number of available object loading plugins</summary>
576 		public int AvailableObjectPluginCount => Plugins.Count(x => x.Object != null);
577 
578 		/// <summary>The total number of available sound loading plugins</summary>
579 		public int AvailableSoundPluginCount => Plugins.Count(x => x.Sound != null);
580 
581 		/// <summary>
582 		/// Array of supported animated object extensions.
583 		/// </summary>
584 		public string[] SupportedAnimatedObjectExtensions => Plugins.Where(x => x.Object != null).SelectMany(x => x.Object.SupportedAnimatedObjectExtensions).ToArray();
585 
586 		/// <summary>
587 		/// Array of supported static object extensions.
588 		/// </summary>
589 		public string[] SupportedStaticObjectExtensions => Plugins.Where(x => x.Object != null).SelectMany(x => x.Object.SupportedStaticObjectExtensions).ToArray();
590 
591 		/// <summary>
592 		/// Dictionary of StaticObject with Path and PreserveVertices as keys.
593 		/// </summary>
594 		public readonly Dictionary<ValueTuple<string, bool>, StaticObject> StaticObjectCache;
595 
596 		/// <summary>
597 		/// Dictionary of AnimatedObjectCollection with Path as key.
598 		/// </summary>
599 
600 		public readonly Dictionary<string, AnimatedObjectCollection> AnimatedObjectCollectionCache;
601 
602 		/// <summary>Adds a marker texture to the host application's display</summary>
603 		/// <param name="MarkerTexture">The texture to add</param>
AddMarker(Texture MarkerTexture)604 		public virtual void AddMarker(Texture MarkerTexture)
605 		{
606 
607 		}
608 
609 		/// <summary>Removes a marker texture if present in the host application's display</summary>
610 		/// <param name="MarkerTexture">The texture to remove</param>
RemoveMarker(Texture MarkerTexture)611 		public virtual void RemoveMarker(Texture MarkerTexture)
612 		{
613 
614 		}
615 
616 		/// <summary>Called when a follower reaches the end of the world</summary>
CameraAtWorldEnd()617 		public virtual void CameraAtWorldEnd()
618 		{
619 
620 		}
621 
622 		/// <summary>Gets the current in-game time</summary>
623 		/// <returns>The time in seconds since midnight on the first day</returns>
624 		public virtual double InGameTime => 0.0;
625 
626 		/// <summary>Adds an entry to the in-game black box recorder</summary>
AddBlackBoxEntry()627 		public virtual void AddBlackBoxEntry()
628 		{
629 
630 		}
631 
632 		/// <summary>Processes a jump</summary>
633 		/// <param name="Train">The train to be jumped</param>
634 		/// <param name="StationIndex">The station to jump to</param>
ProcessJump(AbstractTrain Train, int StationIndex)635 		public virtual void ProcessJump(AbstractTrain Train, int StationIndex)
636 		{
637 
638 		}
639 
640 		/// <summary>May be called from a .Net plugin, in order to add a score to the post-game log</summary>
641 		/// <param name="Score">The score to add</param>
642 		/// <param name="Message">The message to display in the post-game log</param>
643 		/// <param name="Color">The color of the in-game message</param>
644 		/// <param name="Timeout">The time in seconds for which to display the in-game message</param>
AddScore(int Score, string Message, MessageColor Color, double Timeout)645 		public virtual void AddScore(int Score, string Message, MessageColor Color, double Timeout)
646 		{
647 
648 		}
649 
650 		/// <summary>Returns the trains within the simulation</summary>
651 		public virtual AbstractTrain[] Trains
652 		{
653 			get
654 			{
655 				return null;
656 			}
657 		}
658 
659 		/// <summary>Gets the closest train to the specified train</summary>
660 		/// <param name="Train">The specified train</param>
661 		/// <returns>The closest train, or null if no other trains</returns>
ClosestTrain(AbstractTrain Train)662 		public virtual AbstractTrain ClosestTrain(AbstractTrain Train)
663 		{
664 			return null;
665 		}
666 
667 		/// <summary>Gets the closest train to the specified track location</summary>
668 		/// <param name="TrackPosition">The specified track position</param>
669 		/// <returns>The closest train, or null if no other trains</returns>
ClosestTrain(double TrackPosition)670 		public virtual AbstractTrain ClosestTrain(double TrackPosition)
671 		{
672 			return null;
673 		}
674 
675 		/*
676 		 * Used for interop with the 32-bit plugin host
677 		 */
678 
679 		/// <summary>The event raised when the 32-bit host application signals it is ready to accept connections from clients</summary>
680 		public static readonly EventWaitHandle Win32PluginHostReady = new EventWaitHandle(false, EventResetMode.AutoReset, @"eventHostReady");
681 
682 		/// <summary>The event raised when the proxy client quits and the host should stop</summary>
683 		public static readonly EventWaitHandle Win32PluginHostStopped = new EventWaitHandle(false, EventResetMode.AutoReset, @"eventHostShouldStop");
684 
685 		/// <summary>The base pipe address</summary>
686 		public const string pipeBaseAddress = @"net.pipe://localhost";
687 
688 		/// <summary>Pipe name</summary>
689 		public const string pipeName = @"pipename";
690 
691 		/// <summary>Base addresses for the hosted service.</summary>
692 		public static Uri baseAddress { get { return new Uri(pipeBaseAddress); } }
693 
694 		/// <summary>Complete address of the named pipe endpoint.</summary>
695 		public static Uri Win32PluginHostEndpointAddress { get { return new Uri(pipeBaseAddress + '/' + pipeName); } }
696 	}
697 }
698