diff --git a/NewHorizons/Assets/title-screen.json b/NewHorizons/Assets/title-screen.json new file mode 100644 index 00000000..cb6ea336 --- /dev/null +++ b/NewHorizons/Assets/title-screen.json @@ -0,0 +1,11 @@ +{ + "disableNHPlanets": false, + "mergeWithOtherTitles": true, + // FOR TESTING!!!! + // Remove once actually loading a json file is implemented + "menuTextTint": { + "r": 128, + "g": 128, + "b": 255 + } +} \ No newline at end of file diff --git a/NewHorizons/External/Configs/TitleScreenConfig.cs b/NewHorizons/External/Configs/TitleScreenConfig.cs index cd2e40fd..3ae2f0ee 100644 --- a/NewHorizons/External/Configs/TitleScreenConfig.cs +++ b/NewHorizons/External/Configs/TitleScreenConfig.cs @@ -1,10 +1,8 @@ +using NewHorizons.External.Modules; +using NewHorizons.External.Modules.Props; using NewHorizons.External.SerializableData; +using NewHorizons.Handlers; using Newtonsoft.Json; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace NewHorizons.External.Configs { @@ -15,5 +13,73 @@ namespace NewHorizons.External.Configs /// Colour of the text on the main menu /// public MColor menuTextTint; + + /// + /// Ship log fact required for this title screen to appear. + /// + public string factRequiredForTitle; + + /// + /// Persistent condition required for this title screen to appear. + /// + public string conditionRequiredForTitle; + + /// + /// If set to true, NH generated planets will not show on the title screen. If false, this title screen has the same chance as other NH planet title screens to show. + /// + public bool disableNHPlanets = true; + + /// + /// If set to true, this custom title screen will merge with all other custom title screens with shareTitleScreen set to true. If false, NH will randomly select between this and other valid title screens that are loaded. + /// + public bool shareTitleScreen = true; + + /// + /// Customize the skybox for this title screen + /// + public SkyboxModule Skybox; + + /// + /// Relative path to music to replace the title screen music with. + /// + public string music; + + /// + /// Changes the speed the main menu planet and the skybox rotates. + /// + public float rotationSpeed; + + /// + /// Edit properties of the main menu planet + /// + public MenuPlanetModule MenuPlanet; + + [JsonObject] + public class MenuPlanetModule + { + /// + /// Disables the renderers of the main menu planet and all objects on it (this is to improve compatibility with other mods that don't use the NH title screen json). + /// + public bool destroyMenuPlanet = false; + + /// + /// Disables the renderers of objects at the provided paths + /// + public string[] removeChildren; + + /// + /// A list of DetailInfos to populate the main menu planet with. + /// + public SimplifiedDetailInfo[] details; + } + + /// + /// Extra data that may be used by extension mods + /// + public object extras; + + public bool KnowsFact() => string.IsNullOrEmpty(factRequiredForTitle) || ShipLogHandler.KnowsFact(factRequiredForTitle); + + public bool HasCondition() => string.IsNullOrEmpty(conditionRequiredForTitle) || PlayerData.GetPersistentCondition(conditionRequiredForTitle); } } diff --git a/NewHorizons/Handlers/TitleSceneHandler.cs b/NewHorizons/Handlers/TitleSceneHandler.cs index 5c8a13d1..4aa0293f 100644 --- a/NewHorizons/Handlers/TitleSceneHandler.cs +++ b/NewHorizons/Handlers/TitleSceneHandler.cs @@ -1,10 +1,13 @@ using NewHorizons.Builder.Body; +using NewHorizons.Builder.StarSystem; using NewHorizons.External; using NewHorizons.External.Configs; using NewHorizons.External.Modules; +using NewHorizons.External.Modules.Props; using NewHorizons.Handlers.TitleScreen; using NewHorizons.Utility; using NewHorizons.Utility.OWML; +using OWML.Common; using System.Collections.Generic; using System.Linq; using UnityEngine; @@ -28,12 +31,82 @@ namespace NewHorizons.Handlers subtitleContainer.AddComponent(); } - public static void SetUp(TitleScreenConfig config) + public static void SetUp(IModBehaviour mod, TitleScreenConfig config) { if (config.menuTextTint != null) { TitleScreenColourHandler.SetColour(config.menuTextTint.ToColor()); } + + if (config.Skybox?.destroyStarField ?? false) + { + Object.Destroy(SearchUtilities.Find("Skybox/Starfield")); + } + + if (config.Skybox?.rightPath != null || + config.Skybox?.leftPath != null || + config.Skybox?.topPath != null || + config.Skybox?.bottomPath != null || + config.Skybox?.frontPath != null || + config.Skybox?.bottomPath != null) + { + SkyboxBuilder.Make(config.Skybox, mod); + } + + if (!string.IsNullOrEmpty(config.music)) + { + //TODO: Implement + } + + if (config.MenuPlanet != null) + { + if (config.MenuPlanet.destroyMenuPlanet) + { + //TODO: Implement + } + + if (config.MenuPlanet.removeChildren != null) + { + //TODO: Implement + //RemoveChildren(null, config.MenuPlanet.removeChildren); + } + + if (config.MenuPlanet.details != null) + { + foreach (var simplifiedDetail in config.MenuPlanet.details) + { + var detail = new DetailInfo(simplifiedDetail); + //TODO: Implement + } + } + } + } + + private static void RemoveChildren(GameObject go, string[] paths) + { + var goPath = go.transform.GetPath(); + var transforms = go.GetComponentsInChildren(true); + foreach (var childPath in paths) + { + // Multiple children can have the same path so we delete all that match + var path = $"{goPath}/{childPath}"; + + var flag = true; + foreach (var childObj in transforms.Where(x => x.GetPath() == path)) + { + flag = false; + // idk why we wait here but we do + Delay.FireInNUpdates(() => + { + if (childObj != null && childObj.gameObject != null) + { + childObj.gameObject.SetActive(false); + } + }, 2); + } + + if (flag) NHLogger.LogWarning($"Couldn't find \"{childPath}\"."); + } } public static void DisplayBodyOnTitleScreen(List bodies) diff --git a/NewHorizons/INewHorizons.cs b/NewHorizons/INewHorizons.cs index 350d0e2b..c9c3579e 100644 --- a/NewHorizons/INewHorizons.cs +++ b/NewHorizons/INewHorizons.cs @@ -96,6 +96,16 @@ namespace NewHorizons /// T QuerySystem(string path); + /// + /// Uses JSONPath to query a title screen config + /// + object QueryTitleScreen(Type outType, IModBehaviour mod, string path); + + /// + /// Uses JSONPath to query a title screen config + /// + T QueryTitleScreen(IModBehaviour mod, string path); + /// /// Register your own builder that will act on the given GameObject by reading the json string of its "extras" module /// @@ -222,5 +232,8 @@ namespace NewHorizons /// /// void SetNextSpawnID(string id); + + + void RegisterTitleScreenHandler(Action builder, bool deleteNHPlanets = true, bool shareTitleScreen = false, string conditionRequired = null, string factRequired = null); } } diff --git a/NewHorizons/Main.cs b/NewHorizons/Main.cs index 3885bfa0..2e6295cd 100644 --- a/NewHorizons/Main.cs +++ b/NewHorizons/Main.cs @@ -55,6 +55,7 @@ namespace NewHorizons public static Dictionary> BodyDict = new(); public static List MountedAddons = new(); public static Dictionary AddonConfigs = new(); + public static Dictionary TitleScreenConfigs = new(); public static float SecondsElapsedInLoop = -1; @@ -269,6 +270,7 @@ namespace NewHorizons OnChangeStarSystem.AddListener(RichPresenceHandler.OnChangeStarSystem); LoadAddonManifest("Assets/addon-manifest.json", this); + LoadTitleScreenConfig("Assets/title-screen.json", this); } public override void SetupPauseMenu(IPauseMenuManager pauseMenu) @@ -431,9 +433,9 @@ namespace NewHorizons } TitleSceneHandler.InitSubtitles(); - // FOR TESTING!!!! - // Remove once actually loading a json file is implemented - TitleSceneHandler.SetUp(new TitleScreenConfig() { menuTextTint = new External.SerializableData.MColor(128, 128, 255) }); + // TODO: Select one title screen and if it has shareTitleScreen set to true do all the other ones that have it true too. + var (mod, config) = Main.TitleScreenConfigs.FirstOrDefault(kvp => kvp.Value.KnowsFact() && kvp.Value.HasCondition()); + TitleSceneHandler.SetUp(mod, config); } // EOTU fixes @@ -792,6 +794,10 @@ namespace NewHorizons { LoadAddonManifest("addon-manifest.json", mod); } + if (File.Exists(Path.Combine(folder, "title-screen.json"))) + { + LoadTitleScreenConfig("title-screen.json", mod); + } if (Directory.Exists(Path.Combine(folder, "translations"))) { LoadTranslations(folder, mod); @@ -840,6 +846,21 @@ namespace NewHorizons AddonConfigs[mod] = addonConfig; } + private void LoadTitleScreenConfig(string file, IModBehaviour mod) + { + NHLogger.LogVerbose($"Loading title screen config for {mod.ModHelper.Manifest.Name}"); + + var titleScreenConfig = mod.ModHelper.Storage.Load(file, false); + + if (titleScreenConfig == null) + { + NHLogger.LogError($"Title screen config for {mod.ModHelper.Manifest.Name} could not load, check your JSON"); + return; + } + + TitleScreenConfigs[mod] = titleScreenConfig; + } + private void LoadTranslations(string folder, IModBehaviour mod) { var foundFile = false; diff --git a/NewHorizons/NewHorizonsApi.cs b/NewHorizons/NewHorizonsApi.cs index 348991c0..85e1a1a4 100644 --- a/NewHorizons/NewHorizonsApi.cs +++ b/NewHorizons/NewHorizonsApi.cs @@ -178,6 +178,24 @@ namespace NewHorizons return default; } + public object QueryTitleScreen(Type outType, IModBehaviour mod, string jsonPath) + { + var titleScreenConfig = Main.TitleScreenConfigs[mod]; + return titleScreenConfig == null + ? null + : QueryJson(outType, Path.Combine(mod.ModHelper.Manifest.ModFolderPath, "title-screen.json"), jsonPath); + } + + public T QueryTitleScreen(IModBehaviour mod, string jsonPath) + { + var data = QueryTitleScreen(typeof(T), mod, jsonPath); + if (data is T result) + { + return result; + } + return default; + } + public GameObject SpawnObject(IModBehaviour mod, GameObject planet, Sector sector, string propToCopyPath, Vector3 position, Vector3 eulerAngles, float scale, bool alignRadial) { @@ -344,5 +362,11 @@ namespace NewHorizons public void AddSubtitle(IModBehaviour mod, string filePath) => SubtitlesHandler.RegisterAdditionalSubtitle(mod, filePath); public void SetNextSpawnID(string id) => PlayerSpawnHandler.TargetSpawnID = id; + + // TODO: Implement + public void RegisterTitleScreenHandler(Action builder, bool deleteNHPlanets = true, bool shareTitleScreen = false, string conditionRequired = null, string factRequired = null) + { + throw new NotImplementedException(); + } } } diff --git a/SchemaExporter/SchemaExporter.cs b/SchemaExporter/SchemaExporter.cs index 4f4d6ddf..5c5aad09 100644 --- a/SchemaExporter/SchemaExporter.cs +++ b/SchemaExporter/SchemaExporter.cs @@ -98,7 +98,7 @@ public static class SchemaExporter break; } - if (_title is "Star System Schema" or "Celestial Body Schema") + if (_title is "Star System Schema" or "Celestial Body Schema" or "Title Screen Schema") { schema.Properties["extras"] = new JsonSchemaProperty { Type = JsonObjectType.Object,