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
{
///
/// Writes a broadcast to writer.
///
internal static PooledWriter WriteBroadcast(NetworkManager networkManager, PooledWriter writer, T message, ref Channel channel)
{
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());
//Update channel to reliable if needed.
networkManager.TransportManager.CheckSetReliableChannel(writer.Length, ref channel);
dataWriter.Store();
return writer;
}
}
internal static class BroadcastExtensions
{
///
/// Gets the key for a broadcast type.
///
///
///
///
internal static ushort GetKey()
{
return typeof(T).FullName.GetStableHashU16();
}
}
///
/// Implemented by server and client broadcast handlers.
///
public abstract class BroadcastHandlerBase
{
///
/// Current index when iterating invokes.
/// This value will be -1 when not iterating.
///
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;
}
///
/// Handles broadcasts received on server, from clients.
///
internal class ClientBroadcastHandler : BroadcastHandlerBase
{
///
/// Action handlers for the broadcast.
///
private List> _handlers = new();
///
/// True to require authentication for the broadcast type.
///
private bool _requireAuthentication;
public ClientBroadcastHandler(bool requireAuthentication)
{
_requireAuthentication = requireAuthentication;
}
///
/// Invokes handlers after reading broadcast.
///
/// True if a rebuild was required.
public override void InvokeHandlers(NetworkConnection conn, PooledReader reader, Channel channel)
{
T result = reader.Read();
for (base.IteratingIndex = 0; base.IteratingIndex < _handlers.Count; base.IteratingIndex++)
{
Action item = _handlers[base.IteratingIndex];
if (item != null)
{
item.Invoke(conn, result, channel);
}
else
{
_handlers.RemoveAt(base.IteratingIndex);
base.IteratingIndex--;
}
}
base.IteratingIndex = -1;
}
///
/// Adds a handler for this type.
///
public override void RegisterHandler(object obj)
{
Action handler = (Action)obj;
_handlers.AddUnique(handler);
}
///
/// Removes a handler from this type.
///
///
public override void UnregisterHandler(object obj)
{
Action handler = (Action)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 (base.IteratingIndex >= 0 && (indexOf <= base.IteratingIndex))
base.IteratingIndex--;
//Remove entry.
_handlers.RemoveAt(indexOf);
}
///
/// True to require authentication for the broadcast type.
///
public override bool RequireAuthentication => _requireAuthentication;
}
///
/// Handles broadcasts received on client, from server.
///
internal class ServerBroadcastHandler : BroadcastHandlerBase
{
///
/// Action handlers for the broadcast.
/// Even though List lookups are slower this allows easy adding and removing of entries during iteration.
///
private List> _handlers = new();
///
/// Invokes handlers after reading broadcast.
///
/// True if a rebuild was required.
public override void InvokeHandlers(PooledReader reader, Channel channel)
{
T result = reader.Read();
for (base.IteratingIndex = 0; base.IteratingIndex < _handlers.Count; base.IteratingIndex++)
{
Action item = _handlers[base.IteratingIndex];
if (item != null)
{
item.Invoke(result, channel);
}
else
{
_handlers.RemoveAt(base.IteratingIndex);
base.IteratingIndex--;
}
}
base.IteratingIndex = -1;
}
///
/// Adds a handler for this type.
///
public override void RegisterHandler(object obj)
{
Action handler = (Action)obj;
_handlers.AddUnique(handler);
}
///
/// Removes a handler from this type.
///
///
public override void UnregisterHandler(object obj)
{
Action handler = (Action)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 (base.IteratingIndex >= 0 && (indexOf <= base.IteratingIndex))
base.IteratingIndex--;
//Remove entry.
_handlers.RemoveAt(indexOf);
}
///
/// True to require authentication for the broadcast type.
///
public override bool RequireAuthentication => false;
}
}