Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion RiptideNetworking/RiptideNetworking/Client.cs
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,12 @@ public void ChangeTransport(IClient newTransport)
transport = newTransport;
}

/// <summary>
/// Sets whether or not the server should throw an exception when handling messages. If set to <see langword="true"/>, the server will not throw exceptions when handling messages (like normal). Othervise it will throw an exception.
/// </summary>
/// <param name="preventExceptions">New value for the PREVENT_EXCEPTION property.</param>
public void ChangeExceptionPrevention(bool preventExceptions) => Server.SetPreventException(preventExceptions);

/// <summary>Attempts to connect to a server at the given host address.</summary>
/// <param name="hostAddress">The host address to connect to.</param>
/// <param name="maxConnectionAttempts">How many connection attempts to make before giving up.</param>
Expand All @@ -107,10 +113,12 @@ public void ChangeTransport(IClient newTransport)
/// <para>Setting <paramref name="useMessageHandlers"/> to <see langword="false"/> will disable the automatic detection and execution of methods with the <see cref="MessageHandlerAttribute"/>, which is beneficial if you prefer to handle messages via the <see cref="MessageReceived"/> event.</para>
/// </remarks>
/// <returns><see langword="true"/> if a connection attempt will be made. <see langword="false"/> if an issue occurred (such as <paramref name="hostAddress"/> being in an invalid format) and a connection attempt will <i>not</i> be made.</returns>
public bool Connect(string hostAddress, int maxConnectionAttempts = 5, byte messageHandlerGroupId = 0, Message message = null, bool useMessageHandlers = true)
public bool Connect(string hostAddress, int maxConnectionAttempts = 5, byte messageHandlerGroupId = 0, Message message = null, bool useMessageHandlers = true, bool preventExceptions = true)
{
Disconnect();

Server.SetPreventException(preventExceptions);

SubToTransportEvents();

if (!transport.Connect(hostAddress, out connection, out string connectError))
Expand Down
11 changes: 5 additions & 6 deletions RiptideNetworking/RiptideNetworking/Connection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
using Riptide.Transports;
using Riptide.Utils;
using System;
using System.Collections.Generic;
using System.Collections.Concurrent;

namespace Riptide
{
Expand Down Expand Up @@ -104,7 +104,7 @@ public bool CanTimeout
/// <summary>The sequencer for reliable messages.</summary>
private readonly ReliableSequencer reliable;
/// <summary>The currently pending reliably sent messages whose delivery has not been acknowledged yet. Stored by sequence ID.</summary>
private readonly Dictionary<ushort, PendingMessage> pendingMessages;
private readonly ConcurrentDictionary<ushort, PendingMessage> pendingMessages;
/// <summary>The connection's current state.</summary>
private ConnectionState state;
/// <summary>The number of consecutive times that the <see cref="MaxAvgSendAttempts"/> threshold was exceeded.</summary>
Expand Down Expand Up @@ -136,7 +136,7 @@ protected Connection()
MaxSendAttempts = 15;
MaxNotifyLoss = 0.05f; // 5%
NotifyLossResilience = 64;
pendingMessages = new Dictionary<ushort, PendingMessage>();
pendingMessages = new ConcurrentDictionary<ushort, PendingMessage>();
}

/// <summary>Initializes connection data.</summary>
Expand Down Expand Up @@ -184,7 +184,7 @@ public ushort Send(Message message, bool shouldRelease = true)
{
sequenceId = reliable.NextSequenceId;
PendingMessage pendingMessage = PendingMessage.Create(sequenceId, message, this);
pendingMessages.Add(sequenceId, pendingMessage);
pendingMessages.TryAdd(sequenceId, pendingMessage);
pendingMessage.TrySend();
Metrics.ReliableUniques++;
}
Expand Down Expand Up @@ -249,11 +249,10 @@ private void ResendMessage(ushort sequenceId)
/// <param name="sequenceId">The sequence ID that was acknowledged.</param>
internal void ClearMessage(ushort sequenceId)
{
if (pendingMessages.TryGetValue(sequenceId, out PendingMessage pendingMessage))
if (pendingMessages.TryRemove(sequenceId, out PendingMessage pendingMessage))
{
ReliableDelivered?.Invoke(sequenceId);
pendingMessage.Clear();
pendingMessages.Remove(sequenceId);
UpdateSendAttemptsViolations();
}
}
Expand Down
59 changes: 59 additions & 0 deletions RiptideNetworking/RiptideNetworking/Exceptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,65 @@ private static string GetErrorMessage(Type declaringType, string handlerMethodNa
}
}

