public static void StartAsync(SimulationModel simulation) { Debug.Assert(Instance.CurrentSimulation == null); Instance.Actions.Enqueue(() => { using (var db = DatabaseManager.Open()) { AssetBundle textureBundle = null; AssetBundle mapBundle = null; try { if (Config.Headless && (simulation.Headless.HasValue && !simulation.Headless.Value)) { throw new Exception("Simulator is configured to run in headless mode, only headless simulations are allowed"); } simulation.Status = "Starting"; NotificationManager.SendNotification("simulation", SimulationResponse.Create(simulation), simulation.Owner); Instance.LoaderUI.SetLoaderUIState(LoaderUI.LoaderUIStateType.PROGRESS); Instance.SimConfig = new SimulationConfig() { Name = simulation.Name, Clusters = db.Single <ClusterModel>(simulation.Cluster).Ips.Split(',').Where(c => c != "127.0.0.1").ToArray(), ClusterName = db.Single <ClusterModel>(simulation.Cluster).Name, ApiOnly = simulation.ApiOnly.GetValueOrDefault(), Headless = simulation.Headless.GetValueOrDefault(), Interactive = simulation.Interactive.GetValueOrDefault(), TimeOfDay = simulation.TimeOfDay.GetValueOrDefault(new DateTime(1980, 3, 24, 12, 0, 0)), Rain = simulation.Rain.GetValueOrDefault(), Fog = simulation.Fog.GetValueOrDefault(), Wetness = simulation.Wetness.GetValueOrDefault(), Cloudiness = simulation.Cloudiness.GetValueOrDefault(), UseTraffic = simulation.UseTraffic.GetValueOrDefault(), UsePedestrians = simulation.UsePedestrians.GetValueOrDefault(), Seed = simulation.Seed, }; if (simulation.Vehicles == null || simulation.Vehicles.Length == 0 || simulation.ApiOnly.GetValueOrDefault()) { Instance.SimConfig.Agents = Array.Empty <AgentConfig>(); } else { Instance.SimConfig.Agents = simulation.Vehicles.Select(v => { var vehicle = db.SingleOrDefault <VehicleModel>(v.Vehicle); var config = new AgentConfig() { Name = vehicle.Name, Url = vehicle.Url, AssetBundle = vehicle.LocalPath, Connection = v.Connection, Sensors = vehicle.Sensors, }; if (!string.IsNullOrEmpty(vehicle.BridgeType)) { config.Bridge = Config.Bridges.Find(bridge => bridge.Name == vehicle.BridgeType); if (config.Bridge == null) { throw new Exception($"Bridge {vehicle.BridgeType} not found"); } } return(config); }).ToArray(); } // load environment if (Instance.SimConfig.ApiOnly) { var api = Instantiate(Instance.ApiManagerPrefab); api.name = "ApiManager"; Instance.CurrentSimulation = simulation; // ready to go! Instance.CurrentSimulation.Status = "Running"; NotificationManager.SendNotification("simulation", SimulationResponse.Create(simulation), simulation.Owner); Instance.LoaderUI.SetLoaderUIState(LoaderUI.LoaderUIStateType.READY); } else { var mapModel = db.Single <MapModel>(simulation.Map); var mapBundlePath = mapModel.LocalPath; mapBundle = null; textureBundle = null; ZipFile zip = new ZipFile(mapBundlePath); { string manfile; ZipEntry entry = zip.GetEntry("manifest"); using (var ms = zip.GetInputStream(entry)) { int streamSize = (int)entry.Size; byte[] buffer = new byte[streamSize]; streamSize = ms.Read(buffer, 0, streamSize); manfile = Encoding.UTF8.GetString(buffer); } Manifest manifest = new Deserializer().Deserialize <Manifest>(manfile); if (manifest.bundleFormat != BundleConfig.MapBundleFormatVersion) { zip.Close(); // TODO: proper exception throw new ZipException("BundleFormat version mismatch"); } if (zip.FindEntry($"{manifest.bundleGuid}_environment_textures", false) != -1) { var texStream = zip.GetInputStream(zip.GetEntry($"{manifest.bundleGuid}_environment_textures")); textureBundle = AssetBundle.LoadFromStream(texStream, 0, 1 << 20); } string platform = SystemInfo.operatingSystemFamily == OperatingSystemFamily.Windows ? "windows" : "linux"; var mapStream = zip.GetInputStream(zip.GetEntry($"{manifest.bundleGuid}_environment_main_{platform}")); mapBundle = AssetBundle.LoadFromStream(mapStream, 0, 1 << 20); if (mapBundle == null) { throw new Exception($"Failed to load environment from '{mapModel.Name}' asset bundle"); } textureBundle?.LoadAllAssets(); var scenes = mapBundle.GetAllScenePaths(); if (scenes.Length != 1) { throw new Exception($"Unsupported environment in '{mapModel.Name}' asset bundle, only 1 scene expected"); } var sceneName = Path.GetFileNameWithoutExtension(scenes[0]); Instance.SimConfig.MapName = sceneName; Instance.SimConfig.MapUrl = mapModel.Url; var isMasterSimulation = Instance.SimConfig.Clusters.Length > 0; var loader = SceneManager.LoadSceneAsync(sceneName, isMasterSimulation? LoadSceneMode.Additive : LoadSceneMode.Single); loader.completed += op => { if (op.isDone) { if (isMasterSimulation) { SceneManager.SetActiveScene(SceneManager.GetSceneByName(sceneName)); } textureBundle?.Unload(false); mapBundle.Unload(false); zip.Close(); SetupScene(simulation); } }; } } } catch (ZipException ex) { Debug.Log($"Failed to start '{simulation.Name}' simulation"); Debug.LogException(ex); // NOTE: In case of failure we have to update Simulation state simulation.Status = "Invalid"; simulation.Error = "Out of date Map AssetBundle. Please check content website for updated bundle or rebuild the bundle."; db.Update(simulation); if (SceneManager.GetActiveScene().name != Instance.LoaderScene) { SceneManager.LoadScene(Instance.LoaderScene); } textureBundle?.Unload(false); mapBundle?.Unload(false); AssetBundle.UnloadAllAssetBundles(true); Instance.CurrentSimulation = null; // TODO: take ex.Message and append it to response here NotificationManager.SendNotification("simulation", SimulationResponse.Create(simulation), simulation.Owner); } catch (Exception ex) { Debug.Log($"Failed to start '{simulation.Name}' simulation"); Debug.LogException(ex); // NOTE: In case of failure we have to update Simulation state simulation.Status = "Invalid"; simulation.Error = ex.Message; db.Update(simulation); if (SceneManager.GetActiveScene().name != Instance.LoaderScene) { SceneManager.LoadScene(Instance.LoaderScene); } textureBundle?.Unload(false); mapBundle?.Unload(false); AssetBundle.UnloadAllAssetBundles(true); Instance.CurrentSimulation = null; // TODO: take ex.Message and append it to response here NotificationManager.SendNotification("simulation", SimulationResponse.Create(simulation), simulation.Owner); } } }); }
public static void StartAsync(SimulationModel simulation) { Debug.Assert(Instance.CurrentSimulation == null); Instance.Actions.Enqueue(() => { using (var db = DatabaseManager.Open()) { AssetBundle mapBundle = null; try { if (Config.Headless && (simulation.Headless.HasValue && !simulation.Headless.Value)) { throw new Exception("Simulator is configured to run in headless mode, only headless simulations are allowed"); } simulation.Status = "Starting"; NotificationManager.SendNotification("simulation", SimulationResponse.Create(simulation), simulation.Owner); Instance.LoaderUI.SetLoaderUIState(LoaderUI.LoaderUIStateType.PROGRESS); Instance.SimConfig = new SimulationConfig() { Name = simulation.Name, Clusters = db.Single <ClusterModel>(simulation.Cluster).Ips.Split(',').Where(c => c != "127.0.0.1").ToArray(), ClusterName = db.Single <ClusterModel>(simulation.Cluster).Name, ApiOnly = simulation.ApiOnly.GetValueOrDefault(), Headless = simulation.Headless.GetValueOrDefault(), Interactive = simulation.Interactive.GetValueOrDefault(), TimeOfDay = simulation.TimeOfDay.GetValueOrDefault(DateTime.MinValue.AddHours(12)), Rain = simulation.Rain.GetValueOrDefault(), Fog = simulation.Fog.GetValueOrDefault(), Wetness = simulation.Wetness.GetValueOrDefault(), Cloudiness = simulation.Cloudiness.GetValueOrDefault(), UseTraffic = simulation.UseTraffic.GetValueOrDefault(), UsePedestrians = simulation.UsePedestrians.GetValueOrDefault(), Seed = simulation.Seed, }; if (simulation.Vehicles == null || simulation.Vehicles.Length == 0 || simulation.ApiOnly.GetValueOrDefault()) { Instance.SimConfig.Agents = Array.Empty <AgentConfig>(); } else { Instance.SimConfig.Agents = simulation.Vehicles.Select(v => { var vehicle = db.SingleOrDefault <VehicleModel>(v.Vehicle); var config = new AgentConfig() { Name = vehicle.Name, AssetBundle = vehicle.LocalPath, Connection = v.Connection, Sensors = vehicle.Sensors, }; if (!string.IsNullOrEmpty(vehicle.BridgeType)) { config.Bridge = Config.Bridges.Find(bridge => bridge.Name == vehicle.BridgeType); if (config.Bridge == null) { throw new Exception($"Bridge {vehicle.BridgeType} not found"); } } return(config); }).ToArray(); } // load environment if (Instance.SimConfig.ApiOnly) { var api = Instantiate(Instance.ApiManagerPrefab); api.name = "ApiManager"; Instance.CurrentSimulation = simulation; // ready to go! Instance.CurrentSimulation.Status = "Running"; NotificationManager.SendNotification("simulation", SimulationResponse.Create(simulation), simulation.Owner); Instance.LoaderUI.SetLoaderUIState(LoaderUI.LoaderUIStateType.READY); } else { var mapModel = db.Single <MapModel>(simulation.Map); var mapBundlePath = mapModel.LocalPath; // TODO: make this async mapBundle = AssetBundle.LoadFromFile(mapBundlePath); if (mapBundle == null) { throw new Exception($"Failed to load environment from '{mapModel.Name}' asset bundle"); } var scenes = mapBundle.GetAllScenePaths(); if (scenes.Length != 1) { throw new Exception($"Unsupported environment in '{mapModel.Name}' asset bundle, only 1 scene expected"); } var sceneName = Path.GetFileNameWithoutExtension(scenes[0]); Instance.SimConfig.MapName = sceneName; var loader = SceneManager.LoadSceneAsync(sceneName); loader.completed += op => { if (op.isDone) { mapBundle.Unload(false); SetupScene(simulation); } }; } } catch (Exception ex) { Debug.Log($"Failed to start '{simulation.Name}' simulation"); Debug.LogException(ex); // NOTE: In case of failure we have to update Simulation state simulation.Status = "Invalid"; db.Update(simulation); if (SceneManager.GetActiveScene().name != Instance.LoaderScene) { SceneManager.LoadScene(Instance.LoaderScene); } mapBundle?.Unload(false); AssetBundle.UnloadAllAssetBundles(true); Instance.CurrentSimulation = null; // TODO: take ex.Message and append it to response here NotificationManager.SendNotification("simulation", SimulationResponse.Create(simulation), simulation.Owner); } } }); }