From 911846acff3c1fa235d9ad192b214edd600acf0a Mon Sep 17 00:00:00 2001 From: Regalis Date: Wed, 20 Jul 2016 17:20:27 +0300 Subject: [PATCH] - submarines send position updates more frequently when they're moving faster - small AICharacter syncing optimizations - respawning can be disabled in server setting - netstats show the total amount of bytes sent for each networkevent type --- Subsurface/Source/Characters/AICharacter.cs | 38 ++++++++++++------ Subsurface/Source/Map/Submarine.cs | 18 ++++++++- Subsurface/Source/Map/TransitionCinematic.cs | 4 +- Subsurface/Source/Networking/GameClient.cs | 39 ++++--------------- Subsurface/Source/Networking/GameServer.cs | 30 +++++++------- .../Source/Networking/GameServerSettings.cs | 25 +++++++++++- Subsurface/Source/Networking/NetStats.cs | 13 ++++++- Subsurface/Source/Networking/NetworkMember.cs | 23 +++++++++++ 8 files changed, 127 insertions(+), 63 deletions(-) diff --git a/Subsurface/Source/Characters/AICharacter.cs b/Subsurface/Source/Characters/AICharacter.cs index 40aa1f941..b32f053d5 100644 --- a/Subsurface/Source/Characters/AICharacter.cs +++ b/Subsurface/Source/Characters/AICharacter.cs @@ -100,21 +100,29 @@ namespace Barotrauma //message.Write(AnimController.RefLimb.Rotation); - message.WriteRangedSingle(MathHelper.Clamp(AnimController.StunTimer, 0.0f, 60.0f), 0.0f, 60.0f, 8); message.Write((byte)((health / maxHealth) * 255.0f)); - Bleeding = MathHelper.Clamp(Bleeding, 0.0f, 5.0f); - message.WriteRangedSingle(Bleeding, 0.0f, 5.0f, 8); + message.Write(AnimController.StunTimer > 0.0f); + if (AnimController.StunTimer > 0.0f) + { + message.WriteRangedSingle(MathHelper.Clamp(AnimController.StunTimer, 0.0f, 60.0f), 0.0f, 60.0f, 8); + } + + if (DoesBleed) + { + Bleeding = MathHelper.Clamp(Bleeding, 0.0f, 5.0f); + message.WriteRangedSingle(Bleeding, 0.0f, 5.0f, 8); + } aiController.FillNetworkData(message); return true; case NetworkEventType.EntityUpdate: message.Write(AnimController.Dir > 0.0f); - message.WriteRangedSingle(MathHelper.Clamp(AnimController.TargetMovement.X, -1.0f, 1.0f), -1.0f, 1.0f, 8); - message.WriteRangedSingle(MathHelper.Clamp(AnimController.TargetMovement.Y, -1.0f, 1.0f), -1.0f, 1.0f, 8); + message.WriteRangedSingle(MathHelper.Clamp(AnimController.TargetMovement.X, -1.0f, 1.0f), -1.0f, 1.0f, 4); + message.WriteRangedSingle(MathHelper.Clamp(AnimController.TargetMovement.Y, -1.0f, 1.0f), -1.0f, 1.0f, 4); - message.Write(Submarine != null); + if (AnimController.CanEnterSubmarine) message.Write(Submarine != null); message.Write(AnimController.RefLimb.SimPosition.X); message.Write(AnimController.RefLimb.SimPosition.Y); @@ -124,7 +132,7 @@ namespace Barotrauma #if DEBUG DebugConsole.ThrowError("AICharacter network event had a wrong type ("+type+")"); #endif - return false; + return false; } } @@ -168,11 +176,17 @@ namespace Barotrauma try { - newStunTimer = message.ReadRangedSingle(0.0f, 60.0f, 8); newHealth = (message.ReadByte() / 255.0f) * maxHealth; + if (message.ReadBoolean()) + { + newStunTimer = message.ReadRangedSingle(0.0f, 60.0f, 8); + } - newBleeding = message.ReadRangedSingle(0.0f, 5.0f, 8); + if (DoesBleed) + { + newBleeding = message.ReadRangedSingle(0.0f, 5.0f, 8); + } } catch (Exception e) { @@ -199,10 +213,10 @@ namespace Barotrauma try { targetDir = message.ReadBoolean(); - targetMovement.X = message.ReadRangedSingle(-1.0f, 1.0f, 8); - targetMovement.Y = message.ReadRangedSingle(-1.0f, 1.0f, 8); + targetMovement.X = message.ReadRangedSingle(-1.0f, 1.0f, 4); + targetMovement.Y = message.ReadRangedSingle(-1.0f, 1.0f, 4); - inSub = message.ReadBoolean(); + if (AnimController.CanEnterSubmarine) inSub = message.ReadBoolean(); pos.X = message.ReadFloat(); pos.Y = message.ReadFloat(); diff --git a/Subsurface/Source/Map/Submarine.cs b/Subsurface/Source/Map/Submarine.cs index a3988789c..1fbcc7c87 100644 --- a/Subsurface/Source/Map/Submarine.cs +++ b/Subsurface/Source/Map/Submarine.cs @@ -58,7 +58,7 @@ namespace Barotrauma private Vector2 prevPosition; - private float lastNetworkUpdate; + private float lastNetworkUpdate, networkUpdateTimer; //properties ---------------------------------------------------- @@ -425,7 +425,21 @@ namespace Barotrauma { if (Level.Loaded == null) return; - if (subBody!=null) subBody.Update(deltaTime); + if (subBody == null) return; + + subBody.Update(deltaTime); + + if (this != MainSub && MainSub.DockedTo.Contains(this)) return; + + //send updates more frequently if moving fast + networkUpdateTimer -= MathHelper.Clamp(Velocity.Length(), 0.1f, 5.0f) * deltaTime; + + if (networkUpdateTimer < 0.0f) + { + new Networking.NetworkEvent(ID, false); + networkUpdateTimer = 1.0f; + } + } public void ApplyForce(Vector2 force) diff --git a/Subsurface/Source/Map/TransitionCinematic.cs b/Subsurface/Source/Map/TransitionCinematic.cs index 15dda5317..476255cff 100644 --- a/Subsurface/Source/Map/TransitionCinematic.cs +++ b/Subsurface/Source/Map/TransitionCinematic.cs @@ -26,12 +26,12 @@ namespace Barotrauma public TransitionCinematic(List submarines, Camera cam, float duration) { + if (!submarines.Any(s => s != null)) return; + Vector2 targetPos = new Vector2( submarines.Sum(s => s.Position.X), submarines.Sum(s => s.Position.Y)) / submarines.Count; - if (!submarines.Any()) return; - if (submarines.First().AtEndPosition) { targetPos = Level.Loaded.EndPosition + Vector2.UnitY * 500.0f; diff --git a/Subsurface/Source/Networking/GameClient.cs b/Subsurface/Source/Networking/GameClient.cs index 7889ad367..89ec3471f 100644 --- a/Subsurface/Source/Networking/GameClient.cs +++ b/Subsurface/Source/Networking/GameClient.cs @@ -96,9 +96,10 @@ namespace Barotrauma.Networking NetPeerConfiguration config = new NetPeerConfiguration("barotrauma"); #if DEBUG - config.SimulatedLoss = 0.1f; - config.SimulatedMinimumLatency = 0.3f; - config.SimulatedRandomLatency = 0.5f; + config.SimulatedLoss = 0.05f; + config.SimulatedDuplicatesChance = 0.05f; + config.SimulatedMinimumLatency = 0.1f; + config.SimulatedRandomLatency = 0.2f; #endif config.DisableMessageType(NetIncomingMessageType.DebugMessage | NetIncomingMessageType.WarningMessage | NetIncomingMessageType.Receipt @@ -448,32 +449,7 @@ namespace Barotrauma.Networking message = ComposeNetworkEventMessage(NetworkEventDeliveryMethod.ReliableLidgren); if (message != null) client.SendMessage(message, NetDeliveryMethod.ReliableUnordered); - - //foreach (NetworkEvent networkEvent in NetworkEvent.Events) - //{ - // if (networkEvent.IsImportant) - // { - // ReliableMessage reliableMessage = reliableChannel.CreateMessage(); - // reliableMessage.InnerMessage.Write((byte)PacketTypes.NetworkEvent); - - // if (networkEvent.FillData(reliableMessage.InnerMessage)) - // { - // reliableChannel.SendMessage(reliableMessage, client.ServerConnection); - // } - // } - // else - // { - // NetOutgoingMessage message = client.CreateMessage(); - // message.Write((byte)PacketTypes.NetworkEvent); - - - // if (networkEvent.FillData(message)) - // { - // client.SendMessage(message, NetDeliveryMethod.Unreliable); - // } - // } - //} - + NetworkEvent.Events.Clear(); // Update current time @@ -650,7 +626,6 @@ namespace Barotrauma.Networking endRoundButton.Selected = false; int seed = inc.ReadInt32(); - string levelSeed = inc.ReadString(); int missionTypeIndex = inc.ReadByte(); @@ -660,6 +635,8 @@ namespace Barotrauma.Networking string modeName = inc.ReadString(); + bool respawnAllowed = inc.ReadBoolean(); + GameModePreset gameMode = GameModePreset.list.Find(gm => gm.Name == modeName); if (gameMode == null) @@ -681,7 +658,7 @@ namespace Barotrauma.Networking GameMain.GameSession = new GameSession(GameMain.NetLobbyScreen.SelectedSub, "", gameMode, Mission.MissionTypes[missionTypeIndex]); GameMain.GameSession.StartShift(levelSeed); - respawnManager = new RespawnManager(this); + if (respawnAllowed) respawnManager = new RespawnManager(this); yield return CoroutineStatus.Running; diff --git a/Subsurface/Source/Networking/GameServer.cs b/Subsurface/Source/Networking/GameServer.cs index 52cb9ed5a..9ef055e9e 100644 --- a/Subsurface/Source/Networking/GameServer.cs +++ b/Subsurface/Source/Networking/GameServer.cs @@ -63,7 +63,7 @@ namespace Barotrauma.Networking #if DEBUG config.SimulatedLoss = 0.05f; - config.SimulatedRandomLatency = 0.3f; + config.SimulatedRandomLatency = 0.2f; config.SimulatedDuplicatesChance = 0.05f; config.SimulatedMinimumLatency = 0.1f; #endif @@ -281,7 +281,7 @@ namespace Barotrauma.Networking { inGameHUD.Update((float)Physics.step); - respawnManager.Update(deltaTime); + if (respawnManager != null) respawnManager.Update(deltaTime); bool isCrewDead = connectedClients.Find(c => c.Character != null && !c.Character.IsDead)==null && @@ -391,16 +391,16 @@ namespace Barotrauma.Networking private void SparseUpdate() { - if (gameStarted) - { - foreach (Submarine sub in Submarine.Loaded) - { - //no need to send position updates for submarines that are docked to mainsub - if (sub != Submarine.MainSub && sub.DockedTo.Contains(Submarine.MainSub)) continue; + //if (gameStarted) + //{ + // foreach (Submarine sub in Submarine.Loaded) + // { + // //no need to send position updates for submarines that are docked to mainsub + // if (sub != Submarine.MainSub && sub.DockedTo.Contains(Submarine.MainSub)) continue; - new NetworkEvent(sub.ID, false); - } - } + // new NetworkEvent(sub.ID, false); + // } + //} foreach (Character c in Character.CharacterList) { @@ -957,7 +957,7 @@ namespace Barotrauma.Networking GameServer.Log("Game mode: " + selectedMode.Name, Color.Cyan); GameServer.Log("Level seed: " + GameMain.NetLobbyScreen.LevelSeed, Color.Cyan); - respawnManager = new RespawnManager(this); + if (AllowRespawn) respawnManager = new RespawnManager(this); yield return CoroutineStatus.Running; @@ -1061,6 +1061,8 @@ namespace Barotrauma.Networking msg.Write(selectedMode.Name); + msg.Write(AllowRespawn); + //msg.Write(GameMain.NetLobbyScreen.GameDuration.TotalMinutes); List playingClients = connectedClients.FindAll(c => c.Character != null); @@ -1154,6 +1156,8 @@ namespace Barotrauma.Networking public void SendRespawnManagerMsg() { + if (respawnManager == null) return; + NetOutgoingMessage msg = server.CreateMessage(); respawnManager.WriteNetworkEvent(msg); @@ -1418,7 +1422,7 @@ namespace Barotrauma.Networking netStats.AddValue(NetStats.NetStatType.SentBytes, server.Statistics.SentBytes); netStats.AddValue(NetStats.NetStatType.ReceivedBytes, server.Statistics.ReceivedBytes); - netStats.Draw(spriteBatch, new Rectangle(200,0,800,200)); + netStats.Draw(spriteBatch, new Rectangle(200,0,800,200), this); } diff --git a/Subsurface/Source/Networking/GameServerSettings.cs b/Subsurface/Source/Networking/GameServerSettings.cs index 6f6f17926..e1a74f496 100644 --- a/Subsurface/Source/Networking/GameServerSettings.cs +++ b/Subsurface/Source/Networking/GameServerSettings.cs @@ -68,6 +68,12 @@ namespace Barotrauma.Networking set; } + public bool AllowRespawn + { + get; + set; + } + public SelectionMode SubSelectionMode { get { return subSelectionMode; } @@ -123,6 +129,8 @@ namespace Barotrauma.Networking writer.WriteAttributeString("SubSelection", subSelectionMode.ToString()); writer.WriteAttributeString("ModeSelection", modeSelectionMode.ToString()); + writer.WriteAttributeString("AllowRespawn", AllowRespawn.ToString()); + writer.Flush(); } } @@ -160,6 +168,8 @@ namespace Barotrauma.Networking Enum.TryParse(ToolBox.GetAttributeString(doc.Root, "ModeSelection", "Manual"), out modeSelectionMode); Voting.AllowModeVoting = modeSelectionMode == SelectionMode.Vote; + AllowRespawn = ToolBox.GetAttributeBool(doc.Root, "AllowRespawn", true); + FileStreamSender.MaxTransferDuration = new TimeSpan(0,0,ToolBox.GetAttributeInt(doc.Root, "MaxFileTransferDuration", 150)); } @@ -190,9 +200,20 @@ namespace Barotrauma.Networking return true; }; - var votesRequiredText = new GUITextBlock(new Rectangle(20, y+20, 20, 20), "Votes required: 50 %", GUI.Style, innerFrame, GUI.SmallFont); + y += 30; - var votesRequiredSlider = new GUIScrollBar(new Rectangle(150, y+22, 100, 10), GUI.Style, 0.1f, innerFrame); + var respawnBox = new GUITickBox(new Rectangle(0, y, 20, 20), "Allow respawning", Alignment.Left, innerFrame); + respawnBox.Selected = AllowRespawn; + respawnBox.OnSelected = (GUITickBox) => + { + AllowRespawn = !AllowRespawn; + return true; + }; + + + var votesRequiredText = new GUITextBlock(new Rectangle(20, y + 20, 20, 20), "Votes required: 50 %", GUI.Style, innerFrame, GUI.SmallFont); + + var votesRequiredSlider = new GUIScrollBar(new Rectangle(150, y + 22, 100, 10), GUI.Style, 0.1f, innerFrame); votesRequiredSlider.UserData = votesRequiredText; votesRequiredSlider.Step = 0.2f; votesRequiredSlider.BarScroll = (EndVoteRequiredRatio - 0.5f) * 2.0f; diff --git a/Subsurface/Source/Networking/NetStats.cs b/Subsurface/Source/Networking/NetStats.cs index 0bc89f864..7a9de4c1b 100644 --- a/Subsurface/Source/Networking/NetStats.cs +++ b/Subsurface/Source/Networking/NetStats.cs @@ -61,7 +61,7 @@ namespace Barotrauma.Networking updateTimer = UpdateInterval; } - public void Draw(SpriteBatch spriteBatch, Rectangle rect) + public void Draw(SpriteBatch spriteBatch, Rectangle rect, GameServer server) { GUI.DrawRectangle(spriteBatch, rect, Color.Black*0.4f, true); @@ -83,6 +83,17 @@ namespace Barotrauma.Networking spriteBatch.DrawString(GUI.SmallFont, "Peak resent: " + graphs[(int)NetStatType.ResentMessages].LargestValue() + " messages/s", new Vector2(rect.X + 10, rect.Y + 50), Color.Red); +#if DEBUG + int y = 10; + + foreach (KeyValuePair msgBytesSent in server.messageCount.OrderBy(key => key.Value)) + { + spriteBatch.DrawString(GUI.SmallFont, msgBytesSent.Key + ": " + MathUtils.GetBytesReadable(msgBytesSent.Value), + new Vector2(rect.Right - 200, rect.Y + y), Color.Red); + + y += 15; + } +#endif } } diff --git a/Subsurface/Source/Networking/NetworkMember.cs b/Subsurface/Source/Networking/NetworkMember.cs index 6b7edd427..db16a2e4b 100644 --- a/Subsurface/Source/Networking/NetworkMember.cs +++ b/Subsurface/Source/Networking/NetworkMember.cs @@ -55,6 +55,10 @@ namespace Barotrauma.Networking abstract class NetworkMember { +#if DEBUG + public Dictionary messageCount = new Dictionary(); +#endif + protected NetPeer netPeer; protected string name; @@ -163,6 +167,24 @@ namespace Barotrauma.Networking tempMessage.Position = 0; msgBytes.Add(tempMessage.ReadBytes(tempMessage.LengthBytes)); + +#if DEBUG + string msgType = networkEvent.Type.ToString(); + if (networkEvent.Type == NetworkEventType.EntityUpdate) + { + msgType += " (" + Entity.FindEntityByID(networkEvent.ID) + ")"; + } + + long sentBytes = 0; + if (!messageCount.TryGetValue(msgType, out sentBytes)) + { + messageCount.Add(msgType, tempMessage.LengthBytes); + } + else + { + messageCount[msgType] += tempMessage.LengthBytes; + } +#endif } if (msgBytes.Count == 0) return null; @@ -181,6 +203,7 @@ namespace Barotrauma.Networking message.Write(msgData); } + return message; }