diff --git a/NewHorizons/Assets/DefaultMapModNoAtmoOutline.png b/NewHorizons/Assets/DefaultMapModNoAtmoOutline.png new file mode 100644 index 00000000..0e3954d3 Binary files /dev/null and b/NewHorizons/Assets/DefaultMapModNoAtmoOutline.png differ diff --git a/NewHorizons/Assets/DefaultMapModePlanetOutline.png b/NewHorizons/Assets/DefaultMapModePlanetOutline.png new file mode 100644 index 00000000..d2534b61 Binary files /dev/null and b/NewHorizons/Assets/DefaultMapModePlanetOutline.png differ diff --git a/NewHorizons/Assets/DefaultMapModeStarOutline.png b/NewHorizons/Assets/DefaultMapModeStarOutline.png new file mode 100644 index 00000000..b002a0b0 Binary files /dev/null and b/NewHorizons/Assets/DefaultMapModeStarOutline.png differ diff --git a/NewHorizons/Builder/ShipLog/MapModeBuilder.cs b/NewHorizons/Builder/ShipLog/MapModeBuilder.cs index 9d66447f..eeb2b959 100644 --- a/NewHorizons/Builder/ShipLog/MapModeBuilder.cs +++ b/NewHorizons/Builder/ShipLog/MapModeBuilder.cs @@ -1,14 +1,12 @@ using NewHorizons.Components.ShipLog; using NewHorizons.External; using NewHorizons.External.Modules; -using NewHorizons.External.Modules.VariableSize; using NewHorizons.Handlers; using NewHorizons.Utility; using NewHorizons.Utility.Files; using NewHorizons.Utility.OuterWilds; using NewHorizons.Utility.OWML; using OWML.ModHelper; -using System; using System.Collections.Generic; using System.Linq; using UnityEngine; @@ -195,10 +193,10 @@ namespace NewHorizons.Builder.ShipLog string outlinePath = body.Config.ShipLog?.mapMode?.outlineSprite; if (imagePath != null) image = ImageUtilities.GetTexture(body.Mod, imagePath); - if (image == null) image = AutoGenerateMapModePicture(body); + if (image == null) image = ImageUtilities.AutoGenerateMapModePicture(body); if (outlinePath != null) outline = ImageUtilities.GetTexture(body.Mod, outlinePath); - if (outline == null) outline = ImageUtilities.MakeOutline(image, Color.white, 10); + if (outline == null) outline = ImageUtilities.GetCachedOutlineOrCreate(body, image, imagePath); astroObject._imageObj = CreateImage(gameObject, image, body.Config.name + " Revealed", layer); astroObject._outlineObj = CreateImage(gameObject, outline, body.Config.name + " Outline", layer); @@ -246,10 +244,10 @@ namespace NewHorizons.Builder.ShipLog string outlinePath = info.outlineSprite; if (imagePath != null) image = ImageUtilities.GetTexture(body.Mod, imagePath); - else image = AutoGenerateMapModePicture(body); + else image = ImageUtilities.AutoGenerateMapModePicture(body); if (outlinePath != null) outline = ImageUtilities.GetTexture(body.Mod, outlinePath); - else outline = ImageUtilities.MakeOutline(image, Color.white, 10); + else outline = ImageUtilities.GetCachedOutlineOrCreate(body, image, imagePath); Image revealedImage = CreateImage(detailGameObject, image, "Detail Revealed", parent.gameObject.layer).GetComponent(); Image outlineImage = CreateImage(detailGameObject, outline, "Detail Outline", parent.gameObject.layer).GetComponent(); @@ -605,68 +603,6 @@ namespace NewHorizons.Builder.ShipLog } #endregion - private static Texture2D AutoGenerateMapModePicture(NewHorizonsBody body) - { - Texture2D texture; - - if (body.Config.Star != null) texture = ImageUtilities.GetTexture(Main.Instance, "Assets/DefaultMapModeStar.png"); - else if (body.Config.Atmosphere != null) texture = ImageUtilities.GetTexture(Main.Instance, "Assets/DefaultMapModNoAtmo.png"); - else texture = ImageUtilities.GetTexture(Main.Instance, "Assets/DefaultMapModePlanet.png"); - - var color = GetDominantPlanetColor(body); - var darkColor = new Color(color.r / 3f, color.g / 3f, color.b / 3f); - - texture = ImageUtilities.LerpGreyscaleImage(texture, color, darkColor); - - return texture; - } - - private static Color GetDominantPlanetColor(NewHorizonsBody body) - { - try - { - var starColor = body.Config?.Star?.tint; - if (starColor != null) return starColor.ToColor(); - - var atmoColor = body.Config.Atmosphere?.atmosphereTint; - if (body.Config.Atmosphere?.clouds != null && atmoColor != null) return atmoColor.ToColor(); - - if (body.Config?.HeightMap?.textureMap != null) - { - try - { - var texture = ImageUtilities.GetTexture(body.Mod, body.Config.HeightMap.textureMap); - var landColor = ImageUtilities.GetAverageColor(texture); - if (landColor != null) return landColor; - } - catch (Exception) { } - } - - var waterColor = body.Config.Water?.tint; - if (waterColor != null) return waterColor.ToColor(); - - var lavaColor = body.Config.Lava?.tint; - if (lavaColor != null) return lavaColor.ToColor(); - - var sandColor = body.Config.Sand?.tint; - if (sandColor != null) return sandColor.ToColor(); - - switch (body.Config?.Props?.singularities?.FirstOrDefault()?.type) - { - case SingularityModule.SingularityType.BlackHole: - return Color.black; - case SingularityModule.SingularityType.WhiteHole: - return Color.white; - } - } - catch (Exception) - { - NHLogger.LogWarning($"Something went wrong trying to pick the colour for {body.Config.name} but I'm too lazy to fix it."); - } - - return Color.white; - } - #region Replacement private static List<(NewHorizonsBody, ModBehaviour, MapModeInfo)> _mapModIconsToUpdate = new(); public static void TryReplaceExistingMapModeIcon(NewHorizonsBody body, ModBehaviour mod, MapModeInfo info) diff --git a/NewHorizons/External/Modules/ShipLogModule.cs b/NewHorizons/External/Modules/ShipLogModule.cs index 3b9e5615..558ae650 100644 --- a/NewHorizons/External/Modules/ShipLogModule.cs +++ b/NewHorizons/External/Modules/ShipLogModule.cs @@ -61,7 +61,7 @@ namespace NewHorizons.External.Modules public float offset; /// - /// The path to the sprite (.png/.jpg/.exr) to show when the planet is unexplored in map mode. + /// The path to the sprite (.png/.jpg/.exr) to show when the planet is unexplored in map mode. If empty, a texture will be created and cached based on the revealed sprite. /// public string outlineSprite; diff --git a/NewHorizons/Handlers/InvulnerabilityHandler.cs b/NewHorizons/Handlers/InvulnerabilityHandler.cs index cacc9e19..85f45601 100644 --- a/NewHorizons/Handlers/InvulnerabilityHandler.cs +++ b/NewHorizons/Handlers/InvulnerabilityHandler.cs @@ -4,7 +4,7 @@ using UnityEngine.SceneManagement; namespace NewHorizons.Handlers { - internal class InvulnerabilityHandler + public static class InvulnerabilityHandler { /// /// Used in patches @@ -32,8 +32,25 @@ namespace NewHorizons.Handlers } } - private static DeathManager GetDeathManager() => GameObject.FindObjectOfType(); - private static PlayerResources GetPlayerResouces() => GameObject.FindObjectOfType(); + private static DeathManager _deathManager; + private static DeathManager GetDeathManager() + { + if (_deathManager == null) + { + _deathManager = GameObject.FindObjectOfType(); + } + return _deathManager; + } + + private static PlayerResources _playerResources; + private static PlayerResources GetPlayerResouces() + { + if (_playerResources == null) + { + _playerResources = GameObject.FindObjectOfType(); + } + return _playerResources; + } static InvulnerabilityHandler() { diff --git a/NewHorizons/Schemas/body_schema.json b/NewHorizons/Schemas/body_schema.json index cbe6f892..1cfb74f0 100644 --- a/NewHorizons/Schemas/body_schema.json +++ b/NewHorizons/Schemas/body_schema.json @@ -4746,7 +4746,7 @@ }, "outlineSprite": { "type": "string", - "description": "The path to the sprite (.png/.jpg/.exr) to show when the planet is unexplored in map mode." + "description": "The path to the sprite (.png/.jpg/.exr) to show when the planet is unexplored in map mode. If empty, a texture will be created and cached based on the revealed sprite." }, "remove": { "type": "boolean", diff --git a/NewHorizons/Utility/Files/ImageUtilities.cs b/NewHorizons/Utility/Files/ImageUtilities.cs index e124fe89..65f73aba 100644 --- a/NewHorizons/Utility/Files/ImageUtilities.cs +++ b/NewHorizons/Utility/Files/ImageUtilities.cs @@ -1,9 +1,12 @@ using NewHorizons.Builder.Props; +using NewHorizons.External; +using NewHorizons.External.Modules.VariableSize; using NewHorizons.Utility.OWML; using OWML.Common; using System; using System.Collections.Generic; using System.IO; +using System.Linq; using UnityEngine; namespace NewHorizons.Utility.Files @@ -101,8 +104,8 @@ namespace NewHorizons.Utility.Files DeleteTexture(key, texture); } - public static void DeleteTexture(string key, Texture2D texture) - { + public static void DeleteTexture(string key, Texture2D texture) + { if (_textureCache.ContainsKey(key)) { if (_textureCache[key] == texture) @@ -257,7 +260,7 @@ namespace NewHorizons.Utility.Files return texture; } - public static Texture2D MakeOutline(Texture2D texture, Color color, int thickness) + private static Texture2D MakeOutline(Texture2D texture, Color color, int thickness) { var key = $"{texture.name} > outline {color} {thickness}"; if (_textureCache.TryGetValue(key, out var existingTexture)) return (Texture2D)existingTexture; @@ -378,7 +381,7 @@ namespace NewHorizons.Utility.Files var pixels = image.GetPixels(); for (int i = 0; i < pixels.Length; i++) { - var amount = (i % image.width) / (float) image.width; + var amount = (i % image.width) / (float)image.width; var lightTint = LerpColor(lightTintStart, lightTintEnd, amount); var darkTint = LerpColor(darkTintStart, darkTintEnd, amount); @@ -499,5 +502,119 @@ namespace NewHorizons.Utility.Files sprite.name = texture.name; return sprite; } + + public static Texture2D GetCachedOutlineOrCreate(NewHorizonsBody body, Texture2D original, string originalPath) + { + if (string.IsNullOrEmpty(originalPath)) + { + Texture2D defaultTexture = null; + if (body.Config.Star != null) + { + defaultTexture = ImageUtilities.GetTexture(Main.Instance, "Assets/DefaultMapModeStarOutline.png"); + } + else if (body.Config.Atmosphere != null) + { + defaultTexture = ImageUtilities.GetTexture(Main.Instance, "Assets/DefaultMapModNoAtmoOutline.png"); + } + else + { + defaultTexture = ImageUtilities.GetTexture(Main.Instance, "Assets/DefaultMapModePlanetOutline.png"); + } + + return defaultTexture; + } + else + { + var cachedPath = Path.Combine(body.Mod.ModHelper.Manifest.ModFolderPath, $"TextureCache_{Main.Instance.CurrentStarSystem}", originalPath); + var outlineTexture = ImageUtilities.GetTexture(body.Mod, cachedPath); + + if (outlineTexture == null) + { + NHLogger.LogVerbose($"Caching outline to {cachedPath}"); + + var newTexture = ImageUtilities.MakeOutline(original, Color.white, 10); + + Directory.CreateDirectory(Path.GetDirectoryName(cachedPath)); + File.WriteAllBytes(cachedPath, newTexture.EncodeToPNG()); + + return newTexture; + } + else + { + return outlineTexture; + } + } + } + + public static Texture2D AutoGenerateMapModePicture(NewHorizonsBody body) + { + Texture2D texture; + + if (body.Config.Star != null) + { + texture = ImageUtilities.GetTexture(Main.Instance, "Assets/DefaultMapModeStar.png"); + } + else if (body.Config.Atmosphere != null) + { + texture = ImageUtilities.GetTexture(Main.Instance, "Assets/DefaultMapModNoAtmo.png"); + } + else + { + texture = ImageUtilities.GetTexture(Main.Instance, "Assets/DefaultMapModePlanet.png"); + } + + var color = GetDominantPlanetColor(body); + var darkColor = new Color(color.r / 3f, color.g / 3f, color.b / 3f); + + texture = ImageUtilities.LerpGreyscaleImage(texture, color, darkColor); + + return texture; + } + + private static Color GetDominantPlanetColor(NewHorizonsBody body) + { + try + { + var starColor = body.Config?.Star?.tint; + if (starColor != null) return starColor.ToColor(); + + var atmoColor = body.Config.Atmosphere?.atmosphereTint; + if (body.Config.Atmosphere?.clouds != null && atmoColor != null) return atmoColor.ToColor(); + + if (body.Config?.HeightMap?.textureMap != null) + { + try + { + var texture = ImageUtilities.GetTexture(body.Mod, body.Config.HeightMap.textureMap); + var landColor = ImageUtilities.GetAverageColor(texture); + if (landColor != null) return landColor; + } + catch (Exception) { } + } + + var waterColor = body.Config.Water?.tint; + if (waterColor != null) return waterColor.ToColor(); + + var lavaColor = body.Config.Lava?.tint; + if (lavaColor != null) return lavaColor.ToColor(); + + var sandColor = body.Config.Sand?.tint; + if (sandColor != null) return sandColor.ToColor(); + + switch (body.Config?.Props?.singularities?.FirstOrDefault()?.type) + { + case SingularityModule.SingularityType.BlackHole: + return Color.black; + case SingularityModule.SingularityType.WhiteHole: + return Color.white; + } + } + catch (Exception) + { + NHLogger.LogWarning($"Something went wrong trying to pick the colour for {body.Config.name} but I'm too lazy to fix it."); + } + + return Color.white; + } } }