IoC property-based field injection. (#258)

* IoC Field Injection base changes. Usages not converted yet.

* Fix issues with the csproj file.

* Work on converting the client.

* We're done here. All implemented and good.
This commit is contained in:
Pieter-Jan Briers
2017-07-06 09:06:52 +02:00
committed by Silver
parent eefa09f93b
commit 7df089bebe
56 changed files with 559 additions and 475 deletions

View File

@@ -5,6 +5,8 @@ using SS14.Client.Graphics;
using SS14.Client.Graphics.Event;
using SS14.Client.Graphics.Render;
using SS14.Client.Interfaces.Input;
using SS14.Client.Interfaces.Map;
using SS14.Client.Interfaces.MessageLogging;
using SS14.Client.Interfaces.Network;
using SS14.Client.Interfaces.Resource;
using SS14.Client.Interfaces.State;
@@ -13,6 +15,7 @@ using SS14.Client.Interfaces;
using SS14.Client.State.States;
using SS14.Shared.Interfaces.Configuration;
using SS14.Shared.Configuration;
using SS14.Shared.GameObjects;
using SS14.Shared.IoC;
using SS14.Shared.Log;
using SS14.Shared.Utility;
@@ -28,13 +31,25 @@ namespace SS14.Client
{
#region Fields
[Dependency]
readonly private IConfigurationManager _configurationManager;
// private Input _input;
[Dependency]
readonly private INetworkGrapher _netGrapher;
[Dependency]
readonly private INetworkManager _networkManager;
[Dependency]
readonly private IStateManager _stateManager;
[Dependency]
readonly private IUserInterfaceManager _userInterfaceManager;
[Dependency]
readonly private IResourceManager _resourceManager;
[Dependency]
readonly private IMessageLogger _messageLogger;
[Dependency]
readonly private IEntityNetworkManager _entityNetworkManager;
[Dependency]
readonly private ITileDefinitionManager _tileDefinitionManager;
private SFML.System.Clock _clock;
@@ -43,22 +58,6 @@ namespace SS14.Client
#region Methods
#region Constructors
public GameController(IConfigurationManager configManager,
INetworkGrapher networkGrapher,
INetworkManager networkManager,
IStateManager stateManager,
IUserInterfaceManager userInterfaceManager,
IResourceManager resourceManager)
{
_configurationManager = configManager;
_netGrapher = networkGrapher;
_networkManager = networkManager;
_stateManager = stateManager;
_userInterfaceManager = userInterfaceManager;
_resourceManager = resourceManager;
}
public void Run()
{
Logger.Debug("Initialising GameController.");
@@ -75,6 +74,10 @@ namespace SS14.Client
CleanupSplashScreen();
//Initialization of private members
_messageLogger.Initialize();
_entityNetworkManager.Initialize();
_tileDefinitionManager.InitializeResources();
var prototypeManager = IoCManager.Resolve<IPrototypeManager>();
prototypeManager.LoadDirectory(PathHelpers.ExecutableRelativeFile("Prototypes"));
prototypeManager.Resync();

View File

@@ -13,18 +13,22 @@ using System.IO;
namespace SS14.Client.GameObjects
{
public class EntityNetworkManager : IEntityNetworkManager
public class EntityNetworkManager : IEntityNetworkManager, IPostInjectInit
{
private readonly bool _messageProfiling;
private bool _messageProfiling = false;
[Dependency]
private readonly INetworkManager _networkManager;
[Dependency]
private readonly IConfigurationManager _configManager;
public EntityNetworkManager(INetworkManager networkManager)
public void PostInject()
{
_networkManager = networkManager;
_configManager.RegisterCVar("ent.logging", false);
}
var config = IoCManager.Resolve<IConfigurationManager>();
config.RegisterCVar("ent.logging", false);
_messageProfiling = config.GetCVar<bool>("ent.logging");
public void Initialize()
{
_messageProfiling = _configManager.GetCVar<bool>("ent.logging");
}
#region IEntityNetworkManager Members

View File

@@ -1,10 +1,12 @@
using SFML.System;
using SS14.Client.Graphics.Sprite;
using SS14.Client.Interfaces.Resource;
namespace SS14.Client.Interfaces.Map
{
public interface ITileDefinition
{
void InitializeResources(IResourceManager resourceManager);
ushort TileId { get; }
void InvalidateTileId();

View File

@@ -6,6 +6,7 @@ namespace SS14.Client.Interfaces.Map
{
public interface ITileDefinitionManager : IEnumerable<ITileDefinition>
{
void InitializeResources();
ushort Register(ITileDefinition tileDef);
void RegisterServerTileMapping(NetIncomingMessage message);

View File

@@ -6,6 +6,7 @@ namespace SS14.Client.Interfaces.MessageLogging
{
public interface IMessageLogger
{
void Initialize();
void LogOutgoingComponentNetMessage(int uid, ComponentFamily family, object[] parameters);
void LogIncomingComponentNetMessage(int uid, EntityMessage entityMessage, ComponentFamily componentFamily,

View File

@@ -11,8 +11,10 @@ namespace SS14.Client.Map
[System.Diagnostics.DebuggerDisplay("TileDef: {Name}")]
public sealed class SpaceTileDefinition : ITileDefinition
{
public static readonly ITileDefinition Instance = new SpaceTileDefinition();
private SpaceTileDefinition() { }
public void InitializeResources(IResourceManager resourceManager)
{
tileSprite = resourceManager.GetSprite("space_texture");
}
public ushort TileId { get { return 0; } }
public void InvalidateTileId() { }
@@ -32,9 +34,6 @@ namespace SS14.Client.Map
public void Render(float xTopLeft, float yTopLeft, SpriteBatch batch)
{
if (tileSprite == null)
tileSprite = IoCManager.Resolve<IResourceManager>().GetSprite("space_texture");
tileSprite.Position = new SFML.System.Vector2f(xTopLeft, yTopLeft);
batch.Draw(tileSprite);
}
@@ -73,8 +72,11 @@ namespace SS14.Client.Map
IsGasVolume = true;
IsVentedIntoSpace = false;
IsWall = false;
}
tileSprite = IoCManager.Resolve<IResourceManager>().GetSprite("floor_texture");
public override void InitializeResources(IResourceManager resourceManager)
{
tileSprite = resourceManager.GetSprite("floor_texture");
}
}
@@ -92,11 +94,6 @@ namespace SS14.Client.Map
IsGasVolume = false;
IsVentedIntoSpace = false;
IsWall = true;
tileSprite = IoCManager.Resolve<IResourceManager>().GetSprite("wall_texture");
var bounds = tileSprite.GetLocalBounds();
shape = new RectangleShape(new SFML.System.Vector2f(bounds.Width, bounds.Height));
}
public override void RenderPos(float x, float y)
@@ -105,5 +102,12 @@ namespace SS14.Client.Map
shape.Position = new SFML.System.Vector2f(x, y);
shape.Draw(CluwneLib.CurrentRenderTarget, RenderStates.Default);
}
public override void InitializeResources(IResourceManager resourceManager)
{
tileSprite = resourceManager.GetSprite("wall_texture");
var bounds = tileSprite.GetLocalBounds();
shape = new RectangleShape(new SFML.System.Vector2f(bounds.Width, bounds.Height));
}
}
}

View File

@@ -2,6 +2,7 @@ using SFML.Graphics;
using SFML.System;
using SS14.Client.Graphics.Sprite;
using SS14.Client.Interfaces.Map;
using SS14.Client.Interfaces.Resource;
using SS14.Shared.IoC;
using System.Diagnostics;
@@ -68,5 +69,10 @@ namespace SS14.Client.Map
public void RenderTop(float xTopLeft, float yTopLeft, SpriteBatch wallTopsBatch)
{
}
public virtual void InitializeResources(IResourceManager resourceManager)
{
}
}
}

View File

@@ -1,5 +1,6 @@
using Lidgren.Network;
using SS14.Client.Interfaces.Map;
using SS14.Client.Interfaces.Resource;
using System;
using System.Collections.Generic;
using SS14.Shared.IoC;
@@ -8,17 +9,27 @@ namespace SS14.Client.Map
{
public sealed class TileDefinitionManager : ITileDefinitionManager
{
[Dependency]
private readonly IResourceManager resourceManager;
List<ITileDefinition> tileDefs = new List<ITileDefinition>();
Dictionary<string, ITileDefinition> tileNames = new Dictionary<string, ITileDefinition>();
Dictionary<ITileDefinition, ushort> tileIds = new Dictionary<ITileDefinition, ushort>();
public TileDefinitionManager()
{
Register(SpaceTileDefinition.Instance);
Register(new SpaceTileDefinition());
Register(new FloorTileDefinition());
Register(new WallTileDefinition());
}
public void InitializeResources()
{
foreach (var item in tileDefs)
{
item.InitializeResources(resourceManager);
}
}
public ushort Register(ITileDefinition tileDef)
{
ushort id;

View File

@@ -11,16 +11,17 @@ namespace SS14.Client.MessageLogging
{
public class MessageLogger : IMessageLogger
{
private readonly Timer _pingTimer;
private readonly MessageLoggerServiceClient _loggerServiceClient;
[Dependency]
private readonly IConfigurationManager _configurationManager;
private Timer _pingTimer;
private MessageLoggerServiceClient _loggerServiceClient;
private bool _logging;
public MessageLogger(IConfigurationManager _configurationManager)
public void Initialize()
{
_logging = _configurationManager.GetCVar<bool>("log.enabled");
_loggerServiceClient = new MessageLoggerServiceClient("NetNamedPipeBinding_IMessageLoggerService");
if (_logging)
{
_loggerServiceClient = new MessageLoggerServiceClient("NetNamedPipeBinding_IMessageLoggerService");
Ping();
_pingTimer = new Timer(5000);
_pingTimer.Elapsed += CheckServer;

View File

@@ -14,7 +14,9 @@ namespace SS14.Client.Network
{
private const int MaxDataPoints = 200;
private readonly List<NetworkStatisticsDataPoint> _dataPoints = new List<NetworkStatisticsDataPoint>();
[Dependency]
private readonly INetworkManager _networkManager;
[Dependency]
private readonly IResourceManager _resourceManager;
private TextSprite _textSprite;
private bool _enabled;
@@ -22,10 +24,8 @@ namespace SS14.Client.Network
private int _lastRecievedBytes;
private int _lastSentBytes;
public NetworkGrapher(IResourceManager resourceManager, INetworkManager networkManager)
public NetworkGrapher()
{
_resourceManager = resourceManager;
_networkManager = networkManager;
_lastDataPointTime = DateTime.Now;
}

View File

@@ -26,9 +26,13 @@ namespace SS14.Client.Placement
{
public class PlacementManager : IPlacementManager
{
[Dependency]
public readonly ICollisionManager CollisionManager;
[Dependency]
public readonly INetworkManager NetworkManager;
[Dependency]
public readonly IPlayerManager PlayerManager;
[Dependency]
public readonly IResourceManager ResourceManager;
private readonly Dictionary<string, Type> _modeDictionary = new Dictionary<string, Type>();
@@ -40,14 +44,8 @@ namespace SS14.Client.Placement
public Direction Direction = Direction.South;
public bool ValidPosition;
public PlacementManager(IResourceManager resourceManager, INetworkManager networkManager,
ICollisionManager collisionManager, IPlayerManager playerManager)
public PlacementManager()
{
ResourceManager = resourceManager;
NetworkManager = networkManager;
CollisionManager = collisionManager;
PlayerManager = playerManager;
Type type = typeof(PlacementMode);
List<Assembly> assemblies = AppDomain.CurrentDomain.GetAssemblies().ToList();
List<Type> types = assemblies.SelectMany(t => t.GetTypes()).Where(p => type.IsAssignableFrom(p)).ToList();

View File

@@ -24,14 +24,10 @@ namespace SS14.Client.Player
* This class also communicates with the server to let the server control what entity it is attached to. */
private readonly List<PostProcessingEffect> _effects = new List<PostProcessingEffect>();
[Dependency]
private readonly INetworkManager _networkManager;
private SessionStatus status = SessionStatus.Zombie;
public PlayerManager(INetworkManager networkManager)
{
_networkManager = networkManager;
}
#region IPlayerManager Members
public event EventHandler<TypeEventArgs> RequestedStateSwitch;

View File

@@ -99,6 +99,8 @@ namespace SS14.Client
IoCManager.Register<IEntityNetworkManager, EntityNetworkManager>();
IoCManager.Register<IPlayerManager, PlayerManager>();
IoCManager.Register<IGameController, GameController>();
IoCManager.BuildGraph();
}
private static void LoadAssemblies()

View File

@@ -6,6 +6,7 @@ using SS14.Client.Graphics.Collection;
using SS14.Client.Graphics.Shader;
using SS14.Client.Graphics.Sprite;
using SS14.Client.Interfaces.Resource;
using SS14.Shared.IoC;
using SS14.Shared.GameObjects;
using SS14.Shared.Interfaces.Configuration;
using SS14.Shared.Log;
@@ -28,6 +29,7 @@ namespace SS14.Client.Resources
private const int zipBufferSize = 4096;
private MemoryStream VertexShader, FragmentShader;
[Dependency]
private readonly IConfigurationManager _configurationManager;
private readonly Dictionary<string, Font> _fonts = new Dictionary<string, Font>();
private readonly Dictionary<string, ParticleSettings> _particles = new Dictionary<string, ParticleSettings>();
@@ -45,11 +47,6 @@ namespace SS14.Client.Resources
public int done = 0;
public ResourceManager(IConfigurationManager configurationManager)
{
_configurationManager = configurationManager;
}
#region Resource Loading & Disposal
/// <summary>
@@ -94,7 +91,7 @@ namespace SS14.Client.Resources
{
var cfgMgr = _configurationManager;
cfgMgr.RegisterCVar("res.pack", @"..\..\Resources\ResourcePack.zip", CVarFlags.ARCHIVE);
cfgMgr.RegisterCVar("res.pack", @"../../Resources/ResourcePack.zip", CVarFlags.ARCHIVE);
cfgMgr.RegisterCVar("res.password", String.Empty, CVarFlags.SERVER | CVarFlags.REPLICATED);
string zipPath = path ?? _configurationManager.GetCVar<string>("res.pack");

View File

@@ -42,6 +42,7 @@
<UseApplicationTrust>false</UseApplicationTrust>
<BootstrapperEnabled>true</BootstrapperEnabled>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<NoWarn>0649</NoWarn>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
<AllowUnsafeBlocks>False</AllowUnsafeBlocks>
@@ -61,8 +62,6 @@
<TreatWarningsAsErrors>False</TreatWarningsAsErrors>
<WarningLevel>4</WarningLevel>
<NoStdLib>False</NoStdLib>
<NoWarn>
</NoWarn>
<PlatformTarget>x86</PlatformTarget>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
@@ -84,8 +83,6 @@
<TreatWarningsAsErrors>False</TreatWarningsAsErrors>
<WarningLevel>4</WarningLevel>
<NoStdLib>False</NoStdLib>
<NoWarn>
</NoWarn>
<PlatformTarget>x86</PlatformTarget>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
@@ -447,4 +444,4 @@
<PropertyGroup>
<DefineConstants Condition="Exists('Microsoft.VisualStudio.DebuggerVisualizers.dll') ">$(DefineConstants);VS_DEBUGGERVISUALIZERS_EXISTS</DefineConstants>
</PropertyGroup>
</Project>
</Project>

View File

@@ -9,6 +9,7 @@ using SS14.Client.Interfaces.Resource;
using SS14.Client.Interfaces.State;
using SS14.Client.Interfaces.UserInterface;
using SS14.Shared;
using SS14.Shared.IoC;
using SS14.Shared.Interfaces.Configuration;
using System;
using System.Collections.Generic;
@@ -16,45 +17,49 @@ using KeyEventArgs = SFML.Window.KeyEventArgs;
namespace SS14.Client.State
{
public class StateManager : IStateManager
public class StateManager : IStateManager, IPostInjectInit
{
private readonly Dictionary<Type, IState> _loadedStates;
private readonly Dictionary<Type, object> _managers;
[Dependency]
private readonly IConfigurationManager configurationManager;
[Dependency]
private readonly INetworkManager networkManager;
[Dependency]
private readonly IUserInterfaceManager userInterfaceManager;
[Dependency]
private readonly IResourceManager resourceManager;
[Dependency]
private readonly IMapManager mapManager;
[Dependency]
private readonly IPlayerManager playerManager;
[Dependency]
private readonly IPlacementManager placementManager;
[Dependency]
private readonly IKeyBindingManager keyBindingManager;
private readonly Dictionary<Type, IState> _loadedStates = new Dictionary<Type, IState>();
private readonly Dictionary<Type, object> _managers = new Dictionary<Type, object>();
#region IStateManager Members
public IState CurrentState { get; private set; }
public IState CurrentState { get; private set; } = null;
#endregion
#region Constructor
public StateManager(IConfigurationManager configurationManager, INetworkManager networkManager,
IUserInterfaceManager userInterfaceManager,
IResourceManager resourceManager, IMapManager mapManager, IPlayerManager playerManager,
IPlacementManager placementManager, IKeyBindingManager keyBindingManager)
public void PostInject()
{
_managers = new Dictionary<Type, object>
{
{typeof (INetworkManager), networkManager},
{typeof (IUserInterfaceManager), userInterfaceManager},
{typeof (IResourceManager), resourceManager},
{typeof (IMapManager), mapManager},
{typeof (IPlayerManager), playerManager},
{typeof (IConfigurationManager), configurationManager},
{typeof (IPlacementManager), placementManager},
{typeof (IKeyBindingManager), keyBindingManager},
{typeof (IStateManager), this}
};
_loadedStates = new Dictionary<Type, IState>();
CurrentState = null;
_managers[typeof(INetworkManager)] = networkManager;
_managers[typeof(IUserInterfaceManager)] = userInterfaceManager;
_managers[typeof(IResourceManager)] = resourceManager;
_managers[typeof(IMapManager)] = mapManager;
_managers[typeof(IPlayerManager)] = playerManager;
_managers[typeof(IPlacementManager)] = placementManager;
_managers[typeof(IKeyBindingManager)] = keyBindingManager;
_managers[typeof(IConfigurationManager)] = configurationManager;
_managers[typeof(IStateManager)] = this;
playerManager.RequestedStateSwitch += HandleStateChange;
}
#endregion
#region Input
public void KeyDown(KeyEventArgs e)

View File

@@ -9,6 +9,7 @@ using SS14.Client.Interfaces.Resource;
using SS14.Client.Interfaces.UserInterface;
using SS14.Client.UserInterface.Components;
using SS14.Shared;
using SS14.Shared.IoC;
using SS14.Shared.Interfaces.Configuration;
using SS14.Shared.Maths;
using System;
@@ -22,14 +23,16 @@ namespace SS14.Client.UserInterface
/// <summary>
/// Manages UI Components. This includes input, rendering, updates and net messages.
/// </summary>
public class UserInterfaceManager : IUserInterfaceManager
public class UserInterfaceManager : IUserInterfaceManager, IPostInjectInit
{
/// <summary>
/// List of iGuiComponents. Components in this list will recieve input, updates and net messages.
/// </summary>
private readonly List<IGuiComponent> _components;
private readonly List<IGuiComponent> _components = new List<IGuiComponent>();
[Dependency]
private readonly IConfigurationManager _config;
[Dependency]
private readonly IResourceManager _resourceManager;
private IGuiComponent _currentFocus;
private Sprite _cursorSprite;
@@ -40,18 +43,9 @@ namespace SS14.Client.UserInterface
private IGuiComponent movingComp;
private bool showCursor = true;
/// <summary>
/// Currently targeting action.
/// </summary>
public UserInterfaceManager(IResourceManager resourceManager, IConfigurationManager config)
public void PostInject()
{
config.RegisterCVar("key.keyboard.console", Keyboard.Key.Home, CVarFlags.ARCHIVE);
_resourceManager = resourceManager;
DragInfo = new DragDropInfo();
_components = new List<IGuiComponent>();
_config = config;
_config.RegisterCVar("key.keyboard.console", Keyboard.Key.Home, CVarFlags.ARCHIVE);
}
public void Initialize()
@@ -64,7 +58,7 @@ namespace SS14.Client.UserInterface
#region IUserInterfaceManager Members
public IDragDropInfo DragInfo { get; private set; }
public IDragDropInfo DragInfo { get; private set; } = new DragDropInfo();
public IDebugConsole Console => _console;

View File

@@ -22,8 +22,11 @@ namespace SS14.Server.Chat
{
public class ChatManager : IChatManager
{
private ISS14Server _serverMain;
[Dependency]
private readonly ISS14Server _serverMain;
[Dependency]
private readonly IReflectionManager reflectionManager;
[Dependency]
private readonly IServerEntityManager entityManager;
private Dictionary<string, Emote> _emotes = new Dictionary<string, Emote>();
@@ -32,17 +35,10 @@ namespace SS14.Server.Chat
public IDictionary<string, IChatCommand> Commands => _commands;
public ChatManager(IServerEntityManager entityManager, IReflectionManager reflectionManager)
{
this.entityManager = entityManager;
this.reflectionManager = reflectionManager;
}
#region IChatManager Members
public void Initialize(ISS14Server server)
public void Initialize()
{
_serverMain = server;
LoadEmotes();
LoadCommands();
}

View File

@@ -17,8 +17,10 @@ using System;
namespace SS14.Server.ClientConsoleHost
{
public class ClientConsoleHost : IClientConsoleHost
public class ClientConsoleHost : IClientConsoleHost, IPostInjectInit
{
[Dependency]
private readonly IReflectionManager reflectionManager;
private Dictionary<string, IClientCommand> availableCommands = new Dictionary<string, IClientCommand>();
public IDictionary<string, IClientCommand> AvailableCommands => availableCommands;
@@ -38,9 +40,9 @@ namespace SS14.Server.ClientConsoleHost
netMgr.SendMessage(message, senderConnection);
}
public ClientConsoleHost(IReflectionManager reflactionManager)
public void PostInject()
{
foreach (Type type in reflactionManager.GetAllChildren<IClientCommand>())
foreach (Type type in reflectionManager.GetAllChildren<IClientCommand>())
{
var instance = Activator.CreateInstance(type, null) as IClientCommand;
if (AvailableCommands.ContainsKey(instance.Command))

View File

@@ -17,12 +17,12 @@ namespace SS14.Server.GameObjects
{
public class EntityNetworkManager : IEntityNetworkManager
{
private readonly bool _messageProfiling;
private bool _messageProfiling = false;
[Dependency]
private readonly ISS14NetServer m_netServer;
public EntityNetworkManager(ISS14NetServer netServer)
public void Initialize()
{
m_netServer = netServer;
_messageProfiling = IoCManager.Resolve<IConfigurationManager>().GetCVar<bool>("log.enabled");
}

View File

@@ -9,7 +9,7 @@ namespace SS14.Server.Interfaces.Chat
{
void SendChatMessage(ChatChannel channel, string text, string name, int? entityID);
void SendPrivateMessage(IClient client, ChatChannel channel, string text, string name, int? entityId);
void Initialize(ISS14Server server);
void Initialize();
void HandleNetMessage(NetIncomingMessage message);
IDictionary<string, IChatCommand> Commands { get; }

View File

@@ -11,6 +11,7 @@ namespace SS14.Server.Interfaces.Map
public interface IMapManager
{
void Initialize();
bool LoadMap(string mapName);
void SaveMap(string mapName);

View File

@@ -6,6 +6,7 @@ namespace SS14.Server.Interfaces.MessageLogging
{
public interface IMessageLogger
{
void Initialize();
void LogOutgoingComponentNetMessage(long clientUID, int uid, ComponentFamily family, object[] parameters);
void LogIncomingComponentNetMessage(long clientUID, int uid, EntityMessage entityMessage,

View File

@@ -80,7 +80,7 @@ namespace SS14.Server.Log
return;
}
if (disposing)
if (disposing && logStream != null)
{
logStream.Dispose();
logStream = null;

View File

@@ -28,6 +28,10 @@ namespace SS14.Server.Map
public MapManager()
{
tileIndexer = new TileCollection(this);
}
public void Initialize()
{
NewMap();
}

View File

@@ -11,16 +11,19 @@ namespace SS14.Server.MessageLogging
{
public class MessageLogger : IMessageLogger
{
private readonly Timer _pingTimer;
private readonly MessageLoggerServiceClient _loggerServiceClient;
private bool _logging;
[Dependency]
private readonly IConfigurationManager _configurationManager;
private Timer _pingTimer;
private MessageLoggerServiceClient _loggerServiceClient;
private bool _logging = false;
public MessageLogger(IConfigurationManager _configurationManager)
public void Initialize()
{
_logging = _configurationManager.GetCVar<bool>("log.enabled");
_loggerServiceClient = new MessageLoggerServiceClient("NetNamedPipeBinding_IMessageLoggerService");
if (_logging)
{
_loggerServiceClient = new MessageLoggerServiceClient("NetNamedPipeBinding_IMessageLoggerService");
Ping();
_pingTimer = new Timer(5000);
_pingTimer.Elapsed += CheckServer;

View File

@@ -109,6 +109,8 @@ namespace SS14.Server
IoCManager.Register<IReflectionManager, ServerReflectionManager>();
IoCManager.Register<IClientConsoleHost, ClientConsoleHost.ClientConsoleHost>();
IoCManager.Register<IPlayerManager, PlayerManager>();
IoCManager.BuildGraph();
}
// TODO: Move to the main server so we can have proper logging and stuff.

View File

@@ -27,6 +27,7 @@
</FileUpgradeFlags>
<TargetFrameworkProfile />
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<NoWarn>0649</NoWarn>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
<AllowUnsafeBlocks>False</AllowUnsafeBlocks>
@@ -46,8 +47,6 @@
<TreatWarningsAsErrors>False</TreatWarningsAsErrors>
<WarningLevel>4</WarningLevel>
<NoStdLib>False</NoStdLib>
<NoWarn>
</NoWarn>
<PlatformTarget>x86</PlatformTarget>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
@@ -69,8 +68,6 @@
<TreatWarningsAsErrors>False</TreatWarningsAsErrors>
<WarningLevel>4</WarningLevel>
<NoStdLib>False</NoStdLib>
<NoWarn>
</NoWarn>
<PlatformTarget>x86</PlatformTarget>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
@@ -343,4 +340,4 @@
<PostBuildEvent>
</PostBuildEvent>
</PropertyGroup>
</Project>
</Project>

View File

@@ -79,11 +79,8 @@ namespace SS14.Server
private int lastRecievedBytes;
private int lastSentBytes;
public SS14Server(ICommandLineArgs args, IServerLogManager logManager)
public bool Start()
{
LogManager = logManager;
Runlevel = RunLevel.Init;
var configMgr = IoCManager.Resolve<IConfigurationManager>();
configMgr.LoadFromFile(PathHelpers.ExecutableRelativeFile("server_config.toml"));
@@ -113,8 +110,24 @@ namespace SS14.Server
TickRate = configMgr.GetCVar<int>("net.tickrate");
ServerRate = 1000.0f / TickRate;
EntityManager = IoCManager.Resolve<IServerEntityManager>();
ComponentManager = IoCManager.Resolve<IComponentManager>();
Time = DateTime.Now;
LoadSettings();
var prototypeManager = IoCManager.Resolve<IPrototypeManager>();
prototypeManager.LoadDirectory(PathHelpers.ExecutableRelativeFile("Prototypes"));
prototypeManager.Resync();
IoCManager.Resolve<ISS14NetServer>().Start();
IoCManager.Resolve<IChatManager>().Initialize();
IoCManager.Resolve<IPlayerManager>().Initialize(this);
IoCManager.Resolve<IPlacementManager>().Initialize(this);
IoCManager.Resolve<IMapManager>().Initialize();
StartLobby();
StartGame();
_active = true;
return false;
}
public float ServerRate // desired server frame (tick) time in milliseconds
@@ -127,10 +140,13 @@ namespace SS14.Server
#region ISS13Server Members
[Dependency]
private readonly IServerEntityManager EntityManager;
[Dependency]
private readonly IComponentManager ComponentManager;
[Dependency]
private readonly IServerLogManager LogManager;
public RunLevel Runlevel { get; private set; }
public RunLevel Runlevel { get; private set; } = RunLevel.Init;
public void Restart()
{
@@ -510,27 +526,6 @@ namespace SS14.Server
}
}
public bool Start()
{
Time = DateTime.Now;
LoadSettings();
var prototypeManager = IoCManager.Resolve<IPrototypeManager>();
prototypeManager.LoadDirectory(PathHelpers.ExecutableRelativeFile("Prototypes"));
prototypeManager.Resync();
IoCManager.Resolve<ISS14NetServer>().Start();
IoCManager.Resolve<IChatManager>().Initialize(this);
IoCManager.Resolve<IPlayerManager>().Initialize(this);
IoCManager.Resolve<IPlacementManager>().Initialize(this);
StartLobby();
StartGame();
_active = true;
return false;
}
public void StartLobby()
{
IoCManager.Resolve<IRoundManager>().Initialize(new Gamemode(this));

View File

@@ -9,20 +9,17 @@ using SS14.Shared.Interfaces.Reflection;
namespace SS14.Shared.GameObjects
{
public class ComponentFactory : IComponentFactory
public class ComponentFactory : IComponentFactory, IPostInjectInit
{
[Dependency]
private readonly IReflectionManager ReflectionManager;
private readonly Dictionary<string, Type> componentNames;
private readonly Dictionary<string, Type> componentNames = new Dictionary<string, Type>();
public ComponentFactory(IReflectionManager reflectionManager)
public void PostInject()
{
ReflectionManager = reflectionManager;
componentNames = new Dictionary<string, Type>();
ReloadComponents();
reflectionManager.OnAssemblyAdded += (_, __) => ReloadComponents();
ReflectionManager.OnAssemblyAdded += (_, __) => ReloadComponents();
}
/// <summary>
@@ -76,9 +73,9 @@ namespace SS14.Shared.GameObjects
throw new InvalidImplementationException(type, typeof(IComponent), "Does not have a " + nameof(IComponent.Name));
}
if (componentNames.ContainsKey(instance.Name))
if (componentNames.TryGetValue(instance.Name, out Type duplicate))
{
throw new InvalidImplementationException(type, typeof(IComponent), "Duplicate Name for component: " + instance.Name);
throw new InvalidImplementationException(type, typeof(IComponent), $"Duplicate Name for component: {instance.Name}, previous: {duplicate}");
}
componentNames[instance.Name] = type;

View File

@@ -11,10 +11,15 @@ namespace SS14.Shared.GameObjects
public class EntityManager : IEntityManager
{
#region Dependencies
[Dependency]
protected readonly IEntityNetworkManager EntityNetworkManager;
[Dependency]
protected readonly IPrototypeManager PrototypeManager;
[Dependency]
protected readonly IEntitySystemManager EntitySystemManager;
[Dependency]
protected readonly IComponentFactory ComponentFactory;
[Dependency]
protected readonly IComponentManager ComponentManager;
# endregion Dependencies
@@ -37,15 +42,6 @@ namespace SS14.Shared.GameObjects
ComponentFamily.Mover
};
public EntityManager()
{
EntitySystemManager = IoCManager.Resolve<IEntitySystemManager>();
ComponentFactory = IoCManager.Resolve<IComponentFactory>();
EntityNetworkManager = IoCManager.Resolve<IEntityNetworkManager>();
ComponentManager = IoCManager.Resolve<IComponentManager>();
PrototypeManager = IoCManager.Resolve<IPrototypeManager>();
}
public bool Initialized { get; protected set; }
#region IEntityManager Members

View File

@@ -1,6 +1,5 @@
using Lidgren.Network;
using NetSerializer;
using SS14.Shared.GameObjects.Exceptions;
using SS14.Shared.Interfaces.GameObjects;
using SS14.Shared.Interfaces.GameObjects.System;
using SS14.Shared.Interfaces.Reflection;
@@ -14,6 +13,7 @@ namespace SS14.Shared.GameObjects
{
public class EntitySystemManager : IEntitySystemManager
{
[Dependency]
private readonly IReflectionManager ReflectionManager;
/// <summary>
/// Maps system types to instances.
@@ -25,11 +25,6 @@ namespace SS14.Shared.GameObjects
/// </summary>
private readonly Dictionary<Type, IEntitySystem> SystemMessageTypes = new Dictionary<Type, IEntitySystem>();
public EntitySystemManager(IReflectionManager reflectionManager)
{
ReflectionManager = reflectionManager;
}
/// <exception cref="InvalidOperationException">Thrown if the specified type is already registered by another system.</exception>
/// <exception cref="InvalidEntitySystemException">Thrown if the entity system instance is not registered with this <see cref="EntitySystemManager"/></exception>
/// <exception cref="ArgumentNullException">Thrown if the provided system is null.</exception>

View File

@@ -1,19 +0,0 @@
using System;
namespace SS14.Shared.GameObjects.Exceptions
{
internal class MissingImplementationException : Exception
{
private readonly Type _type;
public MissingImplementationException(Type type)
{
_type = type;
}
public override string Message
{
get { return String.Format("There is no concrete implementation for type {0}.", _type); }
}
}
}

View File

@@ -1,19 +0,0 @@
using System;
namespace SS14.Shared.GameObjects.Exceptions
{
internal class NoPublicConstructorException : Exception
{
private readonly Type _type;
public NoPublicConstructorException(Type type)
{
_type = type;
}
public override string Message
{
get { return String.Format("Type {0} does not have a public constructor.", _type); }
}
}
}

View File

@@ -6,6 +6,8 @@ namespace SS14.Shared.GameObjects
{
public interface IEntityNetworkManager
{
void Initialize();
NetOutgoingMessage CreateEntityMessage();
/// <summary>

View File

@@ -0,0 +1,26 @@
using System;
namespace SS14.Shared.IoC
{
/// <summary>
/// Specifies that the field this is applied to is a dependency,
/// which will be resolved by <see cref="IoCManager" /> when the containing class is instantiated.
/// </summary>
/// <remarks>
/// <para>
/// The dependency is resolved as if <see cref="IoCManager.Resolve{T}" /> were to be called,
/// but it avoids circular references and init order issues due to internal code in the <see cref="IoCManager" />.
/// </para>
/// <para>
/// The dependency can be injected into read only fields without issues,
/// and as a matter of fact it is recommended to use read only fields.
/// </para>
/// <para>
/// If you would like to run code after the dependencies have been injected, use <see cref="IPostInjectInit" />
/// </para>
/// </remarks>
[AttributeUsage(AttributeTargets.Field, AllowMultiple = false)]
public class DependencyAttribute : Attribute
{
}
}

View File

@@ -1,20 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SS14.Shared.IoC.Exceptions
{
public class CircularDependencyException : Exception
{
public readonly Type type;
// TODO: More detailed saying of how the object graph is screwed up.
public override string Message => string.Format("The type {0} is in a circular dependency reference.", type);
public CircularDependencyException(Type type)
{
this.type = type;
}
}
}

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

View File

@@ -1,19 +0,0 @@
using System;
namespace SS14.Shared.IoC.Exceptions
{
public class MissingImplementationException : Exception
{
private readonly Type _type;
public MissingImplementationException(Type type)
{
_type = type;
}
public override string Message
{
get { return String.Format("There is no concrete implementation for type {0}.", _type); }
}
}
}

View File

@@ -1,19 +0,0 @@
using System;
namespace SS14.Shared.IoC.Exceptions
{
public class NoPublicConstructorException : Exception
{
private readonly Type _type;
public NoPublicConstructorException(Type type)
{
_type = type;
}
public override string Message
{
get { return String.Format("Type {0} does not have a public constructor.", _type); }
}
}
}

View File

@@ -0,0 +1,55 @@
using System;
using System.Runtime.Serialization;
namespace SS14.Shared.IoC.Exceptions
{
/// <summary>
/// Like <see cref="UnregisteredTypeException"/>,
/// except that this is thrown when using field injection via <see cref="DependencyAttribute"/> and includes extra metadata.
/// </summary>
[Serializable]
public class UnregisteredDependencyException : Exception
{
/// <summary>
/// The type name of the type requesting the unregistered dependency.
/// </summary>
public readonly string OwnerType;
/// <summary>
/// The type name of the type that was requested and unregistered.
/// </summary>
public readonly string TargetType;
/// <summary>
/// The name of the field that was marked as dependency.
/// </summary>
public readonly string FieldName;
public UnregisteredDependencyException(Type owner, Type target, string fieldName)
: base(string.Format("{0} requested unregistered type with its field {1}: {2}",
owner, target, fieldName))
{
OwnerType = owner.AssemblyQualifiedName;
TargetType = target.AssemblyQualifiedName;
FieldName = fieldName;
}
protected UnregisteredDependencyException(
SerializationInfo info,
StreamingContext context) : base(info, context)
{
OwnerType = info.GetString("OwnerType");
TargetType = info.GetString("TargetType");
FieldName = info.GetString("FieldName");
}
public override void GetObjectData(SerializationInfo info, StreamingContext context)
{
base.GetObjectData(info, context);
info.AddValue("OwnerType", OwnerType);
info.AddValue("TargetType", TargetType);
info.AddValue("FieldName", FieldName);
}
}
}

View File

@@ -0,0 +1,34 @@
using System;
using System.Runtime.Serialization;
namespace SS14.Shared.IoC.Exceptions
{
/// <summary>
/// Thrown by <see cref="IoCManager.Resolve{T}"/> if one attempts to resolve an interface that isn't registered.
/// </summary>
[Serializable]
public class UnregisteredTypeException : Exception
{
/// <summary>
/// The actual type that was attempted to be resolved, but wasn't registered. This is the <see cref="Type.AssemblyQualifiedName"/>.
/// </summary>
public readonly string TypeName;
public UnregisteredTypeException(Type type) : base($"Attempted to resolve unregistered type: {type}")
{
TypeName = type.AssemblyQualifiedName;
}
public UnregisteredTypeException(SerializationInfo info, StreamingContext context) : base(info, context)
{
TypeName = info.GetString("TypeName");
}
public override void GetObjectData(SerializationInfo info, StreamingContext context)
{
base.GetObjectData(info, context);
info.AddValue("TypeName", TypeName);
}
}
}

View File

@@ -0,0 +1,18 @@
namespace SS14.Shared.IoC
{
/// <summary>
/// If implemented on a type instantiated by IoC,
/// <see cref="IPostInjectInit.PostInject" /> will be called after all dependencies have been injected.
/// Do not assume any order in the initialization of other managers,
/// Or the availability of things through <see cref="IoCManager.Resolve{T}" />
/// </summary>
/// <seealso cref="IoCManager" />
/// <seealso cref="DependencyAttribute" />
public interface IPostInjectInit
{
/// <summary>
/// Essentially functions as a constructor after dependencies have been injected.
/// </summary>
void PostInject();
}
}

View File

@@ -3,7 +3,6 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using SS14.Shared.Exceptions;
namespace SS14.Shared.IoC
{
@@ -12,8 +11,8 @@ namespace SS14.Shared.IoC
/// </summary>
/// <remarks>
/// <para>
/// Dependency Injection is a concept where instead of saying "I need the <code>EntityManager</code>",
/// you say "I need something that implements <code>IEntityManager</code>".
/// Dependency Injection is a concept where instead of saying "I need the <c>EntityManager</c>",
/// you say "I need something that implements <c>IEntityManager</c>".
/// This decouples the various systems into swappable components that have standardized interfaces.
/// </para>
/// <para>
@@ -23,7 +22,7 @@ namespace SS14.Shared.IoC
/// </para>
/// <para>
/// To use the IoCManager, it first needs some types registered through <see cref="Register{TInterface, TImplementation}"/>.
/// These implementations can then be fetched with <see cref="Resolve{T}"/>.
/// These implementations can then be fetched with <see cref="Resolve{T}"/>, or through field injection with <see cref="DependencyAttribute" />.
/// </para>
/// </remarks>
/// <seealso cref="Interfaces.Reflection.IReflectionManager"/>
@@ -50,28 +49,34 @@ namespace SS14.Shared.IoC
/// Registers an interface to an implementation, to make it accessible to <see cref="Resolve{T}"/>
/// </summary>
/// <typeparam name="TInterface">The type that will be resolvable.</typeparam>
/// <typeparam name="TImplementation">The type that will be constructed as implementation. Must not be abstract or an interface.</typeparam>
/// <typeparam name="TImplementation">The type that will be constructed as implementation.</typeparam>
/// <param name="overwrite">
/// If true, do not throw an <see cref="InvalidOperationException"/> if an interface is already registered,
/// replace the current implementation instead.
/// </param>
/// <exception cref="InvalidOperationException">
/// Thrown if <paramref name="overwrite"/> is false and <typeparamref name="TInterface"/> has been registered before.
/// Thrown if <paramref name="overwrite"/> is false and <typeparamref name="TInterface"/> has been registered before,
/// or if an already instantiated interface (by <see cref="BuildGraph"/>) is attempting to be overwriten.
/// </exception>
public static void Register<TInterface, TImplementation>(bool overwrite = false) where TImplementation : TInterface
public static void Register<TInterface, TImplementation>(bool overwrite = false) where TImplementation : class, TInterface, new()
{
if (typeof(TImplementation).IsAbstract)
{
throw new TypeArgumentException("Must not be abstract.", nameof(TImplementation));
}
var interfaceType = typeof(TInterface);
if (!overwrite && ResolveTypes.ContainsKey(interfaceType))
if (ResolveTypes.ContainsKey(interfaceType))
{
throw new InvalidOperationException(
string.Format("Attempted to register already registered interface {0}. New implementation: {1}, Old implementation: {2}",
interfaceType, typeof(TImplementation), ResolveTypes[interfaceType]
if (!overwrite)
{
throw new InvalidOperationException(
string.Format("Attempted to register already registered interface {0}. New implementation: {1}, Old implementation: {2}",
interfaceType, typeof(TImplementation), ResolveTypes[interfaceType]
));
}
if (Services.ContainsKey(interfaceType))
{
throw new InvalidOperationException($"Attempted to overwrite already instantiated interface {interfaceType}.");
}
}
ResolveTypes[interfaceType] = typeof(TImplementation);
}
@@ -93,101 +98,89 @@ namespace SS14.Shared.IoC
/// <summary>
/// Resolve a dependency manually.
/// </summary>
/// <exception cref="MissingImplementationException">Thrown if the interface was not registered beforehand.</exception>
/// <exception cref="NoPublicConstructorException">Thrown if the resolved implementation does not have a public constructor.</exception>
/// <exception cref="CircularDependencyException">Thrown if the type is already being built. This usually means a circular dependency exists.</exception>
/// <exception cref="UnregisteredTypeException">Thrown if the interface is not registered.</exception>
/// <exception cref="InvalidOperationException">
/// Thrown if the resolved type hasn't been created yet
/// because the object graph still needs to be constructed for it.
/// </exception>
public static T Resolve<T>()
{
Type type = typeof(T);
if (!Services.ContainsKey(type))
{
BuildType(type);
if (ResolveTypes.ContainsKey(type))
{
// If we have the type registered but not created that means we haven't been told to initialize the graph yet.
throw new InvalidOperationException($"Attempted to resolve type {type} before the object graph for it has been populated.");
}
throw new UnregisteredTypeException(type);
}
return (T)Services[type];
}
/// <summary>
/// Build the implementation for an interface.
/// Registers the built implementation so that it can be directly indexed.
/// Initializes the object graph by building every object and resolving all dependencies.
/// </summary>
/// <param name="type">The interface to build.</param>
private static void BuildType(Type type)
public static void BuildGraph()
{
if (!ResolveTypes.TryGetValue(type, out Type concreteType))
{
throw new MissingImplementationException(type);
}
// List of all objects we need to inject dependencies into.
var toInject = new List<object>();
// We're already building this, this means circular dependency!
if (CurrentlyBuilding.Contains(concreteType))
// First we build every type we have registered but isn't yet built.
// This allows us to run this after the content assembly has been loaded.
foreach (KeyValuePair<Type, Type> currentType in ResolveTypes.Where(p => !Services.ContainsKey(p.Key)))
{
throw new CircularDependencyException(type);
}
// Find a potential dupe by checking other registered types that have already been instantiated that have the same instance type.
// Can't catch ourselves because we're not instantiated.
// Ones that aren't yet instantiated are about to be and'll find us instead.
KeyValuePair<Type, Type> dupeType = ResolveTypes
.Where(p => Services.ContainsKey(p.Key) && p.Value == currentType.Value)
.FirstOrDefault();
// See if we already have an valid instance but registered as a different type.
// Example being the EntityManager on client and server,
// which have subinterfaces like IServerEntityManager.
var potentialInstance = Services.Values.FirstOrDefault(s => type.IsAssignableFrom(s.GetType()));
if (potentialInstance != null)
{
// NOTE: if BuildType() gets called when there already IS an instance for the type.
// This'll "catch" that too.
// This is NOT intended and do not rely on it.
Services[type] = potentialInstance;
return;
}
ConstructorInfo constructor = concreteType.GetConstructors().FirstOrDefault();
if (constructor == null)
{
throw new NoPublicConstructorException(concreteType);
}
CurrentlyBuilding.Add(concreteType);
try
{
ParameterInfo[] parameters = constructor.GetParameters();
if (parameters.Any())
// Interface key can't be null so since KeyValuePair<> is a struct,
// this effectively checks whether we found something.
if (dupeType.Key != null)
{
var requiredParameters = new List<object>();
foreach (ParameterInfo parameterInfo in parameters)
{
if (!Services.ContainsKey(parameterInfo.ParameterType))
{
BuildType(parameterInfo.ParameterType);
}
object dependency = Services[parameterInfo.ParameterType];
requiredParameters.Add(dependency);
}
try
{
object instance = Activator.CreateInstance(concreteType, requiredParameters.ToArray());
Services.Add(type, instance);
}
catch (TargetInvocationException e)
{
throw new ImplementationConstructorException(concreteType, e.InnerException);
}
// We have something with the same instance type, use that.
Services[currentType.Key] = Services[dupeType.Key];
continue;
}
else
try
{
try
{
object instance = Activator.CreateInstance(concreteType);
Services.Add(type, instance);
}
catch (TargetInvocationException e)
{
throw new ImplementationConstructorException(concreteType, e.InnerException);
}
var instance = Activator.CreateInstance(currentType.Value);
Services[currentType.Key] = instance;
toInject.Add(instance);
}
catch (TargetInvocationException e)
{
throw new ImplementationConstructorException(currentType.Value, e.InnerException);
}
}
finally
// Graph built, go over ones that need injection.
foreach (var implementation in toInject)
{
CurrentlyBuilding.Remove(concreteType);
foreach (FieldInfo field in implementation.GetType()
.GetFields(BindingFlags.NonPublic | BindingFlags.Instance)
.Where(p => Attribute.GetCustomAttribute(p, typeof(DependencyAttribute)) != null))
{
// Not using Resolve<T>() because we're literally building it right now.
if (!Services.ContainsKey(field.FieldType))
{
throw new UnregisteredDependencyException(implementation.GetType(), field.FieldType, field.Name);
}
// Quick note: this DOES work with readonly fields, though it may be a CLR implementation detail.
field.SetValue(implementation, Services[field.FieldType]);
}
}
foreach (IPostInjectInit item in toInject.OfType<IPostInjectInit>())
{
item.PostInject();
}
}
}

View File

@@ -76,8 +76,9 @@ namespace SS14.Shared.Prototypes
}
}
public class PrototypeManager : IPrototypeManager
public class PrototypeManager : IPrototypeManager, IPostInjectInit
{
[Dependency]
private readonly IReflectionManager ReflectionManager;
private readonly Dictionary<string, Type> prototypeTypes = new Dictionary<string, Type>();
@@ -199,10 +200,9 @@ namespace SS14.Shared.Prototypes
#endregion IPrototypeManager members
public PrototypeManager(IReflectionManager reflectionManager)
public void PostInject()
{
ReflectionManager = reflectionManager;
reflectionManager.OnAssemblyAdded += (_, __) => ReloadPrototypeTypes();
ReflectionManager.OnAssemblyAdded += (_, __) => ReloadPrototypeTypes();
ReloadPrototypeTypes();
}

View File

@@ -21,6 +21,7 @@
</FileUpgradeFlags>
<Platform Condition=" '$(Platform)' == '' ">x86</Platform>
<TargetFrameworkProfile />
<NoWarn>0649</NoWarn>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
<BaseAddress>285212672</BaseAddress>
@@ -131,7 +132,6 @@
<Compile Include="GameStateDelta.cs" />
<Compile Include="GameStates\GameState.cs" />
<Compile Include="GameStates\PlayerState.cs" />
<Compile Include="IoC\Exceptions\CircularDependencyException.cs" />
<Compile Include="IoC\Exceptions\ImplementationConstructorException.cs" />
<Compile Include="Lighting.cs" />
<Compile Include="Log\LogLevel.cs" />
@@ -175,8 +175,8 @@
<DependentUpon>BitStream.cs</DependentUpon>
</EmbeddedResource>
<Compile Include="IoC\IoCManager.cs" />
<Compile Include="IoC\Exceptions\MissingImplementationException.cs" />
<Compile Include="IoC\Exceptions\NoPublicConstructorException.cs" />
<Compile Include="IoC\IPostInjectInit.cs" />
<Compile Include="IoC\DependencyAttribute.cs" />
<Compile Include="IoC\Exceptions\InvalidImplementationException.cs" />
<Compile Include="GameObjects\Component.cs" />
<Compile Include="GameObjects\ComponentFactory.cs" />
@@ -187,8 +187,6 @@
<Compile Include="GameObjects\IEntityNetworkManager.cs" />
<Compile Include="GameObjects\ParticleSettings.cs" />
<Compile Include="GameObjects\StaticConstants.cs" />
<Compile Include="GameObjects\Exceptions\MissingImplementationException.cs" />
<Compile Include="GameObjects\Exceptions\NoPublicConstructorException.cs" />
<Compile Include="GameObjects\System\EntityEventHandlingSystem.cs" />
<Compile Include="GameObjects\System\EntityProcessingSystem.cs" />
<Compile Include="GameObjects\System\EntitySystem.cs" />
@@ -230,6 +228,8 @@
<Compile Include="Prototypes\PrototypeManager.cs" />
<Compile Include="Prototypes\EntityPrototype.cs" />
<Compile Include="Reflection\ReflectionManager.cs" />
<Compile Include="IoC\Exceptions\UnregisteredDependencyException.cs" />
<Compile Include="IoC\Exceptions\UnregisteredTypeException.cs" />
</ItemGroup>
<ItemGroup />
<ItemGroup>
@@ -242,4 +242,4 @@
<PostBuildEvent>
</PostBuildEvent>
</PropertyGroup>
</Project>
</Project>

View File

@@ -1,4 +1,3 @@
#if !HEADLESS
using NUnit.Framework;
namespace SS14.UnitTesting.SS14.Client.Graphics.Shaders
@@ -10,6 +9,7 @@ namespace SS14.UnitTesting.SS14.Client.Graphics.Shaders
{
public override bool NeedsClientConfig => true;
public override bool NeedsResourcePack => true;
public override UnitTestProject Project => UnitTestProject.Client;
[Test]
public void LightBlend_Test()
@@ -18,4 +18,3 @@ namespace SS14.UnitTesting.SS14.Client.Graphics.Shaders
}
}
}
#endif

View File

@@ -13,6 +13,7 @@ namespace SS14.UnitTesting.SS14.Client.Graphics.Shaders
{
public override bool NeedsClientConfig => true;
public override bool NeedsResourcePack => true;
public override UnitTestProject Project => UnitTestProject.Client;
private IResourceManager resources;
private RenderImage testRenderImage;

View File

@@ -12,6 +12,7 @@ namespace SS14.UnitTesting.SS14.Client.Graphics.Sprite
{
public override bool NeedsClientConfig => true;
public override bool NeedsResourcePack => true;
public override UnitTestProject Project => UnitTestProject.Client;
private IResourceManager resources;
private RenderImage test;

View File

@@ -17,6 +17,7 @@ namespace SS14.UnitTesting.SS14.Client.Helpers
{
public override bool NeedsClientConfig => true;
public override bool NeedsResourcePack => true;
public override UnitTestProject Project => UnitTestProject.Client;
private IConfigurationManager _configurationManager;
private IResourceManager _resourceManager;

View File

@@ -13,6 +13,7 @@ namespace SS14.UnitTesting.SS14.Client.Helpers
{
public override bool NeedsClientConfig => true;
public override bool NeedsResourcePack => true;
public override UnitTestProject Project => UnitTestProject.Client;
private RenderImage renderimage;

View File

@@ -10,6 +10,7 @@ namespace SS14.UnitTesting.SS14.Client.Player.PostProcessing
{
public override bool NeedsClientConfig => true;
public override bool NeedsResourcePack => true;
public override UnitTestProject Project => UnitTestProject.Client;
public DeathPostProcessingEffect_Test()
{

View File

@@ -17,6 +17,7 @@
<IsCodedUITest>False</IsCodedUITest>
<TestProjectType>UnitTest</TestProjectType>
<TargetFrameworkProfile />
<NoWarn>0649</NoWarn>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@@ -159,4 +160,4 @@
<PropertyGroup>
<DefineConstants Condition="'$(HEADLESS)'!=''">$(DefineConstants);HEADLESS</DefineConstants>
</PropertyGroup>
</Project>
</Project>

View File

@@ -3,12 +3,14 @@ using SFML.Graphics;
using SFML.System;
using SS14.Client;
using SS14.Client.Collision;
using SS14.Client.GameObjects;
using SS14.Client.GameTimer;
using SS14.Client.Graphics;
using SS14.Client.Graphics.Event;
using SS14.Client.Input;
using SS14.Client.Interfaces;
using SS14.Client.Interfaces.Collision;
using SS14.Client.Interfaces.GameObjects;
using SS14.Client.Interfaces.GameTimer;
using SS14.Client.Interfaces.Input;
using SS14.Client.Interfaces.Lighting;
@@ -21,6 +23,7 @@ using SS14.Client.Lighting;
using SS14.Client.Network;
using SS14.Client.Resources;
using SS14.Client.State;
using SS14.Client.Reflection;
using SS14.Client.UserInterface;
using SS14.Client.Utility;
using SS14.Server;
@@ -47,6 +50,7 @@ using SS14.Server.MessageLogging;
using SS14.Server.Network;
using SS14.Server.Placement;
using SS14.Server.Player;
using SS14.Server.Reflection;
using SS14.Server.Round;
using SS14.Server.Serialization;
using SS14.Server.ServerConsole;
@@ -57,6 +61,7 @@ using SS14.Shared.Interfaces.GameObjects;
using SS14.Shared.Interfaces.Log;
using SS14.Shared.Interfaces.Reflection;
using SS14.Shared.IoC;
using SS14.Shared.Log;
using SS14.Shared.Prototypes;
using SS14.Shared.Utility;
using System;
@@ -67,6 +72,12 @@ using System.Windows.Forms;
namespace SS14.UnitTesting
{
public enum UnitTestProject
{
Server,
Client
}
public abstract class SS14UnitTest
{
private FrameEventArgs frameEvent;
@@ -95,6 +106,8 @@ namespace SS14.UnitTesting
/// </summary>
public virtual bool NeedsClientConfig => false;
public virtual UnitTestProject Project => UnitTestProject.Server;
#endregion Options
#region Accessors
@@ -135,8 +148,18 @@ namespace SS14.UnitTesting
var assemblies = new List<Assembly>(4);
string assemblyDir = Path.GetDirectoryName(new Uri(Assembly.GetExecutingAssembly().CodeBase).LocalPath);
assemblies.Add(Assembly.LoadFrom(Path.Combine(assemblyDir, "SS14.Client.exe")));
assemblies.Add(Assembly.LoadFrom(Path.Combine(assemblyDir, "SS14.Server.exe")));
switch (Project)
{
case UnitTestProject.Client:
assemblies.Add(Assembly.LoadFrom(Path.Combine(assemblyDir, "SS14.Client.exe")));
break;
case UnitTestProject.Server:
assemblies.Add(Assembly.LoadFrom(Path.Combine(assemblyDir, "SS14.Server.exe")));
break;
default:
throw new NotSupportedException($"Unknown testing project: {Project}");
}
assemblies.Add(Assembly.LoadFrom(Path.Combine(assemblyDir, "SS14.Shared.dll")));
assemblies.Add(Assembly.GetExecutingAssembly());
@@ -161,7 +184,7 @@ namespace SS14.UnitTesting
/// <summary>
/// Registers all the types into the <see cref="IoCManager"/> with <see cref="IoCManager.Register{TInterface, TImplementation}"/>
/// </summary>
private static void RegisterIoC()
private void RegisterIoC()
{
// Shared stuff.
IoCManager.Register<IComponentManager, ComponentManager>();
@@ -170,42 +193,73 @@ namespace SS14.UnitTesting
IoCManager.Register<IComponentFactory, ComponentFactory>();
IoCManager.Register<IConfigurationManager, ConfigurationManager>();
// Server stuff.
IoCManager.Register<IEntityManager, ServerEntityManager>();
IoCManager.Register<IServerEntityManager, ServerEntityManager>();
IoCManager.Register<ILogManager, ServerLogManager>();
IoCManager.Register<IServerLogManager, ServerLogManager>();
IoCManager.Register<IMessageLogger, MessageLogger>();
IoCManager.Register<IChatManager, ChatManager>();
IoCManager.Register<ISS14NetServer, SS14NetServer>();
IoCManager.Register<IMapManager, MapManager>();
IoCManager.Register<IPlacementManager, PlacementManager>();
IoCManager.Register<IConsoleManager, ConsoleManager>();
IoCManager.Register<ITileDefinitionManager, TileDefinitionManager>();
IoCManager.Register<IRoundManager, RoundManager>();
IoCManager.Register<ISS14Server, SS14Server>();
IoCManager.Register<ISS14Serializer, SS14Serializer>();
IoCManager.Register<IEntityNetworkManager, EntityNetworkManager>();
IoCManager.Register<ICommandLineArgs, CommandLineArgs>();
IoCManager.Register<IGameStateManager, GameStateManager>();
IoCManager.Register<IClientConsoleHost, Server.ClientConsoleHost.ClientConsoleHost>();
IoCManager.Register<IPlayerManager, PlayerManager>();
switch (Project)
{
case UnitTestProject.Client:
IoCManager.Register<ILogManager, LogManager>();
// Client stuff.
IoCManager.Register<IRand, Rand>();
IoCManager.Register<IStateManager, StateManager>();
IoCManager.Register<INetworkGrapher, NetworkGrapher>();
IoCManager.Register<IKeyBindingManager, KeyBindingManager>();
IoCManager.Register<IUserInterfaceManager, UserInterfaceManager>();
IoCManager.Register<IGameTimer, GameTimer>();
IoCManager.Register<ICollisionManager, CollisionManager>();
IoCManager.Register<INetworkManager, NetworkManager>();
IoCManager.Register<ILightManager, LightManager>();
IoCManager.Register<IResourceManager, ResourceManager>();
IoCManager.Register<IGameController, GameController>();
IoCManager.Register<IRand, Rand>();
IoCManager.Register<IStateManager, StateManager>();
IoCManager.Register<INetworkGrapher, NetworkGrapher>();
IoCManager.Register<IKeyBindingManager, KeyBindingManager>();
IoCManager.Register<IUserInterfaceManager, UserInterfaceManager>();
IoCManager.Register<IGameTimer, GameTimer>();
IoCManager.Register<ITileDefinitionManager, TileDefinitionManager>();
IoCManager.Register<IMessageLogger, MessageLogger>();
IoCManager.Register<ICollisionManager, CollisionManager>();
IoCManager.Register<IEntityManager, ClientEntityManager>();
IoCManager.Register<IClientEntityManager, ClientEntityManager>();
IoCManager.Register<INetworkManager, NetworkManager>();
IoCManager.Register<IReflectionManager, ClientReflectionManager>();
IoCManager.Register<IPlacementManager, PlacementManager>();
IoCManager.Register<ILightManager, LightManager>();
IoCManager.Register<IResourceManager, ResourceManager>();
IoCManager.Register<ISS14Serializer, SS14Serializer>();
IoCManager.Register<IMapManager, MapManager>();
IoCManager.Register<IEntityNetworkManager, Client.GameObjects.EntityNetworkManager>();
IoCManager.Register<IPlayerManager, PlayerManager>();
IoCManager.Register<IGameController, GameController>();
break;
case UnitTestProject.Server:
IoCManager.Register<IEntityManager, ServerEntityManager>();
IoCManager.Register<IServerEntityManager, ServerEntityManager>();
IoCManager.Register<ILogManager, ServerLogManager>();
IoCManager.Register<IServerLogManager, ServerLogManager>();
IoCManager.Register<IMessageLogger, MessageLogger>();
IoCManager.Register<IChatManager, ChatManager>();
IoCManager.Register<ISS14NetServer, SS14NetServer>();
IoCManager.Register<IMapManager, MapManager>();
IoCManager.Register<IPlacementManager, PlacementManager>();
IoCManager.Register<IConsoleManager, ConsoleManager>();
IoCManager.Register<ITileDefinitionManager, TileDefinitionManager>();
IoCManager.Register<IRoundManager, RoundManager>();
IoCManager.Register<ISS14Server, SS14Server>();
IoCManager.Register<ISS14Serializer, SS14Serializer>();
IoCManager.Register<IEntityNetworkManager, Server.GameObjects.EntityNetworkManager>();
IoCManager.Register<ICommandLineArgs, CommandLineArgs>();
IoCManager.Register<IGameStateManager, GameStateManager>();
IoCManager.Register<IReflectionManager, ServerReflectionManager>();
IoCManager.Register<IClientConsoleHost, Server.ClientConsoleHost.ClientConsoleHost>();
IoCManager.Register<IPlayerManager, PlayerManager>();
break;
default:
throw new NotSupportedException($"Unknown testing project: {Project}");
}
OverrideIoC();
IoCManager.BuildGraph();
}
/// <summary>
/// Called after all IoC registration has been done, but before the graph has been built.
/// This allows one to add new IoC types or overwrite existing ones if needed.
/// </summary>
protected virtual void OverrideIoC()
{
// Unit test stuff.
IoCManager.Register<IReflectionManager, Shared.Reflection.ReflectionManagerTest>();
}
public void InitializeResources()

View File

@@ -1,5 +1,6 @@
using NUnit.Framework;
using SS14.Client.Interfaces.Resource;
using SS14.Server.Interfaces.GameObjects;
using SS14.Shared.Interfaces.GameObjects;
using SS14.Shared.Interfaces.Configuration;
using SS14.Shared.IoC;
using SS14.Shared.IoC.Exceptions;
@@ -13,90 +14,53 @@ namespace SS14.UnitTesting.SS14.Shared.IoC
[OneTimeSetUp]
public void Setup()
{
IoCManager.Register<IIoCNoPublicConstructorTest, IoCNoPublicConstructorTest>();
IoCManager.Register<IIoCTestPriories, IoCTestPriorities2>();
IoCManager.Register<IIoCTestPriories, IoCTestPriorities1>(true);
IoCManager.Register<IIoCCircularDeps1, CircularDeps1>();
IoCManager.Register<IIoCCircularDeps2, CircularDeps2>();
IoCManager.Register<IConstructorException, ConstructorException>();
IoCManager.Register<TestFieldInjection, TestFieldInjection>();
IoCManager.BuildGraph();
}
[Test]
public void IoCTestFieldInjection()
{
var tester = IoCManager.Resolve<TestFieldInjection>();
tester.Test();
}
[Test]
public void IoCTestBasic()
{
Assert.That(IoCManager.Resolve<IConfigurationManager>(),
Assert.That(IoCManager.Resolve<IEntityManager>(),
Is.Not.Null,
"IoC failed to return an IServerConfigurationManager.");
Assert.That(IoCManager.Resolve<IResourceManager>(),
Assert.That(IoCManager.Resolve<IServerEntityManager>(),
Is.Not.Null,
"IoC failed to return an IResourceManager.");
}
[Test]
public void IoCTestExceptions()
{
Assert.That(() => IoCManager.Resolve<IIoCFailInterface>(),
Throws.TypeOf<MissingImplementationException>(),
"IoC did not throw a MissingImplementationException.");
Assert.That(() => IoCManager.Resolve<IIoCNoPublicConstructorTest>(),
Throws.TypeOf<NoPublicConstructorException>(),
"IoC did not throw a NoPublicConstructorException.");
}
[Test]
public void IoCTestOverwrite()
{
Assert.That(IoCManager.Resolve<IIoCTestPriories>(), Is.TypeOf<IoCTestPriorities1>());
}
[Test]
public void IoCTestCircularDependencies()
{
Assert.That(() => IoCManager.Resolve<IIoCCircularDeps1>(), Throws.InstanceOf<CircularDependencyException>());
}
[Test]
public void IoCTestConstructorException()
{
Assert.That(() => IoCManager.Resolve<IConstructorException>(), Throws.InstanceOf<ImplementationConstructorException>().And.InnerException.InstanceOf<TestConstructorExceptionException>());
IoCManager.Register<IConstructorException, ConstructorException>();
Assert.That(() => IoCManager.BuildGraph(), Throws.InstanceOf<ImplementationConstructorException>().And.InnerException.InstanceOf<TestConstructorExceptionException>());
}
}
public interface IIoCFailInterface { }
public interface IIoCNoPublicConstructorTest { }
public class IoCNoPublicConstructorTest : IIoCNoPublicConstructorTest
{
private IoCNoPublicConstructorTest()
{
}
}
public interface IIoCTestPriories { }
public class IoCTestPriorities1 : IIoCTestPriories { }
public class IoCTestPriorities2 : IIoCTestPriories { }
public interface IIoCCircularDeps1 { }
public interface IIoCCircularDeps2 { }
public class CircularDeps1 : IIoCCircularDeps1
{
public CircularDeps1(IIoCCircularDeps2 deps2)
{
}
}
public class CircularDeps2 : IIoCCircularDeps2
{
public CircularDeps2(IIoCCircularDeps1 deps1)
{
}
}
public interface IConstructorException { }
public class ConstructorException : IConstructorException
@@ -110,4 +74,15 @@ namespace SS14.UnitTesting.SS14.Shared.IoC
public class TestConstructorExceptionException : Exception
{
}
public class TestFieldInjection
{
[Dependency]
private readonly TestFieldInjection myself;
public void Test()
{
Assert.That(myself, Is.EqualTo(this));
}
}
}

View File

@@ -8,12 +8,19 @@ namespace SS14.UnitTesting.Shared.Reflection
{
public sealed class ReflectionManagerTest : ReflectionManager
{
protected override IEnumerable<string> TypePrefixes => new[] { "", "SS14.UnitTesting.", "SS14.Server.", "SS14.Client.", "SS14.Shared." };
protected override IEnumerable<string> TypePrefixes => new[] { "", "SS14.UnitTesting.", "SS14.Server.", "SS14.Shared." };
}
[TestFixture]
public class ReflectionManager_Test : SS14UnitTest
{
protected override void OverrideIoC()
{
base.OverrideIoC();
IoCManager.Register<IReflectionManager, ReflectionManagerTest>(overwrite: true);
}
[Test]
public void ReflectionManager_TestGetAllChildren()
{