EntityEvent fixes:

- Clients wait for midround syncing to finish before applying the remote state to connection panels and inventories (because the wires connected to the connection panel or items in the inventory may not exist before the EntitySpawner events have been received).
- Server writes 0 as the projectile ID if the projectile doesn't exist anymore when a Turret event is sent.
- More info in networkevent error messages.
This commit is contained in:
Joonas Rikkonen
2018-07-30 13:35:26 +03:00
parent 8c598db10b
commit 60a563fe75
9 changed files with 167 additions and 118 deletions
@@ -224,21 +224,27 @@ namespace Barotrauma.Items.Components
}
//Starts a coroutine that will read the correct state of the component from the NetBuffer when correctionTimer reaches zero.
protected void StartDelayedCorrection(ServerNetObject type, NetBuffer buffer, float sendingTime)
protected void StartDelayedCorrection(ServerNetObject type, NetBuffer buffer, float sendingTime, bool waitForMidRoundSync = false)
{
if (delayedCorrectionCoroutine != null) CoroutineManager.StopCoroutines(delayedCorrectionCoroutine);
delayedCorrectionCoroutine = CoroutineManager.StartCoroutine(DoDelayedCorrection(type, buffer, sendingTime));
delayedCorrectionCoroutine = CoroutineManager.StartCoroutine(DoDelayedCorrection(type, buffer, sendingTime, waitForMidRoundSync));
}
private IEnumerable<object> DoDelayedCorrection(ServerNetObject type, NetBuffer buffer, float sendingTime)
private IEnumerable<object> DoDelayedCorrection(ServerNetObject type, NetBuffer buffer, float sendingTime, bool waitForMidRoundSync)
{
while (correctionTimer > 0.0f)
while (GameMain.Client != null &&
(correctionTimer > 0.0f || (waitForMidRoundSync && GameMain.Client.MidRoundSyncing)))
{
correctionTimer -= CoroutineManager.DeltaTime;
yield return CoroutineStatus.Running;
}
if (item.Removed || GameMain.Client == null)
{
yield return CoroutineStatus.Success;
}
((IServerSerializable)this).ClientRead(type, buffer, sendingTime);
correctionTimer = 0.0f;
@@ -1,5 +1,9 @@
using Barotrauma.Networking;
using Lidgren.Network;
using Microsoft.Xna.Framework.Graphics;
using System;
using System.Collections.Generic;
using System.Linq;
namespace Barotrauma.Items.Components
{
@@ -24,5 +28,66 @@ namespace Barotrauma.Items.Components
HighlightedWire = null;
Connection.DrawConnections(spriteBatch, this, character);
}
public void ClientRead(ServerNetObject type, NetBuffer msg, float sendingTime)
{
if (GameMain.Client.MidRoundSyncing)
{
//delay reading the state until midround syncing is done
//because some of the wires connected to the panel may not exist yet
int bitsToRead = Connections.Count * Connection.MaxLinked * 16;
StartDelayedCorrection(type, msg.ExtractBits(bitsToRead), sendingTime, waitForMidRoundSync: true);
}
else
{
ApplyRemoteState(msg);
}
}
private void ApplyRemoteState(NetBuffer msg)
{
List<Wire> prevWires = Connections.SelectMany(c => Array.FindAll(c.Wires, w => w != null)).ToList();
List<Wire> newWires = new List<Wire>();
foreach (Connection connection in Connections)
{
connection.ClearConnections();
}
foreach (Connection connection in Connections)
{
for (int i = 0; i < Connection.MaxLinked; i++)
{
ushort wireId = msg.ReadUInt16();
Item wireItem = Entity.FindEntityByID(wireId) as Item;
if (wireItem == null) continue;
Wire wireComponent = wireItem.GetComponent<Wire>();
if (wireComponent == null) continue;
newWires.Add(wireComponent);
connection.Wires[i] = wireComponent;
wireComponent.Connect(connection, false);
}
}
foreach (Wire wire in prevWires)
{
if (wire.Connections[0] == null && wire.Connections[1] == null)
{
wire.Item.Drop(null);
}
//wires that are not in anyone's inventory (i.e. not currently being rewired) can never be connected to only one connection
// -> someone must have dropped the wire from the connection panel
else if (wire.Item.ParentInventory == null &&
(wire.Connections[0] != null ^ wire.Connections[1] != null))
{
wire.Item.Drop(null);
}
}
}
}
}
@@ -148,8 +148,10 @@ namespace Barotrauma.Items.Components
public void ClientRead(ServerNetObject type, NetBuffer msg, float sendingTime)
{
UInt16 projectileID = msg.ReadUInt16();
Item projectile = Entity.FindEntityByID(projectileID) as Item;
//projectile removed, do nothing
if (projectileID == 0) return;
Item projectile = Entity.FindEntityByID(projectileID) as Item;
if (projectile == null)
{
DebugConsole.ThrowError("Failed to launch a projectile - item with the ID \"" + projectileID + " not found");