Fix standard lib pathes
This commit is contained in:
parent
baa26769b7
commit
b75f383df1
3 changed files with 159 additions and 8 deletions
|
@ -14,15 +14,15 @@ namespace GamecraftScripting.Commands
|
|||
{
|
||||
class DebugCommandEngine : ICustomCommandEngine
|
||||
{
|
||||
public string Description { get; } = "";
|
||||
public string Description { get; } = "Display Python debug info";
|
||||
|
||||
public string Name { get; } = "";
|
||||
public string Name { get; } = "PythonInfo";
|
||||
|
||||
public IEntitiesDB entitiesDB { set; private get; }
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
CommandRegistrationHelper.Unregister("IronPythonInfo");
|
||||
CommandRegistrationHelper.Unregister("PythonInfo");
|
||||
}
|
||||
|
||||
public void Ready()
|
||||
|
@ -32,7 +32,7 @@ namespace GamecraftScripting.Commands
|
|||
|
||||
private void ironPythonInfo()
|
||||
{
|
||||
Logging.CommandLog(typeof(PythonOptions).Assembly.GetName().ToString());
|
||||
Logging.CommandLog($"Assembly {typeof(PythonOptions).Assembly.GetName().ToString()}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,14 +5,18 @@ 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;
|
||||
|
||||
namespace GamecraftScripting.Commands
|
||||
{
|
||||
class PythonRunnerCommandEngine : ICustomCommandEngine
|
||||
|
@ -23,25 +27,85 @@ namespace GamecraftScripting.Commands
|
|||
|
||||
public IEntitiesDB entitiesDB { set; private get; }
|
||||
|
||||
private ScriptEngine pythonEngine;
|
||||
private ScriptEngine pyEngine;
|
||||
|
||||
private ScriptScope gameScope;
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
CommandRegistrationHelper.Unregister("RunPythonScript");
|
||||
CommandRegistrationHelper.Unregister("RunPython");
|
||||
}
|
||||
|
||||
public void Ready()
|
||||
{
|
||||
CommandRegistrationHelper.Register<string>("RunPythonScript", RunPythonScript, "Run a python script stored on your computer");
|
||||
this.pythonEngine = Python.CreateEngine();
|
||||
this.gameScope = pythonEngine.CreateScope();
|
||||
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()));
|
||||
}
|
||||
|
||||
private void RunPythonScript(string scriptPath)
|
||||
{
|
||||
pythonEngine.ExecuteFile(scriptPath, gameScope);
|
||||
string script = File.ReadAllText(scriptPath);
|
||||
ExecuteScript(script);
|
||||
}
|
||||
|
||||
private void RunPythonString(string expression)
|
||||
{
|
||||
ExecuteScript(expression);
|
||||
}
|
||||
|
||||
private void ExecuteScript(string script, bool logError=true)
|
||||
{
|
||||
ScriptSource src = pyEngine.CreateScriptSourceFromString(script);
|
||||
try
|
||||
{
|
||||
src.Execute(gameScope);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (logError)
|
||||
{
|
||||
Logging.CommandLogError($"Python error: {e.Message}");
|
||||
}
|
||||
else
|
||||
{
|
||||
throw e;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/// <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()
|
||||
|
|
87
GamecraftScripting/Environment/LogStream.cs
Normal file
87
GamecraftScripting/Environment/LogStream.cs
Normal file
|
@ -0,0 +1,87 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using GamecraftModdingAPI.Utility;
|
||||
|
||||
namespace GamecraftScripting.Environment
|
||||
{
|
||||
/// <summary>
|
||||
/// Writeable Stream for Python's print function
|
||||
/// </summary>
|
||||
class PythonLogStream : Stream
|
||||
{
|
||||
public Encoding Encoding { get; set; } = Encoding.Default;
|
||||
|
||||
public override bool CanRead => false;
|
||||
|
||||
public override bool CanSeek => false;
|
||||
|
||||
public override bool CanWrite => true;
|
||||
|
||||
public override long Length => _length;
|
||||
|
||||
private long _length = 0L;
|
||||
|
||||
private StringBuilder strBuffer = new StringBuilder();
|
||||
|
||||
public override long Position { get => _length-1; set => throw new NotImplementedException(); }
|
||||
|
||||
public override void Flush()
|
||||
{
|
||||
if (strBuffer.Length > 0)
|
||||
{
|
||||
Logging.CommandLog(strBuffer.ToString().Trim());
|
||||
strBuffer.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override long Seek(long offset, SeekOrigin origin)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override void SetLength(long value)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
byte[] realBuffer = new byte[count + offset];
|
||||
for (int i = 0; i < realBuffer.Length-offset; i++)
|
||||
{
|
||||
realBuffer[i + offset] = buffer[i];
|
||||
}
|
||||
string toWrite = this.Encoding.GetString(realBuffer);
|
||||
for (int i = 0; i < toWrite.Length; i++)
|
||||
{
|
||||
WriteChar(toWrite[i]);
|
||||
}
|
||||
}
|
||||
|
||||
public void WriteChar(char c)
|
||||
{
|
||||
if (c == '\n')
|
||||
{
|
||||
Flush();
|
||||
}
|
||||
else if (c == '\r')
|
||||
{
|
||||
// Microsoft motto: Why use 1 when 2 will clearly be more bloated!
|
||||
}
|
||||
else
|
||||
{
|
||||
strBuffer.Append(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue