// 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 System; using System.Linq; namespace Riptide { /// Provides functionality for enabling/disabling automatic message relaying by message type. public class MessageRelayFilter { /// The number of bits an int consists of. private const int BitsPerInt = sizeof(int) * 8; /// An array storing all the bits which represent whether messages of a given ID should be relayed or not. private int[] filter; /// Creates a filter of a given size. /// How big to make the filter. /// /// should be set to the value of the largest message ID, plus 1. For example, if a server will /// handle messages with IDs 1, 2, 3, 7, and 8, should be set to 9 (8 is the largest possible value, /// and 8 + 1 = 9) despite the fact that there are only 5 unique message IDs the server will ever handle. /// public MessageRelayFilter(int size) => Set(size); /// Creates a filter based on an enum of message IDs. /// The enum type. public MessageRelayFilter(Type idEnum) => Set(GetSizeFromEnum(idEnum)); /// Creates a filter of a given size and enables relaying for the given message IDs. /// How big to make the filter. /// Message IDs to enable auto relaying for. /// /// should be set to the value of the largest message ID, plus 1. For example, if a server will /// handle messages with IDs 1, 2, 3, 7, and 8, should be set to 9 (8 is the largest possible value, /// and 8 + 1 = 9) despite the fact that there are only 5 unique message IDs the server will ever handle. /// public MessageRelayFilter(int size, params ushort[] idsToEnable) { Set(size); EnableIds(idsToEnable); } /// Creates a filter based on an enum of message IDs and enables relaying for the given message IDs. /// The enum type. /// Message IDs to enable relaying for. public MessageRelayFilter(Type idEnum, params Enum[] idsToEnable) { Set(GetSizeFromEnum(idEnum)); EnableIds(idsToEnable.Cast().ToArray()); } /// Enables auto relaying for the given message IDs. /// Message IDs to enable relaying for. private void EnableIds(ushort[] idsToEnable) { for (int i = 0; i < idsToEnable.Length; i++) EnableRelay(idsToEnable[i]); } /// Calculate the filter size necessary to manage all message IDs in the given enum. /// The enum type. /// The appropriate filter size. /// is not an . private int GetSizeFromEnum(Type idEnum) { if (!idEnum.IsEnum) throw new ArgumentException($"Parameter '{nameof(idEnum)}' must be an enum type!", nameof(idEnum)); return Enum.GetValues(idEnum).Cast().Max() + 1; } /// Sets the filter size. /// How big to make the filter. private void Set(int size) { filter = new int[size / BitsPerInt + (size % BitsPerInt > 0 ? 1 : 0)]; } /// Enables auto relaying for the given message ID. /// The message ID to enable relaying for. public void EnableRelay(ushort forMessageId) { filter[forMessageId / BitsPerInt] |= 1 << (forMessageId % BitsPerInt); } /// public void EnableRelay(Enum forMessageId) => EnableRelay((ushort)(object)forMessageId); /// Disables auto relaying for the given message ID. /// The message ID to enable relaying for. public void DisableRelay(ushort forMessageId) { filter[forMessageId / BitsPerInt] &= ~(1 << (forMessageId % BitsPerInt)); } /// public void DisableRelay(Enum forMessageId) => DisableRelay((ushort)(object)forMessageId); /// Checks whether or not messages with the given ID should be relayed. /// The message ID to check. /// Whether or not messages with the given ID should be relayed. internal bool ShouldRelay(ushort forMessageId) { return (filter[forMessageId / BitsPerInt] & (1 << (forMessageId % BitsPerInt))) != 0; } } }