"ReliableMessages", networkevents aren't sent if FillNetworkEvent fails

This commit is contained in:
Regalis
2015-10-19 22:49:38 +03:00
parent c3d1b971dd
commit 5f07d4b0c9
22 changed files with 604 additions and 76 deletions

View File

@@ -45,7 +45,7 @@
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<DefineConstants>TRACE;USE_RELEASE_STATISTICS</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>

View File

@@ -100,6 +100,7 @@
<Compile Include="Source\Map\SubmarineHull.cs" />
<Compile Include="Source\Networking\NetConfig.cs" />
<Compile Include="Source\Networking\NetStats.cs" />
<Compile Include="Source\Networking\ReliableSender.cs" />
<Compile Include="Source\Particles\ParticleEmitter.cs" />
<Compile Include="Source\Screens\ServerListScreen.cs" />
<Compile Include="Source\Utils\Rand.cs" />

View File

@@ -31,5 +31,5 @@ using System.Runtime.InteropServices;
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("0.2.0.0")]
[assembly: AssemblyFileVersion("0.2.0.0")]
[assembly: AssemblyVersion("0.2.2.0")]
[assembly: AssemblyFileVersion("0.2.2.0")]

View File

@@ -83,11 +83,11 @@ namespace Barotrauma
return result;
}
public override void FillNetworkData(NetworkEventType type, NetOutgoingMessage message, object data)
public override bool FillNetworkData(NetworkEventType type, NetOutgoingMessage message, object data)
{
if (type == NetworkEventType.KillCharacter)
{
return;
return true;
}
message.Write((float)NetTime.Now);
@@ -127,6 +127,9 @@ namespace Barotrauma
LargeUpdateTimer = Math.Max(0, LargeUpdateTimer - 1);
}
return true;
}
public override void ReadNetworkData(NetworkEventType type, NetIncomingMessage message)

View File

@@ -1084,21 +1084,21 @@ namespace Barotrauma
}
}
public override void FillNetworkData(NetworkEventType type, NetOutgoingMessage message, object data)
public override bool FillNetworkData(NetworkEventType type, NetOutgoingMessage message, object data)
{
if (type == NetworkEventType.PickItem)
{
message.Write((int)data);
return;
return true;
}
else if (type== NetworkEventType.SelectCharacter)
{
message.Write((int)data);
return;
return true;
}
else if (type == NetworkEventType.KillCharacter)
{
return;
return true;
}
var hasInputs =
@@ -1160,7 +1160,9 @@ namespace Barotrauma
message.Write(AnimController.RefLimb.SimPosition.Y);
LargeUpdateTimer = Math.Max(0, LargeUpdateTimer-1);
}
}
return true;
}
public override void ReadNetworkData(NetworkEventType type, NetIncomingMessage message)

View File

@@ -325,6 +325,11 @@ namespace Barotrauma
//Ragdoll.DebugDraw = !Ragdoll.DebugDraw;
GameMain.DebugDraw = !GameMain.DebugDraw;
break;
case "netstats":
if (GameMain.Server == null) return;
GameMain.Server.ShowNetStats = !GameMain.Server.ShowNetStats;
break;
default:
NewMessage("Command not found", Color.Red);
break;

View File

