mirror of
https://github.com/aharabada/glitchy-engine-beef.git
synced 2026-09-05 13:01:52 +00:00
More generating script glue
This commit is contained in:
@@ -66,6 +66,17 @@ struct TypeTranslationTemplate
|
||||
}
|
||||
}
|
||||
|
||||
[AttributeUsage(.Parameter)]
|
||||
struct GlueParamAttribute : Attribute
|
||||
{
|
||||
public String WrapperType;
|
||||
|
||||
public this(String wrapperType)
|
||||
{
|
||||
WrapperType = wrapperType;
|
||||
}
|
||||
}
|
||||
|
||||
[AttributeUsage(.Struct)]
|
||||
struct EngineFunctionsGeneratorAttribute : Attribute, IComptimeTypeApply
|
||||
{
|
||||
@@ -74,7 +85,22 @@ struct EngineFunctionsGeneratorAttribute : Attribute, IComptimeTypeApply
|
||||
("int32", "int"),
|
||||
("char16*", "char*"),
|
||||
("char8*", "byte*"),
|
||||
("GlitchyEngine.Events.MouseButton", "GlitchyEngine.MouseButton")
|
||||
("uint8*", "byte*"),
|
||||
("GlitchyEngine.Events.MouseButton", "GlitchyEngine.MouseButton"),
|
||||
("GlitchLog.LogLevel", "Log.LogLevel"),
|
||||
("out GlitchyEngine.Content.AssetHandle", "UUID"),
|
||||
("GlitchyEngine.Content.AssetHandle", "UUID"),
|
||||
("out GlitchyEngine.Renderer.Text.FontRenderer.HorizontalTextAlignment", "HorizontalTextAlignment"),
|
||||
("GlitchyEngine.Renderer.Text.FontRenderer.HorizontalTextAlignment", "HorizontalTextAlignment"),
|
||||
("GlitchyEngine.Renderer.ShaderVariableType", "Material.ShaderVariableType"),
|
||||
("in GlitchyEngine.Math.Quaternion", "in System.Numerics.Quaternion"),
|
||||
("out GlitchyEngine.Math.Quaternion", "out System.Numerics.Quaternion"),
|
||||
("out GlitchyEngine.Scripting.ScriptGlue.AxisAngle", "out RotationAxisAngle"),
|
||||
("GlitchyEngine.Scripting.ScriptGlue.AxisAngle", "RotationAxisAngle"),
|
||||
("out GlitchyEngine.World.Rigidbody2DComponent.BodyType", "out BodyType"),
|
||||
("in GlitchyEngine.World.Rigidbody2DComponent.BodyType", "in BodyType"),
|
||||
("out GlitchyEngine.World.SceneCamera.ProjectionType", "out ProjectionType"),
|
||||
("in GlitchyEngine.World.SceneCamera.ProjectionType", "in ProjectionType"),
|
||||
};
|
||||
|
||||
// {0}... Out name,
|
||||
@@ -158,6 +184,12 @@ struct EngineFunctionsGeneratorAttribute : Attribute, IComptimeTypeApply
|
||||
|
||||
TypeTranslationTemplate template = GetCSharpWrapperTemplate(beefParameterType);
|
||||
|
||||
// TODO: This is currently not implemented in beef.
|
||||
/*if (method.GetParamCustomAttribute<GlueParamAttribute>(i) case .Ok(let attribute))
|
||||
{
|
||||
template.PrettyCSharpParamType = attribute.WrapperType;
|
||||
}*/
|
||||
|
||||
StringView paramName = method.GetParamName(i);
|
||||
|
||||
// Generate the parameter for the wrapper head.
|
||||
@@ -202,7 +234,7 @@ struct EngineFunctionsGeneratorAttribute : Attribute, IComptimeTypeApply
|
||||
TypeTranslationTemplate template = GetCSharpReturnValueTemplate(csharpReturnType);
|
||||
|
||||
outString.AppendF($"""
|
||||
internal static unsafe {template.PrettyCSharpParamType} NEW_{method.Name}({wrapperParameters})
|
||||
internal static unsafe {template.PrettyCSharpParamType} {method.Name}({wrapperParameters})
|
||||
{{
|
||||
{translation}
|
||||
{template.StartCode}_engineFunctions.{method.Name}({callArguments});
|
||||
@@ -215,6 +247,48 @@ struct EngineFunctionsGeneratorAttribute : Attribute, IComptimeTypeApply
|
||||
""");
|
||||
}
|
||||
|
||||
private static String GetTypeInfo(Type type)
|
||||
{
|
||||
String value = new .();
|
||||
type.ToString(value);
|
||||
|
||||
if (type.IsEnum)
|
||||
{
|
||||
value.AppendF($" : {type.UnderlyingType}");
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
private static void GenerateJsonInfo(MethodInfo method, String outString)
|
||||
{
|
||||
String parameters = new String();
|
||||
|
||||
for (int i < method.ParamCount)
|
||||
{
|
||||
if (i != 0)
|
||||
parameters.Append(", ");
|
||||
|
||||
parameters.AppendF($"""
|
||||
|
||||
{{
|
||||
"name": "{method.GetParamName(i)}",
|
||||
"type": "{GetTypeInfo(method.GetParamType(i))}"
|
||||
}}
|
||||
""");
|
||||
}
|
||||
|
||||
outString.AppendF($"""
|
||||
|
||||
{{
|
||||
"name": "{method.Name}",
|
||||
"return_type": "{GetTypeInfo(method.ReturnType)}",
|
||||
"parameters": [{parameters}
|
||||
]
|
||||
}},
|
||||
""");
|
||||
}
|
||||
|
||||
[Comptime]
|
||||
public void ApplyToType(Type self)
|
||||
{
|
||||
@@ -223,6 +297,10 @@ struct EngineFunctionsGeneratorAttribute : Attribute, IComptimeTypeApply
|
||||
using System.Runtime.InteropServices;
|
||||
using GlitchyEngine;
|
||||
using GlitchyEngine.Core;
|
||||
using GlitchyEngine.Math;
|
||||
using GlitchyEngine.Physics;
|
||||
using GlitchyEngine.Graphics;
|
||||
using GlitchyEngine.Graphics.Text;
|
||||
|
||||
namespace GlitchyEngine;
|
||||
|
||||
@@ -239,6 +317,8 @@ struct EngineFunctionsGeneratorAttribute : Attribute, IComptimeTypeApply
|
||||
|
||||
""");
|
||||
|
||||
String jsonOutput = new String("[");
|
||||
|
||||
for (MethodInfo methodInfo in typeof(ScriptGlue).GetMethods(.Static | .NonPublic))
|
||||
{
|
||||
if (methodInfo.GetCustomAttribute<RegisterCallAttribute>() case .Ok(let attribute))
|
||||
@@ -260,6 +340,7 @@ struct EngineFunctionsGeneratorAttribute : Attribute, IComptimeTypeApply
|
||||
GenerateCSharpFunctionPointer(methodInfo, csharpEngineFunctionsStruct);
|
||||
|
||||
GenerateCSharpWrapperMethod(methodInfo, csharpScriptGlue);
|
||||
GenerateJsonInfo(methodInfo, jsonOutput);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -268,7 +349,21 @@ struct EngineFunctionsGeneratorAttribute : Attribute, IComptimeTypeApply
|
||||
|
||||
csharpEngineFunctionsStruct.Append(csharpScriptGlue);
|
||||
|
||||
if (File.WriteAllText("../ScriptCore/ScriptGlue.gen.cs", csharpEngineFunctionsStruct) case .Err)
|
||||
/*if (File.WriteAllText("../ScriptCore/ScriptGlue.gen.cs", csharpEngineFunctionsStruct) case .Err)
|
||||
{
|
||||
Runtime.FatalError("Failed to write file");
|
||||
}*/
|
||||
|
||||
if (jsonOutput.EndsWith(","))
|
||||
{
|
||||
jsonOutput.RemoveFromEnd(1);
|
||||
}
|
||||
|
||||
jsonOutput.Append(']');
|
||||
|
||||
Directory.CreateDirectory("../generated");
|
||||
|
||||
if (File.WriteAllText("../generated/ScriptGlue.json", jsonOutput) case .Err)
|
||||
{
|
||||
Runtime.FatalError("Failed to write file");
|
||||
}
|
||||
@@ -537,7 +632,7 @@ static class ScriptGlue
|
||||
|
||||
[RegisterCall("ScriptGlue::Log_LogMessage")]
|
||||
[CallingConvention(.Cdecl)]
|
||||
static void Log_LogMessage(int32 logLevel, char16* messagePtr, char16* fileNamePtr, int lineNumber)
|
||||
static void Log_LogMessage(LogLevel logLevel, char16* messagePtr, char16* fileNamePtr, int lineNumber)
|
||||
{
|
||||
String escapedMessage = new:ScopedAlloc! String(messagePtr);
|
||||
|
||||
@@ -1421,14 +1516,14 @@ static class ScriptGlue
|
||||
}
|
||||
|
||||
[RegisterCall("ScriptGlue::TextRenderer_GetHorizontalAlignment")]
|
||||
static void TextRenderer_GetHorizontalAlignment(UUID entityId, out HorizontalTextAlignment horizontalAlignment)
|
||||
static void TextRenderer_GetHorizontalAlignment(UUID entityId, [GlueParam("out HorizontalTextAlignment")] out HorizontalTextAlignment horizontalAlignment)
|
||||
{
|
||||
TextRendererComponent* textComponent = GetComponentSafe<TextRendererComponent>(entityId);
|
||||
horizontalAlignment = textComponent.HorizontalAlignment;
|
||||
}
|
||||
|
||||
[RegisterCall("ScriptGlue::TextRenderer_SetHorizontalAlignment")]
|
||||
static void TextRenderer_SetHorizontalAlignment(UUID entityId, HorizontalTextAlignment horizontalAlignment)
|
||||
static void TextRenderer_SetHorizontalAlignment(UUID entityId, [GlueParam("HorizontalTextAlignment")] HorizontalTextAlignment horizontalAlignment)
|
||||
{
|
||||
TextRendererComponent* textComponent = GetComponentSafe<TextRendererComponent>(entityId);
|
||||
textComponent.HorizontalAlignment = horizontalAlignment;
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
using System;
|
||||
|
||||
namespace GlitchyEngine.Core;
|
||||
|
||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum, AllowMultiple = true)]
|
||||
public class EngineClassAttribute : Attribute
|
||||
{
|
||||
public string EngineClassName { get; }
|
||||
|
||||
public EngineClassAttribute(string engineClassName)
|
||||
{
|
||||
EngineClassName = engineClassName;
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,8 @@ namespace GlitchyEngine.Core;
|
||||
/// Represents a universally unique identifier (UUID).
|
||||
/// </summary>
|
||||
[DebuggerDisplay("{ToString()}")]
|
||||
[EngineClass("GlitchyEngine.Core.UUID")]
|
||||
[EngineClass("GlitchyEngine.Core.AssetHandle")]
|
||||
public struct UUID
|
||||
{
|
||||
private ulong _uuid;
|
||||
|
||||
@@ -9,11 +9,19 @@ namespace GlitchyEngine.Graphics;
|
||||
/// </summary>
|
||||
public class Material : Asset
|
||||
{
|
||||
internal enum ShaderVariableType : byte
|
||||
{
|
||||
Bool,
|
||||
Float,
|
||||
Int,
|
||||
UInt
|
||||
}
|
||||
|
||||
public void SetVariable(string name, float4 value)
|
||||
{
|
||||
unsafe
|
||||
{
|
||||
ScriptGlue.Material_SetVariable(_uuid, name, ScriptGlue.ShaderVariableType.Float, 1, 4, 1, &value, sizeof(float4));
|
||||
ScriptGlue.Material_SetVariable(_uuid, name, ShaderVariableType.Float, 1, 4, 1, &value, sizeof(float4));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+3
-1
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.CompilerServices;
|
||||
using GlitchyEngine.Core;
|
||||
|
||||
namespace GlitchyEngine;
|
||||
|
||||
@@ -12,7 +13,8 @@ public class Log
|
||||
/// <summary>
|
||||
/// The severity of the log message.
|
||||
/// </summary>
|
||||
internal enum LogLevel
|
||||
[EngineClass("GlitchLog.LogLevel")]
|
||||
internal enum LogLevel : byte
|
||||
{
|
||||
Trace = 0,
|
||||
Debug,
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
using GlitchyEngine.Core;
|
||||
|
||||
namespace GlitchyEngine;
|
||||
|
||||
/// <summary>
|
||||
/// An enum of all mouse buttons that can be queried using methods in <see cref="Input"/>.
|
||||
/// </summary>
|
||||
[EngineClass("GlitchyEngine.Events.MouseButton")]
|
||||
public enum MouseButton : byte
|
||||
{
|
||||
None = 0,
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
<EnableDynamicLoading>true</EnableDynamicLoading>
|
||||
<!--<DebugType>embedded</DebugType>-->
|
||||
<!--<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>-->
|
||||
<GeneratedSchemaPath>$(ProjectDir)../generated/ScriptGlue.json</GeneratedSchemaPath>
|
||||
</PropertyGroup>
|
||||
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
|
||||
<Exec Command="PowerShell ./postbuild.ps1 -sourceDir $(OutDir) -destinationDir "..\GlitchyEditor\resources\scripts"" />
|
||||
@@ -27,4 +28,7 @@
|
||||
<ProjectReference Include="..\ScriptCoreGenerator\ScriptCoreGenerator.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
|
||||
<ProjectReference Include="..\vendor\ImGui.NET\src\ImGui.NET\ImGui.NET.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AdditionalFiles Include="$(GeneratedSchemaPath)" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
+67
-65
@@ -25,7 +25,7 @@ namespace GlitchyEngine;
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal unsafe partial struct EngineFunctions
|
||||
{
|
||||
public delegate* unmanaged[Cdecl]<Log.LogLevel, char*, char*, int, void> Log_LogMessage;
|
||||
public delegate* unmanaged[Cdecl]<GlitchyEngine.Log.LogLevel, char*, char*, int, void> Log_LogMessage;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -471,22 +471,32 @@ internal static partial class ScriptGlue
|
||||
|
||||
#region Log
|
||||
|
||||
internal static unsafe void Log_LogMessage(Log.LogLevel logLevel, string message, string filePath, int line)
|
||||
{
|
||||
// unsafe
|
||||
// {
|
||||
// byte* mess = (byte*)Marshal.StringToCoTaskMemUTF8(message);
|
||||
//
|
||||
// fixed (char* messagePtr = message)
|
||||
// fixed (char* filePathPtr = filePath)
|
||||
// {
|
||||
// _engineFunctions.Log_LogMessage(logLevel, messagePtr, filePathPtr, line);
|
||||
// }
|
||||
//
|
||||
// Marshal.FreeCoTaskMem((IntPtr)mess);
|
||||
// }
|
||||
}
|
||||
|
||||
// public unsafe static void Log_LogMessage(GlitchyEngine.Log.LogLevel logLevel, string messagePtr, string fileNamePtr, int lineNumber)
|
||||
// {
|
||||
// fixed (char* messagePtrConverted = messagePtr) {
|
||||
// fixed (char* fileNamePtrConverted = fileNamePtr) {
|
||||
// _engineFunctions.Log_LogMessage(logLevel, messagePtrConverted, fileNamePtrConverted, lineNumber);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
//
|
||||
// }
|
||||
//internal static unsafe void Log_LogMessage(Log.LogLevel logLevel, string message, string filePath, int line)
|
||||
//{
|
||||
// // unsafe
|
||||
// // {
|
||||
// // byte* mess = (byte*)Marshal.StringToCoTaskMemUTF8(message);
|
||||
// //
|
||||
// // fixed (char* messagePtr = message)
|
||||
// // fixed (char* filePathPtr = filePath)
|
||||
// // {
|
||||
// // _engineFunctions.Log_LogMessage(logLevel, messagePtr, filePathPtr, line);
|
||||
// // }
|
||||
// //
|
||||
// // Marshal.FreeCoTaskMem((IntPtr)mess);
|
||||
// // }
|
||||
//}
|
||||
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
public static extern void Log_LogException(Exception exception);
|
||||
@@ -497,13 +507,13 @@ internal static partial class ScriptGlue
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern void Entity_Create(object scriptInstance, string? entityName, Type[]? componentTypes, out UUID entityId);
|
||||
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern void Entity_Destroy(UUID entityId);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern void Entity_CreateInstance(UUID entityId, out UUID newEntityId);
|
||||
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern void Entity_AddComponent(UUID entityId, Type componentType);
|
||||
|
||||
@@ -512,34 +522,34 @@ internal static partial class ScriptGlue
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern bool Entity_HasComponent(UUID entityId, Type componentType);
|
||||
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern void Entity_RemoveComponent(UUID entityId, Type componentType);
|
||||
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern void Entity_FindEntityWithName(string name, out UUID uuid);
|
||||
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern void Entity_GetScriptInstance(UUID entityId, out object? instance);
|
||||
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern object Entity_SetScript(UUID entityId, Type scriptType);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern void Entity_RemoveScript(UUID entityId);
|
||||
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
public static extern string Entity_GetName(UUID entityId);
|
||||
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
public static extern string Entity_SetName(UUID entityId, string name);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
public static extern void Entity_GetEditorFlags(UUID uuid, out EditorFlags flags);
|
||||
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
public static extern void Entity_SetEditorFlags(UUID uuid, EditorFlags editorFlags);
|
||||
|
||||
|
||||
#endregion Entity
|
||||
|
||||
#region TransformComponent
|
||||
@@ -555,31 +565,31 @@ internal static partial class ScriptGlue
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern void Transform_SetTranslation(UUID entityId, in float3 translation);
|
||||
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern void Transform_GetWorldTranslation(UUID entityId, out float3 translation);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern void Transform_SetWorldTranslation(UUID entityId, in float3 translation);
|
||||
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern void Transform_GetRotation(UUID entityId, out Quaternion rotation);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern void Transform_SetRotation(UUID entityId, in Quaternion rotation);
|
||||
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern void Transform_GetRotationEuler(UUID entityId, out float3 rotationEuler);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern void Transform_SetRotationEuler(UUID entityId, in float3 rotationEuler);
|
||||
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern void Transform_GetRotationAxisAngle(UUID entityId, out RotationAxisAngle translation);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern void Transform_SetRotationAxisAngle(UUID entityId, RotationAxisAngle translation);
|
||||
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern void Transform_GetScale(UUID entityId, out float3 scale);
|
||||
|
||||
@@ -589,40 +599,40 @@ internal static partial class ScriptGlue
|
||||
#endregion TransformComponent
|
||||
|
||||
#region RigidBody2D
|
||||
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern void Rigidbody2D_ApplyForce(UUID entityId, in float2 force, float2 point, bool wakeUp);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern void Rigidbody2D_ApplyForceToCenter(UUID entityId, in float2 force, bool wakeUp);
|
||||
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern void Rigidbody2D_SetPosition(UUID entityId, in float2 position);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern void Rigidbody2D_GetPosition(UUID entityId, out float2 position);
|
||||
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern void Rigidbody2D_SetRotation(UUID entityId, in float rotation);
|
||||
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern void Rigidbody2D_GetRotation(UUID entityId, out float rotation);
|
||||
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern void Rigidbody2D_SetLinearVelocity(UUID entityId, in float2 velocity);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern void Rigidbody2D_GetLinearVelocity(UUID entityId, out float2 velocity);
|
||||
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern void Rigidbody2D_SetAngularVelocity(UUID entityId, in float velocity);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern void Rigidbody2D_GetAngularVelocity(UUID entityId, out float velocity);
|
||||
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern void Rigidbody2D_GetBodyType(UUID entityId, out BodyType bodyType);
|
||||
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern void Rigidbody2D_SetBodyType(UUID entityId, in BodyType bodyType);
|
||||
|
||||
@@ -631,23 +641,23 @@ internal static partial class ScriptGlue
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern void Rigidbody2D_SetFixedRotation(UUID entityId, in bool isFixedRotation);
|
||||
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern void Rigidbody2D_GetGravityScale(UUID entityId, out float gravityScale);
|
||||
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern void Rigidbody2D_SetGravityScale(UUID entityId, in float gravityScale);
|
||||
|
||||
|
||||
#endregion RigidBody2D
|
||||
|
||||
#region Camera
|
||||
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern void Camera_GetProjectionType(UUID entityId, out ProjectionType projectionType);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern void Camera_SetProjectionType(UUID entityId, in ProjectionType projectionType);
|
||||
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern void Camera_GetPerspectiveFovY(UUID entityId, out float fovY);
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
@@ -692,7 +702,7 @@ internal static partial class ScriptGlue
|
||||
#endregion
|
||||
|
||||
#region Physics2D
|
||||
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern void Physics2D_GetGravity(out float2 gravity);
|
||||
|
||||
@@ -702,13 +712,13 @@ internal static partial class ScriptGlue
|
||||
#endregion Physics2D
|
||||
|
||||
#region CircleRenderer
|
||||
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern void CircleRenderer_GetColor(UUID entityId, out ColorRGBA color);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern void CircleRenderer_SetColor(UUID entityId, ColorRGBA color);
|
||||
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern void CircleRenderer_GetUvTransform(UUID entityId, out float4 uvTransform);
|
||||
|
||||
@@ -776,7 +786,7 @@ internal static partial class ScriptGlue
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern void TextRenderer_SetFontSize(UUID uuid, float fontSize);
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region MeshRenderer
|
||||
@@ -793,21 +803,21 @@ internal static partial class ScriptGlue
|
||||
#endregion
|
||||
|
||||
#region Math
|
||||
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern float modf_float(float x, out float integerPart);
|
||||
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern float2 modf_float2(float2 x, out float2 integerPart);
|
||||
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern float3 modf_float3(float3 x, out float3 integerPart);
|
||||
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern float4 modf_float4(float4 x, out float4 integerPart);
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern void UUID_CreateNew(out UUID uuid);
|
||||
|
||||
@@ -834,10 +844,10 @@ internal static partial class ScriptGlue
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern void Serialization_CreateObject(IntPtr currentContext, bool isStatic, string fullTypeName, out IntPtr context, out UUID id);
|
||||
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
public static extern unsafe void Serialization_DeserializeField(IntPtr internalContext, SerializationType expectedType, string fieldName, byte* value, out SerializationType actualType);
|
||||
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
public static extern void Serialization_GetObject(IntPtr internalContext, UUID id, out IntPtr objectContext);
|
||||
|
||||
@@ -858,16 +868,8 @@ internal static partial class ScriptGlue
|
||||
|
||||
#region Material
|
||||
|
||||
public enum ShaderVariableType : byte
|
||||
{
|
||||
Bool,
|
||||
Float,
|
||||
Int,
|
||||
UInt
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern unsafe bool Material_SetVariable(UUID assetId, string variableName, ShaderVariableType elementType, int rows, int columns, int arrayLength, void* rawData, int dataLength);
|
||||
internal static extern unsafe bool Material_SetVariable(UUID assetId, string variableName, Material.ShaderVariableType elementType, int rows, int columns, int arrayLength, void* rawData, int dataLength);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern bool Material_ResetVariable(UUID assetId, string variableName);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -4,13 +4,18 @@
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<IsRoslynComponent>true</IsRoslynComponent>
|
||||
<EnforceExtendedAnalyzerRules>true</EnforceExtendedAnalyzerRules>
|
||||
<IncludeBuildOutput>false</IncludeBuildOutput>
|
||||
<EnforceExtendedAnalyzerRules>true</EnforceExtendedAnalyzerRules>
|
||||
<Nullable>enable</Nullable>
|
||||
<!-- <GeneratedSchemaPath>$(ProjectDir)../generated/ScriptGlue.json</GeneratedSchemaPath>-->
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.6.0" PrivateAssets="all" />
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4" PrivateAssets="all" />
|
||||
<PackageReference Include="System.Text.Json" Version="9.0.7" GeneratePathProperty="true" PrivateAssets="all" />
|
||||
|
||||
<!-- <AdditionalFiles Include="$(GeneratedSchemaPath)" />-->
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -0,0 +1,417 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection.Metadata;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Threading;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
|
||||
namespace ScriptCoreGenerator;
|
||||
|
||||
internal class GlueMethod
|
||||
{
|
||||
[JsonPropertyName("name")]
|
||||
public string Name { get; set; }
|
||||
[JsonPropertyName("return_type")]
|
||||
public string ReturnType { get; set; }
|
||||
[JsonPropertyName("parameters")]
|
||||
public List<Parameter> Parameters { get; set; }
|
||||
|
||||
internal class Parameter
|
||||
{
|
||||
[JsonPropertyName("name")]
|
||||
public string Name { get; set; }
|
||||
[JsonPropertyName("type")]
|
||||
public string Type { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
[Generator]
|
||||
public class ScriptGlueGenerator : IIncrementalGenerator
|
||||
{
|
||||
public class GeneratorInput
|
||||
{
|
||||
public ImmutableArray<ITypeSymbol?> TypeMappings;
|
||||
public ImmutableArray<string> GlueFunctionDefinitions;
|
||||
public ImmutableArray<string> ExistingScriptGlueClasses;
|
||||
public ImmutableArray<string> ExistingEngineFunctionStructs;
|
||||
}
|
||||
|
||||
public void Initialize(IncrementalGeneratorInitializationContext context)
|
||||
{
|
||||
var mappedTypes = context.SyntaxProvider
|
||||
.CreateSyntaxProvider(
|
||||
CouldBeMappedType, GetTypeOrNull)
|
||||
.Where(type => type is not null)
|
||||
.Collect();
|
||||
|
||||
var manualScriptGlueWrappers = context.SyntaxProvider
|
||||
.CreateSyntaxProvider(
|
||||
IsScriptGlueClass, GetSymbol<ClassDeclarationSyntax>)
|
||||
.Where(type => type is not null)
|
||||
.SelectMany((type, _) => type!.MemberNames)
|
||||
.Collect();
|
||||
|
||||
var manualEngineFunctions = context.SyntaxProvider
|
||||
.CreateSyntaxProvider(
|
||||
IsEngineFunctionsStruct, GetSymbol<StructDeclarationSyntax>)
|
||||
.Where(type => type is not null)
|
||||
.SelectMany((type, _) => type!.MemberNames)
|
||||
.Collect();
|
||||
|
||||
var glueFunctions = context.AdditionalTextsProvider
|
||||
.Where(text => text.Path.EndsWith("ScriptGlue.json",
|
||||
StringComparison.OrdinalIgnoreCase))
|
||||
.Select((text, token) => text.GetText(token)?.ToString())
|
||||
.Where(text => text is not null)!
|
||||
.Collect<string>();
|
||||
|
||||
// Kombiniere zu einem sauberen Record
|
||||
var combinedProvider = mappedTypes
|
||||
.Combine(manualScriptGlueWrappers)
|
||||
.Combine(manualEngineFunctions)
|
||||
.Combine(glueFunctions)
|
||||
.Select((input, _) => new GeneratorInput{
|
||||
TypeMappings = input.Left.Left.Left,
|
||||
ExistingScriptGlueClasses = input.Left.Left.Right,
|
||||
ExistingEngineFunctionStructs = input.Left.Right,
|
||||
GlueFunctionDefinitions = input.Right
|
||||
});
|
||||
|
||||
context.RegisterSourceOutput(combinedProvider, GenerateCode);
|
||||
}
|
||||
|
||||
public class MappedType
|
||||
{
|
||||
public string BeefTypeName;
|
||||
public string? UnderlyingEnumTypeName;
|
||||
public bool HasUnderlyingType => UnderlyingEnumTypeName is not null;
|
||||
|
||||
private string _cSharpTypeName;
|
||||
private string _cSharpWrapperType;
|
||||
|
||||
public MappedType? CSharpUnderlyingEnumType;
|
||||
|
||||
public string? WrapperConvertInput;
|
||||
public string? WrapperCleanupInput;
|
||||
|
||||
public string? ReturnValueConversion = "return returnValue;";
|
||||
|
||||
public string CSharpWrapperType
|
||||
{
|
||||
get => _cSharpWrapperType ?? CSharpTypeName;
|
||||
set => _cSharpWrapperType = value;
|
||||
}
|
||||
|
||||
public string CSharpTypeName
|
||||
{
|
||||
get => _cSharpTypeName ?? BeefTypeName;
|
||||
set => _cSharpTypeName = value;
|
||||
}
|
||||
}
|
||||
|
||||
private static MappedType DecodeType(string beefType, Dictionary<string, MappedType> beefTypeToMappedType)
|
||||
{
|
||||
if (beefTypeToMappedType.TryGetValue(beefType, out MappedType? mappedType))
|
||||
{
|
||||
return mappedType;
|
||||
}
|
||||
|
||||
int colonIndex = beefType.IndexOf(':');
|
||||
bool isEnum = colonIndex != -1;
|
||||
|
||||
string beefTypeName = beefType;
|
||||
string? underlyingEnumType = null;
|
||||
|
||||
if (isEnum)
|
||||
{
|
||||
beefTypeName = beefType.Substring(0, colonIndex).Trim();
|
||||
underlyingEnumType = beefType.Substring(colonIndex + 1).Trim();
|
||||
|
||||
if (beefTypeToMappedType.TryGetValue(beefTypeName, out mappedType))
|
||||
{
|
||||
if (mappedType.UnderlyingEnumTypeName is null)
|
||||
{
|
||||
mappedType.UnderlyingEnumTypeName = underlyingEnumType;
|
||||
mappedType.CSharpUnderlyingEnumType = DecodeType(underlyingEnumType, beefTypeToMappedType);
|
||||
}
|
||||
|
||||
return mappedType;
|
||||
}
|
||||
}
|
||||
|
||||
MappedType newMapping = new MappedType()
|
||||
{
|
||||
BeefTypeName = beefTypeName,
|
||||
UnderlyingEnumTypeName = underlyingEnumType,
|
||||
CSharpUnderlyingEnumType = underlyingEnumType == null ? null : DecodeType(underlyingEnumType,beefTypeToMappedType),
|
||||
};
|
||||
|
||||
beefTypeToMappedType[beefType] = newMapping;
|
||||
beefTypeToMappedType[beefTypeName] = newMapping;
|
||||
|
||||
return newMapping;
|
||||
}
|
||||
|
||||
private static void InitializeTypes(Dictionary<string, MappedType> beefTypeToMappedType)
|
||||
{
|
||||
beefTypeToMappedType.Add("void", new MappedType
|
||||
{
|
||||
BeefTypeName = "void",
|
||||
ReturnValueConversion = null
|
||||
});
|
||||
|
||||
beefTypeToMappedType.Add("char16*", new MappedType
|
||||
{
|
||||
BeefTypeName = "char16*",
|
||||
CSharpTypeName = "char*",
|
||||
CSharpWrapperType = "string",
|
||||
ReturnValueConversion = null, // TODO!
|
||||
WrapperConvertInput = "fixed (char* {0} = {1}) {{",
|
||||
WrapperCleanupInput = "}}"
|
||||
});
|
||||
}
|
||||
|
||||
private static void GenerateFunctionPointer(GlueMethod method, Dictionary<string, MappedType> beefTypeToMappedType, StringBuilder output)
|
||||
{
|
||||
MappedType returnType = DecodeType(method.ReturnType, beefTypeToMappedType);
|
||||
|
||||
List<MappedType> parameters = new();
|
||||
StringBuilder parameterText = new();
|
||||
|
||||
foreach (var param in method.Parameters)
|
||||
{
|
||||
MappedType parameterType = DecodeType(param.Type, beefTypeToMappedType);
|
||||
parameters.Add(parameterType);
|
||||
|
||||
parameterText.Append(parameterType.CSharpTypeName);
|
||||
parameterText.Append(", ");
|
||||
}
|
||||
|
||||
output.AppendLine($" public delegate* unmanaged[Cdecl]<{parameterText}{returnType.CSharpTypeName}> {method.Name};");
|
||||
}
|
||||
|
||||
private static void GenerateWrapper(GlueMethod method, Dictionary<string, MappedType> beefTypeToMappedType, StringBuilder output)
|
||||
{
|
||||
// MappedType returnType = DecodeType(method.ReturnType, beefTypeToMappedType);
|
||||
//
|
||||
List<MappedType> parameters = new();
|
||||
StringBuilder parameterText = new();
|
||||
StringBuilder parameterConversion = new();
|
||||
StringBuilder cleanup = new();
|
||||
StringBuilder call = new();
|
||||
|
||||
MappedType returnType = DecodeType(method.ReturnType, beefTypeToMappedType);
|
||||
|
||||
if (returnType.ReturnValueConversion is not null)
|
||||
{
|
||||
call.Append("var returnValue = ");
|
||||
}
|
||||
|
||||
call.Append($"_engineFunctions.{method.Name}(");
|
||||
|
||||
foreach (var param in method.Parameters)
|
||||
{
|
||||
MappedType parameterType = DecodeType(param.Type, beefTypeToMappedType);
|
||||
parameters.Add(parameterType);
|
||||
|
||||
if (parameterText.Length > 0)
|
||||
{
|
||||
parameterText.Append(", ");
|
||||
call.Append(", ");
|
||||
}
|
||||
|
||||
parameterText.Append($"{parameterType.CSharpWrapperType} {param.Name}");
|
||||
|
||||
if (parameterType.WrapperConvertInput is not null)
|
||||
{
|
||||
string convertedParamName = $"{param.Name}Converted";
|
||||
|
||||
parameterConversion.AppendLine();
|
||||
parameterConversion.Append("\t\t");
|
||||
parameterConversion.AppendFormat(parameterType.WrapperConvertInput, convertedParamName, param.Name);
|
||||
|
||||
if (parameterType.WrapperCleanupInput is not null)
|
||||
{
|
||||
cleanup.Append("\t\t");
|
||||
cleanup.AppendFormat(parameterType.WrapperCleanupInput, convertedParamName);
|
||||
cleanup.AppendLine();
|
||||
}
|
||||
|
||||
call.Append(convertedParamName);
|
||||
}
|
||||
else
|
||||
{
|
||||
call.Append(param.Name);
|
||||
}
|
||||
}
|
||||
|
||||
call.Append(");");
|
||||
|
||||
output.AppendLine($$"""
|
||||
public static {{returnType.CSharpWrapperType}} {{method.Name}}({{parameterText}})
|
||||
{{{parameterConversion}}
|
||||
{{call}}
|
||||
{{cleanup}}
|
||||
{{returnType.ReturnValueConversion}}
|
||||
}
|
||||
|
||||
""");
|
||||
|
||||
|
||||
}
|
||||
|
||||
private static void GenerateCode(
|
||||
SourceProductionContext context,
|
||||
GeneratorInput input)
|
||||
{
|
||||
Dictionary<string, MappedType> beefTypeToMappedType = new();
|
||||
|
||||
InitializeTypes(beefTypeToMappedType);
|
||||
|
||||
foreach (ITypeSymbol? mapping in input.TypeMappings)
|
||||
{
|
||||
if (mapping is null)
|
||||
continue;
|
||||
|
||||
string csharpTypeName = mapping.ToDisplayString();
|
||||
|
||||
foreach (AttributeData attribute in mapping.GetAttributes()
|
||||
.Where(attribute => attribute.AttributeClass?.Name == "EngineClassAttribute"))
|
||||
{
|
||||
string? beefTypeName = attribute.ConstructorArguments[0].Value?.ToString();
|
||||
|
||||
if (beefTypeName is null)
|
||||
continue;
|
||||
|
||||
MappedType newMapping = DecodeType(beefTypeName, beefTypeToMappedType);
|
||||
newMapping.CSharpTypeName = csharpTypeName;
|
||||
}
|
||||
}
|
||||
|
||||
StringBuilder engineFunctions = new StringBuilder();
|
||||
StringBuilder wrappers = new StringBuilder();
|
||||
|
||||
engineFunctions.Append("""
|
||||
// <auto-generated />
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace GlitchyEngine;
|
||||
|
||||
unsafe internal partial struct EngineFunctions
|
||||
{
|
||||
/*
|
||||
""");
|
||||
|
||||
wrappers.Append("""
|
||||
// <auto-generated />
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace GlitchyEngine;
|
||||
|
||||
unsafe internal partial class ScriptGlue
|
||||
{
|
||||
""");
|
||||
|
||||
List<GlueMethod> methods = new List<GlueMethod>();
|
||||
|
||||
foreach (string glueFunctions in input.GlueFunctionDefinitions)
|
||||
{
|
||||
methods.AddRange(JsonSerializer.Deserialize<GlueMethod[]>(glueFunctions) ?? []);
|
||||
}
|
||||
|
||||
foreach (GlueMethod method in methods)
|
||||
{
|
||||
if (!input.ExistingEngineFunctionStructs.Contains(method.Name))
|
||||
{
|
||||
GenerateFunctionPointer(method, beefTypeToMappedType, engineFunctions);
|
||||
}
|
||||
|
||||
if (!input.ExistingScriptGlueClasses.Contains(method.Name))
|
||||
{
|
||||
GenerateWrapper(method, beefTypeToMappedType, wrappers);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// foreach (var type in input.enumerations)
|
||||
// {
|
||||
// if (type is null)
|
||||
// continue;
|
||||
//
|
||||
// GenerateCode(type, output);
|
||||
// var typeNamespace = type.ContainingNamespace.IsGlobalNamespace
|
||||
// ? null
|
||||
// : $"{type.ContainingNamespace}.";
|
||||
//
|
||||
// }
|
||||
|
||||
engineFunctions.Append("\n*/}");
|
||||
wrappers.Append("\n}");
|
||||
|
||||
context.AddSource("EngineFunctions.g.cs", engineFunctions.ToString());
|
||||
context.AddSource("ScriptGlue.g.cs", wrappers.ToString());
|
||||
}
|
||||
|
||||
private static bool IsScriptGlueClass(
|
||||
SyntaxNode syntaxNode,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
return syntaxNode is ClassDeclarationSyntax { Identifier.ValueText: "ScriptGlue" };
|
||||
}
|
||||
|
||||
private static bool IsEngineFunctionsStruct (
|
||||
SyntaxNode syntaxNode,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
return syntaxNode is StructDeclarationSyntax { Identifier.ValueText: "EngineFunctions" };
|
||||
}
|
||||
|
||||
private static INamedTypeSymbol? GetSymbol<T>(GeneratorSyntaxContext context,
|
||||
CancellationToken cancellationToken) where T : BaseTypeDeclarationSyntax
|
||||
{
|
||||
var classDecl = (T)context.Node;
|
||||
return context.SemanticModel.GetDeclaredSymbol(classDecl) as INamedTypeSymbol;
|
||||
}
|
||||
|
||||
private static bool CouldBeMappedType(
|
||||
SyntaxNode syntaxNode,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
if (syntaxNode is not AttributeSyntax attribute)
|
||||
return false;
|
||||
|
||||
var name = ExtractName(attribute.Name);
|
||||
|
||||
return name is "EngineClass" or "EngineClassAttribute";
|
||||
}
|
||||
|
||||
private static string? ExtractName(NameSyntax? name)
|
||||
{
|
||||
return name switch
|
||||
{
|
||||
SimpleNameSyntax ins => ins.Identifier.Text,
|
||||
QualifiedNameSyntax qns => qns.Right.Identifier.Text,
|
||||
_ => null
|
||||
};
|
||||
}
|
||||
|
||||
private static ITypeSymbol? GetTypeOrNull(
|
||||
GeneratorSyntaxContext context,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var attributeSyntax = (AttributeSyntax)context.Node;
|
||||
|
||||
// "attribute.Parent" is "AttributeListSyntax"
|
||||
// "attribute.Parent.Parent" is a C# fragment the attributes are applied to
|
||||
if (attributeSyntax.Parent?.Parent is not BaseTypeDeclarationSyntax typeDeclaration)
|
||||
return null;
|
||||
|
||||
return context.SemanticModel.GetDeclaredSymbol(typeDeclaration) as ITypeSymbol;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user