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