Scripting() { if (Engine.EditorHint) { return; } Self = this; ScriptOptions = Sc.ScriptOptions.Default.WithReferences(AppDomain.CurrentDomain.GetAssemblies()) .AddReferences(Assembly.GetAssembly(typeof(System.Dynamic.DynamicObject)), // System.Code Assembly.GetAssembly(typeof(Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo)), // Microsoft.CSharp Assembly.GetAssembly(typeof(System.Dynamic.ExpandoObject))); // System.Dynamic Sc.Script CEngine = Cs.Create("", ScriptOptions); ConsoleState = CEngine.ContinueWith("using System; using System.Dynamic; using Godot; using static API; using static Items.ID;") .RunAsync().Result; }
public static void RunConsoleLine(string Line) { object Returned = null; try { ConsoleState = ConsoleState.ContinueWithAsync(Line).Result; Returned = ConsoleState.ReturnValue as object; //just in case of an issue this should become null } catch (Exception Err) { Console.Print(Err.Message); } if (Returned != null) { Console.Print(Returned); } }
public static bool LoadGamemode(string Name) { UnloadGamemode(); Directory ModeDir = new Directory(); if (ModeDir.FileExists($"user://Gamemodes/{Name}/{Name}.json")) { Console.Log($"Found gamemode '{Name}', loading"); GmConfigClass Config; { File ConfigFile = new File(); ConfigFile.Open($"user://Gamemodes/{Name}/{Name}.json", 1); try { Config = Newtonsoft.Json.JsonConvert.DeserializeObject <GmConfigClass>(ConfigFile.GetAsText()); ConfigFile.Close(); } catch (Newtonsoft.Json.JsonReaderException) { ConfigFile.Close(); Console.ThrowLog($"Failed to parse config file for gamemode '{Name}'"); return(false); } } if (Config.MainScript == null) { Console.ThrowLog($"The gamemode '{Name}' did not specify a path for MainScript"); return(false); } File ScriptFile = new File(); if (!ScriptFile.FileExists($"user://Gamemodes/{Name}/{Config.MainScript}")) { Console.ThrowLog($"Specified MainScript '{Config.MainScript}' for gamemode '{Name}' does not exist"); return(false); } ScriptFile.Open($"user://Gamemodes/{Name}/{Config.MainScript}", 1); Sc.Script Engine = Cs.Create(ScriptFile.GetAsText(), ScriptOptions.WithSourceResolver(new Microsoft.CodeAnalysis.SourceFileResolver(ImmutableArray <string> .Empty, $"{OS.GetUserDataDir()}/Gamemodes/{Name}")) .WithEmitDebugInformation(true) .WithFilePath($"{OS.GetUserDataDir()}/Gamemodes/{Name}") .WithFileEncoding(System.Text.Encoding.UTF8)); //NOTE Hardcoding UTF8 should work for now ScriptFile.Close(); object Returned = null; try { Sc.ScriptState State = Engine.RunAsync().Result; Returned = State.ReturnValue; } catch (Exception Err) { Console.ThrowLog($"Error executing gamemode '{Name}': {Err.Message}"); return(false); } if (Returned is Gamemode) { GamemodeName = Name; Game.Mode = Returned as Gamemode; Game.Mode.SetName("Gamemode"); Game.Mode.Self = Game.Mode; Game.Mode.LoadPath = $"{OS.GetUserDataDir()}/Gamemodes/{Name}"; Game.Mode.OwnName = Name; Game.Self.AddChild(Game.Mode); return(true); } else { Console.ThrowLog($"Gamemode script '{Name}' did not return a valid Gamemode instance, unloading"); return(false); } } else { Console.ThrowPrint($"No gamemode named '{Name}'"); return(false); } }
internal abstract Task <ScriptState> CommonContinueAsync(ScriptState previousState, CancellationToken cancellationToken);
public static bool Bind(string KeyName, string FunctionName) { BindingObject NewBind = new BindingObject(KeyName); //We need to check that the function exitst and either takes no args or one float arg and get the Action try //First assume it takes a float argument { Sc.ScriptState State = Scripting.ConsoleState.ContinueWithAsync($"return new Action<float>(delegate(float x) {{ {FunctionName}(x); }} );").Result; NewBind.FuncWithArg = State.ReturnValue as Action <float>; } catch //Must either not exist or has different argument requirements { try //Next we assume that it exists but without an argument { Sc.ScriptState State = Scripting.ConsoleState.ContinueWithAsync($"return new Action(delegate() {{ {FunctionName}(); }} );").Result; NewBind.FuncWithoutArg = State.ReturnValue as Action; } catch //At this point we know it either does not exist or has incompatible argument requirements { Console.ThrowPrint($"The supplied function '{FunctionName}' does not exist, does not take a single float argument, or does not take zero arguments"); return(false); } } Nullable <ButtonList> ButtonValue = null; //Making it null by default prevents a compile warning further down Nullable <DIRECTION> AxisDirection = null; //Making it null by default prevents a compile warning further down Nullable <JoystickList> ControllerButtonValue = null; // Making a new variable for Controller buttons because int Scancode = 0; switch (KeyName) //Checks custom string literals first then assumes Scancode { case ("MouseOne"): { NewBind.Type = TYPE.MOUSEBUTTON; ButtonValue = ButtonList.Left; break; } case ("MouseTwo"): { NewBind.Type = TYPE.MOUSEBUTTON; ButtonValue = ButtonList.Right; break; } case ("MouseThree"): { NewBind.Type = TYPE.MOUSEBUTTON; ButtonValue = ButtonList.Middle; break; } case ("WheelUp"): { NewBind.Type = TYPE.MOUSEWHEEL; ButtonValue = ButtonList.WheelUp; break; } case ("WheelDown"): { NewBind.Type = TYPE.MOUSEWHEEL; ButtonValue = ButtonList.WheelDown; break; } case ("MouseUp"): { NewBind.Type = TYPE.MOUSEAXIS; AxisDirection = DIRECTION.UP; break; } case ("MouseDown"): { NewBind.Type = TYPE.MOUSEAXIS; AxisDirection = DIRECTION.DOWN; break; } case ("MouseRight"): { NewBind.Type = TYPE.MOUSEAXIS; AxisDirection = DIRECTION.RIGHT; break; } case ("MouseLeft"): { NewBind.Type = TYPE.MOUSEAXIS; AxisDirection = DIRECTION.LEFT; break; } case ("LeftStickUp"): { NewBind.Type = TYPE.CONTROLLERAXIS; AxisDirection = DIRECTION.UP; ControllerButtonValue = JoystickList.AnalogLy; break; } case ("LeftStickDown"): { NewBind.Type = TYPE.CONTROLLERAXIS; AxisDirection = DIRECTION.DOWN; ControllerButtonValue = JoystickList.AnalogLy; break; } case ("LeftStickLeft"): { NewBind.Type = TYPE.CONTROLLERAXIS; AxisDirection = DIRECTION.LEFT; ControllerButtonValue = JoystickList.AnalogLx; break; } case ("LeftStickRight"): { NewBind.Type = TYPE.CONTROLLERAXIS; AxisDirection = DIRECTION.RIGHT; ControllerButtonValue = JoystickList.AnalogLx; break; } case ("RightStickUp"): { NewBind.Type = TYPE.CONTROLLERAXIS; AxisDirection = DIRECTION.UP; ControllerButtonValue = JoystickList.AnalogRy; break; } case ("RightStickDown"): { NewBind.Type = TYPE.CONTROLLERAXIS; AxisDirection = DIRECTION.DOWN; ControllerButtonValue = JoystickList.AnalogRy; break; } case ("RightStickLeft"): { NewBind.Type = TYPE.CONTROLLERAXIS; AxisDirection = DIRECTION.LEFT; ControllerButtonValue = JoystickList.AnalogRx; break; } case ("RightStickRight"): { NewBind.Type = TYPE.CONTROLLERAXIS; AxisDirection = DIRECTION.RIGHT; ControllerButtonValue = JoystickList.AnalogRx; break; } case ("XboxA"): { NewBind.Type = TYPE.CONTROLLERBUTTON; ControllerButtonValue = JoystickList.XboxA; break; } case ("XboxB"): { NewBind.Type = TYPE.CONTROLLERBUTTON; ControllerButtonValue = JoystickList.XboxB; break; } case ("XboxX"): { NewBind.Type = TYPE.CONTROLLERBUTTON; ControllerButtonValue = JoystickList.XboxX; break; } case ("XboxY"): { NewBind.Type = TYPE.CONTROLLERBUTTON; ControllerButtonValue = JoystickList.XboxY; break; } case ("XboxLB"): { NewBind.Type = TYPE.CONTROLLERBUTTON; ControllerButtonValue = JoystickList.L; break; } case ("XboxRB"): { NewBind.Type = TYPE.CONTROLLERBUTTON; ControllerButtonValue = JoystickList.R; break; } case ("XboxLT"): { NewBind.Type = TYPE.CONTROLLERBUTTON; ControllerButtonValue = JoystickList.L2; break; } case ("XboxRT"): { NewBind.Type = TYPE.CONTROLLERBUTTON; ControllerButtonValue = JoystickList.R2; break; } case ("RightStickClick"): { NewBind.Type = TYPE.CONTROLLERBUTTON; ControllerButtonValue = JoystickList.R3; break; } case ("LeftStickClick"): { NewBind.Type = TYPE.CONTROLLERBUTTON; ControllerButtonValue = JoystickList.L3; break; } case ("DPadUp"): { NewBind.Type = TYPE.CONTROLLERBUTTON; ControllerButtonValue = JoystickList.DpadUp; break; } case ("DPadDown"): { NewBind.Type = TYPE.CONTROLLERBUTTON; ControllerButtonValue = JoystickList.DpadDown; break; } case ("DPadLeft"): { NewBind.Type = TYPE.CONTROLLERBUTTON; ControllerButtonValue = JoystickList.DpadLeft; break; } case ("DPadRight"): { NewBind.Type = TYPE.CONTROLLERBUTTON; ControllerButtonValue = JoystickList.DpadRight; break; } case ("XboxStart"): { NewBind.Type = TYPE.CONTROLLERBUTTON; ControllerButtonValue = JoystickList.Start; break; } case ("XboxSelect"): { // Or Select. Or Share. Or The big thing in the middle of ps4 remotes. Or -. NewBind.Type = TYPE.CONTROLLERBUTTON; ControllerButtonValue = JoystickList.Select; break; } default: { //Does not match any custom string literal must either be a Scancode or is invalid int LocalScancode = OS.FindScancodeFromString(KeyName); if (LocalScancode != 0) { //Is a valid Scancode NewBind.Type = TYPE.SCANCODE; Scancode = LocalScancode; } else { //If not a valid Scancode then the provided key must not be a valid key Console.ThrowPrint($"The supplied key '{KeyName}' is not a valid key"); return(false); } break; } } //Now we have everything we need to setup the bind with Godot's input system //First clear any bind with the same key UnBind(KeyName); //Then add new bind InputMap.AddAction(KeyName); switch (NewBind.Type) { case (TYPE.SCANCODE): { InputEventKey Event = new InputEventKey(); Event.Scancode = Scancode; InputMap.ActionAddEvent(KeyName, Event); break; } case (TYPE.MOUSEBUTTON): case (TYPE.MOUSEWHEEL): { InputEventMouseButton Event = new InputEventMouseButton(); Event.ButtonIndex = (int)ButtonValue; InputMap.ActionAddEvent(KeyName, Event); break; } case (TYPE.MOUSEAXIS): { InputEventMouseMotion Event = new InputEventMouseMotion(); InputMap.ActionAddEvent(KeyName, Event); NewBind.AxisDirection = (DIRECTION)AxisDirection; //Has to cast as it is Nullable break; } case (TYPE.CONTROLLERAXIS): { InputEventJoypadMotion Event = new InputEventJoypadMotion(); Event.Axis = (int)ControllerButtonValue; // Set which Joystick axis we're using switch (AxisDirection) // Set which direction on the axis we need to trigger the event { case (DIRECTION.UP): { Event.AxisValue = -1; // -1, on the Vertical axis is up break; } case (DIRECTION.LEFT): { Event.AxisValue = -1; // -1, on the Horizontal axis is left break; } case (DIRECTION.DOWN): { Event.AxisValue = 1; // 1, on the Vertical axis is down break; } case (DIRECTION.RIGHT): { Event.AxisValue = 1; // 1, on the Horizontal axis is right break; } } InputMap.ActionAddEvent(KeyName, Event); NewBind.AxisDirection = (DIRECTION)AxisDirection; //Has to cast as it is Nullable break; } case (TYPE.CONTROLLERBUTTON): { InputEventJoypadButton Event = new InputEventJoypadButton(); Event.SetButtonIndex((int)ControllerButtonValue); InputMap.ActionAddEvent(KeyName, Event); break; } } if (NewBind.FuncWithArg != null) { BindingsWithArg.Add(NewBind); } else if (NewBind.FuncWithoutArg != null) { BindingsWithoutArg.Add(NewBind); } return(true); }
/// <summary> /// Continue script execution from the specified state. /// </summary> /// <param name="previousState"> /// Previous state of the script execution. /// </param> /// <param name="cancellationToken">Cancellation token.</param> /// <returns>A <see cref="ScriptState"/> that represents the state after running the script, including all declared variables and return value.</returns> internal Task <ScriptState> ContinueAsync(ScriptState previousState, CancellationToken cancellationToken = default(CancellationToken)) => CommonContinueAsync(previousState, cancellationToken);
internal abstract Task <ScriptState> CommonRunFromAsync(ScriptState previousState, Func <Exception, bool> catchException, CancellationToken cancellationToken);
/// <summary> /// Run the script from the specified state. /// </summary> /// <param name="previousState"> /// Previous state of the script execution. /// </param> /// <param name="catchException"> /// If specified, any exception thrown by the script top-level code is passed to <paramref name="catchException"/>. /// If it returns true the exception is caught and stored on the resulting <see cref="ScriptState"/>, otherwise the exception is propagated to the caller. /// </param> /// <param name="cancellationToken">Cancellation token.</param> /// <returns>A <see cref="ScriptState"/> that represents the state after running the script, including all declared variables and return value.</returns> public Task <ScriptState> RunFromAsync(ScriptState previousState, Func <Exception, bool> catchException = null, CancellationToken cancellationToken = default(CancellationToken)) => CommonRunFromAsync(previousState, catchException, cancellationToken);
/// <summary> /// Run the script from the specified state. /// </summary> /// <param name="previousState"> /// Previous state of the script execution. /// </param> /// <param name="cancellationToken">Cancellation token.</param> /// <returns>A <see cref="ScriptState"/> that represents the state after running the script, including all declared variables and return value.</returns> public Task <ScriptState> RunFromAsync(ScriptState previousState, CancellationToken cancellationToken) => CommonRunFromAsync(previousState, null, cancellationToken);
/// <summary> /// Run the script from the specified state. /// </summary> /// <param name="previousState"> /// Previous state of the script execution. /// </param> /// <param name="cancellationToken">Cancellation token.</param> /// <returns>A <see cref="ScriptState"/> that represents the state after running the script, including all declared variables and return value.</returns> public Task <ScriptState> RunFromAsync(ScriptState previousState, CancellationToken cancellationToken = default(CancellationToken)) => CommonRunFromAsync(previousState, cancellationToken);