Compare commits

...

6 commits

15 changed files with 1212 additions and 271 deletions

View file

@ -21,17 +21,16 @@ namespace GamecraftScripting.Commands
public EntitiesDB entitiesDB { set; private get; }
private bool isEnabledIDE = false;
public bool isRemovable => false;
private bool isEnabledIDE = false;
public void Dispose()
{
CommandRegistrationHelper.Unregister("PythonVersion");
CommandRegistrationHelper.Unregister("PythonSearchPathes");
CommandRegistrationHelper.Unregister("ToggleIDE");
if (isEnabledIDE)
{
toggleIDE();
}
isEnabledIDE = false;
}
public void Ready()

View file

@ -0,0 +1,206 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Text;
using GamecraftModdingAPI.Commands;
using GamecraftModdingAPI.Utility;
using Svelto.ECS;
using Microsoft.Scripting.Hosting;
using GamecraftScripting.Environment;
using GamecraftScripting.Serialization;
namespace GamecraftScripting.Commands
{
public class ExecuteCommandEngine : ICustomCommandEngine
{
public const string URI_IMMEDIATE = "immediate://";
public const string URI_HTTP = "http://";
public const string URI_HTTPS = "https://";
public const string URI_INTERNAL = "internal://";
public const string URI_BUILTIN = "exmods://";
public const string URI_FILE = "file://";
public const string URI_ANSWER = "42://";
public string Description { get; } = "Execute some Python, intelligently guessing how to execute it";
public string Name { get; } = "ExecutePython";
public EntitiesDB entitiesDB { set; private get; }
public bool isRemovable => false;
public void Dispose()
{
CommandRegistrationHelper.Unregister(Name);
}
public void Ready()
{
// TODO command registration
CommandRegistrationHelper.Register<string>(Name, ExecutePythonCommand, Description);
// create insecure Python namespace
ScriptEngine pyEngine = PythonEnvironment.CreateEngine();
ScriptScope pyScope = PythonEnvironment.CreateScope(pyEngine);
PythonEnvironment.CurrentEngine = pyEngine;
PythonEnvironment.CurrentScope = pyScope;
}
private void ExecutePythonCommand(string name)
{
string uriName = urifyName(name.Trim());
if (uriName == null)
{
Logging.CommandLogError("Unable to guess script type. Please add a scheme to the start of the command argument to avoid this. \nValid schemes include: \n" + URI_IMMEDIATE.Replace('/', '\\') + " (for Python code) \n" + URI_FILE.Replace('/', '\\') + " (for Python file) ");
return;
}
string scriptContents = getScript(uriName);
if (scriptContents == null)
{
Logging.CommandLogError("Invalid script or URI scheme. Please replace the scheme at the start of the command argument. Valid schemes include: \n" + URI_IMMEDIATE.Replace('/', '\\') + "\\\\ (for Python code) \n" + URI_FILE.Replace('/', '\\') + "\\\\ (for Python file) ");
return;
}
Execute(uriName, scriptContents);
}
private string urifyName(string name)
{
if (name.Contains("://")) return name; // already is a uri, hopefully a valid uri
if (name.Contains(":\\\\")) return name.Replace(":\\\\", "://"); // :\\ is easier to input in CLI
if (!name.EndsWith(".py", StringComparison.InvariantCultureIgnoreCase))
return URI_IMMEDIATE + name; // probably not a script file, hopefully it's some code
name = name.TrimEnd('\\', '/'); // I still hate that Windows filenames use the escape character as a separator
// search scripts included in game save
EntityCollection<ScriptStruct> integratedScripts = entitiesDB.QueryEntities<ScriptStruct>(ScriptBuilder.ScriptGroup);
for (int i = 0; i < integratedScripts.count; i++)
{
if (integratedScripts[i].name == name)
{
// matching script found in game save
return URI_INTERNAL + name;
}
}
// search scripts on disk
try
{
FileInfo file = new FileInfo(name);
if (file.Exists)
{
return URI_FILE + name;
}
}
catch (Exception e) when (
e is System.Security.SecurityException
|| e is ArgumentException
|| e is UnauthorizedAccessException
|| e is PathTooLongException
|| e is NotSupportedException)
{ }
return null;
}
private string getScheme(string uriName)
{
string[] splitName = uriName.Split(new string[] { @"://" }, StringSplitOptions.None);
if (splitName.Length == 2)
{
return splitName[0] + "://";
}
return null;
}
private string getPath(string uriName)
{
string[] splitName = uriName.Split(new string[] { @"://" }, StringSplitOptions.None);
if (splitName.Length == 2)
{
return splitName[1];
}
return null;
}
private string getScript(string uriName)
{
string uri_scheme = getScheme(uriName);
if (uri_scheme == null) return null;
string uri_path = getPath(uriName);
if (uri_path == null) return null;
switch (uri_scheme)
{
case URI_IMMEDIATE:
return uri_path;
case URI_HTTP: // download from web
case URI_HTTPS:
#if DEBUG
Logging.CommandLogWarning("Executing code from the Internet is dangerous! \nWeb scripts are only available in DEVELOPMENT versions of GamecraftScripting.");
try
{
WebRequest req = WebRequest.Create(uriName);
req.Method = "GET";
HttpWebResponse resp = (HttpWebResponse)req.GetResponse();
byte[] body = new byte[int.Parse(resp.GetResponseHeader("Content-Length"))];
resp.GetResponseStream().Read(body, 0, body.Length);
return Encoding.ASCII.GetString(body);
}
catch (Exception)
{
return null;
}
#else
Logging.CommandLogError("Executing code from the Internet is dangerous! \nWeb scripts are only available in DEVELOPMENT versions of GamecraftScripting.");
return null;
#endif
case URI_INTERNAL: // found in game file (already deserialized to memory)
EntityCollection<ScriptStruct> internalScripts = entitiesDB.QueryEntities<ScriptStruct>(ScriptBuilder.ScriptGroup);
for (int i = 0; i < internalScripts.count; i++)
{
if (internalScripts[i].name == uri_path)
{
return internalScripts[i].script;
}
}
return null;
case URI_BUILTIN:
// TODO: for future implementation
return null;
case URI_FILE:
try
{
return File.ReadAllText(uri_path);
}
catch (Exception)
{
return null;
}
case URI_ANSWER:
return "print 42";
default:
return null;
}
}
private void Execute(string uriName, string script, bool logError = true)
{
ScriptSource src = PythonEnvironment.CurrentEngine.CreateScriptSourceFromString(script);
try
{
src.Execute(PythonEnvironment.CurrentScope);
}
catch (Exception e)
{
if (logError)
{
Logging.CommandLogError($"Python error in '{uriName}': \n{e.Message}");
}
else
{
throw e;
}
}
}
}
}

