diff --git a/QSB/AssetBundles/qsb_network b/QSB/AssetBundles/qsb_network index 20902e41..cbf886f5 100644 Binary files a/QSB/AssetBundles/qsb_network and b/QSB/AssetBundles/qsb_network differ diff --git a/QSB/AssetBundles/qsb_network_big b/QSB/AssetBundles/qsb_network_big index 4688aa52..22247a5b 100644 Binary files a/QSB/AssetBundles/qsb_network_big and b/QSB/AssetBundles/qsb_network_big differ diff --git a/QSB/EchoesOfTheEye/LightSensorSync/Patches/LightSensorPatches.cs b/QSB/EchoesOfTheEye/LightSensorSync/Patches/LightSensorPatches.cs index d060a2f7..dd0a4247 100644 --- a/QSB/EchoesOfTheEye/LightSensorSync/Patches/LightSensorPatches.cs +++ b/QSB/EchoesOfTheEye/LightSensorSync/Patches/LightSensorPatches.cs @@ -247,7 +247,7 @@ internal class LightSensorPatches : QSBPatch } case LightSourceType.PROBE: { - if (lightSource is QSBProbe qsbProbe) + if (lightSource is QSBSurveyorProbe qsbProbe) { var probe = qsbProbe; if (probe != null && @@ -350,7 +350,7 @@ internal class LightSensorPatches : QSBPatch } case LightSourceType.PROBE: { - if (lightSource is not QSBProbe) + if (lightSource is not QSBSurveyorProbe) { var probe = Locator.GetProbe(); if (probe != null && diff --git a/QSB/Messaging/OWEvents.cs b/QSB/Messaging/OWEvents.cs index dc89f647..865b0b12 100644 --- a/QSB/Messaging/OWEvents.cs +++ b/QSB/Messaging/OWEvents.cs @@ -33,6 +33,7 @@ public static class OWEvents public const string ExitDreamWorld = nameof(ExitDreamWorld); public const string EnterRemoteFlightConsole = nameof(EnterRemoteFlightConsole); public const string ExitRemoteFlightConsole = nameof(ExitRemoteFlightConsole); + public const string ProbeSnapshotRemoved = "Probe Snapshot Removed"; // pain public const string StartShipIgnition = nameof(StartShipIgnition); public const string CompleteShipIgnition = nameof(CompleteShipIgnition); public const string CancelShipIgnition = nameof(CancelShipIgnition); diff --git a/QSB/Player/PlayerInfoParts/Tools.cs b/QSB/Player/PlayerInfoParts/Tools.cs index 65788e41..04141b5c 100644 --- a/QSB/Player/PlayerInfoParts/Tools.cs +++ b/QSB/Player/PlayerInfoParts/Tools.cs @@ -15,7 +15,7 @@ namespace QSB.Player; public partial class PlayerInfo { public GameObject ProbeBody { get; set; } - public QSBProbe Probe { get; set; } + public QSBSurveyorProbe Probe { get; set; } public QSBFlashlight FlashLight => CameraBody == null ? null : CameraBody.GetComponentInChildren(); public QSBTool Signalscope => GetToolByType(ToolType.Signalscope); public QSBTool Translator => GetToolByType(ToolType.Translator); diff --git a/QSB/Player/QSBPlayerManager.cs b/QSB/Player/QSBPlayerManager.cs index 20fcf91d..a7216c8e 100644 --- a/QSB/Player/QSBPlayerManager.cs +++ b/QSB/Player/QSBPlayerManager.cs @@ -88,7 +88,7 @@ public static class QSBPlayerManager public static (Flashlight LocalFlashlight, IEnumerable RemoteFlashlights) GetPlayerFlashlights() => (Locator.GetFlashlight(), PlayerList.Where(x => x.FlashLight != null).Select(x => x.FlashLight)); - public static (SurveyorProbe LocalProbe, IEnumerable RemoteProbes) GetPlayerProbes() + public static (SurveyorProbe LocalProbe, IEnumerable RemoteProbes) GetPlayerProbes() => (Locator.GetProbe(), PlayerList.Where(x => x.Probe != null).Select(x => x.Probe)); public static IEnumerable GetThrusterLightTrackers() diff --git a/QSB/QuantumSync/Patches/QuantumPatches.cs b/QSB/QuantumSync/Patches/QuantumPatches.cs index 0da7ade9..a37e418b 100644 --- a/QSB/QuantumSync/Patches/QuantumPatches.cs +++ b/QSB/QuantumSync/Patches/QuantumPatches.cs @@ -478,4 +478,17 @@ public class QuantumPatches : QSBPatch return false; } + [HarmonyPrefix] + [HarmonyPatch(typeof(QuantumObject), nameof(QuantumObject.OnProbeSnapshot))] + public static bool OnProbeSnapshot() + { + return false; + } + + [HarmonyPrefix] + [HarmonyPatch(typeof(QuantumObject), nameof(QuantumObject.OnProbeSnapshotRemoved))] + public static bool OnProbeSnapshotRemoved() + { + return false; + } } \ No newline at end of file diff --git a/QSB/QuantumSync/QuantumManager.cs b/QSB/QuantumSync/QuantumManager.cs index 1d932e6e..888b29f8 100644 --- a/QSB/QuantumSync/QuantumManager.cs +++ b/QSB/QuantumSync/QuantumManager.cs @@ -126,6 +126,32 @@ internal class QuantumManager : WorldObjectManager return QSBPlayerManager.PlayerList.Where(x => x.EntangledObject == worldObj); } + public static void OnTakeProbeSnapshot(PlayerInfo player, ProbeCamera.ID cameraId) + { + DebugLog.DebugWrite($"{player} took a probe snapshot with cameraid {cameraId}"); + + foreach (var quantumObject in QSBWorldSync.GetWorldObjects()) + { + if (quantumObject.ControllingPlayer == QSBPlayerManager.LocalPlayerId) + { + quantumObject.OnTakeProbeSnapshot(player, cameraId); + } + } + } + + public static void OnRemoveProbeSnapshot(PlayerInfo player) + { + DebugLog.DebugWrite($"{player} removed their snapshot."); + + foreach (var quantumObject in QSBWorldSync.GetWorldObjects()) + { + if (quantumObject.ControllingPlayer == QSBPlayerManager.LocalPlayerId) + { + quantumObject.OnRemoveProbeSnapshot(player); + } + } + } + #region debug shapes private static GameObject _debugSphere, _debugCube, _debugCapsule; diff --git a/QSB/QuantumSync/WorldObjects/IQSBQuantumObject.cs b/QSB/QuantumSync/WorldObjects/IQSBQuantumObject.cs index 55d43df0..ebf3a989 100644 --- a/QSB/QuantumSync/WorldObjects/IQSBQuantumObject.cs +++ b/QSB/QuantumSync/WorldObjects/IQSBQuantumObject.cs @@ -1,4 +1,5 @@ -using QSB.WorldSync; +using QSB.Player; +using QSB.WorldSync; using System.Collections.Generic; namespace QSB.QuantumSync.WorldObjects; @@ -12,4 +13,6 @@ public interface IQSBQuantumObject : IWorldObject void SetIsQuantum(bool isQuantum); VisibilityObject GetVisibilityObject(); + void OnTakeProbeSnapshot(PlayerInfo player, ProbeCamera.ID cameraId); + void OnRemoveProbeSnapshot(PlayerInfo player); } \ No newline at end of file diff --git a/QSB/QuantumSync/WorldObjects/QSBQuantumObject.cs b/QSB/QuantumSync/WorldObjects/QSBQuantumObject.cs index 9f9011a2..d062f62f 100644 --- a/QSB/QuantumSync/WorldObjects/QSBQuantumObject.cs +++ b/QSB/QuantumSync/WorldObjects/QSBQuantumObject.cs @@ -3,6 +3,7 @@ using OWML.Common; using QSB.Messaging; using QSB.Player; using QSB.QuantumSync.Messages; +using QSB.Tools.ProbeTool; using QSB.Utility; using QSB.WorldSync; using System.Collections.Generic; @@ -28,6 +29,8 @@ internal abstract class QSBQuantumObject : WorldObject, IQSBQuantumObject public uint ControllingPlayer { get; set; } public bool IsEnabled { get; private set; } + private List _visibleToProbes = new(); + public override void OnRemoval() { if (HostControls) @@ -174,6 +177,116 @@ internal abstract class QSBQuantumObject : WorldObject, IQSBQuantumObject ((IQSBQuantumObject)this).SendMessage(new QuantumAuthorityMessage(0u)); }); + public void OnTakeProbeSnapshot(PlayerInfo player, ProbeCamera.ID cameraId) + { + DebugLog.DebugWrite($"{AttachedObject.name} OnTakeProbeSnapshot playerId:{player.PlayerId} cameraId:{cameraId}"); + if (player.IsLocalPlayer) + { + DebugLog.DebugWrite($"- is local player"); + var probe = Locator.GetProbe(); + ProbeCamera probeCamera = default; + switch (cameraId) + { + case ProbeCamera.ID.Forward: + probeCamera = probe.GetForwardCamera(); + break; + case ProbeCamera.ID.Reverse: + probeCamera = probe.GetReverseCamera(); + break; + case ProbeCamera.ID.Rotating: + probeCamera = probe.GetRotatingCamera(); + break; + case ProbeCamera.ID.PreLaunch: + probeCamera = player.LocalProbeLauncher._preLaunchCamera; + break; + } + + var distance = Vector3.Distance(AttachedObject.transform.position, probeCamera.transform.position); + DebugLog.DebugWrite($"- distance is {distance}"); + if (distance < AttachedObject._maxSnapshotLockRange + && AttachedObject.IsIlluminated() + && !probeCamera.HasInterference() + && AttachedObject.CheckVisibilityFromProbe(probeCamera.GetOWCamera())) + { + DebugLog.DebugWrite($"- Visible in probe snapshot for local player!"); + if (!_visibleToProbes.Contains(player)) + { + _visibleToProbes.Add(player); + } + + AttachedObject._visibleInProbeSnapshot = _visibleToProbes.Any(x => x != null); + DebugLog.DebugWrite($"- _visibleInProbeSnapshot is now {AttachedObject._visibleInProbeSnapshot}"); + return; + } + else + { + DebugLog.DebugWrite($"- not visible :("); + } + } + else + { + DebugLog.DebugWrite($"- not local player"); + var probe = player.Probe; + QSBProbeCamera probeCamera = default; + switch (cameraId) + { + case ProbeCamera.ID.Forward: + probeCamera = probe.GetForwardCamera(); + break; + case ProbeCamera.ID.Reverse: + probeCamera = probe.GetReverseCamera(); + break; + case ProbeCamera.ID.Rotating: + probeCamera = probe.GetRotatingCamera(); + break; + case ProbeCamera.ID.PreLaunch: + //TODO : uhhhh yeah do this lol + probeCamera = null; + break; + } + + var distance = Vector3.Distance(AttachedObject.transform.position, probeCamera.transform.position); + if (distance < AttachedObject._maxSnapshotLockRange + && AttachedObject.IsIlluminated() + && !probeCamera.HasInterference() + && AttachedObject.CheckVisibilityFromProbe(probeCamera.GetOWCamera())) + { + DebugLog.DebugWrite($"Visible in probe snapshot for {player.PlayerId}!"); + if (!_visibleToProbes.Contains(player)) + { + _visibleToProbes.Add(player); + } + + _visibleToProbes.Add(player); + AttachedObject._visibleInProbeSnapshot = _visibleToProbes.Any(x => x != null); + DebugLog.DebugWrite($"- _visibleInProbeSnapshot is now {AttachedObject._visibleInProbeSnapshot}"); + return; + } + } + + if (_visibleToProbes.Contains(player)) + { + DebugLog.DebugWrite($"NOT visible in probe snapshot for {player.PlayerId}!"); + _visibleToProbes.Remove(player); + } + + AttachedObject._visibleInProbeSnapshot = _visibleToProbes.Any(x => x != null); + DebugLog.DebugWrite($"- _visibleInProbeSnapshot is now {AttachedObject._visibleInProbeSnapshot}"); + } + + public void OnRemoveProbeSnapshot(PlayerInfo player) + { + DebugLog.DebugWrite($"{AttachedObject.name} OnRemoveProbeSnapshot playerId:{player.PlayerId}"); + + if (_visibleToProbes.Contains(player)) + { + _visibleToProbes.Remove(player); + } + + AttachedObject._visibleInProbeSnapshot = _visibleToProbes.Any(x => x != null); + DebugLog.DebugWrite($"- _visibleInProbeSnapshot is now {AttachedObject._visibleInProbeSnapshot}"); + } + public override void DisplayLines() { if (AttachedObject == null) diff --git a/QSB/Tools/ProbeLauncherTool/Messages/PlayerLauncherTakeSnapshotMessage.cs b/QSB/Tools/ProbeLauncherTool/Messages/PlayerLauncherTakeSnapshotMessage.cs index 2ff0dfda..93b090d0 100644 --- a/QSB/Tools/ProbeLauncherTool/Messages/PlayerLauncherTakeSnapshotMessage.cs +++ b/QSB/Tools/ProbeLauncherTool/Messages/PlayerLauncherTakeSnapshotMessage.cs @@ -1,16 +1,22 @@ using QSB.Messaging; using QSB.Player; +using QSB.QuantumSync; using QSB.WorldSync; namespace QSB.Tools.ProbeLauncherTool.Messages; -internal class PlayerLauncherTakeSnapshotMessage : QSBMessage +internal class PlayerLauncherTakeSnapshotMessage : QSBMessage { + public PlayerLauncherTakeSnapshotMessage(ProbeCamera.ID cameraId) : base(cameraId) { } + public override bool ShouldReceive => QSBWorldSync.AllObjectsReady; + public override void OnReceiveLocal() => QuantumManager.OnTakeProbeSnapshot(QSBPlayerManager.LocalPlayer, Data); + public override void OnReceiveRemote() { var player = QSBPlayerManager.GetPlayer(From); player.ProbeLauncherTool.TakeSnapshot(); + QuantumManager.OnTakeProbeSnapshot(player, Data); } } diff --git a/QSB/Tools/ProbeLauncherTool/Messages/RemoveSnapshotMessage.cs b/QSB/Tools/ProbeLauncherTool/Messages/RemoveSnapshotMessage.cs new file mode 100644 index 00000000..3d75101b --- /dev/null +++ b/QSB/Tools/ProbeLauncherTool/Messages/RemoveSnapshotMessage.cs @@ -0,0 +1,26 @@ +using QSB.Messaging; +using QSB.Player; +using QSB.Player.TransformSync; +using QSB.QuantumSync; + +namespace QSB.Tools.ProbeLauncherTool.Messages; + +internal class RemoveSnapshotMessage : QSBMessage +{ + static RemoveSnapshotMessage() + => GlobalMessenger.AddListener(OWEvents.ProbeSnapshotRemoved, Handle); + + private static void Handle() + { + if (PlayerTransformSync.LocalInstance) + { + new RemoveSnapshotMessage().Send(); + } + } + + public override void OnReceiveLocal() + => QuantumManager.OnRemoveProbeSnapshot(QSBPlayerManager.LocalPlayer); + + public override void OnReceiveRemote() + => QuantumManager.OnRemoveProbeSnapshot(QSBPlayerManager.GetPlayer(From)); +} diff --git a/QSB/Tools/ProbeLauncherTool/Messages/TakeSnapshotMessage.cs b/QSB/Tools/ProbeLauncherTool/Messages/TakeSnapshotMessage.cs index a92b5b7e..f0d1e77c 100644 --- a/QSB/Tools/ProbeLauncherTool/Messages/TakeSnapshotMessage.cs +++ b/QSB/Tools/ProbeLauncherTool/Messages/TakeSnapshotMessage.cs @@ -1,16 +1,17 @@ using QSB.Messaging; +using QSB.Player; +using QSB.QuantumSync; using QSB.Tools.ProbeLauncherTool.WorldObjects; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace QSB.Tools.ProbeLauncherTool.Messages; -internal class TakeSnapshotMessage : QSBWorldObjectMessage +internal class TakeSnapshotMessage : QSBWorldObjectMessage { - public TakeSnapshotMessage() : base() { } + public TakeSnapshotMessage(ProbeCamera.ID cameraId) : base(cameraId) { } - public override void OnReceiveRemote() => WorldObject.TakeSnapshot(); + public override void OnReceiveLocal() + => QuantumManager.OnTakeProbeSnapshot(QSBPlayerManager.LocalPlayer, Data); + + public override void OnReceiveRemote() + => WorldObject.TakeSnapshot(QSBPlayerManager.GetPlayer(From), Data); } diff --git a/QSB/Tools/ProbeLauncherTool/Patches/LauncherPatches.cs b/QSB/Tools/ProbeLauncherTool/Patches/LauncherPatches.cs index 40cbeac3..7b04554e 100644 --- a/QSB/Tools/ProbeLauncherTool/Patches/LauncherPatches.cs +++ b/QSB/Tools/ProbeLauncherTool/Patches/LauncherPatches.cs @@ -107,7 +107,7 @@ internal class LauncherPatches : QSBPatch } } - [HarmonyPostfix] + /*[HarmonyPostfix] [HarmonyPatch(typeof(ProbeLauncherEffects), nameof(ProbeLauncherEffects.PlaySnapshotClip))] public static void ProbeLauncherEffects_PlaySnapshotClip(ProbeLauncherEffects __instance) { @@ -122,5 +122,24 @@ internal class LauncherPatches : QSBPatch { new PlayerLauncherTakeSnapshotMessage().Send(); } + }*/ + + [HarmonyPostfix] + [HarmonyPatch(typeof(ProbeLauncher), nameof(ProbeLauncher.TakeSnapshotWithCamera))] + public static void TakeSnapshotWithCamera(ProbeLauncher __instance, ProbeCamera camera) + { + DebugLog.DebugWrite($"TakeSnapshotWithCamera - cameraid:{camera.GetID()}"); + if (__instance != QSBPlayerManager.LocalPlayer.LocalProbeLauncher) + { + DebugLog.DebugWrite($"- not local launcher"); + __instance + ?.GetWorldObject() + ?.SendMessage(new TakeSnapshotMessage(camera.GetID())); + } + else + { + DebugLog.DebugWrite($"- local launcher"); + new PlayerLauncherTakeSnapshotMessage(camera.GetID()).Send(); + } } } \ No newline at end of file diff --git a/QSB/Tools/ProbeLauncherTool/WorldObjects/QSBProbeLauncher.cs b/QSB/Tools/ProbeLauncherTool/WorldObjects/QSBProbeLauncher.cs index 72c800aa..3c714a24 100644 --- a/QSB/Tools/ProbeLauncherTool/WorldObjects/QSBProbeLauncher.cs +++ b/QSB/Tools/ProbeLauncherTool/WorldObjects/QSBProbeLauncher.cs @@ -1,6 +1,7 @@ using Cysharp.Threading.Tasks; using QSB.Messaging; using QSB.Player; +using QSB.QuantumSync; using QSB.Tools.ProbeLauncherTool.Messages; using QSB.Tools.ProbeTool; using QSB.WorldSync; @@ -12,7 +13,7 @@ namespace QSB.Tools.ProbeLauncherTool.WorldObjects; public class QSBProbeLauncher : WorldObject { private uint _probeOwnerID = uint.MaxValue; - protected QSBProbe LaunchedProbe { get; private set; } + protected QSBSurveyorProbe LaunchedProbe { get; private set; } public override async UniTask Init(CancellationToken ct) => AttachedObject.OnLaunchProbe += OnLaunchProbe; @@ -83,12 +84,14 @@ public class QSBProbeLauncher : WorldObject AttachedObject._effects.PlayChangeModeClip(); } - public void TakeSnapshot() + public void TakeSnapshot(PlayerInfo player, ProbeCamera.ID cameraId) { // Not using PlaySnapshotClip because that uses Locator.GetPlayerAudioController() instead of owAudioSource for some reason AttachedObject._effects._owAudioSource.PlayOneShot(AudioType.ToolProbeTakePhoto, 1f); // If their probe is launched also play a snapshot from it if (LaunchedProbe && LaunchedProbe.IsLaunched()) LaunchedProbe.TakeSnapshot(); + + QuantumManager.OnTakeProbeSnapshot(player, cameraId); } } \ No newline at end of file diff --git a/QSB/Tools/ProbeTool/Messages/RotateProbeMessage.cs b/QSB/Tools/ProbeTool/Messages/RotateProbeMessage.cs new file mode 100644 index 00000000..50c7bc42 --- /dev/null +++ b/QSB/Tools/ProbeTool/Messages/RotateProbeMessage.cs @@ -0,0 +1,32 @@ +using QSB.Messaging; +using QSB.Player; +using QSB.WorldSync; +using UnityEngine; + +namespace QSB.Tools.ProbeTool.Messages; + +internal class RotateProbeMessage : QSBMessage<(RotationType rotationType, Vector2 cameraRotation)> +{ + public RotateProbeMessage(RotationType rotationType, Vector2 cameraRotation) : base((rotationType, cameraRotation)) { } + + public override bool ShouldReceive => QSBWorldSync.AllObjectsReady; + + public override void OnReceiveRemote() + { + var playerProbe = QSBPlayerManager.GetPlayer(From).Probe; + var rotatingCamera = playerProbe.GetRotatingCamera(); + + if (Data.rotationType == RotationType.Horizontal) + { + rotatingCamera.RotateHorizontal(Data.cameraRotation.x); + } + else if (Data.rotationType == RotationType.Vertical) + { + rotatingCamera.RotateVertical(Data.cameraRotation.y); + } + else + { + rotatingCamera.ResetRotation(); + } + } +} diff --git a/QSB/Tools/ProbeTool/Patches/ProbeToolPatches.cs b/QSB/Tools/ProbeTool/Patches/ProbeToolPatches.cs index db5c5fba..fcfc9d82 100644 --- a/QSB/Tools/ProbeTool/Patches/ProbeToolPatches.cs +++ b/QSB/Tools/ProbeTool/Patches/ProbeToolPatches.cs @@ -1,5 +1,9 @@ using HarmonyLib; +using QSB.Messaging; using QSB.Patches; +using QSB.Tools.ProbeTool.Messages; +using QSB.Utility; +using UnityEngine; namespace QSB.Tools.ProbeTool.Patches; @@ -37,4 +41,53 @@ internal class ProbeToolPatches : QSBPatch return false; } + + [HarmonyPrefix] + [HarmonyPatch(typeof(ProbeCamera), nameof(ProbeCamera.RotateHorizontal))] + public static bool RotateHorizontal(ProbeCamera __instance, float degrees) + { + if (__instance._id != ProbeCamera.ID.Rotating) + { + Debug.LogWarning("Tried to rotate a non-rotating ProbeCamera!", __instance); + return false; + } + + __instance._cameraRotation.x += degrees; + __instance.transform.parent.localRotation = __instance._origParentLocalRotation * Quaternion.AngleAxis(__instance._cameraRotation.x, Vector3.up); + __instance.RaiseEvent(nameof(__instance.OnRotateCamera), __instance._cameraRotation); + new RotateProbeMessage(RotationType.Horizontal, __instance._cameraRotation).Send(); + return false; + } + + [HarmonyPrefix] + [HarmonyPatch(typeof(ProbeCamera), nameof(ProbeCamera.RotateVertical))] + public static bool RotateVertical(ProbeCamera __instance, float degrees) + { + if (__instance._id != ProbeCamera.ID.Rotating) + { + Debug.LogWarning("Tried to rotate a non-rotating ProbeCamera!", __instance); + return false; + } + + __instance._cameraRotation.y = Mathf.Clamp(__instance._cameraRotation.y + degrees, -90f, 0f); + __instance.transform.localRotation = __instance._origLocalRotation * Quaternion.AngleAxis(__instance._cameraRotation.y, Vector3.right); + __instance.RaiseEvent(nameof(__instance.OnRotateCamera), __instance._cameraRotation); + new RotateProbeMessage(RotationType.Vertical, __instance._cameraRotation).Send(); + return false; + } + + [HarmonyPrefix] + [HarmonyPatch(typeof(ProbeCamera), nameof(ProbeCamera.ResetRotation))] + public static bool ResetRotation(ProbeCamera __instance) + { + if (__instance._id == ProbeCamera.ID.Rotating) + { + __instance._cameraRotation = Vector2.zero; + __instance.transform.localRotation = __instance._origLocalRotation; + __instance.transform.parent.localRotation = __instance._origParentLocalRotation; + new RotateProbeMessage(RotationType.Reset, __instance._cameraRotation).Send(); + } + + return false; + } } \ No newline at end of file diff --git a/QSB/Tools/ProbeTool/ProbeCreator.cs b/QSB/Tools/ProbeTool/ProbeCreator.cs index 4a82e84b..8742ac34 100644 --- a/QSB/Tools/ProbeTool/ProbeCreator.cs +++ b/QSB/Tools/ProbeTool/ProbeCreator.cs @@ -26,7 +26,7 @@ internal static class ProbeCreator { var REMOTE_Probe_Body = Object.Instantiate(GetPrefab()); - var qsbProbe = REMOTE_Probe_Body.GetComponent(); + var qsbProbe = REMOTE_Probe_Body.GetComponent(); player.Probe = qsbProbe; qsbProbe.SetOwner(player); diff --git a/QSB/Tools/ProbeTool/QSBProbeAnimatorController.cs b/QSB/Tools/ProbeTool/QSBProbeAnimatorController.cs new file mode 100644 index 00000000..7a4915af --- /dev/null +++ b/QSB/Tools/ProbeTool/QSBProbeAnimatorController.cs @@ -0,0 +1,92 @@ +using UnityEngine; + +namespace QSB.Tools.ProbeTool; + +[RequireComponent(typeof(Animator))] +internal class QSBProbeAnimatorController : MonoBehaviour +{ + private Animator _animator; + private QSBSurveyorProbe _probe; + + [SerializeField] + private Transform _centerBone; + + private Quaternion _startCenterBoneRotation = Quaternion.identity; + private Quaternion _targetCenterBoneRotation = Quaternion.identity; + private Quaternion _currentCenterBoneRotation = Quaternion.identity; + + private float _rotationT; + + private void Awake() + { + this._animator = base.GetComponent(); + this._probe = transform.parent.parent.parent.GetRequiredComponent(); + this._probe.OnLaunchProbe += this.OnProbeFire; + this._probe.OnAnchorProbe += this.OnProbeAnchor; + this._probe.OnRetrieveProbe += this.OnProbeReset; + } + + private void Start() + { + this._probe.GetRotatingCamera().OnRotateCamera += this.OnRotateCamera; + base.enabled = false; + } + + private void OnDestroy() + { + this._probe.OnLaunchProbe -= this.OnProbeFire; + this._probe.OnAnchorProbe -= this.OnProbeAnchor; + this._probe.OnRetrieveProbe -= this.OnProbeReset; + } + + public Quaternion GetCenterBoneLocalRotation() + { + return this._centerBone.localRotation; + } + + private void OnProbeFire() + { + this._animator.SetTrigger("Fire"); + } + + private void OnProbeAnchor() + { + this._animator.SetTrigger("Impact"); + } + + private void OnProbeReset() + { + this._animator.SetTrigger("Reset"); + this._centerBone.localRotation = Quaternion.identity; + this._startCenterBoneRotation = Quaternion.identity; + this._targetCenterBoneRotation = Quaternion.identity; + this._currentCenterBoneRotation = Quaternion.identity; + this._rotationT = 0f; + base.enabled = false; + } + + private void OnRotateCamera(Vector2 rotation) + { + this._startCenterBoneRotation = this._currentCenterBoneRotation; + this._targetCenterBoneRotation = Quaternion.AngleAxis(rotation.x, Vector3.up); + this._rotationT = 0f; + base.enabled = true; + } + + private void LateUpdate() + { + this._rotationT += 10f * Time.deltaTime; + if (this._rotationT >= 1f) + { + this._rotationT = 1f; + this._currentCenterBoneRotation = this._targetCenterBoneRotation; + base.enabled = false; + } + else + { + float t = Mathf.Sqrt(Mathf.SmoothStep(0f, 1f, this._rotationT)); + this._currentCenterBoneRotation = Quaternion.Lerp(this._startCenterBoneRotation, this._targetCenterBoneRotation, t); + } + this._centerBone.localRotation = this._currentCenterBoneRotation; + } +} diff --git a/QSB/Tools/ProbeTool/QSBProbeCamera.cs b/QSB/Tools/ProbeTool/QSBProbeCamera.cs new file mode 100644 index 00000000..8efaa166 --- /dev/null +++ b/QSB/Tools/ProbeTool/QSBProbeCamera.cs @@ -0,0 +1,94 @@ +using UnityEngine; + +namespace QSB.Tools.ProbeTool; + +[RequireComponent(typeof(OWCamera))] +public class QSBProbeCamera : MonoBehaviour +{ + [SerializeField] + private ProbeCamera.ID _id; + + private OWCamera _camera; + private RenderTexture _snapshotTexture; + private NoiseImageEffect _noiseEffect; + private static OWCamera _lastSnapshotCamera; + private Quaternion _origLocalRotation; + private Quaternion _origParentLocalRotation; + private Vector2 _cameraRotation = Vector2.zero; + private QuantumMoon _quantumMoon; + private SandLevelController _sandLevelController; + + public event ProbeCamera.RotateCameraEvent OnRotateCamera; + + private void Awake() + { + _camera = this.GetRequiredComponent(); + _camera.enabled = false; + _noiseEffect = GetComponent(); + //this._snapshotTexture = ProbeCamera.GetSharedSnapshotTexture(); + } + + private void OnDestroy() + => _snapshotTexture = null; + + private void Start() + { + var astroObject = Locator.GetAstroObject(AstroObject.Name.QuantumMoon); + if (astroObject != null) + { + _quantumMoon = astroObject.GetComponent(); + } + } + + public static OWCamera GetLastSnapshotCamera() => + _lastSnapshotCamera; + + public OWCamera GetOWCamera() + => _camera; + + public ProbeCamera.ID GetID() + => _id; + + public void SetSandLevelController(SandLevelController sandLevelController) + => _sandLevelController = sandLevelController; + + public bool HasInterference() => + _id != ProbeCamera.ID.PreLaunch + //&& ((this._quantumMoon != null && this._quantumMoon.IsPlayerInside() != this._quantumMoon.IsProbeInside()) + || (_sandLevelController != null && _sandLevelController.IsPointBuried(transform.position)); + //|| (Locator.GetCloakFieldController() != null && Locator.GetCloakFieldController().isPlayerInsideCloak != Locator.GetCloakFieldController().isProbeInsideCloak)); + + public RenderTexture TakeSnapshot() + { + _lastSnapshotCamera = _camera; + if (_noiseEffect != null) + { + _noiseEffect.enabled = HasInterference(); + } + + _camera.targetTexture = _snapshotTexture; + _camera.Render(); + return _snapshotTexture; + } + + public void RotateHorizontal(float cameraRotationX) + { + _cameraRotation.x = cameraRotationX; + transform.parent.localRotation = _origParentLocalRotation * Quaternion.AngleAxis(_cameraRotation.x, Vector3.up); + OnRotateCamera?.Invoke(_cameraRotation); + } + + public void RotateVertical(float cameraRotationY) + { + _cameraRotation.y = cameraRotationY; + transform.localRotation = _origLocalRotation * Quaternion.AngleAxis(_cameraRotation.y, Vector3.right); + OnRotateCamera?.Invoke(_cameraRotation); + } + + public void ResetRotation() + { + _cameraRotation = Vector2.zero; + transform.localRotation = _origLocalRotation; + transform.parent.localRotation = _origParentLocalRotation; + } +} diff --git a/QSB/Tools/ProbeTool/QSBProbeEffects.cs b/QSB/Tools/ProbeTool/QSBProbeEffects.cs index 8715fe1b..e517f75f 100644 --- a/QSB/Tools/ProbeTool/QSBProbeEffects.cs +++ b/QSB/Tools/ProbeTool/QSBProbeEffects.cs @@ -12,11 +12,11 @@ internal class QSBProbeEffects : MonoBehaviour public OWAudioSource _anchorAudio; public ParticleSystem _anchorParticles; - private QSBProbe _probe; + private QSBSurveyorProbe _probe; private void Awake() { - _probe = QSBWorldSync.GetUnityObjects().First(x => gameObject.transform.IsChildOf(x.transform)); + _probe = QSBWorldSync.GetUnityObjects().First(x => gameObject.transform.IsChildOf(x.transform)); if (_probe == null) { DebugLog.ToConsole($"Error - Couldn't find QSBProbe!", OWML.Common.MessageType.Error); diff --git a/QSB/Tools/ProbeTool/QSBProbeLantern.cs b/QSB/Tools/ProbeTool/QSBProbeLantern.cs index 6269a14d..728033aa 100644 --- a/QSB/Tools/ProbeTool/QSBProbeLantern.cs +++ b/QSB/Tools/ProbeTool/QSBProbeLantern.cs @@ -14,7 +14,7 @@ internal class QSBProbeLantern : MonoBehaviour public OWEmissiveRenderer _emissiveRenderer; public float _originalRange; - private QSBProbe _probe; + private QSBSurveyorProbe _probe; private OWLight2 _light; private float _fadeFraction; private float _targetFade; @@ -24,7 +24,7 @@ internal class QSBProbeLantern : MonoBehaviour private void Awake() { - _probe = QSBWorldSync.GetUnityObjects().First(x => gameObject.transform.IsChildOf(x.transform)); + _probe = QSBWorldSync.GetUnityObjects().First(x => gameObject.transform.IsChildOf(x.transform)); if (_probe == null) { DebugLog.ToConsole($"Error - Couldn't find QSBProbe!", OWML.Common.MessageType.Error); diff --git a/QSB/Tools/ProbeTool/QSBProbeSpotlight.cs b/QSB/Tools/ProbeTool/QSBProbeSpotlight.cs index 68c6f371..00c60016 100644 --- a/QSB/Tools/ProbeTool/QSBProbeSpotlight.cs +++ b/QSB/Tools/ProbeTool/QSBProbeSpotlight.cs @@ -12,13 +12,13 @@ internal class QSBProbeSpotlight : MonoBehaviour public float _fadeInLength = 1f; public float _intensity; - private QSBProbe _probe; + private QSBSurveyorProbe _probe; private OWLight2 _light; private float _timer; private void Awake() { - _probe = QSBWorldSync.GetUnityObjects().First(x => gameObject.transform.IsChildOf(x.transform)); + _probe = QSBWorldSync.GetUnityObjects().First(x => gameObject.transform.IsChildOf(x.transform)); if (_probe == null) { DebugLog.ToConsole($"Error - Couldn't find QSBProbe!", OWML.Common.MessageType.Error); diff --git a/QSB/Tools/ProbeTool/QSBProbe.cs b/QSB/Tools/ProbeTool/QSBSurveyorProbe.cs similarity index 83% rename from QSB/Tools/ProbeTool/QSBProbe.cs rename to QSB/Tools/ProbeTool/QSBSurveyorProbe.cs index c388ba10..1869b7fa 100644 --- a/QSB/Tools/ProbeTool/QSBProbe.cs +++ b/QSB/Tools/ProbeTool/QSBSurveyorProbe.cs @@ -5,7 +5,7 @@ using UnityEngine; namespace QSB.Tools.ProbeTool; [UsedInUnityProject] -public class QSBProbe : MonoBehaviour, ILightSource +public class QSBSurveyorProbe : MonoBehaviour, ILightSource { public delegate void SurveyorProbeEvent(); public delegate void RetrieveEvent(float retrieveLength); @@ -24,6 +24,9 @@ public class QSBProbe : MonoBehaviour, ILightSource private GameObject _detectorObj; private RulesetDetector _rulesetDetector; private SingularityWarpEffect _warpEffect; + private QSBProbeCamera _forwardCam; + private QSBProbeCamera _reverseCam; + private QSBProbeCamera _rotatingCam; private bool _isRetrieving; private PlayerInfo _owner; private bool _anchored; @@ -32,6 +35,21 @@ public class QSBProbe : MonoBehaviour, ILightSource public RulesetDetector GetRulesetDetector() => _rulesetDetector; + public QSBProbeCamera GetForwardCamera() + { + return _forwardCam; + } + + public QSBProbeCamera GetReverseCamera() + { + return _reverseCam; + } + + public QSBProbeCamera GetRotatingCamera() + { + return _rotatingCam; + } + private void Awake() { _detectorObj = GetComponentInChildren().gameObject; @@ -39,6 +57,23 @@ public class QSBProbe : MonoBehaviour, ILightSource _warpEffect = GetComponentInChildren(); _warpEffect.OnWarpComplete += OnWarpComplete; _isRetrieving = false; + + var probeCameras = GetComponentsInChildren(); + for (var i = 0; i < probeCameras.Length; i++) + { + if (probeCameras[i].GetID() == ProbeCamera.ID.Forward) + { + _forwardCam = probeCameras[i]; + } + else if (probeCameras[i].GetID() == ProbeCamera.ID.Reverse) + { + _reverseCam = probeCameras[i]; + } + else if (probeCameras[i].GetID() == ProbeCamera.ID.Rotating) + { + _rotatingCam = probeCameras[i]; + } + } } private void Start() @@ -129,6 +164,9 @@ public class QSBProbe : MonoBehaviour, ILightSource case ProbeEvent.Unanchor: _anchored = false; _owner.ProbeActive = true; // just in case it was missed + _forwardCam.SetSandLevelController(null); + _reverseCam.SetSandLevelController(null); + _rotatingCam.SetSandLevelController(null); OnUnanchorProbe(); break; case ProbeEvent.Retrieve: @@ -167,6 +205,9 @@ public class QSBProbe : MonoBehaviour, ILightSource _lightSourceVol.SetVolumeActivation(false); gameObject.SetActive(false); _isRetrieving = false; + _forwardCam.SetSandLevelController(null); + _reverseCam.SetSandLevelController(null); + _rotatingCam.SetSandLevelController(null); } public void OnStartRetrieve(float duration) diff --git a/QSB/Tools/ProbeTool/RotationType.cs b/QSB/Tools/ProbeTool/RotationType.cs new file mode 100644 index 00000000..30883d71 --- /dev/null +++ b/QSB/Tools/ProbeTool/RotationType.cs @@ -0,0 +1,8 @@ +namespace QSB.Tools.ProbeTool; + +public enum RotationType +{ + Horizontal, + Vertical, + Reset +} diff --git a/QSB/Utility/DebugActions.cs b/QSB/Utility/DebugActions.cs index c741dffd..06c14888 100644 --- a/QSB/Utility/DebugActions.cs +++ b/QSB/Utility/DebugActions.cs @@ -2,6 +2,7 @@ using QSB.ItemSync.WorldObjects.Items; using QSB.Messaging; using QSB.Player; +using QSB.QuantumSync.WorldObjects; using QSB.RespawnSync; using QSB.ShipSync; using QSB.Utility.Messages; @@ -15,7 +16,7 @@ namespace QSB.Utility; public class DebugActions : MonoBehaviour, IAddComponentOnStart { - public static Type WorldObjectSelection; + public static Type WorldObjectSelection = typeof(QSBSocketedQuantumObject); private static void GoToVessel() {