// This file is provided under The MIT License as part of RiptideNetworking. // Copyright (c) Tom Weiland // For additional information please see the included LICENSE.md file or view it on GitHub: // https://github.com/RiptideNetworking/Riptide/blob/main/LICENSE.md using Riptide.Utils; using System; using System.Reflection; namespace Riptide { /// The exception that is thrown when a does not contain enough unwritten bits to perform an operation. public class InsufficientCapacityException : Exception { /// The message with insufficient remaining capacity. public readonly Message RiptideMessage; /// The name of the type which could not be added to the message. public readonly string TypeName; /// The number of available bits the type requires in order to be added successfully. public readonly int RequiredBits; /// Initializes a new instance. public InsufficientCapacityException() { } /// Initializes a new instance with a specified error message. /// The error message that explains the reason for the exception. public InsufficientCapacityException(string message) : base(message) { } /// Initializes a new instance with a specified error message and a reference to the inner exception that is the cause of this exception. /// The error message that explains the reason for the exception. /// The exception that is the cause of the current exception. If is not a null reference, the current exception is raised in a catch block that handles the inner exception. public InsufficientCapacityException(string message, Exception inner) : base(message, inner) { } /// Initializes a new instance and constructs an error message from the given information. /// The message with insufficient remaining capacity. /// The number of bits which were attempted to be reserved. public InsufficientCapacityException(Message message, int reserveBits) : base(GetErrorMessage(message, reserveBits)) { RiptideMessage = message; TypeName = "reservation"; RequiredBits = reserveBits; } /// Initializes a new instance and constructs an error message from the given information. /// The message with insufficient remaining capacity. /// The name of the type which could not be added to the message. /// The number of available bits required for the type to be added successfully. public InsufficientCapacityException(Message message, string typeName, int requiredBits) : base(GetErrorMessage(message, typeName, requiredBits)) { RiptideMessage = message; TypeName = typeName; RequiredBits = requiredBits; } /// Initializes a new instance and constructs an error message from the given information. /// The message with insufficient remaining capacity. /// The length of the array which could not be added to the message. /// The name of the array's type. /// The number of available bits required for a single element of the array to be added successfully. public InsufficientCapacityException(Message message, int arrayLength, string typeName, int requiredBits) : base(GetErrorMessage(message, arrayLength, typeName, requiredBits)) { RiptideMessage = message; TypeName = $"{typeName}[]"; RequiredBits = requiredBits * arrayLength; } /// Constructs the error message from the given information. /// The error message. private static string GetErrorMessage(Message message, int reserveBits) { return $"Cannot reserve {reserveBits} {Helper.CorrectForm(reserveBits, "bit")} in a message with {message.UnwrittenBits} " + $"{Helper.CorrectForm(message.UnwrittenBits, "bit")} of remaining capacity!"; } /// Constructs the error message from the given information. /// The error message. private static string GetErrorMessage(Message message, string typeName, int requiredBits) { return $"Cannot add a value of type '{typeName}' (requires {requiredBits} {Helper.CorrectForm(requiredBits, "bit")}) to " + $"a message with {message.UnwrittenBits} {Helper.CorrectForm(message.UnwrittenBits, "bit")} of remaining capacity!"; } /// Constructs the error message from the given information. /// The error message. private static string GetErrorMessage(Message message, int arrayLength, string typeName, int requiredBits) { requiredBits *= arrayLength; return $"Cannot add an array of type '{typeName}[]' with {arrayLength} {Helper.CorrectForm(arrayLength, "element")} (requires {requiredBits} {Helper.CorrectForm(requiredBits, "bit")}) " + $"to a message with {message.UnwrittenBits} {Helper.CorrectForm(message.UnwrittenBits, "bit")} of remaining capacity!"; } } /// The exception that is thrown when a method with a is not marked as . public class NonStaticHandlerException : Exception { /// The type containing the handler method. public readonly Type DeclaringType; /// The name of the handler method. public readonly string HandlerMethodName; /// Initializes a new instance. public NonStaticHandlerException() { } /// Initializes a new instance with a specified error message. /// The error message that explains the reason for the exception. public NonStaticHandlerException(string message) : base(message) { } /// Initializes a new instance with a specified error message and a reference to the inner exception that is the cause of this exception. /// The error message that explains the reason for the exception. /// The exception that is the cause of the current exception. If is not a null reference, the current exception is raised in a catch block that handles the inner exception. public NonStaticHandlerException(string message, Exception inner) : base(message, inner) { } /// Initializes a new instance and constructs an error message from the given information. /// The type containing the handler method. /// The name of the handler method. public NonStaticHandlerException(Type declaringType, string handlerMethodName) : base(GetErrorMessage(declaringType, handlerMethodName)) { DeclaringType = declaringType; HandlerMethodName = handlerMethodName; } /// Constructs the error message from the given information. /// The error message. private static string GetErrorMessage(Type declaringType, string handlerMethodName) { return $"'{declaringType.Name}.{handlerMethodName}' is an instance method, but message handler methods must be static!"; } } /// The exception that is thrown when a method with a does not have an acceptable message handler method signature (either or ). public class InvalidHandlerSignatureException : Exception { /// The type containing the handler method. public readonly Type DeclaringType; /// The name of the handler method. public readonly string HandlerMethodName; /// Initializes a new instance. public InvalidHandlerSignatureException() { } /// Initializes a new instance with a specified error message. /// The error message that explains the reason for the exception. public InvalidHandlerSignatureException(string message) : base(message) { } /// Initializes a new instance with a specified error message and a reference to the inner exception that is the cause of this exception. /// The error message that explains the reason for the exception. /// The exception that is the cause of the current exception. If is not a null reference, the current exception is raised in a catch block that handles the inner exception. public InvalidHandlerSignatureException(string message, Exception inner) : base(message, inner) { } /// Initializes a new instance and constructs an error message from the given information. /// The type containing the handler method. /// The name of the handler method. public InvalidHandlerSignatureException(Type declaringType, string handlerMethodName) : base(GetErrorMessage(declaringType, handlerMethodName)) { DeclaringType = declaringType; HandlerMethodName = handlerMethodName; } /// Constructs the error message from the given information. /// The error message. private static string GetErrorMessage(Type declaringType, string handlerMethodName) { return $"'{declaringType.Name}.{handlerMethodName}' doesn't match any acceptable message handler method signatures! Server message handler methods should have a 'ushort' and a '{nameof(Riptide.Message)}' parameter, while client message handler methods should only have a '{nameof(Riptide.Message)}' parameter."; } } /// The exception that is thrown when multiple methods with s are set to handle messages with the same ID and have the same method signature. public class DuplicateHandlerException : Exception { /// The message ID with multiple handler methods. public readonly ushort Id; /// The type containing the first handler method. public readonly Type DeclaringType1; /// The name of the first handler method. public readonly string HandlerMethodName1; /// The type containing the second handler method. public readonly Type DeclaringType2; /// The name of the second handler method. public readonly string HandlerMethodName2; /// Initializes a new instance with a specified error message. public DuplicateHandlerException() { } /// Initializes a new instance with a specified error message. /// The error message that explains the reason for the exception. public DuplicateHandlerException(string message) : base(message) { } /// Initializes a new instance with a specified error message and a reference to the inner exception that is the cause of this exception. /// The error message that explains the reason for the exception. /// The exception that is the cause of the current exception. If is not a null reference, the current exception is raised in a catch block that handles the inner exception. public DuplicateHandlerException(string message, Exception inner) : base(message, inner) { } /// Initializes a new instance and constructs an error message from the given information. /// The message ID with multiple handler methods. /// The first handler method's info. /// The second handler method's info. public DuplicateHandlerException(ushort id, MethodInfo method1, MethodInfo method2) : base(GetErrorMessage(id, method1, method2)) { Id = id; DeclaringType1 = method1.DeclaringType; HandlerMethodName1 = method1.Name; DeclaringType2 = method2.DeclaringType; HandlerMethodName2 = method2.Name; } /// Constructs the error message from the given information. /// The error message. private static string GetErrorMessage(ushort id, MethodInfo method1, MethodInfo method2) { return $"Message handler methods '{method1.DeclaringType.Name}.{method1.Name}' and '{method2.DeclaringType.Name}.{method2.Name}' are both set to handle messages with ID {id}! Only one handler method is allowed per message ID!"; } } }