1 using System; 2 using System.Collections.Generic; 3 using System.Drawing; 4 using System.IO; 5 using LibRender2.Screens; 6 using OpenBveApi; 7 using OpenBveApi.Colors; 8 using OpenBveApi.Hosts; 9 using OpenBveApi.Interface; 10 using OpenBveApi.Math; 11 using OpenBveApi.Objects; 12 using OpenBveApi.Routes; 13 using OpenBveApi.Sounds; 14 using OpenBveApi.Textures; 15 using OpenBveApi.Trains; 16 using OpenBveApi.World; 17 using RouteManager2.MessageManager; 18 using SoundManager; 19 using TrainManager.Trains; 20 21 namespace OpenBve { 22 /// <summary>Represents the host application.</summary> 23 internal class Host : HostInterface { 24 25 // --- functions --- 26 27 /// <summary>Reports a problem to the host application.</summary> 28 /// <param name="type">The type of problem that is reported.</param> 29 /// <param name="text">The textual message that describes the problem.</param> ReportProblem(ProblemType type, string text)30 public override void ReportProblem(ProblemType type, string text) { 31 switch (type) 32 { 33 case ProblemType.DirectoryNotFound: 34 case ProblemType.FileNotFound: 35 case ProblemType.PathNotFound: 36 if (!MissingFiles.Contains(text)) 37 { 38 Interface.AddMessage(MessageType.Error, true, type + " : " + text); 39 MissingFiles.Add(text); 40 } 41 break; 42 default: 43 Interface.AddMessage(MessageType.Error, false, type + " : " + text); 44 break; 45 } 46 } 47 AddMessage(MessageType type, bool FileNotFound, string text)48 public override void AddMessage(MessageType type, bool FileNotFound, string text) 49 { 50 Interface.AddMessage(type, FileNotFound, text); 51 } 52 AddMessage(object Message)53 public override void AddMessage(object Message) 54 { 55 MessageManager.AddMessage((AbstractMessage)Message); 56 } 57 AddMessage(string Message, object MessageDependancy, GameMode Mode, MessageColor MessageColor, double MessageTimeOut, string Key)58 public override void AddMessage(string Message, object MessageDependancy, GameMode Mode, MessageColor MessageColor, double MessageTimeOut, string Key) 59 { 60 MessageManager.AddMessage(Message, (MessageDependency)MessageDependancy, Mode, MessageColor, MessageTimeOut, Key); 61 } 62 63 // --- texture --- 64 65 /// <summary>Queries the dimensions of a texture.</summary> 66 /// <param name="path">The path to the file or folder that contains the texture.</param> 67 /// <param name="width">Receives the width of the texture.</param> 68 /// <param name="height">Receives the height of the texture.</param> 69 /// <returns>Whether querying the dimensions was successful.</returns> QueryTextureDimensions(string path, out int width, out int height)70 public override bool QueryTextureDimensions(string path, out int width, out int height) { 71 if (File.Exists(path) || Directory.Exists(path)) { 72 for (int i = 0; i < Program.CurrentHost.Plugins.Length; i++) { 73 if (Program.CurrentHost.Plugins[i].Texture != null) { 74 try { 75 if (Program.CurrentHost.Plugins[i].Texture.CanLoadTexture(path)) { 76 try { 77 if (Program.CurrentHost.Plugins[i].Texture.QueryTextureDimensions(path, out width, out height)) { 78 return true; 79 } 80 Interface.AddMessage(MessageType.Error, false, 81 "Plugin " + Program.CurrentHost.Plugins[i].Title + " returned unsuccessfully at QueryTextureDimensions" 82 ); 83 } catch (Exception ex) { 84 Interface.AddMessage(MessageType.Error, false, 85 "Plugin " + Program.CurrentHost.Plugins[i].Title + " raised the following exception at QueryTextureDimensions:" + ex.Message 86 ); 87 } 88 } 89 } catch (Exception ex) { 90 Interface.AddMessage(MessageType.Error, false, 91 "Plugin " + Program.CurrentHost.Plugins[i].Title + " raised the following exception at CanLoadTexture:" + ex.Message 92 ); 93 } 94 } 95 } 96 FileInfo f = new FileInfo(path); 97 if (f.Length == 0) 98 { 99 Interface.AddMessage(MessageType.Error, false, "Zero-byte texture file encountered at " + path); 100 } 101 else 102 { 103 Interface.AddMessage(MessageType.Error, false, "No plugin found that is capable of loading texture " + path); 104 } 105 } else { 106 ReportProblem(ProblemType.PathNotFound, path); 107 } 108 width = 0; 109 height = 0; 110 return false; 111 } 112 113 /// <summary>Loads a texture and returns the texture data.</summary> 114 /// <param name="path">The path to the file or folder that contains the texture.</param> 115 /// <param name="parameters">The parameters that specify how to process the texture.</param> 116 /// <param name="texture">Receives the texture.</param> 117 /// <returns>Whether loading the texture was successful.</returns> LoadTexture(string path, TextureParameters parameters, out Texture texture)118 public override bool LoadTexture(string path, TextureParameters parameters, out Texture texture) { 119 if (File.Exists(path) || Directory.Exists(path)) { 120 for (int i = 0; i < Program.CurrentHost.Plugins.Length; i++) { 121 if (Program.CurrentHost.Plugins[i].Texture != null) { 122 try { 123 if (Program.CurrentHost.Plugins[i].Texture.CanLoadTexture(path)) { 124 try { 125 if (Program.CurrentHost.Plugins[i].Texture.LoadTexture(path, out texture)) { 126 texture.CompatibleTransparencyMode = Interface.CurrentOptions.OldTransparencyMode; 127 texture = texture.ApplyParameters(parameters); 128 return true; 129 } 130 Interface.AddMessage(MessageType.Error, false, "Plugin " + Program.CurrentHost.Plugins[i].Title + " returned unsuccessfully at LoadTexture"); 131 } catch (Exception ex) { 132 Interface.AddMessage(MessageType.Error, false, "Plugin " + Program.CurrentHost.Plugins[i].Title + " raised the following exception at LoadTexture:" + ex.Message); 133 } 134 } 135 } catch (Exception ex) { 136 Interface.AddMessage(MessageType.Error, false, "Plugin " + Program.CurrentHost.Plugins[i].Title + " raised the following exception at CanLoadTexture:" + ex.Message); 137 } 138 } 139 } 140 FileInfo f = new FileInfo(path); 141 if (f.Length == 0) 142 { 143 Interface.AddMessage(MessageType.Error, false, "Zero-byte texture file encountered at " + path); 144 } 145 else 146 { 147 Interface.AddMessage(MessageType.Error, false, "No plugin found that is capable of loading texture " + path); 148 } 149 } else { 150 ReportProblem(ProblemType.PathNotFound, path); 151 } 152 texture = null; 153 return false; 154 } 155 LoadTexture(ref Texture Texture, OpenGlTextureWrapMode wrapMode)156 public override bool LoadTexture(ref Texture Texture, OpenGlTextureWrapMode wrapMode) 157 { 158 return Program.Renderer.TextureManager.LoadTexture(ref Texture, wrapMode, CPreciseTimer.GetClockTicks(), Interface.CurrentOptions.Interpolation, Interface.CurrentOptions.AnisotropicFilteringLevel); 159 } 160 161 /// <summary>Registers a texture and returns a handle to the texture.</summary> 162 /// <param name="path">The path to the file or folder that contains the texture.</param> 163 /// <param name="parameters">The parameters that specify how to process the texture.</param> 164 /// <param name="handle">Receives the handle to the texture.</param> 165 /// <param name="loadTexture">Whether the texture is to be pre-loaded</param> 166 /// <returns>Whether loading the texture was successful.</returns> RegisterTexture(string path, TextureParameters parameters, out Texture handle, bool loadTexture = false)167 public override bool RegisterTexture(string path, TextureParameters parameters, out Texture handle, bool loadTexture = false) { 168 if (File.Exists(path) || Directory.Exists(path)) { 169 Texture data; 170 if (Program.Renderer.TextureManager.RegisterTexture(path, parameters, out data)) { 171 handle = data; 172 if (loadTexture) 173 { 174 OpenBVEGame.RunInRenderThread(() => 175 { 176 LoadTexture(ref data, OpenGlTextureWrapMode.ClampClamp); 177 }); 178 179 } 180 return true; 181 } 182 } else { 183 ReportProblem(ProblemType.PathNotFound, path); 184 } 185 handle = null; 186 return false; 187 } 188 189 /// <summary>Registers a texture and returns a handle to the texture.</summary> 190 /// <param name="texture">The texture data.</param> 191 /// <param name="parameters">The parameters that specify how to process the texture.</param> 192 /// <param name="handle">Receives the handle to the texture.</param> 193 /// <returns>Whether loading the texture was successful.</returns> RegisterTexture(Texture texture, TextureParameters parameters, out Texture handle)194 public override bool RegisterTexture(Texture texture, TextureParameters parameters, out Texture handle) { 195 texture = texture.ApplyParameters(parameters); 196 handle = Program.Renderer.TextureManager.RegisterTexture(texture); 197 return true; 198 } 199 RegisterTexture(Bitmap texture, TextureParameters parameters, out Texture handle)200 public override bool RegisterTexture(Bitmap texture, TextureParameters parameters, out Texture handle) 201 { 202 handle = new Texture(texture, parameters); 203 return true; 204 } 205 206 // --- sound --- 207 208 /// <summary>Loads a sound and returns the sound data.</summary> 209 /// <param name="path">The path to the file or folder that contains the sound.</param> 210 /// <param name="sound">Receives the sound.</param> 211 /// <returns>Whether loading the sound was successful.</returns> LoadSound(string path, out Sound sound)212 public override bool LoadSound(string path, out Sound sound) { 213 if (File.Exists(path) || Directory.Exists(path)) { 214 for (int i = 0; i < Program.CurrentHost.Plugins.Length; i++) { 215 if (Program.CurrentHost.Plugins[i].Sound != null) { 216 try { 217 if (Program.CurrentHost.Plugins[i].Sound.CanLoadSound(path)) { 218 try { 219 if (Program.CurrentHost.Plugins[i].Sound.LoadSound(path, out sound)) { 220 return true; 221 } 222 Interface.AddMessage(MessageType.Error, false, "Plugin " + Program.CurrentHost.Plugins[i].Title + " returned unsuccessfully at LoadSound"); 223 } catch (Exception ex) { 224 Interface.AddMessage(MessageType.Error, false, "Plugin " + Program.CurrentHost.Plugins[i].Title + " raised the following exception at LoadSound:" + ex.Message); 225 } 226 } 227 } catch (Exception ex) { 228 Interface.AddMessage(MessageType.Error, false, "Plugin " + Program.CurrentHost.Plugins[i].Title + " raised the following exception at CanLoadSound:" + ex.Message); 229 } 230 } 231 } 232 Interface.AddMessage(MessageType.Error, false, "No plugin found that is capable of loading sound " + path); 233 } else { 234 ReportProblem(ProblemType.PathNotFound, path); 235 } 236 sound = null; 237 return false; 238 } 239 240 241 /// <summary>Registers a sound and returns a handle to the sound.</summary> 242 /// <param name="path">The path to the file or folder that contains the sound.</param> 243 /// <param name="handle">Receives a handle to the sound.</param> 244 /// <returns>Whether loading the sound was successful.</returns> RegisterSound(string path, out SoundHandle handle)245 public override bool RegisterSound(string path, out SoundHandle handle) 246 { 247 if (File.Exists(path) || Directory.Exists(path)) 248 { 249 handle = Program.Sounds.RegisterBuffer(path, 0.0); 250 return true; 251 } 252 ReportProblem(ProblemType.PathNotFound, path); 253 handle = null; 254 return false; 255 } 256 257 /// <summary>Registers a sound and returns a handle to the sound.</summary> 258 /// <param name="path">The path to the file or folder that contains the sound.</param> 259 /// /// <param name="radius">The sound radius</param> 260 /// <param name="handle">Receives a handle to the sound.</param> 261 /// <returns>Whether loading the sound was successful.</returns> RegisterSound(string path, double radius, out SoundHandle handle)262 public override bool RegisterSound(string path, double radius, out SoundHandle handle) 263 { 264 if (File.Exists(path) || Directory.Exists(path)) 265 { 266 handle = Program.Sounds.RegisterBuffer(path, radius); 267 return true; 268 } 269 ReportProblem(ProblemType.PathNotFound, path); 270 handle = null; 271 return false; 272 } 273 274 /// <summary>Registers a sound and returns a handle to the sound.</summary> 275 /// <param name="sound">The sound data.</param> 276 /// <param name="handle">Receives a handle to the sound.</param> 277 /// <returns>Whether loading the sound was successful.</returns> RegisterSound(Sound sound, out SoundHandle handle)278 public override bool RegisterSound(Sound sound, out SoundHandle handle) 279 { 280 handle = Program.Sounds.RegisterBuffer(sound, 0.0); 281 return true; 282 } 283 LoadStaticObject(string path, System.Text.Encoding Encoding, bool PreserveVertices, out StaticObject Object)284 public override bool LoadStaticObject(string path, System.Text.Encoding Encoding, bool PreserveVertices, out StaticObject Object) 285 { 286 if (base.LoadStaticObject(path, Encoding, PreserveVertices, out Object)) 287 { 288 return true; 289 } 290 291 if (File.Exists(path) || Directory.Exists(path)) { 292 Encoding = TextEncoding.GetSystemEncodingFromFile(path, Encoding); 293 294 for (int i = 0; i < Program.CurrentHost.Plugins.Length; i++) { 295 if (Program.CurrentHost.Plugins[i].Object != null) { 296 try { 297 if (Program.CurrentHost.Plugins[i].Object.CanLoadObject(path)) { 298 try { 299 UnifiedObject unifiedObject; 300 if (Program.CurrentHost.Plugins[i].Object.LoadObject(path, Encoding, out unifiedObject)) { 301 StaticObject staticObject = unifiedObject as StaticObject; 302 if (staticObject != null) 303 { 304 staticObject.OptimizeObject(PreserveVertices, Interface.CurrentOptions.ObjectOptimizationBasicThreshold, Interface.CurrentOptions.ObjectOptimizationVertexCulling); 305 Object = staticObject; 306 StaticObjectCache.Add(ValueTuple.Create(path, PreserveVertices), Object); 307 return true; 308 } 309 310 Object = null; 311 Interface.AddMessage(MessageType.Error, false, "Attempted to load " + path + " which is an animated object where only static objects are allowed."); 312 } 313 Interface.AddMessage(MessageType.Error, false, "Plugin " + Program.CurrentHost.Plugins[i].Title + " returned unsuccessfully at LoadObject"); 314 } catch (Exception ex) { 315 Interface.AddMessage(MessageType.Error, false, "Plugin " + Program.CurrentHost.Plugins[i].Title + " raised the following exception at LoadObject:" + ex.Message); 316 } 317 } 318 } catch (Exception ex) { 319 Interface.AddMessage(MessageType.Error, false, "Plugin " + Program.CurrentHost.Plugins[i].Title + " raised the following exception at CanLoadObject:" + ex.Message); 320 } 321 } 322 } 323 Interface.AddMessage(MessageType.Error, false, "No plugin found that is capable of loading object " + path); 324 } else { 325 ReportProblem(ProblemType.PathNotFound, path); 326 } 327 Object = null; 328 return false; 329 } 330 LoadObject(string path, System.Text.Encoding Encoding, out UnifiedObject Object)331 public override bool LoadObject(string path, System.Text.Encoding Encoding, out UnifiedObject Object) 332 { 333 if (base.LoadObject(path, Encoding, out Object)) 334 { 335 return true; 336 } 337 338 if (File.Exists(path) || Directory.Exists(path)) { 339 Encoding = TextEncoding.GetSystemEncodingFromFile(path, Encoding); 340 341 for (int i = 0; i < Program.CurrentHost.Plugins.Length; i++) { 342 if (Program.CurrentHost.Plugins[i].Object != null) { 343 try { 344 if (Program.CurrentHost.Plugins[i].Object.CanLoadObject(path)) { 345 try 346 { 347 UnifiedObject obj; 348 if (Program.CurrentHost.Plugins[i].Object.LoadObject(path, Encoding, out obj)) { 349 obj.OptimizeObject(false, Interface.CurrentOptions.ObjectOptimizationBasicThreshold, Interface.CurrentOptions.ObjectOptimizationVertexCulling); 350 Object = obj; 351 352 StaticObject staticObject = Object as StaticObject; 353 if (staticObject != null) 354 { 355 StaticObjectCache.Add(ValueTuple.Create(path, false), staticObject); 356 return true; 357 } 358 359 AnimatedObjectCollection aoc = Object as AnimatedObjectCollection; 360 if (aoc != null) 361 { 362 AnimatedObjectCollectionCache.Add(path, aoc); 363 } 364 365 return true; 366 } 367 Interface.AddMessage(MessageType.Error, false, "Plugin " + Program.CurrentHost.Plugins[i].Title + " returned unsuccessfully at LoadObject"); 368 } catch (Exception ex) { 369 Interface.AddMessage(MessageType.Error, false, "Plugin " + Program.CurrentHost.Plugins[i].Title + " raised the following exception at LoadObject:" + ex.Message); 370 } 371 } 372 } catch (Exception ex) { 373 Interface.AddMessage(MessageType.Error, false, "Plugin " + Program.CurrentHost.Plugins[i].Title + " raised the following exception at CanLoadObject:" + ex.Message); 374 } 375 } 376 } 377 Interface.AddMessage(MessageType.Error, false, "No plugin found that is capable of loading object " + path); 378 } else { 379 ReportProblem(ProblemType.PathNotFound, path); 380 } 381 Object = null; 382 return false; 383 } 384 ExecuteFunctionScript(OpenBveApi.FunctionScripting.FunctionScript functionScript, AbstractTrain train, int CarIndex, Vector3 Position, double TrackPosition, int SectionIndex, bool IsPartOfTrain, double TimeElapsed, int CurrentState)385 public override void ExecuteFunctionScript(OpenBveApi.FunctionScripting.FunctionScript functionScript, AbstractTrain train, int CarIndex, Vector3 Position, double TrackPosition, int SectionIndex, bool IsPartOfTrain, double TimeElapsed, int CurrentState) 386 { 387 FunctionScripts.ExecuteFunctionScript(functionScript, (TrainBase)train, CarIndex, Position, TrackPosition, SectionIndex, IsPartOfTrain, TimeElapsed, CurrentState); 388 } 389 CreateStaticObject(StaticObject Prototype, Vector3 Position, Transformation WorldTransformation, Transformation LocalTransformation, double AccurateObjectDisposalZOffset, double StartingDistance, double EndingDistance, double TrackPosition, double Brightness)390 public override int CreateStaticObject(StaticObject Prototype, Vector3 Position, Transformation WorldTransformation, Transformation LocalTransformation, double AccurateObjectDisposalZOffset, double StartingDistance, double EndingDistance, double TrackPosition, double Brightness) 391 { 392 return Program.Renderer.CreateStaticObject(Prototype, Position, WorldTransformation, LocalTransformation, Program.CurrentRoute.AccurateObjectDisposal, AccurateObjectDisposalZOffset, StartingDistance, EndingDistance, Program.CurrentRoute.BlockLength, TrackPosition, Brightness); 393 } 394 CreateStaticObject(StaticObject Prototype, Transformation LocalTransformation, Matrix4D Rotate, Matrix4D Translate, double AccurateObjectDisposalZOffset, double StartingDistance, double EndingDistance, double TrackPosition, double Brightness)395 public override int CreateStaticObject(StaticObject Prototype, Transformation LocalTransformation, Matrix4D Rotate, Matrix4D Translate, double AccurateObjectDisposalZOffset, double StartingDistance, double EndingDistance, double TrackPosition, double Brightness) 396 { 397 return Program.Renderer.CreateStaticObject(Prototype, LocalTransformation, Rotate, Translate, Program.CurrentRoute.AccurateObjectDisposal, AccurateObjectDisposalZOffset, StartingDistance, EndingDistance, Program.CurrentRoute.BlockLength, TrackPosition, Brightness); 398 } 399 CreateDynamicObject(ref ObjectState internalObject)400 public override void CreateDynamicObject(ref ObjectState internalObject) 401 { 402 Program.Renderer.CreateDynamicObject(ref internalObject); 403 } 404 AddObjectForCustomTimeTable(AnimatedObject animatedObject)405 public override void AddObjectForCustomTimeTable(AnimatedObject animatedObject) 406 { 407 Timetable.AddObjectForCustomTimetable(animatedObject); 408 } 409 ShowObject(ObjectState objectToShow, ObjectType objectType)410 public override void ShowObject(ObjectState objectToShow, ObjectType objectType) 411 { 412 Program.Renderer.VisibleObjects.ShowObject(objectToShow, objectType); 413 } 414 HideObject(ObjectState objectToHide)415 public override void HideObject(ObjectState objectToHide) 416 { 417 Program.Renderer.VisibleObjects.HideObject(objectToHide); 418 } 419 SoundIsPlaying(object SoundSource)420 public override bool SoundIsPlaying(object SoundSource) 421 { 422 return Program.Sounds.IsPlaying(SoundSource); 423 } 424 PlaySound(SoundHandle buffer, double pitch, double volume, Vector3 position, object parent, bool looped)425 public override object PlaySound(SoundHandle buffer, double pitch, double volume, Vector3 position, object parent, bool looped) 426 { 427 return Program.Sounds.PlaySound(buffer, pitch, volume, position, parent, looped); 428 } 429 PlayMicSound(Vector3 position, double backwardTolerance, double forwardTolerance)430 public override void PlayMicSound(Vector3 position, double backwardTolerance, double forwardTolerance) 431 { 432 Program.Sounds.PlayMicSound(position, backwardTolerance, forwardTolerance); 433 } 434 StopSound(object SoundSource)435 public override void StopSound(object SoundSource) 436 { 437 Program.Sounds.StopSound(SoundSource as SoundSource); 438 } 439 StopAllSounds(object parent)440 public override void StopAllSounds(object parent) 441 { 442 Program.Sounds.StopAllSounds(parent); 443 } 444 445 public override SimulationState SimulationState 446 { 447 get 448 { 449 if (!Loading.SimulationSetup) 450 { 451 return SimulationState.Loading; 452 } 453 454 if (Game.MinimalisticSimulation) 455 { 456 return SimulationState.MinimalisticSimulation; 457 } 458 return SimulationState.Running; 459 } 460 } 461 462 public override int AnimatedWorldObjectsUsed 463 { 464 get 465 { 466 return ObjectManager.AnimatedWorldObjectsUsed; 467 } 468 set 469 { 470 int a = ObjectManager.AnimatedWorldObjectsUsed; 471 if (ObjectManager.AnimatedWorldObjects.Length -1 == a) 472 { 473 /* 474 * HACK: We cannot resize an array via an accessor property 475 * With this in mind, resize it via the indexer instead 476 */ 477 Array.Resize(ref ObjectManager.AnimatedWorldObjects, ObjectManager.AnimatedWorldObjects.Length << 1); 478 } 479 480 ObjectManager.AnimatedWorldObjectsUsed = value; 481 } 482 } 483 484 public override WorldObject[] AnimatedWorldObjects 485 { 486 get 487 { 488 return ObjectManager.AnimatedWorldObjects; 489 } 490 set 491 { 492 ObjectManager.AnimatedWorldObjects = value; 493 } 494 } 495 496 public override Dictionary<int, Track> Tracks 497 { 498 get 499 { 500 return Program.CurrentRoute.Tracks; 501 } 502 set 503 { 504 Program.CurrentRoute.Tracks = value; 505 } 506 } 507 UpdateCustomTimetable(Texture Daytime, Texture Nighttime)508 public override void UpdateCustomTimetable(Texture Daytime, Texture Nighttime) 509 { 510 Timetable.UpdateCustomTimetable(Daytime, Nighttime); 511 } 512 ParseTrackFollowingObject(string objectPath, string tfoFile)513 public override AbstractTrain ParseTrackFollowingObject(string objectPath, string tfoFile) 514 { 515 return TrackFollowingObjectParser.ParseTrackFollowingObject(objectPath, tfoFile); 516 } 517 AddMarker(Texture MarkerTexture)518 public override void AddMarker(Texture MarkerTexture) 519 { 520 Program.Renderer.Marker.AddMarker(MarkerTexture); 521 } 522 RemoveMarker(Texture MarkerTexture)523 public override void RemoveMarker(Texture MarkerTexture) 524 { 525 Program.Renderer.Marker.RemoveMarker(MarkerTexture); 526 } 527 CameraAtWorldEnd()528 public override void CameraAtWorldEnd() 529 { 530 Program.Renderer.Camera.AtWorldEnd = !Program.Renderer.Camera.AtWorldEnd; 531 } 532 533 public override double InGameTime => Program.CurrentRoute.SecondsSinceMidnight; 534 AddBlackBoxEntry()535 public override void AddBlackBoxEntry() 536 { 537 Game.AddBlackBoxEntry(); 538 } 539 ProcessJump(AbstractTrain Train, int StationIndex)540 public override void ProcessJump(AbstractTrain Train, int StationIndex) 541 { 542 ObjectManager.ProcessJump(Train); 543 if (Train.IsPlayerTrain) 544 { 545 if (Game.CurrentScore.ArrivalStation <= StationIndex) 546 { 547 Game.CurrentScore.ArrivalStation = StationIndex + 1; 548 } 549 Game.CurrentScore.DepartureStation = StationIndex; 550 Program.Renderer.CurrentInterface = InterfaceType.Normal; 551 Program.TrainManager.UnderailTrains(); 552 } 553 } 554 AddScore(int Score, string Message, MessageColor Color, double Timeout)555 public override void AddScore(int Score, string Message, MessageColor Color, double Timeout) 556 { 557 Game.CurrentScore.CurrentValue += Score; 558 int n = Game.ScoreMessages.Length; 559 Array.Resize(ref Game.ScoreMessages, n + 1); 560 Game.ScoreMessages[n] = new Game.ScoreMessage 561 { 562 Value = Score, 563 Color = Color, 564 RendererPosition = new Vector2(0, 0), 565 RendererAlpha = 0.0, 566 Text = Message, 567 Timeout = Timeout 568 }; 569 } 570 571 public override AbstractTrain[] Trains 572 { 573 get 574 { 575 // ReSharper disable once CoVariantArrayConversion 576 return Program.TrainManager.Trains; 577 } 578 } 579 ClosestTrain(AbstractTrain Train)580 public override AbstractTrain ClosestTrain(AbstractTrain Train) 581 { 582 TrainBase baseTrain = Train as TrainBase; 583 AbstractTrain closestTrain = null; 584 double bestLocation = double.MaxValue; 585 if(baseTrain != null) 586 { 587 for (int i = 0; i < Program.TrainManager.Trains.Length; i++) 588 { 589 if (Program.TrainManager.Trains[i] != baseTrain & Program.TrainManager.Trains[i].State == TrainState.Available & baseTrain.Cars.Length > 0) 590 { 591 TrainBase train = Program.TrainManager.Trains[i]; 592 int c = train.Cars.Length - 1; 593 double z = train.Cars[c].RearAxle.Follower.TrackPosition - train.Cars[c].RearAxle.Position - 0.5 * train.Cars[c].Length; 594 if (z >= baseTrain.FrontCarTrackPosition() & z < bestLocation) 595 { 596 bestLocation = z; 597 closestTrain = Program.TrainManager.Trains[i]; 598 } 599 } 600 } 601 } 602 return closestTrain; 603 } 604 ClosestTrain(double TrackPosition)605 public override AbstractTrain ClosestTrain(double TrackPosition) 606 { 607 AbstractTrain closestTrain = null; 608 double trainDistance = double.MaxValue; 609 for (int j = 0; j < Program.TrainManager.Trains.Length; j++) 610 { 611 if (Program.TrainManager.Trains[j].State == TrainState.Available) 612 { 613 double distance; 614 if (Program.TrainManager.Trains[j].Cars[0].FrontAxle.Follower.TrackPosition < TrackPosition) 615 { 616 distance = TrackPosition - Program.TrainManager.Trains[j].Cars[0].TrackPosition; 617 } 618 else if (Program.TrainManager.Trains[j].Cars[Program.TrainManager.Trains[j].Cars.Length - 1].RearAxle.Follower.TrackPosition > TrackPosition) 619 { 620 distance = Program.TrainManager.Trains[j].Cars[Program.TrainManager.Trains[j].Cars.Length - 1].RearAxle.Follower.TrackPosition - TrackPosition; 621 } 622 else 623 { 624 distance = 0; 625 } 626 if (distance < trainDistance) 627 { 628 closestTrain = Program.TrainManager.Trains[j]; 629 trainDistance = distance; 630 } 631 } 632 } 633 return closestTrain; 634 } 635 Host()636 public Host() : base(HostApplication.OpenBve) 637 { 638 } 639 } 640 } 641