mirror of
https://github.com/aharabada/glitchy-engine-beef.git
synced 2026-09-05 13:01:52 +00:00
Remove mono from Glue functions
This commit is contained in:
@@ -21,9 +21,11 @@ namespace GlitchyEditor.EditWindows
|
|||||||
|
|
||||||
public static this()
|
public static this()
|
||||||
{
|
{
|
||||||
ScriptGlue.OnRegisterNativeCalls.Add(new () => {
|
/*ScriptGlue.OnRegisterNativeCalls.Add(new () => {
|
||||||
ScriptGlue.RegisterCall<function bool(ref AssetHandle)>("ScriptGlue::ImGuiExtension_ShowAssetDropTarget", => ShowAssetDropTarget);
|
// TODO: Implement
|
||||||
});
|
Runtime.NotImplemented();
|
||||||
|
//ScriptGlue.RegisterCall<function bool(ref AssetHandle)>("ScriptGlue::ImGuiExtension_ShowAssetDropTarget", => ShowAssetDropTarget);
|
||||||
|
});*/
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void ShowComponents(Entity entity, Type componentType = null)
|
public static void ShowComponents(Entity entity, Type componentType = null)
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ class MessageSource
|
|||||||
/// If true, the message is only meant for engine developers... so only me :(
|
/// If true, the message is only meant for engine developers... so only me :(
|
||||||
public bool IsEngineMessage = false;
|
public bool IsEngineMessage = false;
|
||||||
|
|
||||||
public MonoExceptionHelper Exception = null ~ _?.ReleaseRef();
|
public ScriptException Exception = null ~ _?.ReleaseRef();
|
||||||
|
|
||||||
public String AdditionalData = null ~ delete _;
|
public String AdditionalData = null ~ delete _;
|
||||||
}
|
}
|
||||||
@@ -370,7 +370,7 @@ class LogWindow : EditorWindow
|
|||||||
_messages.Add(logMessage);
|
_messages.Add(logMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void LogException(DateTime timestamp, MonoExceptionHelper exception)
|
public void LogException(DateTime timestamp, ScriptException exception)
|
||||||
{
|
{
|
||||||
StringView firstLine = exception.StackTrace;
|
StringView firstLine = exception.StackTrace;
|
||||||
|
|
||||||
@@ -383,7 +383,7 @@ class LogWindow : EditorWindow
|
|||||||
message.AppendF($"Exception: \"{exception.FullName}\" | Message: \"{exception.Message}\" {firstLine}\0");
|
message.AppendF($"Exception: \"{exception.FullName}\" | Message: \"{exception.Message}\" {firstLine}\0");
|
||||||
|
|
||||||
// TODO: are mono exceptions never engine only?
|
// TODO: are mono exceptions never engine only?
|
||||||
LogMessage logMessage = new LogMessage(timestamp, message, .Error, new MessageSource(){Entity = exception.Instance, Exception = exception..AddRef(), IsEngineMessage = false});
|
LogMessage logMessage = new LogMessage(timestamp, message, .Error, new MessageSource(){Entity = exception.EntityId, Exception = exception..AddRef(), IsEngineMessage = false});
|
||||||
_messages.Add(logMessage);
|
_messages.Add(logMessage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -110,12 +110,12 @@ public class EditorLogger : Logger
|
|||||||
|
|
||||||
String message = scope String(4096);
|
String message = scope String(4096);
|
||||||
|
|
||||||
MonoExceptionHelper exceptionHelper = null;
|
ScriptException exceptionHelper = null;
|
||||||
MessageOrigin messageOrigin = null;
|
MessageOrigin messageOrigin = null;
|
||||||
|
|
||||||
if (args.Count > 0)
|
if (args.Count > 0)
|
||||||
{
|
{
|
||||||
exceptionHelper = args[^1] as MonoExceptionHelper;
|
exceptionHelper = args[^1] as ScriptException;
|
||||||
messageOrigin = args[^1] as MessageOrigin;
|
messageOrigin = args[^1] as MessageOrigin;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ abstract class Asset : RefCounter
|
|||||||
/// This identifier can be used to request the Asset from the content manager.
|
/// This identifier can be used to request the Asset from the content manager.
|
||||||
public StringView Identifier
|
public StringView Identifier
|
||||||
{
|
{
|
||||||
get => _identifier;
|
get => _identifier..EnsureNullTerminator();
|
||||||
set => _identifier.Set(value);
|
set => _identifier.Set(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -36,6 +36,12 @@ static class CoreClrHelper
|
|||||||
private function void CreateScriptInstanceFunc(UUID entityId, char8* scriptClassName);
|
private function void CreateScriptInstanceFunc(UUID entityId, char8* scriptClassName);
|
||||||
static CreateScriptInstanceFunc _createScriptInstance;
|
static CreateScriptInstanceFunc _createScriptInstance;
|
||||||
|
|
||||||
|
private function void ThrowExceptionFunc(char8* message);
|
||||||
|
static ThrowExceptionFunc _throwException;
|
||||||
|
|
||||||
|
private function void RegisterComponentTypeFunc(StringView fullComponentTypeName, function void(UUID entityId) addComponent, function bool(UUID entityId) hasComponent, function void(UUID entityId) removeComponent);
|
||||||
|
static RegisterComponentTypeFunc _registerComponentType;
|
||||||
|
|
||||||
public static ScriptFunctionPointers _entityScriptFunctions;
|
public static ScriptFunctionPointers _entityScriptFunctions;
|
||||||
|
|
||||||
public static void Init(StringView coreAssemblyPath)
|
public static void Init(StringView coreAssemblyPath)
|
||||||
@@ -106,6 +112,9 @@ static class CoreClrHelper
|
|||||||
|
|
||||||
GetFunctionPointerUnmanagedCallersOnly("GlitchyEngine.ScriptGlue, ScriptCore", "CreateScriptInstance", out _createScriptInstance);
|
GetFunctionPointerUnmanagedCallersOnly("GlitchyEngine.ScriptGlue, ScriptCore", "CreateScriptInstance", out _createScriptInstance);
|
||||||
|
|
||||||
|
GetFunctionPointerUnmanagedCallersOnly("GlitchyEngine.ScriptGlue, ScriptCore", "ThrowException", out _throwException);
|
||||||
|
GetFunctionPointerUnmanagedCallersOnly("GlitchyEngine.ScriptGlue, ScriptCore", "RegisterComponentType", out _registerComponentType);
|
||||||
|
|
||||||
InitEntityFunctions();
|
InitEntityFunctions();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -182,4 +191,14 @@ static class CoreClrHelper
|
|||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void ThrowException(StringView message)
|
||||||
|
{
|
||||||
|
_throwException(message.Ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void RegisterComponent(StringView fullComponentTypeName, function void(UUID entityId) addComponent, function bool(UUID entityId) hasComponent, function void(UUID entityId) removeComponent)
|
||||||
|
{
|
||||||
|
_registerComponentType(fullComponentTypeName, addComponent, hasComponent, removeComponent);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,21 +1,21 @@
|
|||||||
using System;
|
using System;
|
||||||
using GlitchyEngine.Core;
|
using GlitchyEngine.Core;
|
||||||
using Mono;
|
|
||||||
|
|
||||||
namespace GlitchyEngine.Scripting;
|
namespace GlitchyEngine.Scripting;
|
||||||
|
|
||||||
|
|
||||||
public class MonoExceptionHelper : RefCounter
|
public class ScriptException : RefCounter
|
||||||
{
|
{
|
||||||
private String _fullName ~ delete _;
|
private String _fullName ~ delete:append _;
|
||||||
|
|
||||||
private String _message ~ delete _;
|
private String _message ~ delete:append _;
|
||||||
|
|
||||||
private String _stackTrace ~ delete _;
|
private String _stackTrace ~ delete:append _;
|
||||||
/// The clean stack trace only contains the Managed Stack (the full trace contains one line for the native-to-managed entry)
|
/// The clean stack trace only contains the Managed Stack (the full trace contains one line for the native-to-managed entry)
|
||||||
private StringView _cleanStackTrace;
|
private StringView _cleanStackTrace;
|
||||||
|
|
||||||
private MonoExceptionHelper _innerException ~ _?.ReleaseRef();
|
//TODO
|
||||||
|
//private ScriptException _innerException ~ _?.ReleaseRef();
|
||||||
|
|
||||||
public StringView FullName => _fullName;
|
public StringView FullName => _fullName;
|
||||||
public StringView Message => _message;
|
public StringView Message => _message;
|
||||||
@@ -23,59 +23,22 @@ public class MonoExceptionHelper : RefCounter
|
|||||||
public StringView StackTrace => _stackTrace;
|
public StringView StackTrace => _stackTrace;
|
||||||
public StringView CleanStackTrace => _cleanStackTrace;
|
public StringView CleanStackTrace => _cleanStackTrace;
|
||||||
|
|
||||||
public MonoExceptionHelper InnerException => _innerException;
|
//public ScriptException InnerException => _innerException;
|
||||||
|
|
||||||
public UUID Instance { get; set; }
|
public UUID EntityId { get; set; }
|
||||||
|
|
||||||
public this(MonoException* exception)
|
[AllowAppend]
|
||||||
|
public this(UUID entityId, StringView fullExceptionClassName, StringView message, StringView stackTrace)
|
||||||
{
|
{
|
||||||
MonoObject* exObject = (MonoObject*)exception;
|
String allocFullExceptionClassName = append String(fullExceptionClassName);
|
||||||
|
String allocMessage = append String(fullExceptionClassName);
|
||||||
|
String allocStackTrace = append String(fullExceptionClassName);
|
||||||
|
|
||||||
MonoClass* monoClass = Mono.mono_object_get_class(exObject);
|
_fullName = allocFullExceptionClassName;
|
||||||
|
_message = allocMessage;
|
||||||
|
_stackTrace = allocStackTrace;
|
||||||
|
|
||||||
StringView classNamespace = .(Mono.mono_class_get_namespace(monoClass));
|
// TODO
|
||||||
StringView className = .(Mono.mono_class_get_name(monoClass));
|
|
||||||
_fullName = new $"{classNamespace}.{className}";
|
|
||||||
|
|
||||||
GetMessage(exObject, monoClass);
|
|
||||||
|
|
||||||
GetStackTrace(exception);
|
|
||||||
|
|
||||||
GetInnerException(exObject, monoClass);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void GetMessage(MonoObject* exceptionObject, MonoClass* monoClass)
|
|
||||||
{
|
|
||||||
var messageProperty = Mono.mono_class_get_property_from_name(monoClass, "Message");
|
|
||||||
|
|
||||||
MonoObject* message = Mono.mono_property_get_value(messageProperty, exceptionObject, null, null);
|
|
||||||
char8* exMessage = Mono.mono_string_to_utf8((.)message);
|
|
||||||
|
|
||||||
_message = new String(exMessage);
|
|
||||||
|
|
||||||
Mono.mono_free(exMessage);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void GetStackTrace(MonoException* exception)
|
|
||||||
{
|
|
||||||
char8* stacktracePtr = Mono.mono_exception_get_managed_backtrace(exception);
|
|
||||||
_stackTrace = new String(stacktracePtr);
|
|
||||||
|
|
||||||
int entryIndex = _stackTrace.IndexOf("at (wrapper native-to-managed)");
|
|
||||||
|
|
||||||
if (entryIndex != -1)
|
|
||||||
_cleanStackTrace = _stackTrace.Substring(0, entryIndex);
|
|
||||||
else
|
|
||||||
_cleanStackTrace = _stackTrace;
|
_cleanStackTrace = _stackTrace;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void GetInnerException(MonoObject* exceptionObject, MonoClass* monoClass)
|
|
||||||
{
|
|
||||||
MonoProperty* innerExceptionProperty = Mono.mono_class_get_property_from_name(monoClass, "InnerException");
|
|
||||||
|
|
||||||
MonoObject* innerException = Mono.mono_property_get_value(innerExceptionProperty, exceptionObject, null, null);
|
|
||||||
|
|
||||||
if (innerException != null)
|
|
||||||
_innerException = new MonoExceptionHelper((MonoException*)innerException);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -507,15 +507,18 @@ static class ScriptEngine
|
|||||||
return scriptClass;
|
return scriptClass;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static void HandleMonoException(MonoException* exception, UUID entityId)
|
internal static void HandleException()
|
||||||
{
|
{
|
||||||
MonoExceptionHelper wrappedException = new MonoExceptionHelper(exception);
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void LogScriptException(ScriptException exception, UUID entityId)
|
||||||
|
{
|
||||||
String entityInfo = scope .();
|
String entityInfo = scope .();
|
||||||
|
|
||||||
if (entityId != .Zero)
|
if (entityId != .Zero)
|
||||||
{
|
{
|
||||||
wrappedException.Instance = entityId;
|
exception.EntityId = entityId;
|
||||||
|
|
||||||
Result<Entity> sourceEntity = Context.GetEntityByID(entityId);
|
Result<Entity> sourceEntity = Context.GetEntityByID(entityId);
|
||||||
|
|
||||||
@@ -525,14 +528,13 @@ static class ScriptEngine
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Log.ClientLogger.Error($"Mono Exception \"{wrappedException.FullName}\": \"{wrappedException.Message}\"{entityInfo}\nStackTrace:\n{wrappedException.StackTrace}", wrappedException);
|
Log.ClientLogger.Error($"Mono Exception \"{exception.FullName}\": \"{exception.Message}\"{entityInfo}\nStackTrace:\n{exception.StackTrace}", exception);
|
||||||
|
|
||||||
wrappedException.ReleaseRef();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: This can go soon?
|
||||||
internal static void HandleMonoException(MonoException* exception, ScriptInstance sourceInstance = null)
|
internal static void HandleMonoException(MonoException* exception, ScriptInstance sourceInstance = null)
|
||||||
{
|
{
|
||||||
HandleMonoException(exception, sourceInstance?.EntityId ?? .Zero);
|
//LogScriptException(exception, sourceInstance?.EntityId ?? .Zero);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void ShowScriptEditor(Entity entity, ScriptComponent* scriptComponent)
|
public static void ShowScriptEditor(Entity entity, ScriptComponent* scriptComponent)
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -90,7 +90,7 @@ class SerializedObject
|
|||||||
Fields.Add(nameCopy, (fieldType, data));
|
Fields.Add(nameCopy, (fieldType, data));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddField(StringView name, SerializationType primitiveType, MonoObject* value, MonoString* fullTypeName)
|
public void AddField(StringView name, SerializationType primitiveType, void* value, StringView fullTypeName)
|
||||||
{
|
{
|
||||||
FieldData data = .();
|
FieldData data = .();
|
||||||
|
|
||||||
@@ -102,15 +102,10 @@ class SerializedObject
|
|||||||
|
|
||||||
if (value != null)
|
if (value != null)
|
||||||
{
|
{
|
||||||
MonoString* string = (.)value;
|
String stringValue = new String((char8*)value);
|
||||||
char8* rawStringValue = Mono.mono_string_to_utf8(string);
|
|
||||||
|
|
||||||
String stringValue = new String(rawStringValue);
|
|
||||||
|
|
||||||
_ownedString.Add(stringValue);
|
_ownedString.Add(stringValue);
|
||||||
|
|
||||||
Mono.mono_free(rawStringValue);
|
|
||||||
|
|
||||||
valueView = stringValue;
|
valueView = stringValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -118,21 +113,14 @@ class SerializedObject
|
|||||||
case .EngineObjectReference:
|
case .EngineObjectReference:
|
||||||
String typeName = null;
|
String typeName = null;
|
||||||
|
|
||||||
if (fullTypeName != null)
|
if (!fullTypeName.IsEmpty)
|
||||||
{
|
{
|
||||||
char8* rawTypeName = Mono.mono_string_to_utf8(fullTypeName);
|
_ownedString.Add(new String(fullTypeName));
|
||||||
typeName = new String(rawTypeName);
|
|
||||||
|
|
||||||
_ownedString.Add(typeName);
|
|
||||||
|
|
||||||
Mono.mono_free(rawTypeName);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
data.EngineObject = (FullTypeName: typeName, ID: *(UUID*)Mono.mono_object_unbox(value));
|
data.EngineObject = (FullTypeName: typeName, ID: *(UUID*)value);
|
||||||
default:
|
default:
|
||||||
void* rawValue = Mono.mono_object_unbox(value);
|
SetDataSimple(primitiveType, value, ref data);
|
||||||
|
|
||||||
SetDataSimple(primitiveType, rawValue, ref data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
AddField(name, primitiveType, data);
|
AddField(name, primitiveType, data);
|
||||||
|
|||||||
@@ -686,7 +686,7 @@ namespace GlitchyEngine.World
|
|||||||
|
|
||||||
private append List<Entity> _destroyQueue = .();
|
private append List<Entity> _destroyQueue = .();
|
||||||
|
|
||||||
private append List<ScriptInstance> _destroyScriptQueue = .();
|
private append List<NewScriptInstance> _destroyScriptQueue = .();
|
||||||
|
|
||||||
float physicsDelta = 0;
|
float physicsDelta = 0;
|
||||||
|
|
||||||
@@ -926,7 +926,7 @@ namespace GlitchyEngine.World
|
|||||||
* @param scriptInstance The script instance to destroy.
|
* @param scriptInstance The script instance to destroy.
|
||||||
* @param removeComponent If set to true the ScriptComponent will be removed from the entity.
|
* @param removeComponent If set to true the ScriptComponent will be removed from the entity.
|
||||||
*/
|
*/
|
||||||
public void DestroyScriptDeferred(ScriptInstance scriptInstance, bool removeComponent)
|
public void DestroyScriptDeferred(NewScriptInstance scriptInstance, bool removeComponent)
|
||||||
{
|
{
|
||||||
_destroyScriptQueue.Add(scriptInstance..AddRef());
|
_destroyScriptQueue.Add(scriptInstance..AddRef());
|
||||||
|
|
||||||
|
|||||||
+30
-12
@@ -70,12 +70,17 @@ public class Entity : EngineObject
|
|||||||
|
|
||||||
private void Create(string? name, Type[]? components)
|
private void Create(string? name, Type[]? components)
|
||||||
{
|
{
|
||||||
ScriptGlue.Entity_Create(this, name, components, out _uuid);
|
ScriptGlue.Entity_Create(name, out _uuid);
|
||||||
|
|
||||||
if (_uuid == UUID.Zero)
|
if (_uuid == UUID.Zero)
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException("Failed to create the Entity. Received UUID.Zero from the engine.");
|
throw new InvalidOperationException("Failed to create the Entity. Received UUID.Zero from the engine.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (components != null)
|
||||||
|
{
|
||||||
|
AddComponents(components);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -98,7 +103,10 @@ public class Entity : EngineObject
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="type">The type of the component.</param>
|
/// <param name="type">The type of the component.</param>
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public bool HasComponent(Type type) => ScriptGlue.Entity_HasComponent(_uuid, type);
|
public bool HasComponent(Type type)
|
||||||
|
{
|
||||||
|
return ScriptGlue.Entity_HasComponent(_uuid, type);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the component with the specified type.
|
/// Gets the component with the specified type.
|
||||||
@@ -208,8 +216,6 @@ public class Entity : EngineObject
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ScriptGlue.Entity_AddComponents(_uuid, componentTypes);
|
|
||||||
|
|
||||||
Component?[] components = new Component[componentTypes.Length];
|
Component?[] components = new Component[componentTypes.Length];
|
||||||
|
|
||||||
foreach ((Type componentType, int index) in componentTypes.WithIndex())
|
foreach ((Type componentType, int index) in componentTypes.WithIndex())
|
||||||
@@ -218,6 +224,8 @@ public class Entity : EngineObject
|
|||||||
if (componentType == null!)
|
if (componentType == null!)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
ScriptGlue.Entity_AddComponent(_uuid, componentType);
|
||||||
|
|
||||||
components[index] = ActivatorExtension.CreateComponent(componentType, _uuid);
|
components[index] = ActivatorExtension.CreateComponent(componentType, _uuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -232,7 +240,8 @@ public class Entity : EngineObject
|
|||||||
where T1 : Component, new()
|
where T1 : Component, new()
|
||||||
where T2 : Component, new()
|
where T2 : Component, new()
|
||||||
{
|
{
|
||||||
ScriptGlue.Entity_AddComponents(_uuid, new []{typeof(T1), typeof(T2)});
|
ScriptGlue.Entity_AddComponent(_uuid, typeof(T1));
|
||||||
|
ScriptGlue.Entity_AddComponent(_uuid, typeof(T2));
|
||||||
|
|
||||||
return (new T1 { _uuid = _uuid }, new T2 { _uuid = _uuid });
|
return (new T1 { _uuid = _uuid }, new T2 { _uuid = _uuid });
|
||||||
}
|
}
|
||||||
@@ -246,7 +255,9 @@ public class Entity : EngineObject
|
|||||||
where T2 : Component, new()
|
where T2 : Component, new()
|
||||||
where T3 : Component, new()
|
where T3 : Component, new()
|
||||||
{
|
{
|
||||||
ScriptGlue.Entity_AddComponents(_uuid, new []{typeof(T1), typeof(T2), typeof(T3)});
|
ScriptGlue.Entity_AddComponent(_uuid, typeof(T1));
|
||||||
|
ScriptGlue.Entity_AddComponent(_uuid, typeof(T2));
|
||||||
|
ScriptGlue.Entity_AddComponent(_uuid, typeof(T3));
|
||||||
|
|
||||||
return (new T1 { _uuid = _uuid }, new T2 { _uuid = _uuid }, new T3 { _uuid = _uuid });
|
return (new T1 { _uuid = _uuid }, new T2 { _uuid = _uuid }, new T3 { _uuid = _uuid });
|
||||||
}
|
}
|
||||||
@@ -285,7 +296,14 @@ public class Entity : EngineObject
|
|||||||
/// <returns>A reference to the new script or <see langword="null"/>, if the operation failed.</returns>
|
/// <returns>A reference to the new script or <see langword="null"/>, if the operation failed.</returns>
|
||||||
public T? SetScript<T>() where T : Entity
|
public T? SetScript<T>() where T : Entity
|
||||||
{
|
{
|
||||||
return ScriptGlue.Entity_SetScript(_uuid, typeof(T)) as T;
|
Entity? scriptInstance = null;
|
||||||
|
|
||||||
|
if (ScriptGlue.Entity_SetScript(_uuid, typeof(T).FullName))
|
||||||
|
{
|
||||||
|
ScriptGlue.Entity_GetScriptInstance(_uuid, out scriptInstance);
|
||||||
|
}
|
||||||
|
|
||||||
|
return scriptInstance as T;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -323,7 +341,7 @@ public class Entity : EngineObject
|
|||||||
/// <returns><see langword="true"/> if the <see cref="Entity"/> has a script component of the given type; or <see langword="false"/> if the <see cref="Entity"/> either has no script or the script is not of the specified type.</returns>
|
/// <returns><see langword="true"/> if the <see cref="Entity"/> has a script component of the given type; or <see langword="false"/> if the <see cref="Entity"/> either has no script or the script is not of the specified type.</returns>
|
||||||
public bool Is<T>() where T : Entity
|
public bool Is<T>() where T : Entity
|
||||||
{
|
{
|
||||||
ScriptGlue.Entity_GetScriptInstance(_uuid, out object? scriptInstance);
|
ScriptGlue.Entity_GetScriptInstance(_uuid, out Entity? scriptInstance);
|
||||||
|
|
||||||
return scriptInstance is T;
|
return scriptInstance is T;
|
||||||
}
|
}
|
||||||
@@ -341,7 +359,7 @@ public class Entity : EngineObject
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ScriptGlue.Entity_GetScriptInstance(_uuid, out object? scriptInstance);
|
ScriptGlue.Entity_GetScriptInstance(_uuid, out Entity? scriptInstance);
|
||||||
|
|
||||||
return type.IsInstanceOfType(scriptInstance);
|
return type.IsInstanceOfType(scriptInstance);
|
||||||
}
|
}
|
||||||
@@ -353,7 +371,7 @@ public class Entity : EngineObject
|
|||||||
/// <returns>The script instance of the given type; or <see langword="null"/> if the <see cref="Entity"/> has no script of the given type.</returns>
|
/// <returns>The script instance of the given type; or <see langword="null"/> if the <see cref="Entity"/> has no script of the given type.</returns>
|
||||||
public T? As<T>() where T : Entity
|
public T? As<T>() where T : Entity
|
||||||
{
|
{
|
||||||
ScriptGlue.Entity_GetScriptInstance(_uuid, out object? scriptInstance);
|
ScriptGlue.Entity_GetScriptInstance(_uuid, out Entity? scriptInstance);
|
||||||
|
|
||||||
return scriptInstance as T;
|
return scriptInstance as T;
|
||||||
}
|
}
|
||||||
@@ -371,7 +389,7 @@ public class Entity : EngineObject
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
ScriptGlue.Entity_GetScriptInstance(_uuid, out object? scriptInstance);
|
ScriptGlue.Entity_GetScriptInstance(_uuid, out Entity? scriptInstance);
|
||||||
|
|
||||||
return scriptInstance;
|
return scriptInstance;
|
||||||
}
|
}
|
||||||
@@ -386,7 +404,7 @@ public class Entity : EngineObject
|
|||||||
{
|
{
|
||||||
Debug.Assert(typeof(Entity).IsAssignableFrom(type));
|
Debug.Assert(typeof(Entity).IsAssignableFrom(type));
|
||||||
|
|
||||||
ScriptGlue.Entity_GetScriptInstance(id, out object? scriptInstance);
|
ScriptGlue.Entity_GetScriptInstance(id, out Entity? scriptInstance);
|
||||||
|
|
||||||
return scriptInstance as Entity;
|
return scriptInstance as Entity;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -77,7 +77,9 @@ public static class ImGuiExtension
|
|||||||
|
|
||||||
public static bool ShowAssetDropTarget(ref UUID uuid)
|
public static bool ShowAssetDropTarget(ref UUID uuid)
|
||||||
{
|
{
|
||||||
return ScriptGlue.ImGuiExtension_ShowAssetDropTarget(ref uuid);
|
// TODO: !!!
|
||||||
|
// return ScriptGlue.ImGuiExtension_ShowAssetDropTarget(ref uuid);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool Checkbox2(string label, ref bool2 value) => CheckboxN(2, label, ref value.X);
|
public static bool Checkbox2(string label, ref bool2 value) => CheckboxN(2, label, ref value.X);
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using System.Diagnostics.SymbolStore;
|
using System;
|
||||||
|
using System.Diagnostics.SymbolStore;
|
||||||
using GlitchyEngine.Core;
|
using GlitchyEngine.Core;
|
||||||
using GlitchyEngine.Math;
|
using GlitchyEngine.Math;
|
||||||
|
|
||||||
@@ -22,7 +23,7 @@ public class Material : Asset
|
|||||||
{
|
{
|
||||||
unsafe
|
unsafe
|
||||||
{
|
{
|
||||||
ScriptGlue.Material_SetVariable(_uuid, name, ShaderVariableType.Float, 1, 4, 1, &value, sizeof(float4));
|
ScriptGlue.Material_SetVariable(_uuid, name, ShaderVariableType.Float, 1, 4, 1, (IntPtr)(void*)&value, sizeof(float4));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -30,10 +30,20 @@ public class SpriteRenderer : Component
|
|||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
ScriptGlue.SpriteRenderer_GetUvTransform(_uuid, out UVTransform uvTransform);
|
unsafe
|
||||||
return uvTransform;
|
{
|
||||||
|
// TODO: Is this a type we want to have in the engine?
|
||||||
|
ScriptGlue.SpriteRenderer_GetUvTransform(_uuid, out float4 uvTransform);
|
||||||
|
return *(UVTransform*)&uvTransform;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
ScriptGlue.SpriteRenderer_SetUvTransform(_uuid, *(float4*)&value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
set => ScriptGlue.SpriteRenderer_SetUvTransform(_uuid, value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
+1
-1
@@ -141,6 +141,6 @@ public class Log
|
|||||||
/// <param name="exception">The exception to log.</param>
|
/// <param name="exception">The exception to log.</param>
|
||||||
public static void Exception(Exception exception)
|
public static void Exception(Exception exception)
|
||||||
{
|
{
|
||||||
ScriptGlue.Log_LogException(exception);
|
ScriptGlue.Log_LogException(UUID.Zero, exception.GetType().FullName, exception.Message, exception.StackTrace);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -152,16 +152,16 @@ public static partial class Math
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Splits the value x into fractional and integer parts, each of which has the same sign as x.
|
/// Splits the value x into fractional and integer parts, each of which has the same sign as x.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static float modf(float x, out float integerPart) => ScriptGlue.modf_float(x, out integerPart);
|
public static float modf(float x, out float integerPart) => ScriptGlue.Math_ModfFloat(x, out integerPart);
|
||||||
|
|
||||||
/// <inheritdoc cref="modf(float,out float)"/>
|
/// <inheritdoc cref="modf(float,out float)"/>
|
||||||
public static float2 modf(float2 x, out float2 integerPart) => ScriptGlue.modf_float2(x, out integerPart);
|
public static float2 modf(float2 x, out float2 integerPart) => ScriptGlue.Math_ModfFloat2(x, out integerPart);
|
||||||
|
|
||||||
/// <inheritdoc cref="modf(float2,out float2)"/>
|
/// <inheritdoc cref="modf(float2,out float2)"/>
|
||||||
public static float3 modf(float3 x, out float3 integerPart) => ScriptGlue.modf_float3(x, out integerPart);
|
public static float3 modf(float3 x, out float3 integerPart) => ScriptGlue.Math_ModfFloat3(x, out integerPart);
|
||||||
|
|
||||||
/// <inheritdoc cref="modf(float2,out float2)"/>
|
/// <inheritdoc cref="modf(float2,out float2)"/>
|
||||||
public static float4 modf(float4 x, out float4 integerPart) => ScriptGlue.modf_float4(x, out integerPart);
|
public static float4 modf(float4 x, out float4 integerPart) => ScriptGlue.Math_ModfFloat4(x, out integerPart);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns the fractional (or decimal) part of x; which is greater than or equal to 0 and less than 1.
|
/// Returns the fractional (or decimal) part of x; which is greater than or equal to 0 and less than 1.
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"profiles": {
|
||||||
|
"Start Editor": {
|
||||||
|
"commandName": "Executable",
|
||||||
|
"executablePath": "..\\build\\Debug_Win64\\GlitchyEditor\\GlitchyEditor.exe",
|
||||||
|
"commandLineArgs": "\"D:\\Development\\Git\\SingleStateToOrbit\"",
|
||||||
|
"workingDirectory": "..\\GlitchyEditor",
|
||||||
|
"nativeDebugging": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+138
-215
@@ -26,24 +26,31 @@ namespace GlitchyEngine;
|
|||||||
[StructLayout(LayoutKind.Sequential)]
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
internal unsafe partial struct EngineFunctions
|
internal unsafe partial struct EngineFunctions
|
||||||
{
|
{
|
||||||
//public delegate* unmanaged[Cdecl]<GlitchyEngine.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
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal static unsafe partial class ScriptGlue
|
internal static unsafe partial class ScriptGlue
|
||||||
{
|
{
|
||||||
#region Script Glueing infrastructure
|
#region Script Glueing infrastructure
|
||||||
|
|
||||||
static ScriptGlue()
|
static ScriptGlue()
|
||||||
|
{
|
||||||
|
ConfigureDllImportResolver();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ConfigureDllImportResolver()
|
||||||
{
|
{
|
||||||
NativeLibrary.SetDllImportResolver(typeof(ScriptGlue).Assembly, ImportResolver);
|
NativeLibrary.SetDllImportResolver(typeof(ScriptGlue).Assembly, ImportResolver);
|
||||||
// TODO: With this we can actually use the official ImGui.NET-Branch in the future!
|
// TODO: With this we can actually use the official ImGui.NET-Branch in the future!
|
||||||
NativeLibrary.SetDllImportResolver(typeof(ImGui).Assembly, ImportResolver);
|
NativeLibrary.SetDllImportResolver(typeof(ImGui).Assembly, ImportResolver);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Resolves an import request for the DLL <b>__Internal</b> (<c>[DllImport("__Internal")]</c>) to the current executable file.
|
||||||
|
/// This allows calling functions that are part of the native executable (e.g. native libraries we want to use from C# scripts).
|
||||||
|
/// </summary>
|
||||||
private static IntPtr ImportResolver(string libraryName, Assembly assembly, DllImportSearchPath? searchPath)
|
private static IntPtr ImportResolver(string libraryName, Assembly assembly, DllImportSearchPath? searchPath)
|
||||||
{
|
{
|
||||||
if (libraryName == "__Internal")
|
if (libraryName == "__Internal")
|
||||||
@@ -59,24 +66,34 @@ internal static unsafe partial class ScriptGlue
|
|||||||
return IntPtr.Zero;
|
return IntPtr.Zero;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private static EngineFunctions _engineFunctions;
|
private static EngineFunctions _engineFunctions;
|
||||||
|
|
||||||
|
private static AssemblyLoadContext? _scriptAssemblyContext;
|
||||||
|
|
||||||
|
private static Assembly? _appAssembly;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Entity script instances
|
||||||
|
/// </summary>
|
||||||
|
private static readonly Dictionary<UUID, (Entity Entity, Type Type)> EntityScriptInstances = new();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Called by the engine to provide a struct containing all functions pointers that can be called from C##
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="engineFunctions">The struct containing the function pointers to the engine functions.</param>
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
public static unsafe void SetEngineFunctions(EngineFunctions* engineFunctions)
|
public static void SetEngineFunctions(EngineFunctions* engineFunctions)
|
||||||
{
|
{
|
||||||
_engineFunctions = *engineFunctions;
|
_engineFunctions = *engineFunctions;
|
||||||
|
|
||||||
Log.Info("Yeah");
|
Log.Info("Yeah");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static AssemblyLoadContext? _scriptAssemblyContext;
|
/// <summary>
|
||||||
|
/// Called by the engine to load the provided assembly (containing user scripts) and optionally debug symbols.
|
||||||
private static Assembly? _appAssembly;
|
/// </summary>
|
||||||
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
public static unsafe void LoadScriptAssembly(byte* assemblyData, long assemblyLength, byte* pdbData, long pdbLength)
|
public static void LoadScriptAssembly(byte* assemblyData, long assemblyLength, byte* pdbData, long pdbLength)
|
||||||
{
|
{
|
||||||
using UnmanagedMemoryStream assemblyStream = new(assemblyData, assemblyLength);
|
using UnmanagedMemoryStream assemblyStream = new(assemblyData, assemblyLength);
|
||||||
|
|
||||||
@@ -101,6 +118,9 @@ internal static unsafe partial class ScriptGlue
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Called by the engine to unload the assembly (containing user scripts).
|
||||||
|
/// </summary>
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
public static void UnloadAssemblies()
|
public static void UnloadAssemblies()
|
||||||
{
|
{
|
||||||
@@ -108,15 +128,9 @@ internal static unsafe partial class ScriptGlue
|
|||||||
_scriptAssemblyContext = null;
|
_scriptAssemblyContext = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ScriptClassInfo
|
|
||||||
{
|
|
||||||
public byte[] Name;
|
|
||||||
public Guid Guid;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static NativeScriptClassInfo[]? _unsafeClasses;
|
private static NativeScriptClassInfo[]? _unsafeClasses;
|
||||||
|
|
||||||
struct NativeScriptClassInfo
|
public struct NativeScriptClassInfo
|
||||||
{
|
{
|
||||||
public IntPtr Name;
|
public IntPtr Name;
|
||||||
public Guid Guid;
|
public Guid Guid;
|
||||||
@@ -133,8 +147,16 @@ internal static unsafe partial class ScriptGlue
|
|||||||
OnDestroy = 0x4
|
OnDestroy = 0x4
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Called by the engine to receive a list of all script classes.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="outBuffer">Pointer to the array of <see cref="NativeScriptClassInfo"/>s</param>
|
||||||
|
/// <param name="length">The number of elements in <see cref="outBuffer"/></param>
|
||||||
|
/// <remarks>
|
||||||
|
/// The array returned by <see cref="outBuffer"/> must be freed using <see cref="FreeScriptClassNames"/>.
|
||||||
|
/// </remarks>
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
public static unsafe void GetScriptClasses(void** outBuffer, long* length)
|
public static void GetScriptClasses(NativeScriptClassInfo** outBuffer, long* length)
|
||||||
{
|
{
|
||||||
using var contextualReflection = AssemblyLoadContext.EnterContextualReflection(_appAssembly);
|
using var contextualReflection = AssemblyLoadContext.EnterContextualReflection(_appAssembly);
|
||||||
|
|
||||||
@@ -189,17 +211,20 @@ internal static unsafe partial class ScriptGlue
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
*outBuffer = (void*)Marshal.UnsafeAddrOfPinnedArrayElement(_unsafeClasses, 0);
|
*outBuffer = (NativeScriptClassInfo*)Marshal.UnsafeAddrOfPinnedArrayElement(_unsafeClasses, 0);
|
||||||
*length = _unsafeClasses.Length;
|
*length = _unsafeClasses.Length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Called by the engine to free the data allocated by <see cref="GetScriptClasses"/>
|
||||||
|
/// </summary>
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
public static void FreeScriptClassNames()
|
public static void FreeScriptClassNames()
|
||||||
{
|
{
|
||||||
Internal_FreeScriptClassNames();
|
Internal_FreeScriptClassNames();
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static void Internal_FreeScriptClassNames()
|
private static void Internal_FreeScriptClassNames()
|
||||||
{
|
{
|
||||||
if (_unsafeClasses == null)
|
if (_unsafeClasses == null)
|
||||||
return;
|
return;
|
||||||
@@ -212,21 +237,27 @@ internal static unsafe partial class ScriptGlue
|
|||||||
_unsafeClasses = null;
|
_unsafeClasses = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Dictionary<UUID, (Entity Entity, Type Type)> _entityScripts = new();
|
|
||||||
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
public static void ShowEntityEditor(UUID entityId)
|
public static void ShowEntityEditor(UUID entityId)
|
||||||
{
|
{
|
||||||
(Entity entity, Type type) = _entityScripts[entityId];
|
try
|
||||||
|
{
|
||||||
|
(Entity entity, Type type) = EntityScriptInstances[entityId];
|
||||||
EntityEditor.ShowEntityEditor(entity);
|
EntityEditor.ShowEntityEditor(entity);
|
||||||
}
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Console.WriteLine(e);
|
||||||
|
// TODO: Log exceptions to console
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
public static void InvokeEntityOnCreate(UUID entityId)
|
public static void InvokeEntityOnCreate(UUID entityId)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
(Entity entity, Type type) = _entityScripts[entityId];
|
(Entity entity, Type type) = EntityScriptInstances[entityId];
|
||||||
entity.OnCreate();
|
entity.OnCreate();
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
@@ -241,19 +272,19 @@ internal static unsafe partial class ScriptGlue
|
|||||||
{
|
{
|
||||||
// using var _ = AssemblyLoadContext.EnterContextualReflection(_appAssembly); // TODO: Check if reflection works correctly in entities
|
// using var _ = AssemblyLoadContext.EnterContextualReflection(_appAssembly); // TODO: Check if reflection works correctly in entities
|
||||||
|
|
||||||
(Entity entity, Type type) = _entityScripts[entityId];
|
(Entity entity, Type type) = EntityScriptInstances[entityId];
|
||||||
entity.OnUpdate(deltaTime);
|
entity.OnUpdate(deltaTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
public static void InvokeEntityOnDestroy(UUID entityId, float deltaTime)
|
public static void InvokeEntityOnDestroy(UUID entityId, float deltaTime)
|
||||||
{
|
{
|
||||||
(Entity entity, Type type) = _entityScripts[entityId];
|
(Entity entity, Type type) = EntityScriptInstances[entityId];
|
||||||
entity.OnDestroy();
|
entity.OnDestroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
public static unsafe void CreateScriptInstance(UUID entityId, byte* scriptClassName)
|
public static void CreateScriptInstance(UUID entityId, byte* scriptClassName)
|
||||||
{
|
{
|
||||||
using var _ = AssemblyLoadContext.EnterContextualReflection(_appAssembly);
|
using var _ = AssemblyLoadContext.EnterContextualReflection(_appAssembly);
|
||||||
|
|
||||||
@@ -269,212 +300,104 @@ internal static unsafe partial class ScriptGlue
|
|||||||
|
|
||||||
Entity? scriptInstance = ActivatorExtension.CreateEngineObject(scriptType, entityId) as Entity;
|
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.");
|
Debug.Assert(scriptInstance != null, "Failed to create script instance.");
|
||||||
//
|
|
||||||
// if (scriptInstance != null)
|
|
||||||
// scriptInstance._uuid = entityId;
|
|
||||||
|
|
||||||
//ScriptFunctions functions = new();
|
EntityScriptInstances.Add(entityId, (scriptInstance!, scriptType));
|
||||||
|
|
||||||
_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)
|
struct ComponentFunctionPointers
|
||||||
{
|
{
|
||||||
if (method == null)
|
public delegate* unmanaged[Cdecl]<UUID, void> AddComponent;
|
||||||
{
|
public delegate* unmanaged[Cdecl]<UUID, bool> HasComponent;
|
||||||
throw new ArgumentNullException(nameof(method));
|
public delegate* unmanaged[Cdecl]<UUID, void> RemoveComponent;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!method.IsStatic)
|
private static readonly Dictionary<Type, ComponentFunctionPointers> ComponentTypeFunctions = new();
|
||||||
|
|
||||||
|
[UnmanagedCallersOnly]
|
||||||
|
public static void RegisterComponentType(byte* fullComponentTypeName,
|
||||||
|
delegate* unmanaged[Cdecl]<UUID, void> addComponent,
|
||||||
|
delegate* unmanaged[Cdecl]<UUID, bool> hasComponent,
|
||||||
|
delegate* unmanaged[Cdecl]<UUID, void> removeComponent)
|
||||||
{
|
{
|
||||||
throw new ArgumentException("The provided method must be static.", nameof(method));
|
string? beefComponentTypeName = Marshal.PtrToStringUTF8((IntPtr)fullComponentTypeName);
|
||||||
}
|
|
||||||
|
|
||||||
if (method.IsGenericMethod)
|
if (beefComponentTypeName == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
foreach(Type componentType in TypeExtension.FindDerivedTypes(typeof(Component)))
|
||||||
{
|
{
|
||||||
throw new ArgumentException("The provided method must not be generic.", nameof(method));
|
if (!componentType.TryGetCustomAttribute(out EngineClassAttribute mapping) ||
|
||||||
}
|
mapping.EngineClassName != beefComponentTypeName) continue;
|
||||||
|
|
||||||
return method.CreateDelegate(Expression.GetDelegateType(
|
ComponentTypeFunctions[componentType] = new ComponentFunctionPointers
|
||||||
(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 ||
|
AddComponent = addComponent,
|
||||||
target is null)
|
HasComponent = hasComponent,
|
||||||
return null;
|
RemoveComponent = removeComponent
|
||||||
|
};
|
||||||
|
|
||||||
//if (method.IsStatic)
|
break;
|
||||||
// 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
|
#endregion
|
||||||
|
|
||||||
|
public static void Entity_AddComponent(UUID entityId, Type componentType)
|
||||||
|
{
|
||||||
|
ComponentTypeFunctions[componentType].AddComponent(entityId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool Entity_HasComponent(UUID entityId, Type componentType)
|
||||||
|
{
|
||||||
|
return ComponentTypeFunctions[componentType].HasComponent(entityId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Entity_RemoveComponent(UUID entityId, Type componentType)
|
||||||
|
{
|
||||||
|
ComponentTypeFunctions[componentType].RemoveComponent(entityId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Entity_GetScriptInstance(UUID entityId, out Entity? instance)
|
||||||
|
{
|
||||||
|
// We currently can implement this method here, because we only have C# scripts.
|
||||||
|
// If we ever need to do something to interop with other script languages, then this would change.
|
||||||
|
if (EntityScriptInstances.TryGetValue(entityId, out var match))
|
||||||
|
{
|
||||||
|
instance = match.Entity;
|
||||||
|
}
|
||||||
|
|
||||||
|
instance = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Serialization_SerializeField(IntPtr serializationContext, SerializationType type, string fieldName, object? valueObject, string fullTypeName)
|
||||||
|
{
|
||||||
|
byte* fieldNameConverted = (byte*)Marshal.StringToCoTaskMemUTF8(fieldName);
|
||||||
|
byte* fullTypeNameConverted = (byte*)Marshal.StringToCoTaskMemUTF8(fullTypeName);
|
||||||
|
|
||||||
|
void* valueObjectConverted = null;
|
||||||
|
bool deleteValueObject = false;
|
||||||
|
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case SerializationType.String:
|
||||||
|
valueObjectConverted = (void*)Marshal.StringToCoTaskMemUTF8(fullTypeName);
|
||||||
|
deleteValueObject = true;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (valueObject is not null)
|
||||||
|
valueObjectConverted = Unsafe.AsPointer(ref Unsafe.Unbox<byte>(valueObject));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
_engineFunctions.Serialization_SerializeField((void*)serializationContext, type, fieldNameConverted, valueObjectConverted, fullTypeNameConverted);
|
||||||
|
|
||||||
|
Marshal.FreeCoTaskMem((IntPtr)fieldNameConverted);
|
||||||
|
Marshal.FreeCoTaskMem((IntPtr)fullTypeNameConverted);
|
||||||
|
|
||||||
|
if (deleteValueObject)
|
||||||
|
Marshal.FreeCoTaskMem((IntPtr)valueObjectConverted);
|
||||||
|
}
|
||||||
|
|
||||||
//#region Log
|
//#region Log
|
||||||
|
|
||||||
|
|||||||
@@ -100,6 +100,8 @@ public class ScriptGlueGenerator : IIncrementalGenerator
|
|||||||
public string? WrapperConvertInput;
|
public string? WrapperConvertInput;
|
||||||
public string? WrapperCleanupInput;
|
public string? WrapperCleanupInput;
|
||||||
|
|
||||||
|
public string? WrapperOutConversion;
|
||||||
|
|
||||||
public string? ReturnValueConversion = "return returnValue;";
|
public string? ReturnValueConversion = "return returnValue;";
|
||||||
|
|
||||||
public string CSharpWrapperType
|
public string CSharpWrapperType
|
||||||
@@ -238,6 +240,17 @@ public class ScriptGlueGenerator : IIncrementalGenerator
|
|||||||
WrapperCleanupInput = "}}"
|
WrapperCleanupInput = "}}"
|
||||||
});
|
});
|
||||||
|
|
||||||
|
beefTypeToMappedType.Add("char8*", new MappedType
|
||||||
|
{
|
||||||
|
BeefTypeName = "char8*",
|
||||||
|
CSharpTypeName = "byte*",
|
||||||
|
CSharpWrapperType = "string",
|
||||||
|
ReturnValueConversion = "return Marshal.PtrToStringUTF8((IntPtr)returnValue);",
|
||||||
|
WrapperConvertInput = "byte* {0} = (byte*)Marshal.StringToCoTaskMemUTF8({1});",
|
||||||
|
WrapperCleanupInput = "Marshal.FreeCoTaskMem((IntPtr){0});",
|
||||||
|
WrapperOutConversion = "{1} = Marshal.PtrToStringUTF8((IntPtr){0}) ?? \"\";"
|
||||||
|
});
|
||||||
|
|
||||||
beefTypeToMappedType.Add("int32", new MappedType
|
beefTypeToMappedType.Add("int32", new MappedType
|
||||||
{
|
{
|
||||||
BeefTypeName = "int32",
|
BeefTypeName = "int32",
|
||||||
@@ -249,6 +262,16 @@ public class ScriptGlueGenerator : IIncrementalGenerator
|
|||||||
BeefTypeName = "System.Numerics.Quaternion",
|
BeefTypeName = "System.Numerics.Quaternion",
|
||||||
ReturnValueConversion = null
|
ReturnValueConversion = null
|
||||||
});
|
});
|
||||||
|
|
||||||
|
beefTypeToMappedType.Add("void*", new MappedType
|
||||||
|
{
|
||||||
|
BeefTypeName = "void*",
|
||||||
|
CSharpTypeName = "void*",
|
||||||
|
CSharpWrapperType = "IntPtr",
|
||||||
|
ReturnValueConversion = "return (IntPtr)returnValue;",
|
||||||
|
WrapperConvertInput = "void* {0} = (void*){1};",
|
||||||
|
WrapperOutConversion = "{1} = (IntPtr){0};"
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void GenerateFunctionPointer(GlueMethod method, Dictionary<string, MappedType> beefTypeToMappedType, StringBuilder output)
|
private static void GenerateFunctionPointer(GlueMethod method, Dictionary<string, MappedType> beefTypeToMappedType, StringBuilder output)
|
||||||
@@ -341,7 +364,17 @@ public class ScriptGlueGenerator : IIncrementalGenerator
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parameterType.WrapperConvertInput is not null)
|
if (parameterModifier == TypeModifier.Out && parameterType.WrapperOutConversion is not null)
|
||||||
|
{
|
||||||
|
string tmpArgName = $"{param.Name}Tmp";
|
||||||
|
|
||||||
|
call.Append($"var {tmpArgName}");
|
||||||
|
|
||||||
|
cleanup.Append("\t\t");
|
||||||
|
cleanup.AppendFormat(parameterType.WrapperOutConversion, tmpArgName, param.Name);
|
||||||
|
cleanup.AppendLine();
|
||||||
|
}
|
||||||
|
else if (parameterType.WrapperConvertInput is not null)
|
||||||
{
|
{
|
||||||
string convertedParamName = $"{param.Name}Converted";
|
string convertedParamName = $"{param.Name}Converted";
|
||||||
|
|
||||||
@@ -422,7 +455,9 @@ public class ScriptGlueGenerator : IIncrementalGenerator
|
|||||||
|
|
||||||
wrappers.Append("""
|
wrappers.Append("""
|
||||||
// <auto-generated />
|
// <auto-generated />
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace GlitchyEngine;
|
namespace GlitchyEngine;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user