diff --git a/QSB/Animation/Player/Events/AnimationTriggerEvent.cs b/QSB/Animation/Player/Events/AnimationTriggerEvent.cs index ea2d8f30..b84781a8 100644 --- a/QSB/Animation/Player/Events/AnimationTriggerEvent.cs +++ b/QSB/Animation/Player/Events/AnimationTriggerEvent.cs @@ -21,11 +21,11 @@ namespace QSB.Animation.Player.Events public override void OnReceiveRemote(bool server, AnimationTriggerMessage message) { - if (!QSBCore.WorldObjectsReady) + var animationSync = QSBPlayerManager.GetSyncObject(message.AttachedNetId); + if (!QSBCore.WorldObjectsReady || animationSync != null) { return; } - var animationSync = QSBPlayerManager.GetSyncObject(message.AttachedNetId); animationSync.VisibleAnimator.SetTrigger(message.Name); } } diff --git a/QSB/DeathSync/Patches/DeathPatches.cs b/QSB/DeathSync/Patches/DeathPatches.cs index bac4037f..7b4d3c63 100644 --- a/QSB/DeathSync/Patches/DeathPatches.cs +++ b/QSB/DeathSync/Patches/DeathPatches.cs @@ -1,9 +1,11 @@ using Harmony; using QSB.Events; using QSB.Patches; +using QSB.Utility; using System.Collections.Generic; using System.Linq; using System.Reflection.Emit; +using UnityEngine; namespace QSB.DeathSync.Patches { @@ -20,6 +22,8 @@ namespace QSB.DeathSync.Patches QSBCore.HarmonyHelper.EmptyMethod("OnPressInteract"); QSBCore.HarmonyHelper.AddPostfix("Awake", typeof(DeathPatches), nameof(DamageController_Exploded)); QSBCore.HarmonyHelper.AddPrefix("VanishShip", typeof(DeathPatches), nameof(DestructionVolume_VanishShip)); + QSBCore.HarmonyHelper.AddPrefix("FixedUpdate", typeof(DeathPatches), nameof(HighSpeedImpactSensor_FixedUpdate)); + QSBCore.HarmonyHelper.AddPrefix("OnImpact", typeof(DeathPatches), nameof(PlayerResources_OnImpact)); } public override void DoUnpatches() @@ -30,6 +34,150 @@ namespace QSB.DeathSync.Patches QSBCore.HarmonyHelper.Unpatch("OnPressInteract"); QSBCore.HarmonyHelper.Unpatch("Awake"); QSBCore.HarmonyHelper.Unpatch("VanishShip"); + QSBCore.HarmonyHelper.Unpatch("FixedUpdate"); + QSBCore.HarmonyHelper.Unpatch("OnImpact"); + } + + public static bool PlayerResources_OnImpact(ImpactData impact, PlayerResources __instance, float ____currentHealth) + { + if (PlayerState.IsInsideShip()) + { + return false; + } + + var speed = Mathf.Clamp01((impact.speed - __instance.GetMinImpactSpeed()) / (__instance.GetMaxImpactSpeed() - __instance.GetMinImpactSpeed())); + var tookDamage = __instance.ApplyInstantDamage(100f * speed, InstantDamageType.Impact); + if (tookDamage && ____currentHealth <= 0f && !PlayerState.IsDead()) + { + Locator.GetDeathManager().SetImpactDeathSpeed(impact.speed); + Locator.GetDeathManager().KillPlayer(DeathType.Impact); + DebugLog.DebugWrite(string.Concat(new object[] + { + "Player killed from impact with ", + impact.otherCollider, + " attached to ", + impact.otherCollider.attachedRigidbody.gameObject.name + })); + } + return false; + } + + public static bool HighSpeedImpactSensor_FixedUpdate( + HighSpeedImpactSensor __instance, + bool ____isPlayer, + ref bool ____dead, + ref bool ____dieNextUpdate, + OWRigidbody ____body, + ref float ____impactSpeed, + float ____sqrCheckSpeedThreshold, + RaycastHit[] ____raycastHits, + SectorDetector ____sectorDetector, + float ____radius, + Vector3 ____localOffset + ) + { + if (____isPlayer && (PlayerState.IsAttached() || PlayerState.IsInsideShuttle() || PlayerState.UsingNomaiRemoteCamera())) + { + return false; + } + + if (____dieNextUpdate && !____dead) + { + ____dead = true; + ____dieNextUpdate = false; + if (__instance.gameObject.CompareTag("Player")) + { + Locator.GetDeathManager().SetImpactDeathSpeed(____impactSpeed); + Locator.GetDeathManager().KillPlayer(DeathType.Impact); + } + else if (__instance.gameObject.CompareTag("Ship")) + { + __instance.GetComponent().Explode(false); + } + } + + if (____isPlayer && PlayerState.IsInsideShip()) + { + var shipCenter = Locator.GetShipTransform().position + (Locator.GetShipTransform().up * 2f); + var distanceFromShip = Vector3.Distance(____body.GetPosition(), shipCenter); + if (distanceFromShip > 8f) + { + ____body.SetPosition(shipCenter); + DebugLog.DebugWrite("MOVE PLAYER BACK TO SHIP CENTER"); + } + + if (!____dead) + { + var a = ____body.GetVelocity() - Locator.GetShipBody().GetPointVelocity(____body.GetPosition()); + if (a.sqrMagnitude > ____sqrCheckSpeedThreshold) + { + ____impactSpeed = a.magnitude; + ____body.AddVelocityChange(-a); + DebugLog.DebugWrite("Would have killed player..."); + //____dieNextUpdate = true; + DebugLog.DebugWrite(string.Concat(new object[] + { + "HIGH SPEED IMPACT: ", + __instance.name, + " hit the Ship at ", + ____impactSpeed, + "m/s Dist from ship: ", + distanceFromShip + })); + } + } + return false; + } + + var passiveReferenceFrame = ____sectorDetector.GetPassiveReferenceFrame(); + if (!____dead && passiveReferenceFrame != null) + { + var relativeVelocity = ____body.GetVelocity() - passiveReferenceFrame.GetOWRigidBody().GetPointVelocity(____body.GetPosition()); + if (relativeVelocity.sqrMagnitude > ____sqrCheckSpeedThreshold) + { + var hitCount = Physics.RaycastNonAlloc(__instance.transform.TransformPoint(____localOffset), relativeVelocity, ____raycastHits, (relativeVelocity.magnitude * Time.deltaTime) + ____radius, OWLayerMask.physicalMask, QueryTriggerInteraction.Ignore); + for (var i = 0; i < hitCount; i++) + { + if (____raycastHits[i].rigidbody.mass > 10f && !____raycastHits[i].rigidbody.Equals(____body.GetRigidbody())) + { + var owRigidbody = ____raycastHits[i].rigidbody.GetComponent(); + if (owRigidbody == null) + { + DebugLog.ToConsole("Rigidbody does not have attached OWRigidbody!!!", OWML.Common.MessageType.Error); + Debug.Break(); + } + else + { + relativeVelocity = ____body.GetVelocity() - owRigidbody.GetPointVelocity(____body.GetPosition()); + var a2 = Vector3.Project(relativeVelocity, ____raycastHits[i].normal); + if (a2.sqrMagnitude > ____sqrCheckSpeedThreshold) + { + ____body.AddVelocityChange(-a2); + ____impactSpeed = a2.magnitude; + if (!PlayerState.IsInsideTheEye()) + { + ____dieNextUpdate = true; + } + DebugLog.DebugWrite(string.Concat(new object[] + { + "HIGH SPEED IMPACT: ", + __instance.name, + " hit ", + ____raycastHits[i].rigidbody.name, + " at ", + ____impactSpeed, + "m/s RF: ", + passiveReferenceFrame.GetOWRigidBody().name + })); + break; + } + } + } + } + } + } + + return false; } public static bool PreFinishDeathSequence(DeathType deathType) diff --git a/QSB/DeathSync/RespawnOnDeath.cs b/QSB/DeathSync/RespawnOnDeath.cs index 23181671..091a5e77 100644 --- a/QSB/DeathSync/RespawnOnDeath.cs +++ b/QSB/DeathSync/RespawnOnDeath.cs @@ -30,6 +30,7 @@ namespace QSB.DeathSync private ShipCockpitController _cockpitController; private PlayerSpacesuit _spaceSuit; private ShipTractorBeamSwitch _shipTractorBeam; + private SuitPickupVolume[] _suitPickupVolumes; public void Awake() => Instance = this; @@ -40,6 +41,8 @@ namespace QSB.DeathSync _spaceSuit = Locator.GetPlayerSuit(); _playerSpawner = FindObjectOfType(); _shipTractorBeam = FindObjectOfType(); + _suitPickupVolumes = FindObjectsOfType(); + _fluidDetector = Locator.GetPlayerCamera().GetComponentInChildren(); _playerSpawnPoint = GetSpawnPoint(); @@ -88,6 +91,33 @@ namespace QSB.DeathSync _playerResources.SetValue("_isSuffocating", false); _playerResources.DebugRefillResources(); _spaceSuit.RemoveSuit(true); + + foreach (var pickupVolume in _suitPickupVolumes) + { + var containsSuit = pickupVolume.GetValue("_containsSuit"); + var allowReturn = pickupVolume.GetValue("_allowSuitReturn"); + + if (!containsSuit && allowReturn) + { + + var interactVolume = pickupVolume.GetValue("_interactVolume"); + var pickupSuitIndex = pickupVolume.GetValue("_pickupSuitCommandIndex"); + + pickupVolume.SetValue("_containsSuit", true); + interactVolume.ChangePrompt(UITextType.SuitUpPrompt, pickupSuitIndex); + + var suitGeometry = pickupVolume.GetValue("_suitGeometry"); + var suitCollider = pickupVolume.GetValue("_suitOWCollider"); + var toolGeometries = pickupVolume.GetValue("_toolGeometry"); + + suitGeometry.SetActive(true); + suitCollider.SetActivation(true); + foreach (var geo in toolGeometries) + { + geo.SetActive(true); + } + } + } } public void ResetShip() diff --git a/QSB/OrbSync/TransformSync/NomaiOrbTransformSync.cs b/QSB/OrbSync/TransformSync/NomaiOrbTransformSync.cs index 8dc4d273..6edf9820 100644 --- a/QSB/OrbSync/TransformSync/NomaiOrbTransformSync.cs +++ b/QSB/OrbSync/TransformSync/NomaiOrbTransformSync.cs @@ -11,17 +11,11 @@ namespace QSB.OrbSync.TransformSync public static List OrbTransformSyncs = new List(); private int _index => OrbTransformSyncs.IndexOf(this); - private bool _isReady; - public override void OnStartClient() - { - QSBSceneManager.OnSceneLoaded += (OWScene scene, bool inUniverse) => _isReady = false; - OrbTransformSyncs.Add(this); - } + public override void OnStartClient() => OrbTransformSyncs.Add(this); protected override void OnDestroy() { - QSBSceneManager.OnSceneLoaded -= (OWScene scene, bool inUniverse) => _isReady = false; OrbTransformSyncs.Remove(this); QSBSceneManager.OnSceneLoaded -= OnSceneLoaded; } @@ -34,6 +28,11 @@ namespace QSB.OrbSync.TransformSync private GameObject GetTransform() { + if (_index == -1) + { + DebugLog.ToConsole($"Error - Index cannot be found.", OWML.Common.MessageType.Error); + return null; + } if (QSBWorldSync.OldOrbList == null || QSBWorldSync.OldOrbList.Count <= _index) { DebugLog.ToConsole($"Error - OldOrbList is null or does not contain index {_index}.", OWML.Common.MessageType.Error); diff --git a/QSB/Player/QSBPlayerManager.cs b/QSB/Player/QSBPlayerManager.cs index 28cbd141..8a6564e1 100644 --- a/QSB/Player/QSBPlayerManager.cs +++ b/QSB/Player/QSBPlayerManager.cs @@ -20,7 +20,9 @@ namespace QSB.Player var localInstance = PlayerTransformSync.LocalInstance; if (localInstance == null) { - DebugLog.ToConsole($"Error - Trying to get LocalPlayerId when the local PlayerTransformSync instance is null.", MessageType.Error); + var method = new StackTrace().GetFrame(1).GetMethod(); + DebugLog.ToConsole($"Error - Trying to get LocalPlayerId when the local PlayerTransformSync instance is null." + + $"{Environment.NewLine} Called from {method.DeclaringType.Name}.{method.Name} ", MessageType.Error); return uint.MaxValue; } if (localInstance.NetIdentity == null) diff --git a/QSB/QSBCore.cs b/QSB/QSBCore.cs index e69c5355..e8f6bd67 100644 --- a/QSB/QSBCore.cs +++ b/QSB/QSBCore.cs @@ -64,7 +64,7 @@ namespace QSB public static AssetBundle NetworkAssetBundle { get; private set; } public static AssetBundle InstrumentAssetBundle { get; private set; } public static AssetBundle ConversationAssetBundle { get; private set; } - public static bool WorldObjectsReady => WorldObjectManager.AllReady; + public static bool WorldObjectsReady => WorldObjectManager.AllReady && IsInMultiplayer && PlayerTransformSync.LocalInstance != null; public static bool IsServer => QNetworkServer.active; public static bool IsInMultiplayer => QNetworkManager.singleton.isNetworkActive; public static string QSBVersion => Helper.Manifest.Version; @@ -176,15 +176,23 @@ namespace QSB { GUI.Label(new Rect(420, offset3, 200f, 20f), $"In control of ship? : {ship.HasAuthority}"); offset3 += _debugLineSpacing; - GUI.Label(new Rect(420, offset3, 200f, 20f), $"Ship sector : {(ship.ReferenceSector == null ? "NULL" : ship.ReferenceSector.Name)}"); + GUI.Label(new Rect(420, offset3, 400f, 20f), $"Ship sector : {(ship.ReferenceSector == null ? "NULL" : ship.ReferenceSector.Name)}"); offset3 += _debugLineSpacing; - GUI.Label(new Rect(420, offset3, 400f, 20f), $"Ship relative velocity : {ship.AttachedObject.GetRelativeVelocity(ship.ReferenceTransform.GetAttachedOWRigidbody())}"); - offset3 += _debugLineSpacing; - offset3 += _debugLineSpacing; - GUI.Label(new Rect(420, offset3, 400f, 20f), $"Ship velocity mag. : {ship.GetVelocityChangeMagnitude()}"); + if (ship.ReferenceTransform != null) + { + GUI.Label(new Rect(420, offset3, 400f, 20f), $"Ship relative velocity : {ship.GetRelativeVelocity()}"); + offset3 += _debugLineSpacing; + GUI.Label(new Rect(420, offset3, 400f, 20f), $"Ship velocity mag. : {ship.GetVelocityChangeMagnitude()}"); + offset3 += _debugLineSpacing; + } + GUI.Label(new Rect(420, offset3, 200f, 20f), $"Ship sectors :"); offset3 += _debugLineSpacing; + foreach (var sector in ship.SectorSync.SectorList) + { + GUI.Label(new Rect(420, offset3, 400f, 20f), $"- {sector.Name}"); + offset3 += _debugLineSpacing; + } } - var offset2 = 10f; @@ -217,6 +225,16 @@ namespace QSB GUI.Label(new Rect(220, offset, 400f, 20f), $"- Thrusting : {player.JetpackAcceleration?.IsThrusting}"); offset += _debugLineSpacing; } + GUI.Label(new Rect(220, offset, 200f, 20f), $"QM Illuminated : {Locator.GetQuantumMoon().IsIlluminated()}"); + offset += _debugLineSpacing; + GUI.Label(new Rect(220, offset, 200f, 20f), $"QM Visible by :"); + offset += _debugLineSpacing; + var tracker = Locator.GetQuantumMoon().GetValue("_visibilityTracker"); + foreach (var player in QSBPlayerManager.GetPlayersWithCameras()) + { + GUI.Label(new Rect(220, offset, 200f, 20f), $" - {player.PlayerId} : {tracker.GetType().GetMethod("IsInFrustum", BindingFlags.NonPublic | BindingFlags.Instance).Invoke(tracker, new object[] { player.Camera.GetFrustumPlanes() })}"); + offset += _debugLineSpacing; + } if (SocketedObjToDebug == -1) { diff --git a/QSB/QSBNetworkLobby.cs b/QSB/QSBNetworkLobby.cs index 7f233a3b..be49c50b 100644 --- a/QSB/QSBNetworkLobby.cs +++ b/QSB/QSBNetworkLobby.cs @@ -11,6 +11,8 @@ namespace QSB public bool CanEditName { get; set; } public string PlayerName { get; private set; } + // TODO : Could delete a lot of this - shouldnt be possible to not have a profile and still play + private readonly string[] _defaultNames = { "Arkose", "Chert", diff --git a/QSB/QuantumSync/Patches/QuantumPatches.cs b/QSB/QuantumSync/Patches/QuantumPatches.cs index 6553557f..58a561f6 100644 --- a/QSB/QuantumSync/Patches/QuantumPatches.cs +++ b/QSB/QuantumSync/Patches/QuantumPatches.cs @@ -435,7 +435,7 @@ namespace QSB.QuantumSync.Patches fogAlpha = Mathf.InverseLerp(____fogThickness + ____fogRolloffDistance, ____fogThickness, distanceFromFog); if (distanceFromFog < 0f) { - if ((bool)__instance.GetType().GetMethod("IsLockedByProbeSnapshot", BindingFlags.NonPublic | BindingFlags.Instance).Invoke(__instance, null) || QuantumManager.IsVisibleUsingCameraFrustum((ShapeVisibilityTracker)____visibilityTracker, true)) + if ((bool)__instance.GetType().GetMethod("IsLockedByProbeSnapshot", BindingFlags.NonPublic | BindingFlags.Instance).Invoke(__instance, null) || QuantumManager.IsVisibleUsingCameraFrustum((ShapeVisibilityTracker)____visibilityTracker, true).First) { ____isPlayerInside = true; __instance.GetType().GetMethod("SetSurfaceState", BindingFlags.NonPublic | BindingFlags.Instance).Invoke(__instance, new object[] { ____stateIndex }); @@ -456,7 +456,7 @@ namespace QSB.QuantumSync.Patches if (____stateIndex != 5) { ____isPlayerInside = false; - if (!(bool)__instance.GetType().GetMethod("IsLockedByProbeSnapshot", BindingFlags.NonPublic | BindingFlags.Instance).Invoke(__instance, null) && !QuantumManager.IsVisibleUsingCameraFrustum((ShapeVisibilityTracker)____visibilityTracker, true)) + if (!(bool)__instance.GetType().GetMethod("IsLockedByProbeSnapshot", BindingFlags.NonPublic | BindingFlags.Instance).Invoke(__instance, null) && !QuantumManager.IsVisibleUsingCameraFrustum((ShapeVisibilityTracker)____visibilityTracker, true).First) { __instance.GetType().GetMethod("Collapse", BindingFlags.NonPublic | BindingFlags.Instance).Invoke(__instance, new object[] { true }); } diff --git a/QSB/QuantumSync/Patches/QuantumVisibilityPatches.cs b/QSB/QuantumSync/Patches/QuantumVisibilityPatches.cs index b7c484f6..cd5f9b24 100644 --- a/QSB/QuantumSync/Patches/QuantumVisibilityPatches.cs +++ b/QSB/QuantumSync/Patches/QuantumVisibilityPatches.cs @@ -41,7 +41,7 @@ namespace QSB.QuantumSync.Patches public static bool ShapeIsVisibleUsingCameraFrustum(ShapeVisibilityTracker __instance, ref bool __result) { - __result = QuantumManager.IsVisibleUsingCameraFrustum(__instance, false); + __result = QuantumManager.IsVisibleUsingCameraFrustum(__instance, false).First; return false; } diff --git a/QSB/QuantumSync/Patches/ServerQuantumPatches.cs b/QSB/QuantumSync/Patches/ServerQuantumPatches.cs index c4f9859c..8e53c80e 100644 --- a/QSB/QuantumSync/Patches/ServerQuantumPatches.cs +++ b/QSB/QuantumSync/Patches/ServerQuantumPatches.cs @@ -1,8 +1,9 @@ using OWML.Common; using QSB.Events; using QSB.Patches; +using QSB.Player; using QSB.Utility; -using System.Diagnostics; +using System.Linq; using System.Reflection; using UnityEngine; @@ -40,16 +41,36 @@ namespace QSB.QuantumSync.Patches GameObject[] ____deactivateAtEye ) { - if (QuantumManager.IsVisibleUsingCameraFrustum((ShapeVisibilityTracker)____visibilityTracker, skipInstantVisibilityCheck) && !QuantumManager.Shrine.IsPlayerInDarkness()) + var isVisibleOutput = QuantumManager.IsVisibleUsingCameraFrustum((ShapeVisibilityTracker)____visibilityTracker, skipInstantVisibilityCheck); + //var moonVisible = isVisibleOutput.First; + var moonVisiblePlayers = isVisibleOutput.Second; + var inMoonPlayers = QSBPlayerManager.PlayerList.Where(x => x.IsInMoon); + var inShrinePlayers = QSBPlayerManager.PlayerList.Where(x => x.IsInShrine); + //var outMoonPlayers = QSBPlayerManager.PlayerList.Where(x => !x.IsInMoon); + var outShrinePlayers = QSBPlayerManager.PlayerList.Where(x => !x.IsInShrine); + var shrineLit = QuantumManager.Shrine.IsPlayerInDarkness(); + + // If any of the players in the moon are not in the shrine + if (inMoonPlayers.Any(x => !x.IsInShrine)) { - if (!skipInstantVisibilityCheck) - { - var method = new StackTrace().GetFrame(3).GetMethod(); - DebugLog.ToConsole($"Warning - Tried to change moon state while still observed. Called by {method.DeclaringType}.{method.Name}", MessageType.Warning); - } __result = false; return false; } + + // If any of the players outside the shrine can see the moon + if (outShrinePlayers.Any(moonVisiblePlayers.Contains)) + { + __result = false; + return false; + } + + // If there are players in the shrine and the shrine is not lit + if(inShrinePlayers.Count() != 0 && !shrineLit) + { + __result = false; + return false; + } + var flag = false; if (____isPlayerInside && ____hasSunCollapsed) { @@ -98,7 +119,7 @@ namespace QSB.QuantumSync.Patches { Physics.SyncTransforms(); } - if (__instance.IsPlayerEntangled() || !QuantumManager.IsVisibleUsingCameraFrustum((ShapeVisibilityTracker)____visibilityTracker, skipInstantVisibilityCheck)) + if (__instance.IsPlayerEntangled() || !QuantumManager.IsVisibleUsingCameraFrustum((ShapeVisibilityTracker)____visibilityTracker, skipInstantVisibilityCheck).First) { ____moonBody.transform.position = position; if (!Physics.autoSyncTransforms) diff --git a/QSB/QuantumSync/QuantumManager.cs b/QSB/QuantumSync/QuantumManager.cs index 6a56867b..e0d84cd9 100644 --- a/QSB/QuantumSync/QuantumManager.cs +++ b/QSB/QuantumSync/QuantumManager.cs @@ -76,19 +76,22 @@ namespace QSB.QuantumSync } } - public static bool IsVisibleUsingCameraFrustum(ShapeVisibilityTracker tracker, bool ignoreLocalCamera) + public static Tuple> IsVisibleUsingCameraFrustum(ShapeVisibilityTracker tracker, bool ignoreLocalCamera) { var playersWithCameras = QSBPlayerManager.GetPlayersWithCameras(!ignoreLocalCamera); if (playersWithCameras.Count == 0) { DebugLog.ToConsole($"Warning - Trying to run IsVisibleUsingCameraFrustum when there are no players!", MessageType.Warning); - return false; + return new Tuple>(false, null); } if (!tracker.gameObject.activeInHierarchy) { - return false; + return new Tuple>(false, null); } var frustumMethod = tracker.GetType().GetMethod("IsInFrustum", BindingFlags.NonPublic | BindingFlags.Instance); + + var playersWhoCanSee = new List(); + var foundPlayers = false; foreach (var player in playersWithCameras) { if (player.Camera == null) @@ -99,16 +102,18 @@ namespace QSB.QuantumSync var isInFrustum = (bool)frustumMethod.Invoke(tracker, new object[] { player.Camera.GetFrustumPlanes() }); if (isInFrustum) { - return true; + playersWhoCanSee.Add(player); + foundPlayers = true; } } - return false; + + return new Tuple>(foundPlayers, playersWhoCanSee); } public static bool IsVisible(ShapeVisibilityTracker tracker, bool ignoreLocalCamera) { return tracker.gameObject.activeInHierarchy - && IsVisibleUsingCameraFrustum(tracker, ignoreLocalCamera) + && IsVisibleUsingCameraFrustum(tracker, ignoreLocalCamera).First && QSBPlayerManager.GetPlayersWithCameras(!ignoreLocalCamera) .Any(x => VisibilityOccluder.CanYouSee(tracker, x.Camera.mainCamera.transform.position)); } diff --git a/QSB/RoastingSync/Patches/RoastingPatches.cs b/QSB/RoastingSync/Patches/RoastingPatches.cs index 480d2201..3e9dce13 100644 --- a/QSB/RoastingSync/Patches/RoastingPatches.cs +++ b/QSB/RoastingSync/Patches/RoastingPatches.cs @@ -19,7 +19,7 @@ namespace QSB.RoastingSync.Patches public override void DoUnpatches() { - + // TODO : add unpatches } public static bool Marshmallow_SpawnMallow() diff --git a/QSB/SectorSync/QSBSectorManager.cs b/QSB/SectorSync/QSBSectorManager.cs index a8ac7e90..be9ea06d 100644 --- a/QSB/SectorSync/QSBSectorManager.cs +++ b/QSB/SectorSync/QSBSectorManager.cs @@ -1,8 +1,6 @@ using OWML.Common; using QSB.SectorSync.WorldObjects; using QSB.Syncs; -using QSB.Syncs.RigidbodySync; -using QSB.Syncs.TransformSync; using QSB.Utility; using QSB.WorldSync; using QuantumUNET; @@ -21,11 +19,12 @@ namespace QSB.SectorSync private void OnEnable() => RepeatingManager.Repeatings.Add(this); private void OnDisable() => RepeatingManager.Repeatings.Remove(this); - public List> SectoredSyncs = new List>(); + public List> SectoredTransformSyncs = new List>(); + public List> SectoredRigidbodySyncs = new List>(); public void Invoke() { - foreach (var sync in SectoredSyncs) + foreach (var sync in SectoredTransformSyncs) { if (sync.AttachedObject == null) { @@ -38,6 +37,20 @@ namespace QSB.SectorSync CheckTransformSyncSector(sync); } } + + foreach (var sync in SectoredRigidbodySyncs) + { + if (sync.AttachedObject == null) + { + continue; + } + if ((sync as QNetworkBehaviour).HasAuthority + && sync.AttachedObject.gameObject.activeInHierarchy + && sync.IsReady) + { + CheckTransformSyncSector(sync); + } + } } public override void Awake() diff --git a/QSB/SectorSync/SectorSync.cs b/QSB/SectorSync/SectorSync.cs index d8c7851e..8605a949 100644 --- a/QSB/SectorSync/SectorSync.cs +++ b/QSB/SectorSync/SectorSync.cs @@ -86,8 +86,10 @@ namespace QSB.SectorSync return null; } - var listToCheck = SectorList.Count(x => x.ShouldSyncTo(_targetType)) == 0 - ? QSBWorldSync.GetWorldObjects() + var numSectorsCurrentlyIn = SectorList.Count(x => x.ShouldSyncTo(_targetType)); + + var listToCheck = numSectorsCurrentlyIn == 0 + ? QSBWorldSync.GetWorldObjects().Where(x => !x.IsFakeSector) : SectorList; /* Explanation of working out which sector to sync to : @@ -113,7 +115,9 @@ namespace QSB.SectorSync var ordered = activeNotNullNotBlacklisted .OrderBy(sector => CalculateSectorScore(sector, trans, _attachedOWRigidbody)); + // TODO : clean up this shit??? if ( + numSectorsCurrentlyIn != 0 && // if any fake sectors are *roughly* in the same place as other sectors - we want fake sectors to override other sectors QSBSectorManager.Instance.FakeSectors.Any( x => OWMath.ApproxEquals(Vector3.Distance(x.Position, trans.position), Vector3.Distance(ordered.FirstOrDefault().Position, trans.position), 0.01f) diff --git a/QSB/ShipSync/TransformSync/ShipTransformSync.cs b/QSB/ShipSync/TransformSync/ShipTransformSync.cs index ff30494d..a4b760e9 100644 --- a/QSB/ShipSync/TransformSync/ShipTransformSync.cs +++ b/QSB/ShipSync/TransformSync/ShipTransformSync.cs @@ -29,13 +29,11 @@ namespace QSB.ShipSync.TransformSync { if (HasAuthority && ShipManager.Instance.CurrentFlyer != QSBPlayerManager.LocalPlayerId) { - DebugLog.DebugWrite($"Warning - Local player has ship authority, but is not the current flyer!", OWML.Common.MessageType.Warning); return; } if (!HasAuthority && ShipManager.Instance.CurrentFlyer == QSBPlayerManager.LocalPlayerId) { - DebugLog.DebugWrite($"Warning - Local player does not have ship authority, but is the current flyer!", OWML.Common.MessageType.Warning); return; } @@ -45,5 +43,6 @@ namespace QSB.ShipSync.TransformSync public override TargetType Type => TargetType.Ship; public override bool UseInterpolation => true; + protected override float DistanceLeeway => 20f; } } \ No newline at end of file diff --git a/QSB/Syncs/RigidbodySync/SectoredRigidbodySync.cs b/QSB/Syncs/RigidbodySync/SectoredRigidbodySync.cs index 91c5d575..abc1c1a0 100644 --- a/QSB/Syncs/RigidbodySync/SectoredRigidbodySync.cs +++ b/QSB/Syncs/RigidbodySync/SectoredRigidbodySync.cs @@ -2,7 +2,6 @@ using QSB.SectorSync.WorldObjects; using QSB.WorldSync; using QuantumUNET.Transport; -using System.Collections.Generic; namespace QSB.Syncs.RigidbodySync { @@ -15,14 +14,14 @@ namespace QSB.Syncs.RigidbodySync public override void Start() { SectorSync = gameObject.AddComponent(); - QSBSectorManager.Instance.SectoredSyncs.Add((ISectoredSync)this); + QSBSectorManager.Instance.SectoredRigidbodySyncs.Add(this); base.Start(); } protected override void OnDestroy() { base.OnDestroy(); - QSBSectorManager.Instance.SectoredSyncs.Remove((ISectoredSync)this); + QSBSectorManager.Instance.SectoredRigidbodySyncs.Remove(this); if (SectorSync != null) { Destroy(SectorSync); @@ -104,7 +103,7 @@ namespace QSB.Syncs.RigidbodySync public void SetReferenceSector(QSBSector sector) { ReferenceSector = sector; - SetReferenceTransform(sector.Transform); + SetReferenceTransform(sector?.Transform); } } } diff --git a/QSB/Syncs/RigidbodySync/UnparentedBaseRigidbodySync.cs b/QSB/Syncs/RigidbodySync/UnparentedBaseRigidbodySync.cs index 56dd0d33..b50f7a54 100644 --- a/QSB/Syncs/RigidbodySync/UnparentedBaseRigidbodySync.cs +++ b/QSB/Syncs/RigidbodySync/UnparentedBaseRigidbodySync.cs @@ -1,4 +1,5 @@ using OWML.Common; +using OWML.Utils; using QSB.Utility; using QuantumUNET.Components; using QuantumUNET.Transport; @@ -14,6 +15,10 @@ namespace QSB.Syncs.RigidbodySync public abstract bool IsReady { get; } public abstract bool UseInterpolation { get; } + protected virtual float DistanceLeeway { get; } = 5f; + private float _previousDistance; + private const float SmoothTime = 0.1f; + protected bool _isInitialized; protected IntermediaryTransform _intermediaryTransform; protected Vector3 _velocity; @@ -21,6 +26,8 @@ namespace QSB.Syncs.RigidbodySync protected Vector3 _prevVelocity; protected Vector3 _prevAngularVelocity; private string _logName => $"{NetId}:{GetType().Name}"; + private Vector3 _positionSmoothVelocity; + private Quaternion _rotationSmoothVelocity; protected abstract OWRigidbody GetRigidbody(); @@ -61,18 +68,6 @@ namespace QSB.Syncs.RigidbodySync * We can't store the last two on the IntermediaryTransform, so they come from fields. */ - // Get world position from IT. - - // Get world rotation from IT. - - // Get velocity from field. - - // Get angular velocity from field. - - // Send all. - - // Set _prev fields. - var worldPos = _intermediaryTransform.GetPosition(); var worldRot = _intermediaryTransform.GetRotation(); var velocity = _velocity; @@ -82,6 +77,7 @@ namespace QSB.Syncs.RigidbodySync SerializeRotation(writer, worldRot); writer.Write(velocity); writer.Write(angularVelocity); + _prevPosition = worldPos; _prevRotation = worldRot; _prevVelocity = velocity; @@ -153,6 +149,11 @@ namespace QSB.Syncs.RigidbodySync return; } + if (ReferenceTransform == null) + { + return; + } + UpdateTransform(); base.Update(); @@ -164,7 +165,7 @@ namespace QSB.Syncs.RigidbodySync { _intermediaryTransform.EncodePosition(AttachedObject.transform.position); _intermediaryTransform.EncodeRotation(AttachedObject.transform.rotation); - _velocity = AttachedObject.GetRelativeVelocity(ReferenceTransform.GetAttachedOWRigidbody()); + _velocity = GetRelativeVelocity(); _angularVelocity = AttachedObject.GetRelativeAngularVelocity(ReferenceTransform.GetAttachedOWRigidbody()); return; } @@ -177,12 +178,41 @@ namespace QSB.Syncs.RigidbodySync return; } - AttachedObject.transform.position = targetPos; - AttachedObject.transform.rotation = targetRot; - AttachedObject.SetVelocity(ReferenceTransform.GetAttachedOWRigidbody().GetVelocity() + _velocity); + if (UseInterpolation) + { + AttachedObject.SetPosition(SmartPositionSmoothDamp(AttachedObject.transform.position, targetPos)); + AttachedObject.SetRotation(QuaternionHelper.SmoothDamp(AttachedObject.transform.rotation, targetRot, ref _rotationSmoothVelocity, SmoothTime)); + } + else + { + AttachedObject.SetPosition(targetPos); + AttachedObject.SetRotation(targetRot); + } + + SetVelocity(AttachedObject, ReferenceTransform.GetAttachedOWRigidbody().GetPointVelocity(targetPos) + _velocity); AttachedObject.SetAngularVelocity(ReferenceTransform.GetAttachedOWRigidbody().GetAngularVelocity() + _angularVelocity); } + private void SetVelocity(OWRigidbody rigidbody, Vector3 newVelocity) + { + var isRunningKinematic = rigidbody.RunningKinematicSimulation(); + var currentVelocity = rigidbody.GetValue("_currentVelocity"); + + if (isRunningKinematic) + { + var kinematicRigidbody = rigidbody.GetValue("_kinematicRigidbody"); + kinematicRigidbody.velocity = newVelocity + Locator.GetCenterOfTheUniverse().GetStaticFrameWorldVelocity(); + } + else + { + var normalRigidbody = rigidbody.GetValue("_rigidbody"); + normalRigidbody.velocity = newVelocity + Locator.GetCenterOfTheUniverse().GetStaticFrameWorldVelocity(); + } + + rigidbody.SetValue("_lastVelocity", currentVelocity); + rigidbody.SetValue("_currentVelocity", newVelocity); + } + public void SetReferenceTransform(Transform transform) { if (ReferenceTransform == transform) @@ -193,6 +223,21 @@ namespace QSB.Syncs.RigidbodySync _intermediaryTransform.SetReferenceTransform(transform); } + // TODO : remove .Distance + private Vector3 SmartPositionSmoothDamp(Vector3 currentPosition, Vector3 targetPosition) + { + var distance = Vector3.Distance(currentPosition, targetPosition); + if (distance > _previousDistance + DistanceLeeway) + { + DebugLog.DebugWrite($"Warning - {AttachedObject.name} moved too far!", MessageType.Warning); + _previousDistance = distance; + return targetPosition; + } + _previousDistance = distance; + return Vector3.SmoothDamp(currentPosition, targetPosition, ref _positionSmoothVelocity, SmoothTime); + } + + // TODO : optimize by using sqrMagnitude public override bool HasMoved() { var displacementMagnitude = (_intermediaryTransform.GetPosition() - _prevPosition).magnitude; @@ -201,6 +246,7 @@ namespace QSB.Syncs.RigidbodySync { return true; } + if (Quaternion.Angle(_intermediaryTransform.GetRotation(), _prevRotation) > 1E-03f) { return true; @@ -212,6 +258,7 @@ namespace QSB.Syncs.RigidbodySync { return true; } + if (angularVelocityChangeMagnitude > 1E-03f) { return true; @@ -223,9 +270,16 @@ namespace QSB.Syncs.RigidbodySync public float GetVelocityChangeMagnitude() => (_velocity - _prevVelocity).magnitude; + public Vector3 GetRelativeVelocity() + => ReferenceTransform.GetAttachedOWRigidbody().GetPointVelocity(AttachedObject.transform.position) - AttachedObject.GetVelocity(); + private void OnRenderObject() { - if (!QSBCore.WorldObjectsReady || !QSBCore.DebugMode || !QSBCore.ShowLinesInDebug || !IsReady) + if (!QSBCore.WorldObjectsReady + || !QSBCore.DebugMode + || !QSBCore.ShowLinesInDebug + || !IsReady + || ReferenceTransform == null) { return; } @@ -235,6 +289,8 @@ namespace QSB.Syncs.RigidbodySync var color = HasMoved() ? Color.green : Color.yellow; Popcron.Gizmos.Cube(AttachedObject.transform.position, AttachedObject.transform.rotation, Vector3.one / 2, color); Popcron.Gizmos.Line(AttachedObject.transform.position, ReferenceTransform.position, Color.cyan); + + Popcron.Gizmos.Line(AttachedObject.transform.position, AttachedObject.transform.position + GetRelativeVelocity(), Color.blue); } } } diff --git a/QSB/Syncs/TransformSync/BaseTransformSync.cs b/QSB/Syncs/TransformSync/BaseTransformSync.cs index a072c3b6..6f9edc95 100644 --- a/QSB/Syncs/TransformSync/BaseTransformSync.cs +++ b/QSB/Syncs/TransformSync/BaseTransformSync.cs @@ -16,8 +16,36 @@ namespace QSB.Syncs.TransformSync public abstract class BaseTransformSync : QNetworkTransform, ISync { - public uint AttachedNetId => NetIdentity?.NetId.Value ?? uint.MaxValue; - public uint PlayerId => NetIdentity.RootIdentity?.NetId.Value ?? NetIdentity.NetId.Value; + public uint AttachedNetId + { + get + { + if (NetIdentity == null) + { + DebugLog.ToConsole($"Error - Trying to get AttachedNetId with null NetIdentity! Type:{GetType().Name} GrandType:{GetType().GetType().Name}", MessageType.Error); + return uint.MaxValue; + } + + return NetIdentity.NetId.Value; + } + } + + public uint PlayerId + { + get + { + if (NetIdentity == null) + { + DebugLog.ToConsole($"Error - Trying to get PlayerId with null NetIdentity! Type:{GetType().Name} GrandType:{GetType().GetType().Name}", MessageType.Error); + return uint.MaxValue; + } + + return NetIdentity.RootIdentity != null + ? NetIdentity.RootIdentity.NetId.Value + : AttachedNetId; + } + } + public PlayerInfo Player => QSBPlayerManager.GetPlayer(PlayerId); public Transform ReferenceTransform { get; set; } @@ -53,7 +81,7 @@ namespace QSB.Syncs.TransformSync { if (!HasAuthority && AttachedObject != null) { - Destroy(AttachedObject); + Destroy(AttachedObject.gameObject); } QSBSceneManager.OnSceneLoaded -= OnSceneLoaded; } @@ -69,7 +97,7 @@ namespace QSB.Syncs.TransformSync } if (!HasAuthority && AttachedObject != null) { - Destroy(AttachedObject); + Destroy(AttachedObject.gameObject); } AttachedObject = HasAuthority ? InitLocalTransform() : InitRemoteTransform(); _isInitialized = true; @@ -149,6 +177,11 @@ namespace QSB.Syncs.TransformSync return; } + if (ReferenceTransform == null) + { + return; + } + UpdateTransform(); base.Update(); @@ -196,7 +229,7 @@ namespace QSB.Syncs.TransformSync _intermediaryTransform.SetReferenceTransform(transform); if (AttachedObject == null) { - DebugLog.ToConsole($"Warning - AttachedObject was null for {_logName} when trying to set reference transform to {transform.name}. Waiting until not null...", MessageType.Warning); + DebugLog.ToConsole($"Warning - AttachedObject was null for {_logName} when trying to set reference transform to {transform?.name}. Waiting until not null...", MessageType.Warning); QSBCore.UnityEvents.RunWhen( () => AttachedObject != null, () => ReparentAttachedObject(transform)); @@ -234,12 +267,11 @@ namespace QSB.Syncs.TransformSync private void OnRenderObject() { - if (!QSBCore.WorldObjectsReady || !QSBCore.DebugMode || !QSBCore.ShowLinesInDebug || !IsReady) - { - return; - } - - if (ReferenceTransform == null) + if (!QSBCore.WorldObjectsReady + || !QSBCore.DebugMode + || !QSBCore.ShowLinesInDebug + || !IsReady + || ReferenceTransform == null) { return; } diff --git a/QSB/Syncs/TransformSync/SectoredTransformSync.cs b/QSB/Syncs/TransformSync/SectoredTransformSync.cs index 3aeae708..ac5aa495 100644 --- a/QSB/Syncs/TransformSync/SectoredTransformSync.cs +++ b/QSB/Syncs/TransformSync/SectoredTransformSync.cs @@ -2,7 +2,6 @@ using QSB.SectorSync.WorldObjects; using QSB.WorldSync; using QuantumUNET.Transport; -using System.Collections.Generic; using UnityEngine; namespace QSB.Syncs.TransformSync @@ -16,14 +15,14 @@ namespace QSB.Syncs.TransformSync public override void Start() { SectorSync = gameObject.AddComponent(); - QSBSectorManager.Instance.SectoredSyncs.Add((ISectoredSync)this); + QSBSectorManager.Instance.SectoredTransformSyncs.Add(this); base.Start(); } protected override void OnDestroy() { base.OnDestroy(); - QSBSectorManager.Instance.SectoredSyncs.Remove((ISectoredSync)this); + QSBSectorManager.Instance.SectoredTransformSyncs.Remove(this); if (SectorSync != null) { Destroy(SectorSync); @@ -105,7 +104,7 @@ namespace QSB.Syncs.TransformSync public void SetReferenceSector(QSBSector sector) { ReferenceSector = sector; - SetReferenceTransform(sector.Transform); + SetReferenceTransform(sector?.Transform); } } } diff --git a/QSB/Syncs/TransformSync/UnparentedBaseTransformSync.cs b/QSB/Syncs/TransformSync/UnparentedBaseTransformSync.cs index ff64e0c1..ae91b965 100644 --- a/QSB/Syncs/TransformSync/UnparentedBaseTransformSync.cs +++ b/QSB/Syncs/TransformSync/UnparentedBaseTransformSync.cs @@ -11,8 +11,36 @@ namespace QSB.Syncs.TransformSync { public abstract class UnparentedBaseTransformSync : QNetworkTransform, ISync { - public uint AttachedNetId => NetIdentity?.NetId.Value ?? uint.MaxValue; - public uint PlayerId => NetIdentity.RootIdentity?.NetId.Value ?? NetIdentity.NetId.Value; + public uint AttachedNetId + { + get + { + if (NetIdentity == null) + { + DebugLog.ToConsole($"Error - Trying to get AttachedNetId with null NetIdentity! Type:{GetType().Name} GrandType:{GetType().GetType().Name}", MessageType.Error); + return uint.MaxValue; + } + + return NetIdentity.NetId.Value; + } + } + + public uint PlayerId + { + get + { + if (NetIdentity == null) + { + DebugLog.ToConsole($"Error - Trying to get PlayerId with null NetIdentity! Type:{GetType().Name} GrandType:{GetType().GetType().Name}", MessageType.Error); + return uint.MaxValue; + } + + return NetIdentity.RootIdentity != null + ? NetIdentity.RootIdentity.NetId.Value + : AttachedNetId; + } + } + public PlayerInfo Player => QSBPlayerManager.GetPlayer(PlayerId); public Transform ReferenceTransform { get; set; } @@ -47,7 +75,7 @@ namespace QSB.Syncs.TransformSync { if (!HasAuthority && AttachedObject != null) { - Destroy(AttachedObject); + Destroy(AttachedObject.gameObject); } QSBSceneManager.OnSceneLoaded -= OnSceneLoaded; } @@ -130,6 +158,11 @@ namespace QSB.Syncs.TransformSync return; } + if (ReferenceTransform == null) + { + return; + } + UpdateTransform(); base.Update(); @@ -177,11 +210,13 @@ namespace QSB.Syncs.TransformSync _intermediaryTransform.SetReferenceTransform(transform); } + // TODO : remove .Distance private Vector3 SmartSmoothDamp(Vector3 currentPosition, Vector3 targetPosition) { var distance = Vector3.Distance(currentPosition, targetPosition); if (distance > _previousDistance + DistanceLeeway) { + DebugLog.DebugWrite($"Warning - {AttachedObject.name} moved too far!", MessageType.Warning); _previousDistance = distance; return targetPosition; } @@ -191,7 +226,11 @@ namespace QSB.Syncs.TransformSync private void OnRenderObject() { - if (!QSBCore.WorldObjectsReady || !QSBCore.DebugMode || !QSBCore.ShowLinesInDebug || !IsReady) + if (!QSBCore.WorldObjectsReady + || !QSBCore.DebugMode + || !QSBCore.ShowLinesInDebug + || !IsReady + || ReferenceTransform == null) { return; } diff --git a/QSB/TimeSync/Patches/WakeUpPatches.cs b/QSB/TimeSync/Patches/WakeUpPatches.cs index ba106002..2c4d89a3 100644 --- a/QSB/TimeSync/Patches/WakeUpPatches.cs +++ b/QSB/TimeSync/Patches/WakeUpPatches.cs @@ -7,17 +7,10 @@ namespace QSB.TimeSync.Patches { public override QSBPatchTypes Type => QSBPatchTypes.OnNonServerClientConnect; - public static bool OnStartOfTimeLoopPrefix(ref PlayerCameraEffectController __instance) - { - if (__instance.gameObject.CompareTag("MainCamera") && QSBSceneManager.CurrentScene != OWScene.EyeOfTheUniverse) - { - __instance.Invoke("WakeUp"); - } - return false; - } + public override void DoPatches() + => QSBCore.HarmonyHelper.EmptyMethod("OnStartOfTimeLoop"); - public override void DoPatches() => QSBCore.HarmonyHelper.AddPrefix("OnStartOfTimeLoop", typeof(WakeUpPatches), nameof(OnStartOfTimeLoopPrefix)); - - public override void DoUnpatches() => QSBCore.HarmonyHelper.Unpatch("OnStartOfTimeLoop"); + public override void DoUnpatches() + => QSBCore.HarmonyHelper.Unpatch("OnStartOfTimeLoop"); } } \ No newline at end of file diff --git a/QSB/TimeSync/WakeUpSync.cs b/QSB/TimeSync/WakeUpSync.cs index 2291cd5f..d42672e2 100644 --- a/QSB/TimeSync/WakeUpSync.cs +++ b/QSB/TimeSync/WakeUpSync.cs @@ -1,4 +1,5 @@ using OWML.Common; +using OWML.Utils; using QSB.DeathSync; using QSB.Events; using QSB.TimeSync.Events; @@ -27,6 +28,7 @@ namespace QSB.TimeSync private float _serverTime; private bool _isFirstFastForward = true; private int _serverLoopCount; + private bool _hasWokenUp; public override void OnStartLocalPlayer() => LocalInstance = this; @@ -60,6 +62,7 @@ namespace QSB.TimeSync { RespawnOnDeath.Instance.Init(); } + _hasWokenUp = true; } public void OnDestroy() @@ -71,8 +74,13 @@ namespace QSB.TimeSync private void OnSceneLoaded(OWScene scene, bool isInUniverse) { DebugLog.DebugWrite($"ONSCENELOADED"); + _hasWokenUp = false; if (isInUniverse) { + if (scene == OWScene.EyeOfTheUniverse) + { + _hasWokenUp = true; + } Init(); } else @@ -158,6 +166,7 @@ namespace QSB.TimeSync { Locator.GetActiveCamera().enabled = false; } + OWInput.ChangeInputMode(InputMode.None); _state = State.FastForwarding; OWTime.SetMaxDeltaTime(0.033333335f); OWTime.SetFixedTimestep(0.033333335f); @@ -173,6 +182,7 @@ namespace QSB.TimeSync } DebugLog.DebugWrite($"START PAUSING (Target:{_serverTime} Current:{Time.timeSinceLevelLoad})", MessageType.Info); Locator.GetActiveCamera().enabled = false; + OWInput.ChangeInputMode(InputMode.None); OWTime.SetTimeScale(0f); _state = State.Pausing; SpinnerUI.Show(); @@ -194,8 +204,22 @@ namespace QSB.TimeSync TimeSyncUI.Stop(); QSBEventManager.FireEvent(EventNames.QSBPlayerStatesRequest); RespawnOnDeath.Instance.Init(); + + if (OWInput.GetInputMode() == InputMode.None) + { + OWInput.RestorePreviousInputs(); + } + + if (!_hasWokenUp) + { + WakeUp(); + OWInput.ChangeInputMode(InputMode.Character); + } } + private void WakeUp() + => Locator.GetPlayerCamera().GetComponent().Invoke("WakeUp"); + public void Update() { if (IsServer)