/// <summary> /// Insert our list of tips into the specified loading screen state. /// </summary> /// <param name="state"></param> private static void InsertTips(LoadingScreen.LoadingScreenState state) { List <string> tipsList = new List <string>(); tipsList.AddRange(state.tips); tipsList.AddRange(NEW_TIPS); state.tips = tipsList.ToArray(); }
void LoadScreen(LoadingScreen.LoadingScreenState screen) { // Add the texture to the Loading Screens List <Object> newScreens = screen.screens.ToList(); newScreens.Add(texture); screen.screens = newScreens.ToArray(); }
internal void Awake() { LoadingScreen.LoadingScreenState state = FindLoadingScreenState(); if (state != null) { InsertTips(state); } }
internal void Awake() { LoadingScreen.LoadingScreenState state = FindLoadingScreenState(); if (state != null) { InsertTips(state); if (state.tipTime > MAX_TIP_TIME) { state.tipTime = MAX_TIP_TIME; } } }
/// <summary> /// Insert our list of tips into the specified loading screen state. /// </summary> /// <param name="state"></param> private static void InsertTips(LoadingScreen.LoadingScreenState state) { string[] newTips = new string[state.tips.Length + NEW_TIPS.Length]; for (int i = 0; i < state.tips.Length; ++i) { newTips[i] = state.tips[i]; } for (int i = 0; i < NEW_TIPS.Length; ++i) { newTips[state.tips.Length + i] = NEW_TIPS[i]; } state.tips = newTips; }
/// <summary> /// Insert our list of tips into the specified loading screen state. /// </summary> /// <param name="state"></param> private static void InsertTips(LoadingScreen.LoadingScreenState state) { List <string> tipsList = new List <string>(); tipsList.AddRange(state.tips); tipsList.AddRange(NEW_TIPS); int numThanks = 1 + (int)Mathf.Sqrt(THANK_USERS.Length); System.Random random = new System.Random(System.DateTime.UtcNow.Second); for (int i = 0; i < numThanks; ++i) { tipsList.Add(string.Format("Thanking {0}...", THANK_USERS[random.Next(THANK_USERS.Length)])); } state.tips = tipsList.ToArray(); }
void AddScreen(List <LoadingScreen.LoadingScreenState> newScreens, Texture2D texture, string[] tips) { // All normal loading screens (except the logo of course) get rebuilt to use the timings and images. // The default on the main screen is 40 minutes, so if we didn't do this the slideshow wouldn't work! var screen = new LoadingScreen.LoadingScreenState { displayTime = cfg._displayTime, fadeInTime = cfg._fadeInTime, fadeOutTime = cfg._fadeOutTime, tipTime = cfg._tipTime, screens = new[] { texture }, tips = tips }; newScreens.Add(screen); }
public virtual void UpdateScreens(LoadingScreen.LoadingScreenState screen) { StockLogo = (Texture2D)screen.screens.FirstOrDefault(t => t.name == "mainMenuBg"); List <string> newTips = SASSTips(); List <Texture2D> newScreens = SASSScreens(); if (newTips.Count > 0) { screen.tips = newTips.ToArray(); } if (newScreens.Count > 0) { screen.screens = newScreens.ToArray(); } }
/// <summary> /// Finds the loading screen where we want to tinker with the tips, /// or null if there's no suitable candidate. /// </summary> /// <returns></returns> private static LoadingScreen.LoadingScreenState FindLoadingScreenState() { if (LoadingScreen.Instance == null) { return(null); } List <LoadingScreen.LoadingScreenState> screens = LoadingScreen.Instance.Screens; if (screens == null) { return(null); } for (int i = 0; i < screens.Count; ++i) { LoadingScreen.LoadingScreenState state = screens[i]; if ((state != null) && (state.tips != null) && (state.tips.Length > 1)) { return(state); } } return(null); }
/// <summary> /// The core of the program that replaces the default LoadingScreen information with our customizations. /// </summary> private void ModifyLoadingScreens() { // We are going to rebuild the loaders and screens, so first grab the existing ones. // The logic is built to cope if mods and/or a future version change the screen types and/or ordering. Originally // I thought this would be YAGNI but it turns out some mods add loaders and not screens so in fact it is very // needed, and the first implementation did not quite go far enough! // I don't know why anything would clear these, but just in case... if (LoadingScreen.Instance.loaders == null) { Log.Error("** WARNING - Loaders not defined."); LoadingScreen.Instance.loaders = new List <LoadingSystem>(); } if (LoadingScreen.Instance.Screens == null) { Log.Error("** WARNING - Screens not defined."); LoadingScreen.Instance.Screens = new List <LoadingScreen.LoadingScreenState>(); } var gameDatabaseIndex = -1; LoadingSystem gameDatabaseLoader = null; LoadingScreen.LoadingScreenState gameDatabaseScreen = null; LoadingScreen.LoadingScreenState firstModifiableScreen = null; // It's possible something could have removed all loaders (in which case we'll just add ours later). if (LoadingScreen.Instance.loaders.Count > 0) { // The GameDatabase loader and its accompanying screen is the one that shows the SQUAD logo. Normally it's 1st, // but we find it dynamically in case some mod behaved badly and moved it. // *** IMPORTANT NOTE *** // Under KSP forum rules, mods may not modify the in-games logos, so please don't submit anything that makes // changes to these. All we are doing here is saving them so we can add them back later. gameDatabaseIndex = LoadingScreen.Instance.loaders.FindIndex(l => l is GameDatabase); if (gameDatabaseIndex >= 0) { if (gameDatabaseIndex != 0) { Log.Warning("** WARNING - Game Database Loader is not where expected."); } gameDatabaseLoader = LoadingScreen.Instance.loaders[gameDatabaseIndex]; gameDatabaseScreen = LoadingScreen.Instance.Screens[gameDatabaseIndex]; } else { Log.Error("** WARNING - Game Database Loader is not present."); } // The "normal" loading screen after the logo is supposed to be second, but a mod could have inserted one. // So the first screen that isn't the logo is the one we can modify. // Note that we just assume this screen has the "original" tips and screens. Could look for PartLoader to find // which index it is, but we don't need to be that strict. // Unless the *only* loader is the GameDatabase then there has to be a modifiable screen, and the only time it // can't be at index 0 is if the GameDatabase is (which is actually the norm). if (LoadingScreen.Instance.loaders.Count > 1 || gameDatabaseIndex < 0) { var firstModifiableIndex = gameDatabaseIndex == 0 ? 1 : 0; firstModifiableScreen = LoadingScreen.Instance.Screens[firstModifiableIndex]; } if (firstModifiableScreen == null) { Log.Warning("** WARNING - No existing modifiable loaders."); } } else { Log.Warning("** WARNING - No existing loaders found."); } var imageFilenames = this.GetImageFilenames(); var customTips = this.LoadCustomTips(); if (cfg._includeOriginalTips && firstModifiableScreen != null) { customTips.AddRange(firstModifiableScreen.tips); } var tips = customTips.ToArray(); if (cfg._includeOriginalScreens && firstModifiableScreen != null) { for (var i = 0; i < firstModifiableScreen.screens.Length; i++) { // Identify original by indexes, with a * in front so we know they can't be filenames. imageFilenames.Add($"*{i}"); } } if (cfg._forceSlideshowWithNoImageFiles || imageFilenames.Count > 0) { var newScreens = new List <LoadingScreen.LoadingScreenState>(cfg._maxSlides + 1); Texture2D texture; string[] ltips = new string[1]; // Add logo screens here Log.Info("Adding logoscreens: " + cfg.logoScreens.Count); for (int i = 0; i < cfg.logoScreens.Count; i++) { var s = cfg.logoScreens[i]; if (File.Exists(s)) { ltips[0] = cfg.logoTips[i]; if (LoadImageFile(s, out texture)) { AddScreen(newScreens, texture, ltips); } } } //int cnt = 0; while (newScreens.Count < cfg._maxSlides && imageFilenames.Count > 0) { string filename; #if true int filenameIndex = this._random.Next(imageFilenames.Count); filename = imageFilenames[filenameIndex]; imageFilenames.RemoveAt(filenameIndex); #else filename = imageFilenames[cnt++]; #endif // A * in front of a filename denotes an original image (see above). if (filename[0] == '*') { Log.Info("Using original image: Index {0}", filename); Debug.Assert(firstModifiableScreen != null); // ReSharper doesn't recognize Unity's Assert() and I don't want to bother with external annotations... // ReSharper disable once PossibleNullReferenceException texture = (Texture2D)firstModifiableScreen.screens[int.Parse(filename.Substring(1))]; } else { if (!LoadImageFile(filename, out texture)) { continue; } } texture.name = filename; Log.Info("Adding image: " + filename); AddScreen(newScreens, texture, tips); } // Existing loaders are saved to be added at the end. See below for why. var existingLoaders = new List <LoadingSystem>(cfg._maxSlides + 1); // ReSharper disable once LoopCanBeConvertedToQuery for (var i = 0; i < LoadingScreen.Instance.loaders.Count; i++) { if (i != gameDatabaseIndex) { existingLoaders.Add(LoadingScreen.Instance.loaders[i]); } } var totalDummyLoaders = newScreens.Count - existingLoaders.Count; var newLoaders = new List <LoadingSystem>(cfg._maxSlides + 1); for (var i = 0; i < totalDummyLoaders; i++) { newLoaders.Add(new DummyLoader()); } // Add the logo stuff to the start. Note if some mod had moved it, this will get undone. if (gameDatabaseLoader != null) { newLoaders.Insert(0, gameDatabaseLoader); newScreens.Insert(0, gameDatabaseScreen); } // Add existing loaders at the end. // The reason we put our loaders first is that, for some reason I haven't been able to figure out, they will // disrupt the progress bar partway through, but at least if they're at the end the progress bar will end up // going to 100% eventually. If we just tacked them onto the end the progress bar would finish at like 20%, // which would look bad to the user. newLoaders.AddRange(existingLoaders); LoadingScreen.Instance.loaders = newLoaders; LoadingScreen.Instance.Screens = newScreens; // Raw counts for debugging. Log.Info("{0} loaders set{1}", newLoaders.Count, gameDatabaseIndex >= 0 ? " (including GameDatabase)" : ""); Log.Info("{0} raw screens set{1}", newScreens.Count, gameDatabaseIndex >= 0 ? " (including logo)" : ""); // Slide count. The logo is not counted as a slide. slideCount = gameDatabaseIndex >= 0 ? newScreens.Count - 1 : newScreens.Count; Log.Info("{0} slides set", slideCount); if (slideCount < cfg._maxSlides) { Log.Info("** WARNING: Not enough images available ({0}) to meet requested number of slides ({1}).", slideCount, cfg._maxSlides); } #if DEBUG for (int i = 0; i < slideCount; i++) { Log.Info("Texture # : " + i + ", name: " + newScreens[i].screens[0].name); } #endif } }
protected void Update() { if (done || LoadingScreen.Instance == null) { return; } if (LoadingScreen.Instance.Screens.Count < 1) { return; } //foreach (LoadingScreen.LoadingScreenState state in LoadingScreen.Instance.Screens) //{ // Debug.Log("*pLRTR found a state. Disp/In/Out" + state.displayTime + ", " + state.fadeInTime + ", " + state.fadeOutTime // + "\nHas " + state.screens.Length + " screens. Tips:"); // string s = string.Empty; // foreach (string t in state.tips) // s += " " + t; // Debug.Log(s); //} try { Debug.Log("[LRTR]: Replacing loading screens."); int loadingScreenIdx = Versioning.version_minor < 4 ? 1 : 3; // KSP 1.4+ has 2 extra loading screens LoadingScreen.LoadingScreenState origState = LoadingScreen.Instance.Screens[loadingScreenIdx]; List <Texture2D> textures = new List <Texture2D>(); DirectoryInfo di = new DirectoryInfo(KSPUtil.ApplicationRootPath + "GameData/LRTR/pluginData/Screens"); foreach (FileInfo fi in di.GetFiles()) { if (fi.FullName.ToLowerInvariant().EndsWith(".dds")) { //Debug.Log("Loading " + fi.FullName); try { Texture2D t = LoadDDS(fi.FullName); if (t != null) { textures.Add(t); } } catch (Exception e) { Debug.LogError("[LRTR]: Exception loading " + fi.FullName + ":\n" + e); } } } int tC = textures.Count; if (tC > 0) { LoadingScreen.LoadingScreenState sc = LoadingScreen.Instance.Screens[loadingScreenIdx]; sc.screens = textures.ToArray(); sc.displayTime = 8; // Default value is 4 which causes the images to switch too quickly var newTips = LoadTips(); if (newTips?.Length > 0) { sc.tips = newTips; sc.tipTime = float.MaxValue; // Change only when the loading screen image is switched } string msgStr = "[LRTR]: Loading screens replaced."; Debug.Log(msgStr); } else { Debug.LogError("[LRTR]: No screens found in LRTR/LRRealProgression/PluginData/Screens!"); } } catch (Exception e) { Debug.LogError("[LRTR]: Patching failed: with error " + error + ", exception " + e); } GameObject.Destroy(this); done = true; }
protected void Update() { if (done || LoadingScreen.Instance == null) { return; } if (LoadingScreen.Instance.Screens.Count < 1) { return; } //foreach (LoadingScreen.LoadingScreenState state in LoadingScreen.Instance.Screens) //{ // Debug.Log("*pRP1 found a state. Disp/In/Out" + state.displayTime + ", " + state.fadeInTime + ", " + state.fadeOutTime // + "\nHas " + state.screens.Length + " screens. Tips:"); // string s = string.Empty; // foreach (string t in state.tips) // s += " " + t; // Debug.Log(s); //} try { Debug.Log("[RP-0]: Replacing loading screens."); LoadingScreen.LoadingScreenState origState = LoadingScreen.Instance.Screens[1]; List <Texture2D> textures = new List <Texture2D>(); DirectoryInfo di = new DirectoryInfo(KSPUtil.ApplicationRootPath + "GameData/RP-0/PluginData/Screens"); foreach (FileInfo fi in di.GetFiles()) { if (fi.FullName.ToLowerInvariant().EndsWith(".dds")) { //Debug.Log("Loading " + fi.FullName); try { Texture2D t = LoadDDS(fi.FullName); if (t != null) { textures.Add(t); } } catch (Exception e) { Debug.LogError("[RP-0]: Exception loading " + fi.FullName + ":\n" + e); } } } int tC = textures.Count; if (tC > 0) { LoadingScreen.LoadingScreenState sc = LoadingScreen.Instance.Screens[1]; sc.screens = textures.ToArray(); sc.displayTime = 8; // Default value is 4 which causes the images to switch too quickly string msgStr = "[RP-0]: Loading screens replaced."; Debug.Log(msgStr); } else { Debug.LogError("[RP-0]: No screens found in RP-0/PluginData/Screens!"); } } catch (Exception e) { Debug.LogError("[RP-0]: Patching failed: with error " + error + ", exception " + e); } GameObject.Destroy(this); done = true; }
protected void Update() { if (done || LoadingScreen.Instance == null) { return; } if (LoadingScreen.Instance.Screens.Count < 2) { return; } try { Debug.Log("[RP-0]: Replacing loading screens."); LoadingScreen.LoadingScreenState origState = LoadingScreen.Instance.Screens[1]; List <Texture2D> textures = new List <Texture2D>(); DirectoryInfo di = new DirectoryInfo(KSPUtil.ApplicationRootPath + "GameData/RP-0/PluginData/Screens"); foreach (FileInfo fi in di.GetFiles()) { if (fi.FullName.ToLowerInvariant().EndsWith(".dds")) { Debug.Log("Loading " + fi.FullName); try { Texture2D t = LoadDDS(fi.FullName); if (t != null) { textures.Add(t); } } catch (Exception e) { Debug.LogError("[RP-0]: Exception loading " + fi.FullName + ":\n" + e); } } } int tC = textures.Count; float screenTime = Mathf.Round(240f / (float)tC); System.Random random = new System.Random(); if (tC > 0) { for (int i = tC - 1; i-- > 0;) { int idx = random.Next(0, textures.Count); LoadingScreen.LoadingScreenState state = new LoadingScreen.LoadingScreenState(); state.fadeInTime = origState.fadeInTime; state.fadeOutTime = origState.fadeOutTime; state.displayTime = screenTime; state.tips = origState.tips; state.tipTime = origState.tipTime; state.screens = new Texture2D[] { textures[idx] }; LoadingScreen.Instance.Screens.Add(state); textures.RemoveAt(idx); LoadingScreen.Instance.loaders.Add(LoadingScreen.Instance.gameObject.AddComponent <DummyLoadingSystem>()); } origState.screens = new Texture2D[] { textures[0] }; origState.displayTime = screenTime; LoadingScreen.Instance.Screens[LoadingScreen.Instance.Screens.Count - 1].displayTime = 2400f; string msgStr = "[RP-0]: Loading screens replaced."; Debug.Log(msgStr); } else { Debug.LogError("[RP-0]: No screens found in RP-0/PluginData/Screens!"); } // Try to jigger the unity random thing. for (int i = (int)((new System.Random()).NextDouble() * 100d); i-- > 0;) { UnityEngine.Random.Range(0, 10); } } catch (Exception e) { Debug.LogError("Patching failed: " + e); } GameObject.Destroy(this); done = true; }