Skip to content

Commit c5571ea

Browse files
improve flag argument system
1 parent d57e031 commit c5571ea

File tree

6 files changed

+154
-116
lines changed

6 files changed

+154
-116
lines changed

FlagSystem/Flags/CustomCommandFlag.cs

Lines changed: 58 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
using SER.Helpers.ResultSystem;
1111
using SER.ScriptSystem;
1212
using SER.ScriptSystem.Structures;
13+
using SER.TokenSystem;
1314
using SER.ValueSystem;
1415
using SER.VariableSystem.Variables;
1516
using Console = GameCore.Console;
@@ -22,29 +23,62 @@ public class CustomCommandFlag : Flag
2223
public override string Description =>
2324
"Creates a command and binds it to the script. When the command is ran, it executes the script.";
2425

25-
public override (string argName, string description)? InlineArgDescription =>
26-
("commandName", "The name of the command; cannot have any whitespace.");
2726

28-
public override Dictionary<string, (string description, Func<string[], Result> handler)> Arguments => new()
29-
{
30-
["arguments"] = (
27+
public override Argument? InlineArgument => new(
28+
"command name",
29+
"The name of the command to create",
30+
inlineArgs =>
31+
{
32+
switch (inlineArgs.Length)
33+
{
34+
case 0:
35+
return "Command name is missing.";
36+
case > 1:
37+
return "Command name can only be a single word, no whitespace allowed.";
38+
}
39+
40+
var name = inlineArgs.First();
41+
if (name.Any(char.IsWhiteSpace))
42+
{
43+
return "Command name can only be a single word, no whitespace allowed.";
44+
}
45+
46+
Command = new CustomCommand
47+
{
48+
Command = name
49+
};
50+
51+
return true;
52+
},
53+
true
54+
);
55+
56+
public override Argument[] Arguments =>
57+
[
58+
new(
59+
"arguments",
3160
"The arguments that this command expects in order to run. " +
3261
"The script cannot run unless every single argument is specified. " +
3362
"When the command is ran, the provided values for the arguments turn into their own literal local " +
3463
"variables for you to use in the script. " +
3564
"For example: making a command with an argument 'x' will then create a local variable {x} in your script. " +
36-
"Side note: when a player is running the command, a @sender local player variable will also be created.",
37-
AddArguments
65+
"Side note: when a player is running the command, a @sender local player variable will also be created.",
66+
AddArguments,
67+
false
3868
),
39-
["availableFor"] = (
69+
new(
70+
"availableFor",
4071
$"Specifies from which console the command can be executed from. Accepts {nameof(ConsoleType)} enum values.",
41-
AddConsoleType
72+
AddConsoleType,
73+
false
4274
),
43-
["description"] = (
44-
"The description of the command.",
45-
AddDescription
75+
new(
76+
"description",
77+
"The description of the command.",
78+
AddDescription,
79+
false
4680
)
47-
};
81+
];
4882

4983
[Flags]
5084
public enum ConsoleType
@@ -55,30 +89,6 @@ public enum ConsoleType
5589
Server = 1 << 2
5690
}
5791

58-
public override Result TryInitialize(string[] inlineArgs)
59-
{
60-
switch (inlineArgs.Length)
61-
{
62-
case 0:
63-
return "Command name is missing.";
64-
case > 1:
65-
return "Command name can only be a single word, no whitespace allowed.";
66-
}
67-
68-
var name = inlineArgs.First();
69-
if (name.Any(char.IsWhiteSpace))
70-
{
71-
return "Command name can only be a single word, no whitespace allowed.";
72-
}
73-
74-
Command = new CustomCommand
75-
{
76-
Command = name
77-
};
78-
79-
return true;
80-
}
81-
8292
public override void FinalizeFlag()
8393
{
8494
if (ScriptCommands.ContainsKey(Command))
@@ -171,16 +181,22 @@ public static Result RunAttachedScript(CustomCommand requestingCommand, ScriptEx
171181
return "The script that was supposed to handle this command was not found.";
172182
}
173183

174-
if (args.Length < requestingCommand.Usage.Length)
184+
if (Tokenizer.SliceLine(args.JoinStrings(" ")).HasErrored(out var sliceError, out var outSlices))
185+
{
186+
return sliceError;
187+
}
188+
189+
var slices = outSlices.ToArray();
190+
if (slices.Length < requestingCommand.Usage.Length)
175191
{
176192
return "Not enough arguments. " +
177-
$"Expected {requestingCommand.Usage.Length} but got {args.Length}.";
193+
$"Expected {requestingCommand.Usage.Length} but got {slices.Length}.";
178194
}
179195

180-
if (args.Length > requestingCommand.Usage.Length)
196+
if (slices.Length > requestingCommand.Usage.Length)
181197
{
182198
return "Too many arguments. " +
183-
$"Expected {requestingCommand.Usage.Length} but got {args.Length}.";
199+
$"Expected {requestingCommand.Usage.Length} but got {slices.Length}.";
184200
}
185201

186202
if (Script.CreateByScriptName(flag.ScriptName, sender)
@@ -196,7 +212,7 @@ public static Result RunAttachedScript(CustomCommand requestingCommand, ScriptEx
196212
var name = argVariable[0].ToString().ToLower() + argVariable.Substring(1);
197213

198214
// todo: need to parse values from string too (probably using tokenizer)
199-
script.AddVariable(new LiteralVariable<TextValue>(name, args[index]));
215+
script.AddVariable(new LiteralVariable<TextValue>(name, slices[index].Value));
200216
}
201217

202218
script.Run();

FlagSystem/Flags/OnCustomTriggerFlag.cs

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -19,23 +19,25 @@ public class OnCustomTriggerFlag : Flag
1919
public override string Description =>
2020
$"Makes a script execute when a trigger with a matching name is fired (done using {nameof(TriggerMethod).Replace("Method", "")} method)";
2121

22-
public override (string argName, string description)? InlineArgDescription =>
23-
("triggerName", "The name of the trigger to bind to.");
24-
25-
public override Dictionary<string, (string description, Func<string[], Result> handler)> Arguments => [];
26-
27-
public override Result TryInitialize(string[] inlineArgs)
28-
{
29-
switch (inlineArgs.Length)
22+
public override Argument? InlineArgument => new(
23+
"triggerName",
24+
"The name of the trigger to bind to.",
25+
inlineArgs =>
3026
{
31-
case < 1: return "Trigger name is missing";
32-
case > 1: return "Too many arguments, only trigger name is allowed";
33-
}
27+
switch (inlineArgs.Length)
28+
{
29+
case < 1: return "Trigger name is missing";
30+
case > 1: return "Too many arguments, only trigger name is allowed";
31+
}
3432

35-
_trigger = inlineArgs.First();
36-
ScriptsBoundToTrigger.AddOrInitListWithKey(_trigger, ScriptName);
37-
return true;
38-
}
33+
_trigger = inlineArgs.First();
34+
ScriptsBoundToTrigger.AddOrInitListWithKey(_trigger, ScriptName);
35+
return true;
36+
},
37+
true
38+
);
39+
40+
public override Argument[] Arguments => [];
3941

4042
public override void FinalizeFlag()
4143
{

FlagSystem/Flags/OnEventFlag.cs

Lines changed: 22 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -15,29 +15,31 @@ public class OnEventFlag : Flag
1515
"Binds a script to an in-game event. When the event happens, the script will execute. " +
1616
"Events can sometimes also carry information of their own, ";
1717

18-
public override (string argName, string description)? InlineArgDescription =>
19-
("eventName", "The name of the event to bind to.");
20-
21-
public override Dictionary<string, (string description, Func<string[], Result> handler)> Arguments => new();
22-
23-
public override Result TryInitialize(string[] inlineArgs)
24-
{
25-
switch (inlineArgs.Length)
18+
public override Argument? InlineArgument => new(
19+
"eventName",
20+
"The name of the event to bind to.",
21+
inlineArgs =>
2622
{
27-
case < 1:
28-
return "Event name is missing";
29-
case > 1:
30-
return "Too many arguments, only event name is allowed";
31-
}
23+
switch (inlineArgs.Length)
24+
{
25+
case < 1:
26+
return "Event name is missing";
27+
case > 1:
28+
return "Too many arguments, only event name is allowed";
29+
}
3230

33-
if (EventHandler.ConnectEvent(inlineArgs.First(), ScriptName).HasErrored(out var error))
34-
{
35-
return error;
36-
}
37-
38-
return true;
39-
}
31+
if (EventHandler.ConnectEvent(inlineArgs.First(), ScriptName).HasErrored(out var error))
32+
{
33+
return error;
34+
}
4035

36+
return true;
37+
},
38+
true
39+
);
40+
41+
public override Argument[] Arguments => [];
42+
4143
public override void FinalizeFlag()
4244
{
4345
}

FlagSystem/ScriptFlagHandler.cs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -64,13 +64,14 @@ private static void HandleFlagArgument(string argName, string[] arguments, strin
6464
return;
6565
}
6666

67-
if (!_currentFlag.Arguments.TryGetValue(argName, out var argInfo))
67+
var arg = _currentFlag.Arguments.FirstOrDefault(arg => arg.Name == argName);
68+
if (string.IsNullOrEmpty(arg.Name))
6869
{
6970
Log.Error(scriptName, $"Flag {_currentFlag.Name} does not accept the '{argName}' argument.");
7071
return;
7172
}
7273

73-
if (argInfo.handler(arguments).HasErrored(out var error))
74+
if (arg.AddArgument(arguments).HasErrored(out var error))
7475
{
7576
Log.Error(scriptName, $"Error while handling flag argument '{argName}' in flag '{_currentFlag.Name}': {error}");
7677
}
@@ -86,10 +87,10 @@ private static void HandleFlag(string name, string[] arguments, string scriptNam
8687
Log.Error(scriptName, rs + getErr);
8788
return;
8889
}
89-
90-
if (flag.TryInitialize(arguments).HasErrored(out var bindErr))
90+
91+
if (flag.InlineArgument.HasValue && flag.InlineArgument.Value.AddArgument(arguments).HasErrored(out var error))
9192
{
92-
Log.Error(scriptName, rs + bindErr);
93+
Log.Error(scriptName, rs + error);
9394
return;
9495
}
9596

FlagSystem/Structures/Flag.cs

Lines changed: 16 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -3,25 +3,26 @@
33
using System.Linq;
44
using System.Reflection;
55
using LabApi.Features.Console;
6+
using SER.Helpers.Extensions;
67
using SER.Helpers.ResultSystem;
7-
using FlagDictionary = System.Collections.Generic.Dictionary<string,
8-
(
9-
System.Type type,
10-
string description,
11-
(string argName, string description)? inlineArgDescription, System.Collections.Generic.Dictionary<string, string> argDescription
12-
)>;
138

149
namespace SER.FlagSystem.Structures;
1510

1611
public abstract class Flag
1712
{
1813
public abstract string Description { get; }
1914

20-
public abstract (string argName, string description)? InlineArgDescription { get; }
15+
public readonly struct Argument(string name, string description, Func<string[], Result> handler, bool required)
16+
{
17+
public string Name => name;
18+
public string Description => description;
19+
public Result AddArgument(string[] values) => handler(values);
20+
public bool IsRequired => required;
21+
}
2122

22-
public abstract Dictionary<string, (string description, Func<string[], Result> handler)> Arguments { get; }
23+
public abstract Argument? InlineArgument { get; }
2324

24-
public abstract Result TryInitialize(string[] inlineArgs);
25+
public abstract Argument[] Arguments { get; }
2526

2627
public abstract void FinalizeFlag();
2728

@@ -31,7 +32,7 @@ public abstract class Flag
3132

3233
public string Name { get; set; } = null!;
3334

34-
public static FlagDictionary FlagInfos = [];
35+
public static Dictionary<string, Type> FlagInfos = [];
3536

3637
internal static void RegisterFlags()
3738
{
@@ -46,32 +47,22 @@ public static void RegisterFlagsAsExternalPlugin()
4647
FlagInfos = FlagInfos.Concat(flags).ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
4748
}
4849

49-
private static FlagDictionary GetRegisteredFlags(Assembly ass)
50+
private static Dictionary<string, Type> GetRegisteredFlags(Assembly? ass = null)
5051
{
52+
ass ??= Assembly.GetExecutingAssembly();
5153
return ass.GetTypes()
5254
.Where(t => t.IsClass && !t.IsAbstract && typeof(Flag).IsAssignableFrom(t))
53-
.Select(t => (t, Activator.CreateInstance(t) as Flag))
54-
.Cast<(Type type, Flag flag)>()
55-
.ToDictionary(tuple => tuple.type.Name.Replace("Flag", ""), tuple =>
56-
{
57-
return
58-
(
59-
tuple.type,
60-
tuple.flag.Description,
61-
tuple.flag.InlineArgDescription,
62-
tuple.flag.Arguments.ToDictionary(kvp => kvp.Key, kvp => kvp.Value.description)
63-
);
64-
});
55+
.ToDictionary(t => t.Name.Replace("Flag", ""), t => t);
6556
}
6657

6758
public static TryGet<Flag> TryGet(string flagName, string scriptName)
6859
{
69-
if (!FlagInfos.TryGetValue(flagName, out var tuple))
60+
if (!FlagInfos.TryGetValue(flagName, out var type))
7061
{
7162
return $"Flag '{flagName}' is not a valid flag.";
7263
}
7364

74-
var flag = (Flag)Activator.CreateInstance(tuple.type);
65+
var flag = type.CreateInstance<Flag>();
7566
flag.ScriptName = scriptName;
7667
flag.Name = flagName;
7768
return flag;

0 commit comments

Comments
 (0)