/// <summary> /// Checks if the game has all required building prefabs currently in memory. /// </summary> bool AllPrefabsAvailable() { try { PrefabLoader.Create().LookupSimulationPrefabs(); return(PrefabLoader.instance.AllPrefabsAvailable()); } catch (Exception e) { UnityEngine.Debug.LogException(e); } return(true); }
const string ROUTINE = "<InitializePrefabs>c__Iterator6"; // TODO make robust internal PrefabLoader() { instance = this; Type coroutine = typeof(BuildingCollection).GetNestedType(ROUTINE, BindingFlags.NonPublic); nameField = coroutine?.GetField("name", BindingFlags.NonPublic | BindingFlags.Instance); prefabsField = coroutine?.GetField("prefabs", BindingFlags.NonPublic | BindingFlags.Instance); prefabsField2 = coroutine?.GetField("<$>prefabs", BindingFlags.NonPublic | BindingFlags.Instance); replacesField = coroutine?.GetField("replaces", BindingFlags.NonPublic | BindingFlags.Instance); replacesField2 = coroutine?.GetField("<$>replaces", BindingFlags.NonPublic | BindingFlags.Instance); if (nameField != null && prefabsField != null && prefabsField2 != null && replacesField != null && replacesField2 != null) { init(typeof(LoadingManager), "QueueLoadingAction"); } }
/// <summary> /// Creates the list of standard prefab levels to load. /// </summary> KeyValuePair <string, float>[] SetLevels() { if (Settings.settings.SkipPrefabs) { PrefabLoader.Create().Deploy(); } LoadingManager.instance.m_supportsExpansion[0] = Check(369150); LoadingManager.instance.m_supportsExpansion[1] = Check(420610); LoadingManager.instance.m_supportsExpansion[2] = Check(515191); LoadingManager.instance.m_supportsExpansion[3] = Check(547502); LoadingManager.instance.m_supportsExpansion[4] = Check(614580); LoadingManager.instance.m_supportsExpansion[5] = Check(715191); LoadingManager.instance.m_supportsExpansion[6] = Check(715194); LoadingManager.instance.m_supportsExpansion[7] = Check(944071); LoadingManager.instance.m_supportsExpansion[8] = Check(1146930); bool isWinter = SimulationManager.instance.m_metaData.m_environment == "Winter"; if (isWinter && !LoadingManager.instance.m_supportsExpansion[1]) { SimulationManager.instance.m_metaData.m_environment = "Sunny"; isWinter = false; } List <KeyValuePair <string, float> > levels = new List <KeyValuePair <string, float> >(18); string scene = (string)Util.Invoke(LoadingManager.instance, "GetLoadingScene"); if (!string.IsNullOrEmpty(scene)) { levels.Add(new KeyValuePair <string, float>(scene, 0.015f)); } levels.Add(new KeyValuePair <string, float>(SimulationManager.instance.m_metaData.m_environment + "Prefabs", 0.12f)); if ((bool)Util.Invoke(LoadingManager.instance, "LoginUsed")) { levels.Add(new KeyValuePair <string, float>(isWinter ? "WinterLoginPackPrefabs" : "LoginPackPrefabs", 0.121f)); } levels.Add(new KeyValuePair <string, float>(isWinter ? "WinterPreorderPackPrefabs" : "PreorderPackPrefabs", 0.122f)); levels.Add(new KeyValuePair <string, float>(isWinter ? "WinterSignupPackPrefabs" : "SignupPackPrefabs", 0.123f)); if (Check(346791)) { levels.Add(new KeyValuePair <string, float>("DeluxePackPrefabs", 0.124f)); } if (PlatformService.IsAppOwned(238370u)) { levels.Add(new KeyValuePair <string, float>("MagickaPackPrefabs", 0.125f)); } if (LoadingManager.instance.m_supportsExpansion[0]) { levels.Add(new KeyValuePair <string, float>(isWinter ? "WinterExpansion1Prefabs" : "Expansion1Prefabs", 0.126f)); } if (LoadingManager.instance.m_supportsExpansion[1]) { levels.Add(new KeyValuePair <string, float>("Expansion2Prefabs", 0.127f)); } if (LoadingManager.instance.m_supportsExpansion[2]) { levels.Add(new KeyValuePair <string, float>("Expansion3Prefabs", 0.128f)); } if (LoadingManager.instance.m_supportsExpansion[3]) { levels.Add(new KeyValuePair <string, float>("Expansion4Prefabs", 0.129f)); } if (LoadingManager.instance.m_supportsExpansion[4]) { levels.Add(new KeyValuePair <string, float>(isWinter ? "WinterExpansion5Prefabs" : "Expansion5Prefabs", 0.131f)); } if (LoadingManager.instance.m_supportsExpansion[5]) { levels.Add(new KeyValuePair <string, float>(SimulationManager.instance.m_metaData.m_environment + "Expansion6Prefabs", 0.132f)); } if (LoadingManager.instance.m_supportsExpansion[6]) { levels.Add(new KeyValuePair <string, float>(isWinter ? "WinterExpansion7Prefabs" : "Expansion7Prefabs", 0.133f)); } if (LoadingManager.instance.m_supportsExpansion[7]) { levels.Add(new KeyValuePair <string, float>(isWinter ? "WinterExpansion8Prefabs" : "Expansion8Prefabs", 0.1f)); } if (LoadingManager.instance.m_supportsExpansion[8]) { levels.Add(new KeyValuePair <string, float>(isWinter ? "WinterExpansion9Prefabs" : "Expansion9Prefabs", 0.11f)); } for (int i = 0; i < levelStrings.Length; i++) { if (Check(levelStrings[i].Value)) { levels.Add(new KeyValuePair <string, float>(levelStrings[i].Key, 0.134f + i * 0.01f / levelStrings.Length)); } } if (Check(715190)) { Package.Asset asset = PackageManager.FindAssetByName("System." + DistrictStyle.kEuropeanSuburbiaStyleName); if (asset != null && asset.isEnabled) { levels.Add(new KeyValuePair <string, float>("ModderPack3Prefabs", 0.144f)); } } if (Check(563850)) { levels.Add(new KeyValuePair <string, float>("ChinaPackPrefabs", 0.145f)); } Package.Asset europeanStyles = PackageManager.FindAssetByName("System." + DistrictStyle.kEuropeanStyleName); if (europeanStyles != null && europeanStyles.isEnabled) { levels.Add(new KeyValuePair <string, float>(SimulationManager.instance.m_metaData.m_environment.Equals("Europe") ? "EuropeNormalPrefabs" : "EuropeStylePrefabs", 0.15f)); } return(levels.ToArray()); }
public IEnumerator LoadLevelCoroutine(Package.Asset asset, string playerScene, string uiScene, SimulationMetaData ngs, bool forceEnvironmentReload) { string scene; int i; yield return(null); try { Util.InvokeVoid(LoadingManager.instance, "PreLoadLevel"); } catch (Exception e) { Util.DebugPrint("PreLoadLevel: exception from some mod."); UnityEngine.Debug.LogException(e); } if (!LoadingManager.instance.LoadingAnimationComponent.AnimationLoaded) { LoadingManager.instance.m_loadingProfilerScenes.BeginLoading("LoadingAnimation"); yield return(SceneManager.LoadSceneAsync("LoadingAnimation", LoadSceneMode.Additive)); LoadingManager.instance.m_loadingProfilerScenes.EndLoading(); } DateTime skipStamp = Settings.settings.LoadSkipFile(); AsyncTask task = Singleton <SimulationManager> .instance.AddAction("Loading", (IEnumerator)Util.Invoke(LoadingManager.instance, "LoadSimulationData", asset, ngs)); LoadSaveStatus.activeTask = task; if (LoadingManager.instance.m_loadedEnvironment == null) // loading from main menu { fastLoad = false; } else // loading from in-game (the pause menu) { while (!LoadingManager.instance.m_metaDataLoaded && !task.completedOrFailed) // IL_139 { yield return(null); } if (SimulationManager.instance.m_metaData == null) { SimulationManager.instance.m_metaData = new SimulationMetaData(); SimulationManager.instance.m_metaData.m_environment = "Sunny"; SimulationManager.instance.m_metaData.Merge(ngs); } Util.InvokeVoid(LoadingManager.instance, "MetaDataLoaded"); // No OnCreated string mapThemeName = SimulationManager.instance.m_metaData.m_MapThemeMetaData?.name; fastLoad = SimulationManager.instance.m_metaData.m_environment == LoadingManager.instance.m_loadedEnvironment && mapThemeName == LoadingManager.instance.m_loadedMapTheme && !forceEnvironmentReload; // The game is nicely optimized when loading from the pause menu. We must specifically address the following situations: // - environment (biome) stays the same // - map theme stays the same // - forceEnvironmentReload is false // - 'load used assets' is enabled // - not all assets and prefabs used in the save being loaded are currently in memory // - prefab skipping has changed. if (fastLoad) { // Check custom asset availability. if (Settings.settings.loadUsed && !IsKnownFastLoad(asset)) { while (!IsSaveDeserialized()) { yield return(null); } fastLoad = AllAssetsAvailable(); } // Check building prefab availability. if (fastLoad) { if (skipStamp != savedSkipStamp) { fastLoad = false; } else if (Settings.settings.SkipPrefabs && !IsKnownFastLoad(asset)) { while (!IsSaveDeserialized()) { yield return(null); } fastLoad = AllPrefabsAvailable(); } } if (fastLoad) // optimized load { if (Settings.settings.SkipPrefabs && skippedPrefabs[0] != null) { while (!IsSaveDeserialized()) { yield return(null); } PrefabLoader.Create().SetSkippedPrefabs(skippedPrefabs); LoadingManager.instance.QueueLoadingAction(PrefabLoader.RemoveSkippedFromSimulation()); } LoadingManager.instance.QueueLoadingAction((IEnumerator)Util.Invoke(LoadingManager.instance, "EssentialScenesLoaded")); LoadingManager.instance.QueueLoadingAction((IEnumerator)Util.Invoke(LoadingManager.instance, "RenderDataReady")); Util.DebugPrint("fast load at", Profiling.Millis); } else // fallback to full load { DestroyLoadedPrefabs(); LoadingManager.instance.m_loadedEnvironment = null; LoadingManager.instance.m_loadedMapTheme = null; Util.DebugPrint("fallback to full load at", Profiling.Millis); } } else // full load { // Notice that there is a race condition in the base game at this point: DestroyAllPrefabs ruins the simulation // if its deserialization has progressed far enough. Typically there is no problem. Util.InvokeVoid(LoadingManager.instance, "DestroyAllPrefabs"); LoadingManager.instance.m_loadedEnvironment = null; LoadingManager.instance.m_loadedMapTheme = null; Util.DebugPrint("full load at", Profiling.Millis); } } // Full load. if (LoadingManager.instance.m_loadedEnvironment == null) // IL_27C { AsyncOperation op; Reset(); fullLoadTime = DateTime.Now; savedSkipStamp = skipStamp; Array.Clear(skippedPrefabs, 0, skippedPrefabs.Length); loadingLock = Util.Get(LoadingManager.instance, "m_loadingLock"); mainThreadQueue = (Queue <IEnumerator>)Util.Get(LoadingManager.instance, "m_mainThreadQueue"); if (!string.IsNullOrEmpty(playerScene)) { LoadingManager.instance.m_loadingProfilerScenes.BeginLoading(playerScene); op = SceneManager.LoadSceneAsync(playerScene, LoadSceneMode.Single); while (!op.isDone) // IL_2FF { LoadingManager.instance.SetSceneProgress(op.progress * 0.01f); yield return(null); } LoadingManager.instance.m_loadingProfilerScenes.EndLoading(); } while (!LoadingManager.instance.m_metaDataLoaded && !task.completedOrFailed) // IL_33C { yield return(null); } if (SimulationManager.instance.m_metaData == null) { SimulationManager.instance.m_metaData = new SimulationMetaData(); SimulationManager.instance.m_metaData.m_environment = "Sunny"; SimulationManager.instance.m_metaData.Merge(ngs); } try { Util.InvokeVoid(LoadingManager.instance, "MetaDataLoaded"); // OnCreated if loading from the main manu } catch (Exception e) { Util.DebugPrint("OnCreated: exception from some mod."); UnityEngine.Debug.LogException(e); } KeyValuePair <string, float>[] levels = SetLevels(); float currentProgress = 0.10f; for (i = 0; i < levels.Length; i++) { scene = levels[i].Key; LoadingManager.instance.m_loadingProfilerScenes.BeginLoading(scene); op = SceneManager.LoadSceneAsync(scene, LoadSceneMode.Additive); while (!op.isDone) { LoadingManager.instance.SetSceneProgress(currentProgress + op.progress * (levels[i].Value - currentProgress)); yield return(null); } LoadingManager.instance.m_loadingProfilerScenes.EndLoading(); currentProgress = levels[i].Value; } PrefabLoader.instance?.Revert(); if (Settings.settings.SkipPrefabs) { LoadingManager.instance.QueueLoadingAction(PrefabLoader.RemoveSkippedFromSimulation()); } // Some major mods (Network Extensions 1 & 2, Single Train Track, Metro Overhaul) have a race condition issue // in their NetInfo Installer. Everything goes fine if LoadCustomContent() below is NOT queued before the // said Installers have finished. This is just a workaround for the issue. The actual fix should be in // the Installers. Notice that the built-in loader of the game is also affected. do { yield return(null); yield return(null); lock (loadingLock) { i = mainThreadQueue.Count; } }while (i > 0); AssetLoader.Create().Setup(); LoadingManager.instance.QueueLoadingAction(AssetLoader.instance.LoadCustomContent()); RenderManager.Managers_CheckReferences(); LoadingManager.instance.QueueLoadingAction((IEnumerator)Util.Invoke(LoadingManager.instance, "EssentialScenesLoaded")); RenderManager.Managers_InitRenderData(); LoadingManager.instance.QueueLoadingAction((IEnumerator)Util.Invoke(LoadingManager.instance, "RenderDataReady")); simulationFailed = HasFailed(task); // Performance optimization: do not load scenes while custom assets are loading. while (!assetsFinished) { yield return(null); } scene = SimulationManager.instance.m_metaData.m_environment + "Properties"; if (!string.IsNullOrEmpty(scene)) { LoadingManager.instance.m_loadingProfilerScenes.BeginLoading(scene); op = SceneManager.LoadSceneAsync(scene, LoadSceneMode.Additive); while (!op.isDone) // IL_C47 { LoadingManager.instance.SetSceneProgress(0.85f + op.progress * 0.05f); yield return(null); } LoadingManager.instance.m_loadingProfilerScenes.EndLoading(); } if (!simulationFailed) { simulationFailed = HasFailed(task); } if (!string.IsNullOrEmpty(uiScene)) // IL_C67 { LoadingManager.instance.m_loadingProfilerScenes.BeginLoading(uiScene); op = SceneManager.LoadSceneAsync(uiScene, LoadSceneMode.Additive); while (!op.isDone) // IL_CDE { LoadingManager.instance.SetSceneProgress(0.90f + op.progress * 0.08f); yield return(null); } LoadingManager.instance.m_loadingProfilerScenes.EndLoading(); } LoadingManager.instance.m_loadedEnvironment = SimulationManager.instance.m_metaData.m_environment; // IL_CFE LoadingManager.instance.m_loadedMapTheme = SimulationManager.instance.m_metaData.m_MapThemeMetaData?.name; } else { scene = (string)Util.Invoke(LoadingManager.instance, "GetLoadingScene"); if (!string.IsNullOrEmpty(scene)) { LoadingManager.instance.m_loadingProfilerScenes.BeginLoading(scene); yield return(SceneManager.LoadSceneAsync(scene, LoadSceneMode.Additive)); LoadingManager.instance.m_loadingProfilerScenes.EndLoading(); } } LoadingManager.instance.SetSceneProgress(1f); // IL_DBF if (!simulationFailed) { simulationFailed = HasFailed(task); } while (!task.completedOrFailed) // IL_DED { yield return(null); } LoadingManager.instance.m_simulationDataLoaded = LoadingManager.instance.m_metaDataLoaded; LoadingManager.SimulationDataReadyHandler SimDataReady = Util.Get(LoadingManager.instance, "m_simulationDataReady") as LoadingManager.SimulationDataReadyHandler; SimDataReady?.Invoke(); SimulationManager.UpdateMode mode = SimulationManager.UpdateMode.Undefined; if (ngs != null) { mode = ngs.m_updateMode; } LoadingManager.instance.QueueLoadingAction(CheckPolicies()); LoadingManager.instance.QueueLoadingAction((IEnumerator)Util.Invoke(LoadingManager.instance, "LoadLevelComplete", mode)); // OnLevelLoaded PrefabLoader.instance?.Dispose(); LoadingManager.instance.QueueLoadingAction(LoadingComplete()); knownFastLoads[asset.checksum] = true; AssetLoader.PrintMem(); }
public IEnumerator LoadCustomContent() { LoadingManager.instance.m_loadingProfilerMain.BeginLoading("LoadCustomContent"); LoadingManager.instance.m_loadingProfilerCustomContent.Reset(); LoadingManager.instance.m_loadingProfilerCustomAsset.Reset(); LoadingManager.instance.m_loadingProfilerCustomContent.BeginLoading("District Styles"); LoadingManager.instance.m_loadingProfilerCustomAsset.PauseLoading(); LevelLoader.instance.assetsStarted = true; int i, j; DistrictStyle districtStyle; DistrictStyleMetaData districtStyleMetaData; List <DistrictStyle> districtStyles = new List <DistrictStyle>(); HashSet <string> styleBuildings = new HashSet <string>(); FastList <DistrictStyleMetaData> districtStyleMetaDatas = new FastList <DistrictStyleMetaData>(); FastList <Package> districtStylePackages = new FastList <Package>(); Package.Asset europeanStyles = PackageManager.FindAssetByName("System." + DistrictStyle.kEuropeanStyleName); if (europeanStyles != null && europeanStyles.isEnabled) { districtStyle = new DistrictStyle(DistrictStyle.kEuropeanStyleName, true); Util.InvokeVoid(LoadingManager.instance, "AddChildrenToBuiltinStyle", GameObject.Find("European Style new"), districtStyle, false); Util.InvokeVoid(LoadingManager.instance, "AddChildrenToBuiltinStyle", GameObject.Find("European Style others"), districtStyle, true); if (Settings.settings.SkipPrefabs) { PrefabLoader.RemoveSkippedFromStyle(districtStyle); } districtStyles.Add(districtStyle); } if ((bool)typeof(LoadingManager).GetMethod("DLC", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(LoadingManager.instance, new object[] { 715190u })) { Package.Asset asset = PackageManager.FindAssetByName("System." + DistrictStyle.kEuropeanSuburbiaStyleName); if (asset != null && asset.isEnabled) { districtStyle = new DistrictStyle(DistrictStyle.kEuropeanSuburbiaStyleName, true); Util.InvokeVoid(LoadingManager.instance, "AddChildrenToBuiltinStyle", GameObject.Find("Modder Pack 3"), districtStyle, false); if (Settings.settings.SkipPrefabs) { PrefabLoader.RemoveSkippedFromStyle(districtStyle); } districtStyles.Add(districtStyle); } } if (Settings.settings.SkipPrefabs) { PrefabLoader.UnloadSkipped(); } foreach (Package.Asset asset in PackageManager.FilterAssets(UserAssetType.DistrictStyleMetaData)) { try { if (asset != null && asset.isEnabled) { districtStyleMetaData = asset.Instantiate <DistrictStyleMetaData>(); if (districtStyleMetaData != null && !districtStyleMetaData.builtin) { districtStyleMetaDatas.Add(districtStyleMetaData); districtStylePackages.Add(asset.package); if (districtStyleMetaData.assets != null) { for (i = 0; i < districtStyleMetaData.assets.Length; i++) { styleBuildings.Add(districtStyleMetaData.assets[i]); } } } } } catch (Exception ex) { CODebugBase <LogChannel> .Warn(LogChannel.Modding, string.Concat(new object[] { ex.GetType(), ": Loading custom district style failed[", asset, "]\n", ex.Message })); } } LoadingManager.instance.m_loadingProfilerCustomAsset.ContinueLoading(); LoadingManager.instance.m_loadingProfilerCustomContent.EndLoading(); if (Settings.settings.loadUsed) { UsedAssets.Create(); } lastMillis = Profiling.Millis; LoadingScreen.instance.DualSource.Add("Custom Assets"); LoadingManager.instance.m_loadingProfilerCustomContent.BeginLoading("Calculating asset load order"); Package.Asset[] queue = GetLoadQueue(styleBuildings); Util.DebugPrint("LoadQueue", queue.Length, Profiling.Millis); LoadingManager.instance.m_loadingProfilerCustomContent.EndLoading(); plugins = (Dictionary <string, PluginInfo>)Util.Get(Singleton <PluginManager> .instance, "m_Plugins"); //PrintPlugins(); LoadingManager.instance.m_loadingProfilerCustomContent.BeginLoading("Loading Custom Assets"); Sharing.instance.Start(queue); beginMillis = Profiling.Millis; for (i = 0; i < queue.Length; i++) { Package.Asset assetRef = queue[i]; if ((i & 63) == 0) { PrintMem(i); } Sharing.instance.WaitForWorkers(); try { stack.Clear(); LoadImpl(assetRef); } catch (Exception e) { AssetFailed(assetRef, assetRef.package, e); } Sharing.instance.ManageLoadQueue(i); if (Profiling.Millis - lastMillis > yieldInterval) { lastMillis = Profiling.Millis; progress = 0.15f + (i + 1) * 0.7f / queue.Length; LoadingScreen.instance.SetProgress(progress, progress, assetCount, assetCount - i - 1 + queue.Length, beginMillis, lastMillis); yield return(null); } } lastMillis = Profiling.Millis; LoadingScreen.instance.SetProgress(0.85f, 1f, assetCount, assetCount, beginMillis, lastMillis); LoadingManager.instance.m_loadingProfilerCustomContent.EndLoading(); Util.DebugPrint("Custom assets loaded in", lastMillis - beginMillis); PrintMem(); queue = null; stack.Clear(); Report(); LoadingManager.instance.m_loadingProfilerCustomContent.BeginLoading("Finalizing District Styles"); LoadingManager.instance.m_loadingProfilerCustomAsset.PauseLoading(); for (i = 0; i < districtStyleMetaDatas.m_size; i++) { try { districtStyleMetaData = districtStyleMetaDatas.m_buffer[i]; districtStyle = new DistrictStyle(districtStyleMetaData.name, false); if (districtStylePackages.m_buffer[i].GetPublishedFileID() != PublishedFileId.invalid) { districtStyle.PackageName = districtStylePackages.m_buffer[i].packageName; } if (districtStyleMetaData.assets != null) { for (j = 0; j < districtStyleMetaData.assets.Length; j++) { BuildingInfo bi = CustomDeserializer.FindLoaded <BuildingInfo>(districtStyleMetaData.assets[j] + "_Data"); if (bi != null) { districtStyle.Add(bi); if (districtStyleMetaData.builtin) // this is always false { bi.m_dontSpawnNormally = !districtStyleMetaData.assetRef.isEnabled; } } else { CODebugBase <LogChannel> .Warn(LogChannel.Modding, "Warning: Missing asset (" + districtStyleMetaData.assets[j] + ") in style " + districtStyleMetaData.name); } } districtStyles.Add(districtStyle); } } catch (Exception ex) { CODebugBase <LogChannel> .Warn(LogChannel.Modding, ex.GetType() + ": Loading district style failed\n" + ex.Message); } } Singleton <DistrictManager> .instance.m_Styles = districtStyles.ToArray(); if (Singleton <BuildingManager> .exists) { Singleton <BuildingManager> .instance.InitializeStyleArray(districtStyles.Count); } LoadingManager.instance.m_loadingProfilerCustomAsset.ContinueLoading(); LoadingManager.instance.m_loadingProfilerCustomContent.EndLoading(); LoadingManager.instance.m_loadingProfilerMain.EndLoading(); LevelLoader.instance.assetsFinished = true; }