using JetBrains.Annotations; using Moq; using Robust.Shared.Asynchronous; using Robust.Shared.Configuration; 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.Physics; using Robust.Shared.Prototypes; using Robust.Shared.Reflection; using Robust.Shared.Serialization; using Robust.Shared.Serialization.Manager; using Robust.Shared.Serialization.Manager.Attributes; using Robust.Shared.Serialization.TypeSerializers.Implementations; using Robust.Shared.Timing; namespace Robust.UnitTesting.Server { [PublicAPI] internal interface ISimulationFactory { ISimulationFactory RegisterComponents(CompRegistrationDelegate factory); ISimulationFactory RegisterDependencies(DiContainerDelegate factory); ISimulationFactory RegisterEntitySystems(EntitySystemRegistrationDelegate factory); ISimulationFactory RegisterPrototypes(PrototypeRegistrationDelegate factory); ISimulation InitializeInstance(); } [PublicAPI] internal interface ISimulation { IDependencyCollection Collection { get; } /// /// Resolves a dependency directly out of IoC collection. /// T Resolve(); /// /// Adds a new map directly to the map manager. /// EntityUid AddMap(int mapId); EntityUid AddMap(MapId mapId); IEntity SpawnEntity(string? protoId, EntityCoordinates coordinates); IEntity SpawnEntity(string? protoId, MapCoordinates coordinates); } internal delegate void DiContainerDelegate(IDependencyCollection diContainer); internal delegate void CompRegistrationDelegate(IComponentFactory factory); internal delegate void EntitySystemRegistrationDelegate(IEntitySystemManager systemMan); internal delegate void PrototypeRegistrationDelegate(IPrototypeManager protoMan); internal 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() { return Collection.Resolve(); } public EntityUid AddMap(int mapId) { var mapMan = Collection.Resolve(); mapMan.CreateMap(new MapId(mapId)); return mapMan.GetMapEntityId(new MapId(mapId)); } public EntityUid AddMap(MapId mapId) { var mapMan = Collection.Resolve(); mapMan.CreateMap(mapId); return mapMan.GetMapEntityId(mapId); } public IEntity SpawnEntity(string? protoId, EntityCoordinates coordinates) { var entMan = Collection.Resolve(); return entMan.SpawnEntity(protoId, coordinates); } public IEntity SpawnEntity(string? protoId, MapCoordinates coordinates) { var entMan = Collection.Resolve(); 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(); container.Register(); container.Register(); container.Register(); container.Register(); container.Register(); container.Register(); container.Register(); container.RegisterInstance(new Mock().Object); var reflectionManager = new Mock(); reflectionManager .Setup(x => x.FindTypesWithAttribute()) .Returns(() => new[] { typeof(DataDefinitionAttribute) }); reflectionManager .Setup(x => x.FindTypesWithAttribute(typeof(DataDefinitionAttribute))) .Returns(() => new[] { typeof(EntityPrototype), typeof(TransformComponent), typeof(MetaDataComponent) }); reflectionManager .Setup(x => x.FindTypesWithAttribute()) .Returns(() => new[] {typeof(StringSerializer)}); container.RegisterInstance(reflectionManager.Object); // tests should not be searching for types container.RegisterInstance(new Mock().Object); container.RegisterInstance(new Mock().Object); // no disk access for tests container.RegisterInstance(new Mock().Object); // TODO: get timing working similar to RobustIntegrationTest //Tier 2: Simulation container.Register(); container.Register(); container.Register(); container.Register(); container.Register(); container.Register(); container.Register(); container.Register(); container.Register(); container.Register(); container.RegisterInstance(new Mock().Object); // TODO: get timing working similar to RobustIntegrationTest _diFactory?.Invoke(container); container.BuildGraph(); var logMan = container.Resolve(); logMan.RootSawmill.AddHandler(new TestLogHandler("SIM")); var compFactory = container.Resolve(); compFactory.RegisterClass(); compFactory.RegisterClass(); compFactory.RegisterClass(); compFactory.RegisterClass(); compFactory.RegisterClass(); _regDelegate?.Invoke(compFactory); var entityMan = container.Resolve(); entityMan.Initialize(); IoCManager.Resolve().Initialize(); _systemDelegate?.Invoke(container.Resolve()); entityMan.Startup(); var mapManager = container.Resolve(); mapManager.Initialize(); mapManager.Startup(); container.Resolve().Initialize(); var protoMan = container.Resolve(); protoMan.RegisterType(typeof(EntityPrototype)); _protoDelegate?.Invoke(protoMan); protoMan.Resync(); return this; } public static ISimulationFactory NewSimulation() { return new RobustServerSimulation(); } } }