From 402c745fc3a52e5e27e07c7d8a23d4c43b84b5c1 Mon Sep 17 00:00:00 2001 From: Regalis Date: Sat, 7 Jan 2017 19:22:48 +0200 Subject: [PATCH] Reimplemented chat range & radio messages. Each client now has their own chatMsgQueue, so all chat messages don't have to be sent to all clients. --- .../Items/Components/Signal/WifiComponent.cs | 28 ++- Subsurface/Source/Networking/ChatMessage.cs | 14 +- Subsurface/Source/Networking/Client.cs | 2 +- Subsurface/Source/Networking/GameClient.cs | 10 +- Subsurface/Source/Networking/GameServer.cs | 173 ++++++++++++++---- Subsurface/Source/Networking/NetworkMember.cs | 32 +--- 6 files changed, 182 insertions(+), 77 deletions(-) diff --git a/Subsurface/Source/Items/Components/Signal/WifiComponent.cs b/Subsurface/Source/Items/Components/Signal/WifiComponent.cs index 7572e53e4..595d8d24a 100644 --- a/Subsurface/Source/Items/Components/Signal/WifiComponent.cs +++ b/Subsurface/Source/Items/Components/Signal/WifiComponent.cs @@ -45,9 +45,14 @@ namespace Barotrauma.Items.Components list.Add(this); } + public bool CanTransmit() + { + return HasRequiredContainedItems(true); + } + public void Transmit(string signal) { - if (!HasRequiredContainedItems(true)) return; + if (!CanTransmit()) return; var receivers = GetReceiversInRange(); foreach (WifiComponent w in receivers) @@ -60,14 +65,22 @@ namespace Barotrauma.Items.Components private List GetReceiversInRange() { - return list.FindAll(w => - w != this && w.channel == channel && - Vector2.Distance(item.WorldPosition, w.item.WorldPosition) <= Range); + return list.FindAll(w => w != this && w.CanReceive(this)); + } + + public bool CanReceive(WifiComponent sender) + { + if (!HasRequiredContainedItems(false)) return false; + + if (sender == null || sender.channel != channel) return false; + + return Vector2.Distance(item.WorldPosition, sender.item.WorldPosition) <= sender.Range; } public override void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item sender, float power=0.0f) { - if (!HasRequiredContainedItems(false)) return; + var senderComponent = sender.GetComponent(); + if (senderComponent != null && !CanReceive(senderComponent)) return; if (LinkToChat) { @@ -76,7 +89,10 @@ namespace Barotrauma.Items.Components item.ParentInventory.Owner == Character.Controlled && GameMain.NetworkMember != null) { - signal = ChatMessage.ApplyDistanceEffect(item, sender, signal, range); + if (senderComponent != null) + { + signal = ChatMessage.ApplyDistanceEffect(item, sender, signal, senderComponent.range); + } GameMain.NetworkMember.AddChatMessage(signal, ChatMessageType.Radio); } diff --git a/Subsurface/Source/Networking/ChatMessage.cs b/Subsurface/Source/Networking/ChatMessage.cs index e69dfd6e6..1a8c1d39f 100644 --- a/Subsurface/Source/Networking/ChatMessage.cs +++ b/Subsurface/Source/Networking/ChatMessage.cs @@ -40,10 +40,11 @@ namespace Barotrauma.Networking } public static UInt32 LastID = 0; - public UInt32 netStateID = 0; + public UInt32 NetStateID { - get { return netStateID; } + get; + set; } private ChatMessage(string senderName, string text, ChatMessageType type, Character sender) @@ -56,12 +57,6 @@ namespace Barotrauma.Networking SenderName = senderName; TextWithSender = string.IsNullOrWhiteSpace(senderName) ? text : senderName + ": " + text; - - if (GameMain.Server != null) - { - LastID++; - netStateID = LastID; - } } public static ChatMessage Create(string senderName, string text, ChatMessageType type, Character sender) @@ -140,7 +135,8 @@ namespace Barotrauma.Networking if (c.lastSentChatMsgID < ID) { //this chat message is new to the server - GameMain.Server.AddChatMessage(txt, ChatMessageType.Default, c.name); + GameMain.Server.SendChatMessage(txt, null, c); + //GameMain.Server.AddChatMessage(txt, ChatMessageType.Default, c.name); c.lastSentChatMsgID = ID; } } diff --git a/Subsurface/Source/Networking/Client.cs b/Subsurface/Source/Networking/Client.cs index e8b94e8af..41d9039c0 100644 --- a/Subsurface/Source/Networking/Client.cs +++ b/Subsurface/Source/Networking/Client.cs @@ -41,7 +41,7 @@ namespace Barotrauma.Networking public UInt32 lastRecvEntitySpawnID = 0; - public List ChatMessages = new List(); + public List chatMsgQueue = new List(); public float ChatSpamSpeed; public float ChatSpamTimer; public int ChatSpamCount; diff --git a/Subsurface/Source/Networking/GameClient.cs b/Subsurface/Source/Networking/GameClient.cs index 9426bdccd..d786d62ac 100644 --- a/Subsurface/Source/Networking/GameClient.cs +++ b/Subsurface/Source/Networking/GameClient.cs @@ -847,18 +847,18 @@ namespace Barotrauma.Networking client.SendMessage(outmsg, NetDeliveryMethod.Unreliable); } - public override void SendChatMessage(string message, ChatMessageType? type = null) + public void SendChatMessage(string message) { if (client.ServerConnection == null) return; - type = ChatMessageType.Default; - ChatMessage chatMessage = ChatMessage.Create( gameStarted && myCharacter != null ? myCharacter.Name : name, - message, (ChatMessageType)type, gameStarted ? myCharacter : null); + message, + ChatMessageType.Default, + gameStarted ? myCharacter : null); lastQueueChatMsgID++; - chatMessage.netStateID = lastQueueChatMsgID; + chatMessage.NetStateID = lastQueueChatMsgID; chatMsgQueue.Add(chatMessage); } diff --git a/Subsurface/Source/Networking/GameServer.cs b/Subsurface/Source/Networking/GameServer.cs index 5ccaaf5cb..f8bb3c890 100644 --- a/Subsurface/Source/Networking/GameServer.cs +++ b/Subsurface/Source/Networking/GameServer.cs @@ -542,7 +542,7 @@ namespace Barotrauma.Networking // } //} - foreach (Character c in Character.CharacterList) + /*foreach (Character c in Character.CharacterList) { if (c.IsDead) continue; @@ -554,7 +554,7 @@ namespace Barotrauma.Networking //if (FarseerPhysics.ConvertUnits.ToSimUnits(diff.Length()) > NetConfig.CharacterIgnoreDistance) continue; } - } + }*/ sparseUpdateTimer = DateTime.Now + sparseUpdateInterval; } @@ -658,17 +658,11 @@ namespace Barotrauma.Networking outmsg.Write(c.lastSentChatMsgID); //send this to client so they know which chat messages weren't received by the server outmsg.Write(c.lastSentEntityEventID); - foreach (GUIComponent gc in GameMain.NetLobbyScreen.ChatBox.children) + c.chatMsgQueue.RemoveAll(cMsg => cMsg.NetStateID <= c.lastRecvChatMsgID); + foreach (ChatMessage cMsg in c.chatMsgQueue) { - if (gc is GUITextBlock && gc.UserData is ChatMessage) - { - ChatMessage cMsg = (ChatMessage)gc.UserData; - if (cMsg.NetStateID > c.lastRecvChatMsgID) - { - cMsg.ServerWrite(outmsg, c); - } - } - } + cMsg.ServerWrite(outmsg, c); + } if (Item.Spawner.NetStateID > c.lastRecvEntitySpawnID) { @@ -681,7 +675,7 @@ namespace Barotrauma.Networking { if (character is AICharacter) { - //TODO: don't send if the ai character is far from the client + //TODO: don't send if the ai character is far from the client //(some sort of distance-based culling might be a good idea for player-controlled characters as well) outmsg.Write((byte)ServerNetObject.ENTITY_POSITION); character.ServerWrite(outmsg, c); @@ -766,20 +760,12 @@ namespace Barotrauma.Networking outmsg.Write(c.lastSentChatMsgID); //send this to client so they know which chat messages weren't received by the server - foreach (GUIComponent gc in GameMain.NetLobbyScreen.ChatBox.children) + c.chatMsgQueue.RemoveAll(cMsg => cMsg.NetStateID <= c.lastRecvChatMsgID); + foreach (ChatMessage cMsg in c.chatMsgQueue) { - if (gc is GUITextBlock) - { - if (gc.UserData is ChatMessage) - { - ChatMessage cMsg = (ChatMessage)gc.UserData; - if (cMsg.NetStateID > c.lastRecvChatMsgID) - { - cMsg.ServerWrite(outmsg,c); - } - } - } - } + cMsg.ServerWrite(outmsg, c); + } + outmsg.Write((byte)ServerNetObject.END_OF_MESSAGE); server.SendMessage(outmsg, c.Connection, NetDeliveryMethod.Unreliable); } @@ -1214,16 +1200,139 @@ namespace Barotrauma.Networking } } - public override void SendChatMessage(string message, ChatMessageType? type = null) + /// + /// Add the message to the chatbox and pass it to all clients who can receive it + /// + public void SendChatMessage(string message, ChatMessageType? type = null, Client senderClient = null) { - type = ChatMessageType.Default; + Character senderCharacter = null; + string senderName = ""; + + if (type==null) + { + string tempStr; + string command = ChatMessage.GetChatMessageCommand(message, out tempStr); + switch (command) + { + case "r": + case "radio": + type = ChatMessageType.Radio; + break; + case "d": + case "dead": + type = ChatMessageType.Dead; + break; + default: + type = ChatMessageType.Default; + break; + } + } - ChatMessage chatMessage = ChatMessage.Create( - gameStarted && myCharacter != null ? myCharacter.Name : name, - message, (ChatMessageType)type, gameStarted ? myCharacter : null); + if (gameStarted) + { + //msg sent by the server + if (senderClient == null) + { + senderCharacter = myCharacter; + senderName = myCharacter == null ? name : myCharacter.Name; + } + //msg sent by a client + else + { + senderCharacter = senderClient.Character; + senderName = senderCharacter == null ? senderClient.name : senderCharacter.Name; + //sender doesn't have an alive character -> only ChatMessageType.Dead allowed + if (senderCharacter == null || senderCharacter.IsDead) + { + type = ChatMessageType.Dead; + } + } + } + else + { + //game not started -> clients can only send normal chatmessages + if (senderClient != null) + { + type = ChatMessageType.Default; + } + } - AddChatMessage(chatMessage); + //check if the client is allowed to send the message + WifiComponent senderRadio = null; + switch (type) + { + case ChatMessageType.Radio: + if (senderCharacter == null) return; + + //return if senderCharacter doesn't have a working radio + var radio = senderCharacter.Inventory.Items.First(i => i != null && i.GetComponent() != null); + if (radio == null) return; + + senderRadio = radio.GetComponent(); + if (!senderRadio.CanTransmit()) return; + break; + case ChatMessageType.Dead: + //character still alive -> not allowed + if (senderClient != null && senderCharacter != null && !senderCharacter.IsDead) + { + return; + } + break; + } + + //check which clients can receive the message and apply distance effects + foreach (Client client in ConnectedClients) + { + string modifiedMessage = message; + + switch (type) + { + case ChatMessageType.Default: + if (senderCharacter != null && + client.Character != null && !client.Character.IsDead) + { + modifiedMessage = ChatMessage.ApplyDistanceEffect(client.Character, senderCharacter, message, ChatMessage.SpeakRange); + + //too far to hear the msg -> don't send + if (string.IsNullOrWhiteSpace(modifiedMessage)) continue; + } + break; + case ChatMessageType.Radio: + if (client.Character != null && !client.Character.IsDead) + { + var radio = client.Character.Inventory.Items.First(i => i != null && i.GetComponent() != null); + //client doesn't have a radio -> don't send + if (radio == null) return; + + var radioComponent = radio.GetComponent(); + if (!radioComponent.CanReceive(senderRadio)) return; + + modifiedMessage = ChatMessage.ApplyDistanceEffect(radio, senderRadio.Item, message, senderRadio.Range); + + //too far to hear the msg -> don't send + if (string.IsNullOrWhiteSpace(modifiedMessage)) continue; + } + break; + case ChatMessageType.Dead: + if (client.Character != null && !client.Character.IsDead) return; + break; + } + + var chatMsg = ChatMessage.Create( + senderName, + modifiedMessage, + (ChatMessageType)type, + senderCharacter); + + chatMsg.NetStateID = client.chatMsgQueue.Count > 0 ? + client.chatMsgQueue.Last().NetStateID + 1 : + client.lastRecvChatMsgID+1; + + client.chatMsgQueue.Add(chatMsg); + } + + AddChatMessage(message, (ChatMessageType)type, senderName); } public override void Draw(Microsoft.Xna.Framework.Graphics.SpriteBatch spriteBatch) diff --git a/Subsurface/Source/Networking/NetworkMember.cs b/Subsurface/Source/Networking/NetworkMember.cs index c27335465..7131a5df2 100644 --- a/Subsurface/Source/Networking/NetworkMember.cs +++ b/Subsurface/Source/Networking/NetworkMember.cs @@ -195,7 +195,14 @@ namespace Barotrauma.Networking if (string.IsNullOrWhiteSpace(message)) return false; - SendChatMessage(message); + if (this == GameMain.Server) + { + GameMain.Server.SendChatMessage(message, null, null); + } + else if (this == GameMain.Client) + { + GameMain.Client.SendChatMessage(message); + } if (textBox == chatMsgBox) textBox.Deselect(); @@ -209,33 +216,12 @@ namespace Barotrauma.Networking public void AddChatMessage(ChatMessage message) { - - if (message.Type == ChatMessageType.Radio && - Character.Controlled != null && - message.Sender != null && message.Sender != myCharacter) - { - var radio = message.Sender.Inventory.Items.First(i => i != null && i.GetComponent() != null); - if (radio == null) return; - - message.Sender.ShowSpeechBubble(2.0f, ChatMessage.MessageColor[(int)ChatMessageType.Radio]); - - var radioComponent = radio.GetComponent(); - radioComponent.Transmit(message.TextWithSender); - return; - } - GameServer.Log(message.TextWithSender, message.Color); string displayedText = message.Text; if (message.Sender != null) { - if (message.Type == ChatMessageType.Default && Character.Controlled != null) - { - displayedText = message.ApplyDistanceEffect(Character.Controlled); - if (string.IsNullOrWhiteSpace(displayedText)) return; - } - message.Sender.ShowSpeechBubble(2.0f, ChatMessage.MessageColor[(int)ChatMessageType.Default]); } @@ -279,8 +265,6 @@ namespace Barotrauma.Networking GUI.PlayUISound(soundType); } - public virtual void SendChatMessage(string message, ChatMessageType? type = null) { } - public virtual void KickPlayer(string kickedName, bool ban, bool range = false) { } public virtual void AddToGUIUpdateList()