View file

@ -9,6 +9,7 @@ using Svelto.ECS;
using Microsoft.Scripting.Hosting;
using GamecraftScripting.Environment;
using GamecraftScripting.Serialization;
namespace GamecraftScripting.Commands
{
@ -19,17 +20,23 @@ namespace GamecraftScripting.Commands
public string Name { get; } = "PythonRunner";
public EntitiesDB entitiesDB { set; private get; }
public bool isRemovable => false;
public void Dispose()
public void Dispose()
{
CommandRegistrationHelper.Unregister("RunPythonScript");
CommandRegistrationHelper.Unregister("RunPython");
CommandRegistrationHelper.Unregister("RunGamePython");
CommandRegistrationHelper.Unregister("ListGameScripts");
}
public void Ready()
{
CommandRegistrationHelper.Register<string>("RunPythonScript", RunPythonScript, "Run a python script stored on your computer");
CommandRegistrationHelper.Register<string>("RunPython", RunPythonString, "Run a python argument");
CommandRegistrationHelper.Register<string>("RunGamePython", RunIntegratedScript, "Run a python script stored in the game file");
CommandRegistrationHelper.Register("ListGameScripts", ListIntegratedScripts, "List python scripts stored in the game file");
// create insecure Python namespace
ScriptEngine pyEngine = PythonEnvironment.CreateEngine();
ScriptScope pyScope = PythonEnvironment.CreateScope(pyEngine);
@ -38,6 +45,37 @@ namespace GamecraftScripting.Commands
//Logging.MetaLog(string.Join(", ", pyEngine.GetSearchPaths().ToArray()));
}
private void ListIntegratedScripts()
{
string result = "";
EntityCollection<ScriptStruct> scripts = entitiesDB.QueryEntities<ScriptStruct>(ScriptBuilder.ScriptGroup);
for (uint i = 0u; i < scripts.count; i++)
{
result += scripts[i].name + " \n";
}
Logging.CommandLog($"Found {scripts.count} integrated script(s) \n{result}");
}
private void RunIntegratedScript(string scriptName)
{
if (scriptName == null) return;
if (scriptName.StartsWith("exmods://", StringComparison.InvariantCultureIgnoreCase))
{
// TODO: Lookup for built-in scripts
return;
}
EntityCollection<ScriptStruct> scripts = entitiesDB.QueryEntities<ScriptStruct>(ScriptBuilder.ScriptGroup);
for (uint i = 0u; i < scripts.count; i++)
{
if (scripts[i].name == scriptName)
{
ExecuteScript(scripts[i].script);
return;
}
}
Logging.CommandLogError("Script not found");
}
private void RunPythonScript(string scriptPath)
{
string script = File.ReadAllText(scriptPath);

View file

@ -0,0 +1,38 @@
using System;
using System.IO;
using Svelto.ECS;
using GamecraftModdingAPI.Commands;
using GamecraftModdingAPI.Utility;
namespace GamecraftScripting.Commands
{
public class SerializationCommandEngine : ICustomCommandEngine
{
public string Description => "Save a script into a Gamecraft game file";
public string Name => "IntegrateScript";
public EntitiesDB entitiesDB { set; private get; }
public bool isRemovable => false;
internal static IEntityFactory entityFactory = null;
public void Dispose()
{
CommandRegistrationHelper.Unregister(Name);
}
public void Ready()
{
CommandRegistrationHelper.Register<string>(Name, persistScript, Description);
}
private void persistScript(string filepath)
{
if (entityFactory == null) return;
EGID scriptId = Serialization.ScriptBuilder.BuildScriptEntity(filepath, File.ReadAllText(filepath), entityFactory);
Logging.MetaLog($"Created persistent script with id {scriptId.entityID}");
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -9,6 +9,7 @@ using IllusionPlugin;
using UnityEngine;
using GamecraftModdingAPI;
using GamecraftModdingAPI.Commands;
using HarmonyLib;
namespace GamecraftScripting
{
@ -17,26 +18,35 @@ namespace GamecraftScripting
public string[] Filter { get; } = new string[] { "Gamecraft" };
public string Name { get; } = Assembly.GetExecutingAssembly().GetName().Name;
public string Version { get; } = Assembly.GetExecutingAssembly().GetName().Version.ToString();
private Harmony harmony = null;
public void OnApplicationQuit()
{
var currentAssembly = Assembly.GetExecutingAssembly();
harmony.UnpatchAll(currentAssembly.GetName().Name);
harmony = null;
Main.Shutdown();
}
public void OnApplicationStart()
{
Main.Init();
var currentAssembly = Assembly.GetExecutingAssembly();
harmony = new Harmony(currentAssembly.GetName().Name);
harmony.PatchAll(currentAssembly);
// register development commands
#if DEBUG
//CommandManager.AddCommand(new SimpleCustomCommandEngine(() => { Application.Quit(); }, "Exit", "Exit the game immediately"));
#endif
// debugging commands
CommandManager.AddCommand(new Commands.DebugCommandEngine());
// functional commands
CommandManager.AddCommand(new Commands.PythonRunnerCommandEngine());
CommandManager.AddCommand(new Commands.ExecuteCommandEngine());
CommandManager.AddCommand(new Commands.SerializationCommandEngine());
}
public void OnFixedUpdate() { }

View file

@ -0,0 +1,74 @@
using System;
using System.Text;
using System.Reflection;
using HarmonyLib;
using RobocraftX.Common;
using Svelto.DataStructures;
using Svelto.ECS;
using Svelto.ECS.Serialization;
namespace GamecraftScripting.Serialization
{
[HarmonyPatch]
class DeserializeFromDiskEntitiesEnginePatch
{
internal static IEntityFactory entityFactory = null;
private static readonly byte[] frameStart = (new UTF8Encoding()).GetBytes("GamecraftScripting");
public static void Prefix(ref ISerializationData ____serializationData, ref FasterList<byte> ____bytesStream, ref IEntitySerialization ____entitySerializer)
{
____entitySerializer.RegisterSerializationFactory<ScriptEntityDescriptor>(new ScriptDeserializationFactory(entityFactory));
uint scriptDataStart = ____serializationData.dataPos;
GamecraftModdingAPI.Utility.Logging.MetaLog($"dataPos: {scriptDataStart}");
BinaryBufferReader bbr = new BinaryBufferReader(____bytesStream.ToArrayFast(out uint count), ____serializationData.dataPos);
byte[] frameBuffer = new byte[frameStart.Length];
GamecraftModdingAPI.Utility.Logging.MetaLog($"serial data count: {____serializationData.data.count} capacity: {____serializationData.data.capacity}");
int i = 0;
// match frame start
while (frameBuffer != frameStart && bbr.Position < count-frameStart.Length)
{
i = 0;
frameBuffer[0] = bbr.ReadByte();
GamecraftModdingAPI.Utility.Logging.MetaLog($"Buffer byte 0: {(new UTF8Encoding()).GetString(new byte[]{frameBuffer[0]})}");
while (frameBuffer[i] == frameStart[i])
{
i++;
if (i == frameStart.Length) break;
frameBuffer[i] = bbr.ReadByte();
GamecraftModdingAPI.Utility.Logging.MetaLog($"Buffer byte {i}: {(new UTF8Encoding()).GetString(new byte[] { frameBuffer[i] })}");
}
if (i == frameStart.Length) break;
}
// abort if at end of file
if (bbr.Position >= count - frameStart.Length)
{
GamecraftModdingAPI.Utility.Logging.MetaLog("Skipping script deserialization (no frame found)");
return;
}
____serializationData.dataPos = bbr.Position;
GamecraftModdingAPI.Utility.Logging.MetaLog($"dataPos (after frame): {____serializationData.dataPos}");
uint scriptCount = bbr.ReadUint();
GamecraftModdingAPI.Utility.Logging.MetaLog($"scriptCount: {scriptCount}");
uint potentialStart = bbr.ReadUint();
if (potentialStart == ____serializationData.dataPos - frameStart.Length) return;
____serializationData.dataPos += 4u;
for (uint j = 0; j < scriptCount; j++)
{
EGID newScriptId = new EGID(j, ScriptBuilder.ScriptGroup);
// why doesn't \/this\/ do anything?
____entitySerializer.DeserializeNewEntity(newScriptId, ____serializationData, (int)SerializationType.Storage);
}
bbr = new BinaryBufferReader(____bytesStream.ToArrayFast(out count), ____serializationData.dataPos);
uint actualStart = bbr.ReadUint();
GamecraftModdingAPI.Utility.Logging.MetaLog($"actualStart: {actualStart}");
GamecraftModdingAPI.Utility.Logging.MetaLog($"Deserialized {scriptCount} scripts starting at {scriptDataStart} ({actualStart})");
____serializationData.dataPos = scriptDataStart; // change back to original end point (just in case)
}
public static MethodBase TargetMethod()
{
return AccessTools.Method("RobocraftX.SaveAndLoad.DeserializeFromDiskEntitiesEngine:LoadingFinished");//AccessTools.TypeByName("RobocraftX.SaveAndLoad.DeserializeFromDiskEntities")
}
}
}

View file

@ -0,0 +1,17 @@
using System;
using HarmonyLib;
using RobocraftX.SaveAndLoad;
using Svelto.ECS;
namespace GamecraftScripting.Serialization
{
[HarmonyPatch(typeof(SaveAndLoadCompositionRoot), "Compose")]
class SaveAndLoadCompositionRootPatch
{
public static void Prefix(EnginesRoot enginesRoot)
{
IEntityFactory factory = enginesRoot.GenerateEntityFactory();
DeserializeFromDiskEntitiesEnginePatch.entityFactory = factory;
Commands.SerializationCommandEngine.entityFactory = factory;
}
}
}

View file

@ -0,0 +1,57 @@
using System;
using System.Text;
using System.Reflection;
using HarmonyLib;
using RobocraftX.Common;
using RobocraftX.SaveAndLoad;
using Svelto.DataStructures;
using Svelto.ECS;
using Svelto.ECS.Serialization;
using GamecraftModdingAPI.Utility;
namespace GamecraftScripting.Serialization
{
[HarmonyPatch]
class SaveGameEnginePatch
{
private static readonly byte[] frameStart = (new UTF8Encoding()).GetBytes("GamecraftScripting");
public static void Postfix(ref ISerializationData serializationData, EntitiesDB entitiesDB, IEntitySerialization entitySerializer)
{
Logging.MetaLog("Running Postfix on game save serializer");
serializationData.data.ExpandBy((uint)frameStart.Length);
BinaryBufferWriter bbw = new BinaryBufferWriter(serializationData.data.ToArrayFast(out uint buffLen), serializationData.dataPos);
EntityCollection<ScriptStruct> scripts = entitiesDB.QueryEntities<ScriptStruct>(ScriptBuilder.ScriptGroup);
uint scriptDataStart = serializationData.dataPos;
GamecraftModdingAPI.Utility.Logging.MetaLog($"dataPos: {scriptDataStart}");
for (int i = 0; i < frameStart.Length; i++)
{
bbw.Write(frameStart[i]);
}
serializationData.dataPos += (uint)frameStart.Length;
GamecraftModdingAPI.Utility.Logging.MetaLog($"dataPos (after frame start): {serializationData.dataPos}");
serializationData.data.ExpandBy(4u);
Logging.MetaLog($"scriptCount: {scripts.count}");
bbw.Write(scripts.count);
serializationData.dataPos += 4u;
//foreach (byte b in BitConverter.GetBytes(count)) serializationData.data.Add(b);
for (uint i = 0; i < scripts.count; i++)
{
EGID scriptId = new EGID(i, ScriptBuilder.ScriptGroup);
entitySerializer.SerializeEntity(scriptId, serializationData, (int)SerializationType.Storage);
}
bbw = new BinaryBufferWriter(serializationData.data.ToArrayFast(out buffLen), serializationData.dataPos);
serializationData.data.ExpandBy(4u);
bbw.Write(scriptDataStart);
serializationData.dataPos += 4u;
//foreach (byte b in BitConverter.GetBytes(scriptDataStart)) serializationData.data.Add(b);
serializationData.data.Trim();
}
public static MethodBase TargetMethod()
{
return typeof(SaveGameEngine).GetMethod("SerializeGameToBuffer");
}
}
}

View file

@ -0,0 +1,24 @@
using System;
using Svelto.ECS;
using Svelto.ECS.Experimental;
namespace GamecraftScripting.Serialization
{
public static class ScriptBuilder
{
public static readonly ExclusiveGroup ScriptGroup = new ExclusiveGroup("SCRIPT_GROUP");
private static uint nextScriptId = 0u;
public static EGID BuildScriptEntity(string name, string script, IEntityFactory entityFactory)
{
EGID scriptId = new EGID(nextScriptId++, ScriptGroup);
EntityComponentInitializer builder = entityFactory.BuildEntity<ScriptEntityDescriptor>(scriptId);
builder.Init(new ScriptStruct {
name = new ECSString(name),
script = new ECSString(script),
});
return scriptId;
}
}
}

View file

@ -0,0 +1,25 @@
using System;
using Svelto.ECS;
using Svelto.ECS.Serialization;
using GamecraftModdingAPI.Utility;
namespace GamecraftScripting.Serialization
{
public class ScriptDeserializationFactory : IDeserializationFactory
{
private IEntityFactory entityFactory;
public ScriptDeserializationFactory(IEntityFactory entityFactory)
{
this.entityFactory = entityFactory;
}
public EntityComponentInitializer BuildDeserializedEntity(EGID egid, ISerializationData serializationData, ISerializableEntityDescriptor entityDescriptor, int serializationType, IEntitySerialization entitySerialization)
{
Logging.MetaLog(entityFactory == null);
EntityComponentInitializer esi = entityFactory.BuildEntity<ScriptEntityDescriptor>(egid);
entitySerialization.DeserializeEntityComponents(serializationData, entityDescriptor, ref esi, serializationType);
Logging.MetaLog($"Deserialized script named {esi.Get<ScriptStruct>().name.ToString()}");
return esi;
}
}
}

View file

@ -0,0 +1,29 @@
using System;
using RobocraftX.Common;
using Svelto.ECS;
using Svelto.ECS.Serialization;
namespace GamecraftScripting.Serialization
{
public class ScriptEntityDescriptor : SerializableEntityDescriptor<ScriptEntityDescriptor._ScriptEntityDescriptor>
{
[HashName("GamecraftScriptingScriptEntityDescriptorV0")]
public class _ScriptEntityDescriptor : IEntityDescriptor
{
public IComponentBuilder[] componentsToBuild => _entityBuilders;
private static readonly IComponentBuilder[] _entityBuilders = new IComponentBuilder[1]
{
new SerializableComponentBuilder<SerializationType, ScriptStruct>(((int)SerializationType.Network, new ScriptSerializer()),
((int)SerializationType.Storage, new ScriptSerializer()))
};
}
public ScriptEntityDescriptor() : base()
{
GamecraftModdingAPI.Utility.Logging.MetaLog("ScriptEntityDescriptor Initialized");
GamecraftModdingAPI.Utility.Logging.MetaLog($"Entities to serialize: {entitiesToSerialize.Length}");
GamecraftModdingAPI.Utility.Logging.MetaLog($"Entities to serialize: {componentsToBuild.Length}");
}
}
}

View file

@ -0,0 +1,61 @@
using System;
using System.Text;
using RobocraftX.Common;
using Svelto.ECS;
using Svelto.ECS.Serialization;
namespace GamecraftScripting.Serialization
{
public class ScriptSerializer : IComponentSerializer<ScriptStruct>
{
private static readonly UTF8Encoding utf8Encoding = new UTF8Encoding();
private static readonly uint padding = 42u;
public uint size => 0u;
public bool Deserialize(ref ScriptStruct value, ISerializationData serializationData)
{
GamecraftModdingAPI.Utility.Logging.MetaLog($"dataPos: {serializationData.dataPos}");
BinaryBufferReader bbr = new BinaryBufferReader(serializationData.data.ToArrayFast(out uint count), serializationData.dataPos);
short nameLength = bbr.ReadShort();
GamecraftModdingAPI.Utility.Logging.MetaLog($"nameLength: {nameLength}");
byte[] serialName = new byte[nameLength];
bbr.ReadBytes(serialName, (uint)nameLength);
value.name.Set(utf8Encoding.GetString(serialName));
int scriptLength = bbr.ReadInt();
GamecraftModdingAPI.Utility.Logging.MetaLog($"scriptLength: {scriptLength}");
byte[] serialScript = new byte[scriptLength];
bbr.ReadBytes(serialScript, (uint)scriptLength);
value.script.Set(utf8Encoding.GetString(serialScript));
uint serialPadding = bbr.ReadUint();
serializationData.dataPos += (uint)(2 + nameLength + 4 + scriptLength + 4);
GamecraftModdingAPI.Utility.Logging.MetaLog($"Deserializing Script successful: {serialPadding == padding}");
return true;
}
public bool Serialize(in ScriptStruct value, ISerializationData serializationData)
{
GamecraftModdingAPI.Utility.Logging.MetaLog($"dataPos: {serializationData.dataPos}");
byte[] serialName = utf8Encoding.GetBytes(value.name);
byte[] serialScript = utf8Encoding.GetBytes(value.script);
uint actualSize = (uint)(2 + serialName.Length + 4 + serialScript.Length + 4);
serializationData.data.ExpandBy(actualSize);
BinaryBufferWriter bbw = new BinaryBufferWriter(serializationData.data.ToArrayFast(out uint count), serializationData.dataPos);
bbw.Write((short)serialName.Length);
for (int i = 0; i < serialName.Length; i++)
{
bbw.Write(serialName[i]);
}
bbw.Write((int)serialScript.Length);
for (int i = 0; i < serialScript.Length; i++)
{
bbw.Write(serialScript[i]);
}
bbw.Write(padding);
serializationData.dataPos += actualSize;
return true;
}
}
}

View file

@ -0,0 +1,13 @@
using System;
using Svelto.ECS;
using Svelto.ECS.Experimental;
namespace GamecraftScripting.Serialization
{
public struct ScriptStruct : IEntityComponent
{
public ECSString name;
public ECSString script;
}
}

View file

@ -0,0 +1,60 @@
using System;
using System.Reflection;
using HarmonyLib;
using Svelto.ECS;
using Svelto.ECS.Serialization;
using GamecraftModdingAPI.Utility;
namespace GamecraftScripting.Serialization
{
#if DEBUG
[HarmonyPatch]
public class SerializationDescriptorMapPatch
{
public static void Prefix(ISerializableEntityDescriptor descriptor)
{
if (descriptor.entitiesToSerialize.Length == 0)
{
if (descriptor.componentsToBuild.Length != 0)
{
Logging.MetaLog($"Descriptor: {descriptor.componentsToBuild[0].GetType().FullName} (hash:{descriptor.hash})");
}
else
{
Logging.MetaLog($"Emtpy descriptor (hash: {descriptor.hash})");
}
}
else
{
Logging.MetaLog($"Descriptor: {descriptor.entitiesToSerialize[0].GetType().FullName} (hash:{descriptor.hash}) (serializables: {descriptor.entitiesToSerialize.Length})");
}
}
public static MethodBase TargetMethod()
{
//Logging.MetaLog(AccessTools.Method(AccessTools.Inner(AccessTools.TypeByName("Svelto.ECS.EnginesRoot"), "SerializationDescriptorMap"), "RegisterEntityDescriptor") == null);
return AccessTools.Method(AccessTools.Inner(AccessTools.TypeByName("Svelto.ECS.EnginesRoot"), "SerializationDescriptorMap"), "RegisterEntityDescriptor");
}
}
[HarmonyPatch]
public class SerializationDescriptorMapGetPatch
{
public static void Prefix(uint descriptorID)
{
if (descriptorID == 3520129338u)
{
Logging.MetaLog("Got hash for ScriptStruct");
}
Logging.MetaLog($"GetDescriptorFromHash({descriptorID})");
}
public static MethodBase TargetMethod()
{
//Logging.MetaLog(AccessTools.Method(AccessTools.Inner(AccessTools.TypeByName("Svelto.ECS.EnginesRoot"), "SerializationDescriptorMap"), "RegisterEntityDescriptor") == null);
return AccessTools.Method(AccessTools.Inner(AccessTools.TypeByName("Svelto.ECS.EnginesRoot"), "SerializationDescriptorMap"), "GetDescriptorFromHash");
}
}
#endif
}