diff --git a/ConsoleUtils.cs b/ConsoleUtils.cs new file mode 100644 index 0000000..b1a2f05 --- /dev/null +++ b/ConsoleUtils.cs @@ -0,0 +1,28 @@ +using HarmonyLib; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEngine; + +namespace VSideLoader +{ + [HarmonyPatch(typeof(Console), "InputText")] + internal static class ConsoleUtils + { + public static void Postfix(ref Console __instance) + { + string text = __instance.m_input.text; + string[] array = text.Split(' '); + if (array.Length > 0) + { + if (array[0] == "reloadtextures") + { + TextureReplacement.HandleTextures(false); + __instance.Print("Reloaded textures"); + } + } + } + } +} diff --git a/README.md b/README.md index 20b94c0..e81ae64 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,8 @@ BepInEx\plugins\Textures\Dump BepInEx\plugins\Textures\Load It will also create a config file at BepInEx\config\VSideLoader.cfg +VSideLoader adds a new command called "reloadtextures", to quickly reload textures in game + Dump: (default false) If enabled, dumps all textures to the `BepInEx\plugins\Textures\Dump` folder Load: (default true) diff --git a/TextureInfo.cs b/TextureInfo.cs new file mode 100644 index 0000000..b94c096 --- /dev/null +++ b/TextureInfo.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEngine; + +namespace VSideLoader +{ + internal class TextureInfo + { + internal Texture2D tex; + internal DateTime time; + + internal TextureInfo(Texture2D tex, DateTime time) + { + this.tex = tex; + this.time = time; + } + } +} diff --git a/TextureReplacement.cs b/TextureReplacement.cs index 5dcde77..51d5b90 100644 --- a/TextureReplacement.cs +++ b/TextureReplacement.cs @@ -14,7 +14,7 @@ namespace VSideLoader internal static class TextureReplacement { private static Dictionary texSet = new Dictionary(); - private static Dictionary loadedTextures = new Dictionary(); + private static Dictionary loadedTextures = new Dictionary(); private static string[] smokeNames = { "aoe_smoke_MainTex", @@ -53,7 +53,7 @@ internal static class TextureReplacement "_SnowNormal" }; - internal static void OnSceneLoaded(Scene scene, LoadSceneMode loadSceneMode) + internal static void HandleTextures(bool allowDump) { string basePath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "Textures"); string dumpPath = Path.Combine(basePath, "Dump"); @@ -75,7 +75,7 @@ internal static void OnSceneLoaded(Scene scene, LoadSceneMode loadSceneMode) Texture texture = material.GetTexture(propertyName); if (texture != null) { - bool dumpTexture = true; + bool dumpTexture = allowDump; if (Settings.useTextureName.Value && !Settings.ignoreName.Contains(texture.name)) { texName = texture.name; @@ -92,7 +92,7 @@ internal static void OnSceneLoaded(Scene scene, LoadSceneMode loadSceneMode) { texName = matTexName; } - if (Settings.blackList.Contains(texName) || loadedTextures.ContainsValue(texture)) + if (Settings.blackList.Contains(texName) || loadedTextures.Any(pair => pair.Value.tex == texture)) { // ignore texture dumpTexture = false; @@ -145,39 +145,55 @@ internal static void OnSceneLoaded(Scene scene, LoadSceneMode loadSceneMode) if (File.Exists(texPath)) { Texture2D tex; + bool needsLoad = false; + DateTime time = File.GetLastWriteTime(texPath); if (loadedTextures.ContainsKey(texPath)) { - tex = (Texture2D)loadedTextures[texPath]; // Reuse existing texture + tex = loadedTextures[texPath].tex; // Reuse existing texture + if (!loadedTextures[texPath].time.Equals(time)) + { + needsLoad = true; + } } else { tex = new Texture2D(2, 2, TextureFormat.RGBA32, true, normalMap.Contains(propertyName)); - loadedTextures.Add(texPath, tex); + loadedTextures.Add(texPath, new TextureInfo(tex, new DateTime())); + needsLoad = true; } if (texture != null) { tex.name = texture.name; } tex.filterMode = Settings.textureFilter.Value; - if (tex.LoadImage(File.ReadAllBytes(texPath), !Settings.normalFix.Contains(propertyName))) + if (needsLoad) { - if (Settings.normalFix.Contains(propertyName) && tex.isReadable) + if (tex.LoadImage(File.ReadAllBytes(texPath), !Settings.normalFix.Contains(propertyName))) { - Color[] pixels = tex.GetPixels(); - for (int i = 0; i < pixels.Length; i++) + if (Settings.normalFix.Contains(propertyName) && tex.isReadable) { - pixels[i].a = pixels[i].r; - pixels[i].r = 1f; - pixels[i].b = pixels[i].g; + Color[] pixels = tex.GetPixels(); + for (int i = 0; i < pixels.Length; i++) + { + pixels[i].a = pixels[i].r; + pixels[i].r = 1f; + pixels[i].b = pixels[i].g; + } + tex.SetPixels(pixels); } - tex.SetPixels(pixels); + VSideLoader.Logger.LogInfo("Loaded " + Path.GetFileName(texPath) + " (" + tex.width + "x" + tex.height + ") for " + material.name + "." + propertyName); + material.SetTexture(propertyName, tex); + loadedTextures[texPath].time = time; + } + else + { + VSideLoader.Logger.LogError("Failed to load " + Path.GetFileName(texPath)); } - VSideLoader.Logger.LogInfo("Loaded " + Path.GetFileName(texPath) + " (" + tex.width + "x" + tex.height + ") for " + material.name + "." + propertyName); - material.SetTexture(propertyName, tex); } else { - VSideLoader.Logger.LogError("Failed to load " + Path.GetFileName(texPath)); + VSideLoader.Logger.LogInfo("Reusing loaded texture " + Path.GetFileName(texPath) + " for " + material.name + "." + propertyName); + material.SetTexture(propertyName, tex); } } } @@ -189,6 +205,11 @@ internal static void OnSceneLoaded(Scene scene, LoadSceneMode loadSceneMode) } } + internal static void OnSceneLoaded(Scene scene, LoadSceneMode loadSceneMode) + { + HandleTextures(true); + } + private static Texture2D DuplicateTexture(Texture2D source) { // TODO: This is causing very slight 1 bit corruption diff --git a/VSideLoader.csproj b/VSideLoader.csproj index f70fcec..bd1248a 100644 --- a/VSideLoader.csproj +++ b/VSideLoader.csproj @@ -35,8 +35,10 @@ + + @@ -377,4 +379,4 @@ - \ No newline at end of file +