From a0b6decf78c0ffa8d980c8d0a81fd47821fd214c Mon Sep 17 00:00:00 2001 From: Ethan Moffat Date: Sun, 6 Feb 2022 17:48:52 -0800 Subject: [PATCH 1/5] Add error, getenv, and setenv functions. Reduce code duplication in FunctionEvaluator. FunctionEvaluator exception handling for dispatched calls now happens in one place instead of being copy/pasted --- EOBot/EOBot.csproj | 1 + EOBot/Interpreter/BotScriptErrorException.cs | 13 + .../BuiltInIdentifierConfigurator.cs | 15 +- EOBot/Interpreter/States/FunctionEvaluator.cs | 225 +++++------------- .../Variables/PredefinedIdentifiers.cs | 4 + EOBot/Program.cs | 14 +- 6 files changed, 104 insertions(+), 168 deletions(-) create mode 100644 EOBot/Interpreter/BotScriptErrorException.cs diff --git a/EOBot/EOBot.csproj b/EOBot/EOBot.csproj index 7b309cf5e..1e249d8c7 100644 --- a/EOBot/EOBot.csproj +++ b/EOBot/EOBot.csproj @@ -95,6 +95,7 @@ + diff --git a/EOBot/Interpreter/BotScriptErrorException.cs b/EOBot/Interpreter/BotScriptErrorException.cs new file mode 100644 index 000000000..b2c54ff09 --- /dev/null +++ b/EOBot/Interpreter/BotScriptErrorException.cs @@ -0,0 +1,13 @@ +using System; + +namespace EOBot.Interpreter +{ + public class BotScriptErrorException : Exception + { + public BotScriptErrorException(string message) + : base(message) { } + + public BotScriptErrorException(string message, BotToken token) + : base($"Error at line {token.LineNumber} column {token.Column}: {message}") { } + } +} diff --git a/EOBot/Interpreter/BuiltInIdentifierConfigurator.cs b/EOBot/Interpreter/BuiltInIdentifierConfigurator.cs index 541a00c37..6f66c7c33 100644 --- a/EOBot/Interpreter/BuiltInIdentifierConfigurator.cs +++ b/EOBot/Interpreter/BuiltInIdentifierConfigurator.cs @@ -42,6 +42,9 @@ public void SetupBuiltInFunctions() _state.SymbolTable[PredefinedIdentifiers.SLEEP_FUNC] = Readonly(new VoidFunction(PredefinedIdentifiers.SLEEP_FUNC, param1 => Thread.Sleep(param1))); _state.SymbolTable[PredefinedIdentifiers.TIME_FUNC] = Readonly(new Function(PredefinedIdentifiers.TIME_FUNC, () => DateTime.Now.ToLongTimeString())); _state.SymbolTable[PredefinedIdentifiers.OBJECT_FUNC] = Readonly(new Function(PredefinedIdentifiers.OBJECT_FUNC, () => new ObjectVariable())); + _state.SymbolTable[PredefinedIdentifiers.SETENV_FUNC] = Readonly(new VoidFunction(PredefinedIdentifiers.SETENV_FUNC, (varName, varValue) => Environment.SetEnvironmentVariable(varName, varValue, EnvironmentVariableTarget.User))); + _state.SymbolTable[PredefinedIdentifiers.GETENV_FUNC] = Readonly(new Function(PredefinedIdentifiers.GETENV_FUNC, varName => Environment.GetEnvironmentVariable(varName, EnvironmentVariableTarget.User))); + _state.SymbolTable[PredefinedIdentifiers.ERROR_FUNC] = Readonly(new VoidFunction(PredefinedIdentifiers.ERROR_FUNC, message => throw new BotScriptErrorException(message))); BotDependencySetup(); _state.SymbolTable[PredefinedIdentifiers.CONNECT_FUNC] = Readonly(new AsyncVoidFunction(PredefinedIdentifiers.CONNECT_FUNC, ConnectAsync)); @@ -56,12 +59,12 @@ public void SetupBuiltInFunctions() } public void SetupBuiltInVariables() { - _state.SymbolTable[PredefinedIdentifiers.HOST] = (true, new StringVariable(_parsedArgs.Host)); - _state.SymbolTable[PredefinedIdentifiers.PORT] = (true, new IntVariable(_parsedArgs.Port)); - _state.SymbolTable[PredefinedIdentifiers.USER] = (true, new StringVariable(_parsedArgs.Account)); - _state.SymbolTable[PredefinedIdentifiers.PASS] = (true, new StringVariable(_parsedArgs.Password)); - _state.SymbolTable[PredefinedIdentifiers.BOTINDEX] = (true, new IntVariable(_botIndex)); - _state.SymbolTable[PredefinedIdentifiers.ARGS] = (true, new ArrayVariable( + _state.SymbolTable[PredefinedIdentifiers.HOST] = Readonly(new StringVariable(_parsedArgs.Host)); + _state.SymbolTable[PredefinedIdentifiers.PORT] = Readonly(new IntVariable(_parsedArgs.Port)); + _state.SymbolTable[PredefinedIdentifiers.USER] = Readonly(new StringVariable(_parsedArgs.Account)); + _state.SymbolTable[PredefinedIdentifiers.PASS] = Readonly(new StringVariable(_parsedArgs.Password)); + _state.SymbolTable[PredefinedIdentifiers.BOTINDEX] = Readonly(new IntVariable(_botIndex)); + _state.SymbolTable[PredefinedIdentifiers.ARGS] = Readonly(new ArrayVariable( (_parsedArgs.UserArgs ?? new List()).Select(x => new StringVariable(x)).Cast().ToList())); // default to version 0.0.28 diff --git a/EOBot/Interpreter/States/FunctionEvaluator.cs b/EOBot/Interpreter/States/FunctionEvaluator.cs index 41847eb0c..8888e0837 100644 --- a/EOBot/Interpreter/States/FunctionEvaluator.cs +++ b/EOBot/Interpreter/States/FunctionEvaluator.cs @@ -59,36 +59,20 @@ public FunctionEvaluator(IEnumerable evaluators) var function = input.SymbolTable[functionToken.TokenValue].Identifiable; - if (function is IAsyncFunction) - return await CallAsync(input, functionToken, (dynamic)function, parameters.Select(x => x.VariableValue).ToArray()); - else if (function is IFunction) - return Call(input, functionToken, (dynamic)function, parameters.Select(x => x.VariableValue).ToArray()); - else - return (EvalResult.Failed, $"Expected identifier {functionToken.TokenValue} to be a function, but it was {function.GetType().Name}", functionToken); - } - - private (EvalResult, string, BotToken) Call(ProgramState input, BotToken functionToken, ICallable function, params IVariable[] variables) - { try { - function.Call(variables); - } - catch (ArgumentException ae) - { - return (EvalResult.Failed, ae.Message, functionToken); + if (function is IAsyncFunction) + await CallAsync(input, (dynamic)function, parameters.Select(x => x.VariableValue).ToArray()); + else if (function is IFunction) + Call(input, (dynamic)function, parameters.Select(x => x.VariableValue).ToArray()); + else + return (EvalResult.Failed, $"Expected identifier {functionToken.TokenValue} to be a function, but it was {function.GetType().Name}", functionToken); } - - return Success(); - } - - private (EvalResult, string, BotToken) Call(ProgramState input, BotToken functionToken, ICallable function, params IVariable[] variables) - { - try + catch (BotScriptErrorException bse) { - var result = function.Call(variables); - var varResult = new IntVariable(result); - input.SymbolTable[PredefinedIdentifiers.RESULT] = (true, varResult); - input.OperationStack.Push(new VariableBotToken(BotTokenType.Literal, varResult.StringValue, varResult)); + // stack information isn't really important since this is only used to signal to the framework that a bot failed + // recreate the exception so it prints line number/column info with the error + throw new BotScriptErrorException(bse.Message, functionToken); } catch (ArgumentException ae) { @@ -98,169 +82,92 @@ public FunctionEvaluator(IEnumerable evaluators) return Success(); } - private (EvalResult, string, BotToken) Call(ProgramState input, BotToken functionToken, ICallable function, params IVariable[] variables) + private void Call(ProgramState input, ICallable function, params IVariable[] variables) { - try - { - var result = function.Call(variables); - var varResult = new StringVariable(result); - input.SymbolTable[PredefinedIdentifiers.RESULT] = (true, varResult); - input.OperationStack.Push(new VariableBotToken(BotTokenType.Literal, varResult.StringValue, varResult)); - } - catch (ArgumentException ae) - { - return (EvalResult.Failed, ae.Message, functionToken); - } - - return Success(); + function.Call(variables); } - private (EvalResult, string, BotToken) Call(ProgramState input, BotToken functionToken, ICallable> function, params IVariable[] variables) + private void Call(ProgramState input, ICallable function, params IVariable[] variables) { - try - { - var result = function.Call(variables); - var varResult = new ArrayVariable(result); - input.SymbolTable[PredefinedIdentifiers.RESULT] = (true, varResult); - input.OperationStack.Push(new VariableBotToken(BotTokenType.Literal, varResult.StringValue, varResult)); - } - catch (ArgumentException ae) - { - return (EvalResult.Failed, ae.Message, functionToken); - } - - return Success(); + var result = function.Call(variables); + var varResult = new IntVariable(result); + input.SymbolTable[PredefinedIdentifiers.RESULT] = (true, varResult); + input.OperationStack.Push(new VariableBotToken(BotTokenType.Literal, varResult.StringValue, varResult)); } - private (EvalResult, string, BotToken) Call(ProgramState input, BotToken functionToken, ICallable function, params IVariable[] variables) + private void Call(ProgramState input, ICallable function, params IVariable[] variables) { - try - { - var result = function.Call(variables); - var varResult = new BoolVariable(result); - input.SymbolTable[PredefinedIdentifiers.RESULT] = (true, varResult); - input.OperationStack.Push(new VariableBotToken(BotTokenType.Literal, varResult.StringValue, varResult)); - } - catch (ArgumentException ae) - { - return (EvalResult.Failed, ae.Message, functionToken); - } - - return Success(); + var result = function.Call(variables); + var varResult = new StringVariable(result); + input.SymbolTable[PredefinedIdentifiers.RESULT] = (true, varResult); + input.OperationStack.Push(new VariableBotToken(BotTokenType.Literal, varResult.StringValue, varResult)); } - private (EvalResult, string, BotToken) Call(ProgramState input, BotToken functionToken, ICallable function, params IVariable[] variables) + private void Call(ProgramState input, ICallable> function, params IVariable[] variables) { - try - { - var varResult = function.Call(variables); - input.SymbolTable[PredefinedIdentifiers.RESULT] = (true, varResult); - input.OperationStack.Push(new VariableBotToken(BotTokenType.Literal, varResult.StringValue, varResult)); - } - catch (ArgumentException ae) - { - return (EvalResult.Failed, ae.Message, functionToken); - } - - return Success(); + var result = function.Call(variables); + var varResult = new ArrayVariable(result); + input.SymbolTable[PredefinedIdentifiers.RESULT] = (true, varResult); + input.OperationStack.Push(new VariableBotToken(BotTokenType.Literal, varResult.StringValue, varResult)); } - private async Task<(EvalResult, string, BotToken)> CallAsync(ProgramState input, BotToken functionToken, IAsyncCallable function, params IVariable[] variables) + private void Call(ProgramState input, ICallable function, params IVariable[] variables) { - try - { - await function.CallAsync(variables); - } - catch (ArgumentException ae) - { - return (EvalResult.Failed, ae.Message, functionToken); - } - - return Success(); + var result = function.Call(variables); + var varResult = new BoolVariable(result); + input.SymbolTable[PredefinedIdentifiers.RESULT] = (true, varResult); + input.OperationStack.Push(new VariableBotToken(BotTokenType.Literal, varResult.StringValue, varResult)); } - private async Task<(EvalResult, string, BotToken)> CallAsync(ProgramState input, BotToken functionToken, IAsyncCallable function, params IVariable[] variables) + private void Call(ProgramState input, ICallable function, params IVariable[] variables) { - try - { - var result = await function.CallAsync(variables); - var varResult = new IntVariable(result); - input.SymbolTable[PredefinedIdentifiers.RESULT] = (true, varResult); - input.OperationStack.Push(new VariableBotToken(BotTokenType.Literal, varResult.StringValue, varResult)); - } - catch (ArgumentException ae) - { - return (EvalResult.Failed, ae.Message, functionToken); - } - - return Success(); + var varResult = function.Call(variables); + input.SymbolTable[PredefinedIdentifiers.RESULT] = (true, varResult); + input.OperationStack.Push(new VariableBotToken(BotTokenType.Literal, varResult.StringValue, varResult)); } - private async Task<(EvalResult, string, BotToken)> CallAsync(ProgramState input, BotToken functionToken, IAsyncCallable function, params IVariable[] variables) + private async Task CallAsync(ProgramState input, IAsyncCallable function, params IVariable[] variables) { - try - { - var result = await function.CallAsync(variables); - var varResult = new StringVariable(result); - input.SymbolTable[PredefinedIdentifiers.RESULT] = (true, varResult); - input.OperationStack.Push(new VariableBotToken(BotTokenType.Literal, varResult.StringValue, varResult)); - } - catch (ArgumentException ae) - { - return (EvalResult.Failed, ae.Message, functionToken); - } - - return Success(); + await function.CallAsync(variables); } - private async Task<(EvalResult, string, BotToken)> CallAsync(ProgramState input, BotToken functionToken, IAsyncCallable> function, params IVariable[] variables) + private async Task CallAsync(ProgramState input, IAsyncCallable function, params IVariable[] variables) { - try - { - var result = await function.CallAsync(variables); - var varResult = new ArrayVariable(result); - input.SymbolTable[PredefinedIdentifiers.RESULT] = (true, varResult); - input.OperationStack.Push(new VariableBotToken(BotTokenType.Literal, varResult.StringValue, varResult)); - } - catch (ArgumentException ae) - { - return (EvalResult.Failed, ae.Message, functionToken); - } - - return Success(); + var result = await function.CallAsync(variables); + var varResult = new IntVariable(result); + input.SymbolTable[PredefinedIdentifiers.RESULT] = (true, varResult); + input.OperationStack.Push(new VariableBotToken(BotTokenType.Literal, varResult.StringValue, varResult)); } - private async Task<(EvalResult, string, BotToken)> CallAsync(ProgramState input, BotToken functionToken, IAsyncCallable function, params IVariable[] variables) + private async Task CallAsync(ProgramState input, IAsyncCallable function, params IVariable[] variables) { - try - { - var result = await function.CallAsync(variables); - var varResult = new BoolVariable(result); - input.SymbolTable[PredefinedIdentifiers.RESULT] = (true, varResult); - input.OperationStack.Push(new VariableBotToken(BotTokenType.Literal, varResult.StringValue, varResult)); - } - catch (ArgumentException ae) - { - return (EvalResult.Failed, ae.Message, functionToken); - } + var result = await function.CallAsync(variables); + var varResult = new StringVariable(result); + input.SymbolTable[PredefinedIdentifiers.RESULT] = (true, varResult); + input.OperationStack.Push(new VariableBotToken(BotTokenType.Literal, varResult.StringValue, varResult)); + } - return Success(); + private async Task CallAsync(ProgramState input, IAsyncCallable> function, params IVariable[] variables) + { + var result = await function.CallAsync(variables); + var varResult = new ArrayVariable(result); + input.SymbolTable[PredefinedIdentifiers.RESULT] = (true, varResult); + input.OperationStack.Push(new VariableBotToken(BotTokenType.Literal, varResult.StringValue, varResult)); } - private async Task<(EvalResult, string, BotToken)> CallAsync(ProgramState input, BotToken functionToken, IAsyncCallable function, params IVariable[] variables) + private async Task CallAsync(ProgramState input, IAsyncCallable function, params IVariable[] variables) { - try - { - var varResult = await function.CallAsync(variables); - input.SymbolTable[PredefinedIdentifiers.RESULT] = (true, varResult); - input.OperationStack.Push(new VariableBotToken(BotTokenType.Literal, varResult.StringValue, varResult)); - } - catch (ArgumentException ae) - { - return (EvalResult.Failed, ae.Message, functionToken); - } + var result = await function.CallAsync(variables); + var varResult = new BoolVariable(result); + input.SymbolTable[PredefinedIdentifiers.RESULT] = (true, varResult); + input.OperationStack.Push(new VariableBotToken(BotTokenType.Literal, varResult.StringValue, varResult)); + } - return Success(); + private async Task CallAsync(ProgramState input, IAsyncCallable function, params IVariable[] variables) + { + var varResult = await function.CallAsync(variables); + input.SymbolTable[PredefinedIdentifiers.RESULT] = (true, varResult); + input.OperationStack.Push(new VariableBotToken(BotTokenType.Literal, varResult.StringValue, varResult)); } } } \ No newline at end of file diff --git a/EOBot/Interpreter/Variables/PredefinedIdentifiers.cs b/EOBot/Interpreter/Variables/PredefinedIdentifiers.cs index 5ab8e48d0..bd779f3e4 100644 --- a/EOBot/Interpreter/Variables/PredefinedIdentifiers.cs +++ b/EOBot/Interpreter/Variables/PredefinedIdentifiers.cs @@ -11,6 +11,7 @@ public static class PredefinedIdentifiers public const string VERSION = "version"; public const string ARGS = "args"; public const string BOTINDEX = "botindex"; + public const string RETCODE = "retcode"; // state variables public const string ACCOUNT = "account"; @@ -27,6 +28,9 @@ public static class PredefinedIdentifiers public const string OBJECT_FUNC = "object"; public const string SLEEP_FUNC = "sleep"; public const string TIME_FUNC = "time"; + public const string SETENV_FUNC = "setenv"; + public const string GETENV_FUNC = "getenv"; + public const string ERROR_FUNC = "error"; // game functions public const string CONNECT_FUNC = "Connect"; diff --git a/EOBot/Program.cs b/EOBot/Program.cs index 1d2caa173..2657b5e5f 100644 --- a/EOBot/Program.cs +++ b/EOBot/Program.cs @@ -1,4 +1,5 @@ using AutomaticTypeMapper; +using EOBot.Interpreter; using EOLib.Domain.Character; using EOLib.Domain.Extensions; using EOLib.Domain.Map; @@ -154,7 +155,7 @@ public void StartOtherCharacterAttackAnimation(int characterID) { } public void StartOtherCharacterWalkAnimation(int characterID) { } } - static async Task Main(string[] args) + static async Task Main(string[] args) { var assemblyNames = new[] { @@ -178,7 +179,7 @@ static async Task Main(string[] args) if (parsedArgs.Error != ArgsError.NoError) { ShowError(parsedArgs); - return; + return 1; } DependencyMaster.TypeRegistry = new ITypeRegistry[parsedArgs.NumBots]; @@ -202,7 +203,7 @@ static async Task Main(string[] args) if (parsedArgs.NumBots > 1 && parsedArgs.ScriptFile != null && !parsedArgs.AutoConnect ) { ConsoleHelper.WriteMessage(ConsoleHelper.Type.Error, "AutoConnect is required when using a script with more than 1 bot due to eoserv connection throttling"); - return; + return 1; } ConsoleHelper.WriteMessage(ConsoleHelper.Type.None, "Starting bots..."); @@ -222,10 +223,17 @@ static async Task Main(string[] args) { ConsoleHelper.WriteMessage(ConsoleHelper.Type.Error, bex.Message, ConsoleColor.DarkRed); } + catch (BotScriptErrorException bse) + { + ConsoleHelper.WriteMessage(ConsoleHelper.Type.Error, bse.Message, ConsoleColor.DarkRed); + return 1; + } catch (Exception ex) { ConsoleHelper.WriteMessage(ConsoleHelper.Type.Error, $"Unhandled error: {ex.Message}", ConsoleColor.DarkRed); } + + return 0; } static bool HandleCtrl(Win32.CtrlTypes type) From 940e3ccc828261f1919a59666e3bf08431a28eab Mon Sep 17 00:00:00 2001 From: Ethan Moffat Date: Sun, 6 Feb 2022 19:34:05 -0800 Subject: [PATCH 2/5] Use consistent method for checking validity of arguments --- EOBot/ArgumentsParser.cs | 138 +++++++++++++++++++++++---------------- EOBot/Program.cs | 18 +++-- 2 files changed, 91 insertions(+), 65 deletions(-) diff --git a/EOBot/ArgumentsParser.cs b/EOBot/ArgumentsParser.cs index de48b7245..2de648d01 100644 --- a/EOBot/ArgumentsParser.cs +++ b/EOBot/ArgumentsParser.cs @@ -17,7 +17,9 @@ public enum ArgsError InvalidSimultaneousNumberOfBots, InvalidWaitFlag, InvalidInitDelay, - InvalidPath + InvalidPath, + InvalidScriptArgs, + AutoConnectRequired } public class ArgumentsParser @@ -42,80 +44,100 @@ public class ArgumentsParser public List UserArgs { get; internal set; } + public bool ExtendedHelp { get; private set; } + + public ArgumentsParser(string[] args) { InitDelay = 1100; Error = ArgsError.NoError; - if (args.Length < 5) + if (args.Select(x => x.ToLower()).Any(x => x == "help")) { - Error = ArgsError.WrongNumberOfArgs; - return; + ExtendedHelp = true; } - - for (int i = 0; i < args.Length; i++) + else { - var arg = args[i]; - - if (arg == "--") + for (int i = 0; i < args.Length; i++) { - UserArgs = new List(); - for (i = i + 1; i < args.Length; i++) + var arg = args[i]; + + if (arg == "--") { - UserArgs.Add(args[i]); + UserArgs = new List(); + for (i = i + 1; i < args.Length; i++) + { + UserArgs.Add(args[i]); + } + break; } - break; - } - var pair = arg.ToLower().Split('='); + var pair = arg.ToLower().Split('='); - if (pair.Length != 2) - { - Error = ArgsError.BadFormat; - return; + if (pair.Length != 2) + { + Error = ArgsError.BadFormat; + return; + } + + switch (pair[0]) + { + case "script": + if (!File.Exists(pair[1])) + { + Error = ArgsError.InvalidPath; + return; + } + ScriptFile = pair[1]; + break; + case "autoconnect": + AutoConnect = bool.Parse(pair[1]); + break; + case "host": + ParseHost(pair[1]); + break; + case "port": + if (!ParsePort(pair[1])) + return; + break; + case "bots": + if (!ParseNumBots(pair)) + return; + break; + case "initdelay": + if (!ParseInitDelay(pair[1])) + return; + break; + case "account": + Account = pair[1]; + break; + case "password": + Password = pair[1]; + break; + case "character": + Character = pair[1]; + break; + default: + Error = ArgsError.BadFormat; + return; + } } - switch (pair[0]) + if (ScriptFile == null) { - case "script": - if (!File.Exists(pair[1])) - { - Error = ArgsError.InvalidPath; - return; - } - ScriptFile = pair[1]; - break; - case "autoconnect": - AutoConnect = bool.Parse(pair[1]); - break; - case "host": - ParseHost(pair[1]); - break; - case "port": - if (!ParsePort(pair[1])) - return; - break; - case "bots": - if (!ParseNumBots(pair)) - return; - break; - case "initdelay": - if (!ParseInitDelay(pair[1])) - return; - break; - case "account": - Account = pair[1]; - break; - case "password": - Password = pair[1]; - break; - case "character": - Character = pair[1]; - break; - default: - Error = ArgsError.BadFormat; - return; + if (Host == null || Port == 0 || NumBots == 0 || Account == null || Password == null || Character == null) + { + Error = ArgsError.WrongNumberOfArgs; + } + else if (UserArgs != null || !AutoConnect) + { + Error = ArgsError.InvalidScriptArgs; + } + } + else if (NumBots > 1 && ScriptFile != null && !AutoConnect) + { + Error = ArgsError.AutoConnectRequired; } } } diff --git a/EOBot/Program.cs b/EOBot/Program.cs index 2657b5e5f..5d9a28755 100644 --- a/EOBot/Program.cs +++ b/EOBot/Program.cs @@ -176,7 +176,7 @@ static async Task Main(string[] args) ArgumentsParser parsedArgs = new ArgumentsParser(args); - if (parsedArgs.Error != ArgsError.NoError) + if (parsedArgs.Error != ArgsError.NoError || parsedArgs.ExtendedHelp) { ShowError(parsedArgs); return 1; @@ -200,12 +200,6 @@ static async Task Main(string[] args) botFactory = new TrainerBotFactory(parsedArgs); } - if (parsedArgs.NumBots > 1 && parsedArgs.ScriptFile != null && !parsedArgs.AutoConnect ) - { - ConsoleHelper.WriteMessage(ConsoleHelper.Type.Error, "AutoConnect is required when using a script with more than 1 bot due to eoserv connection throttling"); - return 1; - } - ConsoleHelper.WriteMessage(ConsoleHelper.Type.None, "Starting bots..."); try @@ -280,6 +274,12 @@ static void ShowError(ArgumentsParser args) case ArgsError.InvalidPath: Console.WriteLine("Invalid: Script file does not exist or is not a valid path."); break; + case ArgsError.InvalidScriptArgs: + Console.WriteLine("Invalid: User-defined arguments and disabling autoconnect require a script."); + break; + case ArgsError.AutoConnectRequired: + Console.WriteLine("Invalid: AutoConnect is required when using a script with more than 1 bot due to eoserv connection throttling."); + break; } Console.WriteLine("\n\nUsage: (enter arguments in any order) (angle brackets is entry) (square brackets is optional)"); @@ -303,6 +303,10 @@ static void ShowError(ArgumentsParser args) Console.WriteLine("\t script: script file to execute\n\t if script is not specified, default trainer bot will be used"); Console.WriteLine("\t autoconnect: (default true) true to automatically connect/disconnect to server with initDelay timeout between connection attempts for bots, false otherwise"); Console.WriteLine("\t --: Any arguments passed after '--' will be available in a script under the '$args' array"); + + if (!args.ExtendedHelp) + return; + Console.WriteLine(@" =============================================================== Bot Script Info From f418d5fdea1304c69d52b1a6afbe2d709f3eb1e6 Mon Sep 17 00:00:00 2001 From: Ethan Moffat Date: Sun, 6 Feb 2022 19:36:49 -0800 Subject: [PATCH 3/5] Fix extended help case if user-defined args contains "help" --- EOBot/ArgumentsParser.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/EOBot/ArgumentsParser.cs b/EOBot/ArgumentsParser.cs index 2de648d01..62b50a831 100644 --- a/EOBot/ArgumentsParser.cs +++ b/EOBot/ArgumentsParser.cs @@ -53,7 +53,8 @@ public ArgumentsParser(string[] args) Error = ArgsError.NoError; - if (args.Select(x => x.ToLower()).Any(x => x == "help")) + if ((!args.Contains("--") && args.Select(x => x.ToLower()).Contains("help")) || + (args.Contains("--") && args.TakeWhile(x => x != "--").Select(x => x.ToLower()).Contains("help"))) { ExtendedHelp = true; } From 284ac1bb3cf0c5e3b776ff95efe5a4b9563c2c17 Mon Sep 17 00:00:00 2001 From: Ethan Moffat Date: Sun, 6 Feb 2022 21:39:35 -0800 Subject: [PATCH 4/5] Fix if evaluation when skipping blocks with more than one newline after --- EOBot/Interpreter/States/IfEvaluator.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/EOBot/Interpreter/States/IfEvaluator.cs b/EOBot/Interpreter/States/IfEvaluator.cs index ed4d8736c..10786cd1a 100644 --- a/EOBot/Interpreter/States/IfEvaluator.cs +++ b/EOBot/Interpreter/States/IfEvaluator.cs @@ -44,6 +44,7 @@ public IfEvaluator(IEnumerable evaluators) { input.Expect(BotTokenType.Keyword); SkipBlock(input); + while (input.Expect(BotTokenType.NewLine)) ; } RestoreLastNewline(input); From b98a7c9b66781fe0ff4e507facdf08ff7e7a6d59 Mon Sep 17 00:00:00 2001 From: Ethan Moffat Date: Sun, 6 Feb 2022 22:25:41 -0800 Subject: [PATCH 5/5] Rev version to 0.2.x --- azure-pipelines.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index ec3918827..ab5f8346d 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -1,4 +1,4 @@ -name: 0.1.$(rev:rrr) +name: 0.2.$(rev:rrr) variables: - name: BuildParameters.solution