@@ -450,3 +450,5 @@ dmypy.json | |||
# Pyre type checker | |||
.pyre/ | |||
# Gamecraft install folder | |||
ref |
@@ -7,6 +7,7 @@ using System.Threading.Tasks; | |||
using GamecraftModdingAPI.Commands; | |||
using GamecraftModdingAPI.Utility; | |||
using Svelto.ECS; | |||
using uREPL; | |||
using IronPython; | |||
@@ -20,19 +21,54 @@ namespace GamecraftScripting.Commands | |||
public IEntitiesDB entitiesDB { set; private get; } | |||
private bool isEnabledIDE = false; | |||
public void Dispose() | |||
{ | |||
CommandRegistrationHelper.Unregister("PythonInfo"); | |||
CommandRegistrationHelper.Unregister("PythonVersion"); | |||
CommandRegistrationHelper.Unregister("PythonSearchPathes"); | |||
CommandRegistrationHelper.Unregister("ToggleIDE"); | |||
if (isEnabledIDE) | |||
{ | |||
toggleIDE(); | |||
} | |||
} | |||
public void Ready() | |||
{ | |||
CommandRegistrationHelper.Register("PythonInfo", ironPythonInfo, "Display Python debug info"); | |||
CommandRegistrationHelper.Register("PythonVersion", ironPythonVersion, "Display Python info"); | |||
CommandRegistrationHelper.Register("PythonSearchPathes", ironPythonPathes, "Display Python import search pathes"); | |||
CommandRegistrationHelper.Register("ToggleIDE", toggleIDE, "Toggle command line IDE tools"); | |||
} | |||
private void ironPythonInfo() | |||
private void ironPythonVersion() | |||
{ | |||
Logging.CommandLog($"Assembly {typeof(PythonOptions).Assembly.GetName().ToString()}"); | |||
} | |||
private void ironPythonPathes() | |||
{ | |||
Logging.CommandLog("'"+string.Join("', '", Environment.PythonEnvironment.CurrentEngine.GetSearchPaths().ToArray())+"'"); | |||
} | |||
private void toggleIDE() | |||
{ | |||
uREPL.Parameters cliConfig = uREPL.Window.selected.parameters; | |||
if (isEnabledIDE) | |||
{ | |||
// disable | |||
} | |||
else | |||
{ | |||
// enable | |||
} | |||
isEnabledIDE = !isEnabledIDE; | |||
cliConfig.useMonoCompletion = isEnabledIDE; | |||
cliConfig.useGameObjectNameCompletion = isEnabledIDE; | |||
cliConfig.useGameObjectPathCompletion = isEnabledIDE; | |||
cliConfig.useGlobalClassCompletion = isEnabledIDE; | |||
string word = isEnabledIDE ? "On" : "Off"; | |||
Logging.CommandLog($"IDE {word}"); | |||
} | |||
} | |||
} |
@@ -1,18 +1,11 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.IO; | |||
using System.Numerics; | |||
using System.Linq; | |||
using System.Text; | |||
using System.Threading.Tasks; | |||
using System.Security.Policy; | |||
using GamecraftModdingAPI.Commands; | |||
using GamecraftModdingAPI.Utility; | |||
using Svelto.ECS; | |||
using RobocraftX.Common; | |||
using IronPython.Hosting; | |||
using Microsoft.Scripting.Hosting; | |||
using GamecraftScripting.Environment; | |||
@@ -27,10 +20,6 @@ namespace GamecraftScripting.Commands | |||
public IEntitiesDB entitiesDB { set; private get; } | |||
private ScriptEngine pyEngine; | |||
private ScriptScope gameScope; | |||
public void Dispose() | |||
{ | |||
CommandRegistrationHelper.Unregister("RunPythonScript"); | |||
@@ -42,14 +31,11 @@ namespace GamecraftScripting.Commands | |||
CommandRegistrationHelper.Register<string>("RunPythonScript", RunPythonScript, "Run a python script stored on your computer"); | |||
CommandRegistrationHelper.Register<string>("RunPython", RunPythonString, "Run a python argument"); | |||
// create insecure Python namespace | |||
CreateFreeInstance(); | |||
// make "import GamecraftModdingAPI" work without the clr boilerplate | |||
pyEngine.Execute("import clr\nclr.AddReference(\"GamecraftModdingAPI\")", gameScope); | |||
ICollection<string> searchPaths = pyEngine.GetSearchPaths(); | |||
searchPaths.Add(@".\Lib\"); | |||
searchPaths.Add(@".\Gamecraft_Data\Managed\Lib\"); | |||
pyEngine.SetSearchPaths(searchPaths); | |||
Logging.MetaLog(string.Join(", ", pyEngine.GetSearchPaths().ToArray())); | |||
ScriptEngine pyEngine = PythonEnvironment.CreateEngine(); | |||
ScriptScope pyScope = PythonEnvironment.CreateScope(pyEngine); | |||
PythonEnvironment.CurrentEngine = pyEngine; | |||
PythonEnvironment.CurrentScope = pyScope; | |||
//Logging.MetaLog(string.Join(", ", pyEngine.GetSearchPaths().ToArray())); | |||
} | |||
private void RunPythonScript(string scriptPath) | |||
@@ -65,10 +51,10 @@ namespace GamecraftScripting.Commands | |||
private void ExecuteScript(string script, bool logError=true) | |||
{ | |||
ScriptSource src = pyEngine.CreateScriptSourceFromString(script); | |||
ScriptSource src = PythonEnvironment.CurrentEngine.CreateScriptSourceFromString(script); | |||
try | |||
{ | |||
src.Execute(gameScope); | |||
src.Execute(PythonEnvironment.CurrentScope); | |||
} | |||
catch (Exception e) | |||
{ | |||
@@ -84,33 +70,9 @@ namespace GamecraftScripting.Commands | |||
} | |||
} | |||
/// <summary> | |||
/// [Experimental] Create a Python instance without access to any(?) assemblies | |||
/// </summary> | |||
private void CreateSandboxedInstance() | |||
{ | |||
Evidence evidence = new Evidence(); // an uninformative class name to limit accessible Assemblies | |||
AppDomain domain = AppDomain.CreateDomain(GameMode.SaveGameDetails.Name, evidence); | |||
this.pyEngine = Python.CreateEngine(domain); | |||
PythonLogStream pyLog = new PythonLogStream(); | |||
pyEngine.Runtime.IO.SetOutput(pyLog, pyLog.Encoding); | |||
this.gameScope = pyEngine.CreateScope(); | |||
} | |||
/// <summary> | |||
/// Create an unsecured Python instance | |||
/// </summary> | |||
private void CreateFreeInstance() | |||
{ | |||
this.pyEngine = Python.CreateEngine(); | |||
PythonLogStream pyLog = new PythonLogStream(); | |||
pyEngine.Runtime.IO.SetOutput(pyLog, pyLog.Encoding); | |||
this.gameScope = pyEngine.CreateScope(); | |||
} | |||
public PythonRunnerCommandEngine() | |||
{ | |||
Logging.CommandLog($"cwd: {Directory.GetCurrentDirectory()}"); | |||
//Logging.CommandLog($"cwd: {Directory.GetCurrentDirectory()}"); | |||
} | |||
} | |||
} |
@@ -0,0 +1,73 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Security.Policy; | |||
using RobocraftX.Common; | |||
using IronPython.Hosting; | |||
using Microsoft.Scripting.Hosting; | |||
namespace GamecraftScripting.Environment | |||
{ | |||
/// <summary> | |||
/// Python environment factories and utilities | |||
/// </summary> | |||
public static class PythonEnvironment | |||
{ | |||
public static ScriptEngine CurrentEngine { get; set; } | |||
public static ScriptScope CurrentScope { get; set; } | |||
/// <summary> | |||
/// Creates and configure the Python execution engine | |||
/// </summary> | |||
/// <returns>The Python engine</returns> | |||
public static ScriptEngine CreateEngine() | |||
{ | |||
ScriptEngine pyEngine = Python.CreateEngine(); | |||
PythonLogStream pyLog = new PythonLogStream(); | |||
pyEngine.Runtime.IO.SetOutput(pyLog, pyLog.Encoding); | |||
ICollection<string> searchPaths = pyEngine.GetSearchPaths(); | |||
// Add Python standard lib to import search pathes | |||
searchPaths.Add(@".\Lib\"); // try not to use this location | |||
searchPaths.Add(@".\Gamecraft_Data\Managed\Lib\"); | |||
pyEngine.SetSearchPaths(searchPaths); | |||
return pyEngine; | |||
} | |||
/// <summary> | |||
/// Creates a restricted Python execution engine | |||
/// </summary> | |||
/// <returns>The Python engine</returns> | |||
public static ScriptEngine CreateRestrictedEngine() | |||
{ | |||
Evidence evidence = new Evidence(); // an uninformative class name to limit accessible Assemblies | |||
AppDomain domain = AppDomain.CreateDomain(GameMode.SaveGameDetails.Name, evidence); | |||
ScriptEngine pyEngine = Python.CreateEngine(domain); | |||
// Add Python standard lib to import search pathes | |||
ICollection<string> searchPaths = pyEngine.GetSearchPaths(); | |||
searchPaths.Add(@".\Lib\"); // try not to use this location | |||
searchPaths.Add(@".\Gamecraft_Data\Managed\Lib\"); | |||
if (!string.IsNullOrWhiteSpace(GameMode.SaveGameDetails.Folder)) | |||
{ | |||
// Add game's working directory, in case multiple files are used | |||
searchPaths.Add(GameMode.SaveGameDetails.Folder); | |||
} | |||
pyEngine.SetSearchPaths(searchPaths); | |||
return pyEngine; | |||
} | |||
/// <summary> | |||
/// Creates the Python execution scope | |||
/// </summary> | |||
/// <returns>The Python scope</returns> | |||
/// <param name="pyEngine">The Python engine</param> | |||
public static ScriptScope CreateScope(ScriptEngine pyEngine) | |||
{ | |||
ScriptScope pyScope = pyEngine.CreateScope(); | |||
// make "import GamecraftModdingAPI" work without the clr boilerplate | |||
pyEngine.Execute("import clr\nclr.AddReference(\"GamecraftModdingAPI\")", pyScope); | |||
return pyScope; | |||
} | |||
} | |||
} |
@@ -2,6 +2,7 @@ | |||
<PropertyGroup> | |||
<TargetFramework>net48</TargetFramework> | |||
<TargetFramework>net472</TargetFramework> | |||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects> | |||
<Version>0.0.1.0</Version> | |||
<Authors>Exmods</Authors> | |||