@@ -613,6 +613,8 @@ namespace Barotrauma
{
do
{
if (enemy == null) break;
enemy.Health = 50.0f;
enemy.AIController.State = AIController.AiState.None;

View File

@@ -279,12 +279,14 @@ namespace Barotrauma
spriteBatch.DrawString(GUI.Font, (int)item.Condition + " %", new Vector2(rect.X + rect.Width / 2, rect.Y + rect.Height / 2), Color.Red);
}
public override void FillNetworkData(NetworkEventType type, NetOutgoingMessage message, object data)
public override bool FillNetworkData(NetworkEventType type, NetOutgoingMessage message, object data)
{
for (int i = 0; i<capacity; i++)
{
message.Write((items[i] == null) ? -1 : items[i].ID);
}
return true;
}
public override void ReadNetworkData(NetworkEventType type, NetIncomingMessage message)

View File

@@ -1156,7 +1156,7 @@ namespace Barotrauma
new NetworkEvent(NetworkEventType.UpdateComponent, ID, isClient, index);
}
public override void FillNetworkData(NetworkEventType type, NetOutgoingMessage message, object data)
public override bool FillNetworkData(NetworkEventType type, NetOutgoingMessage message, object data)
{
message.Write(condition);
@@ -1172,7 +1172,7 @@ namespace Barotrauma
case NetworkEventType.UpdateComponent:
int componentIndex = (int)data;
if (componentIndex < 0 || componentIndex >= components.Count) return;
if (componentIndex < 0 || componentIndex >= components.Count) return false;
message.Write((byte)componentIndex);
components[componentIndex].FillNetworkData(type, message);
@@ -1214,6 +1214,8 @@ namespace Barotrauma
break;
}
return true;
}
public override void ReadNetworkData(NetworkEventType type, NetIncomingMessage message)

View File

@@ -64,7 +64,10 @@ namespace Barotrauma
dictionary.Add(id, this);
}
public virtual void FillNetworkData(NetworkEventType type, NetOutgoingMessage message, object data) { }
public virtual bool FillNetworkData(NetworkEventType type, NetOutgoingMessage message, object data)
{
return false;
}
public virtual void ReadNetworkData(NetworkEventType type, NetIncomingMessage message) { }
/// <summary>

View File

@@ -471,9 +471,11 @@ namespace Barotrauma
h.ID = int.Parse(element.Attribute("ID").Value);
}
public override void FillNetworkData(Networking.NetworkEventType type, Lidgren.Network.NetOutgoingMessage message, object data)
public override bool FillNetworkData(Networking.NetworkEventType type, Lidgren.Network.NetOutgoingMessage message, object data)
{
message.Write(volume);
return true;
}
public override void ReadNetworkData(Networking.NetworkEventType type, Lidgren.Network.NetIncomingMessage message)

View File

@@ -636,7 +636,7 @@ namespace Barotrauma
}
public override void FillNetworkData(NetworkEventType type, NetOutgoingMessage message, object data)
public override bool FillNetworkData(NetworkEventType type, NetOutgoingMessage message, object data)
{
int sectionIndex = 0;
byte byteIndex = 0;
@@ -648,12 +648,14 @@ namespace Barotrauma
}
catch
{
return;
return false;
}
message.Write((float)NetTime.Now);
message.Write(byteIndex);
message.Write(sections[sectionIndex].damage);
return true;
}
public override void ReadNetworkData(NetworkEventType type, NetIncomingMessage message)

View File

@@ -149,7 +149,7 @@ namespace Barotrauma
}
base.Remove();
ID = -1;
ID = -5;
}
//drawing ----------------------------------------------------
@@ -378,14 +378,18 @@ namespace Barotrauma
Level.Loaded.Move(-amount);
}
public override void FillNetworkData(Networking.NetworkEventType type, NetOutgoingMessage message, object data)
public override bool FillNetworkData(Networking.NetworkEventType type, NetOutgoingMessage message, object data)
{
if (subBody == null) return false;
message.Write((float)NetTime.Now);
message.Write(Position.X);
message.Write(Position.Y);
message.Write(Speed.X);
message.Write(Speed.Y);
return true;
}
public override void ReadNetworkData(Networking.NetworkEventType type, NetIncomingMessage message)

View File

