Browse Source

Fix standard lib pathes

tags/v0.0.1.0
NGnius (Graham) 5 years ago
parent
commit
b75f383df1
3 changed files with 159 additions and 8 deletions
  1. +4
    -4
      GamecraftScripting/Commands/DebugCommandEngine.cs
  2. +68
    -4
      GamecraftScripting/Commands/PythonRunnerCommandEngine.cs
  3. +87
    -0
      GamecraftScripting/Environment/LogStream.cs

+ 4
- 4
GamecraftScripting/Commands/DebugCommandEngine.cs View File

@@ -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()}");
}
}
}

+ 68
- 4
GamecraftScripting/Commands/PythonRunnerCommandEngine.cs View File

@@ -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
- 0
GamecraftScripting/Environment/LogStream.cs View 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);
}
}
}
}