From 1be3bf209f1f63972e1693345145be00c8a5aba0 Mon Sep 17 00:00:00 2001 From: Joshua Thome Date: Sat, 5 Oct 2024 00:54:25 -0500 Subject: [PATCH] Dream arrival point and dream campfire builders --- .../DreamArrivalPointBuilder.cs | 63 ++++++++++++++ .../EchoesOfTheEye/DreamCampfireBuilder.cs | 73 ++++++++++++++++ NewHorizons/Builder/Props/PropBuildManager.cs | 3 + NewHorizons/External/Modules/PropModule.cs | 10 +++ .../EchoesOfTheEye/DreamArrivalPointInfo.cs | 22 +++++ .../Props/EchoesOfTheEye/DreamCampfireInfo.cs | 18 ++++ NewHorizons/Handlers/DreamHandler.cs | 85 +++++++++++++++++++ .../Handlers/PlanetDestructionHandler.cs | 9 ++ NewHorizons/Main.cs | 3 + .../DreamworldControllerPatches.cs | 35 ++++++++ 10 files changed, 321 insertions(+) create mode 100644 NewHorizons/Builder/Props/EchoesOfTheEye/DreamArrivalPointBuilder.cs create mode 100644 NewHorizons/Builder/Props/EchoesOfTheEye/DreamCampfireBuilder.cs create mode 100644 NewHorizons/External/Modules/Props/EchoesOfTheEye/DreamArrivalPointInfo.cs create mode 100644 NewHorizons/External/Modules/Props/EchoesOfTheEye/DreamCampfireInfo.cs create mode 100644 NewHorizons/Handlers/DreamHandler.cs diff --git a/NewHorizons/Builder/Props/EchoesOfTheEye/DreamArrivalPointBuilder.cs b/NewHorizons/Builder/Props/EchoesOfTheEye/DreamArrivalPointBuilder.cs new file mode 100644 index 00000000..cb828744 --- /dev/null +++ b/NewHorizons/Builder/Props/EchoesOfTheEye/DreamArrivalPointBuilder.cs @@ -0,0 +1,63 @@ +using NewHorizons.Components.Props; +using NewHorizons.External.Modules.Props; +using NewHorizons.External.Modules.Props.EchoesOfTheEye; +using NewHorizons.Handlers; +using NewHorizons.Utility; +using NewHorizons.Utility.OWML; +using OWML.Common; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEngine; + +namespace NewHorizons.Builder.Props.EchoesOfTheEye +{ + public static class DreamArrivalPointBuilder + { + private static GameObject _prefab; + + internal static void InitPrefab() + { + if (_prefab == null) + { + _prefab = SearchUtilities.Find("DreamWorld_Body/Sector_DreamWorld/Sector_DreamZone_1/DreamFireHouse_1/Interactibles_DreamFireHouse_1/Prefab_IP_DreamArrivalPoint_Zone1").InstantiateInactive().Rename("Prefab_DreamArrivalPoint").DontDestroyOnLoad(); + if (_prefab == null) + { + NHLogger.LogWarning($"Tried to make a dream arrival point but couldn't. Do you have the DLC installed?"); + return; + } + else + { + _prefab.AddComponent()._destroyOnDLCNotOwned = true; + var dreamArrivalPoint = _prefab.GetComponent(); + dreamArrivalPoint._location = DreamArrivalPoint.Location.Undefined; + dreamArrivalPoint._sector = null; + dreamArrivalPoint._entrywayVolumes = []; + dreamArrivalPoint._raftSpawn = null; + dreamArrivalPoint._connectedDreamCampfire = null; + dreamArrivalPoint._campfire._sector = null; + } + } + } + + public static GameObject Make(GameObject planetGO, Sector sector, DreamArrivalPointInfo info, IModBehaviour mod) + { + InitPrefab(); + + if (_prefab == null || sector == null) return null; + + var arrivalPointObj = DetailBuilder.Make(planetGO, sector, mod, _prefab, new DetailInfo(info)); + + StreamingHandler.SetUpStreaming(arrivalPointObj, sector); + + DreamArrivalPoint arrivalPoint = arrivalPointObj.GetComponent(); + arrivalPoint._sector = arrivalPoint.GetComponentInParent(); + arrivalPoint._location = DreamHandler.GetDreamArrivalLocation(info.id); + Locator.RegisterDreamArrivalPoint(arrivalPoint, arrivalPoint._location); + + return arrivalPointObj; + } + } +} diff --git a/NewHorizons/Builder/Props/EchoesOfTheEye/DreamCampfireBuilder.cs b/NewHorizons/Builder/Props/EchoesOfTheEye/DreamCampfireBuilder.cs new file mode 100644 index 00000000..5005e310 --- /dev/null +++ b/NewHorizons/Builder/Props/EchoesOfTheEye/DreamCampfireBuilder.cs @@ -0,0 +1,73 @@ +using NewHorizons.External.Modules.Props; +using NewHorizons.External.Modules.Props.EchoesOfTheEye; +using NewHorizons.Handlers; +using NewHorizons.Utility; +using NewHorizons.Utility.OWML; +using OWML.Common; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEngine; + +namespace NewHorizons.Builder.Props.EchoesOfTheEye +{ + public static class DreamCampfireBuilder + { + private static GameObject _prefab; + + internal static void InitPrefab() + { + if (_prefab == null) + { + _prefab = SearchUtilities.Find("RingWorld_Body/Sector_RingInterior/Sector_Zone4/Sector_PrisonDocks/Sector_PrisonInterior/Interactibles_PrisonInterior/Prefab_IP_DreamCampfire").InstantiateInactive().Rename("Prefab_DreamCampfire").DontDestroyOnLoad(); + if (_prefab == null) + { + NHLogger.LogWarning($"Tried to make a dream campfire but couldn't. Do you have the DLC installed?"); + return; + } + else + { + _prefab.AddComponent()._destroyOnDLCNotOwned = true; + var campfire = _prefab.GetComponentInChildren(); + campfire._dreamArrivalLocation = DreamArrivalPoint.Location.Undefined; + campfire._sector = null; + campfire._entrywayVolumes = []; + } + } + } + + public static GameObject Make(GameObject planetGO, Sector sector, DreamCampfireInfo info, IModBehaviour mod) + { + InitPrefab(); + + if (_prefab == null || sector == null) return null; + + var campfireObj = DetailBuilder.Make(planetGO, sector, mod, _prefab, new DetailInfo(info)); + + var campfire = campfireObj.GetComponentInChildren(); + campfire._dreamArrivalLocation = DreamHandler.GetDreamArrivalLocation(info.id); + + Delay.FireInNUpdates(() => { + var streaming = campfireObj.GetComponentInChildren(); + if (streaming != null) + { + var targetArrivalPoint = Locator.GetDreamArrivalPoint(campfire._dreamArrivalLocation); + if (targetArrivalPoint != null) + { + var streamingGroup = targetArrivalPoint.transform.root.GetComponentInChildren(); + if (streamingGroup) + { + streaming._streamingGroup = streamingGroup; + } + } + } + }, 2); + + Locator.RegisterDreamCampfire(campfire, campfire._dreamArrivalLocation); + + return campfireObj; + } + } +} diff --git a/NewHorizons/Builder/Props/PropBuildManager.cs b/NewHorizons/Builder/Props/PropBuildManager.cs index 433b7bc4..8cff2939 100644 --- a/NewHorizons/Builder/Props/PropBuildManager.cs +++ b/NewHorizons/Builder/Props/PropBuildManager.cs @@ -1,5 +1,6 @@ using NewHorizons.Builder.Body; using NewHorizons.Builder.Props.Audio; +using NewHorizons.Builder.Props.EchoesOfTheEye; using NewHorizons.Builder.Props.TranslatorText; using NewHorizons.Builder.ShipLog; using NewHorizons.External; @@ -101,6 +102,8 @@ namespace NewHorizons.Builder.Props // If a prop has set its parentPath and the parent cannot be found, add it to the next pass and try again later nextPass = new List(); + if (Main.HasDLC) MakeGeneralProps(go, config.Props.dreamCampfires, (campfire) => DreamCampfireBuilder.Make(go, sector, campfire, mod), (campfire) => campfire.id); + if (Main.HasDLC) MakeGeneralProps(go, config.Props.dreamArrivalPoints, (point) => DreamArrivalPointBuilder.Make(go, sector, point, mod), (point) => point.id); MakeGeneralProps(go, config.Props.gravityCannons, (cannon) => GravityCannonBuilder.Make(go, sector, cannon, mod), (cannon) => cannon.shuttleID); MakeGeneralProps(go, config.Props.shuttles, (shuttle) => ShuttleBuilder.Make(go, sector, mod, shuttle), (shuttle) => shuttle.id); MakeGeneralProps(go, config.Props.details, (detail) => DetailBuilder.Make(go, sector, mod, detail), (detail) => detail.path); diff --git a/NewHorizons/External/Modules/PropModule.cs b/NewHorizons/External/Modules/PropModule.cs index b77c2f68..68ff0ee6 100644 --- a/NewHorizons/External/Modules/PropModule.cs +++ b/NewHorizons/External/Modules/PropModule.cs @@ -123,6 +123,16 @@ namespace NewHorizons.External.Modules /// public ShuttleInfo[] shuttles; + /// + /// Add campfires that allow you to enter the dream world/simulation. Must be paired with a dream arrival point, which can be placed on this planet or elsewhere. + /// + public DreamCampfireInfo[] dreamCampfires; + + /// + /// Add the points you will arrive at when entering the dream world/simulation from a paired dream campfire, which can be placed on this planet or elsewhere. + /// + public DreamArrivalPointInfo[] dreamArrivalPoints; + [Obsolete("reveal is deprecated. Use Volumes->revealVolumes instead.")] public RevealVolumeInfo[] reveal; [Obsolete("audioVolumes is deprecated. Use Volumes->audioVolumes instead.")] public AudioVolumeInfo[] audioVolumes; diff --git a/NewHorizons/External/Modules/Props/EchoesOfTheEye/DreamArrivalPointInfo.cs b/NewHorizons/External/Modules/Props/EchoesOfTheEye/DreamArrivalPointInfo.cs new file mode 100644 index 00000000..148ec55d --- /dev/null +++ b/NewHorizons/External/Modules/Props/EchoesOfTheEye/DreamArrivalPointInfo.cs @@ -0,0 +1,22 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NewHorizons.External.Modules.Props.EchoesOfTheEye +{ + [JsonObject] + public class DreamArrivalPointInfo : GeneralPropInfo + { + /// + /// Unique ID for this dream-world arrival point + /// + public string id; + /// + /// Whether to generate simulation meshes (the models used in the "tronworld" or "matrix" view) for most objects on the current planet by cloning the existing meshes and applying the simulation materials. Leave this off if you are building your own simulation meshes or using existing objects which have them. + /// + public bool generateSimulationMeshes; + } +} diff --git a/NewHorizons/External/Modules/Props/EchoesOfTheEye/DreamCampfireInfo.cs b/NewHorizons/External/Modules/Props/EchoesOfTheEye/DreamCampfireInfo.cs new file mode 100644 index 00000000..4b96d0ff --- /dev/null +++ b/NewHorizons/External/Modules/Props/EchoesOfTheEye/DreamCampfireInfo.cs @@ -0,0 +1,18 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NewHorizons.External.Modules.Props.EchoesOfTheEye +{ + [JsonObject] + public class DreamCampfireInfo : GeneralPropInfo + { + /// + /// Unique ID for this dream-world campfire + /// + public string id; + } +} diff --git a/NewHorizons/Handlers/DreamHandler.cs b/NewHorizons/Handlers/DreamHandler.cs new file mode 100644 index 00000000..7bc8b0bf --- /dev/null +++ b/NewHorizons/Handlers/DreamHandler.cs @@ -0,0 +1,85 @@ +using NewHorizons.Utility; +using NewHorizons.Utility.OWML; +using OWML.Utils; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEngine; + +namespace NewHorizons.Handlers +{ + public static class DreamHandler + { + public static DreamArrivalPoint.Location GetDreamArrivalLocation(string id) + { + try + { + if (EnumUtils.TryParse(id, out DreamArrivalPoint.Location location)) + { + return location; + } + else + { + NHLogger.LogVerbose($"Registering new dream arrival location [{id}]"); + return EnumUtilities.Create(id); + } + } + catch (Exception e) + { + NHLogger.LogError($"Couldn't load dream arrival location [{id}]:\n{e}"); + return DreamArrivalPoint.Location.Undefined; + } + } + + public static void MigrateDreamWorldController() + { + // Create new DreamWorldController instance since the existing one is disabled + var managerObj = new GameObject("DreamWorldManager"); + managerObj.SetActive(false); + var oldDWC = Locator.GetDreamWorldController(); + var dwc = managerObj.AddComponent(); + + var simRootObj = MigrateCopy(oldDWC._primarySimulationRoot.gameObject, managerObj); + + dwc._primarySimulationRoot = simRootObj.transform; + dwc._simulationRoots = [simRootObj.transform]; + dwc._simulationCamera = simRootObj.FindChild("Camera_Simulation").GetComponent(); + dwc._simulationSphere = simRootObj.FindChild("SimulationSphere").GetComponent(); + + dwc._tempSkyboxColor = oldDWC._tempSkyboxColor; + dwc._sarcophagusController = oldDWC._sarcophagusController; + dwc._prisonerDirector = oldDWC._prisonerDirector; + + // These should correspond to the arrival point's attached body + dwc._dreamBody = null; + dwc._dreamWorldSector = null; + dwc._dreamWorldVolume = null; + + // These should correspond to the campfire's attached body + dwc._planetBody = null; + dwc._ringWorldController = null; + + managerObj.SetActive(true); + + // Run after Start() completes + Delay.FireOnNextUpdate(() => + { + dwc._dreamBody = null; + dwc._dreamWorldSector = null; + dwc._dreamWorldVolume = null; + dwc._planetBody = null; + dwc._ringWorldController = null; + }); + + } + + private static GameObject MigrateCopy(GameObject go, GameObject newParent) + { + var clone = GameObject.Instantiate(go); + clone.transform.SetParent(newParent.transform, false); + return clone; + } + } +} diff --git a/NewHorizons/Handlers/PlanetDestructionHandler.cs b/NewHorizons/Handlers/PlanetDestructionHandler.cs index 7087c6fe..65152541 100644 --- a/NewHorizons/Handlers/PlanetDestructionHandler.cs +++ b/NewHorizons/Handlers/PlanetDestructionHandler.cs @@ -70,6 +70,7 @@ namespace NewHorizons.Handlers if (Main.HasDLC) { StrangerRemoved(); + DreamWorldRemoved(); } // Put it back at the center of the universe after banishing it else there are weird graphical bugs @@ -90,6 +91,11 @@ namespace NewHorizons.Handlers } } + private static void DreamWorldRemoved() + { + DreamHandler.MigrateDreamWorldController(); + } + private static void SunRemoved() { var sun = SearchUtilities.Find("Sun_Body").GetComponent(); @@ -207,6 +213,9 @@ namespace NewHorizons.Handlers case AstroObject.Name.RingWorld: StrangerRemoved(); break; + case AstroObject.Name.DreamWorld: + DreamWorldRemoved(); + break; } // Always delete the children diff --git a/NewHorizons/Main.cs b/NewHorizons/Main.cs index b80cf1e3..3da1061e 100644 --- a/NewHorizons/Main.cs +++ b/NewHorizons/Main.cs @@ -4,6 +4,7 @@ using NewHorizons.Builder.Body; using NewHorizons.Builder.General; using NewHorizons.Builder.Props; using NewHorizons.Builder.Props.Audio; +using NewHorizons.Builder.Props.EchoesOfTheEye; using NewHorizons.Builder.Props.TranslatorText; using NewHorizons.Components.Fixers; using NewHorizons.Components.Ship; @@ -381,6 +382,8 @@ namespace NewHorizons ProjectionBuilder.InitPrefabs(); CloakBuilder.InitPrefab(); RaftBuilder.InitPrefab(); + DreamCampfireBuilder.InitPrefab(); + DreamArrivalPointBuilder.InitPrefab(); } WarpPadBuilder.InitPrefabs(); diff --git a/NewHorizons/Patches/EchoesOfTheEyePatches/DreamworldControllerPatches.cs b/NewHorizons/Patches/EchoesOfTheEyePatches/DreamworldControllerPatches.cs index 4119fd0a..84471b9b 100644 --- a/NewHorizons/Patches/EchoesOfTheEyePatches/DreamworldControllerPatches.cs +++ b/NewHorizons/Patches/EchoesOfTheEyePatches/DreamworldControllerPatches.cs @@ -26,5 +26,40 @@ namespace NewHorizons.Patches.EchoesOfTheEyePatches .Repeat(matcher => matcher.RemoveInstructions(5)) .InstructionEnumeration(); } + + [HarmonyPrefix] + [HarmonyPatch(nameof(DreamWorldController.EnterDreamWorld))] + public static void DreamWorldController_EnterDreamWorld(DreamWorldController __instance, DreamCampfire dreamCampfire, DreamArrivalPoint arrivalPoint) + { + var dreamWorldAO = Locator.GetAstroObject(AstroObject.Name.DreamWorld); + if (arrivalPoint.GetAttachedOWRigidbody() == dreamWorldAO.GetOWRigidbody()) + { + __instance._dreamBody = dreamWorldAO.GetAttachedOWRigidbody(); + __instance._dreamWorldSector = dreamWorldAO.GetRootSector(); + __instance._dreamWorldVolume = __instance._dreamWorldSector.transform.Find("Volumes_DreamWorld").Find("DreamWorldVolume").GetComponent(); + } + else + { + var arrivalAO = arrivalPoint.GetComponentInParent(); + __instance._dreamBody = arrivalAO.GetAttachedOWRigidbody(); + __instance._dreamWorldSector = arrivalAO.GetRootSector(); + __instance._dreamWorldVolume = arrivalAO._gravityVolume.GetOWTriggerVolume(); + } + + __instance._primarySimulationRoot.GetComponent().SetSector(__instance._dreamWorldSector); + + var ringWorldAO = Locator.GetAstroObject(AstroObject.Name.RingWorld); + if (dreamCampfire.GetAttachedOWRigidbody() == ringWorldAO.GetOWRigidbody()) + { + __instance._planetBody = ringWorldAO.GetAttachedOWRigidbody(); + __instance._ringWorldController = ringWorldAO.GetComponent(); + } + else + { + var departureAO = dreamCampfire.GetComponentInParent(); + __instance._planetBody = departureAO.GetAttachedOWRigidbody(); + __instance._ringWorldController = null; + } + } } }