Files
K-C-Multiplayer/Riptide/MessageRelayFilter.cs
2025-12-13 14:28:35 +01:00

107 lines
5.4 KiB
C#

// 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
{
/// <summary>Provides functionality for enabling/disabling automatic message relaying by message type.</summary>
public class MessageRelayFilter
{
/// <summary>The number of bits an int consists of.</summary>
private const int BitsPerInt = sizeof(int) * 8;
/// <summary>An array storing all the bits which represent whether messages of a given ID should be relayed or not.</summary>
private int[] filter;
/// <summary>Creates a filter of a given size.</summary>
/// <param name="size">How big to make the filter.</param>
/// <remarks>
/// <paramref name="size"/> 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, <paramref name="size"/> 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.
/// </remarks>
public MessageRelayFilter(int size) => Set(size);
/// <summary>Creates a filter based on an enum of message IDs.</summary>
/// <param name="idEnum">The enum type.</param>
public MessageRelayFilter(Type idEnum) => Set(GetSizeFromEnum(idEnum));
/// <summary>Creates a filter of a given size and enables relaying for the given message IDs.</summary>
/// <param name="size">How big to make the filter.</param>
/// <param name="idsToEnable">Message IDs to enable auto relaying for.</param>
/// <remarks>
/// <paramref name="size"/> 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, <paramref name="size"/> 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.
/// </remarks>
public MessageRelayFilter(int size, params ushort[] idsToEnable)
{
Set(size);
EnableIds(idsToEnable);
}
/// <summary>Creates a filter based on an enum of message IDs and enables relaying for the given message IDs.</summary>
/// <param name="idEnum">The enum type.</param>
/// <param name="idsToEnable">Message IDs to enable relaying for.</param>
public MessageRelayFilter(Type idEnum, params Enum[] idsToEnable)
{
Set(GetSizeFromEnum(idEnum));
EnableIds(idsToEnable.Cast<ushort>().ToArray());
}
/// <summary>Enables auto relaying for the given message IDs.</summary>
/// <param name="idsToEnable">Message IDs to enable relaying for.</param>
private void EnableIds(ushort[] idsToEnable)
{
for (int i = 0; i < idsToEnable.Length; i++)
EnableRelay(idsToEnable[i]);
}
/// <summary>Calculate the filter size necessary to manage all message IDs in the given enum.</summary>
/// <param name="idEnum">The enum type.</param>
/// <returns>The appropriate filter size.</returns>
/// <exception cref="ArgumentException"><paramref name="idEnum"/> is not an <see cref="Enum"/>.</exception>
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<ushort>().Max() + 1;
}
/// <summary>Sets the filter size.</summary>
/// <param name="size">How big to make the filter.</param>
private void Set(int size)
{
filter = new int[size / BitsPerInt + (size % BitsPerInt > 0 ? 1 : 0)];
}
/// <summary>Enables auto relaying for the given message ID.</summary>
/// <param name="forMessageId">The message ID to enable relaying for.</param>
public void EnableRelay(ushort forMessageId)
{
filter[forMessageId / BitsPerInt] |= 1 << (forMessageId % BitsPerInt);
}
/// <inheritdoc cref="EnableRelay(ushort)"/>
public void EnableRelay(Enum forMessageId) => EnableRelay((ushort)(object)forMessageId);
/// <summary>Disables auto relaying for the given message ID.</summary>
/// <param name="forMessageId">The message ID to enable relaying for.</param>
public void DisableRelay(ushort forMessageId)
{
filter[forMessageId / BitsPerInt] &= ~(1 << (forMessageId % BitsPerInt));
}
/// <inheritdoc cref="DisableRelay(ushort)"/>
public void DisableRelay(Enum forMessageId) => DisableRelay((ushort)(object)forMessageId);
/// <summary>Checks whether or not messages with the given ID should be relayed.</summary>
/// <param name="forMessageId">The message ID to check.</param>
/// <returns>Whether or not messages with the given ID should be relayed.</returns>
internal bool ShouldRelay(ushort forMessageId)
{
return (filter[forMessageId / BitsPerInt] & (1 << (forMessageId % BitsPerInt))) != 0;
}
}
}