From d46207916f5530a61c397ad34248abafc5b01399 Mon Sep 17 00:00:00 2001 From: Regalis Date: Tue, 7 Feb 2017 18:59:25 +0200 Subject: [PATCH] Server doesn't send character position updates to far-away clients, clients disable characters if they haven't received position updates in a while --- Subsurface/Source/Characters/AICharacter.cs | 10 +-- .../Source/Characters/Animation/Ragdoll.cs | 8 +- Subsurface/Source/Characters/Character.cs | 29 +++++++- .../Source/Events/Missions/MonsterMission.cs | 4 - Subsurface/Source/Networking/GameServer.cs | 74 +++---------------- Subsurface/Source/Networking/NetConfig.cs | 11 +-- 6 files changed, 48 insertions(+), 88 deletions(-) diff --git a/Subsurface/Source/Characters/AICharacter.cs b/Subsurface/Source/Characters/AICharacter.cs index 631767010..7c9c93bfe 100644 --- a/Subsurface/Source/Characters/AICharacter.cs +++ b/Subsurface/Source/Characters/AICharacter.cs @@ -33,16 +33,16 @@ namespace Barotrauma public override void Update(Camera cam, float deltaTime) { - if (!Enabled) return; - base.Update(cam, deltaTime); + + if (!Enabled) return; - float dist = Vector2.Distance(cam.WorldViewCenter, WorldPosition); - if (dist > 8000.0f) + float dist = Vector2.DistanceSquared(cam.WorldViewCenter, WorldPosition); + if (dist > 8000.0f * 8000.0f) { AnimController.SimplePhysicsEnabled = true; } - else if (dist < 7000.0f) + else if (dist < 7000.0f * 7000.0f) { AnimController.SimplePhysicsEnabled = false; } diff --git a/Subsurface/Source/Characters/Animation/Ragdoll.cs b/Subsurface/Source/Characters/Animation/Ragdoll.cs index 390371687..9b5267069 100644 --- a/Subsurface/Source/Characters/Animation/Ragdoll.cs +++ b/Subsurface/Source/Characters/Animation/Ragdoll.cs @@ -1125,14 +1125,14 @@ namespace Barotrauma public void SetPosition(Vector2 simPosition, bool lerp = false) { - Vector2 moveAmount = simPosition - Collider.SimPosition; + Vector2 limbMoveAmount = simPosition - MainLimb.SimPosition; Collider.SetTransform(simPosition, Collider.Rotation); foreach (Limb limb in Limbs) { //check visibility from the new position of the collider to the new position of this limb - Vector2 movePos = limb.SimPosition + moveAmount; + Vector2 movePos = limb.SimPosition + limbMoveAmount; TrySetLimbPosition(limb, simPosition, movePos, lerp); } @@ -1160,7 +1160,7 @@ namespace Barotrauma if (lerp) { limb.body.TargetPosition = movePos; - limb.body.MoveToTargetPosition(Vector2.DistanceSquared(limb.SimPosition, movePos) < 100.0f); + limb.body.MoveToTargetPosition(true); } else { @@ -1179,7 +1179,7 @@ namespace Barotrauma protected void CheckDistFromCollider() { float allowedDist = Math.Max(Math.Max(Collider.radius, Collider.width), Collider.height) * 2.0f; - float resetDist = allowedDist * 10.0f; + float resetDist = allowedDist * 5.0f; float distSqrd = Vector2.DistanceSquared(Collider.SimPosition, MainLimb.SimPosition); diff --git a/Subsurface/Source/Characters/Character.cs b/Subsurface/Source/Characters/Character.cs index 821104198..02e0393b0 100644 --- a/Subsurface/Source/Characters/Character.cs +++ b/Subsurface/Source/Characters/Character.cs @@ -107,7 +107,7 @@ namespace Barotrauma public UInt16 LastNetworkUpdateID = 0; - //public int LargeUpdateTimer; + protected float lastRecvPositionUpdateTime; public readonly Dictionary Properties; public Dictionary ObjectProperties @@ -1331,7 +1331,7 @@ namespace Barotrauma public virtual void Update(Camera cam, float deltaTime) { - if (GameMain.Client!=null && this==Controlled && !isSynced) return; + if (GameMain.Client != null && this == Controlled && !isSynced) return; if (!Enabled) return; @@ -1360,7 +1360,22 @@ namespace Barotrauma if (this != Character.Controlled) { - if (GameMain.Server != null && !(this is AICharacter)) + if (GameMain.Client != null) + { + //freeze AI characters if more than 1 seconds have passed since last update from the server + if (lastRecvPositionUpdateTime < NetTime.Now - 1.0f) + { + AnimController.Frozen = true; + memPos.Clear(); + //hide after 2 seconds + if (lastRecvPositionUpdateTime < NetTime.Now - 2.0f) + { + Enabled = false; + return; + } + } + } + else if (GameMain.Server != null && !(this is AICharacter)) { if (!AllowInput) { @@ -1447,8 +1462,9 @@ namespace Barotrauma memInput.RemoveRange(60, memInput.Count - 60); } } - else //this == Character.Controlled && GameMain.Client == null + else { + //this == Character.Controlled && GameMain.Client == null AnimController.Frozen = false; } @@ -2247,6 +2263,11 @@ namespace Barotrauma case ServerNetObject.ENTITY_POSITION: bool facingRight = AnimController.Dir > 0.0f; + lastRecvPositionUpdateTime = (float)NetTime.Now; + + AnimController.Frozen = false; + Enabled = true; + UInt16 networkUpdateID = 0; if (msg.ReadBoolean()) { diff --git a/Subsurface/Source/Events/Missions/MonsterMission.cs b/Subsurface/Source/Events/Missions/MonsterMission.cs index f06ac445c..02103903d 100644 --- a/Subsurface/Source/Events/Missions/MonsterMission.cs +++ b/Subsurface/Source/Events/Missions/MonsterMission.cs @@ -44,10 +44,6 @@ namespace Barotrauma { radarPosition = monster.Position; } - else if (GameMain.Client == null) - { Vector2 diff = monster.WorldPosition - Submarine.MainSub.WorldPosition; - monster.Enabled = FarseerPhysics.ConvertUnits.ToSimUnits(diff.Length()) < NetConfig.CharacterIgnoreDistance; - } if (!monster.IsDead) return; ShowMessage(state); diff --git a/Subsurface/Source/Networking/GameServer.cs b/Subsurface/Source/Networking/GameServer.cs index 325d11962..29f73a34f 100644 --- a/Subsurface/Source/Networking/GameServer.cs +++ b/Subsurface/Source/Networking/GameServer.cs @@ -466,29 +466,6 @@ namespace Barotrauma.Networking // if 30ms has passed if (updateTimer < DateTime.Now) { - /*if (gameStarted) - { - - float ignoreDistance = FarseerPhysics.ConvertUnits.ToDisplayUnits(NetConfig.CharacterIgnoreDistance); - - foreach (Character c in Character.CharacterList) - { - if (!(c is AICharacter) || c.IsDead) continue; - - if (Character.CharacterList.Any( - c2 => c2.IsRemotePlayer && - Vector2.Distance(c2.WorldPosition, c.WorldPosition) < ignoreDistance)) - { - - } - - //todo: take multiple subs into account - //Vector2 diff = c.WorldPosition - Submarine.MainSub.WorldPosition; - - //if (FarseerPhysics.ConvertUnits.ToSimUnits(diff.Length()) > NetConfig.CharacterIgnoreDistance) continue; - } - }*/ - if (server.ConnectionsCount > 0) { if (sparseUpdateTimer < DateTime.Now) SparseUpdate(); @@ -568,31 +545,6 @@ 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; - - // new NetworkEvent(sub.ID, false); - // } - //} - - /*foreach (Character c in Character.CharacterList) - { - if (c.IsDead) continue; - - if (c is AICharacter) - { - //todo: take multiple subs into account - //Vector2 diff = c.WorldPosition - Submarine.MainSub.WorldPosition; - - //if (FarseerPhysics.ConvertUnits.ToSimUnits(diff.Length()) > NetConfig.CharacterIgnoreDistance) continue; - } - - }*/ - sparseUpdateTimer = DateTime.Now + sparseUpdateInterval; } @@ -672,7 +624,7 @@ namespace Barotrauma.Networking #if DEBUG //client thinks they've received a msg we haven't sent yet (corrupted packet, msg read/written incorrectly?) - if (lastRecvChatMsgID > c.lastChatMsgQueueID) + if (NetIdUtils.IdMoreRecent(lastRecvChatMsgID, c.lastChatMsgQueueID)) DebugConsole.ThrowError("client.lastRecvChatMsgID > lastChatMsgQueueID"); if (lastRecvEntitySpawnID > lastEntitySpawnID) @@ -811,23 +763,21 @@ namespace Barotrauma.Networking Item.Spawner.ServerWrite(outmsg, c); outmsg.WritePadBits(); } - + foreach (Character character in Character.CharacterList) { - if (character is AICharacter) + if (!character.Enabled) continue; + + if (c.Character != null && + Vector2.DistanceSquared(character.WorldPosition, c.Character.WorldPosition) >= + NetConfig.CharacterIgnoreDistance * NetConfig.CharacterIgnoreDistance) { - //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); - outmsg.WritePadBits(); - } - else - { - outmsg.Write((byte)ServerNetObject.ENTITY_POSITION); - character.ServerWrite(outmsg, c); - outmsg.WritePadBits(); + continue; } + + outmsg.Write((byte)ServerNetObject.ENTITY_POSITION); + character.ServerWrite(outmsg, c); + outmsg.WritePadBits(); } foreach (Submarine sub in Submarine.Loaded) diff --git a/Subsurface/Source/Networking/NetConfig.cs b/Subsurface/Source/Networking/NetConfig.cs index 2f055c8e1..86983ee8a 100644 --- a/Subsurface/Source/Networking/NetConfig.cs +++ b/Subsurface/Source/Networking/NetConfig.cs @@ -12,15 +12,8 @@ public static string MasterServerUrl = GameMain.Config.MasterServerUrl; //if a Character is further than this from the sub, the server will ignore it - //(in sim units) - public const float CharacterIgnoreDistance = 300.0f; - - //if a ragdoll is further than this from the correct position, teleport it there - //(in sim units) - public const float ResetRagdollDistance = 1.0f; - - //if the ragdoll is closer than this, don't try to correct its position - public const float AllowedRagdollDistance = 0.1f; + //(in display units) + public const float CharacterIgnoreDistance = 20000.0f; //how much the physics body of an item has to move until the server //send a position update to clients (in sim units)