@@ -3,6 +3,7 @@ using System.Diagnostics;
using Lidgren.Network;
using Microsoft.Xna.Framework;
using System.Collections.Generic;
using Barotrauma.Networking.ReliableMessages;
namespace Barotrauma.Networking
{
@@ -12,6 +13,8 @@ namespace Barotrauma.Networking
private GUIMessageBox reconnectBox;
private ReliableChannel reliableChannel;
private bool connected;
private int myID;
@@ -34,6 +37,7 @@ namespace Barotrauma.Networking
otherClients = new List<Client>();
}
public void ConnectToServer(string hostIP, string password = "")
@@ -63,6 +67,7 @@ namespace Barotrauma.Networking
#if DEBUG
config.SimulatedLoss = 0.1f;
config.SimulatedMinimumLatency = 0.3f;
config.SimulatedRandomLatency = 0.5f;
#endif
config.DisableMessageType(NetIncomingMessageType.DebugMessage | NetIncomingMessageType.WarningMessage | NetIncomingMessageType.Receipt
@@ -70,6 +75,7 @@ namespace Barotrauma.Networking
// Create new client, with previously created configs
client = new NetClient(config);
reliableChannel = new ReliableChannel(client);
NetOutgoingMessage outmsg = client.CreateMessage();
client.Start();
@@ -329,6 +335,8 @@ namespace Barotrauma.Networking
new NetworkEvent(myCharacter.ID, true);
}
}
reliableChannel.Update(deltaTime);
foreach (NetworkEvent networkEvent in NetworkEvent.events)
{
@@ -368,8 +376,17 @@ namespace Barotrauma.Networking
while ((inc = client.ReadMessage()) != null)
{
if (inc.MessageType != NetIncomingMessageType.Data) continue;
switch (inc.ReadByte())
//todo: exception handling
byte packetType = inc.ReadByte();
if (packetType == (byte)PacketTypes.ReliableMessage)
{
if (!reliableChannel.CheckMessage(inc)) continue;
packetType = inc.ReadByte();
}
switch (packetType)
{
case (byte)PacketTypes.StartGame:
if (gameStarted) continue;
@@ -427,6 +444,12 @@ namespace Barotrauma.Networking
new GUIMessageBox("You are the Traitor!", "Your secret task is to assassinate " + targetName + "!");
break;
case (byte)PacketTypes.ResendRequest:
reliableChannel.HandleResendRequest(inc);
break;
case (byte)PacketTypes.Ack:
reliableChannel.HandleAckMessage(inc);
break;
}
}
@@ -652,13 +675,13 @@ namespace Barotrauma.Networking
//AddChatMessage(message);
type = (gameStarted && myCharacter != null && myCharacter.IsDead) ? ChatMessageType.Dead : ChatMessageType.Default;
ReliableMessage msg = reliableChannel.CreateMessage();
msg.InnerMessage.Write((byte)PacketTypes.Chatmessage);
msg.InnerMessage.Write((byte)type);
msg.InnerMessage.Write(message);
NetOutgoingMessage msg = client.CreateMessage();
msg.Write((byte)PacketTypes.Chatmessage);
msg.Write((byte)type);
msg.Write(message);
client.SendMessage(msg, NetDeliveryMethod.ReliableUnordered);
reliableChannel.SendMessage(msg, client.ServerConnection);
}
/// <summary>

View File

