From 9f9f0205e71184acf2b6472f23fd448a89a7f09e Mon Sep 17 00:00:00 2001 From: Regalis Date: Wed, 4 Nov 2015 00:12:53 +0200 Subject: [PATCH] Sending multiple networkevents in one packet, removed limb updates from ImportantEntityUpdate --- Subsurface/Source/Characters/Character.cs | 68 +++++++++--------- Subsurface/Source/Characters/Ragdoll.cs | 29 ++++---- Subsurface/Source/Networking/GameClient.cs | 29 +++++++- Subsurface/Source/Networking/GameServer.cs | 72 ++++++++++++++++--- Subsurface/Source/Networking/NetworkEvent.cs | 1 + Subsurface_Solution.v12.suo | Bin 823808 -> 757760 bytes 6 files changed, 138 insertions(+), 61 deletions(-) diff --git a/Subsurface/Source/Characters/Character.cs b/Subsurface/Source/Characters/Character.cs index daaf5d039..75d9a9575 100644 --- a/Subsurface/Source/Characters/Character.cs +++ b/Subsurface/Source/Characters/Character.cs @@ -1222,21 +1222,21 @@ namespace Barotrauma return inventory.FillNetworkData(NetworkEventType.InventoryUpdate, message, data); case NetworkEventType.ImportantEntityUpdate: - int i = 0; - foreach (Limb limb in AnimController.Limbs) - { - if (limb.SimPosition.Length() > NetConfig.CharacterIgnoreDistance) return false; + //int i = 0; + //foreach (Limb limb in AnimController.Limbs) + //{ + // if (limb.SimPosition.Length() > NetConfig.CharacterIgnoreDistance) return false; - message.WriteRangedSingle(limb.body.SimPosition.X, -NetConfig.CharacterIgnoreDistance, NetConfig.CharacterIgnoreDistance, 16); - message.WriteRangedSingle(limb.body.SimPosition.Y, -NetConfig.CharacterIgnoreDistance, NetConfig.CharacterIgnoreDistance, 16); + // message.WriteRangedSingle(limb.body.SimPosition.X, -NetConfig.CharacterIgnoreDistance, NetConfig.CharacterIgnoreDistance, 16); + // message.WriteRangedSingle(limb.body.SimPosition.Y, -NetConfig.CharacterIgnoreDistance, NetConfig.CharacterIgnoreDistance, 16); - //message.Write(limb.body.LinearVelocity.X); - //message.Write(limb.body.LinearVelocity.Y); + // //message.Write(limb.body.LinearVelocity.X); + // //message.Write(limb.body.LinearVelocity.Y); - message.Write(limb.body.Rotation); - //message.WriteRangedSingle(MathHelper.Clamp(limb.body.AngularVelocity, -10.0f, 10.0f), -10.0f, 10.0f, 8); - i++; - } + // message.Write(limb.body.Rotation); + // //message.WriteRangedSingle(MathHelper.Clamp(limb.body.AngularVelocity, -10.0f, 10.0f), -10.0f, 10.0f, 8); + // i++; + //} message.WriteRangedSingle(MathHelper.Clamp(AnimController.StunTimer,0.0f,60.0f), 0.0f, 60.0f, 8); message.Write((byte)((health/maxHealth)*255.0f)); @@ -1366,32 +1366,32 @@ namespace Barotrauma inventory.ReadNetworkData(NetworkEventType.InventoryUpdate, message); return; case NetworkEventType.ImportantEntityUpdate: - foreach (Limb limb in AnimController.Limbs) - { - Vector2 limbPos = limb.SimPosition, vel = Vector2.Zero; - float rotation = limb.Rotation; + //foreach (Limb limb in AnimController.Limbs) + //{ + // Vector2 limbPos = limb.SimPosition, vel = Vector2.Zero; + // float rotation = limb.Rotation; - try - { - limbPos.X = message.ReadRangedSingle(-NetConfig.CharacterIgnoreDistance, NetConfig.CharacterIgnoreDistance, 16); - limbPos.Y = message.ReadRangedSingle(-NetConfig.CharacterIgnoreDistance, NetConfig.CharacterIgnoreDistance, 16); + // try + // { + // limbPos.X = message.ReadRangedSingle(-NetConfig.CharacterIgnoreDistance, NetConfig.CharacterIgnoreDistance, 16); + // limbPos.Y = message.ReadRangedSingle(-NetConfig.CharacterIgnoreDistance, NetConfig.CharacterIgnoreDistance, 16); - rotation = message.ReadFloat(); - } - catch - { - return; - } + // rotation = message.ReadFloat(); + // } + // catch + // { + // return; + // } - if (limb.body != null) - { - limb.body.TargetVelocity = limb.body.LinearVelocity; - limb.body.TargetPosition = limbPos;// +vel * (float)(deltaTime / 60.0); - limb.body.TargetRotation = rotation;// +angularVel * (float)(deltaTime / 60.0); - limb.body.TargetAngularVelocity = limb.body.AngularVelocity; - } + // if (limb.body != null) + // { + // limb.body.TargetVelocity = limb.body.LinearVelocity; + // limb.body.TargetPosition = limbPos;// +vel * (float)(deltaTime / 60.0); + // limb.body.TargetRotation = rotation;// +angularVel * (float)(deltaTime / 60.0); + // limb.body.TargetAngularVelocity = limb.body.AngularVelocity; + // } - } + //} float newStunTimer = 0.0f, newHealth = 0.0f, newOxygen = 0.0f; diff --git a/Subsurface/Source/Characters/Ragdoll.cs b/Subsurface/Source/Characters/Ragdoll.cs index f1e9bcd7c..604f64724 100644 --- a/Subsurface/Source/Characters/Ragdoll.cs +++ b/Subsurface/Source/Characters/Ragdoll.cs @@ -549,7 +549,7 @@ namespace Barotrauma { if (!character.Enabled) return; - UpdateNetplayerPosition(); + UpdateNetPlayerPosition(); Vector2 flowForce = Vector2.Zero; @@ -654,7 +654,7 @@ namespace Barotrauma } - private void UpdateNetplayerPosition() + private void UpdateNetPlayerPosition() { if (refLimb.body.TargetPosition == Vector2.Zero) { @@ -662,18 +662,13 @@ namespace Barotrauma return; } - //if the limb is further away than resetdistance, all limbs are immediately snapped to their targetpositions - float resetDistance = NetConfig.ResetRagdollDistance; - //if the limb is closer than alloweddistance, just ignore the difference float allowedDistance = NetConfig.AllowedRagdollDistance * ((inWater) ? 2.0f : 1.0f); float dist = Vector2.Distance(refLimb.body.SimPosition, refLimb.body.TargetPosition); - bool resetAll = dist > resetDistance; - if (resetAll) - { - if (Limbs.FirstOrDefault(limb => !limb.ignoreCollisions && limb.body.TargetPosition == Vector2.Zero) != null) resetAll = false; - } + + //if the limb is further away than resetdistance, all limbs are immediately snapped to their targetpositions + bool resetAll = dist > NetConfig.ResetRagdollDistance; Vector2 diff = (refLimb.body.TargetPosition - refLimb.body.SimPosition); @@ -717,16 +712,16 @@ namespace Barotrauma foreach (Limb limb in Limbs) { - if (limb.body.TargetPosition == Vector2.Zero) - { + //if (limb.body.TargetPosition == Vector2.Zero) + //{ limb.body.SetTransform(limb.body.SimPosition + diff, limb.body.Rotation); - continue; - } + //continue; + //} - limb.body.LinearVelocity = limb.body.TargetVelocity; - limb.body.AngularVelocity = limb.body.TargetAngularVelocity; + //limb.body.LinearVelocity = limb.body.TargetVelocity; + //limb.body.AngularVelocity = limb.body.TargetAngularVelocity; - limb.body.SetTransform(limb.body.TargetPosition, limb.body.TargetRotation); + //limb.body.SetTransform(limb.body.TargetPosition, limb.body.TargetRotation); limb.body.TargetPosition = Vector2.Zero; } } diff --git a/Subsurface/Source/Networking/GameClient.cs b/Subsurface/Source/Networking/GameClient.cs index 54c918929..502b082dd 100644 --- a/Subsurface/Source/Networking/GameClient.cs +++ b/Subsurface/Source/Networking/GameClient.cs @@ -474,7 +474,34 @@ namespace Barotrauma.Networking case (byte)PacketTypes.NetworkEvent: //read the data from the message and update client state accordingly if (!gameStarted) break; - NetworkEvent.ReadData(inc); + + byte msgCount = inc.ReadByte(); + + long currPos = inc.PositionInBytes; + + System.Diagnostics.Debug.WriteLine("msgcount: " + msgCount + " startpos: " + inc.PositionInBytes); + for (int i = 0; i < msgCount; i++ ) + { + + byte msgLength = inc.ReadByte(); + + System.Diagnostics.Debug.WriteLine("msglength: "+msgLength); + try + { + NetworkEvent.ReadData(inc); + } + catch + { + int afghj = 1; + } + //+1 because msgLength is one additional byte + currPos += msgLength+1; + inc.Position = currPos*8; + + System.Diagnostics.Debug.WriteLine("currpos: " + currPos); + } + + break; case (byte)PacketTypes.UpdateNetLobby: if (gameStarted) continue; diff --git a/Subsurface/Source/Networking/GameServer.cs b/Subsurface/Source/Networking/GameServer.cs index b3dba2eb7..b0a17d05c 100644 --- a/Subsurface/Source/Networking/GameServer.cs +++ b/Subsurface/Source/Networking/GameServer.cs @@ -635,21 +635,41 @@ namespace Barotrauma.Networking } if (recipients.Count == 0) return; - - foreach (NetworkEvent networkEvent in NetworkEvent.events) + + for (int i = 0; i<2; i++) { + bool important = i==0; + + var unreliableEvents = NetworkEvent.events.FindAll(e => e.IsImportant == important); + if (unreliableEvents.Count == 0) continue; + NetOutgoingMessage message = server.CreateMessage(); message.Write((byte)PacketTypes.NetworkEvent); - //if (!networkEvent.IsClient) continue; - if (!networkEvent.FillData(message)) + + + List msgBytes = new List(); + + foreach (NetworkEvent unreliableEvent in unreliableEvents) { - continue; + NetOutgoingMessage tempMessage = server.CreateMessage(); + if (!unreliableEvent.FillData(tempMessage)) continue; + tempMessage.WritePadBits(); + + tempMessage.Position = 0; + msgBytes.Add(tempMessage.ReadBytes(tempMessage.LengthBytes)); } - //Entity e = Entity.FindEntityByID(networkEvent.ID); - //if (e == null) continue; - if (networkEvent.IsImportant) + message.Write((byte)msgBytes.Count); + foreach (byte[] msgData in msgBytes) + { + if (msgData.Length > 255) DebugConsole.ThrowError("too large networkevent ("+msgData.Length+" bytes)"); + + message.Write((byte)msgData.Length); + message.Write(msgData); + } + + if (important) { foreach (Client c in recipients) { @@ -666,8 +686,42 @@ namespace Barotrauma.Networking { server.SendMessage(message, recipientConnections, NetDeliveryMethod.Unreliable, 0); } - } + } } + + + + //foreach (NetworkEvent networkEvent in NetworkEvent.events) + //{ + // if (!networkEvent.IsImportant) co + // //if (!networkEvent.IsClient) continue; + + // if (!networkEvent.FillData(message)) + // { + // continue; + // } + + // //Entity e = Entity.FindEntityByID(networkEvent.ID); + // //if (e == null) continue; + // if (networkEvent.IsImportant) + // { + // foreach (Client c in recipients) + // { + // ReliableMessage reliableMessage = c.ReliableChannel.CreateMessage(); + // message.Position = 0; + // reliableMessage.InnerMessage.Write(message.ReadBytes(message.LengthBytes)); + + // c.ReliableChannel.SendMessage(reliableMessage, c.Connection); + // } + // } + // else + // { + // if (server.ConnectionsCount>0) + // { + // server.SendMessage(message, recipientConnections, NetDeliveryMethod.Unreliable, 0); + // } + // } + //} NetworkEvent.events.Clear(); } diff --git a/Subsurface/Source/Networking/NetworkEvent.cs b/Subsurface/Source/Networking/NetworkEvent.cs index 2633d6903..f7039dfa5 100644 --- a/Subsurface/Source/Networking/NetworkEvent.cs +++ b/Subsurface/Source/Networking/NetworkEvent.cs @@ -168,6 +168,7 @@ namespace Barotrauma.Networking } Entity e = Entity.FindEntityByID(id); + System.Diagnostics.Debug.WriteLine(e.ToString()); if (e == null) { #if DEBUG diff --git a/Subsurface_Solution.v12.suo b/Subsurface_Solution.v12.suo index 6e0018820465a28c2829eb7d04b1e2077a2f3997..db41847159432334793e4e97b96e41e86a20abdb 100644 GIT binary patch delta 11500 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Ⓢ$*~NPxPFv>&7ovP8i+t7XeA({yR~4T2U!9YswX zF)Zte4VFh+o+jn+Ko6EFmK6)l@6f0&?Yb8^Rb3Fw0U5tFFE=ToMoyCO5YBtQ^ znyNPj#<8$KF?x;0p12CnVoG`ZEcP}5pWo=s9TluuuJN)a2XES_$C1_?q99YfLu3xS z*?#%QYdX2{mg%ZAQFYdCHTFW+QOA^-g?=is@*(mMOO)|{%{t=*i-2yYe|AcY67 zFgJ#TY|99dF_>FZqmf71Pa*CjW`(*Fc%_6cGz{n`%of?^e9$6(Fy#mr@7ljF28H)z zks>>>gvR~*vXhkCS)935S3fQ@xyiF@p~NKfTak#;9`0gmD z-?^YQ9*yW2y?ZF$g%Y|AxbW7;5!{M}A5N-z+!6=j(a+_Gu$vMs7l`fAzsbcyQ~gka z)tV*Tbf$3F_Bx)3_F>zbLL2Y+u0%?FhP7)9CV#~Gb!|6d;n?tjg41MpD4mjiOJm{H z5fbL%MR+PiB+b&{u(RdOtE;0FaI&Ch||$L%xcN9{@4)y zpd}{aM@M229!LMLhgoq<9H_+5arp;@*~viqTHX((7`)7|%)qa{QTY2p{SYJlAM?}i Oqxf4tPan?eC;SiU-$CyH delta 14288 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 P>tC*@>qGxzYW9BsUm&)>