2021-11-08 20:55:53 +00:00
|
|
|
|
using HarmonyLib;
|
2022-02-26 00:02:14 -08:00
|
|
|
|
using QSB.EchoesOfTheEye.LightSensorSync.WorldObjects;
|
2021-11-08 20:55:53 +00:00
|
|
|
|
using QSB.Patches;
|
2022-02-26 00:02:14 -08:00
|
|
|
|
using QSB.WorldSync;
|
2022-05-27 21:10:11 -07:00
|
|
|
|
using System.Collections.Generic;
|
2022-07-24 14:55:13 -07:00
|
|
|
|
using UnityEngine;
|
2021-11-08 20:55:53 +00:00
|
|
|
|
|
2022-07-23 21:25:28 -07:00
|
|
|
|
/*
|
|
|
|
|
* For those who come here,
|
|
|
|
|
* leave while you still can.
|
|
|
|
|
*/
|
|
|
|
|
|
2022-03-02 19:46:33 -08:00
|
|
|
|
namespace QSB.EchoesOfTheEye.LightSensorSync.Patches;
|
|
|
|
|
|
2022-03-06 23:13:48 -08:00
|
|
|
|
[HarmonyPatch(typeof(SingleLightSensor))]
|
2022-03-02 19:46:33 -08:00
|
|
|
|
internal class LightSensorPatches : QSBPatch
|
2021-11-08 20:55:53 +00:00
|
|
|
|
{
|
2022-03-02 19:46:33 -08:00
|
|
|
|
public override QSBPatchTypes Type => QSBPatchTypes.OnClientConnect;
|
|
|
|
|
|
2022-05-27 21:10:11 -07:00
|
|
|
|
[HarmonyPrefix]
|
|
|
|
|
[HarmonyPatch(nameof(SingleLightSensor.OnSectorOccupantsUpdated))]
|
|
|
|
|
private static bool OnSectorOccupantsUpdated(SingleLightSensor __instance)
|
|
|
|
|
{
|
2022-08-15 22:38:03 -07:00
|
|
|
|
if (LightSensorManager.IsPlayerLightSensor(__instance))
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2022-05-27 21:10:11 -07:00
|
|
|
|
if (!QSBWorldSync.AllObjectsReady)
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2022-07-24 15:28:41 -07:00
|
|
|
|
var qsbLightSensor = __instance.GetWorldObject<QSBLightSensor>();
|
2022-05-27 21:10:11 -07:00
|
|
|
|
|
|
|
|
|
var containsAnyOccupants = __instance._sector.ContainsAnyOccupants(DynamicOccupant.Player | DynamicOccupant.Probe);
|
|
|
|
|
if (containsAnyOccupants && !__instance.enabled)
|
|
|
|
|
{
|
|
|
|
|
__instance.enabled = true;
|
|
|
|
|
__instance._lightDetector.GetShape().enabled = true;
|
|
|
|
|
if (__instance._preserveStateWhileDisabled)
|
|
|
|
|
{
|
|
|
|
|
__instance._fixedUpdateFrameDelayCount = 10;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (!containsAnyOccupants && __instance.enabled)
|
|
|
|
|
{
|
|
|
|
|
__instance.enabled = false;
|
|
|
|
|
__instance._lightDetector.GetShape().enabled = false;
|
|
|
|
|
if (!__instance._preserveStateWhileDisabled)
|
|
|
|
|
{
|
2022-08-15 22:38:03 -07:00
|
|
|
|
if (__instance._illuminated)
|
2022-05-27 21:10:11 -07:00
|
|
|
|
{
|
2022-08-15 22:38:03 -07:00
|
|
|
|
__instance.OnDetectDarkness.Invoke();
|
2022-05-27 21:10:11 -07:00
|
|
|
|
}
|
2022-08-15 22:38:03 -07:00
|
|
|
|
__instance._illuminated = false;
|
2022-05-27 21:10:11 -07:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2022-05-28 09:58:19 -07:00
|
|
|
|
|
2022-05-28 10:12:15 -07:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// to prevent allocating a new list every frame
|
|
|
|
|
/// </summary>
|
2022-07-24 10:23:46 -07:00
|
|
|
|
private static readonly List<DreamLanternController> _illuminatingDreamLanternList = new();
|
2022-05-27 21:10:11 -07:00
|
|
|
|
|
2022-05-27 15:03:30 -07:00
|
|
|
|
[HarmonyPrefix]
|
|
|
|
|
[HarmonyPatch(nameof(SingleLightSensor.ManagedFixedUpdate))]
|
|
|
|
|
private static bool ManagedFixedUpdate(SingleLightSensor __instance)
|
|
|
|
|
{
|
2022-08-15 22:38:03 -07:00
|
|
|
|
if (LightSensorManager.IsPlayerLightSensor(__instance))
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2022-05-27 15:03:30 -07:00
|
|
|
|
if (!QSBWorldSync.AllObjectsReady)
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2022-08-15 22:38:03 -07:00
|
|
|
|
var qsbLightSensor = __instance.GetWorldObject<QSBLightSensor>();
|
2022-05-27 15:03:30 -07:00
|
|
|
|
|
|
|
|
|
if (__instance._fixedUpdateFrameDelayCount > 0)
|
|
|
|
|
{
|
|
|
|
|
__instance._fixedUpdateFrameDelayCount--;
|
2022-08-15 22:38:03 -07:00
|
|
|
|
return false;
|
2022-05-27 15:03:30 -07:00
|
|
|
|
}
|
2022-05-27 21:57:59 -07:00
|
|
|
|
var illuminated = __instance._illuminated;
|
2022-08-15 22:48:58 -07:00
|
|
|
|
var locallyIlluminated = qsbLightSensor._locallyIlluminated;
|
2022-05-27 15:03:30 -07:00
|
|
|
|
__instance.UpdateIllumination();
|
2022-08-15 22:38:03 -07:00
|
|
|
|
if (!illuminated && __instance._illuminated)
|
2022-05-28 14:14:25 -07:00
|
|
|
|
{
|
2022-08-15 22:38:03 -07:00
|
|
|
|
__instance.OnDetectLight.Invoke();
|
|
|
|
|
return false;
|
2022-05-27 15:03:30 -07:00
|
|
|
|
}
|
2022-08-15 22:38:03 -07:00
|
|
|
|
if (illuminated && !__instance._illuminated)
|
2022-05-28 09:51:34 -07:00
|
|
|
|
{
|
2022-08-15 22:38:03 -07:00
|
|
|
|
__instance.OnDetectDarkness.Invoke();
|
2022-08-15 22:48:58 -07:00
|
|
|
|
}
|
|
|
|
|
if (!locallyIlluminated && qsbLightSensor._locallyIlluminated)
|
|
|
|
|
{
|
|
|
|
|
qsbLightSensor.OnDetectLocalLight.Invoke();
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (locallyIlluminated && !qsbLightSensor._locallyIlluminated)
|
|
|
|
|
{
|
|
|
|
|
qsbLightSensor.OnDetectLocalDarkness.Invoke();
|
2022-05-28 09:51:34 -07:00
|
|
|
|
}
|
2022-05-27 15:03:30 -07:00
|
|
|
|
return false;
|
|
|
|
|
}
|
2022-08-15 22:29:21 -07:00
|
|
|
|
|
|
|
|
|
[HarmonyPrefix]
|
|
|
|
|
[HarmonyPatch(nameof(SingleLightSensor.UpdateIllumination))]
|
|
|
|
|
private static bool UpdateIllumination(SingleLightSensor __instance)
|
|
|
|
|
{
|
2022-08-15 22:38:03 -07:00
|
|
|
|
if (LightSensorManager.IsPlayerLightSensor(__instance))
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
if (!QSBWorldSync.AllObjectsReady)
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
var qsbLightSensor = __instance.GetWorldObject<QSBLightSensor>();
|
|
|
|
|
|
2022-08-15 22:29:21 -07:00
|
|
|
|
__instance._illuminated = false;
|
2022-08-15 22:38:03 -07:00
|
|
|
|
qsbLightSensor._locallyIlluminated = false;
|
2022-08-15 22:29:21 -07:00
|
|
|
|
__instance._illuminatingDreamLanternList?.Clear();
|
|
|
|
|
if (__instance._lightSources == null || __instance._lightSources.Count == 0)
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
var sensorWorldPos = __instance.transform.TransformPoint(__instance._localSensorOffset);
|
|
|
|
|
var sensorWorldDir = Vector3.zero;
|
|
|
|
|
if (__instance._directionalSensor)
|
|
|
|
|
{
|
|
|
|
|
sensorWorldDir = __instance.transform.TransformDirection(__instance._localDirection).normalized;
|
|
|
|
|
}
|
|
|
|
|
foreach (var lightSource in __instance._lightSources)
|
|
|
|
|
{
|
|
|
|
|
if ((__instance._lightSourceMask & lightSource.GetLightSourceType()) == lightSource.GetLightSourceType() &&
|
|
|
|
|
lightSource.CheckIlluminationAtPoint(sensorWorldPos, __instance._sensorRadius, __instance._maxDistance))
|
|
|
|
|
{
|
|
|
|
|
switch (lightSource.GetLightSourceType())
|
|
|
|
|
{
|
|
|
|
|
case LightSourceType.UNDEFINED:
|
|
|
|
|
{
|
|
|
|
|
var owlight = lightSource as OWLight2;
|
|
|
|
|
var occludableLight = owlight.GetLight().shadows != LightShadows.None &&
|
|
|
|
|
owlight.GetLight().shadowStrength > 0.5f;
|
|
|
|
|
if (owlight.CheckIlluminationAtPoint(sensorWorldPos, __instance._sensorRadius, __instance._maxDistance) &&
|
|
|
|
|
!__instance.CheckOcclusion(owlight.transform.position, sensorWorldPos, sensorWorldDir, occludableLight))
|
|
|
|
|
{
|
|
|
|
|
__instance._illuminated = true;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case LightSourceType.FLASHLIGHT:
|
|
|
|
|
{
|
|
|
|
|
var position = Locator.GetPlayerCamera().transform.position;
|
|
|
|
|
var vector3 = __instance.transform.position - position;
|
|
|
|
|
if (Vector3.Angle(Locator.GetPlayerCamera().transform.forward, vector3) <= __instance._maxSpotHalfAngle &&
|
|
|
|
|
!__instance.CheckOcclusion(position, sensorWorldPos, sensorWorldDir))
|
|
|
|
|
{
|
|
|
|
|
__instance._illuminated = true;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case LightSourceType.PROBE:
|
|
|
|
|
{
|
|
|
|
|
var probe = Locator.GetProbe();
|
|
|
|
|
if (probe != null &&
|
|
|
|
|
probe.IsLaunched() &&
|
|
|
|
|
!probe.IsRetrieving() &&
|
|
|
|
|
probe.CheckIlluminationAtPoint(sensorWorldPos, __instance._sensorRadius, __instance._maxDistance) &&
|
|
|
|
|
!__instance.CheckOcclusion(probe.GetLightSourcePosition(), sensorWorldPos, sensorWorldDir))
|
|
|
|
|
{
|
|
|
|
|
__instance._illuminated = true;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case LightSourceType.DREAM_LANTERN:
|
|
|
|
|
{
|
|
|
|
|
var dreamLanternController = lightSource as DreamLanternController;
|
|
|
|
|
if (dreamLanternController.IsLit() &&
|
|
|
|
|
dreamLanternController.IsFocused(__instance._lanternFocusThreshold) &&
|
|
|
|
|
dreamLanternController.CheckIlluminationAtPoint(sensorWorldPos, __instance._sensorRadius, __instance._maxDistance) &&
|
|
|
|
|
!__instance.CheckOcclusion(dreamLanternController.GetLightPosition(), sensorWorldPos, sensorWorldDir))
|
|
|
|
|
{
|
|
|
|
|
__instance._illuminatingDreamLanternList.Add(dreamLanternController);
|
|
|
|
|
__instance._illuminated = true;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case LightSourceType.SIMPLE_LANTERN:
|
|
|
|
|
foreach (var owlight in lightSource.GetLights())
|
|
|
|
|
{
|
|
|
|
|
var occludableLight = owlight.GetLight().shadows != LightShadows.None &&
|
|
|
|
|
owlight.GetLight().shadowStrength > 0.5f;
|
|
|
|
|
var maxDistance = Mathf.Min(__instance._maxSimpleLanternDistance, __instance._maxDistance);
|
|
|
|
|
if (owlight.CheckIlluminationAtPoint(sensorWorldPos, __instance._sensorRadius, maxDistance) &&
|
|
|
|
|
!__instance.CheckOcclusion(owlight.transform.position, sensorWorldPos, sensorWorldDir, occludableLight))
|
|
|
|
|
{
|
|
|
|
|
__instance._illuminated = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case LightSourceType.VOLUME_ONLY:
|
|
|
|
|
__instance._illuminated = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2022-03-06 23:13:48 -08:00
|
|
|
|
}
|