diff --git a/QSB/Events/QSBEvent.cs b/QSB/Events/QSBEvent.cs index 5194bf7c..ad4f0243 100644 --- a/QSB/Events/QSBEvent.cs +++ b/QSB/Events/QSBEvent.cs @@ -34,19 +34,26 @@ namespace QSB.Events public abstract bool RequireWorldObjectsReady { get; } - public void SendEvent(T message) - { - message.FromId = QSBPlayerManager.LocalPlayerId; - QSBCore.UnityEvents.RunWhen( - () => PlayerTransformSync.LocalInstance != null, - () => _eventHandler.SendToServer(message)); - } + /// used to force set ForId for every sent event + protected static uint ForIdOverride = uint.MaxValue; + + public void SendEvent(T message) => QSBCore.UnityEvents.RunWhen( + () => PlayerTransformSync.LocalInstance != null, + () => + { + message.FromId = LocalPlayerId; + if (ForIdOverride != uint.MaxValue) + { + message.ForId = ForIdOverride; + } + _eventHandler.SendToServer(message); + }); /// - /// Checks whether the message should be processed by the executing client/server. + /// Checks whether the message should be processed by the executing client. /// /// True if the message should be processed. - public virtual bool CheckMessage(bool isServer, T message) + public virtual bool CheckMessage(T message) => !RequireWorldObjectsReady || WorldObjectManager.AllObjectsReady; private void OnReceive(bool isServer, T message) @@ -59,18 +66,24 @@ namespace QSB.Events * hub for all events. */ - if (!CheckMessage(isServer, message)) - { - return; - } - if (isServer) { - _eventHandler.SendToAll(message); + if (message.OnlySendToHost) + { + _eventHandler.SendToHost(message); + } + else if (message.ForId != uint.MaxValue) + { + _eventHandler.SendTo(message.ForId, message); + } + else + { + _eventHandler.SendToAll(message); + } return; } - if (message.OnlySendToHost && !QSBCore.IsHost) + if (!CheckMessage(message)) { return; } @@ -87,8 +100,8 @@ namespace QSB.Events if (!player.IsReady && player.PlayerId != LocalPlayerId - && (player.State is ClientState.AliveInSolarSystem or ClientState.AliveInEye or ClientState.DeadInSolarSystem) - && (message is not PlayerInformationEvent or PlayerReadyEvent)) + && player.State is ClientState.AliveInSolarSystem or ClientState.AliveInEye or ClientState.DeadInSolarSystem + && this is not PlayerInformationEvent or PlayerReadyEvent) { DebugLog.ToConsole($"Warning - Got message from player {message.FromId}, but they were not ready. Asking for state resync, just in case.", MessageType.Warning); QSBEventManager.FireEvent(EventNames.QSBRequestStateResync); @@ -97,14 +110,14 @@ namespace QSB.Events try { - if (message.FromId == QSBPlayerManager.LocalPlayerId || - QSBPlayerManager.IsBelongingToLocalPlayer(message.FromId)) + if (QSBPlayerManager.IsBelongingToLocalPlayer(message.FromId)) { OnReceiveLocal(QSBCore.IsHost, message); - return; } - - OnReceiveRemote(QSBCore.IsHost, message); + else + { + OnReceiveRemote(QSBCore.IsHost, message); + } } catch (Exception ex) { diff --git a/QSB/Messaging/MessageHandler.cs b/QSB/Messaging/MessageHandler.cs index a66bf53b..545f6607 100644 --- a/QSB/Messaging/MessageHandler.cs +++ b/QSB/Messaging/MessageHandler.cs @@ -1,5 +1,4 @@ -using QSB.Events; -using QSB.Utility; +using QSB.Utility; using QuantumUNET; using QuantumUNET.Components; using QuantumUNET.Messages; @@ -58,6 +57,32 @@ namespace QSB.Messaging QNetworkServer.SendToAll(_eventType, message); } + public void SendToHost(T message) + { + if (!QSBNetworkManager.Instance.IsReady) + { + return; + } + + QNetworkServer.SendToClient(0, _eventType, message); + } + + public void SendTo(uint id, T message) + { + if (!QSBNetworkManager.Instance.IsReady) + { + return; + } + + var conn = QNetworkServer.connections.FirstOrDefault(x => x.GetPlayerId() == id); + if (conn == null) + { + DebugLog.ToConsole($"SendTo unknown player! id: {id}, message: {message.GetType().Name}", OWML.Common.MessageType.Error); + return; + } + QNetworkServer.SendToClient(conn.connectionId, _eventType, message); + } + public void SendToServer(T message) { if (!QSBNetworkManager.Instance.IsReady) diff --git a/QSB/Messaging/PlayerMessage.cs b/QSB/Messaging/PlayerMessage.cs index dc22a948..b14eb553 100644 --- a/QSB/Messaging/PlayerMessage.cs +++ b/QSB/Messaging/PlayerMessage.cs @@ -16,16 +16,27 @@ namespace QSB.Messaging public uint AboutId { get; set; } /// - /// If true, only send this message to the host of the current session + /// If true, only send this message to the host of the current session /// (OnReceiveLocal/Remote is not called on any other client) /// public bool OnlySendToHost { get; set; } + /// + /// The Player ID that this message is for. + /// By default, this is uint.MaxValue, + /// which means this is ignored and the message is sent to all clients + /// + public uint ForId { get; set; } = uint.MaxValue; + public override void Deserialize(QNetworkReader reader) { FromId = reader.ReadUInt32(); AboutId = reader.ReadUInt32(); OnlySendToHost = reader.ReadBoolean(); + if (!OnlySendToHost) + { + reader.ReadUInt32(); + } } public override void Serialize(QNetworkWriter writer) @@ -33,6 +44,10 @@ namespace QSB.Messaging writer.Write(FromId); writer.Write(AboutId); writer.Write(OnlySendToHost); + if (!OnlySendToHost) + { + writer.Write(ForId); + } } } -} \ No newline at end of file +} diff --git a/QSB/Player/Events/RequestStateResyncEvent.cs b/QSB/Player/Events/RequestStateResyncEvent.cs index ab1f32f1..26750419 100644 --- a/QSB/Player/Events/RequestStateResyncEvent.cs +++ b/QSB/Player/Events/RequestStateResyncEvent.cs @@ -30,20 +30,31 @@ namespace QSB.Player.Events public override void OnReceiveRemote(bool isHost, PlayerMessage message) { - // if host, send worldobject and server states - - if (isHost) + // send response only to the requesting client + ForIdOverride = message.FromId; + try { - QSBEventManager.FireEvent(EventNames.QSBServerState, ServerStateManager.Instance.GetServerState()); - QSBEventManager.FireEvent(EventNames.QSBPlayerInformation); + // if host, send worldobject and server states + if (isHost) + { + QSBEventManager.FireEvent(EventNames.QSBServerState, ServerStateManager.Instance.GetServerState()); + QSBEventManager.FireEvent(EventNames.QSBPlayerInformation); - SendWorldObjectInfo(); - - return; + if (WorldObjectManager.AllObjectsReady) + { + SendWorldObjectInfo(); + } + } + // if client, send player and client states + else + { + QSBEventManager.FireEvent(EventNames.QSBPlayerInformation); + } + } + finally + { + ForIdOverride = uint.MaxValue; } - - // if client, send player and client states - QSBEventManager.FireEvent(EventNames.QSBPlayerInformation); } private void SendWorldObjectInfo() diff --git a/QSB/QuantumSync/Events/QuantumAuthorityEvent.cs b/QSB/QuantumSync/Events/QuantumAuthorityEvent.cs index c1749fb2..a52e02d5 100644 --- a/QSB/QuantumSync/Events/QuantumAuthorityEvent.cs +++ b/QSB/QuantumSync/Events/QuantumAuthorityEvent.cs @@ -20,9 +20,9 @@ namespace QSB.QuantumSync.Events AuthorityOwner = authorityOwner }; - public override bool CheckMessage(bool isServer, QuantumAuthorityMessage message) + public override bool CheckMessage(QuantumAuthorityMessage message) { - if (!base.CheckMessage(isServer, message)) + if (!base.CheckMessage(message)) { return false; }