@@ -5,11 +5,13 @@ using System.Diagnostics;
using Lidgren.Network;
using Microsoft.Xna.Framework;
using RestSharp;
using Barotrauma.Networking.ReliableMessages;
namespace Barotrauma.Networking
{
class GameServer : NetworkMember
{
public bool ShowNetStats;
public List<Client> connectedClients = new List<Client>();
@@ -64,7 +66,7 @@ namespace Barotrauma.Networking
#if DEBUG
config.SimulatedLoss = 0.2f;
config.SimulatedMinimumLatency = 0.3f;
config.SimulatedRandomLatency = 0.6f;
config.SimulatedDuplicatesChance = 0.05f;
config.SimulatedMinimumLatency = 0.1f;
#endif
@@ -96,9 +98,9 @@ namespace Barotrauma.Networking
}
catch (Exception e)
{
DebugConsole.ThrowError("Couldn't start the server", e);
DebugConsole.ThrowError("Couldn't start the server", e);
}
if (config.EnableUPnP)
{
@@ -225,7 +227,7 @@ namespace Barotrauma.Networking
public override void Update(float deltaTime)
{
if (GameMain.DebugDraw) netStats.Update(deltaTime);
if (ShowNetStats) netStats.Update(deltaTime);
if (!started) return;
@@ -268,8 +270,13 @@ namespace Barotrauma.Networking
disconnectedClients.RemoveAt(i);
}
NetIncomingMessage inc = server.ReadMessage();
if (inc != null)
foreach (Client c in connectedClients)
{
c.ReliableChannel.Update(deltaTime);
}
NetIncomingMessage inc = null;
while ((inc = server.ReadMessage()) != null)
{
try
{
@@ -277,7 +284,11 @@ namespace Barotrauma.Networking
}
catch
{
#if DEBUG
DebugConsole.ThrowError("Failed to read incoming message");
#endif
continue;
}
}
@@ -416,7 +427,26 @@ namespace Barotrauma.Networking
break;
case NetIncomingMessageType.Data:
switch (inc.ReadByte())
Client dataSender = connectedClients.Find(c => c.Connection == inc.SenderConnection);
if (dataSender == null) return;
byte packetType = 0;
try
{
packetType = inc.ReadByte();
}
catch
{
return;
}
if (packetType == (byte)PacketTypes.ReliableMessage)
{
if (!dataSender.ReliableChannel.CheckMessage(inc)) return;
packetType = inc.ReadByte();
}
switch (packetType)
{
case (byte)PacketTypes.NetworkEvent:
if (!gameStarted) break;
@@ -452,6 +482,13 @@ namespace Barotrauma.Networking
case (byte)PacketTypes.CharacterInfo:
ReadCharacterData(inc);
break;
case (byte)PacketTypes.ResendRequest:
dataSender.ReliableChannel.HandleResendRequest(inc);
break;
case (byte)PacketTypes.Ack:
dataSender.ReliableChannel.HandleAckMessage(inc);
break;
}
break;
case NetIncomingMessageType.WarningMessage:
@@ -552,7 +589,7 @@ namespace Barotrauma.Networking
userID++;
}
Client newClient = new Client(name, userID);
Client newClient = new Client(server, name, userID);
newClient.Connection = inc.SenderConnection;
newClient.version = version;
@@ -581,26 +618,23 @@ namespace Barotrauma.Networking
{
if (NetworkEvent.events.Count == 0) return;
List<NetConnection> recipients = new List<NetConnection>();
foreach (Client c in connectedClients)
{
if (c.character == null) continue;
//if (networkEvent.Type == NetworkEventType.UpdateEntity &&
// Vector2.Distance(e.SimPosition, c.character.SimPosition) > NetConfig.UpdateEntityDistance) continue;
recipients.Add(c.Connection);
}
if (recipients.Count == 0) return;
foreach (NetworkEvent networkEvent in NetworkEvent.events)
{
List<NetConnection> recipients = new List<NetConnection>();
Entity e = Entity.FindEntityByID(networkEvent.ID);
if (e == null) continue;
foreach (Client c in connectedClients)
{
if (c.character == null) continue;
//if (networkEvent.Type == NetworkEventType.UpdateEntity &&
// Vector2.Distance(e.SimPosition, c.character.SimPosition) > NetConfig.UpdateEntityDistance) continue;
recipients.Add(c.Connection);
}
if (recipients.Count == 0) return;
NetOutgoingMessage message = server.CreateMessage();
message.Write((byte)PacketTypes.NetworkEvent);
//if (!networkEvent.IsClient) continue;
@@ -872,7 +906,7 @@ namespace Barotrauma.Networking
{
base.Draw(spriteBatch);
if (!GameMain.DebugDraw) return;
if (!ShowNetStats) return;
int width = 200, height = 300;
int x = GameMain.GraphicsWidth - width, y = (int)(GameMain.GraphicsHeight*0.3f);
@@ -934,27 +968,22 @@ namespace Barotrauma.Networking
if (server.Connections.Count == 0) return;
NetOutgoingMessage msg = server.CreateMessage();
msg.Write((byte)PacketTypes.Chatmessage);
msg.Write((byte)type);
msg.Write(message);
List<Client> recipients = new List<Client>();
if (type==ChatMessageType.Dead)
foreach (Client c in connectedClients)
{
List<NetConnection> recipients = new List<NetConnection>();
foreach (Client c in connectedClients)
{
if (c.character != null && c.character.IsDead) recipients.Add(c.Connection);
}
if (recipients.Count>0)
{
server.SendMessage(msg, recipients, NetDeliveryMethod.ReliableUnordered, 0);
}
if (type!=ChatMessageType.Dead || (c.character != null && c.character.IsDead)) recipients.Add(c);
}
else
foreach (Client c in recipients)
{
server.SendMessage(msg, server.Connections, NetDeliveryMethod.ReliableUnordered, 0);
}
ReliableMessage msg = c.ReliableChannel.CreateMessage();
msg.InnerMessage.Write((byte)PacketTypes.Chatmessage);
msg.InnerMessage.Write((byte)type);
msg.InnerMessage.Write(message);
c.ReliableChannel.SendMessage(msg, c.Connection);
}
}
@@ -1177,13 +1206,21 @@ namespace Barotrauma.Networking
public List<JobPrefab> jobPreferences;
public JobPrefab assignedJob;
public ReliableChannel ReliableChannel;
public float deleteDisconnectedTimer;
public Client(NetPeer server, string name, int ID)
: this(name, ID)
{
ReliableChannel = new ReliableChannel(server);
}
public Client(string name, int ID)
{
this.name = name;
this.ID = ID;
jobPreferences = new List<JobPrefab>(JobPrefab.List.GetRange(0,3));
}
}

View File

@@ -79,13 +79,13 @@ namespace Barotrauma.Networking
graphs[(int)NetStatType.ResentMessages].Draw(spriteBatch, rect, null, 0.0f, Color.Red);
spriteBatch.DrawString(GUI.SmallFont, "Max received: "+graphs[(int)NetStatType.ReceivedBytes].LargestValue()+" bytes/s",
spriteBatch.DrawString(GUI.SmallFont, "Peak received: "+graphs[(int)NetStatType.ReceivedBytes].LargestValue()+" bytes/s",
new Vector2(rect.X + 10, rect.Y+10), Color.Cyan);
spriteBatch.DrawString(GUI.SmallFont, "Max sent: " + graphs[(int)NetStatType.SentBytes].LargestValue() + " bytes/s",
spriteBatch.DrawString(GUI.SmallFont, "Peak sent: " + graphs[(int)NetStatType.SentBytes].LargestValue() + " bytes/s",
new Vector2(rect.X + 10, rect.Y + 30), Color.Orange);
spriteBatch.DrawString(GUI.SmallFont, "Max resent: " + graphs[(int)NetStatType.ResentMessages].LargestValue() + " messages/s",
spriteBatch.DrawString(GUI.SmallFont, "Peak resent: " + graphs[(int)NetStatType.ResentMessages].LargestValue() + " messages/s",
new Vector2(rect.X + 10, rect.Y + 50), Color.Red);
}
}

View File

@@ -93,7 +93,15 @@ namespace Barotrauma.Networking
message.Write(id);
e.FillNetworkData(eventType, message, data);
try
{
if (!e.FillNetworkData(eventType, message, data)) return false;
}
catch
{
return false;
}
return true;
}

View File

@@ -8,6 +8,8 @@ namespace Barotrauma.Networking
{
enum PacketTypes
{
Unknown,
Login,
LoggedIn,
LogOut,
@@ -26,7 +28,12 @@ namespace Barotrauma.Networking
NetworkEvent,
Traitor
Traitor,
ResendRequest,
ReliableMessage,
Ack
}
class NetworkMember

View File

@@ -0,0 +1,404 @@
using Lidgren.Network;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
namespace Barotrauma.Networking.ReliableMessages
{
class ReliableChannel
{
ReliableSender sender;
ReliableReceiver receiver;
public ReliableChannel(NetPeer host)
{
sender = new ReliableSender(host);
receiver = new ReliableReceiver(host);
}
public ReliableMessage CreateMessage(int lengthBytes = 0)
{
return sender.CreateMessage();
}
public void SendMessage(ReliableMessage message, NetConnection receiver)
{
sender.SendMessage(message, receiver);
}
public void HandleResendRequest(NetIncomingMessage inc)
{
sender.HandleResendRequest(inc);
}
public void HandleAckMessage(NetIncomingMessage inc)
{
//make sure we've received what's been sent to us, if not, rerequest
receiver.HandleAckMessage(inc);
}
public bool CheckMessage(NetIncomingMessage inc)
{
return receiver.CheckMessage(inc);
}
public void Update(float deltaTime)
{
sender.Update(deltaTime);
//update receiver to rerequest missed messages
receiver.Update(deltaTime);
}
}
internal class ReliableSender
{
private List<ReliableMessage> messageBuffer;
private ushort messageCount;
private NetPeer sender;
private NetConnection recipient;
private float ackTimer;
public ReliableSender(NetPeer sender)
{
this.sender = sender;
messageBuffer = new List<ReliableMessage>();
}
public ReliableMessage CreateMessage()
{
if (messageCount == ushort.MaxValue) messageCount = 0;
messageCount++;
NetOutgoingMessage message = sender.CreateMessage();
var reliableMessage = new ReliableMessage(message, messageCount);
messageBuffer.Add(reliableMessage);
message.Write((byte)PacketTypes.ReliableMessage);
message.Write(messageCount);
while (messageBuffer.Count>100)
{
messageBuffer.RemoveAt(0);
}
return reliableMessage;
//server.SendMessage(msg, server.Connections, NetDeliveryMethod.Unreliable, 0);
}
public void SendMessage(ReliableMessage message, NetConnection connection)
{
message.SaveInnerMessage();
sender.SendMessage(message.InnerMessage, connection, NetDeliveryMethod.Unreliable, 0);
recipient = connection;
}
// NetOutgoingMessage msg = server.CreateMessage();
//reliableSender.CreateMessage(msg);
//msg.Write((byte)PacketTypes.Chatmessage);
//msg.Write((byte)type);
//msg.Write(message);
public void HandleResendRequest(NetIncomingMessage inc)
{
ushort messageId = inc.ReadUInt16();
Debug.WriteLine("received resend request for msg id "+messageId);
ResendMessage(messageId, inc.SenderConnection);
}
private void ResendMessage(ushort messageId, NetConnection connection)
{
ReliableMessage message = messageBuffer.Find(m => m.ID == messageId);
if (message == null) return;
Debug.WriteLine("resending " + messageId);
NetOutgoingMessage resendMessage = sender.CreateMessage();
message.RestoreInnerMessage(resendMessage);
sender.SendMessage(resendMessage, connection, NetDeliveryMethod.Unreliable);
}
public void Update(float deltaTime)
{
if (recipient == null) return;
ackTimer -= deltaTime;
if (ackTimer > 0.0f) return;
Debug.WriteLine("Sending ack message: "+messageCount);
NetOutgoingMessage message = sender.CreateMessage();
message.Write((byte)PacketTypes.Ack);
message.Write(messageCount);
sender.SendMessage(message, recipient, NetDeliveryMethod.Unreliable);
ackTimer = Math.Max(recipient.AverageRoundtripTime, 1.0f);
}
}
internal class ReliableReceiver
{
ushort lastMessageID;
Dictionary<ushort, MissingMessage> missingMessages;
private NetPeer receiver;
private NetConnection recipient;
public ReliableReceiver(NetPeer receiver)
{
this.receiver = receiver;
missingMessages = new Dictionary<ushort,MissingMessage>();
}
public void Update(float deltaTime)
{
foreach (var message in missingMessages.Where(m => m.Value.ResendRequestsSent>10).ToList())
{
missingMessages.Remove(message.Key);
}
foreach (KeyValuePair<ushort, MissingMessage> valuePair in missingMessages)
{
MissingMessage missingMessage = valuePair.Value;
missingMessage.ResendTimer -= deltaTime;
if (missingMessage.ResendRequestsSent==0
|| missingMessage.ResendTimer<0.0f)
{
Debug.WriteLine("rerequest "+missingMessage.ID+" (try #"+missingMessage.ResendRequestsSent+")");
NetOutgoingMessage resendRequest = receiver.CreateMessage();
resendRequest.Write((byte)PacketTypes.ResendRequest);
resendRequest.Write(missingMessage.ID);
receiver.SendMessage(resendRequest, recipient, NetDeliveryMethod.Unreliable);
missingMessage.ResendTimer = Math.Max(recipient.AverageRoundtripTime, 0.2f);
missingMessage.ResendRequestsSent++;
}
}
}
public bool CheckMessage(NetIncomingMessage message)
{
recipient = message.SenderConnection;
ushort id = message.ReadUInt16();
Debug.WriteLine("received message ID " + id + " - last id: " + lastMessageID);
//wrapped around
if (Math.Abs((int)lastMessageID - (int)id) > ushort.MaxValue / 2)
{
//id wrapped around and we missed some messages in between, rerequest them
if (lastMessageID<=ushort.MaxValue && id>1)
{
for (ushort i = (ushort)(Math.Min(lastMessageID, (ushort)(ushort.MaxValue-1)) + 1); i < ushort.MaxValue; i++)
{
//message already marked as missed, continue
if (missingMessages.ContainsKey((i))) continue;
Debug.WriteLine("added " + i + " to missed");
missingMessages.Add(i, new MissingMessage((ushort)i));
}
for (ushort i = 1; i < id; i++)
{
//message already marked as missed, continue
if (missingMessages.ContainsKey((i))) continue;
Debug.WriteLine("added " + i + " to missed");
missingMessages.Add(i, new MissingMessage((ushort)i));
}
lastMessageID = id;
}
//we already wrapped around but the message hasn't, check if it's a duplicate
else if (lastMessageID < ushort.MaxValue / 2 && id > ushort.MaxValue / 2 && !missingMessages.ContainsKey(id))
{
Debug.WriteLine("old already received message, ignore");
return false;
}
else
{
if (missingMessages.ContainsKey(id))
{
Debug.WriteLine("remove " + id + " from missed");
missingMessages.Remove(id);
}
}
}
else
{
if (id>lastMessageID+1)
{
for (ushort i = (ushort)(lastMessageID+1); i < id; i++ )
{
//message already marked as missed, continue
if (missingMessages.ContainsKey((i))) continue;
Debug.WriteLine("added "+i+" to missed");
missingMessages.Add(i, new MissingMessage((ushort)i));
}
}
//received an old message and it wasn't marked as missed, lets ignore it
else if (id<=lastMessageID && !missingMessages.ContainsKey(id))
{
Debug.WriteLine("old already received message, ignore");
return false;
}
else
{
if (missingMessages.ContainsKey(id))
{
Debug.WriteLine("remove "+id+" from missed");
missingMessages.Remove(id);
}
}
lastMessageID = Math.Max(lastMessageID, id);
}
return true;
}
public void HandleAckMessage(NetIncomingMessage inc)
{
int messageId = inc.ReadUInt16();
recipient = inc.SenderConnection;
//id matches, all good
if (messageId == lastMessageID)
{
Debug.WriteLine("Received ack message: " + messageId + ", all good");
return;
}
if (lastMessageID > messageId)
{
//shouldn't happen: we have somehow received messages that the other end hasn't sent
Debug.WriteLine("Reliable message error - recipient last sent: " + messageId + " (current count " + lastMessageID + ")");
return;
}
Debug.WriteLine("Received ack message: " + messageId + ", need to rerequest messages");
if (lastMessageID > ushort.MaxValue / 2 && messageId < short.MaxValue / 2)
{
for (ushort i = (ushort)Math.Min((int)lastMessageID + 1, ushort.MaxValue); i <= ushort.MaxValue; i++)
{
if (!missingMessages.ContainsKey(i)) missingMessages.Add(i, new MissingMessage(i));
}
for (ushort i = 1; i <= messageId; i++)
{
if (!missingMessages.ContainsKey(i)) missingMessages.Add(i, new MissingMessage(i));
}
}
else
{
for (ushort i = (ushort)Math.Min((int)lastMessageID+1, ushort.MaxValue); i <= messageId; i++)
{
if (!missingMessages.ContainsKey(i)) missingMessages.Add(i, new MissingMessage(i));
}
}
// Debug.WriteLine("received recent request for msg id " + messageId);
//ReliableMessage message = messageBuffer.Find(m => m.ID == messageId);
//if (message == null) return;
//NetOutgoingMessage resendMessage = sender.CreateMessage();
//message.RestoreInnerMessage(resendMessage);
//sender.SendMessage(resendMessage, inc.SenderConnection, NetDeliveryMethod.Unreliable);
}
}
internal class MissingMessage
{
private ushort id;
public byte ResendRequestsSent;
public float ResendTimer;
public ushort ID
{
get { return id; }
}
public MissingMessage(ushort id)
{
this.id = id;
}
}
class ReliableMessage
{
private NetOutgoingMessage innerMessage;
private ushort id;
private byte[] innerMessageBytes;
public NetOutgoingMessage InnerMessage
{
get { return innerMessage; }
}
public ushort ID
{
get { return id; }
}
public ReliableMessage(NetOutgoingMessage message, ushort id)
{
this.innerMessage = message;
this.id = id;
}
public void SaveInnerMessage()
{
innerMessageBytes = innerMessage.PeekBytes(innerMessage.LengthBytes);
//innerMessage = null;
}
public void RestoreInnerMessage(NetOutgoingMessage message)
{
message.Write(innerMessageBytes);
}
}
}

View File

@@ -287,8 +287,8 @@ namespace Barotrauma
if (serverList.Selected!=null && (serverList.Selected.GetChild("password") as GUITickBox).Selected)
{
var msgBox = new GUIMessageBox("Password required", "");
var passwordBox = new GUITextBox(new Rectangle(0,0,150,20), Alignment.BottomCenter, GUI.Style, msgBox);
var msgBox = new GUIMessageBox("Password required:", "");
var passwordBox = new GUITextBox(new Rectangle(0,40,150,25), Alignment.TopLeft, GUI.Style, msgBox);
passwordBox.UserData = "password";
var okButton = msgBox.GetChild<GUIButton>();

View File

@@ -1,3 +1,24 @@
---------------------------------------------------------------------------------------------------------
v0.2.2
---------------------------------------------------------------------------------------------------------
Multiplayer:
- network statistics view which can be enabled by opening the debug console (F3) and entering "netstats"
(only works if you're running a server)
- updated to latest version of Lidgren networking library, which may or may not have an effect
on the chat lag issues
Items:
- fixed some game-crashing bugs related to detaching and attaching items (such as buttons)
- railgun shells can be bought in single player
Submarine:
- more tools, diving suits and misc supplies in both default subs
Misc:
- fixed Moloch spawning inside the level in the tutorial
- the launcher shows an error message instead of crashing if it can't connect to the update server
---------------------------------------------------------------------------------------------------------
v0.2.1
---------------------------------------------------------------------------------------------------------

Binary file not shown.