/// <summary>The exception that is thrown when a message does not contain enough bits to retrieve a value of the specified type.</summary>
public class ReadingOrderOrCapacityException : Exception
{
/// <summary>
/// The number of unread bits remaining in the message when the exception was thrown. This is not necessarily the number of bits required to retrieve a value of the specified type, as the exception can also be thrown if the reading order is incorrect (e.g. trying to read a byte before reading a preceding bool).
/// </summary>
public int UnreadBits;
/// <summary>
/// The number of bits required to retrieve a value of the specified type. This is not necessarily the number of unread bits remaining in the message when the exception was thrown, as the exception can also be thrown if the reading order is incorrect (e.g. trying to read a byte before reading a preceding bool).
/// </summary>
public int RequiredBits;
/// <summary>
/// The name of the value that could not be retrieved.
/// </summary>
public readonly string ValueName;

/// <summary>Initializes a new <see cref="ReadingOrderOrCapacityException"/> instance.</summary>
public ReadingOrderOrCapacityException() { }
/// <summary>Initializes a new <see cref="ReadingOrderOrCapacityException"/> instance with a specified error message.</summary>
/// <param name="message">The error message that explains the reason for the exception.</param>
public ReadingOrderOrCapacityException(string message) : base(message) { }
/// <summary>Initializes a new <see cref="ReadingOrderOrCapacityException"/> instance with a specified error message and a reference to the inner exception that is the cause of this exception.</summary>
/// <param name="message">The error message that explains the reason for the exception.</param>
/// <param name="inner">The exception that is the cause of the current exception. If <paramref name="inner"/> is not a null reference, the current exception is raised in a catch block that handles the inner exception.</param>
public ReadingOrderOrCapacityException(string message, Exception inner) : base(message, inner) { }
/// <summary>Initializes a new <see cref="ReadingOrderOrCapacityException"/> instance and constructs an error message from the given information.</summary>
/// <param name="unreadbits">The number of unread bits remaining in the message when the exception was thrown.</param>
/// <param name="declaringType">The name of the type containing the handler method.</param>
public ReadingOrderOrCapacityException(int unreadbits, string declaringType) : base(GetErrorMessage(unreadbits, declaringType))
{
UnreadBits = unreadbits;
ValueName = declaringType;
}

/// <summary>Initializes a new <see cref="ReadingOrderOrCapacityException"/> instance and constructs an error message from the given information.</summary>
/// <param name="unreadbits">The number of unread bits remaining in the message when the exception was thrown.</param>
/// <param name="declaringType">The name of the type containing the handler method.</param>
public ReadingOrderOrCapacityException(int unreadbits, int requiredBits, string declaringType) : base(GetErrorMessage(unreadbits, requiredBits, declaringType))
{
UnreadBits = unreadbits;
RequiredBits = requiredBits;
ValueName = declaringType;
}


/// <summary>Constructs the error message from the given information.</summary>
/// <returns>The error message.</returns>
private static string GetErrorMessage(int unreadBits, string valueName)
{
return $"Message only contains {unreadBits} unread {Helper.CorrectForm(unreadBits, "bit")}, which is not enough to retrieve a value of type '{valueName}'!";
}
/// <summary>Constructs the error message from the given information.</summary>
/// <returns>The error message.</returns>
private static string GetErrorMessage(int unreadBits, int requiredBits, string valueName)
{
return $"Message only contains {unreadBits} unread {Helper.CorrectForm(unreadBits, "bit")}, which is not enough to retrieve a value of type '{valueName}' (requires {requiredBits} bits)!";
}
}

/// <summary>The exception that is thrown when a method with a <see cref="MessageHandlerAttribute"/> does not have an acceptable message handler method signature (either <see cref="Server.MessageHandler"/> or <see cref="Client.MessageHandler"/>).</summary>
public class InvalidHandlerSignatureException : Exception
{
Expand Down
Loading