diff --git a/QSB/EchoesOfTheEye/AirlockSync/AirlockManager.cs b/QSB/EchoesOfTheEye/AirlockSync/AirlockManager.cs new file mode 100644 index 00000000..08fc7f50 --- /dev/null +++ b/QSB/EchoesOfTheEye/AirlockSync/AirlockManager.cs @@ -0,0 +1,13 @@ +using QSB.EchoesOfTheEye.AirlockSync.WorldObjects; +using QSB.WorldSync; + +namespace QSB.EchoesOfTheEye.AirlockSync +{ + class AirlockManager : WorldObjectManager + { + protected override void RebuildWorldObjects(OWScene scene) + { + QSBWorldSync.Init(); + } + } +} diff --git a/QSB/EchoesOfTheEye/AirlockSync/WorldObjects/QSBGhostAirlock.cs b/QSB/EchoesOfTheEye/AirlockSync/WorldObjects/QSBGhostAirlock.cs new file mode 100644 index 00000000..270168ed --- /dev/null +++ b/QSB/EchoesOfTheEye/AirlockSync/WorldObjects/QSBGhostAirlock.cs @@ -0,0 +1,17 @@ +using QSB.WorldSync; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace QSB.EchoesOfTheEye.AirlockSync.WorldObjects +{ + class QSBGhostAirlock : WorldObject + { + public override void Init(GhostAirlock airlock, int id) + { + ObjectId = id; + AttachedObject = airlock; + } + } +} diff --git a/QSB/EchoesOfTheEye/LightSensorSync/LightSensorManager.cs b/QSB/EchoesOfTheEye/LightSensorSync/LightSensorManager.cs new file mode 100644 index 00000000..b8fb2222 --- /dev/null +++ b/QSB/EchoesOfTheEye/LightSensorSync/LightSensorManager.cs @@ -0,0 +1,13 @@ +using QSB.EchoesOfTheEye.LightSensorSync.WorldObjects; +using QSB.WorldSync; + +namespace QSB.EchoesOfTheEye.LightSensorSync +{ + class LightSensorManager : WorldObjectManager + { + protected override void RebuildWorldObjects(OWScene scene) + { + QSBWorldSync.Init(); + } + } +} diff --git a/QSB/EchoesOfTheEye/LightSensorSync/Patches/LightSensorPatches.cs b/QSB/EchoesOfTheEye/LightSensorSync/Patches/LightSensorPatches.cs new file mode 100644 index 00000000..bf0b1240 --- /dev/null +++ b/QSB/EchoesOfTheEye/LightSensorSync/Patches/LightSensorPatches.cs @@ -0,0 +1,150 @@ +using HarmonyLib; +using QSB.Patches; +using QSB.Player; +using QSB.Tools; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using UnityEngine; + +namespace QSB.EchoesOfTheEye.LightSensorSync.Patches +{ + [HarmonyPatch] + class LightSensorPatches : QSBPatch + { + public override QSBPatchTypes Type => QSBPatchTypes.OnClientConnect; + + [HarmonyPrefix] + [HarmonyPatch(typeof(SingleLightSensor), nameof(SingleLightSensor.UpdateIllumination))] + public static bool UpdateIlluminationReplacement(SingleLightSensor __instance) + { + __instance._illuminated = false; + if (__instance._illuminatingDreamLanternList != null) + { + __instance._illuminatingDreamLanternList.Clear(); + } + + var vector = __instance.transform.TransformPoint(__instance._localSensorOffset); + var sensorWorldDir = Vector3.zero; + if (__instance._directionalSensor) + { + sensorWorldDir = __instance.transform.TransformDirection(__instance._localDirection).normalized; + } + + if (__instance._lightSources == null) + { + return false; + } + + for (var i = 0; i < __instance._lightSources.Count; i++) + { + var source = __instance._lightSources[i]; + + if ((__instance._lightSourceMask & source.GetLightSourceType()) == source.GetLightSourceType() + && source.CheckIlluminationAtPoint(vector, __instance._sensorRadius, __instance._maxDistance)) + { + var lightSourceType = source.GetLightSourceType(); + switch (lightSourceType) + { + case LightSourceType.UNDEFINED: + { + var owlight = source as OWLight2; + var occludableLight = owlight.GetLight().shadows != LightShadows.None + && owlight.GetLight().shadowStrength > 0.5f; + + if (owlight.CheckIlluminationAtPoint(vector, __instance._sensorRadius, __instance._maxDistance) + && !__instance.CheckOcclusion(owlight.transform.position, vector, sensorWorldDir, occludableLight)) + { + __instance._illuminated = true; + } + + break; + } + case LightSourceType.FLASHLIGHT: + { + if (source is Flashlight && (source as Flashlight) == Locator.GetFlashlight()) + { + var position = Locator.GetPlayerCamera().transform.position; + var to = __instance.transform.position - position; + if (Vector3.Angle(Locator.GetPlayerCamera().transform.forward, to) <= __instance._maxSpotHalfAngle + && !__instance.CheckOcclusion(position, vector, sensorWorldDir, true)) + { + __instance._illuminated = true; + } + } + else + { + var player = QSBPlayerManager.PlayerList.First(x => x.FlashLight == (QSBFlashlight)source); + + var position = player.Camera.transform.position; + var to = __instance.transform.position - position; + if (Vector3.Angle(player.Camera.transform.forward, to) <= __instance._maxSpotHalfAngle + && !__instance.CheckOcclusion(position, vector, sensorWorldDir, true)) + { + __instance._illuminated = true; + } + } + + break; + } + case LightSourceType.PROBE: + { + var probe = Locator.GetProbe(); + if (probe != null + && probe.IsLaunched() + && !probe.IsRetrieving() + && probe.CheckIlluminationAtPoint(vector, __instance._sensorRadius, __instance._maxDistance) + && !__instance.CheckOcclusion(probe.GetLightSourcePosition(), vector, sensorWorldDir, true)) + { + __instance._illuminated = true; + } + + break; + } + case LightSourceType.FLASHLIGHT | LightSourceType.PROBE: + case LightSourceType.FLASHLIGHT | LightSourceType.DREAM_LANTERN: + case LightSourceType.PROBE | LightSourceType.DREAM_LANTERN: + case LightSourceType.FLASHLIGHT | LightSourceType.PROBE | LightSourceType.DREAM_LANTERN: + break; + case LightSourceType.DREAM_LANTERN: + { + var dreamLanternController = __instance._lightSources[i] as DreamLanternController; + if (dreamLanternController.IsLit() + && dreamLanternController.IsFocused(__instance._lanternFocusThreshold) + && dreamLanternController.CheckIlluminationAtPoint(vector, __instance._sensorRadius, __instance._maxDistance) + && !__instance.CheckOcclusion(dreamLanternController.GetLightPosition(), vector, sensorWorldDir, true)) + { + __instance._illuminatingDreamLanternList.Add(dreamLanternController); + __instance._illuminated = true; + } + + break; + } + case LightSourceType.SIMPLE_LANTERN: + foreach (var owlight in __instance._lightSources[i].GetLights()) + { + var occludableLight = owlight.GetLight().shadows != LightShadows.None + && owlight.GetLight().shadowStrength > 0.5f; + var maxDistance = Mathf.Min(__instance._maxSimpleLanternDistance, __instance._maxDistance); + if (owlight.CheckIlluminationAtPoint(vector, __instance._sensorRadius, maxDistance) && !__instance.CheckOcclusion(owlight.transform.position, vector, sensorWorldDir, occludableLight)) + { + __instance._illuminated = true; + break; + } + } + break; + default: + if (lightSourceType == LightSourceType.VOLUME_ONLY) + { + __instance._illuminated = true; + } + break; + } + } + } + + return false; + } + } +} diff --git a/QSB/EchoesOfTheEye/LightSensorSync/WorldObjects/QSBSingleLightSensor.cs b/QSB/EchoesOfTheEye/LightSensorSync/WorldObjects/QSBSingleLightSensor.cs new file mode 100644 index 00000000..4ec58964 --- /dev/null +++ b/QSB/EchoesOfTheEye/LightSensorSync/WorldObjects/QSBSingleLightSensor.cs @@ -0,0 +1,13 @@ +using QSB.WorldSync; + +namespace QSB.EchoesOfTheEye.LightSensorSync.WorldObjects +{ + class QSBSingleLightSensor : WorldObject + { + public override void Init(SingleLightSensor sensor, int id) + { + ObjectId = id; + AttachedObject = sensor; + } + } +} diff --git a/QSB/Patches/QSBPatchManager.cs b/QSB/Patches/QSBPatchManager.cs index d9f082c4..4ccb787b 100644 --- a/QSB/Patches/QSBPatchManager.cs +++ b/QSB/Patches/QSBPatchManager.cs @@ -10,6 +10,7 @@ using QSB.FrequencySync.Patches; using QSB.GeyserSync.Patches; using QSB.Inputs.Patches; using QSB.ItemSync.Patches; +using QSB.EchoesOfTheEye.LightSensorSync.Patches; using QSB.LogSync.Patches; using QSB.OrbSync.Patches; using QSB.Player.Patches; @@ -69,7 +70,8 @@ namespace QSB.Patches new RespawnPatches(), new LauncherPatches(), new SolanumPatches(), - new SatelliteProjectorPatches() + new SatelliteProjectorPatches(), + new LightSensorPatches() }; TypeToInstance = new Dictionary diff --git a/QSB/QSB.csproj b/QSB/QSB.csproj index f65b9fd1..c83a6a55 100644 --- a/QSB/QSB.csproj +++ b/QSB/QSB.csproj @@ -87,6 +87,8 @@ + + @@ -110,6 +112,9 @@ + + + diff --git a/QSB/QSBCore.cs b/QSB/QSBCore.cs index c72b4687..460540ec 100644 --- a/QSB/QSBCore.cs +++ b/QSB/QSBCore.cs @@ -5,10 +5,12 @@ using QSB.Animation.NPC; using QSB.CampfireSync; using QSB.ConversationSync; using QSB.DeathSync; +using QSB.EchoesOfTheEye.AirlockSync; using QSB.ElevatorSync; using QSB.GeyserSync; using QSB.Inputs; using QSB.ItemSync; +using QSB.EchoesOfTheEye.LightSensorSync; using QSB.Menus; using QSB.OrbSync; using QSB.Patches; @@ -119,6 +121,8 @@ namespace QSB gameObject.AddComponent(); gameObject.AddComponent(); gameObject.AddComponent(); + gameObject.AddComponent(); + gameObject.AddComponent(); DebugBoxManager.Init(); diff --git a/QSB/Tools/QSBFlashlight.cs b/QSB/Tools/QSBFlashlight.cs index b4d47e45..21f49c71 100644 --- a/QSB/Tools/QSBFlashlight.cs +++ b/QSB/Tools/QSBFlashlight.cs @@ -3,29 +3,35 @@ using UnityEngine; namespace QSB.Tools { - public class QSBFlashlight : MonoBehaviour + public class QSBFlashlight : MonoBehaviour, ILightSource { private OWLight2[] _lights; + internal OWLight2 _illuminationCheckLight; private Transform _root; private Transform _basePivot; private Transform _wobblePivot; private Vector3 _baseForward; private Quaternion _baseRotation; + private LightSourceVolume _lightSourceVolume; public bool FlashlightOn; public void Start() { + _lightSourceVolume = this.GetRequiredComponentInChildren(); + _lightSourceVolume.LinkLightSource(this); + _lightSourceVolume.SetVolumeActivation(FlashlightOn); _baseForward = _basePivot.forward; _baseRotation = _basePivot.rotation; } public void Init(Flashlight oldComponent) { - _lights = oldComponent.GetValue("_lights"); - _root = oldComponent.GetValue("_root"); - _basePivot = oldComponent.GetValue("_basePivot"); - _wobblePivot = oldComponent.GetValue("_wobblePivot"); + _lights = oldComponent._lights; + _illuminationCheckLight = oldComponent._illuminationCheckLight; + _root = oldComponent._root; + _basePivot = oldComponent._basePivot; + _wobblePivot = oldComponent._wobblePivot; Destroy(oldComponent.GetComponent()); foreach (var light in _lights) @@ -37,6 +43,12 @@ namespace QSB.Tools FlashlightOn = false; } + public LightSourceType GetLightSourceType() + => LightSourceType.FLASHLIGHT; + + public OWLight2[] GetLights() + => _lights; + public void UpdateState(bool value) { if (value) @@ -58,7 +70,7 @@ namespace QSB.Tools foreach (var light in _lights) { - light.GetLight().enabled = true; + light.SetActivation(true); } FlashlightOn = true; @@ -66,6 +78,7 @@ namespace QSB.Tools _basePivot.rotation = rotation; _baseRotation = rotation; _baseForward = _basePivot.forward; + _lightSourceVolume.SetVolumeActivation(FlashlightOn); } private void TurnOff() @@ -77,15 +90,16 @@ namespace QSB.Tools foreach (var light in _lights) { - light.GetLight().enabled = false; + light.SetActivation(false); } FlashlightOn = false; + _lightSourceVolume.SetVolumeActivation(FlashlightOn); } - public bool CheckIlluminationAtPoint(Vector3 point, float buffer = 0f, float maxDistance = float.PositiveInfinity) + public bool CheckIlluminationAtPoint(Vector3 worldPoint, float buffer = 0f, float maxDistance = float.PositiveInfinity) => FlashlightOn - && _lights[1].CheckIlluminationAtPoint(point, buffer, maxDistance); + && _illuminationCheckLight.CheckIlluminationAtPoint(worldPoint, buffer, maxDistance); public void FixedUpdate() { @@ -97,19 +111,5 @@ namespace QSB.Tools _baseForward = _basePivot.forward; _wobblePivot.localRotation = OWUtilities.GetWobbleRotation(0.3f, 0.15f) * Quaternion.identity; } - - private void OnRenderObject() - { - if (!QSBCore.WorldObjectsReady || !QSBCore.DebugMode || !QSBCore.ShowLinesInDebug) - { - return; - } - - var light = _lights[1].GetLight(); - if (light.enabled) - { - Popcron.Gizmos.Cone(light.transform.position, light.transform.rotation, light.range, light.spotAngle, Color.yellow); - } - } } } \ No newline at end of file