diff --git a/NewHorizons/Builder/General/GroupsBuilder.cs b/NewHorizons/Builder/General/GroupsBuilder.cs index b2252f5e..2998c02f 100644 --- a/NewHorizons/Builder/General/GroupsBuilder.cs +++ b/NewHorizons/Builder/General/GroupsBuilder.cs @@ -25,5 +25,8 @@ public static class GroupsBuilder go.GetAddComponent()._sector = sector; go.GetAddComponent()._sector = sector; go.GetAddComponent()._sector = sector; + + // SectorCollisionGroup is unique among the sector groups because it only attaches its event listener on Start() instead of Awake(), so if the detail gets immediately deactivated then it never gets attached. To avoid this, we'll attach the event listener manually (even if it means getting attached twice). + sector.OnSectorOccupantsUpdated += go.GetComponent().OnSectorOccupantsUpdated; } } \ No newline at end of file diff --git a/NewHorizons/Builder/Props/DetailBuilder.cs b/NewHorizons/Builder/Props/DetailBuilder.cs index 022acd74..825af0c1 100644 --- a/NewHorizons/Builder/Props/DetailBuilder.cs +++ b/NewHorizons/Builder/Props/DetailBuilder.cs @@ -356,7 +356,10 @@ namespace NewHorizons.Builder.Props singleLightSensor._sector.OnSectorOccupantsUpdated -= singleLightSensor.OnSectorOccupantsUpdated; } singleLightSensor._sector = sector; - singleLightSensor._sector.OnSectorOccupantsUpdated += singleLightSensor.OnSectorOccupantsUpdated; + if (singleLightSensor._sector != null) + { + singleLightSensor._sector.OnSectorOccupantsUpdated += singleLightSensor.OnSectorOccupantsUpdated; + } } } diff --git a/NewHorizons/Builder/Props/ItemBuilder.cs b/NewHorizons/Builder/Props/ItemBuilder.cs index f4992e8a..05620329 100644 --- a/NewHorizons/Builder/Props/ItemBuilder.cs +++ b/NewHorizons/Builder/Props/ItemBuilder.cs @@ -1,6 +1,7 @@ using NewHorizons.Components.Props; using NewHorizons.External.Modules.Props.Item; using NewHorizons.Handlers; +using NewHorizons.Utility.OuterWilds; using NewHorizons.Utility.OWML; using OWML.Common; using OWML.Utils; @@ -27,6 +28,8 @@ namespace NewHorizons.Builder.Props public static NHItem MakeItem(GameObject go, GameObject planetGO, Sector sector, ItemInfo info, IModBehaviour mod) { + go.layer = Layer.Interactible; + var itemName = info.name; if (string.IsNullOrEmpty(itemName)) { @@ -93,10 +96,13 @@ namespace NewHorizons.Builder.Props if (info.colliderRadius > 0f) { - go.AddComponent().radius = info.colliderRadius; + var col = go.AddComponent(); + col.radius = info.colliderRadius; + col.isTrigger = info.colliderIsTrigger; go.GetAddComponent(); } + // Wait until next frame when all objects are built before trying to socket the item if it has an initial socket Delay.FireOnNextUpdate(() => { if (item != null && !string.IsNullOrEmpty(info.pathToInitialSocket)) @@ -133,6 +139,8 @@ namespace NewHorizons.Builder.Props public static NHItemSocket MakeSocket(GameObject go, GameObject planetGO, Sector sector, ItemSocketInfo info) { + go.layer = Layer.Interactible; + var itemType = EnumUtils.TryParse(info.itemType, true, out ItemType result) ? result : ItemType.Invalid; if (itemType == ItemType.Invalid && !string.IsNullOrEmpty(info.itemType)) { @@ -151,15 +159,18 @@ namespace NewHorizons.Builder.Props if (socket._socketTransform == null) { var socketGO = GeneralPropBuilder.MakeNew("Socket", planetGO, sector, info, defaultParent: go.transform); - if (info.colliderRadius > 0f) - { - go.AddComponent().radius = info.colliderRadius; - go.GetAddComponent(); - } socketGO.SetActive(true); socket._socketTransform = socketGO.transform; } + if (info.colliderRadius > 0f) + { + var col = go.AddComponent(); + col.radius = info.colliderRadius; + col.isTrigger = info.colliderIsTrigger; + go.GetAddComponent(); + } + socket.ItemType = itemType; socket.UseGiveTakePrompts = info.useGiveTakePrompts; socket.InsertCondition = info.insertCondition; @@ -169,6 +180,7 @@ namespace NewHorizons.Builder.Props socket.ClearRemovalConditionOnInsert = info.clearRemovalConditionOnInsert; socket.RemovalFact = info.removalFact; + // Wait until initial item socketing is done before considering the socket empty Delay.FireInNUpdates(() => { if (socket != null && !socket._socketedItem) diff --git a/NewHorizons/Builder/Props/NomaiTextBuilder.cs b/NewHorizons/Builder/Props/NomaiTextBuilder.cs index ce4ed43d..d71f3d49 100644 --- a/NewHorizons/Builder/Props/NomaiTextBuilder.cs +++ b/NewHorizons/Builder/Props/NomaiTextBuilder.cs @@ -312,7 +312,7 @@ namespace NewHorizons.Builder.Props scrollItem._nomaiWallText = nomaiWallText; scrollItem.SetSector(sector); customScroll.transform.Find("Props_NOM_Scroll/Props_NOM_Scroll_Geo").GetComponent().enabled = true; - customScroll.transform.Find("Props_NOM_Scroll/Props_NOM_Scroll_Collider").gameObject.SetActive(true); + customScroll.transform.Find("Props_NOM_Scroll/Props_NOM_Scroll_Collider").gameObject.SetActive(false); nomaiWallText.gameObject.GetComponent().enabled = false; customScroll.GetComponent().enabled = true; } diff --git a/NewHorizons/Builder/Props/QuantumBuilder.cs b/NewHorizons/Builder/Props/QuantumBuilder.cs index 302270e8..1a5bc8ab 100644 --- a/NewHorizons/Builder/Props/QuantumBuilder.cs +++ b/NewHorizons/Builder/Props/QuantumBuilder.cs @@ -69,13 +69,17 @@ namespace NewHorizons.Builder.Props { (GameObject go, QuantumDetailInfo detail)[] propsInGroup = quantumGroup.details.Select(x => (DetailBuilder.GetGameObjectFromDetailInfo(x), x)).ToArray(); - GameObject specialProp = null; QuantumDetailInfo specialInfo = null; if (propsInGroup.Length == quantumGroup.sockets.Length) { // Special case! - specialProp = propsInGroup.Last().go; + propsInGroup.Last().go.SetActive(false); + + // Will be manually positioned on the sockets anyway specialInfo = propsInGroup.Last().detail; + specialInfo.parentPath = string.Empty; + specialInfo.isRelativeToParent = false; + var propsInGroupList = propsInGroup.ToList(); propsInGroupList.RemoveAt(propsInGroup.Length - 1); propsInGroup = propsInGroupList.ToArray(); @@ -117,13 +121,13 @@ namespace NewHorizons.Builder.Props prop.go.SetActive(true); } - if (specialProp != null) + if (specialInfo != null) { // Can't have 4 objects in 4 slots // Instead we have a duplicate of the final object for each slot, which appears when that slot is "empty" for (int i = 0; i < sockets.Length; i++) - { - var emptySocketObject = DetailBuilder.Make(planetGO, sector, mod, specialProp, new DetailInfo()); + { + var emptySocketObject = DetailBuilder.Make(planetGO, sector, mod, new DetailInfo(specialInfo)); var socket = sockets[i]; socket._emptySocketObject = emptySocketObject; emptySocketObject.SetActive(socket._quantumObject == null); diff --git a/NewHorizons/Builder/Props/TranslatorText/TranslatorTextBuilder.cs b/NewHorizons/Builder/Props/TranslatorText/TranslatorTextBuilder.cs index 18a09f87..cd967809 100644 --- a/NewHorizons/Builder/Props/TranslatorText/TranslatorTextBuilder.cs +++ b/NewHorizons/Builder/Props/TranslatorText/TranslatorTextBuilder.cs @@ -206,7 +206,7 @@ namespace NewHorizons.Builder.Props.TranslatorText scrollItem._nomaiWallText = nomaiWallText; scrollItem.SetSector(sector); customScroll.transform.Find("Props_NOM_Scroll/Props_NOM_Scroll_Geo").GetComponent().enabled = true; - customScroll.transform.Find("Props_NOM_Scroll/Props_NOM_Scroll_Collider").gameObject.SetActive(true); + customScroll.transform.Find("Props_NOM_Scroll/Props_NOM_Scroll_Collider").gameObject.SetActive(false); nomaiWallText.gameObject.GetComponent().enabled = false; customScroll.GetComponent().enabled = true; scrollItem._nomaiWallText.HideImmediate(); diff --git a/NewHorizons/External/Modules/Props/Item/ItemInfo.cs b/NewHorizons/External/Modules/Props/Item/ItemInfo.cs index f837443a..4d5751ae 100644 --- a/NewHorizons/External/Modules/Props/Item/ItemInfo.cs +++ b/NewHorizons/External/Modules/Props/Item/ItemInfo.cs @@ -32,6 +32,10 @@ namespace NewHorizons.External.Modules.Props.Item /// [DefaultValue(0.5f)] public float colliderRadius = 0.5f; /// + /// Whether the added sphere collider will be a trigger (interactible but does not collide). Defaults to true. + /// + [DefaultValue(true)] public bool colliderIsTrigger = true; + /// /// Whether the item can be dropped. Defaults to true. /// [DefaultValue(true)] public bool droppable = true; diff --git a/NewHorizons/External/Modules/Props/Item/ItemSocketInfo.cs b/NewHorizons/External/Modules/Props/Item/ItemSocketInfo.cs index 7294fbb0..d2ff2336 100644 --- a/NewHorizons/External/Modules/Props/Item/ItemSocketInfo.cs +++ b/NewHorizons/External/Modules/Props/Item/ItemSocketInfo.cs @@ -19,6 +19,15 @@ namespace NewHorizons.External.Modules.Props.Item /// [DefaultValue(2f)] public float interactRange = 2f; /// + /// Default collider radius when interacting with the socket + /// + [DefaultValue(0f)] + public float colliderRadius = 0f; + /// + /// Whether the added sphere collider will be a trigger (interactible but does not collide). Defaults to true. + /// + [DefaultValue(true)] public bool colliderIsTrigger = true; + /// /// Whether to use "Give Item" / "Take Item" prompts instead of "Insert Item" / "Remove Item". /// public bool useGiveTakePrompts; @@ -46,10 +55,5 @@ namespace NewHorizons.External.Modules.Props.Item /// A ship log fact to reveal when removing an item from this socket, or when the socket is empty. /// public string removalFact; - /// - /// Default collider radius when interacting with the socket - /// - [DefaultValue(0f)] - public float colliderRadius = 0f; } } diff --git a/NewHorizons/Patches/EchoesOfTheEyePatches/SingleLightSensorPatches.cs b/NewHorizons/Patches/EchoesOfTheEyePatches/SingleLightSensorPatches.cs new file mode 100644 index 00000000..39665dfc --- /dev/null +++ b/NewHorizons/Patches/EchoesOfTheEyePatches/SingleLightSensorPatches.cs @@ -0,0 +1,24 @@ +using HarmonyLib; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NewHorizons.Patches.EchoesOfTheEyePatches +{ + [HarmonyPatch(typeof(SingleLightSensor))] + public static class SingleLightSensorPatches + { + [HarmonyPostfix] + [HarmonyPatch(nameof(SingleLightSensor.Start))] + public static void Start(SingleLightSensor __instance) + { + // SingleLightSensor assumes that the sector will be empty when it starts and disables itself, but this may not be true if it starts disabled and is activated later, or spawned via the API + if (__instance._sector && __instance._sector.ContainsAnyOccupants(DynamicOccupant.Player | DynamicOccupant.Probe)) + { + __instance.OnSectorOccupantsUpdated(); + } + } + } +} diff --git a/NewHorizons/Schemas/body_schema.json b/NewHorizons/Schemas/body_schema.json index f8c63685..c3f289b1 100644 --- a/NewHorizons/Schemas/body_schema.json +++ b/NewHorizons/Schemas/body_schema.json @@ -1121,6 +1121,11 @@ "format": "float", "default": 0.5 }, + "colliderIsTrigger": { + "type": "boolean", + "description": "Whether the added sphere collider will be a trigger (interactible but does not collide). Defaults to true.", + "default": true + }, "droppable": { "type": "boolean", "description": "Whether the item can be dropped. Defaults to true.", @@ -1230,6 +1235,17 @@ "format": "float", "default": 2.0 }, + "colliderRadius": { + "type": "number", + "description": "Default collider radius when interacting with the socket", + "format": "float", + "default": 0.0 + }, + "colliderIsTrigger": { + "type": "boolean", + "description": "Whether the added sphere collider will be a trigger (interactible but does not collide). Defaults to true.", + "default": true + }, "useGiveTakePrompts": { "type": "boolean", "description": "Whether to use \"Give Item\" / \"Take Item\" prompts instead of \"Insert Item\" / \"Remove Item\"." @@ -1259,12 +1275,6 @@ "removalFact": { "type": "string", "description": "A ship log fact to reveal when removing an item from this socket, or when the socket is empty." - }, - "colliderRadius": { - "type": "number", - "description": "Default collider radius when interacting with the socket", - "format": "float", - "default": 0.0 } } }, diff --git a/NewHorizons/manifest.json b/NewHorizons/manifest.json index 7c8435b5..f3408a21 100644 --- a/NewHorizons/manifest.json +++ b/NewHorizons/manifest.json @@ -4,7 +4,7 @@ "author": "xen, Bwc9876, JohnCorby, MegaPiggy, and friends", "name": "New Horizons", "uniqueName": "xen.NewHorizons", - "version": "1.27.0", + "version": "1.27.1", "owmlVersion": "2.12.1", "dependencies": [ "JohnCorby.VanillaFix", "xen.CommonCameraUtility", "dgarro.CustomShipLogModes" ], "conflicts": [ "PacificEngine.OW_CommonResources" ],