mirror of
https://github.com/space-wizards/RobustToolbox.git
synced 2026-02-14 19:29:36 +01:00
* WebSocket-based data transfer system * Move resource downloads/uploads to the new transfer system Should drastically increase the permitted practical size * Transfer impl for Lidgren * Async impl for receive stream * Use unbounded channel for Lidgren * Add metrics * More comments * Add serverside stream limit to avoid being a DoS vector * Fix tests * Oops forgot to actually implement sequence channels in NetMessage * Doc comment for NetMessage.SequenceChannel * Release notes
373 lines
16 KiB
C#
373 lines
16 KiB
C#
using System.Reflection;
|
|
using JetBrains.Annotations;
|
|
using Moq;
|
|
using Robust.Server;
|
|
using Robust.Server.Configuration;
|
|
using Robust.Server.Console;
|
|
using Robust.Server.Containers;
|
|
using Robust.Server.Debugging;
|
|
using Robust.Server.GameObjects;
|
|
using Robust.Server.GameStates;
|
|
using Robust.Server.Localization;
|
|
using Robust.Server.Network.Transfer;
|
|
using Robust.Server.Physics;
|
|
using Robust.Server.Player;
|
|
using Robust.Server.Prototypes;
|
|
using Robust.Server.Reflection;
|
|
using Robust.Server.Replays;
|
|
using Robust.Server.ServerStatus;
|
|
using Robust.Shared;
|
|
using Robust.Shared.Asynchronous;
|
|
using Robust.Shared.Configuration;
|
|
using Robust.Shared.Console;
|
|
using Robust.Shared.Containers;
|
|
using Robust.Shared.ContentPack;
|
|
using Robust.Shared.Exceptions;
|
|
using Robust.Shared.GameObjects;
|
|
using Robust.Shared.IoC;
|
|
using Robust.Shared.Localization;
|
|
using Robust.Shared.Log;
|
|
using Robust.Shared.Map;
|
|
using Robust.Shared.Map.Components;
|
|
using Robust.Shared.Network;
|
|
using Robust.Shared.Network.Transfer;
|
|
using Robust.Shared.Physics;
|
|
using Robust.Shared.Physics.Collision;
|
|
using Robust.Shared.Physics.Components;
|
|
using Robust.Shared.Physics.Systems;
|
|
using Robust.Shared.Player;
|
|
using Robust.Shared.Profiling;
|
|
using Robust.Shared.Prototypes;
|
|
using Robust.Shared.Random;
|
|
using Robust.Shared.Reflection;
|
|
using Robust.Shared.Replays;
|
|
using Robust.Shared.Serialization;
|
|
using Robust.Shared.Serialization.Manager;
|
|
using Robust.Shared.Serialization.Manager.Attributes;
|
|
using Robust.Shared.Testing;
|
|
using Robust.Shared.Threading;
|
|
using Robust.Shared.Timing;
|
|
|
|
// ReSharper disable once CheckNamespace
|
|
namespace Robust.UnitTesting.Server
|
|
{
|
|
[PublicAPI]
|
|
public interface ISimulationFactory
|
|
{
|
|
ISimulationFactory RegisterComponents(CompRegistrationDelegate factory);
|
|
ISimulationFactory RegisterDependencies(DiContainerDelegate factory);
|
|
ISimulationFactory RegisterEntitySystems(EntitySystemRegistrationDelegate factory);
|
|
ISimulationFactory RegisterPrototypes(PrototypeRegistrationDelegate factory);
|
|
ISimulation InitializeInstance();
|
|
}
|
|
|
|
[PublicAPI]
|
|
public interface ISimulation
|
|
{
|
|
IDependencyCollection Collection { get; }
|
|
|
|
/// <summary>
|
|
/// Resolves a dependency directly out of IoC collection.
|
|
/// </summary>
|
|
T Resolve<T>();
|
|
|
|
/// <summary>
|
|
/// Adds a new map directly to the map manager.
|
|
/// </summary>
|
|
(EntityUid Uid, MapId MapId) CreateMap();
|
|
EntityUid SpawnEntity(string? protoId, EntityCoordinates coordinates);
|
|
EntityUid SpawnEntity(string? protoId, MapCoordinates coordinates);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Helper methods for working with <see cref="ISimulation"/>.
|
|
/// </summary>
|
|
internal static class SimulationExtensions
|
|
{
|
|
public static T System<T>(this ISimulation simulation) where T : IEntitySystem
|
|
{
|
|
return simulation.Resolve<IEntitySystemManager>().GetEntitySystem<T>();
|
|
}
|
|
|
|
public static bool HasComp<T>(this ISimulation simulation, EntityUid entity) where T : IComponent
|
|
{
|
|
return simulation.Resolve<IEntityManager>().HasComponent<T>(entity);
|
|
}
|
|
|
|
public static T Comp<T>(this ISimulation simulation, EntityUid entity) where T : IComponent
|
|
{
|
|
return simulation.Resolve<IEntityManager>().GetComponent<T>(entity);
|
|
}
|
|
|
|
public static TransformComponent Transform(this ISimulation simulation, EntityUid entity)
|
|
{
|
|
return simulation.Comp<TransformComponent>(entity);
|
|
}
|
|
}
|
|
|
|
public delegate void DiContainerDelegate(IDependencyCollection diContainer);
|
|
|
|
public delegate void CompRegistrationDelegate(IComponentFactory factory);
|
|
|
|
public delegate void EntitySystemRegistrationDelegate(IEntitySystemManager systemMan);
|
|
|
|
public delegate void PrototypeRegistrationDelegate(IPrototypeManager protoMan);
|
|
|
|
public sealed class RobustServerSimulation : ISimulation, ISimulationFactory
|
|
{
|
|
private DiContainerDelegate? _diFactory;
|
|
private CompRegistrationDelegate? _regDelegate;
|
|
private EntitySystemRegistrationDelegate? _systemDelegate;
|
|
private PrototypeRegistrationDelegate? _protoDelegate;
|
|
|
|
public IDependencyCollection Collection { get; private set; } = default!;
|
|
|
|
public T Resolve<T>()
|
|
{
|
|
return Collection.Resolve<T>();
|
|
}
|
|
|
|
public (EntityUid Uid, MapId MapId) CreateMap()
|
|
{
|
|
var uid = Collection.Resolve<IEntityManager>().System<SharedMapSystem>().CreateMap(out var mapId);
|
|
return (uid, mapId);
|
|
}
|
|
|
|
public EntityUid SpawnEntity(string? protoId, EntityCoordinates coordinates)
|
|
{
|
|
var entMan = Collection.Resolve<IEntityManager>();
|
|
return entMan.SpawnEntity(protoId, coordinates);
|
|
}
|
|
|
|
public EntityUid SpawnEntity(string? protoId, MapCoordinates coordinates)
|
|
{
|
|
var entMan = Collection.Resolve<IEntityManager>();
|
|
return entMan.SpawnEntity(protoId, coordinates);
|
|
}
|
|
|
|
private RobustServerSimulation() { }
|
|
|
|
public ISimulationFactory RegisterDependencies(DiContainerDelegate factory)
|
|
{
|
|
_diFactory += factory;
|
|
return this;
|
|
}
|
|
|
|
public ISimulationFactory RegisterComponents(CompRegistrationDelegate factory)
|
|
{
|
|
_regDelegate += factory;
|
|
return this;
|
|
}
|
|
|
|
public ISimulationFactory RegisterEntitySystems(EntitySystemRegistrationDelegate factory)
|
|
{
|
|
_systemDelegate += factory;
|
|
return this;
|
|
}
|
|
|
|
public ISimulationFactory RegisterPrototypes(PrototypeRegistrationDelegate factory)
|
|
{
|
|
_protoDelegate += factory;
|
|
return this;
|
|
}
|
|
|
|
public ISimulation InitializeInstance()
|
|
{
|
|
var container = new DependencyCollection();
|
|
Collection = container;
|
|
|
|
IoCManager.InitThread(container, true);
|
|
|
|
//TODO: This is a long term project that should eventually have parity with the actual server/client/SP IoC registration.
|
|
// The goal is to be able to pull out all networking and frontend dependencies, and only have a core simulation running.
|
|
// This does NOT replace the full RobustIntegrationTest, or regular unit testing. This simulation sits in the middle
|
|
// and allows you to run integration testing only on the simulation.
|
|
|
|
//Tier 1: System
|
|
container.Register<ILogManager, LogManager>();
|
|
container.Register<IRuntimeLog, RuntimeLog>();
|
|
container.Register<IConfigurationManager, ServerNetConfigurationManager>();
|
|
container.Register<INetConfigurationManager, ServerNetConfigurationManager>();
|
|
container.Register<IConfigurationManagerInternal, ServerNetConfigurationManager>();
|
|
container.Register<IServerNetConfigurationManager, ServerNetConfigurationManager>();
|
|
container.Register<INetConfigurationManagerInternal, ServerNetConfigurationManager>();
|
|
container.Register<IDynamicTypeFactory, DynamicTypeFactory>();
|
|
container.Register<IDynamicTypeFactoryInternal, DynamicTypeFactory>();
|
|
container.Register<ILocalizationManager, ServerLocalizationManager>();
|
|
container.Register<IModLoader, TestingModLoader>();
|
|
container.Register<IModLoaderInternal, TestingModLoader>();
|
|
container.Register<ProfManager, ProfManager>();
|
|
container.RegisterInstance<ITaskManager>(new Mock<ITaskManager>().Object);
|
|
container.Register<HttpClientHolder>();
|
|
container.Register<IHttpClientHolder, HttpClientHolder>();
|
|
container.Register<IHWId, DummyHWId>();
|
|
container.Register<IServerNetManager, NetManager>();
|
|
container.Register<IStatusHost, StatusHost>();
|
|
container.Register<ITransferManager, ServerTransferManager>();
|
|
|
|
var realReflection = new ServerReflectionManager();
|
|
realReflection.LoadAssemblies(new List<Assembly>(2)
|
|
{
|
|
AppDomain.CurrentDomain.GetAssemblyByName("Robust.Shared"),
|
|
AppDomain.CurrentDomain.GetAssemblyByName("Robust.Server"),
|
|
});
|
|
|
|
var reflectionManager = new Mock<IReflectionManager>();
|
|
reflectionManager
|
|
.Setup(x => x.FindTypesWithAttribute<MeansDataDefinitionAttribute>())
|
|
.Returns(() => new[]
|
|
{
|
|
typeof(DataDefinitionAttribute)
|
|
});
|
|
|
|
reflectionManager
|
|
.Setup(x => x.FindTypesWithAttribute(typeof(DataDefinitionAttribute)))
|
|
.Returns(() => new[]
|
|
{
|
|
typeof(EntityPrototype),
|
|
typeof(TransformComponent),
|
|
typeof(MetaDataComponent)
|
|
});
|
|
|
|
reflectionManager
|
|
.Setup(x => x.FindTypesWithAttribute<TypeSerializerAttribute>())
|
|
.Returns(() => realReflection.FindTypesWithAttribute<TypeSerializerAttribute>());
|
|
|
|
reflectionManager
|
|
.Setup(x => x.FindAllTypes())
|
|
.Returns(() => realReflection.FindAllTypes());
|
|
|
|
container.RegisterInstance<IBaseServerInternal>(new Mock<IBaseServerInternal>().Object);
|
|
container.RegisterInstance<IReflectionManager>(reflectionManager.Object); // tests should not be searching for types
|
|
container.RegisterInstance<IRobustSerializer>(new Mock<IRobustSerializer>().Object);
|
|
container.RegisterInstance<IResourceManager>(new Mock<IResourceManager>().Object); // no disk access for tests
|
|
container.RegisterInstance<IGameTiming>(new Mock<IGameTiming>().Object); // TODO: get timing working similar to RobustIntegrationTest
|
|
|
|
//Tier 2: Simulation
|
|
container.RegisterInstance<IConsoleHost>(new Mock<IConsoleHost>().Object); //Console is technically a frontend, we want to run headless
|
|
container.Register<IEntityManager, ServerEntityManager>();
|
|
container.Register<IServerEntityNetworkManager, ServerEntityManager>();
|
|
container.Register<EntityManager, ServerEntityManager>();
|
|
container.Register<IMapManager, NetworkedMapManager>();
|
|
container.Register<INetworkedMapManager, NetworkedMapManager>();
|
|
container.Register<IMapManagerInternal, NetworkedMapManager>();
|
|
container.Register<ISerializationManager, SerializationManager>();
|
|
container.Register<IRobustRandom, RobustRandom>();
|
|
container.Register<IPrototypeManager, ServerPrototypeManager>();
|
|
container.Register<IComponentFactory, ComponentFactory>();
|
|
container.Register<IEntitySystemManager, EntitySystemManager>();
|
|
container.Register<IManifoldManager, CollisionManager>();
|
|
container.Register<INetManager, NetManager>();
|
|
container.Register<IAuthManager, AuthManager>();
|
|
container.Register<ITileDefinitionManager, TileDefinitionManager>();
|
|
container.Register<IParallelManager, TestingParallelManager>();
|
|
container.Register<IParallelManagerInternal, TestingParallelManager>();
|
|
// Needed for grid fixture debugging.
|
|
container.Register<IConGroupController, ConGroupController>();
|
|
container.Register<EntityConsoleHost>();
|
|
|
|
// I just wanted to load pvs system
|
|
container.Register<IServerEntityManager, ServerEntityManager>();
|
|
// god help you if you actually need to test pvs functions
|
|
container.RegisterInstance<IPlayerManager>(new Mock<IPlayerManager>().Object);
|
|
container.RegisterInstance<ISharedPlayerManager>(new Mock<ISharedPlayerManager>().Object);
|
|
container.RegisterInstance<IServerGameStateManager>(new Mock<IServerGameStateManager>().Object);
|
|
container.RegisterInstance<IReplayRecordingManager>(new Mock<IReplayRecordingManager>().Object);
|
|
container.RegisterInstance<IServerReplayRecordingManager>(new Mock<IServerReplayRecordingManager>().Object);
|
|
|
|
_diFactory?.Invoke(container);
|
|
container.BuildGraph();
|
|
|
|
// Because of CVarDef, we have to load every one through reflection
|
|
// just in case a system needs one of them.
|
|
var configMan = container.Resolve<IConfigurationManagerInternal>();
|
|
configMan.Initialize(true);
|
|
configMan.LoadCVarsFromAssembly(typeof(Program).Assembly); // Server
|
|
configMan.LoadCVarsFromAssembly(typeof(ProgramShared).Assembly); // Shared
|
|
configMan.LoadCVarsFromAssembly(typeof(RobustServerSimulation).Assembly); // Tests
|
|
configMan.LoadCVarsFromAssembly(typeof(RTCVars).Assembly); // Tests
|
|
|
|
var logMan = container.Resolve<ILogManager>();
|
|
logMan.RootSawmill.AddHandler(new TestLogHandler(configMan, "SIM"));
|
|
|
|
var compFactory = container.Resolve<IComponentFactory>();
|
|
|
|
// if only we had some sort of attribute for automatically registering components.
|
|
compFactory.RegisterClass<MetaDataComponent>();
|
|
compFactory.RegisterClass<TransformComponent>();
|
|
compFactory.RegisterClass<MapGridComponent>();
|
|
compFactory.RegisterClass<MapComponent>();
|
|
compFactory.RegisterClass<MapLightComponent>();
|
|
compFactory.RegisterClass<PhysicsComponent>();
|
|
compFactory.RegisterClass<JointComponent>();
|
|
compFactory.RegisterClass<EyeComponent>();
|
|
compFactory.RegisterClass<GridTreeComponent>();
|
|
compFactory.RegisterClass<JointRelayTargetComponent>();
|
|
compFactory.RegisterClass<BroadphaseComponent>();
|
|
compFactory.RegisterClass<ContainerManagerComponent>();
|
|
compFactory.RegisterClass<FixturesComponent>();
|
|
compFactory.RegisterClass<CollisionWakeComponent>();
|
|
compFactory.RegisterClass<OccluderComponent>();
|
|
compFactory.RegisterClass<OccluderTreeComponent>();
|
|
compFactory.RegisterClass<CollideOnAnchorComponent>();
|
|
compFactory.RegisterClass<ActorComponent>();
|
|
|
|
_regDelegate?.Invoke(compFactory);
|
|
|
|
compFactory.GenerateNetIds();
|
|
|
|
var entityMan = container.Resolve<IEntityManager>();
|
|
entityMan.Initialize();
|
|
|
|
var entitySystemMan = container.Resolve<IEntitySystemManager>();
|
|
|
|
entitySystemMan.LoadExtraSystemType<PhysicsSystem>();
|
|
entitySystemMan.LoadExtraSystemType<SharedGridTraversalSystem>();
|
|
entitySystemMan.LoadExtraSystemType<ContainerSystem>();
|
|
entitySystemMan.LoadExtraSystemType<JointSystem>();
|
|
entitySystemMan.LoadExtraSystemType<MapSystem>();
|
|
entitySystemMan.LoadExtraSystemType<DebugPhysicsSystem>();
|
|
entitySystemMan.LoadExtraSystemType<DebugRayDrawingSystem>();
|
|
entitySystemMan.LoadExtraSystemType<BroadPhaseSystem>();
|
|
entitySystemMan.LoadExtraSystemType<CollisionWakeSystem>();
|
|
entitySystemMan.LoadExtraSystemType<FixtureSystem>();
|
|
entitySystemMan.LoadExtraSystemType<GridFixtureSystem>();
|
|
entitySystemMan.LoadExtraSystemType<TransformSystem>();
|
|
entitySystemMan.LoadExtraSystemType<EntityLookupSystem>();
|
|
entitySystemMan.LoadExtraSystemType<ServerMetaDataSystem>();
|
|
entitySystemMan.LoadExtraSystemType<PvsSystem>();
|
|
entitySystemMan.LoadExtraSystemType<InputSystem>();
|
|
entitySystemMan.LoadExtraSystemType<PvsOverrideSystem>();
|
|
|
|
_systemDelegate?.Invoke(entitySystemMan);
|
|
|
|
var mapManager = container.Resolve<IMapManager>();
|
|
mapManager.Initialize();
|
|
|
|
entityMan.Startup();
|
|
mapManager.Startup();
|
|
|
|
container.Resolve<INetManager>().Initialize(true);
|
|
container.Resolve<ISerializationManager>().Initialize();
|
|
|
|
var protoMan = container.Resolve<IPrototypeManager>();
|
|
protoMan.Initialize();
|
|
protoMan.RegisterKind(typeof(EntityPrototype), typeof(EntityCategoryPrototype));
|
|
_protoDelegate?.Invoke(protoMan);
|
|
|
|
// This just exists to set protoMan._hasEverBeenReloaded to True
|
|
// The code is perfect.
|
|
protoMan.LoadString("");
|
|
|
|
protoMan.ResolveResults();
|
|
|
|
return this;
|
|
}
|
|
|
|
public static ISimulationFactory NewSimulation()
|
|
{
|
|
return new RobustServerSimulation();
|
|
}
|
|
}
|
|
}
|