diff --git a/QSB/Menus/MenuManager.cs b/QSB/Menus/MenuManager.cs index 8b441ff9..10876c95 100644 --- a/QSB/Menus/MenuManager.cs +++ b/QSB/Menus/MenuManager.cs @@ -2,6 +2,7 @@ using Mirror; using QSB.Messaging; using QSB.Player; +using QSB.Player.Messages; using QSB.Player.TransformSync; using QSB.SaveSync.Messages; using QSB.Utility; @@ -301,6 +302,11 @@ namespace QSB.Menus { _intentionalDisconnect = true; + if (!QSBCore.IsHost) + { + new JoinLeaveSingularityMessage(false).Send(); + } + QSBNetworkManager.singleton.StopHost(); SetButtonActive(DisconnectButton.gameObject, false); @@ -373,7 +379,7 @@ namespace QSB.Menus QSBNetworkManager.singleton.StartClient(); } - private void OnConnected() + private static void OnConnected() { if (QSBCore.IsHost || !QSBCore.IsInMultiplayer) { diff --git a/QSB/Player/JoinLeaveSingularity.cs b/QSB/Player/JoinLeaveSingularity.cs new file mode 100644 index 00000000..cea1caa5 --- /dev/null +++ b/QSB/Player/JoinLeaveSingularity.cs @@ -0,0 +1,80 @@ +using QSB.Utility; +using QSB.WorldSync; +using System.Linq; +using UnityEngine; + +namespace QSB.Player +{ + public static class JoinLeaveSingularity + { + public static void Create(PlayerInfo player, bool joining) + { + DebugLog.DebugWrite($"{player.TransformSync} join/leave singularity: (joining = {joining})"); + + var go = new GameObject(nameof(JoinLeaveSingularity)); + + var playerGo = player.Body; + playerGo.SetActive(false); + go.transform.parent = playerGo.transform.parent; + go.transform.localPosition = playerGo.transform.localPosition; + go.transform.localRotation = playerGo.transform.localRotation; + go.transform.localScale = playerGo.transform.localScale; + + var fakePlayerGo = playerGo.InstantiateInactive(); + fakePlayerGo.transform.parent = go.transform; + fakePlayerGo.transform.localPosition = Vector3.zero; + fakePlayerGo.transform.localRotation = Quaternion.identity; + fakePlayerGo.transform.localScale = Vector3.one; + + foreach (var component in fakePlayerGo.GetComponents()) + { + if (component is not (Transform or Renderer)) + { + Object.Destroy(component); + } + } + + fakePlayerGo.SetActive(true); + + var referenceEffect = joining ? + QSBWorldSync.GetUnityObjects() + .Select(x => x._probeRetrievalEffect) + .First(x => x) : + QSBWorldSync.GetUnityObjects() + .Select(x => x._warpEffect) + .First(x => x); + var effectGo = referenceEffect.gameObject.InstantiateInactive(); + effectGo.transform.parent = go.transform; + effectGo.transform.localPosition = Vector3.zero; + effectGo.transform.localRotation = Quaternion.identity; + effectGo.transform.localScale = Vector3.one; + + var effect = effectGo.GetComponent(); + effect._warpedObjectGeometry = fakePlayerGo; + effectGo.SetActive(true); + + effect.OnWarpComplete += () => + { + DebugLog.DebugWrite($"{player.TransformSync} warp complete"); + + Object.Destroy(go); + + if (playerGo) + { + playerGo.SetActive(true); + } + }; + const float length = 3; + if (joining) + { + DebugLog.DebugWrite($"{player.TransformSync} warp in (white hole)"); + effect.WarpObjectIn(length); + } + else + { + DebugLog.DebugWrite($"{player.TransformSync} warp out (black hole)"); + effect.WarpObjectOut(length); + } + } + } +} diff --git a/QSB/Player/Messages/JoinLeaveSingularityMessage.cs b/QSB/Player/Messages/JoinLeaveSingularityMessage.cs new file mode 100644 index 00000000..79348c28 --- /dev/null +++ b/QSB/Player/Messages/JoinLeaveSingularityMessage.cs @@ -0,0 +1,18 @@ +using QSB.Messaging; + +namespace QSB.Player.Messages +{ + /// + /// sent by non-hosts only + /// + public class JoinLeaveSingularityMessage : QSBMessage + { + public JoinLeaveSingularityMessage(bool joining) => Value = joining; + + public override void OnReceiveRemote() + { + var player = QSBPlayerManager.GetPlayer(From); + JoinLeaveSingularity.Create(player, Value); + } + } +} diff --git a/QSB/Player/TransformSync/PlayerTransformSync.cs b/QSB/Player/TransformSync/PlayerTransformSync.cs index 7c0b01f1..94c5d3a8 100644 --- a/QSB/Player/TransformSync/PlayerTransformSync.cs +++ b/QSB/Player/TransformSync/PlayerTransformSync.cs @@ -46,7 +46,16 @@ namespace QSB.Player.TransformSync DebugLog.DebugWrite($"Create Player : id<{Player.PlayerId}>", MessageType.Info); } - public override void OnStartLocalPlayer() => LocalInstance = this; + public override void OnStartLocalPlayer() + { + LocalInstance = this; + + if (!QSBCore.IsHost) + { + Delay.RunWhen(() => IsValid && ReferenceTransform, + () => new JoinLeaveSingularityMessage(true).Send()); + } + } public override void OnStopClient() { @@ -89,6 +98,10 @@ namespace QSB.Player.TransformSync protected override void GetFromAttached() { base.GetFromAttached(); + if (!ReferenceTransform) + { + return; + } GetFromChild(_visibleStickPivot, _networkStickPivot); GetFromChild(_visibleStickTip, _networkStickTip); @@ -99,6 +112,10 @@ namespace QSB.Player.TransformSync protected override void ApplyToAttached() { base.ApplyToAttached(); + if (!ReferenceTransform) + { + return; + } ApplyToChild(_visibleStickPivot, _networkStickPivot, ref _pivotPositionVelocity, ref _pivotRotationVelocity); ApplyToChild(_visibleStickTip, _networkStickTip, ref _tipPositionVelocity, ref _tipRotationVelocity); diff --git a/QSB/Utility/Extensions.cs b/QSB/Utility/Extensions.cs index 6d092da9..0fb5c309 100644 --- a/QSB/Utility/Extensions.cs +++ b/QSB/Utility/Extensions.cs @@ -19,14 +19,16 @@ namespace QSB.Utility public static GameObject InstantiateInactive(this GameObject original) { - original.SetActive(false); - var copy = Object.Instantiate(original); - original.SetActive(true); - return copy; - } + if (original.activeSelf) + { + original.SetActive(false); + var copy = Object.Instantiate(original); + original.SetActive(true); + return copy; + } - public static Transform InstantiateInactive(this Transform original) => - original.gameObject.InstantiateInactive().transform; + return Object.Instantiate(original); + } #endregion