Add initial Python IDE behaviour
This commit is contained in:
parent
3b7753e530
commit
851483e310
5 changed files with 123 additions and 49 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -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()}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
73
GamecraftScripting/Environment/PythonEnvironment.cs
Normal file
73
GamecraftScripting/Environment/PythonEnvironment.cs
Normal file
|
@ -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>
|
||||
|
|
Loading…
Add table
Reference in a new issue