Files
Nitrox/Nitrox.Test/Helper/Faker/NitroxAbstractFaker.cs
2025-07-06 00:23:46 +02:00

71 lines
2.6 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using NitroxModel_Subnautica.Logger;
using NitroxModel.Packets;
using NitroxModel.Packets.Processors.Abstract;
using NitroxServer;
using NitroxServer_Subnautica;
using NitroxServer.ConsoleCommands.Abstract;
namespace Nitrox.Test.Helper.Faker;
public class NitroxAbstractFaker : NitroxFaker, INitroxFaker
{
private static readonly Dictionary<Type, Type[]> subtypesByBaseType;
static NitroxAbstractFaker()
{
Assembly[] assemblies = { typeof(Packet).Assembly, typeof(SubnauticaInGameLogger).Assembly, typeof(ServerAutoFacRegistrar).Assembly, typeof(SubnauticaServerAutoFacRegistrar).Assembly };
HashSet<Type> blacklistedTypes = new() { typeof(Packet), typeof(CorrelatedPacket), typeof(Command), typeof(PacketProcessor) };
List<Type> types = new();
foreach (Assembly assembly in assemblies)
{
types.AddRange(assembly.GetTypes());
}
subtypesByBaseType = types.Where(type => type.IsAbstract && !type.IsSealed && !blacklistedTypes.Contains(type))
.ToDictionary(type => type, type => types.Where(t => type.IsAssignableFrom(t) && !t.IsAbstract && !t.IsInterface).ToArray())
.Where(dict => dict.Value.Length > 0)
.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
}
public readonly int AssignableTypesCount;
private readonly Queue<INitroxFaker> assignableFakers = new();
public NitroxAbstractFaker(Type type)
{
if (!type.IsAbstract)
{
throw new ArgumentException("Argument is not abstract", nameof(type));
}
if (!subtypesByBaseType.TryGetValue(type, out Type[] subTypes))
{
throw new ArgumentException($"Argument is not contained in {nameof(subtypesByBaseType)}", nameof(type));
}
OutputType = type;
AssignableTypesCount = subTypes.Length;
FakerByType.Add(type, this);
foreach (Type subType in subTypes)
{
assignableFakers.Enqueue(GetOrCreateFaker(subType));
}
}
public INitroxFaker[] GetSubFakers() => assignableFakers.ToArray();
/// <summary>
/// Selects an implementing type in a round-robin fashion of the abstract type of this faker. Then creates an instance of it.
/// </summary>
public object GenerateUnsafe(HashSet<Type> typeTree)
{
INitroxFaker assignableFaker = assignableFakers.Dequeue();
assignableFakers.Enqueue(assignableFaker);
return assignableFaker.GenerateUnsafe(typeTree);
}
}