diff --git a/GlitchyEngine/src/Scripting/NewScriptClass.bf b/GlitchyEngine/src/Scripting/NewScriptClass.bf index c1f09c6..9a4b4b9 100644 --- a/GlitchyEngine/src/Scripting/NewScriptClass.bf +++ b/GlitchyEngine/src/Scripting/NewScriptClass.bf @@ -1,5 +1,6 @@ using System; using GlitchyEngine.Core; +using GlitchyEngine.Scripting.Classes; using static GlitchyEngine.Scripting.ScriptEngine; @@ -16,7 +17,8 @@ class NewScriptClass public this(StringView fullName, Guid guid, ScriptMethods methods, bool runInEditMode = false) { - FullName = new String(fullName); + // TODO: Remove the need for null termination + FullName = new String(fullName)..EnsureNullTerminator(); Guid = guid; int lastDotIndex = FullName.LastIndexOf('.'); diff --git a/GlitchyEngine/src/Scripting/ScriptEngine.bf b/GlitchyEngine/src/Scripting/ScriptEngine.bf index c7efea0..4d53cf6 100644 --- a/GlitchyEngine/src/Scripting/ScriptEngine.bf +++ b/GlitchyEngine/src/Scripting/ScriptEngine.bf @@ -302,7 +302,7 @@ static class ScriptEngine //ScriptGlue.RegisterManagedComponents(); } - //InitAssemblyWatcher(); + InitAssemblyWatcher(); } /// Starts the script runtime and sets the context scene. @@ -343,8 +343,6 @@ static class ScriptEngine /// Disposes of and replaces the old instance, if one exists. public static bool InitializeInstance(Entity entity, ScriptComponent* script) { - Log.EngineLogger.Error($"{Compiler.CallerMemberName} not updated yet."); - NewScriptClass scriptClass = GetScriptClass(script.ScriptClassName); if (scriptClass == null) @@ -480,16 +478,6 @@ static class ScriptEngine s_RootDomain = null;*/ } - // TODO: Do we still need this? It was only called by ScriptGlue - /// Returns the script instance or null. - public static void* GetManagedInstance(UUID entityId) - { - //if (_entityScriptInstances.TryGetValue(entityId, let scriptInstance)) - // return scriptInstance.MonoInstance; - - return null; - } - public static NewScriptClass GetScriptClass(StringView name) { EntityClasses.TryGetValue(name, let scriptClass); @@ -501,7 +489,7 @@ static class ScriptEngine { String entityInfo = scope .(); - if (entityId != .Zero) + if (entityId != .Zero && Context != null) { exception.EntityId = entityId; diff --git a/GlitchyEngine/src/Scripting/ScriptGlue.bf b/GlitchyEngine/src/Scripting/ScriptGlue.bf index 40945e8..01ce165 100644 --- a/GlitchyEngine/src/Scripting/ScriptGlue.bf +++ b/GlitchyEngine/src/Scripting/ScriptGlue.bf @@ -44,6 +44,7 @@ class MessageOrigin } } +[AttributeUsage(.Method)] struct RegisterCallAttribute : Attribute { public bool EngineResultAsBool { get; set mut; } @@ -85,9 +86,18 @@ struct EngineFunctionsGeneratorAttribute : Attribute, IComptimeTypeApply if (type.IsEnum) { + // Pass the underlying integer type for enums. value.AppendF($" : {type.UnderlyingType}"); } + else if (!type.HasCustomAttribute() && !type.IsPrimitive && !type.IsPointer && !(type is RefType)) + { + // For CDecl Functions beef ecpects non CRepr struct to be passed as readonly ref. + // Thus we add in to the type name. However primitive types are passed by value! + value.Insert(0, "in "); + } + // EngineResult will usually just be converted to exceptions -> script method returns void + // But sometimes we want to be able to also return a boolean value. if (type == typeof(EngineResult) && callAttribute.HasValue) { if (callAttribute.Value.EngineResultAsBool) @@ -106,6 +116,8 @@ struct EngineFunctionsGeneratorAttribute : Attribute, IComptimeTypeApply private static void GenerateJsonInfo(MethodInfo method, RegisterCallAttribute registerCallAttribute, String outString) { String parameters = new String(); + + StringView str = method.Name; for (int i < method.ParamCount) { @@ -151,7 +163,7 @@ struct EngineFunctionsGeneratorAttribute : Attribute, IComptimeTypeApply parameters.AppendF($"{methodInfo.GetParamType(i)}"); } - String line = scope $"public function {methodInfo.ReturnType}({parameters}) {methodInfo.Name};\n"; + String line = scope $"public function [CallingConvention(.Cdecl)] {methodInfo.ReturnType}({parameters}) {methodInfo.Name};\n"; Compiler.EmitTypeBody(self, line); @@ -410,16 +422,16 @@ static class ScriptGlue } } - [RegisterCall] - static char8* GetLastExceptionMessage() + [RegisterCall, CallingConvention(.Cdecl)] + static StringView GetLastExceptionMessage() { - return _lastExceptionMessage.Length == 0 ? null : _lastExceptionMessage.CStr(); + return _lastExceptionMessage; } #region Log - [RegisterCall] - static void Log_LogMessage(LogLevel logLevel, char8* messagePtr, char8* fileNamePtr, int lineNumber) + [RegisterCall, CallingConvention(.Cdecl)] + static void Log_LogMessage(LogLevel logLevel, StringView messagePtr, StringView fileNamePtr, int lineNumber) { String escapedMessage = new:ScopedAlloc! String(messagePtr); @@ -427,7 +439,7 @@ static class ScriptGlue escapedMessage.Replace("{", "{{"); escapedMessage.Replace("}", "}}"); - if (fileNamePtr != null) + if (!fileNamePtr.IsEmpty) { String fileName = new:ScopedAlloc! String(fileNamePtr); @@ -441,11 +453,10 @@ static class ScriptGlue } } - [RegisterCall] - static void Log_LogException(UUID entityId, char8* fullExceptionClassName, char8* exceptionMessage, char8* stackTrace) + [RegisterCall, CallingConvention(.Cdecl)] + static void Log_LogException(UUID entityId, StringView fullExceptionClassName, StringView exceptionMessage, StringView stackTrace) { - ScriptException exception = new ScriptException(entityId, StringView(fullExceptionClassName), StringView(exceptionMessage), StringView(stackTrace)); - + ScriptException exception = new ScriptException(entityId, fullExceptionClassName, exceptionMessage, stackTrace); ScriptEngine.LogScriptException(exception, entityId); } @@ -453,47 +464,47 @@ static class ScriptGlue #region Input - [RegisterCall] + [RegisterCall, CallingConvention(.Cdecl)] static bool Input_IsKeyPressed(Key key) => Input.IsKeyPressed(key); - [RegisterCall] + [RegisterCall, CallingConvention(.Cdecl)] static bool Input_IsKeyReleased(Key key) => Input.IsKeyReleased(key); - [RegisterCall] + [RegisterCall, CallingConvention(.Cdecl)] static bool Input_IsKeyToggled(Key key) => Input.IsKeyToggled(key); - [RegisterCall] + [RegisterCall, CallingConvention(.Cdecl)] static bool Input_IsKeyPressing(Key key) => Input.IsKeyPressing(key); - [RegisterCall] + [RegisterCall, CallingConvention(.Cdecl)] static bool Input_IsKeyReleasing(Key key) => Input.IsKeyReleasing(key); - [RegisterCall] + [RegisterCall, CallingConvention(.Cdecl)] static bool Input_IsMouseButtonPressed(MouseButton mouseButton) => Input.IsMouseButtonPressed(mouseButton); - [RegisterCall] + [RegisterCall, CallingConvention(.Cdecl)] static bool Input_IsMouseButtonReleased(MouseButton mouseButton) => Input.IsMouseButtonReleased(mouseButton); - [RegisterCall] + [RegisterCall, CallingConvention(.Cdecl)] static bool Input_IsMouseButtonPressing(MouseButton mouseButton) => Input.IsMouseButtonPressing(mouseButton); - [RegisterCall] + [RegisterCall, CallingConvention(.Cdecl)] static bool Input_IsMouseButtonReleasing(MouseButton mouseButton) => Input.IsMouseButtonReleasing(mouseButton); #endregion Input #region Scene/Entity stuff - [RegisterCall] - static void Entity_Create(char8* entityName, out UUID entityId) + [RegisterCall, CallingConvention(.Cdecl)] + static void Entity_Create(StringView entityName, out UUID entityId) { - Entity entity = ScriptEngine.Context.CreateEntity(StringView(entityName)); + Entity entity = ScriptEngine.Context.CreateEntity(entityName); entityId = entity.UUID; } - [RegisterCall] + [RegisterCall, CallingConvention(.Cdecl)] static EngineResult Entity_Destroy(UUID entityId) { Entity entity = GetEntityOrReturnError!(entityId); @@ -501,7 +512,7 @@ static class ScriptGlue return .Ok; } - [RegisterCall] + [RegisterCall, CallingConvention(.Cdecl)] static EngineResult Entity_CreateInstance(UUID entityId, out UUID newEntityId) { newEntityId = ?; @@ -512,21 +523,19 @@ static class ScriptGlue return .Ok; } - [RegisterCall] - static void Entity_FindEntityWithName(char8* entityName, out UUID outUuid) + [RegisterCall, CallingConvention(.Cdecl)] + static void Entity_FindEntityWithName(StringView entityName, out UUID outUuid) { outUuid = UUID(0); - StringView nameString = StringView(entityName); - - Result entityResult = ScriptEngine.Context.GetEntityByName(nameString); + Result entityResult = ScriptEngine.Context.GetEntityByName(entityName); if (entityResult case .Ok(let entity)) outUuid = entity.UUID; } // TODO: Do we need this? - [RegisterCall] + [RegisterCall, CallingConvention(.Cdecl)] static EngineResult Entity_GetScriptInstance(UUID entityId, out void* instance) { instance = ?; @@ -534,8 +543,8 @@ static class ScriptGlue //instance = ScriptEngine.GetManagedInstance(entityId); } - [RegisterCall(EngineResultAsBool = true)] - static EngineResult Entity_SetScript(UUID entityId, char8* fullScriptTypeName) + [RegisterCall(EngineResultAsBool = true), CallingConvention(.Cdecl)] + static EngineResult Entity_SetScript(UUID entityId, StringView fullScriptTypeName) { Entity entity = GetEntityOrReturnError!(entityId); @@ -555,7 +564,7 @@ static class ScriptGlue scriptComponent.Instance = null; - scriptComponent.ScriptClassName = StringView(fullScriptTypeName); + scriptComponent.ScriptClassName = fullScriptTypeName; // Initializes the created instance // TODO: this returns false, if no script with ScriptClassName exists, we have to handle this case correctly I think. @@ -568,7 +577,7 @@ static class ScriptGlue return .Ok; } - [RegisterCall] + [RegisterCall, CallingConvention(.Cdecl)] static EngineResult Entity_RemoveScript(UUID entityId) { ScriptComponent* scriptComponent = GetComponentOrReturn!(entityId); @@ -578,27 +587,27 @@ static class ScriptGlue return .Ok; } - [RegisterCall] - static char8* Entity_GetName(UUID entityId) + [RegisterCall, CallingConvention(.Cdecl)] + static StringView Entity_GetName(UUID entityId) { Result foundEntity = ScriptEngine.Context.GetEntityByID(entityId); if (foundEntity case .Ok(let entity)) { - return entity.Name.Ptr; + return entity.Name; } return null; } - [RegisterCall] - static EngineResult Entity_SetName(UUID entityId, char8* name) + [RegisterCall, CallingConvention(.Cdecl)] + static EngineResult Entity_SetName(UUID entityId, StringView name) { - GetEntityOrReturnError!(entityId).Name = StringView(name); + GetEntityOrReturnError!(entityId).Name = name; return .Ok; } - [RegisterCall] + [RegisterCall, CallingConvention(.Cdecl)] static void Entity_GetEditorFlags(UUID entityId, out EditorFlags editorFlags) { editorFlags = .Default; @@ -608,7 +617,7 @@ static class ScriptGlue #endif } - [RegisterCall] + [RegisterCall, CallingConvention(.Cdecl)] static void Entity_SetEditorFlags(UUID entityId, EditorFlags editorFlags) { #if GE_EDITOR @@ -621,7 +630,7 @@ static class ScriptGlue #region TransformComponen - [RegisterCall] + [RegisterCall, CallingConvention(.Cdecl)] static EngineResult Transform_GetParent(UUID entityId, out UUID parentId) { parentId = .Zero; @@ -632,8 +641,8 @@ static class ScriptGlue return .Ok; } - [RegisterCall] - static EngineResult Transform_SetParent(UUID entityId, in UUID newParentId) + [RegisterCall, CallingConvention(.Cdecl)] + static EngineResult Transform_SetParent(UUID entityId, UUID newParentId) { Entity entity = GetEntityOrReturnError!(entityId); @@ -648,7 +657,7 @@ static class ScriptGlue return .Ok; } - [RegisterCall] + [RegisterCall, CallingConvention(.Cdecl)] static EngineResult Transform_GetTranslation(UUID entityId, out float3 translation) { translation = ?; @@ -658,7 +667,7 @@ static class ScriptGlue return .Ok; } - [RegisterCall] + [RegisterCall, CallingConvention(.Cdecl)] static EngineResult Transform_SetTranslation(UUID entityId, in float3 translation) { Entity entity = GetEntityOrReturnError!(entityId); @@ -673,7 +682,7 @@ static class ScriptGlue return .Ok; } - [RegisterCall] + [RegisterCall, CallingConvention(.Cdecl)] static EngineResult Transform_GetWorldTranslation(UUID entityId, out float3 translationWorld) { translationWorld = ?; @@ -685,7 +694,7 @@ static class ScriptGlue return .Ok; } - [RegisterCall] + [RegisterCall, CallingConvention(.Cdecl)] static EngineResult Transform_SetWorldTranslation(UUID entityId, in float3 translation) { Log.ClientLogger.Warning("Transform_SetWorldTranslation is not implemented!"); @@ -703,7 +712,7 @@ static class ScriptGlue // TODO: we need to handle repositioning of colliders that are children of the entity with rigidbody... } - [RegisterCall] + [RegisterCall, CallingConvention(.Cdecl)] static EngineResult Transform_TransformPointToWorld(UUID entityId, float3 point, out float3 pointWorld) { pointWorld = ?; @@ -715,7 +724,7 @@ static class ScriptGlue return .Ok; } - [RegisterCall] + [RegisterCall, CallingConvention(.Cdecl)] static EngineResult Transform_GetRotation(UUID entityId, out Quaternion rotation) { rotation = ?; @@ -725,7 +734,7 @@ static class ScriptGlue return .Ok; } - [RegisterCall] + [RegisterCall, CallingConvention(.Cdecl)] static EngineResult Transform_SetRotation(UUID entityId, in Quaternion rotation) { Entity entity = GetEntityOrReturnError!(entityId); @@ -740,7 +749,7 @@ static class ScriptGlue return .Ok; } - [RegisterCall] + [RegisterCall, CallingConvention(.Cdecl)] static EngineResult Transform_GetRotationEuler(UUID entityId, out float3 rotationEuler) { rotationEuler = ?; @@ -750,7 +759,7 @@ static class ScriptGlue return .Ok; } - [RegisterCall] + [RegisterCall, CallingConvention(.Cdecl)] static EngineResult Transform_SetRotationEuler(UUID entityId, in float3 rotationEuler) { Entity entity = GetEntityOrReturnError!(entityId); @@ -777,7 +786,7 @@ static class ScriptGlue } } - [RegisterCall] + [RegisterCall, CallingConvention(.Cdecl)] static EngineResult Transform_GetRotationAxisAngle(UUID entityId, out AxisAngle rotationAxisAngle) { rotationAxisAngle = ?; @@ -787,7 +796,7 @@ static class ScriptGlue return .Ok; } - [RegisterCall] + [RegisterCall, CallingConvention(.Cdecl)] static EngineResult Transform_SetRotationAxisAngle(UUID entityId, AxisAngle rotationAxisAngle) { Entity entity = GetEntityOrReturnError!(entityId); @@ -801,7 +810,7 @@ static class ScriptGlue return .Ok; } - [RegisterCall] + [RegisterCall, CallingConvention(.Cdecl)] static EngineResult Transform_GetScale(UUID entityId, out float3 scale) { scale = ?; @@ -811,7 +820,7 @@ static class ScriptGlue return .Ok; } - [RegisterCall] + [RegisterCall, CallingConvention(.Cdecl)] static EngineResult Transform_SetScale(UUID entityId, float3 scale) { Entity entity = GetEntityOrReturnError!(entityId); @@ -829,113 +838,113 @@ static class ScriptGlue #region Rigidbody2 - [RegisterCall] + [RegisterCall, CallingConvention(.Cdecl)] static void Rigidbody2D_ApplyForce(UUID entityId, in float2 force, in float2 point, bool wakeUp) { Rigidbody2DComponent* rigidBody = GetComponentSafe(entityId); Box2D.Body.ApplyForce(rigidBody.[Friend]RuntimeBody, force, point, wakeUp); } - [RegisterCall] + [RegisterCall, CallingConvention(.Cdecl)] static void Rigidbody2D_ApplyForceToCenter(UUID entityId, in float2 force, bool wakeUp) { Rigidbody2DComponent* rigidBody = GetComponentSafe(entityId); Box2D.Body.ApplyForceToCenter(rigidBody.[Friend]RuntimeBody, force, wakeUp); } - [RegisterCall] + [RegisterCall, CallingConvention(.Cdecl)] static void Rigidbody2D_SetPosition(UUID entityId, in float2 position) { Rigidbody2DComponent* rigidBody = GetComponentSafe(entityId); rigidBody.SetPosition(position); } - [RegisterCall] + [RegisterCall, CallingConvention(.Cdecl)] static void Rigidbody2D_GetPosition(UUID entityId, out float2 position) { Rigidbody2DComponent* rigidBody = GetComponentSafe(entityId); position = rigidBody.GetPosition(); } - [RegisterCall] - static void Rigidbody2D_SetRotation(UUID entityId, in float rotation) + [RegisterCall, CallingConvention(.Cdecl)] + static void Rigidbody2D_SetRotation(UUID entityId, float rotation) { Rigidbody2DComponent* rigidBody = GetComponentSafe(entityId); rigidBody.SetAngle(rotation); } - [RegisterCall] + [RegisterCall, CallingConvention(.Cdecl)] static void Rigidbody2D_GetRotation(UUID entityId, out float rotation) { Rigidbody2DComponent* rigidBody = GetComponentSafe(entityId); rotation = rigidBody.GetAngle(); } - [RegisterCall] + [RegisterCall, CallingConvention(.Cdecl)] static void Rigidbody2D_GetLinearVelocity(UUID entityId, out float2 velocity) { Rigidbody2DComponent* rigidBody = GetComponentSafe(entityId); velocity = rigidBody.GetLinearVelocity(); } - [RegisterCall] + [RegisterCall, CallingConvention(.Cdecl)] static void Rigidbody2D_SetLinearVelocity(UUID entityId, in float2 velocity) { Rigidbody2DComponent* rigidBody = GetComponentSafe(entityId); rigidBody.SetLinearVelocity(velocity); } - [RegisterCall] + [RegisterCall, CallingConvention(.Cdecl)] static void Rigidbody2D_GetAngularVelocity(UUID entityId, out float velocity) { Rigidbody2DComponent* rigidBody = GetComponentSafe(entityId); velocity = rigidBody.GetAngularVelocity(); } - [RegisterCall] - static void Rigidbody2D_SetAngularVelocity(UUID entityId, in float velocity) + [RegisterCall, CallingConvention(.Cdecl)] + static void Rigidbody2D_SetAngularVelocity(UUID entityId, float velocity) { Rigidbody2DComponent* rigidBody = GetComponentSafe(entityId); rigidBody.SetAngularVelocity(velocity); } - [RegisterCall] + [RegisterCall, CallingConvention(.Cdecl)] static void Rigidbody2D_GetBodyType(UUID entityId, out Rigidbody2DComponent.BodyType bodyType) { Rigidbody2DComponent* rigidBody = GetComponentSafe(entityId); bodyType = rigidBody.BodyType; } - [RegisterCall] - static void Rigidbody2D_SetBodyType(UUID entityId, in Rigidbody2DComponent.BodyType bodyType) + [RegisterCall, CallingConvention(.Cdecl)] + static void Rigidbody2D_SetBodyType(UUID entityId, Rigidbody2DComponent.BodyType bodyType) { Rigidbody2DComponent* rigidBody = GetComponentSafe(entityId); rigidBody.BodyType = bodyType; } - [RegisterCall] + [RegisterCall, CallingConvention(.Cdecl)] static void Rigidbody2D_IsFixedRotation(UUID entityId, out bool isFixedRotation) { Rigidbody2DComponent* rigidBody = GetComponentSafe(entityId); isFixedRotation = rigidBody.FixedRotation; } - [RegisterCall] - static void Rigidbody2D_SetFixedRotation(UUID entityId, in bool isFixedRotation) + [RegisterCall, CallingConvention(.Cdecl)] + static void Rigidbody2D_SetFixedRotation(UUID entityId, bool isFixedRotation) { Rigidbody2DComponent* rigidBody = GetComponentSafe(entityId); rigidBody.FixedRotation = isFixedRotation; } - [RegisterCall] + [RegisterCall, CallingConvention(.Cdecl)] static void Rigidbody2D_GetGravityScale(UUID entityId, out float gravityScale) { Rigidbody2DComponent* rigidBody = GetComponentSafe(entityId); gravityScale = rigidBody.GravityScale; } - [RegisterCall] - static void Rigidbody2D_SetGravityScale(UUID entityId, in float gravityScale) + [RegisterCall, CallingConvention(.Cdecl)] + static void Rigidbody2D_SetGravityScale(UUID entityId, float gravityScale) { Rigidbody2DComponent* rigidBody = GetComponentSafe(entityId); rigidBody.GravityScale = gravityScale; @@ -945,126 +954,126 @@ static class ScriptGlue #region Camer - [RegisterCall] + [RegisterCall, CallingConvention(.Cdecl)] static void Camera_GetProjectionType(UUID entityId, out SceneCamera.ProjectionType projectionType) { CameraComponent* camera = GetComponentSafe(entityId); projectionType = camera.Camera.ProjectionType; } - [RegisterCall] - static void Camera_SetProjectionType(UUID entityId, in SceneCamera.ProjectionType projectionType) + [RegisterCall, CallingConvention(.Cdecl)] + static void Camera_SetProjectionType(UUID entityId, SceneCamera.ProjectionType projectionType) { CameraComponent* camera = GetComponentSafe(entityId); camera.Camera.ProjectionType = projectionType; } - [RegisterCall] + [RegisterCall, CallingConvention(.Cdecl)] static void Camera_GetPerspectiveFovY(UUID entityId, out float fovY) { CameraComponent* camera = GetComponentSafe(entityId); fovY = camera.Camera.PerspectiveFovY; } - [RegisterCall] + [RegisterCall, CallingConvention(.Cdecl)] static void Camera_SetPerspectiveFovY(UUID entityId, float fovY) { CameraComponent* camera = GetComponentSafe(entityId); camera.Camera.PerspectiveFovY = fovY; } - [RegisterCall] + [RegisterCall, CallingConvention(.Cdecl)] static void Camera_GetPerspectiveNearPlane(UUID entityId, out float nearPlane) { CameraComponent* camera = GetComponentSafe(entityId); nearPlane = camera.Camera.PerspectiveNearPlane; } - [RegisterCall] + [RegisterCall, CallingConvention(.Cdecl)] static void Camera_SetPerspectiveNearPlane(UUID entityId, float nearPlane) { CameraComponent* camera = GetComponentSafe(entityId); camera.Camera.PerspectiveNearPlane = nearPlane; } - [RegisterCall] + [RegisterCall, CallingConvention(.Cdecl)] static void Camera_GetPerspectiveFarPlane(UUID entityId, out float farPlane) { CameraComponent* camera = GetComponentSafe(entityId); farPlane = camera.Camera.PerspectiveFarPlane; } - [RegisterCall] + [RegisterCall, CallingConvention(.Cdecl)] static void Camera_SetPerspectiveFarPlane(UUID entityId, float farPlane) { CameraComponent* camera = GetComponentSafe(entityId); camera.Camera.PerspectiveFarPlane = farPlane; } - [RegisterCall] + [RegisterCall, CallingConvention(.Cdecl)] static void Camera_GetOrthographicHeight(UUID entityId, out float height) { CameraComponent* camera = GetComponentSafe(entityId); height = camera.Camera.OrthographicHeight; } - [RegisterCall] + [RegisterCall, CallingConvention(.Cdecl)] static void Camera_SetOrthographicHeight(UUID entityId, float height) { CameraComponent* camera = GetComponentSafe(entityId); camera.Camera.OrthographicHeight = height; } - [RegisterCall] + [RegisterCall, CallingConvention(.Cdecl)] static void Camera_SetOrthographicNearPlane(UUID entityId, float nearPlane) { CameraComponent* camera = GetComponentSafe(entityId); camera.Camera.OrthographicNearPlane = nearPlane; } - [RegisterCall] + [RegisterCall, CallingConvention(.Cdecl)] static void Camera_GetOrthographicNearPlane(UUID entityId, out float nearPlane) { CameraComponent* camera = GetComponentSafe(entityId); nearPlane = camera.Camera.OrthographicNearPlane; } - [RegisterCall] + [RegisterCall, CallingConvention(.Cdecl)] static void Camera_SetOrthographicFarPlane(UUID entityId, float farPlane) { CameraComponent* camera = GetComponentSafe(entityId); camera.Camera.OrthographicFarPlane = farPlane; } - [RegisterCall] + [RegisterCall, CallingConvention(.Cdecl)] static void Camera_GetOrthographicFarPlane(UUID entityId, out float farPlane) { CameraComponent* camera = GetComponentSafe(entityId); farPlane = camera.Camera.OrthographicFarPlane; } - [RegisterCall] + [RegisterCall, CallingConvention(.Cdecl)] static void Camera_SetAspectRatio(UUID entityId, float aspectRatio) { CameraComponent* camera = GetComponentSafe(entityId); camera.Camera.AspectRatio = aspectRatio; } - [RegisterCall] + [RegisterCall, CallingConvention(.Cdecl)] static void Camera_GetAspectRatio(UUID entityId, out float aspectRatio) { CameraComponent* camera = GetComponentSafe(entityId); aspectRatio = camera.Camera.AspectRatio; } - [RegisterCall] + [RegisterCall, CallingConvention(.Cdecl)] static void Camera_SetFixedAspectRatio(UUID entityId, bool fixedAspectRatio) { CameraComponent* camera = GetComponentSafe(entityId); camera.Camera.FixedAspectRatio = fixedAspectRatio; } - [RegisterCall] + [RegisterCall, CallingConvention(.Cdecl)] static void Camera_GetFixedAspectRatio(UUID entityId, out bool fixedAspectRatio) { CameraComponent* camera = GetComponentSafe(entityId); @@ -1077,7 +1086,7 @@ static class ScriptGlue // TODO: We need a wrapper class! - [RegisterCall] + [RegisterCall, CallingConvention(.Cdecl)] static void Physics2D_GetGravity(out float2 gravity) { Scene scene = ScriptEngine.Context; @@ -1085,7 +1094,7 @@ static class ScriptGlue gravity = scene.Physics2DSettings.Gravity; } - [RegisterCall] + [RegisterCall, CallingConvention(.Cdecl)] static void Physics2D_SetGravity(in float2 gravity) { Scene scene = ScriptEngine.Context; @@ -1098,42 +1107,42 @@ static class ScriptGlue // TODO: Do we even need the circle renderer? #region CircleRenderer - [RegisterCall] + [RegisterCall, CallingConvention(.Cdecl)] static void CircleRenderer_GetColor(UUID entityId, out ColorRGBA color) { CircleRendererComponent* circleRenderer = GetComponentSafe(entityId); color = circleRenderer.Color; } - [RegisterCall] + [RegisterCall, CallingConvention(.Cdecl)] static void CircleRenderer_SetColor(UUID entityId, ColorRGBA color) { CircleRendererComponent* circleRenderer = GetComponentSafe(entityId); circleRenderer.Color = color; } - [RegisterCall] + [RegisterCall, CallingConvention(.Cdecl)] static void CircleRenderer_GetUvTransform(UUID entityId, out float4 uvTransform) { CircleRendererComponent* circleRenderer = GetComponentSafe(entityId); uvTransform = circleRenderer.UvTransform; } - [RegisterCall] + [RegisterCall, CallingConvention(.Cdecl)] static void CircleRenderer_SetUvTransform(UUID entityId, float4 uvTransform) { CircleRendererComponent* circleRenderer = GetComponentSafe(entityId); circleRenderer.UvTransform = uvTransform; } - [RegisterCall] + [RegisterCall, CallingConvention(.Cdecl)] static void CircleRenderer_GetInnerRadius(UUID entityId, out float innerRadius) { CircleRendererComponent* circleRenderer = GetComponentSafe(entityId); innerRadius = circleRenderer.InnerRadius; } - [RegisterCall] + [RegisterCall, CallingConvention(.Cdecl)] static void CircleRenderer_SetInnerRadius(UUID entityId, float innerRadius) { CircleRendererComponent* circleRenderer = GetComponentSafe(entityId); @@ -1144,7 +1153,7 @@ static class ScriptGlue #region SpriteRenderer - [RegisterCall] + [RegisterCall, CallingConvention(.Cdecl)] static EngineResult SpriteRenderer_GetColor(UUID entityId, out ColorRGBA color) { color = ?; @@ -1153,7 +1162,7 @@ static class ScriptGlue return .Ok; } - [RegisterCall] + [RegisterCall, CallingConvention(.Cdecl)] static EngineResult SpriteRenderer_SetColor(UUID entityId, ColorRGBA color) { SpriteRendererComponent* spriteRenderer = GetComponentOrReturn!(entityId); @@ -1161,7 +1170,7 @@ static class ScriptGlue return .Ok; } - [RegisterCall] + [RegisterCall, CallingConvention(.Cdecl)] static EngineResult SpriteRenderer_GetUvTransform(UUID entityId, out float4 uvTransform) { uvTransform = ?; @@ -1170,7 +1179,7 @@ static class ScriptGlue return .Ok; } - [RegisterCall] + [RegisterCall, CallingConvention(.Cdecl)] static EngineResult SpriteRenderer_SetUvTransform(UUID entityId, float4 uvTransform) { SpriteRendererComponent* spriteRenderer = GetComponentOrReturn!(entityId); @@ -1178,7 +1187,7 @@ static class ScriptGlue return .Ok; } - [RegisterCall] + [RegisterCall, CallingConvention(.Cdecl)] static EngineResult SpriteRenderer_GetMaterial(UUID entityId, out AssetHandle assetId) { assetId = ?; @@ -1200,7 +1209,7 @@ static class ScriptGlue return .Ok; } - [RegisterCall] + [RegisterCall, CallingConvention(.Cdecl)] static EngineResult SpriteRenderer_SetMaterial(UUID entityId, AssetHandle assetId) { SpriteRendererComponent* spriteRenderer = GetComponentOrReturn!(entityId); @@ -1213,14 +1222,14 @@ static class ScriptGlue #region TextRenderer - [RegisterCall(EngineResultAsBool = true)] + [RegisterCall(EngineResultAsBool = true), CallingConvention(.Cdecl)] static EngineResult TextRenderer_GetIsRichText(UUID entityId) { TextRendererComponent* textComponent = GetComponentOrReturn!(entityId); return textComponent.IsRichText ? .Ok : .False; } - [RegisterCall] + [RegisterCall, CallingConvention(.Cdecl)] static EngineResult TextRenderer_SetIsRichText(UUID entityId, bool isRichText) { TextRendererComponent* textComponent = GetComponentOrReturn!(entityId); @@ -1231,28 +1240,28 @@ static class ScriptGlue return .Ok; } - [RegisterCall] - static EngineResult TextRenderer_GetText(UUID entityId, out char8* text) + [RegisterCall, CallingConvention(.Cdecl)] + static EngineResult TextRenderer_GetText(UUID entityId, out StringView text) { text = ?; TextRendererComponent* textComponent = GetComponentOrReturn!(entityId); - text = textComponent.Text.Ptr; + text = textComponent.Text; return .Ok; } - [RegisterCall] - static EngineResult TextRenderer_SetText(UUID entityId, char8* text) + [RegisterCall, CallingConvention(.Cdecl)] + static EngineResult TextRenderer_SetText(UUID entityId, StringView text) { TextRendererComponent* textComponent = GetComponentOrReturn!(entityId); - textComponent.Text = StringView(text); + textComponent.Text = text; textComponent.NeedsRebuild = true; return .Ok; } - [RegisterCall] + [RegisterCall, CallingConvention(.Cdecl)] static EngineResult TextRenderer_GetColor(UUID entityId, out ColorRGBA color) { color = ?; @@ -1262,7 +1271,7 @@ static class ScriptGlue return .Ok; } - [RegisterCall] + [RegisterCall, CallingConvention(.Cdecl)] static EngineResult TextRenderer_SetColor(UUID entityId, ColorRGBA color) { TextRendererComponent* textComponent = GetComponentOrReturn!(entityId); @@ -1272,7 +1281,7 @@ static class ScriptGlue return .Ok; } - [RegisterCall] + [RegisterCall, CallingConvention(.Cdecl)] static EngineResult TextRenderer_GetHorizontalAlignment(UUID entityId, [GlueParam("out HorizontalTextAlignment")] out HorizontalTextAlignment horizontalAlignment) { horizontalAlignment = ?; @@ -1281,7 +1290,7 @@ static class ScriptGlue return .Ok; } - [RegisterCall] + [RegisterCall, CallingConvention(.Cdecl)] static EngineResult TextRenderer_SetHorizontalAlignment(UUID entityId, [GlueParam("HorizontalTextAlignment")] HorizontalTextAlignment horizontalAlignment) { TextRendererComponent* textComponent = GetComponentOrReturn!(entityId); @@ -1290,7 +1299,7 @@ static class ScriptGlue return .Ok; } - [RegisterCall] + [RegisterCall, CallingConvention(.Cdecl)] static EngineResult TextRenderer_GetFontSize(UUID entityId, out float fontSize) { fontSize = ?; @@ -1299,7 +1308,7 @@ static class ScriptGlue return .Ok; } - [RegisterCall] + [RegisterCall, CallingConvention(.Cdecl)] static EngineResult TextRenderer_SetFontSize(UUID entityId, float fontSize) { TextRendererComponent* textComponent = GetComponentOrReturn!(entityId); @@ -1315,7 +1324,7 @@ static class ScriptGlue #region MeshRenderer - [RegisterCall] + [RegisterCall, CallingConvention(.Cdecl)] static EngineResult MeshRenderer_GetMaterial(UUID entityId, out AssetHandle assetId) { assetId = ?; @@ -1337,7 +1346,7 @@ static class ScriptGlue return .Ok; } - [RegisterCall] + [RegisterCall, CallingConvention(.Cdecl)] static EngineResult MeshRenderer_GetSharedMaterial(UUID entityId, out AssetHandle assetId) { assetId = ?; @@ -1356,7 +1365,7 @@ static class ScriptGlue return .Ok; } - [RegisterCall] + [RegisterCall, CallingConvention(.Cdecl)] static EngineResult MeshRenderer_SetMaterial(UUID entityId, AssetHandle assetId) { MeshRendererComponent* meshRenderer = GetComponentOrReturn!(entityId); @@ -1368,25 +1377,25 @@ static class ScriptGlue #region Math - [RegisterCall] + [RegisterCall, CallingConvention(.Cdecl)] static float Math_ModfFloat(float x, out float integerPart) { return modf(x, out integerPart); } - [RegisterCall] + [RegisterCall, CallingConvention(.Cdecl)] static float2 Math_ModfFloat2(float2 x, out float2 integerPart) { return modf(x, out integerPart); } - [RegisterCall] + [RegisterCall, CallingConvention(.Cdecl)] static float3 Math_ModfFloat3(float3 x, out float3 integerPart) { return modf(x, out integerPart); } - [RegisterCall] + [RegisterCall, CallingConvention(.Cdecl)] static float4 Math_ModfFloat4(float4 x, out float4 integerPart) { return modf(x, out integerPart); @@ -1394,7 +1403,7 @@ static class ScriptGlue #endregion - [RegisterCall] + [RegisterCall, CallingConvention(.Cdecl)] static void UUID_Create(out UUID id) { id = UUID.Create(); @@ -1402,25 +1411,25 @@ static class ScriptGlue #region Application - [RegisterCall] + [RegisterCall, CallingConvention(.Cdecl)] static bool Application_IsEditor() { return ScriptEngine.ApplicationInfo.IsEditor; } - [RegisterCall] + [RegisterCall, CallingConvention(.Cdecl)] static bool Application_IsPlayer() { return ScriptEngine.ApplicationInfo.IsPlayer; } - [RegisterCall] + [RegisterCall, CallingConvention(.Cdecl)] static bool Application_IsInEditMode() { return ScriptEngine.ApplicationInfo.IsInEditMode; } - [RegisterCall] + [RegisterCall, CallingConvention(.Cdecl)] static bool Application_IsInPlayMode() { return ScriptEngine.ApplicationInfo.IsInPlayMode; @@ -1430,40 +1439,40 @@ static class ScriptGlue #region Serialization - [RegisterCall] - static void Serialization_SerializeField(void* serializationContext, SerializationType type, char8* fieldName, void* valueObject, char8* fullTypeName) + [RegisterCall, CallingConvention(.Cdecl)] + static void Serialization_SerializeField(void* serializationContext, SerializationType type, StringView fieldName, void* valueObject, StringView fullTypeName) { SerializedObject context = Internal.UnsafeCastToObject(serializationContext) as SerializedObject; Log.EngineLogger.AssertDebug(context != null); - context.AddField(StringView(fieldName), type, valueObject, StringView(fullTypeName)); + context.AddField(fieldName, type, valueObject, fullTypeName); } - [RegisterCall] - static void Serialization_CreateObject(void* currentContext, bool isStatic, char8* typeName, out void* newContext, out UUID newId) + [RegisterCall, CallingConvention(.Cdecl)] + static void Serialization_CreateObject(void* currentContext, bool isStatic, StringView typeName, out void* newContext, out UUID newId) { SerializedObject context = Internal.UnsafeCastToObject(currentContext) as SerializedObject; Log.EngineLogger.AssertDebug(context != null); - SerializedObject newObject = new SerializedObject(context.Serializer, isStatic, StringView(typeName)); + SerializedObject newObject = new SerializedObject(context.Serializer, isStatic, typeName); newContext = Internal.UnsafeCastToPtr(newObject); newId = newObject.Id; } - [RegisterCall] - public static void Serialization_DeserializeField(void* internalContext, SerializationType expectedType, char8* fieldName, uint8* target, out SerializationType actualType) + [RegisterCall, CallingConvention(.Cdecl)] + public static void Serialization_DeserializeField(void* internalContext, SerializationType expectedType, StringView fieldName, uint8* target, out SerializationType actualType) { SerializedObject context = Internal.UnsafeCastToObject(internalContext) as SerializedObject; Log.EngineLogger.AssertDebug(context != null); - context.GetField(StringView(fieldName), expectedType, target, out actualType); + context.GetField(fieldName, expectedType, target, out actualType); } - [RegisterCall] + [RegisterCall, CallingConvention(.Cdecl)] public static void Serialization_GetObject(void* internalContext, UUID id, out void* objectContext) { SerializedObject context = Internal.UnsafeCastToObject(internalContext) as SerializedObject; @@ -1480,14 +1489,14 @@ static class ScriptGlue objectContext = Internal.UnsafeCastToPtr(foundObject); } - [RegisterCall] - public static void Serialization_GetObjectTypeName(void* internalContext, out char8* fullTypeName) + [RegisterCall, CallingConvention(.Cdecl)] + public static void Serialization_GetObjectTypeName(void* internalContext, out StringView fullTypeName) { SerializedObject context = Internal.UnsafeCastToObject(internalContext) as SerializedObject; Log.EngineLogger.AssertDebug(context != null); - fullTypeName = context.TypeName.CStr(); + fullTypeName = context.TypeName; } #endregion @@ -1539,18 +1548,18 @@ static class ScriptGlue asset } - [RegisterCall] - static EngineResult Asset_GetIdentifier(UUID assetId, out char8* identifier) + [RegisterCall, CallingConvention(.Cdecl)] + static EngineResult Asset_GetIdentifier(UUID assetId, out StringView identifier) { identifier = ?; Asset asset = GetAssetOrReturn!(assetId); - identifier = asset.Identifier.Ptr; + identifier = asset.Identifier; return .Ok; } - [RegisterCall] - static EngineResult Asset_SetIdentifier(UUID assetId, char8* identifier) + [RegisterCall, CallingConvention(.Cdecl)] + static EngineResult Asset_SetIdentifier(UUID assetId, StringView identifier) { return .NotImplemented; @@ -1569,28 +1578,26 @@ static class ScriptGlue #region Material - [RegisterCall] - static EngineResult Material_SetVariable(AssetHandle assetHandle, char8* variableName, ShaderVariableType elementType, int32 rows, int32 columns, int32 arrayLength, void* rawData, int32 dataLength) + [RegisterCall, CallingConvention(.Cdecl)] + static EngineResult Material_SetVariable(AssetHandle assetHandle, StringView variableName, ShaderVariableType elementType, int32 rows, int32 columns, int32 arrayLength, void* rawData, int32 dataLength) { Material material = GetAssetOrReturn!(assetHandle); - StringView variableNameView = StringView(variableName); - - if (material.[Friend]SetVariableRaw(variableNameView, elementType, rows, columns , arrayLength, Span((uint8*)rawData, dataLength)) case .Err(let error)) + if (material.[Friend]SetVariableRaw(variableName, elementType, rows, columns , arrayLength, Span((uint8*)rawData, dataLength)) case .Err(let error)) { switch (error) { case .VariableNotFound: - SetExceptionMessage(scope $"Material \"{material.Identifier}\" has no variable \"{variableNameView}\"."); + SetExceptionMessage(scope $"Material \"{material.Identifier}\" has no variable \"{variableName}\"."); return .ArgumentError; case .ElementTypeMismatch: - SetExceptionMessage(scope $"Variable \"{variableNameView}\" has incompatible element type."); + SetExceptionMessage(scope $"Variable \"{variableName}\" has incompatible element type."); return .ArgumentError; case .MatrixDimensionMismatch: - SetExceptionMessage(scope $"Variable \"{variableNameView}\" has incompatible matrix dimension type."); + SetExceptionMessage(scope $"Variable \"{variableName}\" has incompatible matrix dimension type."); return .ArgumentError; case .ProvidedBufferTooShort: - SetExceptionMessage(scope $"The provided data buffer for variable \"{variableNameView}\" is not large enough."); + SetExceptionMessage(scope $"The provided data buffer for variable \"{variableName}\" is not large enough."); } return .Error; } @@ -1598,33 +1605,33 @@ static class ScriptGlue return .Ok; } - [RegisterCall] - static EngineResult Material_ResetVariable(AssetHandle assetHandle, char8* variableName) + [RegisterCall, CallingConvention(.Cdecl)] + static EngineResult Material_ResetVariable(AssetHandle assetHandle, StringView variableName) { Material material = GetAssetOrReturn!(assetHandle); - material.ResetVariable(StringView(variableName)); + material.ResetVariable(variableName); return .Ok; } - [RegisterCall] - static EngineResult Material_SetTexture(AssetHandle materialHandle, char8* variableName, AssetHandle textureHandle) + [RegisterCall, CallingConvention(.Cdecl)] + static EngineResult Material_SetTexture(AssetHandle materialHandle, StringView variableName, AssetHandle textureHandle) { Material material = GetAssetOrReturn!(materialHandle); - material.SetTexture(StringView(variableName), textureHandle); + material.SetTexture(variableName, textureHandle); return .Ok; } - [RegisterCall] - static EngineResult Material_GetTexture(AssetHandle materialHandle, char8* variableName, out AssetHandle textureHandle) + [RegisterCall, CallingConvention(.Cdecl)] + static EngineResult Material_GetTexture(AssetHandle materialHandle, StringView variableName, out AssetHandle textureHandle) { textureHandle = ?; Material material = GetAssetOrReturn!(materialHandle); - var v = material.GetTexture(StringView(variableName), ?); + var v = material.GetTexture(variableName, ?); if (v case .Err(let err)) { @@ -1636,12 +1643,12 @@ static class ScriptGlue return .Ok; } - [RegisterCall] - static EngineResult Material_ResetTexture(AssetHandle materialHandle, char8* variableName) + [RegisterCall, CallingConvention(.Cdecl)] + static EngineResult Material_ResetTexture(AssetHandle materialHandle, StringView variableName) { Material material = GetAssetOrReturn!(materialHandle); - material.ResetTexture(StringView(variableName)); + material.ResetTexture(variableName); return .Ok; } @@ -1650,7 +1657,7 @@ static class ScriptGlue #region ImGui Extension - [RegisterCall] + [RegisterCall, CallingConvention(.Cdecl)] static void ImGuiExtension_ListElementGrabber() { ImGui.ImGui.ListElementGrabber(); diff --git a/GlitchyEngine/src/World/Scene.bf b/GlitchyEngine/src/World/Scene.bf index f850792..65bb1d5 100644 --- a/GlitchyEngine/src/World/Scene.bf +++ b/GlitchyEngine/src/World/Scene.bf @@ -407,9 +407,8 @@ namespace GlitchyEngine.World collision.Rigidbody = rigidbodyEntityA.UUID; collision.OtherRigidbody = rigidbodyEntityB.UUID; - // TODO: - //scriptOfColliderA?.Instance?.InvokeOnCollisionEnter2D(collision); - //scriptOfRigidbodyA?.Instance?.InvokeOnCollisionEnter2D(collision); + scriptOfColliderA?.Instance?.InvokeOnCollisionEnter2D(collision); + scriptOfRigidbodyA?.Instance?.InvokeOnCollisionEnter2D(collision); } bool fireEventB = colliderEntityB.TryGetComponent(let scriptOfColliderB); @@ -423,8 +422,8 @@ namespace GlitchyEngine.World collision.Rigidbody = rigidbodyEntityB.UUID; collision.OtherRigidbody = rigidbodyEntityA.UUID; - //scriptOfColliderB?.Instance?.InvokeOnCollisionEnter2D(collision); - //scriptOfRigidbodyB?.Instance?.InvokeOnCollisionEnter2D(collision); + scriptOfColliderB?.Instance?.InvokeOnCollisionEnter2D(collision); + scriptOfRigidbodyB?.Instance?.InvokeOnCollisionEnter2D(collision); } }; _contactListener.endContactCallback = (contact, userData) => { diff --git a/ScriptCore/Entity.cs b/ScriptCore/Entity.cs index 27d8d72..56921ec 100644 --- a/ScriptCore/Entity.cs +++ b/ScriptCore/Entity.cs @@ -427,13 +427,18 @@ public class Entity : EngineObject /// The new . public static Entity CreateInstance(Entity entity) { + if (entity == null) + { + throw new ArgumentException("The provided instance must not be null!", nameof(entity)); + } + ScriptGlue.Entity_CreateInstance(entity.UUID, out UUID newEntityId); return new Entity(newEntityId); } /// - /// Will be executed once after the entity has be created. + /// Will be called once after the entity has be created. /// protected internal virtual void OnCreate() { } @@ -443,7 +448,7 @@ public class Entity : EngineObject protected internal virtual void OnUpdate(float deltaTime) { } /// - /// Will be executed once when the entity is being destroyed. + /// Will be called once when the entity is being destroyed. /// protected internal virtual void OnDestroy() { } } diff --git a/ScriptCore/Native/StringView.cs b/ScriptCore/Native/StringView.cs new file mode 100644 index 0000000..bd038b8 --- /dev/null +++ b/ScriptCore/Native/StringView.cs @@ -0,0 +1,73 @@ +using GlitchyEngine.Core; +using System; +using System.Diagnostics; +using System.Runtime.InteropServices; +using System.Text; + +namespace GlitchyEngine.Native; + +[DebuggerDisplay("{ToString(),raw}")] +[StructLayout(LayoutKind.Sequential, Pack = 0)] +[EngineClass("System.StringView")] +internal unsafe struct StringView +{ + public byte* Utf8Ptr; + public long Length; + + public StringView() + { + Utf8Ptr = null; + Length = 0; + } + + public StringView(byte* utf8Ptr, long length) + { + Utf8Ptr = utf8Ptr; + Length = length; + } + + public override string? ToString() + { + if (Utf8Ptr == null) + return null; + + if (Length == 0) + return string.Empty; + + if (Length is < 0 or > int.MaxValue) + { + throw new InvalidOperationException($"String length is invalid: {Length}."); + } + + return Encoding.UTF8.GetString(Utf8Ptr, (int)Length); + } + + /// + /// Creates a StringView that can be passed to native code. This method allocates native memory that must be freed using + /// . + /// + /// The string to convert. + /// The pointing to the native memory containing the UTF8-text; or null, if was null. + /// + /// The allocated string is guaranteed to have a null terminator. + /// The null terminator is not counted into the length of the resulting . + /// + public static StringView FromManagedString(string? s) + { + if (s == null) + return new StringView(); + + int maxByteCount = Encoding.UTF8.GetMaxByteCount(s.Length); + + byte* pointer = (byte*)NativeMemory.Alloc((nuint) checked (maxByteCount + 1)); + int bytes = Encoding.UTF8.GetBytes((ReadOnlySpan) s, new Span(pointer, maxByteCount)); + pointer[bytes] = (byte) 0; + + return new StringView(pointer, bytes); + } + + public static void FreeNativeMemory(StringView s) + { + NativeMemory.Free(s.Utf8Ptr); + } +} diff --git a/ScriptCore/Physics/Physics2D.cs b/ScriptCore/Physics/Physics2D.cs index 09e7b69..bb6e17a 100644 --- a/ScriptCore/Physics/Physics2D.cs +++ b/ScriptCore/Physics/Physics2D.cs @@ -17,6 +17,6 @@ public static class Physics2D ScriptGlue.Physics2D_GetGravity(out float2 gravity); return gravity; } - set => ScriptGlue.Physics2D_SetGravity(in value); + set => ScriptGlue.Physics2D_SetGravity(value); } } \ No newline at end of file diff --git a/ScriptCore/ScriptGlue.cs b/ScriptCore/ScriptGlue.cs index 54affa2..b3039ac 100644 --- a/ScriptCore/ScriptGlue.cs +++ b/ScriptCore/ScriptGlue.cs @@ -8,18 +8,24 @@ using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; +using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Loader; +using GlitchyEngine.Native; +using GlitchyEngine.Physics; namespace GlitchyEngine; +/// +/// Contains functions pointer to engine functions that can be called form scripts. +/// [StructLayout(LayoutKind.Sequential)] internal unsafe partial struct EngineFunctions { } /// -/// All methods in here are glued to the ScriptGlue.bf in the engine. +/// Provides the interface between engine and scripts. /// internal static unsafe partial class ScriptGlue { @@ -187,7 +193,16 @@ internal static unsafe partial class ScriptGlue static ScriptMethods HasMethod(Type type, string methodName, ScriptMethods methodFlag) { - MethodInfo? methodInfo = type.GetMethod(methodName, BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly); + MethodInfo? methodInfo = null; + Type? currentType = type; + + while (methodInfo == null && currentType != typeof(Entity) && currentType != null) + { + methodInfo = currentType.GetMethod(methodName, + BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly); + + currentType = currentType.BaseType; + } return methodInfo != null ? methodFlag : ScriptMethods.None; } @@ -280,8 +295,8 @@ internal static unsafe partial class ScriptGlue Log.Exception(e); } } - - [UnmanagedCallersOnly] + + [UnmanagedCallersOnly(CallConvs = [typeof(CallConvCdecl)])] public static void InvokeEntityOnUpdate(UUID entityId, float deltaTime) { try @@ -340,7 +355,7 @@ internal static unsafe partial class ScriptGlue Debug.Assert(scriptInstance != null, "Failed to create script instance."); - EntityScriptInstances.Add(entityId, (scriptInstance!, scriptType)); + EntityScriptInstances.Add(entityId, (scriptInstance, scriptType)); } catch (Exception e) { @@ -489,6 +504,8 @@ internal static unsafe partial class ScriptGlue #endregion + #region Custom engine call implementations + public static void Entity_AddComponent(UUID entityId, Type componentType) { ComponentTypeFunctions[componentType].AddComponent(entityId); @@ -520,8 +537,8 @@ internal static unsafe partial class ScriptGlue 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); + StringView fieldNameConverted = StringView.FromManagedString(fieldName); + StringView fullTypeNameConverted = StringView.FromManagedString(fullTypeName); void* valueObjectConverted = null; bool deleteValueObject = false; @@ -530,29 +547,32 @@ internal static unsafe partial class ScriptGlue { case SerializationType.String: case SerializationType.Enum: - if (valueObject is String stringValue) + if (valueObject is string stringValue) { - valueObjectConverted = (void*)Marshal.StringToCoTaskMemUTF8(stringValue); + StringView nativeString = StringView.FromManagedString(stringValue); + valueObjectConverted = nativeString.Utf8Ptr; deleteValueObject = true; } break; default: if (valueObject is not null) { - void* p = &valueObject; +#pragma warning disable CS8500 // This takes the address of, gets the size of, or declares a pointer to a managed type + object?* objectRef = &valueObject; // Skip Object Header (IntPtr) + Method Table (IntPtr) - valueObjectConverted = (byte*)*(IntPtr*)p + sizeof(IntPtr); - float i = *(float*)valueObjectConverted; + valueObjectConverted = (byte*)*(IntPtr*)objectRef + sizeof(IntPtr); } break; } _engineFunctions.Serialization_SerializeField((void*)serializationContext, type, fieldNameConverted, valueObjectConverted, fullTypeNameConverted); - - Marshal.FreeCoTaskMem((IntPtr)fieldNameConverted); - Marshal.FreeCoTaskMem((IntPtr)fullTypeNameConverted); + + NativeMemory.Free(fieldNameConverted.Utf8Ptr); + NativeMemory.Free(fullTypeNameConverted.Utf8Ptr); if (deleteValueObject) - Marshal.FreeCoTaskMem((IntPtr)valueObjectConverted); + NativeMemory.Free(valueObjectConverted); } + + #endregion Custom engine call implementations } diff --git a/ScriptCore/Serialization/DeserializationObject.cs b/ScriptCore/Serialization/DeserializationObject.cs index d19725e..7ae0809 100644 --- a/ScriptCore/Serialization/DeserializationObject.cs +++ b/ScriptCore/Serialization/DeserializationObject.cs @@ -11,6 +11,7 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Text; using GlitchyEngine.Editor; +using GlitchyEngine.Native; namespace GlitchyEngine.Serialization; @@ -105,13 +106,13 @@ public class DeserializationObject return type; } - public DeserializationObject? GetDeserializedObject(UUID id) + public unsafe DeserializationObject? GetDeserializedObject(UUID id) { DeserializationObject context; if (DeserializedClasses.TryGetValue(id, out context)) return context; - + ScriptGlue.Serialization_GetObject(_internalContext, id, out IntPtr contextPtr); if (contextPtr == IntPtr.Zero) @@ -148,15 +149,8 @@ public class DeserializationObject } [StructLayout(LayoutKind.Explicit)] - public struct DataHelper + internal struct DataHelper { - [StructLayout(LayoutKind.Sequential)] - public unsafe struct StringView - { - public byte* Utf8Ptr; - public long Length; - } - [FieldOffset(0)] public EngineObjectReferenceHelper EngineObjectReference; @@ -187,27 +181,11 @@ public class DeserializationObject ScriptGlue.Serialization_DeserializeField(_internalContext, expectedType, completeFieldName, rawData, out SerializationType actualType); - string? GetString() - { - if (dataHelper.String.Utf8Ptr == null) - return null; - - if (dataHelper.String.Length == 0) - return string.Empty; - - if (dataHelper.String.Length is < 0 or > int.MaxValue) - { - throw new InvalidOperationException($"String length is invalid: {dataHelper.String.Length}"); - } - - return Encoding.UTF8.GetString(dataHelper.String.Utf8Ptr, (int)dataHelper.String.Utf8Ptr); - } - object? value = actualType switch { SerializationType.Bool => *(bool*)rawData, SerializationType.Char => *(char*)rawData, - SerializationType.String => GetString(), + SerializationType.String => dataHelper.String.ToString(), SerializationType.Int8 => *(sbyte*)rawData, SerializationType.Int16 => *(short*)rawData, SerializationType.Int32 => *(int*)rawData, @@ -219,7 +197,7 @@ public class DeserializationObject SerializationType.Float => *(float*)rawData, SerializationType.Double => *(double*)rawData, SerializationType.Decimal => *(decimal*)rawData, - SerializationType.Enum => GetString(), + SerializationType.Enum => dataHelper.String.ToString(), SerializationType.EngineObjectReference => dataHelper.EngineObjectReference, SerializationType.ObjectReference => dataHelper.UUID, _ => NoValueDeserialized @@ -522,7 +500,7 @@ public class DeserializationObject } catch { - Log.Error($"Failed to parse \"{valueName}\" as enum-type \"{enumType}\""); + Log.Error($"Failed to deserialize field \"{fieldName}\": Could not parse \"{valueName}\" as enum-type \"{enumType}\""); } return NoValueDeserialized; diff --git a/ScriptCoreGenerator/ScriptGlueGenerator.cs b/ScriptCoreGenerator/ScriptGlueGenerator.cs index 7f0fcd6..0814cd0 100644 --- a/ScriptCoreGenerator/ScriptGlueGenerator.cs +++ b/ScriptCoreGenerator/ScriptGlueGenerator.cs @@ -194,36 +194,6 @@ public class ScriptGlueGenerator : IIncrementalGenerator ReturnValueConversion = null }); - beefTypeToMappedType.Add("Mono.MonoString*", new MappedType - { - BeefTypeName = "object /*TODO: Mono.MonoString**/", - ReturnValueConversion = null - }); - - beefTypeToMappedType.Add("Mono.MonoException*", new MappedType - { - BeefTypeName = "object /*TODO: Mono.MonoException**/", - ReturnValueConversion = null - }); - - beefTypeToMappedType.Add("Mono.MonoArray*", new MappedType - { - BeefTypeName = "object /*TODO: Mono.MonoArray**/", - ReturnValueConversion = null - }); - - beefTypeToMappedType.Add("Mono.MonoObject*", new MappedType - { - BeefTypeName = "object /*TODO: Mono.MonoObject**/", - ReturnValueConversion = null - }); - - beefTypeToMappedType.Add("Mono.MonoReflectionType*", new MappedType - { - BeefTypeName = "object /*TODO: Mono.MonoReflectionType**/", - ReturnValueConversion = null - }); - beefTypeToMappedType.Add("uint8*", new MappedType { BeefTypeName = "uint8*", @@ -287,6 +257,17 @@ public class ScriptGlueGenerator : IIncrementalGenerator CSharpWrapperType = "bool", ReturnValueConversion = "EngineErrors.ThrowIfError(returnValue);\nreturn (returnValue == EngineResult.Ok);" }); + + beefTypeToMappedType.Add("System.StringView", new MappedType() + { + BeefTypeName = "System.StringView", + CSharpTypeName = "GlitchyEngine.Native.StringView", + CSharpWrapperType = "string", + ReturnValueConversion = "return returnValue.ToString();", + WrapperConvertInput = "var {0} = GlitchyEngine.Native.StringView.FromManagedString({1});", + WrapperCleanupInput = "GlitchyEngine.Native.StringView.FreeNativeMemory({0});", + WrapperOutConversion = "{1} = {0}.ToString();" + }); } private static void GenerateFunctionPointer(GlueMethod method, Dictionary beefTypeToMappedType, StringBuilder output)