From 0c9a55e9e0fcb4e44b827140fc590edb7bef1329 Mon Sep 17 00:00:00 2001 From: Regalis Date: Mon, 14 Nov 2016 16:58:21 +0200 Subject: [PATCH] - server doesn't create a new EntityEvent if there's a duplicate event waiting to be sent - hull, radar, steering & pump syncing --- Subsurface/Source/Characters/Character.cs | 6 -- .../Source/Items/Components/Machines/Pump.cs | 36 ++++++- .../Source/Items/Components/Machines/Radar.cs | 15 ++- .../Items/Components/Machines/Steering.cs | 31 ++++-- Subsurface/Source/Map/Hull.cs | 99 ++++++++++++++++--- Subsurface/Source/Networking/GameServer.cs | 2 +- .../Source/Networking/INetSerializable.cs | 4 - .../NetEntityEvent/NetEntityEvent.cs | 2 + .../ServerEntityEventManager.cs | 18 +++- Subsurface/Source/Screens/GameScreen.cs | 4 - 10 files changed, 166 insertions(+), 51 deletions(-) diff --git a/Subsurface/Source/Characters/Character.cs b/Subsurface/Source/Characters/Character.cs index fc755a550..25fa0895d 100644 --- a/Subsurface/Source/Characters/Character.cs +++ b/Subsurface/Source/Characters/Character.cs @@ -1451,12 +1451,6 @@ namespace Barotrauma closestCharacter = null; } } - - findClosestTimer = 0.1f; - } - else - { - findClosestTimer -= deltaTime; } if (selectedCharacter == null && closestItem != null) diff --git a/Subsurface/Source/Items/Components/Machines/Pump.cs b/Subsurface/Source/Items/Components/Machines/Pump.cs index 4d3200d1f..6c5448bcc 100644 --- a/Subsurface/Source/Items/Components/Machines/Pump.cs +++ b/Subsurface/Source/Items/Components/Machines/Pump.cs @@ -1,4 +1,5 @@ -using Microsoft.Xna.Framework; +using Barotrauma.Networking; +using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using System; using System.Collections.Specialized; @@ -7,15 +8,13 @@ using System.Xml.Linq; namespace Barotrauma.Items.Components { - class Pump : Powered + class Pump : Powered, IServerSerializable, IClientSerializable { private float flowPercentage; private float maxFlow; private float? targetLevel; - - private float lastUpdate; - + public Hull hull1; private GUITickBox isActiveTickBox; @@ -75,6 +74,15 @@ namespace Barotrauma.Items.Components IsActive = !IsActive; if (!IsActive) currPowerConsumption = 0.0f; + if (GameMain.Server != null) + { + item.CreateServerEvent(this); + } + else if (GameMain.Client != null) + { + item.CreateClientEvent(this); + } + return true; }; @@ -83,6 +91,15 @@ namespace Barotrauma.Items.Components { FlowPercentage -= 10.0f; + if (GameMain.Server != null) + { + item.CreateServerEvent(this); + } + else if (GameMain.Client != null) + { + item.CreateClientEvent(this); + } + return true; }; @@ -91,6 +108,15 @@ namespace Barotrauma.Items.Components { FlowPercentage += 10.0f; + if (GameMain.Server != null) + { + item.CreateServerEvent(this); + } + else if (GameMain.Client != null) + { + item.CreateClientEvent(this); + } + return true; }; } diff --git a/Subsurface/Source/Items/Components/Machines/Radar.cs b/Subsurface/Source/Items/Components/Machines/Radar.cs index 5390508e0..7e4ca4c6e 100644 --- a/Subsurface/Source/Items/Components/Machines/Radar.cs +++ b/Subsurface/Source/Items/Components/Machines/Radar.cs @@ -1,4 +1,5 @@ -using FarseerPhysics; +using Barotrauma.Networking; +using FarseerPhysics; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using System; @@ -8,7 +9,7 @@ using Voronoi2; namespace Barotrauma.Items.Components { - class Radar : Powered + class Radar : Powered, IServerSerializable, IClientSerializable { private float range; @@ -56,6 +57,14 @@ namespace Barotrauma.Items.Components isActiveTickBox = new GUITickBox(new Rectangle(0, 0, 20, 20), "Sonar", Alignment.TopLeft, GuiFrame); isActiveTickBox.OnSelected = (GUITickBox box) => { + if (GameMain.Server != null) + { + item.CreateServerEvent(this); + } + else if (GameMain.Client != null) + { + item.CreateClientEvent(this); + } IsActive = box.Selected; return true; @@ -420,6 +429,8 @@ namespace Barotrauma.Items.Components { IsActive = msg.ReadBoolean(); isActiveTickBox.Selected = IsActive; + + item.CreateServerEvent(this); } public void ServerWrite(Lidgren.Network.NetBuffer msg, Barotrauma.Networking.Client c, object[] extraData = null) diff --git a/Subsurface/Source/Items/Components/Machines/Steering.cs b/Subsurface/Source/Items/Components/Machines/Steering.cs index 7c858ae0b..a3ea3d2f8 100644 --- a/Subsurface/Source/Items/Components/Machines/Steering.cs +++ b/Subsurface/Source/Items/Components/Machines/Steering.cs @@ -1,4 +1,5 @@ -using FarseerPhysics; +using Barotrauma.Networking; +using FarseerPhysics; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using System; @@ -11,7 +12,7 @@ using Voronoi2; namespace Barotrauma.Items.Components { - class Steering : Powered + class Steering : Powered, IServerSerializable, IClientSerializable { private const float AutopilotRayCastInterval = 0.5f; @@ -30,7 +31,7 @@ namespace Barotrauma.Items.Components private PathFinder pathFinder; private float networkUpdateTimer; - private bool valueChanged; + private bool unsentChanges; private float autopilotRayCastTimer; @@ -112,7 +113,7 @@ namespace Barotrauma.Items.Components autopilotTickBox.OnSelected = (GUITickBox box) => { AutoPilot = box.Selected; - valueChanged = true; + unsentChanges = true; return true; }; @@ -139,13 +140,22 @@ namespace Barotrauma.Items.Components public override void Update(float deltaTime, Camera cam) { - if (valueChanged) + if (unsentChanges) { networkUpdateTimer -= deltaTime; if (networkUpdateTimer <= 0.0f) { + if (GameMain.Client != null) + { + item.CreateClientEvent(this); + } + else if (GameMain.Server != null) + { + item.CreateServerEvent(this); + } + networkUpdateTimer = 0.5f; - valueChanged = false; + unsentChanges = false; } } @@ -219,7 +229,7 @@ namespace Barotrauma.Items.Components TargetVelocity = PlayerInput.MousePosition - new Vector2(velRect.Center.X, velRect.Center.Y); targetVelocity.Y = -targetVelocity.Y; - valueChanged = true; + unsentChanges = true; } } } @@ -389,7 +399,7 @@ namespace Barotrauma.Items.Components private bool ToggleMaintainPosition(GUITickBox tickBox) { - valueChanged = true; + unsentChanges = true; levelStartTickBox.Selected = false; levelEndTickBox.Selected = false; @@ -410,7 +420,7 @@ namespace Barotrauma.Items.Components private bool SelectDestination(GUITickBox tickBox) { - valueChanged = true; + unsentChanges = true; if (tickBox == levelStartTickBox) { @@ -501,6 +511,9 @@ namespace Barotrauma.Items.Components } } } + + //notify all clients of the changed state + unsentChanges = true; } public void ServerWrite(Lidgren.Network.NetBuffer msg, Barotrauma.Networking.Client c, object[] extraData = null) diff --git a/Subsurface/Source/Map/Hull.cs b/Subsurface/Source/Map/Hull.cs index 8eb280a9f..f81097179 100644 --- a/Subsurface/Source/Map/Hull.cs +++ b/Subsurface/Source/Map/Hull.cs @@ -8,11 +8,12 @@ using FarseerPhysics.Dynamics; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using Lidgren.Network; +using Barotrauma.Networking; namespace Barotrauma { - class Hull : MapEntity, IPropertyObject + class Hull : MapEntity, IPropertyObject, IServerSerializable { public static List hullList = new List(); private static List entityGrids = new List(); @@ -362,6 +363,8 @@ namespace Barotrauma public void AddFireSource(FireSource fireSource) { fireSources.Add(fireSource); + + if (GameMain.Server != null) GameMain.Server.CreateEntityEvent(this); } public override void Update(Camera cam, float deltaTime) @@ -446,21 +449,22 @@ namespace Barotrauma soundIndex = -1; } } - + //update client hulls if the amount of water has changed by >10% //or if oxygen percentage has changed by 5% if (Math.Abs(lastSentVolume - volume) > FullVolume * 0.1f || Math.Abs(lastSentOxygen - OxygenPercentage) > 5f) { - + if (GameMain.Server != null) GameMain.Server.CreateEntityEvent(this); } - + if (!update) { lethalPressure = 0.0f; return; } + float surfaceY = rect.Y - rect.Height + Volume / rect.Width; for (int i = 0; i < waveY.Length; i++) { @@ -555,6 +559,8 @@ namespace Barotrauma public void RemoveFire(FireSource fire) { fireSources.Remove(fire); + + if (GameMain.Server != null) GameMain.Server.CreateEntityEvent(this); } public override void Draw(SpriteBatch spriteBatch, bool editing, bool back = true) @@ -806,19 +812,82 @@ namespace Barotrauma return false; } - //public List FindGaps() - //{ - // List gaps = new List(); - - // foreach (Gap gap in Gap.GapList) - // { - // if (gap.Open < 0.01f) continue; + public void ServerWrite(NetBuffer message, Client c, object[] extraData = null) + { + message.WriteRangedSingle(MathHelper.Clamp(volume / FullVolume, 0.0f, 1.5f), 0.0f, 1.5f, 8); + message.WriteRangedSingle(MathHelper.Clamp(OxygenPercentage, 0.0f, 100.0f), 0.0f, 100.0f, 8); - // if (gap.linkedTo.Contains(this)) gaps.Add(gap); - // } + message.Write(fireSources.Count > 0); + if (fireSources.Count > 0) + { + message.WriteRangedInteger(0, 16, Math.Min(fireSources.Count, 16)); + for (int i = 0; i < Math.Min(fireSources.Count, 16); i++) + { + var fireSource = fireSources[i]; + Vector2 normalizedPos = new Vector2( + (fireSource.Position.X - rect.X) / rect.Width, + (fireSource.Position.Y - (rect.Y - rect.Height)) / rect.Height); - // return gaps; - //} + message.WriteRangedSingle(MathHelper.Clamp(normalizedPos.X, 0.0f, 1.0f), 0.0f, 1.0f, 4); + message.WriteRangedSingle(MathHelper.Clamp(normalizedPos.Y, 0.0f, 1.0f), 0.0f, 1.0f, 4); + message.WriteRangedSingle(MathHelper.Clamp(fireSource.Size.X / rect.Width, 0.0f, 1.0f), 0, 1.0f, 6); + } + } + + lastSentVolume = volume; + lastSentOxygen = OxygenPercentage; + } + + public void ClientRead(NetIncomingMessage message, float sendingTime) + { + Volume = message.ReadRangedSingle(0.0f, 1.5f, 8) * FullVolume; + OxygenPercentage = message.ReadRangedSingle(0.0f, 100.0f, 8); + + bool hasFireSources = message.ReadBoolean(); + + List newFireSources = new List(); + if (hasFireSources) + { + int fireSourceCount = message.ReadRangedInteger(0, 16); + for (int i = 0; i < fireSourceCount; i++) + { + Vector2 pos = Vector2.Zero; + float size = 0.0f; + pos.X = MathHelper.Clamp(message.ReadRangedSingle(0.0f, 1.0f, 4), 0.05f, 0.95f); + pos.Y = MathHelper.Clamp(message.ReadRangedSingle(0.0f, 1.0f, 4), 0.05f, 0.95f); + size = message.ReadRangedSingle(0.0f, 1.0f, 6); + + pos = new Vector2( + rect.X + rect.Width * pos.X, + rect.Y - rect.Height + (rect.Height * pos.Y)); + + var existingFire = fireSources.Find(fs => fs.Contains(pos)); + if (existingFire != null) + { + newFireSources.Add(existingFire); + existingFire.Position = pos; + existingFire.Size = new Vector2( + existingFire.Hull == null ? size : size * existingFire.Hull.rect.Width, + existingFire.Size.Y); + } + else + { + var newFire = new FireSource(pos + Submarine.Position); + newFire.Size = new Vector2( + newFire.Hull == null ? size : size * newFire.Hull.rect.Width, + newFire.Size.Y); + //ignore if the fire wasn't added to this room (invalid position)? + if (!fireSources.Contains(newFire)) continue; + newFireSources.Add(newFire); + } + } + } + + var toBeRemoved = fireSources.FindAll(fs => !newFireSources.Contains(fs)); + toBeRemoved.ForEach(tbr => tbr.Remove()); + + fireSources = newFireSources; + } public override XElement Save(XElement parentElement) { diff --git a/Subsurface/Source/Networking/GameServer.cs b/Subsurface/Source/Networking/GameServer.cs index e4f23a2e2..7c8ce07d0 100644 --- a/Subsurface/Source/Networking/GameServer.cs +++ b/Subsurface/Source/Networking/GameServer.cs @@ -546,7 +546,7 @@ namespace Barotrauma.Networking sparseUpdateTimer = DateTime.Now + sparseUpdateInterval; } - public void CreateEntityEvent(IServerSerializable entity, object[] extraData) + public void CreateEntityEvent(IServerSerializable entity, object[] extraData = null) { entityEventManager.CreateEvent(entity, extraData); } diff --git a/Subsurface/Source/Networking/INetSerializable.cs b/Subsurface/Source/Networking/INetSerializable.cs index a43001ce5..f54d34854 100644 --- a/Subsurface/Source/Networking/INetSerializable.cs +++ b/Subsurface/Source/Networking/INetSerializable.cs @@ -10,8 +10,6 @@ namespace Barotrauma.Networking /// interface IClientSerializable : INetSerializable { - UInt32 NetStateID { get; } - void ClientWrite(NetBuffer msg, object[] extraData = null); void ServerRead(NetIncomingMessage msg, Client c); } @@ -21,8 +19,6 @@ namespace Barotrauma.Networking /// interface IServerSerializable : INetSerializable { - UInt32 NetStateID { get; } - void ServerWrite(NetBuffer msg, Client c, object[] extraData = null); void ClientRead(NetIncomingMessage msg, float sendingTime); } diff --git a/Subsurface/Source/Networking/NetEntityEvent/NetEntityEvent.cs b/Subsurface/Source/Networking/NetEntityEvent/NetEntityEvent.cs index 5528ffdea..0abc69fda 100644 --- a/Subsurface/Source/Networking/NetEntityEvent/NetEntityEvent.cs +++ b/Subsurface/Source/Networking/NetEntityEvent/NetEntityEvent.cs @@ -54,6 +54,8 @@ namespace Barotrauma.Networking { private IServerSerializable serializable; + public bool Sent; + public ServerEntityEvent(IServerSerializable entity, UInt32 id) : base(entity, id) { diff --git a/Subsurface/Source/Networking/NetEntityEvent/ServerEntityEventManager.cs b/Subsurface/Source/Networking/NetEntityEvent/ServerEntityEventManager.cs index b2f9d5597..bcfb00586 100644 --- a/Subsurface/Source/Networking/NetEntityEvent/ServerEntityEventManager.cs +++ b/Subsurface/Source/Networking/NetEntityEvent/ServerEntityEventManager.cs @@ -12,7 +12,7 @@ namespace Barotrauma.Networking private List events; private UInt32 ID; - + public ServerEntityEventManager(GameServer server) { events = new List(); @@ -26,11 +26,18 @@ namespace Barotrauma.Networking return; } - ID++; - - var newEvent = new ServerEntityEvent(entity, ID); + var newEvent = new ServerEntityEvent(entity, ID + 1); if (extraData != null) newEvent.SetData(extraData); + for (int i = events.Count - 1; i >= 0 && !events[i].Sent; i--) + { + //we already have an identical event that's waiting to be sent + // -> no need to add a new one + if (events[i].IsDuplicate(newEvent)) return; + } + + ID++; + events.Add(newEvent); } @@ -51,13 +58,14 @@ namespace Barotrauma.Networking { break; } - + eventsToSync.Insert(0, events[i]); } if (eventsToSync.Count == 0) return; foreach (NetEntityEvent entityEvent in eventsToSync) { + (entityEvent as ServerEntityEvent).Sent = true; client.entityEventLastSent[entityEvent.ID] = (float)NetTime.Now; } diff --git a/Subsurface/Source/Screens/GameScreen.cs b/Subsurface/Source/Screens/GameScreen.cs index bd5068a03..62dce6099 100644 --- a/Subsurface/Source/Screens/GameScreen.cs +++ b/Subsurface/Source/Screens/GameScreen.cs @@ -189,10 +189,6 @@ namespace Barotrauma { Character.Controlled.SelectedConstruction.DrawHUD(spriteBatch, cam, Character.Controlled); } - else if (!Character.Controlled.SelectedConstruction.IsInPickRange(Character.Controlled.WorldPosition)) - { - Character.Controlled.SelectedConstruction = null; - } } if (Character.Controlled != null && cam != null) Character.Controlled.DrawHUD(spriteBatch, cam);