private void WriteType(TypeDefinition type) { if (type.HasAttribute("PureJSService")) { return; } var interfaces = type.Interfaces.Select(x => x.InterfaceType.AsCsName()).ToList(); var isComponentData = type.Interfaces.Count(x => x.InterfaceType.Name == "IComponentData") != 0 || type.Interfaces.Count(x => x.InterfaceType.Name == "ISharedComponentData") != 0 || type.Interfaces.Count(x => x.InterfaceType.Name == "ISystemStateComponentData") != 0; if (isComponentData && !BindGem.PureJS) { interfaces.Add("UTiny.IComponentDataInternal"); if (type.IsPodType()) { interfaces.Add("UTiny.IComponentIsPodData"); } } var interfacesLine = isComponentData ? ": " + String.Join(", ", interfaces) : ""; string kind; if (type.IsInterface) { kind = type.HasAttribute("Service") ? "static class" : "partial struct"; } else { kind = type.HasAttribute("CsPartial") ? "partial struct" : "struct"; } bool isService = type.HasAttribute("Service"); bool isNativeClassType = type.IsInterface && !isService; bool isConstructable = type.HasAttribute("Constructable") && !isService; line("namespace " + type.Namespace); line("{"); if (type.IsComponentType() || type.IsStructValueType()) { line( " [global::System.Runtime.InteropServices.StructLayout(global::System.Runtime.InteropServices.LayoutKind.Sequential)]"); } line($" public {kind} {type.CsName()} {interfacesLine}"); line(" {"); var constructorName = $"ut_{type.Name}_{type.Name}"; var cppFnName = type.FullyQualifiedCppName("_"); if (isNativeClassType) { line($" public global::System.IntPtr mThis;"); line($" [global::System.Runtime.InteropServices.DllImport(UTiny.Interop.NativeLibraryName)]"); line($" private static extern global::System.IntPtr {constructorName}();"); line($" public {type.CsName()}(global::System.IntPtr t) {{ mThis = t; }}"); line(""); line($" [global::System.Runtime.InteropServices.DllImport(UTiny.Interop.NativeLibraryName)]"); line($" private static extern void ut_{type.Name}_shRelease(global::System.IntPtr ptr);"); line($" public void _NativeRelease() {{ ut_{type.Name}_shRelease(mThis); mThis = global::System.IntPtr.Zero; }}"); } if (isConstructable) { line($" public static {type.CsName()} New{type.CsName()}() {{ return new {type.CsName()}({constructorName}()); }}"); } line(""); if (isComponentData && !BindGem.PureJS) { line($@" [global::System.Runtime.InteropServices.DllImport(UTiny.Interop.NativeLibraryName)]"); line($@" internal static extern int {cppFnName}_cid();"); line($@" public int NativeComponentId() {{ return {cppFnName}_cid(); }}"); GenerateComponentSerializeToNativeCppMethod(type); GenerateComponentDeserializeFromNativeCppMethod(type); } line(""); foreach (var f in type.Fields) { if (f.FieldType.MetadataType == MetadataType.String) { line($" public string {f.Name};"); } else if (f.FieldType.IsDynamicArray()) { line($" public {f.FieldType.DynamicArrayElementType().AsCsName()}[] {f.Name};"); } else { line($" public {f.FieldType.AsCsName()} {CSharpIdentifierFor(f.Name)};"); } } line(""); line(""); foreach (var m in type.MemberFunctions()) { if (m.HasAttribute("CsCustomImpl")) { continue; } // Declare the DllImported C call line($" [global::System.Runtime.InteropServices.DllImport(UTiny.Interop.NativeLibraryName)]"); if (m.ReturnType.Resolve().MetadataType == MetadataType.Boolean && !m.ReturnType.IsPointer) { line($" [return:global::System.Runtime.InteropServices.MarshalAs(global::System.Runtime.InteropServices.UnmanagedType.I1)]"); } line($" private static unsafe extern {m.ReturnType.AsCsReturnName()} {cppFnName}_{m.Name}({ParameterListForCCall(m, isService, isService).JoinWithComma()});"); // Then declare the public C# API line($" public {(isService || m.IsStatic ? "static " : "")}unsafe {m.ReturnType.AsCsName()} {m.Name}({ParameterList(m, true, false).JoinWithComma()})"); line($" {{"); var callStr = $"{cppFnName}_{m.Name}({ParameterNamesForCCall(m, isNativeClassType || isService, isService).JoinWithComma()})"; if ((type.IsStructValueType() || type.IsComponentType()) && !m.IsStatic) { line($" //fixed ({type.AsCsName()}* self = &this)"); line($" void* self = UnsafeUtility.AddressOf(ref this);"); } // Marshal type conversions for C# -> C++ call for (int i = 0; i < m.Parameters.Count; ++i) { if (m.Parameters[i].ParameterType.MetadataType == MetadataType.String) { line($" NativeString arg{i}str = new NativeString();"); line($" StringInterop.ut_nativestring_placement_create(&arg{i}str, (uint)StringInterop.StringLengthUtf8(arg{i}));"); line($" StringInterop.StringToUtf8(arg{i}, arg{i}str.mStr, arg{i}str.mSize+1);"); } else if (m.Parameters[i].ParameterType.IsDynamicArray()) { if (m.Parameters[i].ParameterType.DynamicArrayElementType().MetadataType == MetadataType.String) { line($" NativeBuffer arg{i}arr = StringInterop.StringListToNewNativeBuffer(arg{i});"); } else { var sz32 = TypeUtils.AlignAndSizeOfType(m.Parameters[i].ParameterType.DynamicArrayElementType(), 32); var sz64 = TypeUtils.AlignAndSizeOfType(m.Parameters[i].ParameterType.DynamicArrayElementType(), 64); string sizeString = (sz32.size == sz64.size) ? sz32.size.ToString() : $"global::System.IntPtr.Size == 8 ? {sz64.size} : {sz32.size}"; line($" NativeBuffer arg{i}arr = StringInterop.PodDataListToNewNativeBuffer(arg{i}, {sizeString});"); } } } string retval = null; if (m.ReturnType.MetadataType == MetadataType.Void) { line($" {callStr};"); } else if (m.ReturnType.MetadataType == MetadataType.String) { line($" NativeString retval;"); line($" {callStr};"); line($" string str = StringInterop.Utf8ToString(retval.mStr, retval.mSize);"); line($" StringInterop.ut_nativestring_free_data(&retval);"); retval = "str"; } else if (m.ReturnType.IsSharedPtrType() || m.ReturnType.IsNonSharedPtrType()) { line($" var ptr = {callStr};"); retval = $"new {m.ReturnType.Resolve().AsCsName()}(ptr)"; } else if (m.ReturnType.EmCppReturnToFirstArgPtr()) { line($" {m.ReturnType.AsCsName()} retval;"); line($" {callStr};"); retval = "retval"; } else { line($" {m.ReturnType.AsCsName()} retval = {callStr};"); retval = "retval"; } // Cleanup for marshalled type conversions for C# -> C++ calls for (int i = 0; i < m.Parameters.Count; ++i) { if (m.Parameters[i].ParameterType.MetadataType == MetadataType.String) { line($" StringInterop.ut_nativestring_placement_delete(&arg{i}str);"); } else if (m.Parameters[i].ParameterType.IsDynamicArray()) { if (m.Parameters[i].ParameterType.DynamicArrayElementType().MetadataType == MetadataType.String) { line($" StringInterop.ut_nativebuffer_nativestring_placement_delete(&arg{i}arr);"); } else { line($" StringInterop.ut_nativebuffer_pod_placement_delete(&arg{i}arr);"); } } } if (retval != null) { line($" return {retval};"); } line($" }}"); line(""); } line(""); foreach (var e in type.NestedTypes.Where(x => x.IsEnum)) { line($" public enum {e.Name}"); line(" {"); foreach (var field in e.Fields.Where(f => f.IsStatic)) { line($" {field.Name} = {field.Constant},"); } line(" }"); } line(" }"); line("}"); }