Files
2026-04-07 03:11:52 +07:00

216 lines
7.2 KiB
C#

using FishNet.Connection;
using FishNet.Managing;
using FishNet.Serializing;
using FishNet.Transporting;
using GameKit.Dependencies.Utilities;
using System;
using System.Collections.Generic;
namespace FishNet.Broadcast.Helping
{
internal static class BroadcastsSerializers
{
/// <summary>
/// Writes a broadcast to writer.
/// </summary>
internal static PooledWriter WriteBroadcast<T>(PooledWriter writer, T message)
{
writer.WritePacketIdUnpacked(PacketId.Broadcast);
writer.WriteUInt16(typeof(T).FullName.GetStableHashU16());
// Write data to a new writer.
PooledWriter dataWriter = WriterPool.Retrieve();
dataWriter.Write(message);
// Write length of data.
writer.WriteInt32(dataWriter.Length);
// Write data.
writer.WriteArraySegment(dataWriter.GetArraySegment());
dataWriter.Store();
return writer;
}
}
internal static class BroadcastExtensions
{
/// <summary>
/// Gets the key for a broadcast type.
/// </summary>
/// <typeparam name = "T"></typeparam>
/// <param name = "broadcastType"></param>
/// <returns></returns>
internal static ushort GetKey<T>()
{
return typeof(T).FullName.GetStableHashU16();
}
}
/// <summary>
/// Implemented by server and client broadcast handlers.
/// </summary>
public abstract class BroadcastHandlerBase
{
/// <summary>
/// Current index when iterating invokes.
/// This value will be -1 when not iterating.
/// </summary>
protected int IteratingIndex;
public abstract void RegisterHandler(object obj);
public abstract void UnregisterHandler(object obj);
public virtual void InvokeHandlers(PooledReader reader, Channel channel) { }
public virtual void InvokeHandlers(NetworkConnection conn, PooledReader reader, Channel channel) { }
public virtual bool RequireAuthentication => false;
}
/// <summary>
/// Handles broadcasts received on server, from clients.
/// </summary>
internal class ClientBroadcastHandler<T> : BroadcastHandlerBase
{
/// <summary>
/// Action handlers for the broadcast.
/// </summary>
private List<Action<NetworkConnection, T, Channel>> _handlers = new();
/// <summary>
/// True to require authentication for the broadcast type.
/// </summary>
private bool _requireAuthentication;
public ClientBroadcastHandler(bool requireAuthentication)
{
_requireAuthentication = requireAuthentication;
}
/// <summary>
/// Invokes handlers after reading broadcast.
/// </summary>
/// <returns>True if a rebuild was required.</returns>
public override void InvokeHandlers(NetworkConnection conn, PooledReader reader, Channel channel)
{
T result = reader.Read<T>();
for (IteratingIndex = 0; IteratingIndex < _handlers.Count; IteratingIndex++)
{
Action<NetworkConnection, T, Channel> item = _handlers[IteratingIndex];
if (item != null)
{
item.Invoke(conn, result, channel);
}
else
{
_handlers.RemoveAt(IteratingIndex);
IteratingIndex--;
}
}
IteratingIndex = -1;
}
/// <summary>
/// Adds a handler for this type.
/// </summary>
public override void RegisterHandler(object obj)
{
Action<NetworkConnection, T, Channel> handler = (Action<NetworkConnection, T, Channel>)obj;
_handlers.AddUnique(handler);
}
/// <summary>
/// Removes a handler from this type.
/// </summary>
/// <param name = "handler"></param>
public override void UnregisterHandler(object obj)
{
Action<NetworkConnection, T, Channel> handler = (Action<NetworkConnection, T, Channel>)obj;
int indexOf = _handlers.IndexOf(handler);
// Not registered.
if (indexOf == -1)
return;
/* Has already been iterated over, need to subtract
* 1 from iteratingIndex to accomodate
* for the entry about to be removed. */
if (IteratingIndex >= 0 && indexOf <= IteratingIndex)
IteratingIndex--;
// Remove entry.
_handlers.RemoveAt(indexOf);
}
/// <summary>
/// True to require authentication for the broadcast type.
/// </summary>
public override bool RequireAuthentication => _requireAuthentication;
}
/// <summary>
/// Handles broadcasts received on client, from server.
/// </summary>
internal class ServerBroadcastHandler<T> : BroadcastHandlerBase
{
/// <summary>
/// Action handlers for the broadcast.
/// Even though List lookups are slower this allows easy adding and removing of entries during iteration.
/// </summary>
private List<Action<T, Channel>> _handlers = new();
/// <summary>
/// Invokes handlers after reading broadcast.
/// </summary>
/// <returns>True if a rebuild was required.</returns>
public override void InvokeHandlers(PooledReader reader, Channel channel)
{
T result = reader.Read<T>();
for (IteratingIndex = 0; IteratingIndex < _handlers.Count; IteratingIndex++)
{
Action<T, Channel> item = _handlers[IteratingIndex];
if (item != null)
{
item.Invoke(result, channel);
}
else
{
_handlers.RemoveAt(IteratingIndex);
IteratingIndex--;
}
}
IteratingIndex = -1;
}
/// <summary>
/// Adds a handler for this type.
/// </summary>
public override void RegisterHandler(object obj)
{
Action<T, Channel> handler = (Action<T, Channel>)obj;
_handlers.AddUnique(handler);
}
/// <summary>
/// Removes a handler from this type.
/// </summary>
/// <param name = "handler"></param>
public override void UnregisterHandler(object obj)
{
Action<T, Channel> handler = (Action<T, Channel>)obj;
int indexOf = _handlers.IndexOf(handler);
// Not registered.
if (indexOf == -1)
return;
/* Has already been iterated over, need to subtract
* 1 from iteratingIndex to accomodate
* for the entry about to be removed. */
if (IteratingIndex >= 0 && indexOf <= IteratingIndex)
IteratingIndex--;
// Remove entry.
_handlers.RemoveAt(indexOf);
}
/// <summary>
/// True to require authentication for the broadcast type.
/// </summary>
public override bool RequireAuthentication => false;
}
}