using HarmonyLib; using OWML.Utils; using QSB.Events; using QSB.Patches; using QSB.Utility; using System; using UnityEngine; namespace QSB.ShipSync.Patches { [HarmonyPatch] internal class ShipPatches : QSBPatch { public override QSBPatchTypes Type => QSBPatchTypes.OnClientConnect; [HarmonyPrefix] [HarmonyPatch(typeof(HatchController), nameof(HatchController.OnPressInteract))] public static bool HatchController_OnPressInteract() { if (!PlayerState.IsInsideShip()) { ShipManager.Instance.ShipTractorBeam.ActivateTractorBeam(); QSBEventManager.FireEvent(EventNames.QSBEnableFunnel); } QSBEventManager.FireEvent(EventNames.QSBHatchState, true); return true; } [HarmonyPrefix] [HarmonyPatch(typeof(HatchController), nameof(HatchController.OnEntry))] public static bool HatchController_OnEntry(GameObject hitObj) { if (hitObj.CompareTag("PlayerDetector")) { QSBEventManager.FireEvent(EventNames.QSBHatchState, false); } return true; } [HarmonyPrefix] [HarmonyPatch(typeof(ShipTractorBeamSwitch), nameof(ShipTractorBeamSwitch.OnTriggerExit))] public static bool ShipTractorBeamSwitch_OnTriggerExit(ShipTractorBeamSwitch __instance, Collider hitCollider) { if (!__instance._isPlayerInShip && __instance._functional && hitCollider.CompareTag("PlayerDetector") && !ShipManager.Instance.HatchController._hatchObject.activeSelf) { ShipManager.Instance.HatchController.Invoke("CloseHatch"); ShipManager.Instance.ShipTractorBeam.DeactivateTractorBeam(); QSBEventManager.FireEvent(EventNames.QSBHatchState, false); } return false; } [HarmonyReversePatch] [HarmonyPatch(typeof(SingleInteractionVolume), nameof(SingleInteractionVolume.UpdateInteractVolume))] public static void SingleInteractionVolume_UpdateInteractVolume_Stub(object instance) => throw new NotImplementedException(); [HarmonyPrefix] [HarmonyPatch(typeof(InteractZone), nameof(InteractZone.UpdateInteractVolume))] public static bool InteractZone_UpdateInteractVolume(InteractZone __instance) { /* Angle for interaction with the ship hatch * * \ 80° / - If in ship * \ / * \ / * [=====] - Hatch * / \ * / \ * / 280° \ - If not in ship * */ if (!QSBCore.WorldObjectsReady || __instance != ShipManager.Instance.HatchInteractZone) { return true; } var angle = 2f * Vector3.Angle(__instance._playerCam.transform.forward, __instance.transform.forward); __instance._focused = PlayerState.IsInsideShip() ? angle <= 80 : angle >= 280; SingleInteractionVolume_UpdateInteractVolume_Stub(__instance); return false; } [HarmonyReversePatch] [HarmonyPatch(typeof(ShipComponent), nameof(ShipComponent.OnEnterShip))] public static void ShipComponent_OnEnterShip_Stub(object instance) => throw new NotImplementedException(); [HarmonyPrefix] [HarmonyPatch(typeof(ShipElectricalComponent), nameof(ShipElectricalComponent.OnEnterShip))] public static bool ShipElectricalComponent_OnEnterShip(ShipElectricalComponent __instance) { ShipComponent_OnEnterShip_Stub(__instance); return false; } [HarmonyReversePatch] [HarmonyPatch(typeof(ShipComponent), nameof(ShipComponent.OnExitShip))] public static void ShipComponent_OnExitShip_Stub(object instance) => throw new NotImplementedException(); [HarmonyPrefix] [HarmonyPatch(typeof(ShipElectricalComponent), nameof(ShipElectricalComponent.OnExitShip))] public static bool ShipElectricalComponent_OnExitShip(ShipElectricalComponent __instance) { ShipComponent_OnExitShip_Stub(__instance); return false; } [HarmonyPrefix] [HarmonyPatch(typeof(ShipComponent), nameof(ShipComponent.SetDamaged))] public static bool ShipComponent_SetDamaged(ShipComponent __instance, bool damaged) { if (__instance._damaged == damaged) { return false; } if (damaged) { __instance._damaged = true; __instance._repairFraction = 0f; __instance.GetType().GetAnyMethod("OnComponentDamaged").Invoke(__instance, null); __instance.RaiseEvent("OnDamaged", __instance); QSBEventManager.FireEvent(EventNames.QSBComponentDamaged, __instance); } else { __instance._damaged = false; __instance._repairFraction = 1f; __instance.GetType().GetAnyMethod("OnComponentRepaired").Invoke(__instance, null); __instance.RaiseEvent("OnRepaired", __instance); QSBEventManager.FireEvent(EventNames.QSBComponentRepaired, __instance); } __instance.GetType().GetAnyMethod("UpdateColliderState").Invoke(__instance, null); if (__instance._damageEffect) { __instance._damageEffect.SetEffectBlend(1f - __instance._repairFraction); } return false; } [HarmonyPrefix] [HarmonyPatch(typeof(ShipHull), nameof(ShipHull.FixedUpdate))] public static bool ShipHull_FixedUpdate(ShipHull __instance, ref ImpactData ____dominantImpact, ref float ____integrity, ref bool ____damaged, DamageEffect ____damageEffect, ShipComponent[] ____components) { if (____dominantImpact != null) { var damage = Mathf.InverseLerp(30f, 200f, ____dominantImpact.speed); if (damage > 0f) { var num2 = 0.15f; if (damage < num2 && ____integrity > 1f - num2) { damage = num2; } ____integrity = Mathf.Max(____integrity - damage, 0f); if (!____damaged) { ____damaged = true; __instance.RaiseEvent("OnDamaged", __instance); QSBEventManager.FireEvent(EventNames.QSBHullDamaged, __instance); } if (____damageEffect != null) { ____damageEffect.SetEffectBlend(1f - ____integrity); } QSBEventManager.FireEvent(EventNames.QSBHullChangeIntegrity, __instance, ____integrity); } foreach (var component in ____components) { if (!(component == null) && !component.isDamaged) { if (component.ApplyImpact(____dominantImpact)) { break; } } } __instance.RaiseEvent("OnImpact", ____dominantImpact, damage); QSBEventManager.FireEvent(EventNames.QSBHullImpact, __instance, ____dominantImpact, damage); ____dominantImpact = null; } __instance.enabled = false; return false; } [HarmonyPrefix] [HarmonyPatch(typeof(ShipDamageController), nameof(ShipDamageController.OnImpact))] public static bool ShipDamageController_OnImpact() => ShipManager.Instance.HasAuthority; [HarmonyPostfix] [HarmonyPatch(typeof(ShipComponent), nameof(ShipComponent.RepairTick))] public static void ShipComponent_RepairTick(ShipComponent __instance, float ____repairFraction) { QSBEventManager.FireEvent(EventNames.QSBComponentRepairTick, __instance, ____repairFraction); return; } [HarmonyPrefix] [HarmonyPatch(typeof(ShipHull), nameof(ShipHull.RepairTick))] public static bool ShipHull_RepairTick(ShipHull __instance, ref float ____integrity, ref bool ____damaged, DamageEffect ____damageEffect, float ____repairTime) { if (!____damaged) { return false; } ____integrity = Mathf.Min(____integrity + Time.deltaTime / ____repairTime, 1f); QSBEventManager.FireEvent(EventNames.QSBHullRepairTick, __instance, ____integrity); if (____integrity >= 1f) { ____damaged = false; __instance.RaiseEvent("OnRepaired", __instance); QSBEventManager.FireEvent(EventNames.QSBHullRepaired, __instance); } if (____damageEffect != null) { ____damageEffect.SetEffectBlend(1f - ____integrity); } return false; } } }