diff --git a/Application/Factories/ScriptCommandFactory.cs b/Application/Factories/ScriptCommandFactory.cs
index a3453a906..8b6091444 100644
--- a/Application/Factories/ScriptCommandFactory.cs
+++ b/Application/Factories/ScriptCommandFactory.cs
@@ -25,7 +25,7 @@ namespace IW4MAdmin.Application.Factories
}
///
- public IManagerCommand CreateScriptCommand(string name, string alias, string description, string permission, IEnumerable<(string, bool)> args, Action executeAction)
+ public IManagerCommand CreateScriptCommand(string name, string alias, string description, string permission, bool isTargetRequired, IEnumerable<(string, bool)> args, Action executeAction)
{
var permissionEnum = Enum.Parse(permission);
var argsArray = args.Select(_arg => new CommandArgument
@@ -34,7 +34,7 @@ namespace IW4MAdmin.Application.Factories
Required = _arg.Item2
}).ToArray();
- return new ScriptCommand(name, alias, description, permissionEnum, argsArray, executeAction, _config, _transLookup);
+ return new ScriptCommand(name, alias, description, isTargetRequired, permissionEnum, argsArray, executeAction, _config, _transLookup);
}
}
}
diff --git a/Application/Misc/ScriptCommand.cs b/Application/Misc/ScriptCommand.cs
index fdf4785de..6f181bba9 100644
--- a/Application/Misc/ScriptCommand.cs
+++ b/Application/Misc/ScriptCommand.cs
@@ -15,7 +15,7 @@ namespace IW4MAdmin.Application.Misc
{
private readonly Action _executeAction;
- public ScriptCommand(string name, string alias, string description, Permission permission,
+ public ScriptCommand(string name, string alias, string description, bool isTargetRequired, Permission permission,
CommandArgument[] args, Action executeAction, CommandConfiguration config, ITranslationLookup layout)
: base(config, layout)
{
@@ -24,6 +24,7 @@ namespace IW4MAdmin.Application.Misc
Name = name;
Alias = alias;
Description = description;
+ RequiresTarget = isTargetRequired;
Permission = permission;
Arguments = args;
}
diff --git a/Application/Misc/ScriptPlugin.cs b/Application/Misc/ScriptPlugin.cs
index 4a692d04f..c8dd97da0 100644
--- a/Application/Misc/ScriptPlugin.cs
+++ b/Application/Misc/ScriptPlugin.cs
@@ -252,6 +252,7 @@ namespace IW4MAdmin.Application.Misc
string alias = dynamicCommand.alias;
string description = dynamicCommand.description;
string permission = dynamicCommand.permission;
+ bool targetRequired = false;
List<(string, bool)> args = new List<(string, bool)>();
dynamic arguments = null;
@@ -266,6 +267,16 @@ namespace IW4MAdmin.Application.Misc
// arguments are optional
}
+ try
+ {
+ targetRequired = dynamicCommand.targetRequired;
+ }
+
+ catch (RuntimeBinderException)
+ {
+ // arguments are optional
+ }
+
if (arguments != null)
{
foreach (var arg in dynamicCommand.arguments)
@@ -290,7 +301,7 @@ namespace IW4MAdmin.Application.Misc
}
}
- commandList.Add(scriptCommandFactory.CreateScriptCommand(name, alias, description, permission, args, execute));
+ commandList.Add(scriptCommandFactory.CreateScriptCommand(name, alias, description, permission, targetRequired, args, execute));
}
return commandList;
diff --git a/Application/Misc/ScriptPluginServiceResolver.cs b/Application/Misc/ScriptPluginServiceResolver.cs
index f8f308ac7..552bbe532 100644
--- a/Application/Misc/ScriptPluginServiceResolver.cs
+++ b/Application/Misc/ScriptPluginServiceResolver.cs
@@ -18,14 +18,31 @@ namespace IW4MAdmin.Application.Misc
public object ResolveService(string serviceName)
{
- var serviceType = typeof(IScriptPluginServiceResolver).Assembly.GetTypes().FirstOrDefault(_type => _type.Name == serviceName);
+ var serviceType = DetermineRootType(serviceName);
+ return _serviceProvider.GetService(serviceType);
+ }
+
+ public object ResolveService(string serviceName, string[] genericParameters)
+ {
+ var serviceType = DetermineRootType(serviceName, genericParameters.Length);
+ var genericTypes = genericParameters.Select(_genericTypeParam => DetermineRootType(_genericTypeParam));
+ var resolvedServiceType = serviceType.MakeGenericType(genericTypes.ToArray());
+ return _serviceProvider.GetService(resolvedServiceType);
+ }
+
+ private Type DetermineRootType(string serviceName, int genericParamCount = 0)
+ {
+ var typeCollection = AppDomain.CurrentDomain.GetAssemblies()
+ .SelectMany(t => t.GetTypes());
+ string generatedName = $"{serviceName}{(genericParamCount == 0 ? "" : $"`{genericParamCount}")}".ToLower();
+ var serviceType = typeCollection.FirstOrDefault(_type => _type.Name.ToLower() == generatedName);
if (serviceType == null)
{
- throw new InvalidOperationException($"No service type '{serviceName}' defined in IW4MAdmin assembly");
+ throw new InvalidOperationException($"No object type '{serviceName}' defined in loaded assemblies");
}
- return _serviceProvider.GetService(serviceType);
+ return serviceType;
}
}
}
diff --git a/Plugins/ScriptPlugins/SampleScriptPluginCommand.js b/Plugins/ScriptPlugins/SampleScriptPluginCommand.js
index b80724dad..b02f92382 100644
--- a/Plugins/ScriptPlugins/SampleScriptPluginCommand.js
+++ b/Plugins/ScriptPlugins/SampleScriptPluginCommand.js
@@ -7,6 +7,8 @@ let commands = [{
alias: "pp",
// required
permission: "User",
+ // optional (defaults to false)
+ targetRequired: false,
// optional
arguments: [{
name: "times to ping",
diff --git a/SharedLibraryCore/Interfaces/IScriptCommandFactory.cs b/SharedLibraryCore/Interfaces/IScriptCommandFactory.cs
index b59d0876d..f6c3cf994 100644
--- a/SharedLibraryCore/Interfaces/IScriptCommandFactory.cs
+++ b/SharedLibraryCore/Interfaces/IScriptCommandFactory.cs
@@ -15,9 +15,10 @@ namespace SharedLibraryCore.Interfaces
/// alias of command
/// description of command
/// minimum required permission
+ /// target required or not
/// command arguments (name, is required)
/// action to peform when commmand is executed
///
- IManagerCommand CreateScriptCommand(string name, string alias, string description, string permission, IEnumerable<(string, bool)> args, Action executeAction);
+ IManagerCommand CreateScriptCommand(string name, string alias, string description, string permission, bool isTargetRequired, IEnumerable<(string, bool)> args, Action executeAction);
}
}
diff --git a/SharedLibraryCore/Interfaces/IScriptPluginServiceResolver.cs b/SharedLibraryCore/Interfaces/IScriptPluginServiceResolver.cs
index 08883074d..4a977703c 100644
--- a/SharedLibraryCore/Interfaces/IScriptPluginServiceResolver.cs
+++ b/SharedLibraryCore/Interfaces/IScriptPluginServiceResolver.cs
@@ -1,10 +1,25 @@
-namespace SharedLibraryCore.Interfaces
+using System.Collections.Generic;
+
+namespace SharedLibraryCore.Interfaces
{
///
/// interface used to dynamically resolve services by string name
///
public interface IScriptPluginServiceResolver
{
+ ///
+ /// resolves a service with the given name
+ ///
+ /// class name of service
+ ///
object ResolveService(string serviceName);
+
+ ///
+ /// resolves a service with the given name and generic params
+ ///
+ /// class name of service
+ /// generic class names
+ ///
+ object ResolveService(string serviceName, string[] genericParameters);
}
}
diff --git a/Tests/ApplicationTests/Mocks/ScriptResolverGenericMock.cs b/Tests/ApplicationTests/Mocks/ScriptResolverGenericMock.cs
new file mode 100644
index 000000000..677bae215
--- /dev/null
+++ b/Tests/ApplicationTests/Mocks/ScriptResolverGenericMock.cs
@@ -0,0 +1,23 @@
+namespace ApplicationTests.Mocks
+{
+ public interface IScriptResolverMock
+ {
+ string Value { get; set; }
+ }
+
+ public class ScriptResolverMock : IScriptResolverMock
+ {
+ public string Value { get; set; }
+ }
+ public interface IScriptResolverGenericMock
+ {
+ T Value { get; set; }
+ V Value2 { get; set; }
+ }
+
+ public class ScriptResolverGenericMock : IScriptResolverGenericMock
+ {
+ public T Value { get; set; }
+ public V Value2 { get; set; }
+ }
+}
diff --git a/Tests/ApplicationTests/PluginTests.cs b/Tests/ApplicationTests/PluginTests.cs
index 00ecc8128..893c8e221 100644
--- a/Tests/ApplicationTests/PluginTests.cs
+++ b/Tests/ApplicationTests/PluginTests.cs
@@ -33,6 +33,7 @@ namespace ApplicationTests
serviceProvider = new ServiceCollection().BuildBase()
.AddSingleton(A.Fake())
.AddSingleton()
+ .AddSingleton(A.Fake())
.BuildServiceProvider();
fakeManager = serviceProvider.GetRequiredService();
mockEventHandler = serviceProvider.GetRequiredService();
@@ -66,7 +67,7 @@ namespace ApplicationTests
A.CallTo(() => fakeManager.GetClientService())
.Returns(fakeClientService);
- await plugin.Initialize(serviceProvider.GetRequiredService(), serviceProvider.GetRequiredService());
+ await plugin.Initialize(serviceProvider.GetRequiredService(), serviceProvider.GetRequiredService(), serviceProvider.GetRequiredService());
var gameEvent = new GameEvent()
{
diff --git a/Tests/ApplicationTests/ScriptPluginServiceResolverTests.cs b/Tests/ApplicationTests/ScriptPluginServiceResolverTests.cs
new file mode 100644
index 000000000..e6c08bb66
--- /dev/null
+++ b/Tests/ApplicationTests/ScriptPluginServiceResolverTests.cs
@@ -0,0 +1,66 @@
+using ApplicationTests.Mocks;
+using IW4MAdmin.Application.Misc;
+using Microsoft.Extensions.DependencyInjection;
+using NUnit.Framework;
+using System;
+
+namespace ApplicationTests
+{
+ public class ScriptPluginServiceResolverTests
+ {
+ private IServiceProvider serviceProvider;
+
+ [SetUp]
+ public void Setup()
+ {
+ serviceProvider = new ServiceCollection()
+ .BuildBase()
+ .AddSingleton()
+ .AddSingleton()
+ .AddSingleton(new ScriptResolverMock { Value = "test" })
+ .AddSingleton, ScriptResolverGenericMock>()
+ .AddSingleton(new ScriptResolverGenericMock { Value = 123, Value2 = "test" })
+ .BuildServiceProvider();
+ }
+
+ [Test]
+ public void Test_ResolveType()
+ {
+ var resolver = serviceProvider.GetService();
+ var expectedResolvedService = serviceProvider.GetService();
+ var resolvedService = resolver.ResolveService(nameof(ScriptResolverMock));
+
+ Assert.AreEqual(expectedResolvedService, resolvedService);
+ }
+
+ [Test]
+ public void Test_ResolveType_Interface()
+ {
+ var resolver = serviceProvider.GetService();
+ var expectedResolvedService = serviceProvider.GetService();
+ var resolvedService = resolver.ResolveService(nameof(IScriptResolverMock));
+
+ Assert.AreEqual(expectedResolvedService, resolvedService);
+ }
+
+ [Test]
+ public void Test_ResolveGenericType()
+ {
+ var resolver = serviceProvider.GetService();
+ var expectedResolvedService = serviceProvider.GetService>();
+ var resolvedService = resolver.ResolveService("ScriptResolverGenericMock", new[] { "Int32", "String" });
+
+ Assert.AreEqual(expectedResolvedService, resolvedService);
+ }
+
+ [Test]
+ public void Test_ResolveGenericType_Interface()
+ {
+ var resolver = serviceProvider.GetService();
+ var expectedResolvedService = serviceProvider.GetService>();
+ var resolvedService = resolver.ResolveService("IScriptResolverGenericMock", new[] { "Int32", "String" });
+
+ Assert.AreEqual(expectedResolvedService, resolvedService);
+ }
+ }
+}