From e60d74fccd7883406a3e6b2a3158f582fde34eaa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20L=C3=BCbe=C3=9F?= Date: Wed, 29 Mar 2023 13:33:34 +0200 Subject: [PATCH] Basic entity scripting --- .../src/EditWindows/ComponentEditWindow.bf | 32 +++ GlitchyEngine/src/Scripting/ScriptClass.bf | 120 +++++++++ GlitchyEngine/src/Scripting/ScriptEngine.bf | 230 +++++++++++++----- GlitchyEngine/src/Scripting/ScriptGlue.bf | 131 ++++++++++ GlitchyEngine/src/Scripting/ScriptInstance.bf | 52 ++++ .../src/World/Components/Components.bf | 24 ++ GlitchyEngine/src/World/Scene.bf | 19 +- GlitchyEngineHelper/src/Mono/Mono.bf | 31 +++ ScriptCore/CSharpTesting.cs | 62 +++-- ScriptCore/Components/Component.cs | 8 + ScriptCore/Components/Transform.cs | 8 + ScriptCore/Core/EngineObject.cs | 26 ++ ScriptCore/Core/UUID.cs | 6 + ScriptCore/Entity.cs | 56 +++++ ScriptCore/Input.cs | 27 ++ ScriptCore/Key.cs | 120 +++++++++ ScriptCore/Log.cs | 50 ++++ ScriptCore/Math/Vector2.cs | 53 ++++ ScriptCore/Math/Vector3.cs | 128 ++++++++++ ScriptCore/MouseButton.cs | 11 + ScriptCore/MyTestEntity.cs | 59 +++++ ScriptCore/ScriptCore.csproj | 13 + ScriptCore/ScriptGlue.cs | 16 ++ 23 files changed, 1193 insertions(+), 89 deletions(-) create mode 100644 GlitchyEngine/src/Scripting/ScriptClass.bf create mode 100644 GlitchyEngine/src/Scripting/ScriptGlue.bf create mode 100644 GlitchyEngine/src/Scripting/ScriptInstance.bf create mode 100644 ScriptCore/Components/Component.cs create mode 100644 ScriptCore/Components/Transform.cs create mode 100644 ScriptCore/Core/EngineObject.cs create mode 100644 ScriptCore/Core/UUID.cs create mode 100644 ScriptCore/Entity.cs create mode 100644 ScriptCore/Input.cs create mode 100644 ScriptCore/Key.cs create mode 100644 ScriptCore/Log.cs create mode 100644 ScriptCore/Math/Vector2.cs create mode 100644 ScriptCore/Math/Vector3.cs create mode 100644 ScriptCore/MouseButton.cs create mode 100644 ScriptCore/MyTestEntity.cs create mode 100644 ScriptCore/ScriptGlue.cs diff --git a/GlitchyEditor/src/EditWindows/ComponentEditWindow.bf b/GlitchyEditor/src/EditWindows/ComponentEditWindow.bf index 54c48f7..ca7cc8d 100644 --- a/GlitchyEditor/src/EditWindows/ComponentEditWindow.bf +++ b/GlitchyEditor/src/EditWindows/ComponentEditWindow.bf @@ -6,6 +6,7 @@ using System.Collections; using GlitchyEngine.Renderer; using GlitchyEngine; using GlitchyEngine.Content; +using GlitchyEngine.Scripting; namespace GlitchyEditor.EditWindows { @@ -68,6 +69,7 @@ namespace GlitchyEditor.EditWindows ShowComponentEditor("Rigidbody 2D", entity, => ShowRigidBody2DComponentEditor, => ShowComponentContextMenu); ShowComponentEditor("Box collider 2D", entity, => ShowBoxCollider2DComponentEditor, => ShowComponentContextMenu); ShowComponentEditor("Circle collider 2D", entity, => ShowCircleCollider2DComponentEditor, => ShowComponentContextMenu); + ShowComponentEditor("Script Component", entity, => ShowScriptComponentEditor, => ShowComponentContextMenu); ShowAddComponentButton(entity); } @@ -429,6 +431,35 @@ namespace GlitchyEditor.EditWindows circleCollider.RestitutionThreshold = restitutionThreshold; } + private static void ShowScriptComponentEditor(Entity entity, ScriptComponent* scriptComponent) + { + static char8[64] buffer = .(); + + StringView search = StringView(); + + if (ImGui.InputText("##ScriptName", &buffer, buffer.Count)) + { + search = StringView(&buffer); + } + + if (ImGui.BeginCombo("##Type", scriptComponent.Instance?.ScriptClass.FullName.ToScopeCStr!())) + { + for (let (className, script) in ScriptEngine.EntityClasses) + { + if (!search.IsWhiteSpace && !className.Contains(search, true)) + continue; + + if (ImGui.Selectable(className.ToScopeCStr!(), + className == scriptComponent.Instance?.ScriptClass.FullName)) + { + scriptComponent.Instance = new ScriptInstance(script); + } + } + + ImGui.EndCombo(); + } + } + private static void LabelColumn(StringView label) { ImGui.TextUnformatted(label); @@ -584,6 +615,7 @@ namespace GlitchyEditor.EditWindows ShowComponentButton("Circle collider 2D"); ShowComponentButton("Mesh"); ShowComponentButton("Mesh Renderer"); + ShowComponentButton("C# Script"); ImGui.EndCombo(); } diff --git a/GlitchyEngine/src/Scripting/ScriptClass.bf b/GlitchyEngine/src/Scripting/ScriptClass.bf new file mode 100644 index 0000000..0ea2ee3 --- /dev/null +++ b/GlitchyEngine/src/Scripting/ScriptClass.bf @@ -0,0 +1,120 @@ +using Mono; +using System; +using GlitchyEngine.Core; + +namespace GlitchyEngine.Scripting; + +class ScriptClass +{ + private String _namespace ~ delete _; + private String _className ~ delete _; + private String _fullName ~ delete _; + + private MonoClass* _monoClass; + + //typealias ConstructorMethod = function void(MonoObject* instance, UUID uuid, MonoException** exception); + typealias OnCreateMethod = function MonoObject*(MonoObject* instance, MonoException** exception); + typealias OnUpdateMethod = function MonoObject*(MonoObject* instance, float deltaTime, MonoException** exception); + typealias OnDestroyMethod = function MonoObject*(MonoObject* instance, MonoException** exception); + + private MonoMethod* _constructor; + //private ConstructorMethod _constructor; + private OnCreateMethod _onCreate; + private OnUpdateMethod _onUpdate; + private OnDestroyMethod _onDestroy; + + public StringView Namespace => _namespace; + public StringView ClassName => _className; + public StringView FullName => _fullName; + + [AllowAppend] + public this(StringView classNamespace, StringView className) + { + _namespace = new String(classNamespace); + _className = new String(className); + _fullName = new $"{_namespace}.{_className}"; + + _monoClass = Mono.mono_class_from_name(ScriptEngine.[Friend]s_CoreAssemblyImage, _namespace, _className); + + //_constructor = (ConstructorMethod)GetMethodThunk(".ctor", 1); // GetMethod(".ctor", 1);// + _constructor = GetMethod(".ctor", 1); + _onCreate = (OnCreateMethod)GetMethodThunk("OnCreate"); + _onUpdate = (OnUpdateMethod)GetMethodThunk("OnUpdate", 1); + _onDestroy = (OnDestroyMethod)GetMethodThunk("OnDestroy"); + } + + public void OnCreate(MonoObject* instance) + { + MonoException* exception = null; + if (_onCreate != null) + _onCreate(instance, &exception); + } + + public void OnUpdate(MonoObject* instance, float deltaTime) + { + MonoException* exception; + if (_onUpdate != null) + _onUpdate(instance, deltaTime, &exception); + } + + public void OnDestroy(MonoObject* instance) + { + MonoException* exception; + if (_onDestroy != null) + _onDestroy(instance, &exception); + } + + public MonoObject* CreateInstance(UUID uuid) + { + MonoObject* instance = Mono.mono_object_new(ScriptEngine.[Friend]s_AppDomain, _monoClass); + +#unwarn + ScriptEngine.[Friend]s_EngineObject.Invoke(ScriptEngine.[Friend]s_EngineObject._constructor, instance, &uuid); + + //MonoException* exception = null; +//#unwarn + //ScriptEngine.[Friend]s_EntityRoot._constructor(instance, uuid, &exception); + //ScriptEngine.[Friend]s_EntityRoot.Invoke(_constructor, instance, &uuid); + + /*MonoObject* exception = null; +#unwarn*/ + //Mono.mono_runtime_invoke(_constructor, instance, (.)&uuid, &exception); + //Mono.mono_runtime_object_init(instance); + //MonoException* exception; + //_constructor(instance, uuid, &exception); + + return instance; + } + + public MonoMethod* GetMethod(StringView name, int argCount = 0) + { + return Mono.mono_class_get_method_from_name(_monoClass, name.ToScopeCStr!(), argCount); + } + + public void* GetMethodThunk(StringView name, int argCount = 0) + { + MonoMethod* method = GetMethod(name, argCount); + + if (method == null) + return null; + + return Mono.mono_method_get_unmanaged_thunk(method); + } + + public MonoObject* Invoke(MonoMethod* method, MonoObject* instance, void** args = null) + { + MonoObject* exception = null; + return Mono.mono_runtime_invoke(method, instance, args, &exception); + } + + public MonoObject* Invoke(MonoMethod* method, MonoObject* instance, params void*[] args) + { + return Mono.mono_runtime_invoke(method, instance, args.Ptr, null); + } + + public T Invoke(MonoMethod* method, MonoObject* instance, params void*[] args) + { + MonoObject* object = Invoke(method, instance, args.Ptr); + return *(T*)Mono.mono_object_unbox(object); + } +} diff --git a/GlitchyEngine/src/Scripting/ScriptEngine.bf b/GlitchyEngine/src/Scripting/ScriptEngine.bf index edcabd9..fd6f10b 100644 --- a/GlitchyEngine/src/Scripting/ScriptEngine.bf +++ b/GlitchyEngine/src/Scripting/ScriptEngine.bf @@ -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 _entityScripts = new .() ~ { + for (var entry in _) + { + delete entry.value; + } + delete _entityScripts; + }; + + private static Dictionary _entityScriptInstances = new .() ~ { + for (var entry in _) + { + entry.value?.ReleaseRef(); + } + delete _; + }; + + public static Dictionary 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 data = new:ScopedAlloc! List(1024); + List data = new List(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(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; - } + }*/ } \ No newline at end of file diff --git a/GlitchyEngine/src/Scripting/ScriptGlue.bf b/GlitchyEngine/src/Scripting/ScriptGlue.bf new file mode 100644 index 0000000..712c0b3 --- /dev/null +++ b/GlitchyEngine/src/Scripting/ScriptGlue.bf @@ -0,0 +1,131 @@ +using Mono; +using System; +using GlitchLog; +using System.Reflection; +using GlitchyEngine.Events; +using GlitchyEngine.Math; +using GlitchyEngine.World; +using GlitchyEngine.Core; + +namespace GlitchyEngine.Scripting; + +static class ScriptGlue +{ + struct RegisterCallAttribute : Attribute + { + public String MethodName; + + public this(String methodName) + { + MethodName = methodName; + } + } + + /* Adding this attribute to a method will log method entry and returned Result errors */ + [AttributeUsage(.Method)] + struct RegisterMethodAttribute : Attribute, IOnMethodInit + { + [Comptime] + public void OnMethodInit(MethodInfo method, Self* prev) + { + for (var methodInfo in typeof(ScriptGlue).GetMethods(.Static)) + { + if (methodInfo.GetCustomAttribute() case .Ok(let attribute)) + { + String functionType = scope $"{methodInfo.ReturnType}({methodInfo.GetParamsDecl(.. scope .())})"; + + String line = scope $"RegisterCall(\"{attribute.MethodName}\", => {methodInfo.Name});\n"; + + Compiler.EmitMethodEntry(method, line); + } + } + } + } + + public static void Init() + { + RegisterCalls(); + } + + [RegisterMethod] + private static void RegisterCalls() + { + // Generated at CompTime + } + + + [RegisterCall("Log::LogMessage_Impl")] + static void Log(int32 logLevel, MonoString* message) + { + char8* utfMessage = Mono.mono_string_to_utf8(message); + + Log.ClientLogger.Log((LogLevel)logLevel, StringView(utfMessage)); + + Mono.mono_free(utfMessage); + } + +#region Input + + [RegisterCall("Input::IsKeyPressed")] + static bool Input_IsKeyPressed(Key key) => Input.IsKeyPressed(key); + + [RegisterCall("Input::IsKeyReleased")] + static bool Input_IsKeyReleased(Key key) => Input.IsKeyReleased(key); + + [RegisterCall("Input::IsKeyToggled")] + static bool Input_IsKeyToggled(Key key) => Input.IsKeyToggled(key); + + [RegisterCall("Input::IsKeyPressing")] + static bool Input_IsKeyPressing(Key key) => Input.IsKeyPressing(key); + + [RegisterCall("Input::IsKeyReleasing")] + static bool Input_IsKeyReleasing(Key key) => Input.IsKeyReleasing(key); + + + [RegisterCall("Input::IsMouseButtonPressed")] + static bool Input_IsMouseButtonPressed(MouseButton mouseButton) => Input.IsMouseButtonPressed(mouseButton); + + [RegisterCall("Input::IsMouseButtonReleased")] + static bool Input_IsMouseButtonReleased(MouseButton mouseButton) => Input.IsMouseButtonReleased(mouseButton); + + [RegisterCall("Input::IsMouseButtonPressing")] + static bool Input_IsMouseButtonPressing(MouseButton mouseButton) => Input.IsMouseButtonPressing(mouseButton); + + [RegisterCall("Input::IsMouseButtonReleasing")] + static bool Input_IsMouseButtonReleasing(MouseButton mouseButton) => Input.IsMouseButtonReleasing(mouseButton); + +#endregion Input + +#region Scene/Entity stuff + + /*[RegisterCall("Input::IsMouseButtonReleasing")] + static void Destroy() + { + // TODO: + }*/ + + [RegisterCall("ScriptGlue::Entity_GetTranslation")] + static void Entity_GetTranslation(UUID entityId, ref Vector3 translation) + { + Scene scene = ScriptEngine.Context; + Entity entity = scene.GetEntityByID(entityId); + + translation = entity.Transform.Position; + } + + [RegisterCall("ScriptGlue::Entity_SetTranslation")] + static void Entity_SetTranslation(UUID entityId, ref Vector3 translation) + { + Scene scene = ScriptEngine.Context; + Entity entity = scene.GetEntityByID(entityId); + + entity.Transform.Position = translation; + } + +#endregion + + private static void RegisterCall(String name, T method) where T : var + { + Mono.mono_add_internal_call(scope $"GlitchyEngine.{name}", (void*)method); + } +} \ No newline at end of file diff --git a/GlitchyEngine/src/Scripting/ScriptInstance.bf b/GlitchyEngine/src/Scripting/ScriptInstance.bf new file mode 100644 index 0000000..71c4a00 --- /dev/null +++ b/GlitchyEngine/src/Scripting/ScriptInstance.bf @@ -0,0 +1,52 @@ +using Mono; +using GlitchyEngine.Core; + +namespace GlitchyEngine.Scripting; + +class ScriptInstance : RefCounter +{ + private ScriptClass _scriptClass; + + private MonoObject* _instance; + private uint32 _gcHandle; + + public ScriptClass ScriptClass => _scriptClass; + + public bool IsInstatiated => _instance != null; + + public this(ScriptClass scriptClass) + { + Log.EngineLogger.AssertDebug(scriptClass != null); + _scriptClass = scriptClass; + } + + private ~this() + { + if (_instance != null) + { + _scriptClass.OnDestroy(_instance); + Mono.mono_gchandle_free(_gcHandle); + } + } + + public void Instantiate(UUID uuid) + { + _instance = _scriptClass.CreateInstance(uuid); + _gcHandle = Mono.mono_gchandle_new(_instance, true); + } + + public void InvokeOnCreate() + { + _scriptClass.OnCreate(_instance); + } + + public void InvokeOnUpdate(float deltaTime) + { + _scriptClass.OnUpdate(_instance, deltaTime); + } + + public void InvokeOnDestroy() + { + _scriptClass.OnDestroy(_instance); + } +} \ No newline at end of file diff --git a/GlitchyEngine/src/World/Components/Components.bf b/GlitchyEngine/src/World/Components/Components.bf index 90108d8..5962bc0 100644 --- a/GlitchyEngine/src/World/Components/Components.bf +++ b/GlitchyEngine/src/World/Components/Components.bf @@ -4,6 +4,8 @@ using GlitchyEngine.Renderer; using GlitchyEngine.Core; using Box2D; using GlitchyEngine.Content; +using GlitchyEngine.Scripting; +using Mono; namespace GlitchyEngine.World { @@ -442,4 +444,26 @@ namespace GlitchyEngine.World [Inline] internal ref b2Vec2 b2Offset mut => ref *(Box2D.b2Vec2*)(void*)&Offset; } + + struct ScriptComponent : IDisposableComponent + { + private ScriptInstance _instance = null; + + public ScriptInstance Instance + { + [Inline] + get => _instance; + [Inline] + set mut => SetReference!(_instance, value); + } + + public bool InInstantiated => _instance?.IsInstatiated ?? false; + + public void Dispose() mut + { + ReleaseRefAndNullify!(_instance); + + + } + } } \ No newline at end of file diff --git a/GlitchyEngine/src/World/Scene.bf b/GlitchyEngine/src/World/Scene.bf index be82ee6..9bac9a7 100644 --- a/GlitchyEngine/src/World/Scene.bf +++ b/GlitchyEngine/src/World/Scene.bf @@ -5,6 +5,7 @@ using System.Collections; using Box2D; using GlitchyEngine.Core; using GlitchyEngine.Content; +using GlitchyEngine.Scripting; namespace GlitchyEngine.World { @@ -75,7 +76,8 @@ namespace GlitchyEngine.World CopyComponents(this, target); CopyComponents(this, target); CopyComponents(this, target); - + CopyComponents(this, target); + // Copy transforms for (let (sourceHandle, sourceTransform) in _ecsWorld.Enumerate()) { @@ -127,10 +129,12 @@ namespace GlitchyEngine.World public void OnRuntimeStart() { OnSimulationStart(); + ScriptEngine.SetContext(this); } public void OnRuntimeStop() { + ScriptEngine.SetContext(null); OnSimulationStop(); } @@ -211,6 +215,8 @@ namespace GlitchyEngine.World Runtime = 0x04 | Physics, } + //private append List _destroyQueue = .(); + public void Update(GameTime gameTime, UpdateMode mode) { Debug.Profiler.ProfileRendererFunction!(); @@ -231,6 +237,17 @@ namespace GlitchyEngine.World script.Instance.[Friend]OnUpdate(gameTime); } + + // Run scripts + for (var (entity, script) in _ecsWorld.Enumerate()) + { + if (!script.InInstantiated) + { + ScriptEngine.InitializeInstance(Entity(entity, this), script); + } + + script.Instance.InvokeOnUpdate(gameTime.DeltaTime); + } } if (mode.HasFlag(.Physics)) diff --git a/GlitchyEngineHelper/src/Mono/Mono.bf b/GlitchyEngineHelper/src/Mono/Mono.bf index 7f82dc2..ff38319 100644 --- a/GlitchyEngineHelper/src/Mono/Mono.bf +++ b/GlitchyEngineHelper/src/Mono/Mono.bf @@ -61,6 +61,7 @@ static class Mono public static extern char8* mono_metadata_string_heap(MonoImage *meta, uint32 table_index); typealias gconstpointer = void*; + typealias gpointer = void*; [LinkName(.C)] public static extern void mono_add_internal_call(char8* name, gconstpointer method); @@ -96,6 +97,32 @@ static class Mono [LinkName(.C)] public static extern void* mono_domain_unload(MonoDomain* domain); + + + [LinkName(.C)] + public static extern gpointer mono_method_get_unmanaged_thunk(MonoMethod *method); + + [LinkName(.C)] + public static extern mono_bool mono_class_is_subclass_of(MonoClass *monoClass, MonoClass *parentClass, + mono_bool check_interfaces); + + [LinkName(.C)] + public static extern uint32 mono_gchandle_new(MonoObject* obj, mono_bool pinned); + + [LinkName(.C)] + public static extern void mono_gchandle_free(uint32 gchandle); + + [LinkName(.C)] + public static extern char8* mono_string_to_utf8(MonoString *s); + + [LinkName(.C)] + public static extern void mono_free(void* ptr); + + [LinkName(.C)] + public static extern MonoClassField* mono_class_get_field_from_name(MonoClass* monoClass, char8* name); + + [LinkName(.C)] + public static extern void mono_field_set_value(MonoObject* obj, MonoClassField* field, void* value); } struct MonoDomain; @@ -114,6 +141,10 @@ struct MonoObject; struct MonoMethod; +struct MonoException; + +struct MonoClassField; + enum MonoImageOpenStatus { Ok, diff --git a/ScriptCore/CSharpTesting.cs b/ScriptCore/CSharpTesting.cs index 54c0c7e..f88d598 100644 --- a/ScriptCore/CSharpTesting.cs +++ b/ScriptCore/CSharpTesting.cs @@ -1,36 +1,44 @@ using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using GlitchyEngine.Math; -namespace GlitchyEngine +namespace GlitchyEngine; + +public class CSharpTesting { - public class CSharpTesting - { - public float MyPublicFloatVar = 5.0f; - - public CSharpTesting() - { - Console.WriteLine("Hallo von C#!"); - DoSomething(); - Console.WriteLine(Sample()); - } - - [DllImport ("__Internal", EntryPoint="DoSomething")] - static extern void DoSomething(); + public float MyPublicFloatVar = 5.0f; + + public CSharpTesting() + { + Console.WriteLine("Hallo von C#!"); + DoSomething(); + Console.WriteLine(Sample()); - [MethodImpl(MethodImplOptions.InternalCall)] - static extern string Sample(); + Vector3 a = new Vector3(1, 2, 3); + Vector3 b = new Vector3(3, 2, 1); - public void PrintFloatVar() - { - Console.WriteLine("MyPublicFloatVar = {0:F}", MyPublicFloatVar); - } + Vector3 result; + //Vector3.Add_Internal(a, b, out result); - private float IncrementFloatVar(float value) - { - MyPublicFloatVar += value; - - return MyPublicFloatVar; - } + //Console.WriteLine(result); } -} \ No newline at end of file + + [DllImport ("__Internal", EntryPoint="DoSomething")] + static extern void DoSomething(); + + [MethodImpl(MethodImplOptions.InternalCall)] + static extern string Sample(); + + public void PrintFloatVar() + { + Console.WriteLine("MyPublicFloatVar = {0:F}", MyPublicFloatVar); + } + + private float IncrementFloatVar(float value) + { + MyPublicFloatVar += value; + + return MyPublicFloatVar; + } +} diff --git a/ScriptCore/Components/Component.cs b/ScriptCore/Components/Component.cs new file mode 100644 index 0000000..62da665 --- /dev/null +++ b/ScriptCore/Components/Component.cs @@ -0,0 +1,8 @@ +using GlitchyEngine.Core; + +namespace GlitchyEngine; + +public class Component : EngineObject +{ + +} \ No newline at end of file diff --git a/ScriptCore/Components/Transform.cs b/ScriptCore/Components/Transform.cs new file mode 100644 index 0000000..bd891bd --- /dev/null +++ b/ScriptCore/Components/Transform.cs @@ -0,0 +1,8 @@ +using GlitchyEngine.Core; + +namespace GlitchyEngine; + +public class Transform : EngineObject +{ + +} diff --git a/ScriptCore/Core/EngineObject.cs b/ScriptCore/Core/EngineObject.cs new file mode 100644 index 0000000..76e775c --- /dev/null +++ b/ScriptCore/Core/EngineObject.cs @@ -0,0 +1,26 @@ +namespace GlitchyEngine.Core; + +public class EngineObject +{ + protected internal UUID _uuid; + + /// + /// UUID used for identifying the object in the engine. + /// + public UUID UUID => _uuid; + + /// + /// Empty constructor not used. Do NOT USE! + /// + protected EngineObject() + {} + + /// + /// Creates a new EngineObject with the given ID. + /// + /// UUID of the object. + internal EngineObject(UUID uuid) + { + _uuid = uuid; + } +} diff --git a/ScriptCore/Core/UUID.cs b/ScriptCore/Core/UUID.cs new file mode 100644 index 0000000..465f9df --- /dev/null +++ b/ScriptCore/Core/UUID.cs @@ -0,0 +1,6 @@ +namespace GlitchyEngine.Core; + +public struct UUID +{ + private ulong _uuid; +} diff --git a/ScriptCore/Entity.cs b/ScriptCore/Entity.cs new file mode 100644 index 0000000..ac46fc3 --- /dev/null +++ b/ScriptCore/Entity.cs @@ -0,0 +1,56 @@ +using System; +using GlitchyEngine.Core; +using GlitchyEngine.Math; + +namespace GlitchyEngine; + +internal struct EntityHandle +{ + public uint Version; + public uint Index; +} + +public abstract class Entity : EngineObject +{ + //private UUID _uuid; + + //public UUID UUID => _uuid; + + ///// + ///// Empty constructor not used. Do NOT USE! + ///// + //protected Entity() + //{} + + //internal Entity(UUID uuid) + //{ + // _uuid = uuid; + //} + + public T GetComponent() where T : Component + { + return null; + } + + //public Transform Transform => new (){_uuid = _uuid}; + + public Vector3 Translation + { + get + { + ScriptGlue.Entity_GetTranslation(_uuid, out Vector3 translation); + return translation; + } + + set => ScriptGlue.Entity_SetTranslation(_uuid, value); + } + + // Will be executed once after the entity as be created. + // void OnCreate(); + + // Will be executed every frame. + // void OnUpdate(GameTime); + + // Will be executed once when the entity is being destroyed. + // void OnDestroy(); +} diff --git a/ScriptCore/Input.cs b/ScriptCore/Input.cs new file mode 100644 index 0000000..3607122 --- /dev/null +++ b/ScriptCore/Input.cs @@ -0,0 +1,27 @@ +using System.Runtime.CompilerServices; + +namespace GlitchyEngine; + +public static class Input +{ + [MethodImpl(MethodImplOptions.InternalCall)] + public static extern bool IsKeyPressed(Key key); + [MethodImpl(MethodImplOptions.InternalCall)] + public static extern bool IsKeyReleased(Key key); + [MethodImpl(MethodImplOptions.InternalCall)] + public static extern bool IsKeyToggled(Key key); + + [MethodImpl(MethodImplOptions.InternalCall)] + public static extern bool IsKeyPressing(Key key); + [MethodImpl(MethodImplOptions.InternalCall)] + public static extern bool IsKeyReleasing(Key key); + + [MethodImpl(MethodImplOptions.InternalCall)] + public static extern bool IsMouseButtonPressed(MouseButton mouseButton); + [MethodImpl(MethodImplOptions.InternalCall)] + public static extern bool IsMouseButtonReleased(MouseButton mouseButton); + [MethodImpl(MethodImplOptions.InternalCall)] + public static extern bool IsMouseButtonPressing(MouseButton mouseButton); + [MethodImpl(MethodImplOptions.InternalCall)] + public static extern bool IsMouseButtonReleasing(MouseButton mouseButton); +} diff --git a/ScriptCore/Key.cs b/ScriptCore/Key.cs new file mode 100644 index 0000000..1f8ebce --- /dev/null +++ b/ScriptCore/Key.cs @@ -0,0 +1,120 @@ +namespace GlitchyEngine; + +public enum Key +{ + // Based on Win32 Virtual Keys + LeftButton = 1, // Left mouse button + RightRutton = 2, // Right mouse button + MiddleButton = 4, // Middle mouse button(three - button mouse) + XButton1 = 5, // X1 mouse button + XButton2 = 6, // X2 mouse button + Backspace = 8, // Backspace key + Tab = 9, // Tab key + Return = 13, // Enter key + Shift = 16, // Shift key + Control = 17, // Ctrl key + Alt = 18, // Alt key + Pause = 19, // Pause key + CapsLock = 20, // Caps Lock key + Escape = 27, // ESC key + Space = 32, // Spacebar + Prior = 33, // Page Up key + Next = 34, // Page Down key + End = 35, // END key + Home = 36, // HOME key + Left = 37, // LEFT ARROW key + Up = 38, // UP ARROW key + Right = 39, // RIGHT ARROW key + Down = 40, // DOWN ARROW key + Print = 42, // PRINT key + Insert = 45, // INS key + Delete = 46, // DEL key + Help = 47, // HELP key + Zero = 48, // 0 key + One = 49, // 1 key + Two = 50, // 2 key + Three = 51, // 3 key + Four = 52, // 4 key + Five = 53, // 5 key + Six = 54, // 6 key + Seven = 55, // 7 key + Eight = 56, // 8 key + Nine = 57, // 9 key + A = 65, // A key + B = 66, // B key + C = 67, // C key + D = 68, // D key + E = 69, // E key + F = 70, // F key + G = 71, // G key + H = 72, // H key + I = 73, // I key + J = 74, // J key + K = 75, // K key + L = 76, // L key + M = 77, // M key + N = 78, // N key + O = 79, // O key + P = 80, // P key + Q = 81, // Q key + R = 82, // R key + S = 83, // S key + T = 84, // T key + U = 85, // U key + V = 86, // V key + W = 87, // W key + X = 88, // X key + Y = 89, // Y key + Z = 90, // Z key + LeftSuper = 91, // Left Windows key(Microsoft® Natural® keyboard) + RightSuper = 92, // Right Windows key(Natural keyboard) + ContextMenu = 93, // Context Menu key (VK_APPS) + Numpad0 = 96, // Numeric keypad 0 key + Numpad1 = 97, // Numeric keypad 1 key + Numpad2 = 98, // Numeric keypad 2 key + Numpad3 = 99, // Numeric keypad 3 key + Numpad4 = 100, // Numeric keypad 4 key + Numpad5 = 101, // Numeric keypad 5 key + Numpad6 = 102, // Numeric keypad 6 key + Numpad7 = 103, // Numeric keypad 7 key + Numpad8 = 104, // Numeric keypad 8 key + Numpad9 = 105, // Numeric keypad 9 key + Multiply = 106, // Multiply key + Add = 107, // Add key + Separator = 108, // Separator key + Subtract = 109, // Subtract key + Decimal = 110, // Decimal key + Divide = 111, // Divide key + F1 = 112, // F1 key + F2 = 113, // F2 key + F3 = 114, // F3 key + F4 = 115, // F4 key + F5 = 116, // F5 key + F6 = 117, // F6 key + F7 = 118, // F7 key + F8 = 119, // F8 key + F9 = 120, // F9 key + F10 = 121, // F10 key + F11 = 122, // F11 key + F12 = 123, // F12 key + F13 = 124, // F13 key + F14 = 125, // F14 key + F15 = 126, // F15 key + F16 = 127, // F16 key + F17 = 128, // F17 key + F18 = 129, // F18 key + F19 = 130, // F19 key + F20 = 131, // F20 key + F21 = 132, // F21 key + F22 = 133, // F22 key + F23 = 134, // F23 key + F24 = 135, // F24 key + Numlock = 144, // NUM LOCK key + Scroll = 145, // SCROLL LOCK key + LeftShift = 160, // Left SHIFT key + RightShift = 161, // Right SHIFT key + LeftControl = 162, // Left CONTROL key + RightControl = 163, // Right CONTROL key + LeftAlt = 164, // Left Alt key + RightAlt = 165 // Right Alt key +} diff --git a/ScriptCore/Log.cs b/ScriptCore/Log.cs new file mode 100644 index 0000000..05cc533 --- /dev/null +++ b/ScriptCore/Log.cs @@ -0,0 +1,50 @@ +using System.Runtime.CompilerServices; + +namespace GlitchyEngine; + +public class Log +{ + public enum LogLevel + { + Trace = 0, + Debug, + Info, + Warning, + Error, + Critical, + Off + } + + public static void Trace(string message) + { + LogMessage_Impl(LogLevel.Trace, message); + } + + //public static void LogDebug(string message) + //{ + // LogMessage_Impl(LogLevel.Info, message); + //} + + public static void Info(string message) + { + LogMessage_Impl(LogLevel.Info, message); + } + + public static void Warning(string message) + { + LogMessage_Impl(LogLevel.Warning, message); + } + + public static void Error(string message) + { + LogMessage_Impl(LogLevel.Error, message); + } + + public static void Critical(string message) + { + LogMessage_Impl(LogLevel.Critical, message); + } + + [MethodImpl(MethodImplOptions.InternalCall)] + public static extern string LogMessage_Impl(LogLevel logLevel, string message); +} diff --git a/ScriptCore/Math/Vector2.cs b/ScriptCore/Math/Vector2.cs new file mode 100644 index 0000000..049a399 --- /dev/null +++ b/ScriptCore/Math/Vector2.cs @@ -0,0 +1,53 @@ +using System; + +namespace GlitchyEngine.Math; + +public struct Vector2 +{ + public static readonly Vector2 Zero = new(0.0f, 0.0f); + public static readonly Vector2 UnitX = new(1.0f, 0.0f); + public static readonly Vector2 UnitY = new(0.0f, 1.0f); + public static readonly Vector2 One = new(0.0f, 0.0f); + + public const int ComponentCount = 2; + + public float X, Y; + + public Vector2() + { + X = Y = 0.0f; + } + + public Vector2(float x, float y) + { + X = x; + Y = y; + } + + public float this[int index] + { + get + { + switch(index) + { + case 0: return X; + case 1: return Y; + default: throw new IndexOutOfRangeException(); + } + } + + set + { + switch(index) + { + case 0: + X = value; + break; + case 1: + Y = value; + break; + default: throw new IndexOutOfRangeException(); + } + } + } +} \ No newline at end of file diff --git a/ScriptCore/Math/Vector3.cs b/ScriptCore/Math/Vector3.cs new file mode 100644 index 0000000..299f08f --- /dev/null +++ b/ScriptCore/Math/Vector3.cs @@ -0,0 +1,128 @@ +using System; +using System.CodeDom; +using System.Runtime.CompilerServices; + +namespace GlitchyEngine.Math; + +public struct Vector3 +{ + public static readonly Vector3 Zero = new(0.0f, 0.0f, 0.0f); + public static readonly Vector3 UnitX = new(1.0f, 0.0f, 0.0f); + public static readonly Vector3 UnitY = new(0.0f, 1.0f, 0.0f); + public static readonly Vector3 UnitZ = new(0.0f, 0.0f, 1.0f); + public static readonly Vector3 One = new(0.0f, 0.0f, 0.0f); + + public static readonly Vector3 Forward = new(0.0f, 0.0f, 1.0f); + public static readonly Vector3 Backward = new(0.0f, 0.0f, -1.0f); + public static readonly Vector3 Left = new(-1.0f, 0.0f, 0.0f); + public static readonly Vector3 Right = new(1.0f, 0.0f, 0.0f); + public static readonly Vector3 Up = new(0.0f, 1.0f, 0.0f); + public static readonly Vector3 Down = new(0.0f, -1.0f, 0.0f); + + public const int ComponentCount = 3; + + public float X, Y, Z; + + public Vector3() + { + X = Y = Z = 0.0f; + } + + public Vector3(float x, float y, float z) + { + X = x; + Y = y; + Z = z; + } + public Vector3(Vector2 xy, float z) + { + X = xy.X; + Y = xy.Y; + Z = z; + } + + public float this[int index] + { + get + { + switch(index) + { + case 0: return X; + case 1: return Y; + case 2: return Z; + default: throw new IndexOutOfRangeException(); + } + } + + set + { + switch(index) + { + case 0: + X = value; + break; + case 1: + Y = value; + break; + case 2: + Z = value; + break; + default: throw new IndexOutOfRangeException(); + } + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector3 operator +(in Vector3 a, in Vector3 b) => new(a.X + b.X, a.Y + b.Y, a.Z + b.Z); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector3 operator +(float a, in Vector3 b) => new(a + b.X, a + b.Y, a + b.Z); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector3 operator +(in Vector3 a, float b) => new(a.X + b, a.Y + b, a.Z + b); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector3 operator +(in Vector3 a) => a; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector3 operator -(in Vector3 a, in Vector3 b) => new(a.X - b.X, a.Y - b.Y, a.Z - b.Z); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector3 operator -(float a, in Vector3 b) => new(a - b.X, a - b.Y, a - b.Z); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector3 operator -(in Vector3 a, float b) => new(a.X - b, a.Y - b, a.Z - b); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector3 operator -(in Vector3 a) => new Vector3(-a.X, -a.Y, -a.Z); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector3 operator *(in Vector3 a, in Vector3 b) => new(a.X * b.X, a.Y * b.Y, a.Z * b.Z); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector3 operator *(float a, in Vector3 b) => new(a * b.X, a * b.Y, a * b.Z); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector3 operator *(in Vector3 a, float b) => new(a.X * b, a.Y * b, a.Z * b); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector3 operator /(in Vector3 a, in Vector3 b) => new(a.X / b.X, a.Y / b.Y, a.Z / b.Z); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector3 operator /(float a, in Vector3 b) => new(a / b.X, a / b.Y, a / b.Z); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector3 operator /(in Vector3 a, float b) => new(a.X / b, a.Y / b, a.Z / b); + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator ==(Vector3 a, Vector3 b) + { + float diffX = a.X - b.X; + float diffY = a.Y - b.Y; + float diffZ = a.Z - b.Z; + + return diffX * diffX + diffY * diffY + diffZ * diffZ < 0.00001f; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator !=(Vector3 a, Vector3 b) + { + return !(a == b); + } + + public override string ToString() + { + return $"X:{X}, Y:{Y}, Z:{Z}"; + } +} \ No newline at end of file diff --git a/ScriptCore/MouseButton.cs b/ScriptCore/MouseButton.cs new file mode 100644 index 0000000..561afd7 --- /dev/null +++ b/ScriptCore/MouseButton.cs @@ -0,0 +1,11 @@ +namespace GlitchyEngine; + +public enum MouseButton : byte +{ + None = 0, + LeftButton, + RightButton, + MiddleButton, + XButton1, + XButton2, +} diff --git a/ScriptCore/MyTestEntity.cs b/ScriptCore/MyTestEntity.cs new file mode 100644 index 0000000..f8e81af --- /dev/null +++ b/ScriptCore/MyTestEntity.cs @@ -0,0 +1,59 @@ +using System; +using GlitchyEngine.Math; + +namespace GlitchyEngine; + +class MyTestEntity : Entity +{ + //Rigidbody2D _rigidBody; + + /// + /// Called after the script component was created. (The entity might not be fully created yet) + /// + void OnCreate() + { + Log.Info($"Create! {UUID}"); + + //_rigidBody = GetComponent(); + } + + ///// + ///// Called after the entity was created completely. + ///// + //void OnInstantiate() + //{ + // Log.Warning($"Instantiated!"); + //} + + /// + /// Called every frame. + /// + /// + void OnUpdate(float deltaTime) + { + if (Input.IsKeyPressed(Key.A)) + { + Log.Info($"HALLO!"); + + Vector3 translation = Translation; + translation.Y += 1.0f * deltaTime; + + Translation = translation; + + //_rigidBody.ApplyImpulse(new Vector2(0, 10)); + } + + if (Input.IsMouseButtonReleasing(MouseButton.LeftButton)) + { + Log.Info("Ouha!"); + } + } + + /// + /// Called before the component is being destroyed. + /// + void OnDestroy() + { + Log.Trace("Destroy"); + } +} diff --git a/ScriptCore/ScriptCore.csproj b/ScriptCore/ScriptCore.csproj index d4565d4..b558724 100644 --- a/ScriptCore/ScriptCore.csproj +++ b/ScriptCore/ScriptCore.csproj @@ -43,8 +43,21 @@ + + + + + + + + + + + + + diff --git a/ScriptCore/ScriptGlue.cs b/ScriptCore/ScriptGlue.cs new file mode 100644 index 0000000..b809d7d --- /dev/null +++ b/ScriptCore/ScriptGlue.cs @@ -0,0 +1,16 @@ +using System.Runtime.CompilerServices; +using GlitchyEngine.Core; +using GlitchyEngine.Math; + +namespace GlitchyEngine; + +/// +/// All methods in here are glued to the ScriptGlue.bf in the engine. +/// +internal static class ScriptGlue +{ + [MethodImpl(MethodImplOptions.InternalCall)] + internal static extern void Entity_GetTranslation(UUID entityId, out Vector3 translation); + [MethodImpl(MethodImplOptions.InternalCall)] + internal static extern void Entity_SetTranslation(UUID entityId, in Vector3 translation); +}