// 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;
}
}
}