Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Conditions now can be used by other plugins
To make other plugins to be able extend you need 

1) Define class that is marked [ConditionModule]

2) Add method in that class is marked by [Condition("name", helpText: "tooltip")]

3) Method should return bool, and accept MyCubeGrid. It may also accept 1 extra param (string, double, int ...)
  • Loading branch information
slimeradio committed Feb 26, 2023
commit aa8a5026acfaf86b84e55ab908d29863f3fa328e
414 changes: 4 additions & 410 deletions Essentials/Commands/CleanupModule.cs

Large diffs are not rendered by default.

66 changes: 66 additions & 0 deletions Essentials/Conditions/Condition.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
using System;
using System.Reflection;
using Sandbox.Game.Entities;
using Torch.Commands;

namespace Essentials.Conditions
{
public class Condition
{
public string Command;
public string InvertCommand;
public string HelpText;
private MethodInfo _method;
public readonly ParameterInfo Parameter;

public Condition(MethodInfo evalMethod, ConditionAttribute attribute)
{
Command = attribute.Command;
InvertCommand = attribute.InvertCommand;
HelpText = attribute.HelpText;
_method = evalMethod;
if (_method.ReturnType != typeof(bool))
throw new TypeLoadException("Condition does not return a bool!");
var p = _method.GetParameters();
if (p.Length < 1 || p[0].ParameterType != typeof(MyCubeGrid))
throw new TypeLoadException("Condition does not accept MyCubeGrid as first parameter");
if (p.Length > 2)
throw new TypeLoadException("Condition can only have two parameters");
if (p.Length == 1)
Parameter = null;
else
Parameter = p[1];
}

public bool? Evaluate(MyCubeGrid grid, string arg, bool invert, CommandContext context)
{
bool result;
if (!string.IsNullOrEmpty(arg) && Parameter == null)
{
context.Respond($"Condition does not accept an argument. Cannot continue!");
return null;
}
if (string.IsNullOrEmpty(arg) && Parameter != null && !Parameter.HasDefaultValue)
{
context.Respond($"Condition requires an argument! {Parameter.ParameterType.Name}: {Parameter.Name} Not supplied, cannot continue!");
return null;
}
if (Parameter != null && !string.IsNullOrEmpty(arg))
{
if (!arg.TryConvert(Parameter.ParameterType, out object val))
{
context.Respond($"Could not parse argument!");
return null;
}

result = (bool)_method.Invoke(null, new[] { grid, val });
}
else
{
result = (bool)_method.Invoke(null, new object[] { grid });
}

return result != invert;
}
}
}
19 changes: 19 additions & 0 deletions Essentials/Conditions/ConditionAttribute.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using System;

namespace Essentials
{
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
public sealed class ConditionAttribute : Attribute
{
public string Command;
public string InvertCommand;
public string HelpText;

public ConditionAttribute(string command, string invertCommand = null, string helpText = null)
{
Command = command;
InvertCommand = invertCommand;
HelpText = helpText;
}
}
}
10 changes: 10 additions & 0 deletions Essentials/Conditions/ConditionModule.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using System;

namespace Essentials
{
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public sealed class ConditionModule : Attribute
{

}
}
143 changes: 143 additions & 0 deletions Essentials/Conditions/ConditionsChecker.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Essentials.Conditions;
using ParallelTasks;
using Sandbox.Game.Entities;
using Torch.Commands;

namespace Essentials.Commands
{
public static class ConditionsChecker
{
private static List<Condition> _conditionLookup;

public static void Init()
{
_conditionLookup = new List<Condition>();

var types = AppDomain.CurrentDomain.GetAssemblies()
.SelectMany((x) =>
{
try
{
return x.GetTypes();
}
catch (Exception e) // ignored
{
return new Type[0];
}
}).Where(t => t.IsDefined(typeof(ConditionModule)));

foreach (var type in types)
{
var methods = type.GetMethods(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static);
foreach (var m in methods)
{
var a = m.GetCustomAttribute<ConditionAttribute>();
if (a == null)
continue;

var c = new Condition(m, a);

_conditionLookup.Add(c);
}
}
}

public static List<Condition> GetAllConditions()
{
return _conditionLookup;
}

public static IEnumerable<MyCubeGrid> ScanConditions(CommandContext context, IReadOnlyList<string> args)
{
var conditions = new List<Func<MyCubeGrid, bool?>>();

for (var i = 0; i < args.Count; i++)
{
string parameter;
if (i + 1 >= args.Count)
{
parameter = null;
}
else
{
parameter = args[i + 1];
}

var arg = args[i];

if (parameter != null)
{
//parameter is the name of a command. Assume this command requires no parameters
if (_conditionLookup.Any(c => parameter.Equals(c.Command, StringComparison.CurrentCultureIgnoreCase) || parameter.Equals(c.InvertCommand, StringComparison.CurrentCultureIgnoreCase)))
{
parameter = null;
}
//next string is a parameter, so pass it to the condition and skip it next loop
else
i++;
}

bool found = false;

foreach (var condition in _conditionLookup)
{
if (arg.Equals(condition.Command, StringComparison.CurrentCultureIgnoreCase))
{
conditions.Add(g => condition.Evaluate(g, parameter, false, context));
found = true;
break;
}
else if (arg.Equals(condition.InvertCommand, StringComparison.CurrentCultureIgnoreCase))
{
conditions.Add(g => condition.Evaluate(g, parameter, true, context));
found = true;
break;
}
}
if (!found)
{
context.Respond($"Unknown argument '{arg}'");
yield break;
}
}

//default scan to find grids without pilots
if (!args.Contains("haspilot", StringComparer.CurrentCultureIgnoreCase))
conditions.Add(g => !ConditionsImplementations.Piloted(g));

foreach (var group in MyCubeGridGroups.Static.Logical.Groups)
{
//if (group.Nodes.All(grid => conditions.TrueForAll(func => func(grid.NodeData))))
bool res = true;
foreach (var node in group.Nodes)
{
if (node.NodeData.Projector != null)
continue;

foreach (var c in conditions)
{
bool? r = c.Invoke(node.NodeData);
if (r == null)
yield break;
if (r == true)
continue;

res = false;
break;
}
if (!res)
break;
}

if (res)
foreach (var grid in group.Nodes.Where(x => x.NodeData.Projector == null))
yield return grid.NodeData;
}
}

}
}
Loading