mirror of
https://github.com/aharabada/glitchy-engine-beef.git
synced 2026-09-05 13:01:52 +00:00
Start of using CoreCLR and automatic scriptglue generation
This commit is contained in:
@@ -34,3 +34,6 @@
|
|||||||
[submodule "vendor/ImGui.NET"]
|
[submodule "vendor/ImGui.NET"]
|
||||||
path = vendor/ImGui.NET
|
path = vendor/ImGui.NET
|
||||||
url = https://github.com/aharabada/ImGui.NET.git
|
url = https://github.com/aharabada/ImGui.NET.git
|
||||||
|
[submodule "vendor/NetHostBeef"]
|
||||||
|
path = vendor/NetHostBeef
|
||||||
|
url = https://github.com/aharabada/NetHostBeef.git
|
||||||
|
|||||||
+2
-2
@@ -1,7 +1,7 @@
|
|||||||
FileVersion = 1
|
FileVersion = 1
|
||||||
Projects = {GlitchyEngine = {Path = "GlitchyEngine"}, GlitchLog = {Path = "GlitchLog"}, DirectX = {Path = "GlitchyEngine/vendor/directx/DirectX"}, LodePng = {Path = "vendor/lodepng-beef/lodepng-beef"}, FreeType = {Path = "GlitchyEngine/vendor/freetype"}, cgltf-beef = {Path = "GlitchyEngine/vendor/gltf/cgltf-beef"}, GlitchyEditor = {Path = "GlitchyEditor"}, msdfgen-beef = {Path = "GlitchyEngine/vendor/msdfgen/msdfgen-beef"}, ImGui = {Path = "GlitchyEngine/vendor/imgui/ImGui"}, ImGuiImplDX11 = {Path = "GlitchyEngine/vendor/imgui/ImGuiImplDX11"}, ImGuiImplWin32 = {Path = "GlitchyEngine/vendor/imgui/ImGuiImplWin32"}, ImGuizmo = {Path = "GlitchyEngine/vendor/imgui/ImGuizmo"}, GlitchyEngineHelper = {Path = "GlitchyEngineHelper"}, bon = {Path = "GlitchyEngine/vendor/bon"}, box2d-beef = {Path = "GlitchyEngine/vendor/box2D"}, "Beef.Linq" = {Path = "GlitchyEngine/vendor/Beef.Linq/src"}, ScriptCore = {Path = "ScriptCore"}}
|
Projects = {GlitchyEngine = {Path = "GlitchyEngine"}, GlitchLog = {Path = "GlitchLog"}, DirectX = {Path = "GlitchyEngine/vendor/directx/DirectX"}, LodePng = {Path = "vendor/lodepng-beef/lodepng-beef"}, FreeType = {Path = "GlitchyEngine/vendor/freetype"}, cgltf-beef = {Path = "GlitchyEngine/vendor/gltf/cgltf-beef"}, GlitchyEditor = {Path = "GlitchyEditor"}, msdfgen-beef = {Path = "GlitchyEngine/vendor/msdfgen/msdfgen-beef"}, ImGui = {Path = "GlitchyEngine/vendor/imgui/ImGui"}, ImGuiImplDX11 = {Path = "GlitchyEngine/vendor/imgui/ImGuiImplDX11"}, ImGuiImplWin32 = {Path = "GlitchyEngine/vendor/imgui/ImGuiImplWin32"}, ImGuizmo = {Path = "GlitchyEngine/vendor/imgui/ImGuizmo"}, GlitchyEngineHelper = {Path = "GlitchyEngineHelper"}, bon = {Path = "GlitchyEngine/vendor/bon"}, box2d-beef = {Path = "GlitchyEngine/vendor/box2D"}, "Beef.Linq" = {Path = "GlitchyEngine/vendor/Beef.Linq/src"}, ScriptCore = {Path = "ScriptCore"}, NetHostBeef = {Path = "GlitchyEngine/vendor/NetHostBeef/NetHostBeef"}}
|
||||||
Locked = ["ImGui"]
|
Locked = ["ImGui"]
|
||||||
WorkspaceFolders = {GlitchyEngine = ["GlitchyEngine", "GlitchLog", "GlitchyEngineHelper", "ScriptCore"], "GlitchyEngine/Dependencies" = ["cgltf-beef", "DirectX", "FreeType", "ImGui", "ImGuiImplDX11", "ImGuiImplWin32", "ImGuizmo", "LodePng", "msdfgen-beef", "bon", "box2d-beef", "Beef.Linq"], Beef = ["Beefy2D", "corlib", "MiniZ"]}
|
WorkspaceFolders = {GlitchyEngine = ["GlitchyEngine", "GlitchLog", "GlitchyEngineHelper", "ScriptCore"], "GlitchyEngine/Dependencies" = ["cgltf-beef", "DirectX", "FreeType", "ImGui", "ImGuiImplDX11", "ImGuiImplWin32", "ImGuizmo", "LodePng", "msdfgen-beef", "bon", "box2d-beef", "Beef.Linq", "NetHostBeef"], Beef = ["Beefy2D", "corlib", "MiniZ"]}
|
||||||
|
|
||||||
[Workspace]
|
[Workspace]
|
||||||
StartupProject = "GlitchyEditor"
|
StartupProject = "GlitchyEditor"
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ using GlitchyEditor.Platform.Windows;
|
|||||||
using GlitchyEditor.Multithreading;
|
using GlitchyEditor.Multithreading;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using GlitchyEditor.Platform;
|
using GlitchyEditor.Platform;
|
||||||
|
using System.Diagnostics;
|
||||||
|
|
||||||
namespace GlitchyEditor
|
namespace GlitchyEditor
|
||||||
{
|
{
|
||||||
@@ -25,6 +26,11 @@ namespace GlitchyEditor
|
|||||||
|
|
||||||
public this(String[] args)
|
public this(String[] args)
|
||||||
{
|
{
|
||||||
|
while(!Debug.IsDebuggerPresent)
|
||||||
|
{
|
||||||
|
Thread.Sleep(10);
|
||||||
|
}
|
||||||
|
|
||||||
Log.ClientLogger = new EditorLogger();
|
Log.ClientLogger = new EditorLogger();
|
||||||
Log.EngineLogger = new EditorLogger() { IsEngineLogger = true };
|
Log.EngineLogger = new EditorLogger() { IsEngineLogger = true };
|
||||||
|
|
||||||
|
|||||||
@@ -139,7 +139,7 @@ public class EditorLogger : Logger
|
|||||||
}
|
}
|
||||||
else if (args.Count > 0 && messageOrigin != null)
|
else if (args.Count > 0 && messageOrigin != null)
|
||||||
{
|
{
|
||||||
Editor.Instance.LogWindow.Log(timestamp, level, message, new .() {IsEngineMessage = IsEngineLogger, MessageOrigin = messageOrigin});
|
Editor.Instance.LogWindow.Log(timestamp, level, message, new .() {IsEngineMessage = IsEngineLogger, MessageOrigin = new MessageOrigin(messageOrigin.FileName, messageOrigin.LineNumber)});
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
FileVersion = 1
|
FileVersion = 1
|
||||||
Dependencies = {GlitchLog = "*", corlib = "*", DirectX = "*", FreeType = "*", cgltf-beef = "*", msdfgen-beef = "*", ImGui = "*", ImGuiImplDX11 = "*", ImGuiImplWin32 = "*", ImGuizmo = "*", Beefy2D = "*", LodePng = "*", GlitchyEngineHelper = "*", bon = "*", box2d-beef = "*", "Beef.Linq" = "*"}
|
Dependencies = {GlitchLog = "*", corlib = "*", DirectX = "*", FreeType = "*", cgltf-beef = "*", msdfgen-beef = "*", ImGui = "*", ImGuiImplDX11 = "*", ImGuiImplWin32 = "*", ImGuizmo = "*", Beefy2D = "*", LodePng = "*", GlitchyEngineHelper = "*", bon = "*", box2d-beef = "*", "Beef.Linq" = "*", NetHostBeef = "*"}
|
||||||
|
|
||||||
[Project]
|
[Project]
|
||||||
Name = "GlitchyEngine"
|
Name = "GlitchyEngine"
|
||||||
|
|||||||
@@ -0,0 +1,185 @@
|
|||||||
|
using NetHostBeef;
|
||||||
|
using System;
|
||||||
|
using System.Interop;
|
||||||
|
using GlitchyEngine.Core;
|
||||||
|
|
||||||
|
namespace GlitchyEngine.Scripting;
|
||||||
|
|
||||||
|
public struct ScriptFunctionPointers
|
||||||
|
{
|
||||||
|
public function void() OnCreate;
|
||||||
|
public function void(float) OnUpdate;
|
||||||
|
public function void() OnDestroy;
|
||||||
|
}
|
||||||
|
|
||||||
|
static class CoreClrHelper
|
||||||
|
{
|
||||||
|
static HostFxr.InitializeForDotnetCommandLineFn HostFxr_Init;
|
||||||
|
static HostFxr.GetRuntimeDelegateFn HostFxr_GetDelegate;
|
||||||
|
static HostFxr.CloseFn HostFxr_Close;
|
||||||
|
|
||||||
|
static CoreClr.LoadAssemblyAndGetFunctionPointerFn LoadAssemblyAndGetFunctionPointerFn;
|
||||||
|
static CoreClr.GetFunctionPointerFn GetFunctionPointerFn;
|
||||||
|
|
||||||
|
private function void LoadScriptAssemblyFunc(uint8* appData, int64 appLength, uint8* pdbData, int64 pdbLength);
|
||||||
|
|
||||||
|
//static function void(char8* path) LoadScriptAssembly;
|
||||||
|
static LoadScriptAssemblyFunc _loadScriptAssembly;
|
||||||
|
static function void() _unloadAssemblies;
|
||||||
|
|
||||||
|
// public static unsafe void GetScriptClasses(void** outBuffer, long* length)
|
||||||
|
private function void GetScriptClassesFunc(void** outBuffer, int64* length);
|
||||||
|
static GetScriptClassesFunc _getScriptClasses;
|
||||||
|
static function void() _freeScriptClassNames;
|
||||||
|
|
||||||
|
//public static unsafe ScriptFunctions CreateScriptInstance(UUID entityId, byte* scriptClassName)
|
||||||
|
private function void CreateScriptInstanceFunc(UUID entityId, char8* scriptClassName);
|
||||||
|
static CreateScriptInstanceFunc _createScriptInstance;
|
||||||
|
|
||||||
|
public static ScriptFunctionPointers _entityScriptFunctions;
|
||||||
|
|
||||||
|
public static void Init(StringView coreAssemblyPath)
|
||||||
|
{
|
||||||
|
LoadHostFxr();
|
||||||
|
InitAndStartRuntime(coreAssemblyPath);
|
||||||
|
|
||||||
|
PrepareFunction();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void LoadHostFxr()
|
||||||
|
{
|
||||||
|
char_t[256] buffer = ?;
|
||||||
|
c_size bufferSize = buffer.Count;
|
||||||
|
int rc = NetHost.get_hostfxr_path(&buffer, &bufferSize, null);
|
||||||
|
|
||||||
|
Log.EngineLogger.AssertDebug(rc == 0, "Failed to get HostFxr path.");
|
||||||
|
|
||||||
|
// Load hostfxr and get desired exports
|
||||||
|
void* lib = NetHostHelper.LoadLibrary(&buffer);
|
||||||
|
HostFxr_Init = NetHostHelper.GetExport<HostFxr.InitializeForDotnetCommandLineFn>(lib, "hostfxr_initialize_for_dotnet_command_line");
|
||||||
|
HostFxr_GetDelegate = NetHostHelper.GetExport<HostFxr.GetRuntimeDelegateFn>(lib, "hostfxr_get_runtime_delegate");
|
||||||
|
HostFxr_Close = NetHostHelper.GetExport<HostFxr.CloseFn>(lib, "hostfxr_close");
|
||||||
|
|
||||||
|
Log.EngineLogger.AssertDebug(HostFxr_Init != null && HostFxr_GetDelegate != null && HostFxr_Close != null, "Retrieving at least one HostFxr function failed.");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void InitAndStartRuntime(StringView coreAssembly)
|
||||||
|
{
|
||||||
|
char_t* ptr = NetHostHelper.GetScopedRawPtr!(coreAssembly);
|
||||||
|
|
||||||
|
char_t*[2] args = char_t*[](
|
||||||
|
ptr,
|
||||||
|
null
|
||||||
|
);
|
||||||
|
|
||||||
|
HostFxr.Handle cxt = null;
|
||||||
|
int rc = HostFxr_Init(1, &args, null, &cxt);
|
||||||
|
|
||||||
|
if (rc != 0 || cxt == null)
|
||||||
|
{
|
||||||
|
Log.EngineLogger.Error($"Failed to initialize HostFxr: {rc}");
|
||||||
|
HostFxr_Close(cxt);
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.EngineLogger.Assert(rc == 0, "Failed to initialize HostFxr.");
|
||||||
|
|
||||||
|
rc = HostFxr_GetDelegate(cxt, .LoadAssemblyAndGetFunctionPointer, (void**)&LoadAssemblyAndGetFunctionPointerFn);
|
||||||
|
|
||||||
|
Log.EngineLogger.Assert(rc == 0, scope $"Get delegate failed: {rc}. (LoadAssemblyAndGetFunctionPointer)");
|
||||||
|
|
||||||
|
rc = HostFxr_GetDelegate(cxt, .GetFunctionPointer, (void**)&GetFunctionPointerFn);
|
||||||
|
|
||||||
|
Log.EngineLogger.Assert(rc == 0, scope $"Get delegate failed: {rc}. (GetFunctionPointer)");
|
||||||
|
|
||||||
|
HostFxr_Close(cxt);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void PrepareFunction()
|
||||||
|
{
|
||||||
|
GetFunctionPointerUnmanagedCallersOnly("GlitchyEngine.ScriptGlue, ScriptCore", "LoadScriptAssembly", out _loadScriptAssembly);
|
||||||
|
|
||||||
|
GetFunctionPointerUnmanagedCallersOnly("GlitchyEngine.ScriptGlue, ScriptCore", "UnloadAssemblies", out _unloadAssemblies);
|
||||||
|
|
||||||
|
GetFunctionPointerUnmanagedCallersOnly("GlitchyEngine.ScriptGlue, ScriptCore", "GetScriptClasses", out _getScriptClasses);
|
||||||
|
|
||||||
|
GetFunctionPointerUnmanagedCallersOnly("GlitchyEngine.ScriptGlue, ScriptCore", "FreeScriptClassNames", out _freeScriptClassNames);
|
||||||
|
|
||||||
|
GetFunctionPointerUnmanagedCallersOnly("GlitchyEngine.ScriptGlue, ScriptCore", "CreateScriptInstance", out _createScriptInstance);
|
||||||
|
|
||||||
|
InitEntityFunctions();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void InitEntityFunctions()
|
||||||
|
{
|
||||||
|
GetFunctionPointerUnmanagedCallersOnly("GlitchyEngine.ScriptGlue, ScriptCore", "InvokeEntityOnCreate", out _entityScriptFunctions.OnCreate);
|
||||||
|
GetFunctionPointerUnmanagedCallersOnly("GlitchyEngine.ScriptGlue, ScriptCore", "InvokeEntityOnUpdate", out _entityScriptFunctions.OnUpdate);
|
||||||
|
GetFunctionPointerUnmanagedCallersOnly("GlitchyEngine.ScriptGlue, ScriptCore", "InvokeEntityOnDestroy", out _entityScriptFunctions.OnDestroy);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void LoadAppAssembly(Span<uint8> appAssemblyData, Span<uint8> pdbData)
|
||||||
|
{
|
||||||
|
_loadScriptAssembly(appAssemblyData.Ptr, appAssemblyData.Length, pdbData.Ptr, pdbData.Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void UnloadAssemblies()
|
||||||
|
{
|
||||||
|
_unloadAssemblies();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets an array of script class infos. Use FreeScriptClassNames to release the buffer.
|
||||||
|
public static void GetScriptClasses(out void* outBuffer, out int64 entryCount)
|
||||||
|
{
|
||||||
|
outBuffer = null;
|
||||||
|
entryCount = 0;
|
||||||
|
_getScriptClasses(&outBuffer, &entryCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Releases the buffer created by GetScriptClasses
|
||||||
|
public static void FreeScriptClassNames()
|
||||||
|
{
|
||||||
|
_freeScriptClassNames();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void CreateScriptInstance(UUID entityId, StringView scriptName)
|
||||||
|
{
|
||||||
|
_createScriptInstance(entityId, scriptName.Ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int GetFunctionPointer<T>(StringView typeName, StringView methodName, StringView delegateName, out T outDelegate) where T: operator explicit void*
|
||||||
|
{
|
||||||
|
void* funPtr = null;
|
||||||
|
|
||||||
|
int rc = GetFunctionPointerFn(NetHostHelper.GetScopedRawPtr!(typeName),
|
||||||
|
NetHostHelper.GetScopedRawPtr!(methodName), NetHostHelper.GetScopedRawPtr!(delegateName),
|
||||||
|
null, null, out funPtr);
|
||||||
|
|
||||||
|
outDelegate = (T)funPtr;
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int GetFunctionPointerDefaultDelegate(StringView typeName, StringView methodName, out CoreClr.DefaultEntryPoint outDelegate)
|
||||||
|
{
|
||||||
|
void* funPtr = null;
|
||||||
|
|
||||||
|
int rc = GetFunctionPointerFn(NetHostHelper.GetScopedRawPtr!(typeName),
|
||||||
|
NetHostHelper.GetScopedRawPtr!(methodName), null, null, null, out funPtr);
|
||||||
|
|
||||||
|
outDelegate = (CoreClr.DefaultEntryPoint)funPtr;
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int GetFunctionPointerUnmanagedCallersOnly<T>(StringView typeName, StringView methodName, out T outDelegate) where T: operator explicit void*
|
||||||
|
{
|
||||||
|
void* funPtr = null;
|
||||||
|
|
||||||
|
int rc = GetFunctionPointerFn(NetHostHelper.GetScopedRawPtr!(typeName),
|
||||||
|
NetHostHelper.GetScopedRawPtr!(methodName), CoreClr.UNMANAGEDCALLERSONLY_METHOD, null, null, out funPtr);
|
||||||
|
|
||||||
|
outDelegate = (T)funPtr;
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,37 +1,28 @@
|
|||||||
using System;
|
using System;
|
||||||
using Mono;
|
using Mono;
|
||||||
using GlitchyEngine.Core;
|
using GlitchyEngine.Core;
|
||||||
|
using System.Diagnostics;
|
||||||
|
|
||||||
namespace GlitchyEngine.Scripting;
|
namespace GlitchyEngine.Scripting;
|
||||||
|
|
||||||
using internal GlitchyEngine.Scripting;
|
using internal GlitchyEngine.Scripting;
|
||||||
|
|
||||||
class EntityEditorWrapper : ScriptClass
|
class EntityEditorWrapper : NewScriptClass
|
||||||
{
|
{
|
||||||
function void ShowEntityEditorFunc(MonoObject* scriptInstance, MonoException** exception);
|
function void ShowEntityEditorFunc(UUID entityId);
|
||||||
|
|
||||||
private ShowEntityEditorFunc _showEntityEditorFunc;
|
private ShowEntityEditorFunc _showEntityEditorFunc;
|
||||||
|
|
||||||
[AllowAppend]
|
[AllowAppend]
|
||||||
public this(StringView classNamespace, StringView className, MonoImage* image) : base(classNamespace, className, image)
|
public this() : base(FullName, .Empty, .None, false)
|
||||||
{
|
{
|
||||||
_showEntityEditorFunc = (ShowEntityEditorFunc)GetMethodThunk("ShowEntityEditor", 1);
|
CoreClrHelper.GetFunctionPointerUnmanagedCallersOnly("GlitchyEngine.ScriptGlue, ScriptCore", "ShowEntityEditor", out _showEntityEditorFunc);
|
||||||
|
|
||||||
if (_showEntityEditorFunc == null)
|
Debug.Assert(_showEntityEditorFunc != null);
|
||||||
{
|
|
||||||
Log.EngineLogger.Error("Entity editor has no show entity editor func.");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ShowEntityEditor(ScriptInstance instance, UUID entityId)
|
public void ShowEntityEditor(NewScriptInstance instance, UUID entityId)
|
||||||
{
|
{
|
||||||
MonoException* exception = null;
|
_showEntityEditorFunc(entityId);
|
||||||
|
|
||||||
_showEntityEditorFunc(instance.MonoInstance, &exception);
|
|
||||||
|
|
||||||
if (exception != null)
|
|
||||||
{
|
|
||||||
ScriptEngine.HandleMonoException(exception, entityId);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,98 @@
|
|||||||
|
using System;
|
||||||
|
using GlitchyEngine.Core;
|
||||||
|
using static GlitchyEngine.Scripting.ScriptEngine;
|
||||||
|
namespace GlitchyEngine.Scripting;
|
||||||
|
|
||||||
|
class NewScriptClass
|
||||||
|
{
|
||||||
|
public String FullName ~ delete _;
|
||||||
|
public StringView Name;
|
||||||
|
public Guid Guid;
|
||||||
|
public ScriptMethods Methods;
|
||||||
|
|
||||||
|
public bool RunInEditMode;
|
||||||
|
|
||||||
|
public this(StringView fullName, Guid guid, ScriptMethods methods, bool runInEditMode = false)
|
||||||
|
{
|
||||||
|
FullName = new String(fullName);
|
||||||
|
Guid = guid;
|
||||||
|
|
||||||
|
int lastDotIndex = FullName.LastIndexOf('.');
|
||||||
|
|
||||||
|
if (lastDotIndex == -1)
|
||||||
|
Name = FullName;
|
||||||
|
else
|
||||||
|
Name = FullName.Substring(lastDotIndex + 1);
|
||||||
|
|
||||||
|
Methods = methods;
|
||||||
|
|
||||||
|
RunInEditMode = runInEditMode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
using internal GlitchyEngine.Scripting;
|
||||||
|
|
||||||
|
class NewScriptInstance : RefCounter
|
||||||
|
{
|
||||||
|
private NewScriptClass _scriptClass;
|
||||||
|
|
||||||
|
private UUID _entityId;
|
||||||
|
|
||||||
|
private bool _isCreated = false;
|
||||||
|
|
||||||
|
public NewScriptClass ScriptClass => _scriptClass;
|
||||||
|
|
||||||
|
/// Gets whether or not the instance has ben initialized.
|
||||||
|
public bool IsInitialized {get; private set;};
|
||||||
|
|
||||||
|
/// Gets whether or not the Create-Method of this instance has been called before.
|
||||||
|
public bool IsCreated => _isCreated;
|
||||||
|
|
||||||
|
public UUID EntityId => _entityId;
|
||||||
|
|
||||||
|
public this(UUID entityId, NewScriptClass scriptClass)
|
||||||
|
{
|
||||||
|
Log.EngineLogger.AssertDebug(scriptClass != null);
|
||||||
|
|
||||||
|
_entityId = entityId;
|
||||||
|
_scriptClass = scriptClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ~this()
|
||||||
|
{
|
||||||
|
Destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Instantiate()
|
||||||
|
{
|
||||||
|
CoreClrHelper.CreateScriptInstance(_entityId, _scriptClass.FullName);
|
||||||
|
IsInitialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void InvokeOnCreate()
|
||||||
|
{
|
||||||
|
if (_scriptClass.Methods.HasFlag(.OnCreate))
|
||||||
|
CoreClrHelper._entityScriptFunctions.OnCreate();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void InvokeOnUpdate(float deltaTime)
|
||||||
|
{
|
||||||
|
if (_scriptClass.Methods.HasFlag(.OnUpdate))
|
||||||
|
CoreClrHelper._entityScriptFunctions.OnUpdate(deltaTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Destroy()
|
||||||
|
{
|
||||||
|
if (!IsInitialized)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (_scriptClass.Methods.HasFlag(.OnDestroy) && (ScriptEngine.ApplicationInfo.IsInPlayMode || ScriptClass.RunInEditMode))
|
||||||
|
{
|
||||||
|
CoreClrHelper._entityScriptFunctions.OnDestroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
IsInitialized = false;
|
||||||
|
|
||||||
|
ScriptEngine.UnregisterScriptInstance(_entityId);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -81,8 +81,8 @@ class ScriptClass : SharpClass
|
|||||||
// TODO: This is only relevant for the editor!
|
// TODO: This is only relevant for the editor!
|
||||||
MonoCustomAttrInfo* attributes = Mono.mono_custom_attrs_from_class(_monoClass);
|
MonoCustomAttrInfo* attributes = Mono.mono_custom_attrs_from_class(_monoClass);
|
||||||
|
|
||||||
if (attributes != null && ScriptEngine.Classes.RunInEditModeAttribute != null)
|
//if (attributes != null && ScriptEngine.Classes.RunInEditModeAttribute != null)
|
||||||
_runInEditMode = Mono.mono_custom_attrs_has_attr(attributes, ScriptEngine.Classes.RunInEditModeAttribute._monoClass);
|
// _runInEditMode = Mono.mono_custom_attrs_has_attr(attributes, ScriptEngine.Classes.RunInEditModeAttribute._monoClass);
|
||||||
}
|
}
|
||||||
|
|
||||||
private MonoMethod* FindConstructor()
|
private MonoMethod* FindConstructor()
|
||||||
@@ -148,8 +148,8 @@ class ScriptClass : SharpClass
|
|||||||
|
|
||||||
if (_onCollisionEnter2D != null)
|
if (_onCollisionEnter2D != null)
|
||||||
{
|
{
|
||||||
MonoObject* monoObject = ScriptEngine.Classes.Collision2D.BoxValue(collision);
|
//MonoObject* monoObject = ScriptEngine.Classes.Collision2D.BoxValue(collision);
|
||||||
_onCollisionEnter2D(instance, monoObject, &exception);
|
//_onCollisionEnter2D(instance, monoObject, &exception);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -159,8 +159,8 @@ class ScriptClass : SharpClass
|
|||||||
|
|
||||||
if (_onCollisionEnter2D != null)
|
if (_onCollisionEnter2D != null)
|
||||||
{
|
{
|
||||||
MonoObject* monoObject = ScriptEngine.Classes.Collision2D.BoxValue(collision);
|
//MonoObject* monoObject = ScriptEngine.Classes.Collision2D.BoxValue(collision);
|
||||||
_onCollisionLeave2D(instance, monoObject, &exception);
|
//_onCollisionLeave2D(instance, monoObject, &exception);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,30 +16,30 @@ class EngineClasses
|
|||||||
{
|
{
|
||||||
// TODO: Not all of these are actually ScriptClasses (actually none of them are...)
|
// TODO: Not all of these are actually ScriptClasses (actually none of them are...)
|
||||||
|
|
||||||
private ScriptClass s_ComponentRoot;
|
private NewScriptClass s_EngineObject;
|
||||||
private ScriptClass s_EntityRoot;
|
private NewScriptClass s_ComponentRoot;
|
||||||
private ScriptClass s_EngineObject;
|
private NewScriptClass s_EntityRoot;
|
||||||
|
|
||||||
private EntityEditorWrapper s_EntityEditor;
|
private EntityEditorWrapper s_EntityEditor;
|
||||||
|
|
||||||
private EntitySerializerWrapper s_EntitySerializer;
|
private EntitySerializerWrapper s_EntitySerializer;
|
||||||
private ScriptClass s_SerializationContext;
|
//private NewScriptClass s_SerializationContext;
|
||||||
|
|
||||||
private ScriptClass s_Collision2D;
|
private NewScriptClass s_Collision2D;
|
||||||
|
|
||||||
private ScriptClass s_RunInEditModeAttribute;
|
private NewScriptClass s_RunInEditModeAttribute;
|
||||||
|
|
||||||
public ScriptClass ComponentRoot => s_ComponentRoot;
|
public NewScriptClass EngineObject => s_EngineObject;
|
||||||
public ScriptClass EntityRoot => s_EntityRoot;
|
public NewScriptClass ComponentRoot => s_ComponentRoot;
|
||||||
public ScriptClass EngineObject => s_EngineObject;
|
public NewScriptClass EntityRoot => s_EntityRoot;
|
||||||
|
|
||||||
public EntityEditorWrapper EntityEditor => s_EntityEditor;
|
public EntityEditorWrapper EntityEditor => s_EntityEditor;
|
||||||
|
|
||||||
public EntitySerializerWrapper EntitySerializer => s_EntitySerializer;
|
public EntitySerializerWrapper EntitySerializer => s_EntitySerializer;
|
||||||
|
|
||||||
public ScriptClass Collision2D => s_Collision2D;
|
public NewScriptClass Collision2D => s_Collision2D;
|
||||||
|
|
||||||
public ScriptClass RunInEditModeAttribute => s_RunInEditModeAttribute;
|
public NewScriptClass RunInEditModeAttribute => s_RunInEditModeAttribute;
|
||||||
|
|
||||||
public ~this()
|
public ~this()
|
||||||
{
|
{
|
||||||
@@ -48,37 +48,37 @@ class EngineClasses
|
|||||||
|
|
||||||
internal void ReleaseAndNullify()
|
internal void ReleaseAndNullify()
|
||||||
{
|
{
|
||||||
ReleaseRefAndNullify!(s_EngineObject);
|
DeleteAndNullify!(s_EngineObject);
|
||||||
ReleaseRefAndNullify!(s_EntityRoot);
|
DeleteAndNullify!(s_EntityRoot);
|
||||||
ReleaseRefAndNullify!(s_ComponentRoot);
|
DeleteAndNullify!(s_ComponentRoot);
|
||||||
|
|
||||||
ReleaseRefAndNullify!(s_EntityEditor);
|
DeleteAndNullify!(s_EntityEditor);
|
||||||
|
|
||||||
ReleaseRefAndNullify!(s_EntitySerializer);
|
ReleaseRefAndNullify!(s_EntitySerializer);
|
||||||
ReleaseRefAndNullify!(s_SerializationContext);
|
//ReleaseRefAndNullify!(s_SerializationContext);
|
||||||
|
|
||||||
ReleaseRefAndNullify!(s_Collision2D);
|
DeleteAndNullify!(s_Collision2D);
|
||||||
|
|
||||||
ReleaseRefAndNullify!(s_RunInEditModeAttribute);
|
DeleteAndNullify!(s_RunInEditModeAttribute);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void LoadClasses(MonoImage* image)
|
internal void LoadClasses()
|
||||||
{
|
{
|
||||||
ReleaseAndNullify();
|
ReleaseAndNullify();
|
||||||
|
|
||||||
s_EngineObject = new ScriptClass("GlitchyEngine.Core", "EngineObject", image);
|
s_EngineObject = new NewScriptClass("GlitchyEngine.Core.EngineObject", .Empty, .None);
|
||||||
s_EntityRoot = new ScriptClass("GlitchyEngine", "Entity", image);
|
s_EntityRoot = new NewScriptClass("GlitchyEngine.Core.Entity", .Empty, .None);
|
||||||
s_ComponentRoot = new ScriptClass("GlitchyEngine.Core", "Component", image);
|
s_ComponentRoot = new NewScriptClass("GlitchyEngine.Core.Component", .Empty, .None);
|
||||||
|
|
||||||
// Editor classes
|
// Editor classes
|
||||||
s_EntityEditor = new EntityEditorWrapper("GlitchyEngine.Editor", "EntityEditor", image);
|
s_EntityEditor = new EntityEditorWrapper();
|
||||||
|
|
||||||
s_EntitySerializer = new EntitySerializerWrapper("GlitchyEngine.Serialization", "EntitySerializer", image);
|
//s_EntitySerializer = new EntitySerializerWrapper("GlitchyEngine.Serialization", "EntitySerializer");
|
||||||
|
|
||||||
s_Collision2D = new ScriptClass("GlitchyEngine.Physics", "Collision2D", image);
|
s_Collision2D = new NewScriptClass("GlitchyEngine.Physics.Collision2D", .Empty, .None);
|
||||||
|
|
||||||
// Attributes
|
// Attributes
|
||||||
s_RunInEditModeAttribute = new ScriptClass("GlitchyEngine.Editor", "RunInEditModeAttribute", image);
|
s_RunInEditModeAttribute = new NewScriptClass("GlitchyEngine.Editor.RunInEditModeAttribute", .Empty, .None);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -99,9 +99,9 @@ static class ScriptEngine
|
|||||||
|
|
||||||
public static EngineClasses Classes => _classes;
|
public static EngineClasses Classes => _classes;
|
||||||
|
|
||||||
private static Dictionary<StringView, ScriptClass> _entityScripts = new .() ~ DeleteDictionaryAndReleaseValues!(_);
|
private static Dictionary<StringView, NewScriptClass> _entityScripts = new .() ~ DeleteDictionaryAndValues!(_);
|
||||||
|
|
||||||
internal static Dictionary<UUID, ScriptInstance> _entityScriptInstances = new .() ~ {
|
internal static Dictionary<UUID, NewScriptInstance> _entityScriptInstances = new .() ~ {
|
||||||
for (var entry in _)
|
for (var entry in _)
|
||||||
{
|
{
|
||||||
entry.value?.ReleaseRef();
|
entry.value?.ReleaseRef();
|
||||||
@@ -109,7 +109,7 @@ static class ScriptEngine
|
|||||||
delete _;
|
delete _;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Dictionary<StringView, ScriptClass> EntityClasses => _entityScripts;
|
public static Dictionary<StringView, NewScriptClass> EntityClasses => _entityScripts;
|
||||||
|
|
||||||
/// Gets or sets the current scene context for the runtime.
|
/// Gets or sets the current scene context for the runtime.
|
||||||
public static Scene Context
|
public static Scene Context
|
||||||
@@ -189,7 +189,8 @@ static class ScriptEngine
|
|||||||
|
|
||||||
public static void Init()
|
public static void Init()
|
||||||
{
|
{
|
||||||
InitMono();
|
InitRuntime();
|
||||||
|
//InitMono();
|
||||||
|
|
||||||
LoadScriptAssemblies();
|
LoadScriptAssemblies();
|
||||||
}
|
}
|
||||||
@@ -202,7 +203,17 @@ static class ScriptEngine
|
|||||||
ReloadAssemblies();
|
ReloadAssemblies();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void InitMono()
|
static void InitRuntime()
|
||||||
|
{
|
||||||
|
// TODO: We currently have the utility methods (e.g. assembly loading) in ScriptCore,
|
||||||
|
// the problem is, that CoreCLR currently can't unload the initial assembly.
|
||||||
|
// this means that we cannot easily reload changes to ScriptCore.
|
||||||
|
// Since this basic infrastructure shouldn't really ever change we could make a tiny
|
||||||
|
// library with only that enabling us to reload script core.
|
||||||
|
CoreClrHelper.Init("resources/scripts/ScriptCore.dll");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*static void InitMono()
|
||||||
{
|
{
|
||||||
Mono.mono_set_assemblies_path("mono/lib/4.5");
|
Mono.mono_set_assemblies_path("mono/lib/4.5");
|
||||||
|
|
||||||
@@ -226,7 +237,7 @@ static class ScriptEngine
|
|||||||
}
|
}
|
||||||
|
|
||||||
Mono.mono_thread_set_main(Mono.mono_thread_current());
|
Mono.mono_thread_set_main(Mono.mono_thread_current());
|
||||||
}
|
}*/
|
||||||
|
|
||||||
static bool _requestingReload = false;
|
static bool _requestingReload = false;
|
||||||
|
|
||||||
@@ -278,26 +289,27 @@ static class ScriptEngine
|
|||||||
|
|
||||||
ScriptGlue.Init();
|
ScriptGlue.Init();
|
||||||
|
|
||||||
CreateAppDomain("GlitchyEngineScriptRuntime");
|
// TODO: Check if files exist
|
||||||
(s_CoreAssembly, s_CoreAssemblyImage) = LoadAssembly("resources/scripts/ScriptCore.dll", _debuggingEnabled);
|
|
||||||
|
|
||||||
if (File.Exists(_appAssemblyPath))
|
if (File.Exists(_appAssemblyPath))
|
||||||
(s_AppAssembly, s_AppAssemblyImage) = LoadAssembly(_appAssemblyPath, _debuggingEnabled);
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
s_AppAssembly = null;
|
List<uint8> data = new:ScopedAlloc! List<uint8>(1024);
|
||||||
s_AppAssemblyImage = null;
|
File.ReadAll(_appAssemblyPath, data);
|
||||||
}
|
|
||||||
|
|
||||||
Classes.LoadClasses(s_CoreAssemblyImage);
|
List<uint8> pdbData = new:ScopedAlloc! List<uint8>(1024);
|
||||||
|
|
||||||
ClearDictionaryAndReleaseValues!(_entityScripts);
|
String pdbPath = scope .();
|
||||||
|
Path.ChangeExtension(_appAssemblyPath, ".pdb", pdbPath);
|
||||||
|
|
||||||
|
File.ReadAll(pdbPath, pdbData);
|
||||||
|
|
||||||
|
CoreClrHelper.LoadAppAssembly(data, pdbData);
|
||||||
|
|
||||||
GetEntitiesFromAssemblies();
|
GetEntitiesFromAssemblies();
|
||||||
|
|
||||||
ScriptGlue.RegisterManagedComponents();
|
//ScriptGlue.RegisterManagedComponents();
|
||||||
|
}
|
||||||
|
|
||||||
InitAssemblyWatcher();
|
//InitAssemblyWatcher();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Starts the script runtime and sets the context scene.
|
/// Starts the script runtime and sets the context scene.
|
||||||
@@ -338,14 +350,16 @@ static class ScriptEngine
|
|||||||
/// Disposes of and replaces the old instance, if one exists.
|
/// Disposes of and replaces the old instance, if one exists.
|
||||||
public static bool InitializeInstance(Entity entity, ScriptComponent* script)
|
public static bool InitializeInstance(Entity entity, ScriptComponent* script)
|
||||||
{
|
{
|
||||||
ScriptClass scriptClass = GetScriptClass(script.ScriptClassName);
|
Log.EngineLogger.Error($"{Compiler.CallerMemberName} not updated yet.");
|
||||||
|
|
||||||
|
NewScriptClass scriptClass = GetScriptClass(script.ScriptClassName);
|
||||||
|
|
||||||
if (scriptClass == null)
|
if (scriptClass == null)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
UUID entityId = entity.UUID;
|
UUID entityId = entity.UUID;
|
||||||
|
|
||||||
script.Instance = new ScriptInstance(entityId, scriptClass);
|
script.Instance = new NewScriptInstance(entityId, scriptClass);
|
||||||
script.Instance..ReleaseRef();
|
script.Instance..ReleaseRef();
|
||||||
|
|
||||||
if (_entityScriptInstances.TryGetValue(entityId, let currentInstance))
|
if (_entityScriptInstances.TryGetValue(entityId, let currentInstance))
|
||||||
@@ -353,7 +367,7 @@ static class ScriptEngine
|
|||||||
|
|
||||||
_entityScriptInstances[entityId] = script.Instance..AddRef();
|
_entityScriptInstances[entityId] = script.Instance..AddRef();
|
||||||
|
|
||||||
script.Instance.Instantiate(entityId);
|
script.Instance.Instantiate();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -381,109 +395,50 @@ static class ScriptEngine
|
|||||||
_entityScriptInstances.Remove(entityId);
|
_entityScriptInstances.Remove(entityId);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static MonoAssembly* LoadCSharpAssembly(StringView assemblyPath, bool loadPDB = false)
|
public enum ScriptMethods : uint32
|
||||||
{
|
{
|
||||||
Debug.Profiler.ProfileFunction!();
|
None = 0,
|
||||||
|
OnCreate = 0x1,
|
||||||
List<uint8> data = new List<uint8>(1024);
|
OnUpdate = 0x2,
|
||||||
|
OnDestroy = 0x4,
|
||||||
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);
|
|
||||||
|
|
||||||
Log.EngineLogger.Error($"Failed to load C# Assembly: \"{StringView(errorMessage)}\"");
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (loadPDB)
|
struct ScriptClassInfo
|
||||||
{
|
{
|
||||||
String pdbPath = scope .();
|
public char8* Name;
|
||||||
Path.ChangeExtension(assemblyPath, ".pdb", pdbPath);
|
public Guid Guid;
|
||||||
|
public ScriptMethods Methods;
|
||||||
if (File.Exists(pdbPath))
|
public bool RunInEditMode;
|
||||||
{
|
|
||||||
Log.EngineLogger.Trace($"Loading PDB \"{pdbPath}\"...");
|
|
||||||
|
|
||||||
List<uint8> pdbData = new List<uint8>(1024);
|
|
||||||
|
|
||||||
let result = File.ReadAll(pdbPath, pdbData);
|
|
||||||
|
|
||||||
if (result case .Err(let error))
|
|
||||||
{
|
|
||||||
Log.EngineLogger.Error("Failed to load PDB file ({error}).");
|
|
||||||
}
|
|
||||||
|
|
||||||
Mono.mono_debug_open_image_from_memory(image, pdbData.Ptr, (int32)pdbData.Count);
|
|
||||||
|
|
||||||
delete pdbData;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Log.EngineLogger.Warning($"Debugging enabled but no PDB-File found \"{assemblyPath}\".");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
MonoAssembly* assembly = Mono.mono_assembly_load_from_full(image, assemblyPath.ToScopeCStr!(), &status, 0);
|
|
||||||
|
|
||||||
Mono.mono_image_close(image);
|
|
||||||
|
|
||||||
return assembly;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void CreateAppDomain(StringView name)
|
|
||||||
{
|
|
||||||
s_AppDomain = Mono.mono_domain_create_appdomain(name.ToScopeCStr!(), null);
|
|
||||||
Mono.mono_domain_set(s_AppDomain, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
static (MonoAssembly* assembly, MonoImage* image) LoadAssembly(StringView filepath, bool loadPDB = false)
|
|
||||||
{
|
|
||||||
Debug.Profiler.ProfileFunction!();
|
|
||||||
|
|
||||||
MonoAssembly* assembly = LoadCSharpAssembly(filepath, loadPDB);
|
|
||||||
MonoImage* image = Mono.mono_assembly_get_image(assembly);
|
|
||||||
|
|
||||||
return (assembly, image);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void GetEntitiesFromAssemblies()
|
private static void GetEntitiesFromAssemblies()
|
||||||
{
|
{
|
||||||
Debug.Profiler.ProfileFunction!();
|
Debug.Profiler.ProfileFunction!();
|
||||||
|
|
||||||
if (s_AppAssemblyImage == null)
|
// TODO: We should probably verify, that all required types actually exist.
|
||||||
return;
|
Classes.LoadClasses();
|
||||||
|
|
||||||
MonoTableInfo* typeDefinitionsTable = Mono.mono_image_get_table_info(s_AppAssemblyImage, .MONO_TABLE_TYPEDEF);
|
CoreClrHelper.GetScriptClasses(let data, let entryCount);
|
||||||
int32 numTypes = Mono.mono_table_info_get_rows(typeDefinitionsTable);
|
|
||||||
|
|
||||||
for (int32 i = 0; i < numTypes; i++)
|
Span<ScriptClassInfo> scriptClasses = .((.)data, entryCount);
|
||||||
|
|
||||||
|
List<NewScriptClass> newClasses = scope .();
|
||||||
|
|
||||||
|
ClearDictionaryAndDeleteValues!(_entityScripts);
|
||||||
|
|
||||||
|
for (var entry in scriptClasses)
|
||||||
{
|
{
|
||||||
int32[(.)SOME_RANDOM_ENUM.MONO_TYPEDEF_SIZE] cols = .();
|
NewScriptClass scriptClass = new .(StringView(entry.Name), entry.Guid, entry.Methods, entry.RunInEditMode);
|
||||||
Mono.mono_metadata_decode_row(typeDefinitionsTable, i, (.)&cols, (.)SOME_RANDOM_ENUM.MONO_TYPEDEF_SIZE);
|
|
||||||
|
|
||||||
char8* nameSpace = Mono.mono_metadata_string_heap(s_AppAssemblyImage, (.)cols[(.)SOME_RANDOM_ENUM.MONO_TYPEDEF_NAMESPACE]);
|
newClasses.Add(scriptClass);
|
||||||
char8* name = Mono.mono_metadata_string_heap(s_AppAssemblyImage, (.)cols[(.)SOME_RANDOM_ENUM.MONO_TYPEDEF_NAME]);
|
}
|
||||||
|
|
||||||
MonoClass* monoClass = Mono.mono_class_from_name(s_AppAssemblyImage, nameSpace, name);
|
for (var scriptClass in newClasses)
|
||||||
|
|
||||||
// Check if it is an entity
|
|
||||||
if (monoClass != null && Mono.mono_class_is_subclass_of(monoClass, Classes.EntityRoot.[Friend]_monoClass, false))
|
|
||||||
{
|
{
|
||||||
ScriptClass entityScript = new ScriptClass(StringView(nameSpace), StringView(name), s_AppAssemblyImage);
|
_entityScripts.Add(scriptClass.FullName, scriptClass);
|
||||||
_entityScripts.Add(entityScript.FullName, entityScript);
|
}
|
||||||
|
|
||||||
Log.EngineLogger.Info($"Added entity \"{entityScript.FullName}\"");
|
CoreClrHelper.FreeScriptClassNames();
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void ReloadAssemblies()
|
public static void ReloadAssemblies()
|
||||||
@@ -492,20 +447,20 @@ static class ScriptEngine
|
|||||||
|
|
||||||
Log.EngineLogger.Info("Reloading script assemblies.");
|
Log.EngineLogger.Info("Reloading script assemblies.");
|
||||||
|
|
||||||
|
|
||||||
ScriptInstanceSerializer contextSerializer = scope .();
|
ScriptInstanceSerializer contextSerializer = scope .();
|
||||||
|
|
||||||
contextSerializer.SerializeScriptInstances();
|
contextSerializer.SerializeScriptInstances();
|
||||||
|
|
||||||
Mono.mono_domain_set(s_RootDomain, true);
|
// TODO: Unload script assemblies, remove class handles, fire unload events?
|
||||||
|
|
||||||
Mono.mono_domain_unload(s_AppDomain);
|
|
||||||
|
|
||||||
LoadScriptAssemblies();
|
LoadScriptAssemblies();
|
||||||
|
|
||||||
{
|
{
|
||||||
Debug.Profiler.ProfileScope!("Initialize Instances");
|
Debug.Profiler.ProfileScope!("Initialize Instances");
|
||||||
|
|
||||||
// We need to create a new instance for every entity
|
Log.EngineLogger.Error("Recreating and copying instances (ReloadAssemblies) not updated yet.");
|
||||||
|
/*// We need to create a new instance for every entity
|
||||||
for (let (id, scriptInstance) in _entityScriptInstances)
|
for (let (id, scriptInstance) in _entityScriptInstances)
|
||||||
{
|
{
|
||||||
if (Context.GetEntityByID(id) case .Ok(let entity))
|
if (Context.GetEntityByID(id) case .Ok(let entity))
|
||||||
@@ -517,7 +472,7 @@ static class ScriptEngine
|
|||||||
{
|
{
|
||||||
Log.EngineLogger.AssertDebug(false, "Entities script was just serialized but the entity doesn't exist anymore.");
|
Log.EngineLogger.AssertDebug(false, "Entities script was just serialized but the entity doesn't exist anymore.");
|
||||||
}
|
}
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
contextSerializer.DeserializeScriptInstances();
|
contextSerializer.DeserializeScriptInstances();
|
||||||
@@ -527,25 +482,25 @@ static class ScriptEngine
|
|||||||
|
|
||||||
public static void Shutdown()
|
public static void Shutdown()
|
||||||
{
|
{
|
||||||
Mono.mono_domain_set(s_RootDomain, false);
|
/*Mono.mono_domain_set(s_RootDomain, false);
|
||||||
|
|
||||||
Mono.mono_domain_unload(s_AppDomain);
|
Mono.mono_domain_unload(s_AppDomain);
|
||||||
s_AppDomain = null;
|
s_AppDomain = null;
|
||||||
|
|
||||||
Mono.mono_jit_cleanup(s_RootDomain);
|
Mono.mono_jit_cleanup(s_RootDomain);
|
||||||
s_RootDomain = null;
|
s_RootDomain = null;*/
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the script instance or null.
|
/// Returns the script instance or null.
|
||||||
public static MonoObject* GetManagedInstance(UUID entityId)
|
public static MonoObject* GetManagedInstance(UUID entityId)
|
||||||
{
|
{
|
||||||
if (_entityScriptInstances.TryGetValue(entityId, let scriptInstance))
|
//if (_entityScriptInstances.TryGetValue(entityId, let scriptInstance))
|
||||||
return scriptInstance.MonoInstance;
|
// return scriptInstance.MonoInstance;
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ScriptClass GetScriptClass(StringView name)
|
public static NewScriptClass GetScriptClass(StringView name)
|
||||||
{
|
{
|
||||||
EntityClasses.TryGetValue(name, let scriptClass);
|
EntityClasses.TryGetValue(name, let scriptClass);
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,10 @@ using GlitchyEngine.Editor;
|
|||||||
using GlitchyEngine.World.Components;
|
using GlitchyEngine.World.Components;
|
||||||
using GlitchyEngine.Content;
|
using GlitchyEngine.Content;
|
||||||
using GlitchyEngine.Renderer;
|
using GlitchyEngine.Renderer;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.IO;
|
||||||
using static GlitchyEngine.Renderer.Text.FontRenderer;
|
using static GlitchyEngine.Renderer.Text.FontRenderer;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
namespace GlitchyEngine.Scripting;
|
namespace GlitchyEngine.Scripting;
|
||||||
|
|
||||||
@@ -39,12 +42,6 @@ class MessageOrigin
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static class ScriptGlue
|
|
||||||
{
|
|
||||||
private static Dictionary<MonoType*, function void(Entity entityId)> s_AddComponentMethods = new .() ~ delete _;
|
|
||||||
private static Dictionary<MonoType*, function bool(Entity entityId)> s_HasComponentMethods = new .() ~ delete _;
|
|
||||||
private static Dictionary<MonoType*, function void(Entity entityId)> s_RemoveComponentMethods = new .() ~ delete _;
|
|
||||||
|
|
||||||
struct RegisterCallAttribute : Attribute
|
struct RegisterCallAttribute : Attribute
|
||||||
{
|
{
|
||||||
public String MethodName;
|
public String MethodName;
|
||||||
@@ -55,6 +52,240 @@ static class ScriptGlue
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct TypeTranslationTemplate
|
||||||
|
{
|
||||||
|
public String StartCode;
|
||||||
|
public String EndCode;
|
||||||
|
public String PrettyCSharpParamType;
|
||||||
|
|
||||||
|
public this(String startCode, String endCode, String prettyCSharpParamType)
|
||||||
|
{
|
||||||
|
StartCode = startCode;
|
||||||
|
EndCode = endCode;
|
||||||
|
PrettyCSharpParamType = prettyCSharpParamType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[AttributeUsage(.Struct)]
|
||||||
|
struct EngineFunctionsGeneratorAttribute : Attribute, IComptimeTypeApply
|
||||||
|
{
|
||||||
|
private static readonly Dictionary<String, String> BeefToCsharpTypeMap = new .()
|
||||||
|
{
|
||||||
|
("int32", "int"),
|
||||||
|
("char16*", "char*"),
|
||||||
|
("char8*", "byte*"),
|
||||||
|
("GlitchyEngine.Events.MouseButton", "GlitchyEngine.MouseButton")
|
||||||
|
};
|
||||||
|
|
||||||
|
// {0}... Out name,
|
||||||
|
// {1}... In name
|
||||||
|
private static readonly Dictionary<String, TypeTranslationTemplate> BeefTypeToCSharpWrapperTemplate = new .()
|
||||||
|
{
|
||||||
|
("char8*", .("byte* {0} = (byte*)Marshal.StringToCoTaskMemUTF8({1});", "Marshal.FreeCoTaskMem((IntPtr){0});", "string")),
|
||||||
|
("char16*", .("fixed (char* {0} = {1})\n{{", "}}", "string")),
|
||||||
|
};
|
||||||
|
|
||||||
|
private static readonly Dictionary<String, TypeTranslationTemplate> CSharpTypeToReturnValueTemplate = new .()
|
||||||
|
{
|
||||||
|
("void", .("", "", "void")),
|
||||||
|
};
|
||||||
|
|
||||||
|
private static String GetCSharpInterfaceType(String beefType)
|
||||||
|
{
|
||||||
|
if (BeefToCsharpTypeMap.TryGetValueAlt(beefType, let csharpType))
|
||||||
|
{
|
||||||
|
return csharpType;
|
||||||
|
}
|
||||||
|
|
||||||
|
return beefType;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static TypeTranslationTemplate GetCSharpWrapperTemplate(String beefType)
|
||||||
|
{
|
||||||
|
if (BeefTypeToCSharpWrapperTemplate.TryGetValueAlt(beefType, let template))
|
||||||
|
{
|
||||||
|
return template;
|
||||||
|
}
|
||||||
|
|
||||||
|
return .("", "", GetCSharpInterfaceType(beefType));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static TypeTranslationTemplate GetCSharpReturnValueTemplate(String beefType)
|
||||||
|
{
|
||||||
|
if (CSharpTypeToReturnValueTemplate.TryGetValueAlt(beefType, let template))
|
||||||
|
{
|
||||||
|
return template;
|
||||||
|
}
|
||||||
|
|
||||||
|
return .("var returnValue = ", "return returnValue;", GetCSharpInterfaceType(beefType));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void GenerateCSharpFunctionPointer(MethodInfo method, String outString)
|
||||||
|
{
|
||||||
|
String parameters = new String();
|
||||||
|
|
||||||
|
for (int i < method.ParamCount)
|
||||||
|
{
|
||||||
|
if (i != 0)
|
||||||
|
parameters.Append(", ");
|
||||||
|
|
||||||
|
String typeHolder = scope String();
|
||||||
|
|
||||||
|
method.GetParamType(i).ToString(typeHolder);
|
||||||
|
|
||||||
|
StringView csharpType = GetCSharpInterfaceType(typeHolder);
|
||||||
|
|
||||||
|
parameters.AppendF($"{csharpType}");
|
||||||
|
}
|
||||||
|
|
||||||
|
String csharpFunctionPointer = scope $" public delegate* unmanaged[Cdecl]<{parameters}{(parameters.IsEmpty ? "" : ", ")}{method.ReturnType}> {method.Name};\n";
|
||||||
|
outString.Append(csharpFunctionPointer);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void GenerateCSharpWrapperMethod(MethodInfo method, String outString)
|
||||||
|
{
|
||||||
|
String wrapperParameters = new .();
|
||||||
|
|
||||||
|
String callArguments = new .();
|
||||||
|
|
||||||
|
String translation = new .();
|
||||||
|
String cleanup = new .();
|
||||||
|
|
||||||
|
for (int i < method.ParamCount)
|
||||||
|
{
|
||||||
|
String beefParameterType = scope String();
|
||||||
|
method.GetParamType(i).ToString(beefParameterType);
|
||||||
|
|
||||||
|
TypeTranslationTemplate template = GetCSharpWrapperTemplate(beefParameterType);
|
||||||
|
|
||||||
|
StringView paramName = method.GetParamName(i);
|
||||||
|
|
||||||
|
// Generate the parameter for the wrapper head.
|
||||||
|
{
|
||||||
|
if (i != 0)
|
||||||
|
wrapperParameters.Append(", ");
|
||||||
|
|
||||||
|
wrapperParameters.AppendF($"{template.PrettyCSharpParamType} {paramName}");
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
if (i != 0)
|
||||||
|
callArguments.Append(", ");
|
||||||
|
|
||||||
|
String translatedParamName = new String(paramName);
|
||||||
|
|
||||||
|
if (!template.StartCode.IsEmpty)
|
||||||
|
{
|
||||||
|
translatedParamName.Append("Converted");
|
||||||
|
|
||||||
|
callArguments.AppendF($"{translatedParamName}");
|
||||||
|
|
||||||
|
translation.AppendF(template.StartCode, translatedParamName, paramName);
|
||||||
|
translation.Append('\n');
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
callArguments.AppendF($"{paramName}");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!template.EndCode.IsEmpty)
|
||||||
|
{
|
||||||
|
cleanup.AppendF(template.EndCode, translatedParamName, paramName);
|
||||||
|
cleanup.Append('\n');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String returnTypeName = new .();
|
||||||
|
method.ReturnType.ToString(returnTypeName);
|
||||||
|
String csharpReturnType = GetCSharpInterfaceType(returnTypeName);
|
||||||
|
TypeTranslationTemplate template = GetCSharpReturnValueTemplate(csharpReturnType);
|
||||||
|
|
||||||
|
outString.AppendF($"""
|
||||||
|
internal static unsafe {template.PrettyCSharpParamType} NEW_{method.Name}({wrapperParameters})
|
||||||
|
{{
|
||||||
|
{translation}
|
||||||
|
{template.StartCode}_engineFunctions.{method.Name}({callArguments});
|
||||||
|
|
||||||
|
{cleanup}
|
||||||
|
{template.EndCode}
|
||||||
|
}}
|
||||||
|
|
||||||
|
|
||||||
|
""");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Comptime]
|
||||||
|
public void ApplyToType(Type self)
|
||||||
|
{
|
||||||
|
String csharpEngineFunctionsStruct = new String("""
|
||||||
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using GlitchyEngine;
|
||||||
|
using GlitchyEngine.Core;
|
||||||
|
|
||||||
|
namespace GlitchyEngine;
|
||||||
|
|
||||||
|
internal unsafe partial struct EngineFunctions
|
||||||
|
{
|
||||||
|
|
||||||
|
""");
|
||||||
|
|
||||||
|
String csharpScriptGlue = new String("""
|
||||||
|
|
||||||
|
|
||||||
|
internal static partial class ScriptGlue
|
||||||
|
{
|
||||||
|
|
||||||
|
""");
|
||||||
|
|
||||||
|
for (MethodInfo methodInfo in typeof(ScriptGlue).GetMethods(.Static | .NonPublic))
|
||||||
|
{
|
||||||
|
if (methodInfo.GetCustomAttribute<RegisterCallAttribute>() case .Ok(let attribute))
|
||||||
|
{
|
||||||
|
String parameters = new String();
|
||||||
|
|
||||||
|
for (int i < methodInfo.ParamCount)
|
||||||
|
{
|
||||||
|
if (i != 0)
|
||||||
|
parameters.Append(", ");
|
||||||
|
|
||||||
|
parameters.AppendF($"{methodInfo.GetParamType(i)}");
|
||||||
|
}
|
||||||
|
|
||||||
|
String line = scope $"public function {methodInfo.ReturnType}({parameters}) {methodInfo.Name};\n";
|
||||||
|
|
||||||
|
Compiler.EmitTypeBody(self, line);
|
||||||
|
|
||||||
|
GenerateCSharpFunctionPointer(methodInfo, csharpEngineFunctionsStruct);
|
||||||
|
|
||||||
|
GenerateCSharpWrapperMethod(methodInfo, csharpScriptGlue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
csharpEngineFunctionsStruct.Append('}');
|
||||||
|
csharpScriptGlue.Append('}');
|
||||||
|
|
||||||
|
csharpEngineFunctionsStruct.Append(csharpScriptGlue);
|
||||||
|
|
||||||
|
if (File.WriteAllText("../ScriptCore/ScriptGlue.gen.cs", csharpEngineFunctionsStruct) case .Err)
|
||||||
|
{
|
||||||
|
Runtime.FatalError("Failed to write file");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[EngineFunctionsGenerator]
|
||||||
|
struct EngineFunctions
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static class ScriptGlue
|
||||||
|
{
|
||||||
|
private static Dictionary<MonoType*, function void(Entity entityId)> s_AddComponentMethods = new .() ~ delete _;
|
||||||
|
private static Dictionary<MonoType*, function bool(Entity entityId)> s_HasComponentMethods = new .() ~ delete _;
|
||||||
|
private static Dictionary<MonoType*, function void(Entity entityId)> s_RemoveComponentMethods = new .() ~ delete _;
|
||||||
|
|
||||||
/* Adding this attribute to a method will log method entry and returned Result<T> errors */
|
/* Adding this attribute to a method will log method entry and returned Result<T> errors */
|
||||||
[AttributeUsage(.Method)]
|
[AttributeUsage(.Method)]
|
||||||
struct RegisterMethodAttribute : Attribute, IOnMethodInit
|
struct RegisterMethodAttribute : Attribute, IOnMethodInit
|
||||||
@@ -62,27 +293,47 @@ static class ScriptGlue
|
|||||||
[Comptime]
|
[Comptime]
|
||||||
public void OnMethodInit(MethodInfo method, Self* prev)
|
public void OnMethodInit(MethodInfo method, Self* prev)
|
||||||
{
|
{
|
||||||
|
String functionContent = new .();
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
for (var methodInfo in typeof(ScriptGlue).GetMethods(.Static))
|
for (var methodInfo in typeof(ScriptGlue).GetMethods(.Static))
|
||||||
{
|
{
|
||||||
if (methodInfo.GetCustomAttribute<RegisterCallAttribute>() case .Ok(let attribute))
|
if (methodInfo.GetCustomAttribute<RegisterCallAttribute>() case .Ok(let attribute))
|
||||||
{
|
{
|
||||||
String functionType = scope $"{methodInfo.ReturnType}({methodInfo.GetParamsDecl(.. scope .())})";
|
functionContent.AppendF($"functions.{methodInfo.Name} = => {methodInfo.Name};\n");
|
||||||
|
//functionContent.AppendF($"functions[{i}] = (void*)( => {methodInfo.Name});\n");
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
String line = scope $"RegisterCall<function {functionType}>(\"{attribute.MethodName}\", => {methodInfo.Name});\n";
|
functionContent.Insert(0, scope $"EngineFunctions functions = .();\n");
|
||||||
|
|
||||||
Compiler.EmitMethodEntry(method, line);
|
functionContent.Append("_setEngineFunctions(&functions);");
|
||||||
}
|
|
||||||
}
|
Compiler.EmitMethodEntry(method, functionContent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static Event<delegate void()> OnRegisterNativeCalls ~ _.Dispose();
|
public static Event<delegate void()> OnRegisterNativeCalls ~ _.Dispose();
|
||||||
|
|
||||||
|
/*private function void SetEngineFunctions(EngineFunctions* engineFunctions);
|
||||||
|
private static SetEngineFunctions _setEngineFunctions;*/
|
||||||
|
|
||||||
|
private function void SetEngineFunctions(EngineFunctions* engineFunctions);
|
||||||
|
private static SetEngineFunctions _setEngineFunctions;
|
||||||
|
|
||||||
public static void Init()
|
public static void Init()
|
||||||
{
|
{
|
||||||
|
if (_setEngineFunctions == null)
|
||||||
|
{
|
||||||
|
CoreClrHelper.GetFunctionPointerUnmanagedCallersOnly("GlitchyEngine.ScriptGlue, ScriptCore", "SetEngineFunctions", out _setEngineFunctions);
|
||||||
|
}
|
||||||
|
|
||||||
RegisterCalls();
|
RegisterCalls();
|
||||||
|
|
||||||
RegisterMathFunctions();
|
//RegisterMathFunctions();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void RegisterManagedComponents()
|
public static void RegisterManagedComponents()
|
||||||
@@ -103,12 +354,19 @@ static class ScriptGlue
|
|||||||
RegisterComponent<MeshRendererComponent>("GlitchyEngine.Graphics.MeshRenderer");
|
RegisterComponent<MeshRendererComponent>("GlitchyEngine.Graphics.MeshRenderer");
|
||||||
}
|
}
|
||||||
|
|
||||||
[RegisterMethod]
|
|
||||||
private static void RegisterCalls()
|
private static void RegisterCalls()
|
||||||
{
|
{
|
||||||
|
FillEngineFunctions();
|
||||||
|
|
||||||
OnRegisterNativeCalls.Invoke();
|
OnRegisterNativeCalls.Invoke();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[RegisterMethod]
|
||||||
|
private static void FillEngineFunctions()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
private static void RegisterComponent<T>(StringView cSharpClassName = "") where T : struct, new
|
private static void RegisterComponent<T>(StringView cSharpClassName = "") where T : struct, new
|
||||||
{
|
{
|
||||||
String className;
|
String className;
|
||||||
@@ -248,7 +506,7 @@ static class ScriptGlue
|
|||||||
|
|
||||||
#region Log
|
#region Log
|
||||||
|
|
||||||
[RegisterCall("ScriptGlue::Log_LogMessage")]
|
/*[RegisterCall("ScriptGlue::Log_LogMessage")]
|
||||||
static void Log_LogMessage(int32 logLevel, MonoString* message, MonoString* fileName, int lineNumber)
|
static void Log_LogMessage(int32 logLevel, MonoString* message, MonoString* fileName, int lineNumber)
|
||||||
{
|
{
|
||||||
char8* utfMessage = Mono.mono_string_to_utf8(message);
|
char8* utfMessage = Mono.mono_string_to_utf8(message);
|
||||||
@@ -275,6 +533,30 @@ static class ScriptGlue
|
|||||||
}
|
}
|
||||||
|
|
||||||
Mono.mono_free(utfMessage);
|
Mono.mono_free(utfMessage);
|
||||||
|
}*/
|
||||||
|
|
||||||
|
[RegisterCall("ScriptGlue::Log_LogMessage")]
|
||||||
|
[CallingConvention(.Cdecl)]
|
||||||
|
static void Log_LogMessage(int32 logLevel, char16* messagePtr, char16* fileNamePtr, int lineNumber)
|
||||||
|
{
|
||||||
|
String escapedMessage = new:ScopedAlloc! String(messagePtr);
|
||||||
|
|
||||||
|
// Why exactly do we have to replace these? Can we get away without copying the string above?
|
||||||
|
escapedMessage.Replace("{", "{{");
|
||||||
|
escapedMessage.Replace("}", "}}");
|
||||||
|
|
||||||
|
if (fileNamePtr != null)
|
||||||
|
{
|
||||||
|
String fileName = new:ScopedAlloc! String(fileNamePtr);
|
||||||
|
|
||||||
|
MessageOrigin messageOrigin = scope MessageOrigin(fileName, lineNumber);
|
||||||
|
|
||||||
|
Log.ClientLogger.Log((LogLevel)logLevel, escapedMessage, messageOrigin);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log.ClientLogger.Log((LogLevel)logLevel, escapedMessage);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[RegisterCall("ScriptGlue::Log_LogException")]
|
[RegisterCall("ScriptGlue::Log_LogException")]
|
||||||
@@ -457,8 +739,8 @@ static class ScriptGlue
|
|||||||
scriptComponent = entity.GetComponent<ScriptComponent>();
|
scriptComponent = entity.GetComponent<ScriptComponent>();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (scriptComponent.Instance != null)
|
//if (scriptComponent.Instance != null)
|
||||||
ScriptEngine.Context.DestroyScriptDeferred(scriptComponent.Instance, false);
|
// ScriptEngine.Context.DestroyScriptDeferred(scriptComponent.Instance, false);
|
||||||
|
|
||||||
scriptComponent.Instance = null;
|
scriptComponent.Instance = null;
|
||||||
|
|
||||||
@@ -470,7 +752,8 @@ static class ScriptGlue
|
|||||||
// TODO: this returns false, if no script with ScriptClassName exists, we have to handle this case correctly I think.
|
// TODO: this returns false, if no script with ScriptClassName exists, we have to handle this case correctly I think.
|
||||||
ScriptEngine.InitializeInstance(entity, scriptComponent);
|
ScriptEngine.InitializeInstance(entity, scriptComponent);
|
||||||
|
|
||||||
return scriptComponent.Instance.MonoInstance;
|
//return scriptComponent.Instance.MonoInstance;
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
[RegisterCall("ScriptGlue::Entity_RemoveScript")]
|
[RegisterCall("ScriptGlue::Entity_RemoveScript")]
|
||||||
@@ -478,7 +761,7 @@ static class ScriptGlue
|
|||||||
{
|
{
|
||||||
ScriptComponent* scriptComponent = GetComponentSafe<ScriptComponent>(entityId);
|
ScriptComponent* scriptComponent = GetComponentSafe<ScriptComponent>(entityId);
|
||||||
|
|
||||||
ScriptEngine.Context.DestroyScriptDeferred(scriptComponent.Instance, true);
|
//ScriptEngine.Context.DestroyScriptDeferred(scriptComponent.Instance, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
[RegisterCall("ScriptGlue::Entity_GetName")]
|
[RegisterCall("ScriptGlue::Entity_GetName")]
|
||||||
@@ -653,7 +936,7 @@ static class ScriptGlue
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Packed]
|
[Packed]
|
||||||
struct AxisAngle
|
public struct AxisAngle
|
||||||
{
|
{
|
||||||
public float3 Axis;
|
public float3 Axis;
|
||||||
public float Angle;
|
public float Angle;
|
||||||
@@ -1014,8 +1297,8 @@ static class ScriptGlue
|
|||||||
innerRadius = circleRenderer.InnerRadius;
|
innerRadius = circleRenderer.InnerRadius;
|
||||||
}
|
}
|
||||||
|
|
||||||
[RegisterCall("ScriptGlue::CircleRenderer_GetInnerRadius")]
|
[RegisterCall("ScriptGlue::CircleRenderer_SetInnerRadius")]
|
||||||
static void CircleRenderer_GetInnerRadius(UUID entityId, float innerRadius)
|
static void CircleRenderer_SetInnerRadius(UUID entityId, float innerRadius)
|
||||||
{
|
{
|
||||||
CircleRendererComponent* circleRenderer = GetComponentSafe<CircleRendererComponent>(entityId);
|
CircleRendererComponent* circleRenderer = GetComponentSafe<CircleRendererComponent>(entityId);
|
||||||
circleRenderer.InnerRadius = innerRadius;
|
circleRenderer.InnerRadius = innerRadius;
|
||||||
@@ -1085,8 +1368,8 @@ static class ScriptGlue
|
|||||||
|
|
||||||
#region TextRenderer
|
#region TextRenderer
|
||||||
|
|
||||||
[RegisterCall("ScriptGlue::TextRenderer_SetIsRichText")]
|
[RegisterCall("ScriptGlue::TextRenderer_GetIsRichText")]
|
||||||
static bool TextRenderer_SetIsRichText(UUID entityId)
|
static bool TextRenderer_GetIsRichText(UUID entityId)
|
||||||
{
|
{
|
||||||
return GetComponentSafe<TextRendererComponent>(entityId).IsRichText;
|
return GetComponentSafe<TextRendererComponent>(entityId).IsRichText;
|
||||||
}
|
}
|
||||||
@@ -1419,7 +1702,7 @@ static class ScriptGlue
|
|||||||
}
|
}
|
||||||
|
|
||||||
[RegisterCall("ScriptGlue::Asset_SetIdentifier")]
|
[RegisterCall("ScriptGlue::Asset_SetIdentifier")]
|
||||||
static void Asset_GetIdentifier(UUID assetId, MonoString* text)
|
static void Asset_SetIdentifier(UUID assetId, MonoString* text)
|
||||||
{
|
{
|
||||||
ThrowNotImplementedException("Asset.GetIdentifier is not implemented.");
|
ThrowNotImplementedException("Asset.GetIdentifier is not implemented.");
|
||||||
|
|
||||||
|
|||||||
@@ -23,12 +23,12 @@ public class ScriptInstanceSerializer
|
|||||||
public void Clear()
|
public void Clear()
|
||||||
{
|
{
|
||||||
ClearDictionaryAndDeleteValues!(_serializedData);
|
ClearDictionaryAndDeleteValues!(_serializedData);
|
||||||
ScriptEngine.Classes.EntitySerializer.DestroySerializationContext(this);
|
//ScriptEngine.Classes.EntitySerializer.DestroySerializationContext(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Init()
|
public void Init()
|
||||||
{
|
{
|
||||||
ScriptEngine.Classes.EntitySerializer.CreateSerializationContext(this);
|
//ScriptEngine.Classes.EntitySerializer.CreateSerializationContext(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Serializes all script instances that are currently managed by the ScriptEngine.
|
/// Serializes all script instances that are currently managed by the ScriptEngine.
|
||||||
@@ -36,7 +36,11 @@ public class ScriptInstanceSerializer
|
|||||||
{
|
{
|
||||||
Debug.Profiler.ProfileFunction!();
|
Debug.Profiler.ProfileFunction!();
|
||||||
|
|
||||||
Init();
|
Log.EngineLogger.Error("SerializeScriptInstances not implemented.");
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
/*Init();
|
||||||
|
|
||||||
for (let (id, scriptInstance) in ScriptEngine._entityScriptInstances)
|
for (let (id, scriptInstance) in ScriptEngine._entityScriptInstances)
|
||||||
{
|
{
|
||||||
@@ -46,7 +50,7 @@ public class ScriptInstanceSerializer
|
|||||||
for (let (name, scriptClass) in ScriptEngine.EntityClasses)
|
for (let (name, scriptClass) in ScriptEngine.EntityClasses)
|
||||||
{
|
{
|
||||||
SerializeStaticScriptClassFields(scriptClass);
|
SerializeStaticScriptClassFields(scriptClass);
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Serializes the given script instance.
|
/// Serializes the given script instance.
|
||||||
@@ -68,7 +72,11 @@ public class ScriptInstanceSerializer
|
|||||||
{
|
{
|
||||||
Debug.Profiler.ProfileFunction!();
|
Debug.Profiler.ProfileFunction!();
|
||||||
|
|
||||||
Init();
|
Log.EngineLogger.Error("SerializeScriptInstances not implemented.");
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
/*Init();
|
||||||
|
|
||||||
for (let (id, script) in ScriptEngine._entityScriptInstances)
|
for (let (id, script) in ScriptEngine._entityScriptInstances)
|
||||||
{
|
{
|
||||||
@@ -78,7 +86,7 @@ public class ScriptInstanceSerializer
|
|||||||
for (let (name, scriptClass) in ScriptEngine.EntityClasses)
|
for (let (name, scriptClass) in ScriptEngine.EntityClasses)
|
||||||
{
|
{
|
||||||
DeserializeStaticScriptClassFields(scriptClass);
|
DeserializeStaticScriptClassFields(scriptClass);
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Deserializes the data into the given script instance, if there is data available.
|
/// Deserializes the data into the given script instance, if there is data available.
|
||||||
|
|||||||
@@ -674,7 +674,7 @@ namespace GlitchyEngine.World
|
|||||||
{
|
{
|
||||||
private String _scriptClassName = null;
|
private String _scriptClassName = null;
|
||||||
|
|
||||||
private ScriptInstance _instance = null;
|
private NewScriptInstance _instance = null;
|
||||||
|
|
||||||
public StringView ScriptClassName
|
public StringView ScriptClassName
|
||||||
{
|
{
|
||||||
@@ -688,7 +688,7 @@ namespace GlitchyEngine.World
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public ScriptInstance Instance
|
public NewScriptInstance Instance
|
||||||
{
|
{
|
||||||
[Inline]
|
[Inline]
|
||||||
get => _instance;
|
get => _instance;
|
||||||
|
|||||||
@@ -395,8 +395,9 @@ namespace GlitchyEngine.World
|
|||||||
collision.Rigidbody = rigidbodyEntityA.UUID;
|
collision.Rigidbody = rigidbodyEntityA.UUID;
|
||||||
collision.OtherRigidbody = rigidbodyEntityB.UUID;
|
collision.OtherRigidbody = rigidbodyEntityB.UUID;
|
||||||
|
|
||||||
scriptOfColliderA?.Instance?.InvokeOnCollisionEnter2D(collision);
|
// TODO:
|
||||||
scriptOfRigidbodyA?.Instance?.InvokeOnCollisionEnter2D(collision);
|
//scriptOfColliderA?.Instance?.InvokeOnCollisionEnter2D(collision);
|
||||||
|
//scriptOfRigidbodyA?.Instance?.InvokeOnCollisionEnter2D(collision);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool fireEventB = colliderEntityB.TryGetComponent<ScriptComponent>(let scriptOfColliderB);
|
bool fireEventB = colliderEntityB.TryGetComponent<ScriptComponent>(let scriptOfColliderB);
|
||||||
@@ -410,8 +411,8 @@ namespace GlitchyEngine.World
|
|||||||
collision.Rigidbody = rigidbodyEntityB.UUID;
|
collision.Rigidbody = rigidbodyEntityB.UUID;
|
||||||
collision.OtherRigidbody = rigidbodyEntityA.UUID;
|
collision.OtherRigidbody = rigidbodyEntityA.UUID;
|
||||||
|
|
||||||
scriptOfColliderB?.Instance?.InvokeOnCollisionEnter2D(collision);
|
//scriptOfColliderB?.Instance?.InvokeOnCollisionEnter2D(collision);
|
||||||
scriptOfRigidbodyB?.Instance?.InvokeOnCollisionEnter2D(collision);
|
//scriptOfRigidbodyB?.Instance?.InvokeOnCollisionEnter2D(collision);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
_contactListener.endContactCallback = (contact, userData) => {
|
_contactListener.endContactCallback = (contact, userData) => {
|
||||||
@@ -446,8 +447,8 @@ namespace GlitchyEngine.World
|
|||||||
collision.Rigidbody = rigidbodyEntityA.UUID;
|
collision.Rigidbody = rigidbodyEntityA.UUID;
|
||||||
collision.OtherRigidbody = rigidbodyEntityB.UUID;
|
collision.OtherRigidbody = rigidbodyEntityB.UUID;
|
||||||
|
|
||||||
scriptOfColliderA?.Instance?.InvokeOnCollisionLeave2D(collision);
|
//scriptOfColliderA?.Instance?.InvokeOnCollisionLeave2D(collision);
|
||||||
scriptOfRigidbodyA?.Instance?.InvokeOnCollisionLeave2D(collision);
|
//scriptOfRigidbodyA?.Instance?.InvokeOnCollisionLeave2D(collision);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool fireEventB = colliderEntityB.TryGetComponent<ScriptComponent>(let scriptOfColliderB);
|
bool fireEventB = colliderEntityB.TryGetComponent<ScriptComponent>(let scriptOfColliderB);
|
||||||
@@ -461,8 +462,8 @@ namespace GlitchyEngine.World
|
|||||||
collision.Rigidbody = rigidbodyEntityB.UUID;
|
collision.Rigidbody = rigidbodyEntityB.UUID;
|
||||||
collision.OtherRigidbody = rigidbodyEntityA.UUID;
|
collision.OtherRigidbody = rigidbodyEntityA.UUID;
|
||||||
|
|
||||||
scriptOfColliderB?.Instance?.InvokeOnCollisionLeave2D(collision);
|
//scriptOfColliderB?.Instance?.InvokeOnCollisionLeave2D(collision);
|
||||||
scriptOfRigidbodyB?.Instance?.InvokeOnCollisionLeave2D(collision);
|
//scriptOfRigidbodyB?.Instance?.InvokeOnCollisionLeave2D(collision);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -992,13 +993,13 @@ namespace GlitchyEngine.World
|
|||||||
|
|
||||||
if (sourceScript.Instance != null)
|
if (sourceScript.Instance != null)
|
||||||
{
|
{
|
||||||
scriptSerializer.SerializeScriptInstance(sourceScript.Instance);
|
//scriptSerializer.SerializeScriptInstance(sourceScript.Instance);
|
||||||
|
|
||||||
// Initializes the created instance
|
// Initializes the created instance
|
||||||
// TODO: this returns false, if no script with ScriptClassName exists, we have to handle this case correctly I think.
|
// TODO: this returns false, if no script with ScriptClassName exists, we have to handle this case correctly I think.
|
||||||
ScriptEngine.InitializeInstance(copy, targetScript);
|
ScriptEngine.InitializeInstance(copy, targetScript);
|
||||||
|
|
||||||
newScripts.Add((original.UUID, targetScript.Instance));
|
//newScripts.Add((original.UUID, targetScript.Instance));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
Submodule GlitchyEngine/vendor/NetHostBeef added at aeb099576d
+12
-6
@@ -414,12 +414,18 @@ public class Entity : EngineObject
|
|||||||
return new Entity(newEntityId);
|
return new Entity(newEntityId);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Will be executed once after the entity has be created.
|
/// <summary>
|
||||||
// void OnCreate();
|
/// Will be executed once after the entity has be created.
|
||||||
|
/// </summary>
|
||||||
|
protected internal virtual void OnCreate() { }
|
||||||
|
|
||||||
// Will be executed every frame.
|
/// <summary>
|
||||||
// void OnUpdate(GameTime);
|
/// Is called once every frame.
|
||||||
|
/// </summary>
|
||||||
|
protected internal virtual void OnUpdate(float deltaTime) { }
|
||||||
|
|
||||||
// Will be executed once when the entity is being destroyed.
|
/// <summary>
|
||||||
// void OnDestroy();
|
/// Will be executed once when the entity is being destroyed.
|
||||||
|
/// </summary>
|
||||||
|
protected internal virtual void OnDestroy() { }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -148,7 +148,7 @@ public static class TypeExtension
|
|||||||
string name = fullName.TrimEnd(']').ToString();
|
string name = fullName.TrimEnd(']').ToString();
|
||||||
|
|
||||||
// Non generic type, easy!
|
// Non generic type, easy!
|
||||||
foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies().Reverse())
|
foreach (Assembly assembly in ((IEnumerable<Assembly>)AppDomain.CurrentDomain.GetAssemblies()).Reverse())
|
||||||
{
|
{
|
||||||
Type? type = assembly.GetType(name);
|
Type? type = assembly.GetType(name);
|
||||||
|
|
||||||
|
|||||||
+284
-284
@@ -1,284 +1,284 @@
|
|||||||
using System;
|
// using System;
|
||||||
using System.Runtime.CompilerServices;
|
// using System.Runtime.CompilerServices;
|
||||||
|
//
|
||||||
namespace GlitchyEngine.Math;
|
// namespace GlitchyEngine.Math;
|
||||||
|
//
|
||||||
/// <summary>
|
// /// <summary>
|
||||||
/// Represents a 16-bit (half-precision) floating point number. (aka. IEEE 754 half-precision binary floating-point (binary16))
|
// /// Represents a 16-bit (half-precision) floating point number. (aka. IEEE 754 half-precision binary floating-point (binary16))
|
||||||
/// </summary>
|
// /// </summary>
|
||||||
/// <remarks>
|
// /// <remarks>
|
||||||
/// Even though it is possible, it's not recommended to perform large calculations using this type directly because most operators will simply cast the operands to <see cref="float"/> and cast the result back to <see cref="Half"/>.
|
// /// Even though it is possible, it's not recommended to perform large calculations using this type directly because most operators will simply cast the operands to <see cref="float"/> and cast the result back to <see cref="Half"/>.
|
||||||
/// If you need to do larger calculations consider casting to <see cref="float"/> once and cast the result back to <see cref="Half"/> afterwards. This will not only have better performance, but will also increase the accuracy of the result.
|
// /// If you need to do larger calculations consider casting to <see cref="float"/> once and cast the result back to <see cref="Half"/> afterwards. This will not only have better performance, but will also increase the accuracy of the result.
|
||||||
/// </remarks>
|
// /// </remarks>
|
||||||
public struct Half : IComparable , IComparable<Half>, IConvertible, IEquatable<Half>, IFormattable
|
// public struct Half : IComparable , IComparable<Half>, IConvertible, IEquatable<Half>, IFormattable
|
||||||
{
|
// {
|
||||||
public static readonly Half MinValue = new(-65504); // Should be 0xFBFF
|
// public static readonly Half MinValue = new(-65504); // Should be 0xFBFF
|
||||||
public static readonly Half MaxValue = new(65504); // Should be 0x7BFF
|
// public static readonly Half MaxValue = new(65504); // Should be 0x7BFF
|
||||||
|
//
|
||||||
// The numbers for Infinity, NaN and Zero need to be hardcoded as binaries,
|
// // The numbers for Infinity, NaN and Zero need to be hardcoded as binaries,
|
||||||
// because the conversion itself relies on them.
|
// // because the conversion itself relies on them.
|
||||||
|
//
|
||||||
public static readonly Half PositiveInfinity = new(0x7C00);
|
// public static readonly Half PositiveInfinity = new(0x7C00);
|
||||||
public static readonly Half NegativeInfinity = new(0xFC00);
|
// public static readonly Half NegativeInfinity = new(0xFC00);
|
||||||
public static readonly Half NaN = new(0x7CFF);
|
// public static readonly Half NaN = new(0x7CFF);
|
||||||
|
//
|
||||||
public static readonly Half Zero = new(0x0000);
|
// public static readonly Half Zero = new(0x0000);
|
||||||
public static readonly Half NegativeZero = new(0x8000);
|
// public static readonly Half NegativeZero = new(0x8000);
|
||||||
|
//
|
||||||
private ushort _data;
|
// private ushort _data;
|
||||||
|
//
|
||||||
public bool IsNegative => IsNegative_Impl(this);
|
// public bool IsNegative => IsNegative_Impl(this);
|
||||||
|
//
|
||||||
public bool IsFinite => IsFinite_Impl(this);
|
// public bool IsFinite => IsFinite_Impl(this);
|
||||||
public bool IsInfinity => IsInfinity_Impl(this);
|
// public bool IsInfinity => IsInfinity_Impl(this);
|
||||||
public bool IsPositiveInfinity => _data == PositiveInfinity._data;
|
// public bool IsPositiveInfinity => _data == PositiveInfinity._data;
|
||||||
public bool IsNegativeInfinity => _data == NegativeInfinity._data;
|
// public bool IsNegativeInfinity => _data == NegativeInfinity._data;
|
||||||
public bool IsNaN => IsNan_Impl(this);
|
// public bool IsNaN => IsNan_Impl(this);
|
||||||
|
//
|
||||||
public bool IsSubnormal => IsSubnormal_Impl(this);
|
// public bool IsSubnormal => IsSubnormal_Impl(this);
|
||||||
|
//
|
||||||
public Half(float value)
|
// public Half(float value)
|
||||||
{
|
// {
|
||||||
FromFloat32(value, out Half halfValue);
|
// FromFloat32(value, out Half halfValue);
|
||||||
this = halfValue;
|
// this = halfValue;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
private Half(ushort data)
|
// private Half(ushort data)
|
||||||
{
|
// {
|
||||||
_data = data;
|
// _data = data;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
public static explicit operator float(Half value)
|
// public static explicit operator float(Half value)
|
||||||
{
|
// {
|
||||||
ToFloat32(value, out float floatValue);
|
// ToFloat32(value, out float floatValue);
|
||||||
return floatValue;
|
// return floatValue;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
public static explicit operator Half(float value)
|
// public static explicit operator Half(float value)
|
||||||
{
|
// {
|
||||||
FromFloat32(value, out Half halfValue);
|
// FromFloat32(value, out Half halfValue);
|
||||||
return halfValue;
|
// return halfValue;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
/// <summary>Converts the numeric value of this instance to its equivalent string representation.</summary>
|
// /// <summary>Converts the numeric value of this instance to its equivalent string representation.</summary>
|
||||||
/// <returns>The string representation of the value of this instance.</returns>
|
// /// <returns>The string representation of the value of this instance.</returns>
|
||||||
public override string ToString() => ((float)this).ToString();
|
// public override string ToString() => ((float)this).ToString();
|
||||||
|
//
|
||||||
public int CompareTo(object obj)
|
// public int CompareTo(object obj)
|
||||||
{
|
// {
|
||||||
if (obj == null)
|
// if (obj == null)
|
||||||
return 1;
|
// return 1;
|
||||||
|
//
|
||||||
if (obj is not Half value)
|
// if (obj is not Half value)
|
||||||
throw new ArgumentException($"Object must be of type {typeof(Half)}");
|
// throw new ArgumentException($"Object must be of type {typeof(Half)}");
|
||||||
|
//
|
||||||
return CompareTo(value);
|
// return CompareTo(value);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
public int CompareTo(Half other)
|
// public int CompareTo(Half other)
|
||||||
{
|
// {
|
||||||
return ((float)this).CompareTo((float)other);
|
// return ((float)this).CompareTo((float)other);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
public TypeCode GetTypeCode() => TypeCode.Object;
|
// public TypeCode GetTypeCode() => TypeCode.Object;
|
||||||
|
//
|
||||||
public bool ToBoolean(IFormatProvider provider) => Convert.ToBoolean((float)this, provider);
|
// public bool ToBoolean(IFormatProvider provider) => Convert.ToBoolean((float)this, provider);
|
||||||
|
//
|
||||||
public byte ToByte(IFormatProvider provider) => Convert.ToByte((float)this, provider);
|
// public byte ToByte(IFormatProvider provider) => Convert.ToByte((float)this, provider);
|
||||||
|
//
|
||||||
public char ToChar(IFormatProvider provider) => Convert.ToChar((float)this, provider);
|
// public char ToChar(IFormatProvider provider) => Convert.ToChar((float)this, provider);
|
||||||
|
//
|
||||||
public DateTime ToDateTime(IFormatProvider provider) => Convert.ToDateTime((float)this, provider);
|
// public DateTime ToDateTime(IFormatProvider provider) => Convert.ToDateTime((float)this, provider);
|
||||||
|
//
|
||||||
public decimal ToDecimal(IFormatProvider provider) => Convert.ToDecimal((float)this, provider);
|
// public decimal ToDecimal(IFormatProvider provider) => Convert.ToDecimal((float)this, provider);
|
||||||
|
//
|
||||||
public double ToDouble(IFormatProvider provider) => Convert.ToDouble((float)this, provider);
|
// public double ToDouble(IFormatProvider provider) => Convert.ToDouble((float)this, provider);
|
||||||
|
//
|
||||||
public short ToInt16(IFormatProvider provider) => Convert.ToInt16((float)this, provider);
|
// public short ToInt16(IFormatProvider provider) => Convert.ToInt16((float)this, provider);
|
||||||
|
//
|
||||||
public int ToInt32(IFormatProvider provider) => Convert.ToInt32((float)this, provider);
|
// public int ToInt32(IFormatProvider provider) => Convert.ToInt32((float)this, provider);
|
||||||
|
//
|
||||||
public long ToInt64(IFormatProvider provider) => Convert.ToInt64((float)this, provider);
|
// public long ToInt64(IFormatProvider provider) => Convert.ToInt64((float)this, provider);
|
||||||
|
//
|
||||||
public sbyte ToSByte(IFormatProvider provider) => Convert.ToSByte((float)this, provider);
|
// public sbyte ToSByte(IFormatProvider provider) => Convert.ToSByte((float)this, provider);
|
||||||
|
//
|
||||||
public float ToSingle(IFormatProvider provider) => Convert.ToSingle((float)this, provider);
|
// public float ToSingle(IFormatProvider provider) => Convert.ToSingle((float)this, provider);
|
||||||
|
//
|
||||||
/// <summary>Converts the numeric value of this instance to its equivalent string representation using the specified culture-specific format information.</summary>
|
// /// <summary>Converts the numeric value of this instance to its equivalent string representation using the specified culture-specific format information.</summary>
|
||||||
/// <param name="provider">An object that supplies culture-specific formatting information.</param>
|
// /// <param name="provider">An object that supplies culture-specific formatting information.</param>
|
||||||
/// <returns>The string representation of the value of this instance as specified by <paramref name="provider">provider</paramref>.</returns>
|
// /// <returns>The string representation of the value of this instance as specified by <paramref name="provider">provider</paramref>.</returns>
|
||||||
public string ToString(IFormatProvider provider) => ((float)this).ToString(provider);
|
// public string ToString(IFormatProvider provider) => ((float)this).ToString(provider);
|
||||||
|
//
|
||||||
/// <summary>Converts the numeric value of this instance to its equivalent string representation, using the specified format.</summary>
|
// /// <summary>Converts the numeric value of this instance to its equivalent string representation, using the specified format.</summary>
|
||||||
/// <param name="format">A numeric format string.</param>
|
// /// <param name="format">A numeric format string.</param>
|
||||||
/// <returns>The string representation of the value of this instance as specified by <paramref name="format">format</paramref>.</returns>
|
// /// <returns>The string representation of the value of this instance as specified by <paramref name="format">format</paramref>.</returns>
|
||||||
/// <exception cref="T:System.FormatException"><paramref name="format">format</paramref> is invalid.</exception>
|
// /// <exception cref="T:System.FormatException"><paramref name="format">format</paramref> is invalid.</exception>
|
||||||
public string ToString(string format) => ((float)this).ToString(format);
|
// public string ToString(string format) => ((float)this).ToString(format);
|
||||||
|
//
|
||||||
/// <summary>Converts the numeric value of this instance to its equivalent string representation using the specified format and culture-specific format information.</summary>
|
// /// <summary>Converts the numeric value of this instance to its equivalent string representation using the specified format and culture-specific format information.</summary>
|
||||||
/// <param name="format">A numeric format string.</param>
|
// /// <param name="format">A numeric format string.</param>
|
||||||
/// <param name="provider">An object that supplies culture-specific formatting information.</param>
|
// /// <param name="provider">An object that supplies culture-specific formatting information.</param>
|
||||||
/// <returns>The string representation of the value of this instance as specified by <paramref name="format">format</paramref> and <paramref name="provider">provider</paramref>.</returns>
|
// /// <returns>The string representation of the value of this instance as specified by <paramref name="format">format</paramref> and <paramref name="provider">provider</paramref>.</returns>
|
||||||
public string ToString(string format, IFormatProvider provider) => ((float)this).ToString(format, provider);
|
// public string ToString(string format, IFormatProvider provider) => ((float)this).ToString(format, provider);
|
||||||
|
//
|
||||||
public object ToType(Type conversionType, IFormatProvider provider) => ((IConvertible)(float)this).ToType(conversionType, provider);
|
// public object ToType(Type conversionType, IFormatProvider provider) => ((IConvertible)(float)this).ToType(conversionType, provider);
|
||||||
|
//
|
||||||
public ushort ToUInt16(IFormatProvider provider) => Convert.ToUInt16((float)this, provider);
|
// public ushort ToUInt16(IFormatProvider provider) => Convert.ToUInt16((float)this, provider);
|
||||||
|
//
|
||||||
public uint ToUInt32(IFormatProvider provider) => Convert.ToUInt32((float)this, provider);
|
// public uint ToUInt32(IFormatProvider provider) => Convert.ToUInt32((float)this, provider);
|
||||||
|
//
|
||||||
public ulong ToUInt64(IFormatProvider provider) => Convert.ToUInt64((float)this, provider);
|
// public ulong ToUInt64(IFormatProvider provider) => Convert.ToUInt64((float)this, provider);
|
||||||
|
//
|
||||||
public bool Equals(Half other)
|
// public bool Equals(Half other)
|
||||||
{
|
// {
|
||||||
return _data == other._data;
|
// return _data == other._data;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
public override bool Equals(object obj)
|
// public override bool Equals(object obj)
|
||||||
{
|
// {
|
||||||
return obj is Half other && Equals(other);
|
// return obj is Half other && Equals(other);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
public override int GetHashCode()
|
// public override int GetHashCode()
|
||||||
{
|
// {
|
||||||
return _data.GetHashCode();
|
// return _data.GetHashCode();
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
#region Operators
|
// #region Operators
|
||||||
|
//
|
||||||
public static bool operator ==(Half left, Half right) => left._data == right._data;
|
// public static bool operator ==(Half left, Half right) => left._data == right._data;
|
||||||
|
//
|
||||||
public static bool operator !=(Half left, Half right) => left._data != right._data;
|
// public static bool operator !=(Half left, Half right) => left._data != right._data;
|
||||||
|
//
|
||||||
public static bool operator <(Half left, Half right)
|
// public static bool operator <(Half left, Half right)
|
||||||
{
|
// {
|
||||||
LessThan_Impl(left, right, out bool result);
|
// LessThan_Impl(left, right, out bool result);
|
||||||
return result;
|
// return result;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
public static bool operator <=(Half left, Half right)
|
// public static bool operator <=(Half left, Half right)
|
||||||
{
|
// {
|
||||||
LessThanOrEqual_Impl(left, right, out bool result);
|
// LessThanOrEqual_Impl(left, right, out bool result);
|
||||||
return result;
|
// return result;
|
||||||
}
|
// }
|
||||||
public static bool operator >(Half left, Half right)
|
// public static bool operator >(Half left, Half right)
|
||||||
{
|
// {
|
||||||
GreaterThan_Impl(left, right, out bool result);
|
// GreaterThan_Impl(left, right, out bool result);
|
||||||
return result;
|
// return result;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
public static bool operator >=(Half left, Half right)
|
// public static bool operator >=(Half left, Half right)
|
||||||
{
|
// {
|
||||||
GreaterThanOrEqual_Impl(left, right, out bool result);
|
// GreaterThanOrEqual_Impl(left, right, out bool result);
|
||||||
return result;
|
// return result;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
public static Half operator +(Half value) => value;
|
// public static Half operator +(Half value) => value;
|
||||||
|
//
|
||||||
public static Half operator -(Half value)
|
// public static Half operator -(Half value)
|
||||||
{
|
// {
|
||||||
Negate_Impl(value, out Half result);
|
// Negate_Impl(value, out Half result);
|
||||||
return result;
|
// return result;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
public static Half operator +(Half left, Half right)
|
// public static Half operator +(Half left, Half right)
|
||||||
{
|
// {
|
||||||
Add_Impl(left, right, out Half result);
|
// Add_Impl(left, right, out Half result);
|
||||||
return result;
|
// return result;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
public static Half operator -(Half left, Half right)
|
// public static Half operator -(Half left, Half right)
|
||||||
{
|
// {
|
||||||
Subtract_Impl(left, right, out Half result);
|
// Subtract_Impl(left, right, out Half result);
|
||||||
return result;
|
// return result;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
public static Half operator *(Half left, Half right)
|
// public static Half operator *(Half left, Half right)
|
||||||
{
|
// {
|
||||||
Multiply_Impl(left, right, out Half result);
|
// Multiply_Impl(left, right, out Half result);
|
||||||
return result;
|
// return result;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
public static Half operator /(Half left, Half right)
|
// public static Half operator /(Half left, Half right)
|
||||||
{
|
// {
|
||||||
Divide_Impl(left, right, out Half result);
|
// Divide_Impl(left, right, out Half result);
|
||||||
return result;
|
// return result;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
public static Half operator %(Half left, Half right)
|
// public static Half operator %(Half left, Half right)
|
||||||
{
|
// {
|
||||||
Modulo_Impl(left, right, out Half result);
|
// Modulo_Impl(left, right, out Half result);
|
||||||
return result;
|
// return result;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
public static Half operator ++(Half value)
|
// public static Half operator ++(Half value)
|
||||||
{
|
// {
|
||||||
Increment_Impl(value, out Half result);
|
// Increment_Impl(value, out Half result);
|
||||||
return result;
|
// return result;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
public static Half operator --(Half value)
|
// public static Half operator --(Half value)
|
||||||
{
|
// {
|
||||||
Decrement_Impl(value, out Half result);
|
// Decrement_Impl(value, out Half result);
|
||||||
return result;
|
// return result;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
// [MethodImpl(MethodImplOptions.InternalCall)]
|
||||||
private static extern void LessThan_Impl(Half left, Half right, out bool result);
|
// private static extern void LessThan_Impl(Half left, Half right, out bool result);
|
||||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
// [MethodImpl(MethodImplOptions.InternalCall)]
|
||||||
private static extern void LessThanOrEqual_Impl(Half left, Half right, out bool result);
|
// private static extern void LessThanOrEqual_Impl(Half left, Half right, out bool result);
|
||||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
// [MethodImpl(MethodImplOptions.InternalCall)]
|
||||||
private static extern void GreaterThan_Impl(Half left, Half right, out bool result);
|
// private static extern void GreaterThan_Impl(Half left, Half right, out bool result);
|
||||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
// [MethodImpl(MethodImplOptions.InternalCall)]
|
||||||
private static extern void GreaterThanOrEqual_Impl(Half left, Half right, out bool result);
|
// private static extern void GreaterThanOrEqual_Impl(Half left, Half right, out bool result);
|
||||||
|
//
|
||||||
// Externe Methoden hier als Platzhalter
|
// // Externe Methoden hier als Platzhalter
|
||||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
// [MethodImpl(MethodImplOptions.InternalCall)]
|
||||||
private static extern void Add_Impl(Half left, Half right, out Half result);
|
// private static extern void Add_Impl(Half left, Half right, out Half result);
|
||||||
|
//
|
||||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
// [MethodImpl(MethodImplOptions.InternalCall)]
|
||||||
private static extern void Subtract_Impl(Half left, Half right, out Half result);
|
// private static extern void Subtract_Impl(Half left, Half right, out Half result);
|
||||||
|
//
|
||||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
// [MethodImpl(MethodImplOptions.InternalCall)]
|
||||||
private static extern void Multiply_Impl(Half left, Half right, out Half result);
|
// private static extern void Multiply_Impl(Half left, Half right, out Half result);
|
||||||
|
//
|
||||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
// [MethodImpl(MethodImplOptions.InternalCall)]
|
||||||
private static extern void Divide_Impl(Half left, Half right, out Half result);
|
// private static extern void Divide_Impl(Half left, Half right, out Half result);
|
||||||
|
//
|
||||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
// [MethodImpl(MethodImplOptions.InternalCall)]
|
||||||
private static extern void Modulo_Impl(Half left, Half right, out Half result);
|
// private static extern void Modulo_Impl(Half left, Half right, out Half result);
|
||||||
|
//
|
||||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
// [MethodImpl(MethodImplOptions.InternalCall)]
|
||||||
private static extern void Negate_Impl(Half value, out Half result);
|
// private static extern void Negate_Impl(Half value, out Half result);
|
||||||
|
//
|
||||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
// [MethodImpl(MethodImplOptions.InternalCall)]
|
||||||
private static extern void Increment_Impl(Half value, out Half result);
|
// private static extern void Increment_Impl(Half value, out Half result);
|
||||||
|
//
|
||||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
// [MethodImpl(MethodImplOptions.InternalCall)]
|
||||||
private static extern void Decrement_Impl(Half value, out Half result);
|
// private static extern void Decrement_Impl(Half value, out Half result);
|
||||||
|
//
|
||||||
#endregion
|
// #endregion
|
||||||
|
//
|
||||||
#region Bindings
|
// #region Bindings
|
||||||
|
//
|
||||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
// [MethodImpl(MethodImplOptions.InternalCall)]
|
||||||
private static extern void FromFloat32(float value, out Half halfValue);
|
// private static extern void FromFloat32(float value, out Half halfValue);
|
||||||
|
//
|
||||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
// [MethodImpl(MethodImplOptions.InternalCall)]
|
||||||
private static extern void ToFloat32(Half value, out float floatValue);
|
// private static extern void ToFloat32(Half value, out float floatValue);
|
||||||
|
//
|
||||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
// [MethodImpl(MethodImplOptions.InternalCall)]
|
||||||
private static extern bool IsNegative_Impl(Half self);
|
// private static extern bool IsNegative_Impl(Half self);
|
||||||
|
//
|
||||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
// [MethodImpl(MethodImplOptions.InternalCall)]
|
||||||
private static extern bool IsFinite_Impl(Half self);
|
// private static extern bool IsFinite_Impl(Half self);
|
||||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
// [MethodImpl(MethodImplOptions.InternalCall)]
|
||||||
private static extern bool IsInfinity_Impl(Half self);
|
// private static extern bool IsInfinity_Impl(Half self);
|
||||||
|
//
|
||||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
// [MethodImpl(MethodImplOptions.InternalCall)]
|
||||||
private static extern bool IsNan_Impl(Half self);
|
// private static extern bool IsNan_Impl(Half self);
|
||||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
// [MethodImpl(MethodImplOptions.InternalCall)]
|
||||||
private static extern bool IsSubnormal_Impl(Half self);
|
// private static extern bool IsSubnormal_Impl(Half self);
|
||||||
|
//
|
||||||
#endregion
|
// #endregion
|
||||||
}
|
// }
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using GlitchyEngine.Math.Attributes;
|
using System;
|
||||||
|
using GlitchyEngine.Math.Attributes;
|
||||||
|
|
||||||
namespace GlitchyEngine.Math;
|
namespace GlitchyEngine.Math;
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using GlitchyEngine.Math.Attributes;
|
using System;
|
||||||
|
using GlitchyEngine.Math.Attributes;
|
||||||
|
|
||||||
namespace GlitchyEngine.Math;
|
namespace GlitchyEngine.Math;
|
||||||
|
|
||||||
|
|||||||
@@ -1,27 +1,30 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netstandard2.0</TargetFramework>
|
<TargetFramework>net9.0</TargetFramework>
|
||||||
<LangVersion>latest</LangVersion>
|
<LangVersion>latest</LangVersion>
|
||||||
<BaseOutputPath></BaseOutputPath>
|
<BaseOutputPath>
|
||||||
|
</BaseOutputPath>
|
||||||
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
|
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
|
||||||
<RootNamespace>GlitchyEngine</RootNamespace>
|
<RootNamespace>GlitchyEngine</RootNamespace>
|
||||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
|
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
|
||||||
|
|
||||||
|
<GenerateRuntimeConfigurationFiles>true</GenerateRuntimeConfigurationFiles>
|
||||||
|
<EnableDynamicLoading>true</EnableDynamicLoading>
|
||||||
|
<!--<DebugType>embedded</DebugType>-->
|
||||||
|
<!--<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>-->
|
||||||
|
</PropertyGroup>
|
||||||
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
|
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
|
||||||
<Exec Command="PowerShell ./postbuild.ps1 -sourceDir $(OutDir) -destinationDir "..\GlitchyEditor\resources\scripts"" />
|
<Exec Command="PowerShell ./postbuild.ps1 -sourceDir $(OutDir) -destinationDir "..\GlitchyEditor\resources\scripts"" />
|
||||||
</Target>
|
</Target>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="System.Memory" Version="4.5.5" />
|
<PackageReference Include="System.Memory" Version="4.6.3" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\ScriptCoreGenerator\ScriptCoreGenerator.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
|
<ProjectReference Include="..\ScriptCoreGenerator\ScriptCoreGenerator.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
|
||||||
<ProjectReference Include="..\vendor\ImGui.NET\src\ImGui.NET\ImGui.NET.csproj" />
|
<ProjectReference Include="..\vendor\ImGui.NET\src\ImGui.NET\ImGui.NET.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
+468
-3
@@ -1,8 +1,19 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Linq.Expressions;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Reflection.Emit;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Runtime.Loader;
|
||||||
using GlitchyEngine.Core;
|
using GlitchyEngine.Core;
|
||||||
using GlitchyEngine.Editor;
|
using GlitchyEngine.Editor;
|
||||||
|
using GlitchyEngine.Extensions;
|
||||||
using GlitchyEngine.Graphics;
|
using GlitchyEngine.Graphics;
|
||||||
using GlitchyEngine.Graphics.Text;
|
using GlitchyEngine.Graphics.Text;
|
||||||
using GlitchyEngine.Math;
|
using GlitchyEngine.Math;
|
||||||
@@ -11,16 +22,470 @@ using GlitchyEngine.Serialization;
|
|||||||
|
|
||||||
namespace GlitchyEngine;
|
namespace GlitchyEngine;
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
internal unsafe partial struct EngineFunctions
|
||||||
|
{
|
||||||
|
public delegate* unmanaged[Cdecl]<Log.LogLevel, char*, char*, int, void> Log_LogMessage;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// All methods in here are glued to the ScriptGlue.bf in the engine.
|
/// All methods in here are glued to the ScriptGlue.bf in the engine.
|
||||||
/// TODO: This could be auto-generated fairly easily
|
/// TODO: This could be auto-generated fairly easily
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal static class ScriptGlue
|
internal static partial class ScriptGlue
|
||||||
{
|
{
|
||||||
|
#region Script Glueing infrastructure
|
||||||
|
|
||||||
|
static ScriptGlue()
|
||||||
|
{
|
||||||
|
NativeLibrary.SetDllImportResolver(typeof(ScriptGlue).Assembly, ImportResolver);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IntPtr ImportResolver(string libraryName, Assembly assembly, DllImportSearchPath? searchPath)
|
||||||
|
{
|
||||||
|
if (libraryName == "__Internal")
|
||||||
|
{
|
||||||
|
// Lade die aktuelle exe selbst
|
||||||
|
return NativeLibrary.Load(Process.GetCurrentProcess().MainModule.FileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
return IntPtr.Zero;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private static EngineFunctions _engineFunctions;
|
||||||
|
|
||||||
|
[UnmanagedCallersOnly]
|
||||||
|
public static unsafe void SetEngineFunctions(EngineFunctions* engineFunctions)
|
||||||
|
{
|
||||||
|
_engineFunctions = *engineFunctions;
|
||||||
|
|
||||||
|
Log.Info("Yeah");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static AssemblyLoadContext? _scriptAssemblyContext;
|
||||||
|
|
||||||
|
private static Assembly? _appAssembly;
|
||||||
|
|
||||||
|
[UnmanagedCallersOnly]
|
||||||
|
public static unsafe void LoadScriptAssembly(byte* assemblyData, long assemblyLength, byte* pdbData, long pdbLength)
|
||||||
|
{
|
||||||
|
using UnmanagedMemoryStream assemblyStream = new(assemblyData, assemblyLength);
|
||||||
|
|
||||||
|
using UnmanagedMemoryStream? pdbStream = (pdbData != null) ? new UnmanagedMemoryStream(pdbData, pdbLength) : null;
|
||||||
|
|
||||||
|
LoadAssembly(assemblyStream, pdbStream);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void LoadAssembly(Stream assemblyStream, Stream? pdbStream)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_scriptAssemblyContext ??= new AssemblyLoadContext("ScriptContext", true);
|
||||||
|
|
||||||
|
_appAssembly = _scriptAssemblyContext.LoadFromStream(assemblyStream, pdbStream);
|
||||||
|
|
||||||
|
Debug.Assert(_appAssembly != null);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"Fehler: {e}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[UnmanagedCallersOnly]
|
||||||
|
public static void UnloadAssemblies()
|
||||||
|
{
|
||||||
|
_scriptAssemblyContext?.Unload();
|
||||||
|
_scriptAssemblyContext = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ScriptClassInfo
|
||||||
|
{
|
||||||
|
public byte[] Name;
|
||||||
|
public Guid Guid;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static NativeScriptClassInfo[]? _unsafeClasses;
|
||||||
|
|
||||||
|
struct NativeScriptClassInfo
|
||||||
|
{
|
||||||
|
public IntPtr Name;
|
||||||
|
public Guid Guid;
|
||||||
|
public ScriptMethods Methods;
|
||||||
|
public bool RunInEditMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Flags]
|
||||||
|
public enum ScriptMethods
|
||||||
|
{
|
||||||
|
None = 0,
|
||||||
|
OnCreate = 0x1,
|
||||||
|
OnUpdate = 0x2,
|
||||||
|
OnDestroy = 0x4
|
||||||
|
}
|
||||||
|
|
||||||
|
[UnmanagedCallersOnly]
|
||||||
|
public static unsafe void GetScriptClasses(void** outBuffer, long* length)
|
||||||
|
{
|
||||||
|
using var contextualReflection = AssemblyLoadContext.EnterContextualReflection(_appAssembly);
|
||||||
|
|
||||||
|
Debug.Assert(_appAssembly != null);
|
||||||
|
|
||||||
|
Internal_FreeScriptClassNames();
|
||||||
|
|
||||||
|
var types = _appAssembly.GetTypes();
|
||||||
|
|
||||||
|
List<(string Name, Guid Guid, ScriptMethods AvailableMethods, bool runInEditMode)> scriptClasses = new();
|
||||||
|
|
||||||
|
foreach (var type in types)
|
||||||
|
{
|
||||||
|
if (type.IsSubclassOf(typeof(Entity)))
|
||||||
|
{
|
||||||
|
string? name = type.FullName;
|
||||||
|
|
||||||
|
if (name == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
Guid guid = type.GUID;
|
||||||
|
|
||||||
|
ScriptMethods methods = ScriptMethods.None;
|
||||||
|
|
||||||
|
static ScriptMethods HasMethod(Type type, string methodName, ScriptMethods methodFlag)
|
||||||
|
{
|
||||||
|
MethodInfo? methodInfo = type.GetMethod(methodName, BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly);
|
||||||
|
|
||||||
|
return methodInfo != null ? methodFlag : ScriptMethods.None;
|
||||||
|
}
|
||||||
|
|
||||||
|
methods |= HasMethod(type, nameof(Entity.OnCreate), ScriptMethods.OnCreate);
|
||||||
|
methods |= HasMethod(type, nameof(Entity.OnUpdate), ScriptMethods.OnUpdate);
|
||||||
|
methods |= HasMethod(type, nameof(Entity.OnDestroy), ScriptMethods.OnDestroy);
|
||||||
|
|
||||||
|
bool runInEditMode = type.HasCustomAttribute<RunInEditModeAttribute>();
|
||||||
|
|
||||||
|
scriptClasses.Add((name, guid, methods, runInEditMode));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_unsafeClasses = new NativeScriptClassInfo[scriptClasses.Count];
|
||||||
|
|
||||||
|
for (int i = 0; i < _unsafeClasses.Length; i++)
|
||||||
|
{
|
||||||
|
_unsafeClasses[i] = new NativeScriptClassInfo()
|
||||||
|
{
|
||||||
|
Guid = scriptClasses[i].Guid,
|
||||||
|
Name = Marshal.StringToCoTaskMemUTF8(scriptClasses[i].Name),
|
||||||
|
Methods = scriptClasses[i].AvailableMethods,
|
||||||
|
RunInEditMode = scriptClasses[i].runInEditMode
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
*outBuffer = (void*)Marshal.UnsafeAddrOfPinnedArrayElement(_unsafeClasses, 0);
|
||||||
|
*length = _unsafeClasses.Length;
|
||||||
|
}
|
||||||
|
|
||||||
|
[UnmanagedCallersOnly]
|
||||||
|
public static void FreeScriptClassNames()
|
||||||
|
{
|
||||||
|
Internal_FreeScriptClassNames();
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void Internal_FreeScriptClassNames()
|
||||||
|
{
|
||||||
|
if (_unsafeClasses == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
foreach (NativeScriptClassInfo info in _unsafeClasses)
|
||||||
|
{
|
||||||
|
Marshal.FreeCoTaskMem(info.Name);
|
||||||
|
}
|
||||||
|
|
||||||
|
_unsafeClasses = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Dictionary<UUID, (Entity Entity, Type Type)> _entityScripts = new();
|
||||||
|
|
||||||
|
[UnmanagedCallersOnly]
|
||||||
|
public static void ShowEntityEditor(UUID entityId)
|
||||||
|
{
|
||||||
|
(Entity entity, Type type) = _entityScripts[entityId];
|
||||||
|
EntityEditor.ShowEntityEditor(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
[UnmanagedCallersOnly]
|
||||||
|
public static void InvokeEntityOnCreate(UUID entityId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
(Entity entity, Type type) = _entityScripts[entityId];
|
||||||
|
entity.OnCreate();
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Console.WriteLine(e);
|
||||||
|
// TODO: Log exceptions to console
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[UnmanagedCallersOnly]
|
||||||
|
public static void InvokeEntityOnUpdate(UUID entityId, float deltaTime)
|
||||||
|
{
|
||||||
|
// using var _ = AssemblyLoadContext.EnterContextualReflection(_appAssembly); // TODO: Check if reflection works correctly in entities
|
||||||
|
|
||||||
|
(Entity entity, Type type) = _entityScripts[entityId];
|
||||||
|
entity.OnUpdate(deltaTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
[UnmanagedCallersOnly]
|
||||||
|
public static void InvokeEntityOnDestroy(UUID entityId, float deltaTime)
|
||||||
|
{
|
||||||
|
(Entity entity, Type type) = _entityScripts[entityId];
|
||||||
|
entity.OnDestroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
[UnmanagedCallersOnly]
|
||||||
|
public static unsafe void CreateScriptInstance(UUID entityId, byte* scriptClassName)
|
||||||
|
{
|
||||||
|
using var _ = AssemblyLoadContext.EnterContextualReflection(_appAssembly);
|
||||||
|
|
||||||
|
Debug.Assert(_appAssembly != null);
|
||||||
|
|
||||||
|
string? typeName = Marshal.PtrToStringUTF8((IntPtr)scriptClassName);
|
||||||
|
|
||||||
|
Debug.Assert(typeName != null);
|
||||||
|
|
||||||
|
Type? scriptType = _appAssembly.GetType(typeName);
|
||||||
|
|
||||||
|
Debug.Assert(scriptType != null, "Script class Type not found.");
|
||||||
|
|
||||||
|
Entity? scriptInstance = ActivatorExtension.CreateEngineObject(scriptType, entityId) as Entity;
|
||||||
|
|
||||||
|
//
|
||||||
|
// // Get the constructor
|
||||||
|
// ConstructorInfo? constructor = scriptType.GetConstructor(
|
||||||
|
// BindingFlags.Instance | BindingFlags.Public,
|
||||||
|
// null,
|
||||||
|
// [],
|
||||||
|
// null);
|
||||||
|
//
|
||||||
|
// Debug.Assert(constructor != null, "Script class constructor not found.");
|
||||||
|
//
|
||||||
|
// // Call the constructor to create an instance
|
||||||
|
// Entity? scriptInstance = constructor?.Invoke(null) as Entity;
|
||||||
|
Debug.Assert(scriptInstance != null, "Failed to create script instance.");
|
||||||
|
//
|
||||||
|
// if (scriptInstance != null)
|
||||||
|
// scriptInstance._uuid = entityId;
|
||||||
|
|
||||||
|
//ScriptFunctions functions = new();
|
||||||
|
|
||||||
|
_entityScripts.Add(entityId, (scriptInstance!, scriptType));
|
||||||
|
|
||||||
|
//MethodInfo? onCreateMethod = scriptType.GetMethod("OnCreate", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||||
|
//if (onCreateMethod != null)
|
||||||
|
//{
|
||||||
|
// var v = MethodHelpers.GetFunctionPointerForNativeCode(onCreateMethod, null);
|
||||||
|
//}
|
||||||
|
//if (onCreateMethod != null)
|
||||||
|
//{
|
||||||
|
// //Delegate del = CreateDelegateWithTarget(onCreateMethod, scriptInstance);
|
||||||
|
|
||||||
|
// //var createDelegate = onCreateMethod.CreateDelegate<Action>(scriptInstance);
|
||||||
|
// //var createDelegate = onCreateMethod.CreateDelegate(typeof(OnCreateMethodDelegate), scriptInstance);
|
||||||
|
// //onCreateMethod.CreateDelegate(scriptInstance);
|
||||||
|
|
||||||
|
// //functions.OnCreateMethod = Marshal.GetFunctionPointerForDelegate(createDelegate);
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
// MethodInfo? onUpdateMethod = scriptType.GetMethod("OnUpdate", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||||
|
// if (onUpdateMethod != null)
|
||||||
|
// {
|
||||||
|
// // Create the delegate from your method and instance
|
||||||
|
// OnUpdateMethodDelegate onUpdateDelegate = (OnUpdateMethodDelegate)Delegate.CreateDelegate(typeof(OnUpdateMethodDelegate), scriptInstance, onUpdateMethod);
|
||||||
|
//
|
||||||
|
// // Get the function pointer from your delegate
|
||||||
|
// functions.OnUpdateMethod = Marshal.GetFunctionPointerForDelegate(onUpdateDelegate);
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
//functions.OnUpdateMethod = Marshal.GetFunctionPointerForDelegate((float deltaTime) => onUpdateMethod.Invoke(scriptInstance, new object?[]{ deltaTime }));
|
||||||
|
|
||||||
|
//MethodInfo? onDestroyMethod = scriptType.GetMethod("OnUpdate", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||||
|
//if (onDestroyMethod != null)
|
||||||
|
// functions.OnDestroyMethod = Marshal.GetFunctionPointerForDelegate(() => onDestroyMethod.Invoke(scriptInstance, null));
|
||||||
|
|
||||||
|
//return functions;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Delegate CreateDelegate(MethodInfo method)
|
||||||
|
{
|
||||||
|
if (method == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(method));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!method.IsStatic)
|
||||||
|
{
|
||||||
|
throw new ArgumentException("The provided method must be static.", nameof(method));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (method.IsGenericMethod)
|
||||||
|
{
|
||||||
|
throw new ArgumentException("The provided method must not be generic.", nameof(method));
|
||||||
|
}
|
||||||
|
|
||||||
|
return method.CreateDelegate(Expression.GetDelegateType(
|
||||||
|
(from parameter in method.GetParameters() select parameter.ParameterType)
|
||||||
|
.Concat(new[] { method.ReturnType })
|
||||||
|
.ToArray()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create delegate by methodinfo in target
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="method">method info</param>
|
||||||
|
/// <param name="target">A instance of the object which contains the method where will be execute</param>
|
||||||
|
/// <returns>delegate or null</returns>
|
||||||
|
public static Delegate? CreateDelegateWithTarget(MethodInfo? method, object? target)
|
||||||
|
{
|
||||||
|
if (method is null ||
|
||||||
|
target is null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
//if (method.IsStatic)
|
||||||
|
// return null;
|
||||||
|
|
||||||
|
if (method.IsGenericMethod)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
return method.CreateDelegate(Expression.GetDelegateType(
|
||||||
|
(from parameter in method.GetParameters() select parameter.ParameterType)
|
||||||
|
.Concat(new[] { method.ReturnType })
|
||||||
|
.ToArray()), target);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static class MethodHelpers
|
||||||
|
{
|
||||||
|
private const string DelegateTypesAssemblyName = "JitDelegateTypes";
|
||||||
|
|
||||||
|
private static ModuleBuilder _modBuilder;
|
||||||
|
|
||||||
|
private static ConcurrentDictionary<(string, object), Delegate> _delegatesCache;
|
||||||
|
private static ConcurrentDictionary<string, Type> _delegateTypesCache;
|
||||||
|
|
||||||
|
static MethodHelpers()
|
||||||
|
{
|
||||||
|
AssemblyBuilder asmBuilder = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName(DelegateTypesAssemblyName), AssemblyBuilderAccess.Run);
|
||||||
|
|
||||||
|
_modBuilder = asmBuilder.DefineDynamicModule(DelegateTypesAssemblyName);
|
||||||
|
|
||||||
|
_delegatesCache = new ConcurrentDictionary<(string, object), Delegate>();
|
||||||
|
_delegateTypesCache = new ConcurrentDictionary<string, Type>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IntPtr GetFunctionPointerForNativeCode(MethodInfo meth, object instance = null)
|
||||||
|
{
|
||||||
|
string funcName = GetFullName(meth);
|
||||||
|
|
||||||
|
Delegate dlg = _delegatesCache.GetOrAdd((funcName, instance), (_) =>
|
||||||
|
{
|
||||||
|
Type[] parameters = meth.GetParameters().Select(x => x.ParameterType).ToArray();
|
||||||
|
|
||||||
|
Type delegateType = GetDelegateType(parameters, meth.ReturnType);
|
||||||
|
|
||||||
|
return Delegate.CreateDelegate(delegateType, instance, meth);
|
||||||
|
});
|
||||||
|
|
||||||
|
return Marshal.GetFunctionPointerForDelegate<Delegate>(dlg);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GetFullName(MethodInfo meth)
|
||||||
|
{
|
||||||
|
return $"{meth.DeclaringType.FullName}.{meth.Name}";
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Type GetDelegateType(Type[] parameters, Type returnType)
|
||||||
|
{
|
||||||
|
string key = GetFunctionSignatureKey(parameters, returnType);
|
||||||
|
|
||||||
|
return _delegateTypesCache.GetOrAdd(key, (_) => MakeDelegateType(parameters, returnType, key));
|
||||||
|
}
|
||||||
|
|
||||||
|
private const MethodAttributes CtorAttributes =
|
||||||
|
MethodAttributes.RTSpecialName |
|
||||||
|
MethodAttributes.HideBySig |
|
||||||
|
MethodAttributes.Public;
|
||||||
|
|
||||||
|
private const MethodImplAttributes ImplAttributes =
|
||||||
|
MethodImplAttributes.Runtime |
|
||||||
|
MethodImplAttributes.Managed;
|
||||||
|
|
||||||
|
private const MethodAttributes InvokeAttributes =
|
||||||
|
MethodAttributes.Public |
|
||||||
|
MethodAttributes.HideBySig |
|
||||||
|
MethodAttributes.NewSlot |
|
||||||
|
MethodAttributes.Virtual;
|
||||||
|
|
||||||
|
private const TypeAttributes DelegateTypeAttributes =
|
||||||
|
TypeAttributes.Class |
|
||||||
|
TypeAttributes.Public |
|
||||||
|
TypeAttributes.Sealed |
|
||||||
|
TypeAttributes.AnsiClass |
|
||||||
|
TypeAttributes.AutoClass;
|
||||||
|
|
||||||
|
private static readonly Type[] _delegateCtorSignature = { typeof(object), typeof(IntPtr) };
|
||||||
|
|
||||||
|
private static Type MakeDelegateType(Type[] parameters, Type returnType, string name)
|
||||||
|
{
|
||||||
|
TypeBuilder builder = _modBuilder.DefineType(name, DelegateTypeAttributes, typeof(MulticastDelegate));
|
||||||
|
|
||||||
|
builder.DefineConstructor(CtorAttributes, CallingConventions.Standard, _delegateCtorSignature).SetImplementationFlags(ImplAttributes);
|
||||||
|
|
||||||
|
builder.DefineMethod("Invoke", InvokeAttributes, returnType, parameters).SetImplementationFlags(ImplAttributes);
|
||||||
|
|
||||||
|
return builder.CreateTypeInfo();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GetFunctionSignatureKey(Type[] parameters, Type returnType)
|
||||||
|
{
|
||||||
|
string sig = GetTypeName(returnType);
|
||||||
|
|
||||||
|
foreach (Type type in parameters)
|
||||||
|
{
|
||||||
|
sig += '_' + GetTypeName(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
return sig;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GetTypeName(Type type)
|
||||||
|
{
|
||||||
|
return type.FullName.Replace(".", string.Empty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
#region Log
|
#region Log
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
internal static unsafe void Log_LogMessage(Log.LogLevel logLevel, string message, string filePath, int line)
|
||||||
internal static extern void Log_LogMessage(Log.LogLevel logLevel, string message, string filePath, int line);
|
{
|
||||||
|
// unsafe
|
||||||
|
// {
|
||||||
|
// byte* mess = (byte*)Marshal.StringToCoTaskMemUTF8(message);
|
||||||
|
//
|
||||||
|
// fixed (char* messagePtr = message)
|
||||||
|
// fixed (char* filePathPtr = filePath)
|
||||||
|
// {
|
||||||
|
// _engineFunctions.Log_LogMessage(logLevel, messagePtr, filePathPtr, line);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// Marshal.FreeCoTaskMem((IntPtr)mess);
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||||
|
|||||||
@@ -148,7 +148,7 @@ public class DeserializationObject
|
|||||||
}
|
}
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Explicit)]
|
[StructLayout(LayoutKind.Explicit)]
|
||||||
private struct DataHelper
|
public struct DataHelper
|
||||||
{
|
{
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
public unsafe struct StringView
|
public unsafe struct StringView
|
||||||
|
|||||||
+1
Submodule vendor/NetHostBeef added at aeb099576d
Reference in New Issue
Block a user