1 // ╔═════════════════════════════════════════════════════════════╗ 2 // ║ Loading.cs for the Route Viewer ║ 3 // ╠═════════════════════════════════════════════════════════════╣ 4 // ║ This file cannot be used in the openBVE main program. ║ 5 // ║ The file from the openBVE main program cannot be used here. ║ 6 // ╚═════════════════════════════════════════════════════════════╝ 7 8 using System; 9 using System.Drawing; 10 using System.Linq; 11 using System.Text; 12 using System.Threading.Tasks; 13 using System.Windows.Forms; 14 using LibRender2.Cameras; 15 using OpenBveApi.Math; 16 using OpenBveApi.Routes; 17 using OpenBveApi.Runtime; 18 using OpenBveApi.Textures; 19 using RouteManager2; 20 21 namespace RouteViewer { 22 internal static class Loading { 23 24 internal static bool Cancel 25 { 26 get 27 { 28 return _cancel; 29 } 30 set 31 { 32 if (value) 33 { 34 //Send cancellation call to plugins 35 for (int i = 0; i < Program.CurrentHost.Plugins.Length; i++) 36 { 37 if (Program.CurrentHost.Plugins[i].Route != null && Program.CurrentHost.Plugins[i].Route.IsLoading) 38 { 39 Program.CurrentHost.Plugins[i].Route.Cancel = true; 40 } 41 } 42 _cancel = true; 43 } 44 else 45 { 46 _cancel = false; 47 } 48 } 49 } 50 51 private static bool _cancel; 52 internal static bool Complete; 53 private static string CurrentRouteFile; 54 private static Encoding CurrentRouteEncoding; 55 56 internal static bool JobAvailable; 57 58 // load Load(string RouteFile, Encoding RouteEncoding, Bitmap bitmap = null)59 internal static void Load(string RouteFile, Encoding RouteEncoding, Bitmap bitmap = null) 60 { 61 // reset 62 Game.Reset(); 63 Program.Renderer.Loading.InitLoading(Program.FileSystem.GetDataFolder("In-game"), typeof(NewRenderer).Assembly.GetName().Version.ToString(), Interface.CurrentOptions.LoadingLogo, Interface.CurrentOptions.LoadingProgressBar); 64 if (bitmap != null) 65 { 66 Program.Renderer.Loading.SetLoadingBkg(Program.Renderer.TextureManager.RegisterTexture(bitmap, new TextureParameters(null, null))); 67 } 68 // members 69 Cancel = false; 70 Complete = false; 71 CurrentRouteFile = RouteFile; 72 CurrentRouteEncoding = RouteEncoding; 73 // thread 74 Loading.LoadAsynchronously(CurrentRouteFile, CurrentRouteEncoding); 75 RouteViewer.LoadingScreenLoop(); 76 } 77 78 /// <summary>Gets the absolute Railway folder for a given route file</summary> 79 /// <returns>The absolute on-disk path of the railway folder</returns> GetRailwayFolder(string RouteFile)80 internal static string GetRailwayFolder(string RouteFile) { 81 try 82 { 83 string Folder = System.IO.Path.GetDirectoryName(RouteFile); 84 85 while (true) 86 { 87 string Subfolder = OpenBveApi.Path.CombineDirectory(Folder, "Railway"); 88 if (System.IO.Directory.Exists(Subfolder)) 89 { 90 if (System.IO.Directory.EnumerateDirectories(Subfolder).Any() || System.IO.Directory.EnumerateFiles(Subfolder).Any()) 91 { 92 //HACK: Ignore completely empty directories 93 //Doesn't handle wrong directories, or those with stuff missing, TODO..... 94 return Subfolder; 95 } 96 } 97 98 if (Folder == null) continue; 99 System.IO.DirectoryInfo Info = System.IO.Directory.GetParent(Folder); 100 if (Info == null) break; 101 Folder = Info.FullName; 102 } 103 } 104 catch 105 { 106 //ignored 107 } 108 109 //If the Route, Object and Sound folders exist, but are not in a railway folder..... 110 try 111 { 112 string Folder = System.IO.Path.GetDirectoryName(RouteFile); 113 string candidate = null; 114 while (true) 115 { 116 string RouteFolder = OpenBveApi.Path.CombineDirectory(Folder, "Route"); 117 string ObjectFolder = OpenBveApi.Path.CombineDirectory(Folder, "Object"); 118 string SoundFolder = OpenBveApi.Path.CombineDirectory(Folder, "Sound"); 119 if (System.IO.Directory.Exists(RouteFolder) && System.IO.Directory.Exists(ObjectFolder) && System.IO.Directory.Exists(SoundFolder)) 120 { 121 return Folder; 122 } 123 124 if (System.IO.Directory.Exists(RouteFolder) && System.IO.Directory.Exists(ObjectFolder)) 125 { 126 candidate = Folder; 127 } 128 129 // ReSharper disable once AssignNullToNotNullAttribute 130 System.IO.DirectoryInfo Info = System.IO.Directory.GetParent(Folder); 131 if (Info == null) 132 { 133 if (candidate != null) 134 { 135 return candidate; 136 } 137 break; 138 } 139 Folder = Info.FullName; 140 } 141 } 142 catch 143 { 144 //ignored 145 } 146 return Application.StartupPath; 147 } 148 149 // load threaded LoadThreaded()150 private static async Task LoadThreaded() 151 { 152 try 153 { 154 await Task.Run(() => LoadEverythingThreaded()); 155 } 156 catch (Exception ex) 157 { 158 MessageBox.Show("The route loader encountered the following critical error: " + ex.Message, @"OpenBVE", MessageBoxButtons.OK, MessageBoxIcon.Hand); 159 Cancel = true; 160 } 161 } 162 LoadAsynchronously(string RouteFile, Encoding RouteEncoding)163 internal static void LoadAsynchronously(string RouteFile, Encoding RouteEncoding) 164 { 165 // members 166 Cancel = false; 167 Complete = false; 168 CurrentRouteFile = RouteFile; 169 CurrentRouteEncoding = RouteEncoding; 170 171 //Set the route and train folders in the info class 172 // ReSharper disable once UnusedVariable 173 Task loadThreaded = LoadThreaded(); 174 } 175 LoadEverythingThreaded()176 private static void LoadEverythingThreaded() { 177 string RailwayFolder = GetRailwayFolder(CurrentRouteFile); 178 string ObjectFolder = OpenBveApi.Path.CombineDirectory(RailwayFolder, "Object"); 179 string SoundFolder = OpenBveApi.Path.CombineDirectory(RailwayFolder, "Sound"); 180 Program.Renderer.Camera.CurrentMode = CameraViewMode.Track; 181 // load route 182 bool loaded = false; 183 for (int i = 0; i < Program.CurrentHost.Plugins.Length; i++) 184 { 185 if (Program.CurrentHost.Plugins[i].Route != null && Program.CurrentHost.Plugins[i].Route.CanLoadRoute(CurrentRouteFile)) 186 { 187 object Route = (object)Program.CurrentRoute; //must cast to allow us to use the ref keyword. 188 if (Program.CurrentHost.Plugins[i].Route.LoadRoute(CurrentRouteFile, CurrentRouteEncoding, null, ObjectFolder, SoundFolder, false, ref Route)) 189 { 190 Program.CurrentRoute = (CurrentRoute) Route; 191 Program.CurrentRoute.UpdateLighting(); 192 loaded = true; 193 break; 194 } 195 throw Program.CurrentHost.Plugins[i].Route.LastException; 196 } 197 } 198 199 if (!loaded) 200 { 201 throw new Exception("No plugins capable of loading routefile " + CurrentRouteFile + " were found."); 202 } 203 Program.Renderer.CameraTrackFollower = new TrackFollower(Program.CurrentHost); 204 System.Threading.Thread.Sleep(1); if (Cancel) return; 205 Program.CurrentRoute.Atmosphere.CalculateSeaLevelConstants(); 206 // camera 207 Program.Renderer.CameraTrackFollower.UpdateAbsolute( 0.0, true, false); 208 Program.Renderer.CameraTrackFollower.UpdateAbsolute(0.1, true, false); 209 Program.Renderer.CameraTrackFollower.UpdateAbsolute(-0.1, true, false); 210 Program.Renderer.CameraTrackFollower.TriggerType = EventTriggerType.Camera; 211 // default starting time 212 Game.SecondsSinceMidnight = 0.0; 213 // finished created objects 214 System.Threading.Thread.Sleep(1); if (Cancel) return; 215 // signals 216 System.Threading.Thread.Sleep(1); if (Cancel) return; 217 Program.CurrentRoute.UpdateAllSections(); 218 // starting track position 219 System.Threading.Thread.Sleep(1); if (Cancel) return; 220 // int FirstStationIndex = -1; 221 double FirstStationPosition = 0.0; 222 for (int i = 0; i < Program.CurrentRoute.Stations.Length; i++) { 223 if (Program.CurrentRoute.Stations[i].Stops.Length != 0) { 224 // FirstStationIndex = i; 225 FirstStationPosition = Program.CurrentRoute.Stations[i].Stops[Program.CurrentRoute.Stations[i].Stops.Length - 1].TrackPosition; 226 if (Program.CurrentRoute.Stations[i].ArrivalTime < 0.0) { 227 if (Program.CurrentRoute.Stations[i].DepartureTime < 0.0) { 228 Game.SecondsSinceMidnight = 0.0; 229 } else { 230 Game.SecondsSinceMidnight = Program.CurrentRoute.Stations[i].DepartureTime - Program.CurrentRoute.Stations[i].StopTime; 231 } 232 } else { 233 Game.SecondsSinceMidnight = Program.CurrentRoute.Stations[i].ArrivalTime; 234 } 235 break; 236 } 237 } 238 // initialize camera 239 Program.Renderer.CameraTrackFollower.UpdateAbsolute(-1.0, true, false); 240 Program.Renderer.CameraTrackFollower.UpdateAbsolute(FirstStationPosition, true, false); 241 Program.Renderer.Camera.Alignment = new CameraAlignment(new Vector3(0.0, 2.5, 0.0), 0.0, 0.0, 0.0, FirstStationPosition, 1.0); 242 World.UpdateAbsoluteCamera(0.0); 243 Complete = true; 244 } 245 246 } 247 } 248