Basic entity scripting

This commit is contained in:
Simon Lübeß
2023-03-29 13:33:34 +02:00
parent 5e5134a607
commit e60d74fccd
23 changed files with 1193 additions and 89 deletions
+169 -61
View File
@@ -2,6 +2,10 @@ using Mono;
using System;
using System.IO;
using System.Collections;
using GlitchyEngine.Math;
using GlitchyEngine.World;
using GlitchyEngine.Core;
namespace GlitchyEngine.Scripting;
static class ScriptEngine
@@ -10,73 +14,72 @@ static class ScriptEngine
private static MonoDomain* s_AppDomain;
private static MonoAssembly* s_CoreAssembly;
private static MonoImage* s_CoreAssemblyImage;
private static Scene s_Context ~ _?.ReleaseRef();
private static ScriptClass s_EntityRoot ~ delete _;
private static ScriptClass s_EngineObject ~ delete _;
private static Dictionary<StringView, ScriptClass> _entityScripts = new .() ~ {
for (var entry in _)
{
delete entry.value;
}
delete _entityScripts;
};
private static Dictionary<UUID, ScriptInstance> _entityScriptInstances = new .() ~ {
for (var entry in _)
{
entry.value?.ReleaseRef();
}
delete _;
};
public static Dictionary<StringView, ScriptClass> EntityClasses => _entityScripts;
public static Scene Context => s_Context;
public static void Init()
{
Mono.mono_set_assemblies_path("mono/lib");
s_RootDomain = Mono.mono_jit_init("GlitchyEngineJITRuntime");
Log.EngineLogger.Assert(s_RootDomain != null, "Failed to initialize mono root domain");
// Create an App Domain
s_AppDomain = Mono.mono_domain_create_appdomain("GlitchyEngineScriptRuntime", null);
Mono.mono_domain_set(s_AppDomain, true);
ScriptGlue.Init();
s_CoreAssembly = LoadCSharpAssembly("resources/scripts/ScriptCore.dll");
PrintAssemblyTypes(s_CoreAssembly);
LoadAssembly("resources/scripts/ScriptCore.dll");
function MonoString*() v = => Sample;
Mono.mono_add_internal_call("GlitchyEngine.CSharpTesting::Sample", v);
// Create object
MonoImage* image = Mono.mono_assembly_get_image(s_CoreAssembly);
MonoClass* monoClass = Mono.mono_class_from_name(image, "GlitchyEngine", "CSharpTesting");
MonoObject* instance = Mono.mono_object_new(s_AppDomain, monoClass);
Mono.mono_runtime_object_init(instance);
MonoMethod* simpleMethod = Mono.mono_class_get_method_from_name(monoClass, "PrintFloatVar", 0);
Mono.mono_runtime_invoke(simpleMethod, instance, null, null);
MonoMethod* methodWithArg = Mono.mono_class_get_method_from_name(monoClass, "IncrementFloatVar", 1);
float increment = 2.0f;
void*[1] args = .(&increment);
MonoObject* returnValue = Mono.mono_runtime_invoke(methodWithArg, instance, &args, null);
float returnedValue = *(float*)Mono.mono_object_unbox(returnValue);
Log.EngineLogger.Info($"C# returned: {returnedValue}");
Mono.mono_runtime_invoke(simpleMethod, instance, null, null);
//Samples();
}
[LinkName(.C), AlwaysInclude, Export]
public static void DoSomething()
public static void SetContext(Scene scene)
{
Console.WriteLine("P/Invoke: Hallo von der Engine!");
SetReference!(s_Context, scene);
}
[LinkName(.C), AlwaysInclude]
public static MonoString* Sample()
public static void InitializeInstance(Entity entity, ScriptComponent* script)
{
return Mono.mono_string_new(Mono.mono_domain_get(), "Hello!");
_entityScriptInstances[entity.UUID] = script.Instance..AddRef();
script.Instance.Instantiate(entity.UUID);
script.Instance.InvokeOnCreate();
}
private static MonoAssembly* LoadCSharpAssembly(StringView assemblyPath)
{
List<uint8> data = new:ScopedAlloc! List<uint8>(1024);
List<uint8> data = new List<uint8>(1024);
File.ReadAll(assemblyPath, data);
// NOTE: We can't use this image for anything other than loading the assembly because this image doesn't have a reference to the assembly
MonoImageOpenStatus status = .ImageInvalid;
MonoImage* image = Mono.mono_image_open_from_data_full(data.Ptr, (.)data.Count, true, &status, false);
delete data;
if (status != .Ok)
{
char8* errorMessage = Mono.mono_image_strerror(status);
@@ -89,15 +92,132 @@ static class ScriptEngine
MonoAssembly* assembly = Mono.mono_assembly_load_from_full(image, assemblyPath.ToScopeCStr!(), &status, 0);
Mono.mono_image_close(image);
// Create object
// call simple method
// call method with args
return assembly;
}
static void LoadAssembly(StringView filepath)
{
s_AppDomain = Mono.mono_domain_create_appdomain("GlitchyEngineScriptRuntime", null);
Mono.mono_domain_set(s_AppDomain, true);
s_CoreAssembly = LoadCSharpAssembly(filepath);
s_CoreAssemblyImage = Mono.mono_assembly_get_image(s_CoreAssembly);
GetEntitiesFromAssembly(s_CoreAssembly);
}
private static void GetEntitiesFromAssembly(MonoAssembly* assembly)
{
for (var entry in _entityScripts)
{
delete entry.value;
}
_entityScripts.Clear();
MonoImage* image = Mono.mono_assembly_get_image(assembly);
MonoTableInfo* typeDefinitionsTable = Mono.mono_image_get_table_info(image, .MONO_TABLE_TYPEDEF);
int32 numTypes = Mono.mono_table_info_get_rows(typeDefinitionsTable);
s_EngineObject = new ScriptClass("GlitchyEngine.Core", "EngineObject");
s_EntityRoot = new ScriptClass("GlitchyEngine", "Entity");
Log.EngineLogger.Assert(s_EntityRoot != null);
for (int32 i = 0; i < numTypes; i++)
{
int32[(.)SOME_RANDOM_ENUM.MONO_TYPEDEF_SIZE] cols = .();
Mono.mono_metadata_decode_row(typeDefinitionsTable, i, (.)&cols, (.)SOME_RANDOM_ENUM.MONO_TYPEDEF_SIZE);
char8* nameSpace = Mono.mono_metadata_string_heap(image, (.)cols[(.)SOME_RANDOM_ENUM.MONO_TYPEDEF_NAMESPACE]);
char8* name = Mono.mono_metadata_string_heap(image, (.)cols[(.)SOME_RANDOM_ENUM.MONO_TYPEDEF_NAME]);
MonoClass* monoClass = Mono.mono_class_from_name(image, nameSpace, name);
if (monoClass != null && Mono.mono_class_is_subclass_of(monoClass, s_EntityRoot.[Friend]_monoClass, false))
{
ScriptClass entityScript = new ScriptClass(StringView(nameSpace), StringView(name));
_entityScripts.Add(entityScript.FullName, entityScript);
Log.EngineLogger.Info($"Added entity \"{entityScript.FullName}\"");
}
}
}
public static void Shutdown()
{
/*Mono.mono_assembly_close(s_CoreAssembly);
s_CoreAssembly = null;
Mono.mono_domain_unload(s_AppDomain);
s_AppDomain = null;*/
Mono.mono_jit_cleanup(s_RootDomain);
s_RootDomain = null;
}
/*static void Samples()
{
PrintAssemblyTypes(s_CoreAssembly);
function MonoString*() v = => Sample;
Mono.mono_add_internal_call("GlitchyEngine.CSharpTesting::Sample", v);
function void(in Vector3, in Vector3, out Vector3) v2 = => Add;
Mono.mono_add_internal_call("GlitchyEngine.Vector3::Add_Internal", v2);
// Create object
ScriptClass myClass = scope .("GlitchyEngine", "CSharpTesting");
MonoObject* instance = myClass.CreateInstance();
MonoMethod* simpleMethod = myClass.GetMethod("PrintFloatVar");
myClass.Invoke(simpleMethod, instance);
MonoMethod* methodWithArg = myClass.GetMethod("IncrementFloatVar", 1);
float increment = 2.0f;
float returnedValue = myClass.Invoke<float>(methodWithArg, instance, &increment);
Log.EngineLogger.Info($"C# returned: {returnedValue}");
Mono.mono_runtime_invoke(simpleMethod, instance, null, null);
}
[LinkName(.C), AlwaysInclude, Export]
public static void DoSomething()
{
Console.WriteLine("P/Invoke: Hallo von der Engine!");
}
[LinkName(.C), AlwaysInclude, Export]
public static void Add(in Vector3 a, in Vector3 b, out Vector3 c)
{
c = a + b;
}
[LinkName(.C), AlwaysInclude]
public static MonoString* Sample()
{
return Mono.mono_string_new(Mono.mono_domain_get(), "Hello!");
}
private static void PrintAssemblyTypes(MonoAssembly* assembly)
{
MonoImage* image = Mono.mono_assembly_get_image(assembly);
@@ -114,17 +234,5 @@ static class ScriptEngine
Log.EngineLogger.Info($"{StringView(nameSpace)}.{StringView(name)}");
}
}
public static void Shutdown()
{
/*Mono.mono_assembly_close(s_CoreAssembly);
s_CoreAssembly = null;
Mono.mono_domain_unload(s_AppDomain);
s_AppDomain = null;*/
Mono.mono_jit_cleanup(s_RootDomain);
s_RootDomain = null;
}
}*/
}