From 53724fd47cc175bb1f1fc505028ebcf4fb2b65b3 Mon Sep 17 00:00:00 2001 From: Sam Deane Date: Thu, 19 Dec 2024 14:13:47 +0000 Subject: [PATCH] Reverted formatting changes --- Generator/Generator/ClassGen.swift | 1141 +++++++++++++------------- Generator/Generator/Printer.swift | 264 +++--- Generator/Generator/UtilityGen.swift | 32 +- Generator/Generator/main.swift | 183 ++--- Sources/SwiftGodot/EntryPoint.swift | 652 +++++++-------- 5 files changed, 1129 insertions(+), 1143 deletions(-) diff --git a/Generator/Generator/ClassGen.swift b/Generator/Generator/ClassGen.swift index 8f4ee3143..c17e6cae0 100644 --- a/Generator/Generator/ClassGen.swift +++ b/Generator/Generator/ClassGen.swift @@ -5,251 +5,248 @@ // Created by Miguel de Icaza on 3/26/23. // -import ExtensionApi import Foundation +import ExtensionApi -func makeDefaultInit(godotType: String, initCollection: String = "") -> String { - switch godotType { - case "Variant": - return "nil" - case "int": - return "0" - case "float": - return "0.0" - case "bool": - return "false" - case "String": - return "String ()" - case "Array": - return "GArray ()" - case "Dictionary": - return "GDictionary ()" - case let t where t.starts(with: "typedarray::"): - let nestedTypeName = String(t.dropFirst(12)) - let simple = SimpleType(type: nestedTypeName) - if classMap[nestedTypeName] != nil { - return "ObjectCollection<\(getGodotType (simple))>(\(initCollection))" - } else { - return "VariantCollection<\(getGodotType (simple))>(\(initCollection))" +func makeDefaultInit (godotType: String, initCollection: String = "") -> String { + switch godotType { + case "Variant": + return "nil" + case "int": + return "0" + case "float": + return "0.0" + case "bool": + return "false" + case "String": + return "String ()" + case "Array": + return "GArray ()" + case "Dictionary": + return "GDictionary ()" + case let t where t.starts (with: "typedarray::"): + let nestedTypeName = String (t.dropFirst(12)) + let simple = SimpleType(type: nestedTypeName) + if classMap [nestedTypeName] != nil { + return "ObjectCollection<\(getGodotType (simple))>(\(initCollection))" + } else { + return "VariantCollection<\(getGodotType (simple))>(\(initCollection))" + } + case "enum::Error": + return ".ok" + case "enum::Variant.Type": + return ".`nil`" + case let e where e.starts (with: "enum::"): + return "\(e.dropFirst(6))(rawValue: 0)!" + case let e where e.starts (with: "bitfield::"): + let simple = SimpleType (type: godotType, meta: nil) + return "\(getGodotType (simple)) ()" + + case let other where builtinGodotTypeNames [other] != nil: + return "\(godotType) ()" + case "void*", "const Glyph*": + return "nil" + default: + return "\(getGodotType(SimpleType (type: godotType))) ()" } - case "enum::Error": - return ".ok" - case "enum::Variant.Type": - return ".`nil`" - case let e where e.starts(with: "enum::"): - return "\(e.dropFirst(6))(rawValue: 0)!" - case let e where e.starts(with: "bitfield::"): - let simple = SimpleType(type: godotType, meta: nil) - return "\(getGodotType (simple)) ()" - - case let other where builtinGodotTypeNames[other] != nil: - return "\(godotType) ()" - case "void*", "const Glyph*": - return "nil" - default: - return "\(getGodotType(SimpleType (type: godotType))) ()" - } -} - -func makeDefaultReturn(godotType: String) -> String { - return "return \(makeDefaultInit(godotType: godotType))" } -func argTypeNeedsCopy(godotType: String) -> Bool { - if isStruct(godotType) { - return true - } - if godotType.starts(with: "enum::") { - return true - } - if godotType.starts(with: "bitfield::") { - return true - } - return false +func makeDefaultReturn (godotType: String) -> String { + return "return \(makeDefaultInit(godotType: godotType))" } -func generateVirtualProxy( - _ p: Printer, - cdef: JGodotExtensionAPIClass, - methodName: String, - method: JGodotClassMethod -) { - // Generate the glue for the virtual methods (those that start with an underscore in Godot - guard method.isVirtual else { - print("ERROR: internally, we passed methods that are not virtual") - return - } - let virtRet: String? - var returnOptional = false - if let ret = method.returnValue { - let godotReturnType = ret.type - let godotReturnTypeIsReferenceType = classMap[godotReturnType] != nil - returnOptional = godotReturnTypeIsReferenceType && isReturnOptional(className: cdef.name, method: methodName) - - virtRet = getGodotType(ret) - } else { - virtRet = nil - } - p("func _\(cdef.name)_proxy\(method.name) (instance: UnsafeMutableRawPointer?, args: UnsafePointer?, retPtr: UnsafeMutableRawPointer?)") { - p("guard let instance else { return }") - if let arguments = method.arguments, arguments.count > 0 { - p("guard let args else { return }") +func argTypeNeedsCopy (godotType: String) -> Bool { + if isStruct(godotType) { + return true } - p("let swiftObject = Unmanaged<\(cdef.name)>.fromOpaque(instance).takeUnretainedValue()") - - var argCall = "" - var argPrep = "" - var i = 0 - for arg in method.arguments ?? [] { - if argCall != "" { argCall += ", " } - let argName = escapeSwift(snakeToCamel(arg.name)) - - // Drop the first argument name for methods whose name already include the argument - // name, like 'setMultiplayerPeer (peer: ..)' becomes 'setMultiplayerPeer (_ peer: ...)' - if i > 0 || !method.name.hasSuffix("_\(arg.name)") { - argCall += "\(argName): " - } - if arg.type == "String" { - argCall += "GString.stringFromGStringPtr (ptr: args [\(i)]!) ?? \"\"" - } else if classMap[arg.type] != nil { - // - // This idiom guarantees that: if this is a known object, we surface this - // object, but if it is not known, then we create the instance - // - argPrep += "let resolved_\(i) = args [\(i)]!.load (as: UnsafeRawPointer.self)\n" - let handleResolver: String - if hasSubclasses.contains(cdef.name) { - // If the type we are bubbling up has subclasses, we want to create the most - // derived type if possible, so we perform the longer lookup - handleResolver = "lookupObject (nativeHandle: resolved_\(i))!" - } else { - // There are no subclasses, so we can create the object right away - handleResolver = "\(arg.type) (nativeHandle: resolved_\(i))" - } - argCall += "lookupLiveObject (handleAddress: resolved_\(i)) as? \(arg.type) ?? \(handleResolver)" - } else if let storage = builtinClassStorage[arg.type] { - argCall += "\(mapTypeName (arg.type)) (content: args [\(i)]!.assumingMemoryBound (to: \(storage).self).pointee)" - } else { - let gt = getGodotType(arg) - argCall += "args [\(i)]!.assumingMemoryBound (to: \(gt).self).pointee" - } - i += 1 - } - let hasReturn = method.returnValue != nil - if argPrep != "" { - p(argPrep) + if godotType.starts(with: "enum::") { + return true } - var call = "swiftObject.\(methodName) (\(argCall))" - if method.returnValue?.type == "String" { - call = "GString (\(call))" + if godotType.starts(with: "bitfield::") { + return true } - if hasReturn { - p("let ret = \(call)") + return false +} + +func generateVirtualProxy (_ p: Printer, + cdef: JGodotExtensionAPIClass, + methodName: String, + method: JGodotClassMethod) { + // Generate the glue for the virtual methods (those that start with an underscore in Godot + guard method.isVirtual else { + print ("ERROR: internally, we passed methods that are not virtual") + return + } + let virtRet: String? + var returnOptional = false + if let ret = method.returnValue { + let godotReturnType = ret.type + let godotReturnTypeIsReferenceType = classMap [godotReturnType] != nil + returnOptional = godotReturnTypeIsReferenceType && isReturnOptional(className: cdef.name, method: methodName) + + virtRet = getGodotType(ret) } else { - p("\(call)") + virtRet = nil } - if let ret = method.returnValue { - if ret.type == "Variant" { - p( - """ - retPtr!.storeBytes(of: ret.content, as: Variant.ContentType.self) - ret?.content = Variant.zero - """) - } else if isStruct(ret.type) || isStruct(virtRet ?? "NON_EXISTENT") || ret.type.starts(with: "bitfield::") { - p("retPtr!.storeBytes (of: ret, as: \(virtRet!).self)") - } else if ret.type.starts(with: "enum::") { - p("retPtr!.storeBytes (of: Int32 (ret.rawValue), as: Int32.self)") - } else if ret.type.contains("*") { - p("retPtr!.storeBytes (of: ret, as: OpaquePointer?.self)") - } else { - let derefField: String - let derefType: String - if ret.type.starts(with: "typedarray::") { - derefField = "array.content" - derefType = "type (of: ret.array.content)" - } else if classMap[ret.type] != nil { - derefField = "handle" - derefType = "UnsafeRawPointer?.self" - } else { - derefField = "content" - derefType = "type (of: ret.content)" + p ("func _\(cdef.name)_proxy\(method.name) (instance: UnsafeMutableRawPointer?, args: UnsafePointer?, retPtr: UnsafeMutableRawPointer?)") { + p ("guard let instance else { return }") + if let arguments = method.arguments, arguments.count > 0 { + p ("guard let args else { return }") } - - let target: String - if ret.type.starts(with: "typedarray::") { - target = "array.content" + p ("let swiftObject = Unmanaged<\(cdef.name)>.fromOpaque(instance).takeUnretainedValue()") + + var argCall = "" + var argPrep = "" + var i = 0 + for arg in method.arguments ?? [] { + if argCall != "" { argCall += ", " } + let argName = escapeSwift (snakeToCamel (arg.name)) + + // Drop the first argument name for methods whose name already include the argument + // name, like 'setMultiplayerPeer (peer: ..)' becomes 'setMultiplayerPeer (_ peer: ...)' + if i > 0 || !method.name.hasSuffix("_\(arg.name)") { + argCall += "\(argName): " + } + if arg.type == "String" { + argCall += "GString.stringFromGStringPtr (ptr: args [\(i)]!) ?? \"\"" + } else if classMap [arg.type] != nil { + // + // This idiom guarantees that: if this is a known object, we surface this + // object, but if it is not known, then we create the instance + // + argPrep += "let resolved_\(i) = args [\(i)]!.load (as: UnsafeRawPointer.self)\n" + let handleResolver: String + if hasSubclasses.contains(cdef.name) { + // If the type we are bubbling up has subclasses, we want to create the most + // derived type if possible, so we perform the longer lookup + handleResolver = "lookupObject (nativeHandle: resolved_\(i))!" + } else { + // There are no subclasses, so we can create the object right away + handleResolver = "\(arg.type) (nativeHandle: resolved_\(i))" + } + argCall += "lookupLiveObject (handleAddress: resolved_\(i)) as? \(arg.type) ?? \(handleResolver)" + } else if let storage = builtinClassStorage [arg.type] { + argCall += "\(mapTypeName (arg.type)) (content: args [\(i)]!.assumingMemoryBound (to: \(storage).self).pointee)" + } else { + let gt = getGodotType(arg) + argCall += "args [\(i)]!.assumingMemoryBound (to: \(gt).self).pointee" + } + i += 1 + } + let hasReturn = method.returnValue != nil + if argPrep != "" { + p (argPrep) + } + var call = "swiftObject.\(methodName) (\(argCall))" + if method.returnValue?.type == "String" { + call = "GString (\(call))" + } + if hasReturn { + p ("let ret = \(call)") } else { - target = classMap[ret.type] != nil ? "handle" : "content" + p ("\(call)") + } + if let ret = method.returnValue { + if ret.type == "Variant" { + p(""" + retPtr!.storeBytes(of: ret.content, as: Variant.ContentType.self) + ret?.content = Variant.zero + """) + } else if isStruct(ret.type) || isStruct(virtRet ?? "NON_EXISTENT") || ret.type.starts(with: "bitfield::"){ + p ("retPtr!.storeBytes (of: ret, as: \(virtRet!).self)") + } else if ret.type.starts(with: "enum::") { + p ("retPtr!.storeBytes (of: Int32 (ret.rawValue), as: Int32.self)") + } else if ret.type.contains("*") { + p ("retPtr!.storeBytes (of: ret, as: OpaquePointer?.self)") + } else { + let derefField: String + let derefType: String + if ret.type.starts(with: "typedarray::") { + derefField = "array.content" + derefType = "type (of: ret.array.content)" + } else if classMap [ret.type] != nil { + derefField = "handle" + derefType = "UnsafeRawPointer?.self" + } else { + derefField = "content" + derefType = "type (of: ret.content)" + } + + let target: String + if ret.type.starts (with: "typedarray::") { + target = "array.content" + } else { + target = classMap [ret.type] != nil ? "handle" : "content" + } + p ("retPtr!.storeBytes (of: ret\(returnOptional ? "?" : "").\(derefField), as: \(derefType)) // \(ret.type)") + + // Poor man's transfer the ownership: we clear the content + // so the destructor has nothing to act on, because we are + // returning the reference to the other side. + if target == "content" { + let type = getGodotType(SimpleType(type: ret.type)) + switch type { + case "String": + p ("ret.content = GString.zero") + case "Array": + p ("ret.content = GArray.zero") + default: + p ("ret.content = \(type).zero") + } + } + } } - p("retPtr!.storeBytes (of: ret\(returnOptional ? "?" : "").\(derefField), as: \(derefType)) // \(ret.type)") - - // Poor man's transfer the ownership: we clear the content - // so the destructor has nothing to act on, because we are - // returning the reference to the other side. - if target == "content" { - let type = getGodotType(SimpleType(type: ret.type)) - switch type { - case "String": - p("ret.content = GString.zero") - case "Array": - p("ret.content = GArray.zero") - default: - p("ret.content = \(type).zero") - } - } - } } - } } // Dictioanry of Godot Type Name to array of method names that can get a @discardableResult // Notice that the type is looked up as the original Godot name, not // the mapped name (it is "Array", not "GArray"): let discardableResultList: [String: Set] = [ - "Object": ["emit_signal"], - "Array": ["resize"], - "PackedByteArray": ["append", "push_back"], - "PackedColorArray": ["append", "push_back", "resize"], - "PackedFloat32Array": ["append", "push_back", "resize"], - "PackedFloat64Array": ["append", "push_back", "resize"], - "PackedInt32Array": ["append", "push_back", "resize"], - "PackedInt64Array": ["append", "push_back", "resize"], - "PackedStringArray": ["append", "push_back", "resize"], - "PackedVector2Array": ["append", "push_back", "resize"], - "PackedVector3Array": ["append", "push_back", "resize"], - "PackedVector4Array": ["append", "push_back", "resize"], - "CharacterBody2D": ["move_and_slide"], - "CharacterBody3D": ["move_and_slide"], - "RefCounted": ["reference", "unreference"], + "Object": ["emit_signal"], + "Array": ["resize"], + "PackedByteArray": ["append", "push_back"], + "PackedColorArray": ["append", "push_back", "resize"], + "PackedFloat32Array": ["append", "push_back", "resize"], + "PackedFloat64Array": ["append", "push_back", "resize"], + "PackedInt32Array": ["append", "push_back", "resize"], + "PackedInt64Array": ["append", "push_back", "resize"], + "PackedStringArray": ["append", "push_back", "resize"], + "PackedVector2Array": ["append", "push_back", "resize"], + "PackedVector3Array": ["append", "push_back", "resize"], + "PackedVector4Array": ["append", "push_back", "resize"], + "CharacterBody2D": ["move_and_slide"], + "CharacterBody3D": ["move_and_slide"], + "RefCounted": ["reference", "unreference"] ] // Dictionary used to tell the generator to _not_ generate specific functionality since // Source/Native has a better alternative that avoids having to access Godot pointers. let omittedMethodsList: [String: Set] = [ - "Color": ["lerp"], - "Vector2": ["lerp", "snapped"], - "Vector2i": ["snapped"], - "Vector3": ["lerp", "snapped"], - "Vector3i": ["snapped"], - "Vector4": ["lerp", "snapped"], - "Vector4i": ["snapped"], - "utility_functions": [ - "absf", "absi", "absi", "acos", "acosh", "asbs", "asin", "asinh", "atan", "atan2", "atanh", "ceil", "ceilf", - "ceili", "cos", "cosh", "deg_to_rad", "exp", "floor", "floor", "floorf", "floorf", "floori", "floori", - "fmod", "fposmod", "inverse_lerp", "lerp", "lerpf", "log", "posmod", "pow", "rad_to_deg", "round", "roundf", - "roundi", "sin", "sinh", "snapped", "snappedf", "sqrt", "tan", "tanh", - ], + "Color": ["lerp"], + "Vector2": ["lerp", "snapped"], + "Vector2i": ["snapped"], + "Vector3": ["lerp", "snapped"], + "Vector3i": ["snapped"], + "Vector4": ["lerp", "snapped"], + "Vector4i": ["snapped"], + "utility_functions": [ + "absf", "absi", "absi", "acos", "acosh", "asbs", "asin", "asinh", "atan", "atan2", "atanh", "ceil", "ceilf", + "ceili", "cos", "cosh", "deg_to_rad", "exp", "floor", "floor", "floorf", "floorf", "floori", "floori", + "fmod", "fposmod", "inverse_lerp", "lerp", "lerpf", "log", "posmod", "pow", "rad_to_deg", "round", "roundf", + "roundi", "sin", "sinh", "snapped", "snappedf", "sqrt", "tan", "tanh", + ], ] // Dictionary used to explicitly tell the generator to replace the first argument label with "_ " let omittedFirstArgLabelList: [String: Set] = [ - "GArray": ["append"], - "PackedColorArray": ["append"], - "PackedFloat64Array": ["append"], - "PackedInt64Array": ["append"], - "PackedStringArray": ["append"], - "PackedVector2Array": ["append"], - "PackedVector3Array": ["append"], + "GArray": ["append"], + "PackedColorArray": ["append"], + "PackedFloat64Array": ["append"], + "PackedInt64Array": ["append"], + "PackedStringArray": ["append"], + "PackedVector2Array": ["append"], + "PackedVector3Array": ["append"], ] @@ -263,417 +260,407 @@ let omittedFirstArgLabelList: [String: Set] = [ /// - methodName: Name of the method /// - argName: Name of the argument func shouldOmitFirstArgLabel(typeName: String, methodName: String, argName: String) -> Bool { - return methodName.hasSuffix("_\(argName)") || omittedFirstArgLabelList[typeName]?.contains(methodName) == true + return methodName.hasSuffix ("_\(argName)") || omittedFirstArgLabelList[typeName]?.contains(methodName) == true } /// /// Returns a hashtable mapping a godot method name to a Swift Name + its definition /// this list is used to generate later the proxies outside the class /// -func generateMethods( - _ p: Printer, - cdef: JGodotExtensionAPIClass, - methods: [JGodotClassMethod], - usedMethods: Set, - asSingleton: Bool -) -> [String: (String, JGodotClassMethod)] { - p("/* Methods */") - - var virtuals: [String: (String, JGodotClassMethod)] = [:] - - for method in methods { - performExplaniningNonCriticalErrors { - if let virtualMethodName = try generateMethod(p, method: method, className: cdef.name, cdef: cdef, usedMethods: usedMethods, generatedMethodKind: .classMethod, asSingleton: asSingleton) { - virtuals[method.name] = (virtualMethodName, method) - } +func generateMethods (_ p: Printer, + cdef: JGodotExtensionAPIClass, + methods: [JGodotClassMethod], + usedMethods: Set, + asSingleton: Bool) -> [String:(String, JGodotClassMethod)] { + p ("/* Methods */") + + var virtuals: [String:(String, JGodotClassMethod)] = [:] + + for method in methods { + performExplaniningNonCriticalErrors { + if let virtualMethodName = try generateMethod (p, method: method, className: cdef.name, cdef: cdef, usedMethods: usedMethods, generatedMethodKind: .classMethod, asSingleton: asSingleton) { + virtuals[method.name] = (virtualMethodName, method) + } + } } - } - - if virtuals.count > 0 { - p("override class func getVirtualDispatcher (name: StringName) -> GDExtensionClassCallVirtual?") { - p("guard implementedOverrides().contains(name) else { return nil }") - p("switch name.description") { - for name in virtuals.keys.sorted() { - p("case \"\(name)\":") - p(" return _\(cdef.name)_proxy\(name)") - } - p("default:") - p(" return super.getVirtualDispatcher (name: name)") - } + + if virtuals.count > 0 { + p ("override class func getVirtualDispatcher (name: StringName) -> GDExtensionClassCallVirtual?"){ + p ("guard implementedOverrides().contains(name) else { return nil }") + p ("switch name.description") { + for name in virtuals.keys.sorted() { + p ("case \"\(name)\":") + p (" return _\(cdef.name)_proxy\(name)") + } + p ("default:") + p (" return super.getVirtualDispatcher (name: name)") + } + } } - } - return virtuals + return virtuals } -func generateConstants( - _ p: Printer, - cdef: JGodotExtensionAPIClass, - _ constants: [JGodotValueElement] -) { - p("/* Constants */") - - for constant in constants { - doc(p, cdef, constant.description) - p("public static let \(snakeToCamel (constant.name)) = \(constant.value)") - } -} -func generateProperties( - _ p: Printer, - cdef: JGodotExtensionAPIClass, - _ properties: [JGodotProperty], - _ methods: [JGodotClassMethod], - _ referencedMethods: inout Set, - asSingleton: Bool -) { - p("\n/* Properties */\n") - - func findMethod(forProperty: JGodotProperty, startAt: JGodotExtensionAPIClass, name: String, resolvedName: inout String, argName: inout String) -> JGodotClassMethod? { - if let here = methods.first(where: { $0.name == name }) { - return here - } - var cdef: JGodotExtensionAPIClass? = startAt - while true { - guard let parentName = cdef?.inherits, parentName != "" else { - return nil - } - cdef = classMap[parentName] - guard let cdef else { - print("Warning: Missing type \(parentName)") - return nil - } - if let there = cdef.methods?.first(where: { $0.name == name }) { - //print ("Congrats, found a method that was previously missing!") - - // Now, if the parent class has a property referencing this, - // we use the mapped name, otherwise, we use the raw name - if cdef.properties?.contains(where: { $0.getter == there.name || $0.setter == there.name }) ?? false { - return there - } - resolvedName = godotMethodToSwift(there.name) - if let aname = there.arguments?.first?.name { - // Now check thta this argument does not need to be dropped - if !there.name.hasSuffix("_\(aname)") { - argName = aname + ": " - } - } - return there - } - } - } - - for property in properties { - var type: String? - - // Ignore properties that only have getters, just let the setter - // method be surfaced instead - if property.getter == "" { - print("Property with only a setter: \(cdef.name).\(property.name)") - continue - } - if property.getter.starts(with: "_") { - // These exist, but have no equivalent method - // see VisualShaderNodeParameterRef._parameter_type as an example - continue - } - - // // There are properties declared, but they do not actually exist - // // CurveTexture claims to have a get_width, but the method does not exist - // if type == nil { - // continue - // } - // if type!.hasPrefix("Vector3.Axis") { - // continue - // } - let loc = "\(cdef.name).\(property.name)" - - var getterName = property.getter - var gettterArgName = "" - guard let method = findMethod(forProperty: property, startAt: cdef, name: property.getter, resolvedName: &getterName, argName: &gettterArgName) else { - // Not a bug, but needs to be handled https://github.com/migueldeicaza/SwiftGodot/issues/67 - //print ("GodotBug: \(loc): property declared \(property.getter), but it does not exist with that name") - continue +func generateConstants (_ p: Printer, + cdef: JGodotExtensionAPIClass, + _ constants: [JGodotValueElement]) { + p ("/* Constants */") + + for constant in constants { + doc (p, cdef, constant.description) + p ("public static let \(snakeToCamel (constant.name)) = \(constant.value)") } - var setterName = property.setter ?? "" - var setterArgName = "" - var setterMethod: JGodotClassMethod? = nil - if let psetter = property.setter { - setterMethod = findMethod(forProperty: property, startAt: cdef, name: psetter, resolvedName: &setterName, argName: &setterArgName) - if setterMethod == nil { - // Not a bug, but needs to be handled: https://github.com/migueldeicaza/SwiftGodot/issues/67 - //print ("GodotBug \(loc) property declared \(property.setter!) but it does not exist with that name") - continue - } - } - - if method.arguments?.count ?? 0 > 1 { - print("WARNING \(loc) property references a getter method that takes more than one argument") - continue - } - if setterMethod?.arguments?.count ?? 0 > 2 { - print("WARNING \(loc) property references a getter method that takes more than two arguments") - continue - } - guard (method.returnValue?.type) != nil else { - print("WARNING \(loc) Could not get a return type for method") - continue +} +func generateProperties (_ p: Printer, + cdef: JGodotExtensionAPIClass, + _ properties: [JGodotProperty], + _ methods: [JGodotClassMethod], + _ referencedMethods: inout Set, + asSingleton: Bool) +{ + p ("\n/* Properties */\n") + + func findMethod (forProperty: JGodotProperty, startAt: JGodotExtensionAPIClass, name: String, resolvedName: inout String, argName: inout String) -> JGodotClassMethod? { + if let here = methods.first(where: { $0.name == name}) { + return here + } + var cdef: JGodotExtensionAPIClass? = startAt + while true { + guard let parentName = cdef?.inherits, parentName != "" else { + return nil + } + cdef = classMap [parentName] + guard let cdef else { + print ("Warning: Missing type \(parentName)") + return nil + } + if let there = cdef.methods?.first (where: { $0.name == name }) { + //print ("Congrats, found a method that was previously missing!") + + // Now, if the parent class has a property referencing this, + // we use the mapped name, otherwise, we use the raw name + if cdef.properties?.contains(where: { $0.getter == there.name || $0.setter == there.name }) ?? false { + return there + } + resolvedName = godotMethodToSwift (there.name) + if let aname = there.arguments?.first?.name { + // Now check thta this argument does not need to be dropped + if !there.name.hasSuffix("_\(aname)") { + argName = aname + ": " + } + } + return there + } + } } - let godotReturnType = method.returnValue?.type - let godotReturnTypeIsReferenceType = classMap[godotReturnType ?? ""] != nil - - let propertyOptional = godotReturnType == "Variant" || godotReturnTypeIsReferenceType && isReturnOptional(className: cdef.name, method: property.getter) - - // Lookup the type from the method, not the property, - // sometimes the method is a GString, but the property is a StringName - type = getGodotType(method.returnValue) + (propertyOptional ? "?" : "") + + for property in properties { + var type: String? + + // Ignore properties that only have getters, just let the setter + // method be surfaced instead + if property.getter == "" { + print ("Property with only a setter: \(cdef.name).\(property.name)") + continue + } + if property.getter.starts(with: "_") { + // These exist, but have no equivalent method + // see VisualShaderNodeParameterRef._parameter_type as an example + continue + } - // Ok, we have an indexer, this means we call the property with an int - // but we need the type from the method - var access: String - if let idx = property.index { - let type = getGodotType(method.arguments![0]) - if type == "Int32" { - access = "\(idx)" - } else { - access = "\(type) (rawValue: \(idx))!" - } - } else { - access = "" - } +// // There are properties declared, but they do not actually exist +// // CurveTexture claims to have a get_width, but the method does not exist +// if type == nil { +// continue +// } +// if type!.hasPrefix("Vector3.Axis") { +// continue +// } + let loc = "\(cdef.name).\(property.name)" + + var getterName = property.getter + var gettterArgName = "" + guard let method = findMethod (forProperty: property, startAt: cdef, name: property.getter, resolvedName: &getterName, argName: &gettterArgName) else { + // Not a bug, but needs to be handled https://github.com/migueldeicaza/SwiftGodot/issues/67 + //print ("GodotBug: \(loc): property declared \(property.getter), but it does not exist with that name") + continue + } + var setterName = property.setter ?? "" + var setterArgName = "" + var setterMethod: JGodotClassMethod? = nil + if let psetter = property.setter { + setterMethod = findMethod(forProperty: property, startAt: cdef, name: psetter, resolvedName: &setterName, argName: &setterArgName) + if setterMethod == nil { + // Not a bug, but needs to be handled: https://github.com/migueldeicaza/SwiftGodot/issues/67 + //print ("GodotBug \(loc) property declared \(property.setter!) but it does not exist with that name") + continue + } + } - if property.description != "" { - doc(p, cdef, property.description) - } - p("\(asSingleton ? "static" : "final") public var \(godotPropertyToSwift (property.name)): \(type!)") { - p("get") { - p("return \(getterName) (\(gettterArgName)\(access))") - } - referencedMethods.insert(property.getter) - if let setter = property.setter { - p("set") { - var value = "newValue" - if type == "StringName" && setterMethod?.arguments![0].type == "String" { - value = "String (newValue)" - } - var ignore = "" - if setterMethod?.returnValue != nil { - ignore = "_ = " - } - p("\(ignore)\(setterName) (\(access)\(access != "" ? ", " : "")\(setterArgName)\(value))") - } - referencedMethods.insert(setter) - } + if method.arguments?.count ?? 0 > 1 { + print ("WARNING \(loc) property references a getter method that takes more than one argument") + continue + } + if setterMethod?.arguments?.count ?? 0 > 2 { + print ("WARNING \(loc) property references a getter method that takes more than two arguments") + continue + } + guard (method.returnValue?.type) != nil else { + print ("WARNING \(loc) Could not get a return type for method") + continue + } + let godotReturnType = method.returnValue?.type + let godotReturnTypeIsReferenceType = classMap [godotReturnType ?? ""] != nil + + let propertyOptional = godotReturnType == "Variant" || godotReturnTypeIsReferenceType && isReturnOptional(className: cdef.name, method: property.getter) + + // Lookup the type from the method, not the property, + // sometimes the method is a GString, but the property is a StringName + type = getGodotType (method.returnValue) + (propertyOptional ? "?" : "") + + + // Ok, we have an indexer, this means we call the property with an int + // but we need the type from the method + var access: String + if let idx = property.index { + let type = getGodotType(method.arguments! [0]) + if type == "Int32" { + access = "\(idx)" + } else { + access = "\(type) (rawValue: \(idx))!" + } + } else { + access = "" + } + + if property.description != "" { + doc (p, cdef, property.description) + } + p ("\(asSingleton ? "static" : "final") public var \(godotPropertyToSwift (property.name)): \(type!)"){ + p ("get"){ + p ("return \(getterName) (\(gettterArgName)\(access))") + } + referencedMethods.insert (property.getter) + if let setter = property.setter { + p ("set") { + var value = "newValue" + if type == "StringName" && setterMethod?.arguments![0].type == "String" { + value = "String (newValue)" + } + var ignore = "" + if setterMethod?.returnValue != nil { + ignore = "_ = " + } + p ("\(ignore)\(setterName) (\(access)\(access != "" ? ", " : "")\(setterArgName)\(value))") + } + referencedMethods.insert (setter) + } + } } - } } #if false - var okList: Set = [ - "RefCounted", "Node", "Sprite2D", "Node2D", "CanvasItem", "Object", "String", "StringName", "AStar2D", "Material", "Camera3D", "Node3D", "ProjectSettings", "MeshInstance3D", "BoxMesh", - "SceneTree", "Window", "Label", "Timer", "AudioStreamPlayer", "PackedScene", "PathFollow2D", "InputEvent", "ClassDB", "AnimatedSprite2D", "Input", "CollisionShape2D", "SpriteFrames", - "RigidBody2D", - ] - var skipList = Set() +var okList: Set = [ "RefCounted", "Node", "Sprite2D", "Node2D", "CanvasItem", "Object", "String", "StringName", "AStar2D", "Material", "Camera3D", "Node3D", "ProjectSettings", "MeshInstance3D", "BoxMesh", "SceneTree", "Window", "Label", "Timer", "AudioStreamPlayer", "PackedScene", "PathFollow2D", "InputEvent", "ClassDB", "AnimatedSprite2D", "Input", "CollisionShape2D", "SpriteFrames", "RigidBody2D" ] +var skipList = Set() #else - var okList = Set() - var skipList = Set() +var okList = Set() +var skipList = Set() #endif -func generateClasses(values: [JGodotExtensionAPIClass], outputDir: String?) async { - await withTaskGroup(of: Void.self) { group in - for cdef in values { - group.addTask { - await processClass(cdef: cdef, outputDir: outputDir) - } +func generateClasses (values: [JGodotExtensionAPIClass], outputDir: String?) async { + await withTaskGroup(of: Void.self) { group in + for cdef in values { + group.addTask { + await processClass (cdef: cdef, outputDir: outputDir) + } + } } - } } -func generateSignals( - _ p: Printer, - cdef: JGodotExtensionAPIClass, - signals: [JGodotSignal] -) { - p("// Signals ") - var parameterSignals: [JGodotSignal] = [] - - for signal in signals { - let signalProxyType: String - let lambdaSig: String - if signal.arguments != nil { - parameterSignals.append(signal) - - signalProxyType = getGenericSignalType(signal) - lambdaSig = " \(getGenericSignalLambdaArgs(signal)) in" - } else { - signalProxyType = "GenericSignal< /* no args */ >" - lambdaSig = "" +func generateSignals (_ p: Printer, + cdef: JGodotExtensionAPIClass, + signals: [JGodotSignal]) { + p ("// Signals ") + var parameterSignals: [JGodotSignal] = [] + + for signal in signals { + let signalProxyType: String + let lambdaSig: String + if signal.arguments != nil { + parameterSignals.append (signal) + + signalProxyType = getGenericSignalType(signal) + lambdaSig = " \(getGenericSignalLambdaArgs(signal)) in" + } else { + signalProxyType = "GenericSignal< /* no args */ >" + lambdaSig = "" + } + let signalName = godotMethodToSwift (signal.name) + + doc (p, cdef, signal.description) + p ("///") + doc (p, cdef, "To connect to this signal, reference this property and call the\n`connect` method with the method you want to invoke\n") + doc (p, cdef, "Example:") + doc (p, cdef, "```swift") + doc (p, cdef, "obj.\(signalName).connect {\(lambdaSig)") + p ("/// print (\"caught signal\")\n/// }") + doc (p, cdef, "```") + p ("public var \(signalName): \(signalProxyType) { \(signalProxyType) (target: self, signalName: \"\(signal.name)\") }") + p ("") } - let signalName = godotMethodToSwift(signal.name) - - doc(p, cdef, signal.description) - p("///") - doc(p, cdef, "To connect to this signal, reference this property and call the\n`connect` method with the method you want to invoke\n") - doc(p, cdef, "Example:") - doc(p, cdef, "```swift") - doc(p, cdef, "obj.\(signalName).connect {\(lambdaSig)") - p("/// print (\"caught signal\")\n/// }") - doc(p, cdef, "```") - p("public var \(signalName): \(signalProxyType) { \(signalProxyType) (target: self, signalName: \"\(signal.name)\") }") - p("") - } } /// Return the type of a signal's parameters. func getGenericSignalType(_ signal: JGodotSignal) -> String { - var argTypes: [String] = [] - for signalArgument in signal.arguments ?? [] { - let godotType = getGodotType(signalArgument) - if !godotType.isEmpty && godotType != "Variant" { - var t = godotType - if !isCoreType(name: t) && !isPrimitiveType(name: signalArgument.type) { - t += "?" - } - argTypes.append(t) + var argTypes: [String] = [] + for signalArgument in signal.arguments ?? [] { + let godotType = getGodotType(signalArgument) + if !godotType.isEmpty && godotType != "Variant" { + var t = godotType + if !isCoreType(name: t) && !isPrimitiveType(name: signalArgument.type) { + t += "?" + } + argTypes.append(t) + } } - } - - return argTypes.isEmpty ? "GenericSignal< /* no args */ >" : "GenericSignal<\(argTypes.joined(separator: ", "))>" -} - + + return argTypes.isEmpty ? "GenericSignal< /* no args */ >" : "GenericSignal<\(argTypes.joined(separator: ", "))>" + } + /// Return the names of a signal's parameters, /// for use in documenting the corresponding lambda. func getGenericSignalLambdaArgs(_ signal: JGodotSignal) -> String { - var argNames: [String] = [] - for signalArgument in signal.arguments ?? [] { - argNames.append(escapeSwift(snakeToCamel(signalArgument.name))) - } - - return argNames.joined(separator: ", ") -} - -func generateSignalDocAppendix(_ p: Printer, cdef: JGodotExtensionAPIClass, signals: [JGodotSignal]?) { - guard let signals = signals, signals.count > 0 else { - return - } - if signals.count > 0 { - doc(p, cdef, "\nThis object emits the following signals:") - } else { - doc(p, cdef, "\nThis object emits this signal:") - } - for signal in signals { - let signalName = godotMethodToSwift(signal.name) - doc(p, cdef, "- ``\(signalName)``") - } -} - -func processClass(cdef: JGodotExtensionAPIClass, outputDir: String?) async { - // Determine if it is a singleton, but exclude EditorInterface - let isSingleton = jsonApi.singletons.contains(where: { $0.name == cdef.name }) - let asSingleton = isSingleton && cdef.name != "EditorInterface" - - // Clear the result - let p = await PrinterFactory.shared.initPrinter(cdef.name, withPreamble: true) - - // Save it - defer { - if let outputDir { - p.save(outputDir + "\(cdef.name).swift") + var argNames: [String] = [] + for signalArgument in signal.arguments ?? [] { + argNames.append(escapeSwift(snakeToCamel(signalArgument.name))) } - } - let inherits = cdef.inherits ?? "Wrapped" - let typeDecl = "open class \(cdef.name): \(inherits)" - - var virtuals: [String: (String, JGodotClassMethod)] = [:] - if cdef.brief_description == "" { - if cdef.description != "" { - doc(p, cdef, cdef.description) - } - } else { - doc(p, cdef, cdef.brief_description) - if cdef.description != "" { - doc(p, cdef, "") // Add a newline before the fuller description - doc(p, cdef, cdef.description) - } - } - - generateSignalDocAppendix(p, cdef: cdef, signals: cdef.signals) - // class or extension (for Object) - p(typeDecl) { - if isSingleton { - p("/// The shared instance of this class") - p.staticVar(visibility: "public ", name: "shared", type: cdef.name) { - p("return withUnsafePointer (to: &\(cdef.name).godotClassName.content)", arg: " ptr in") { - if hasSubclasses.contains(cdef.name) { - p("lookupObject (nativeHandle: gi.global_get_singleton (ptr)!)!") - } else { - p("\(cdef.name) (nativeHandle: gi.global_get_singleton (ptr)!)") - } - } - } - } - p("override open class var godotClassName: StringName { \"\(cdef.name)\" }") + return argNames.joined(separator: ", ") +} - if cdef.name == "RefCounted" { - p("public required init ()") { - p("super.init ()") - p("_ = initRef()") - } - p("public required init(nativeHandle: UnsafeRawPointer)") { - p("super.init (nativeHandle: nativeHandle)") - p("reference()") - p("ownsHandle = true") - } +func generateSignalDocAppendix (_ p: Printer, cdef: JGodotExtensionAPIClass, signals: [JGodotSignal]?) { + guard let signals = signals, signals.count > 0 else { + return } - var referencedMethods = Set() - - if let enums = cdef.enums { - generateEnums(p, cdef: cdef, values: enums, prefix: nil) + if signals.count > 0 { + doc (p, cdef, "\nThis object emits the following signals:") + } else { + doc (p, cdef, "\nThis object emits this signal:") } - - let oResult = p.result - - if let constants = cdef.constants { - generateConstants(p, cdef: cdef, constants) + for signal in signals { + let signalName = godotMethodToSwift (signal.name) + doc (p, cdef, "- ``\(signalName)``") } +} - if let properties = cdef.properties { - generateProperties(p, cdef: cdef, properties, cdef.methods ?? [], &referencedMethods, asSingleton: asSingleton) - } - if let methods = cdef.methods { - virtuals = generateMethods(p, cdef: cdef, methods: methods, usedMethods: referencedMethods, asSingleton: asSingleton) +func processClass (cdef: JGodotExtensionAPIClass, outputDir: String?) async { + // Determine if it is a singleton, but exclude EditorInterface + let isSingleton = jsonApi.singletons.contains (where: { $0.name == cdef.name }) + let asSingleton = isSingleton && cdef.name != "EditorInterface" + + // Clear the result + let p = await PrinterFactory.shared.initPrinter(cdef.name, withPreamble: true) + + // Save it + defer { + if let outputDir { + p.save(outputDir + "\(cdef.name).swift") + } } - - if let signals = cdef.signals { - generateSignals(p, cdef: cdef, signals: signals) + + let inherits = cdef.inherits ?? "Wrapped" + let typeDecl = "open class \(cdef.name): \(inherits)" + + var virtuals: [String: (String, JGodotClassMethod)] = [:] + if cdef.brief_description == "" { + if cdef.description != "" { + doc (p, cdef, cdef.description) + } + } else { + doc (p, cdef, cdef.brief_description) + if cdef.description != "" { + doc (p, cdef, "") // Add a newline before the fuller description + doc (p, cdef, cdef.description) + } } + + generateSignalDocAppendix (p, cdef: cdef, signals: cdef.signals) + // class or extension (for Object) + p (typeDecl) { + if isSingleton { + p ("/// The shared instance of this class") + p.staticVar(visibility: "public ", name: "shared", type: cdef.name) { + p ("return withUnsafePointer (to: &\(cdef.name).godotClassName.content)", arg: " ptr in") { + if hasSubclasses.contains(cdef.name) { + p ("lookupObject (nativeHandle: gi.global_get_singleton (ptr)!)!") + } else { + p ("\(cdef.name) (nativeHandle: gi.global_get_singleton (ptr)!)") + } + } + } + } + p ("override open class var godotClassName: StringName { \"\(cdef.name)\" }") + + if cdef.name == "RefCounted" { + p ("public required init ()") { + p ("super.init ()") + p ("_ = initRef()") + } + p ("public required init(nativeHandle: UnsafeRawPointer)") { + p ("super.init (nativeHandle: nativeHandle)") + p ("reference()") + p ("ownsHandle = true") + } + } + var referencedMethods = Set() + + if let enums = cdef.enums { + generateEnums (p, cdef: cdef, values: enums, prefix: nil) + } + + let oResult = p.result + + if let constants = cdef.constants { + generateConstants (p, cdef: cdef, constants) + } + + if let properties = cdef.properties { + generateProperties (p, cdef: cdef, properties, cdef.methods ?? [], &referencedMethods, asSingleton: asSingleton) + } + if let methods = cdef.methods { + virtuals = generateMethods (p, cdef: cdef, methods: methods, usedMethods: referencedMethods, asSingleton: asSingleton) + } + + if let signals = cdef.signals { + generateSignals (p, cdef: cdef, signals: signals) + } - // Remove code that we did not want generated - if skipList.contains(cdef.name) || (okList.count > 0 && !okList.contains(cdef.name)) { - p.result = oResult + // Remove code that we did not want generated + if skipList.contains (cdef.name) || (okList.count > 0 && !okList.contains (cdef.name)) { + p.result = oResult + } } - } - if virtuals.count > 0 { - p("// Support methods for proxies") - for k in virtuals.keys.sorted() { - guard let (methodName, methodDef) = virtuals[k] else { - print("Internal error: in processClass \(cdef.name)") - continue - } - if !skipList.contains(cdef.name) && (okList.count == 0 || okList.contains(cdef.name)) { - generateVirtualProxy(p, cdef: cdef, methodName: methodName, method: methodDef) - } + if virtuals.count > 0 { + p ("// Support methods for proxies") + for k in virtuals.keys.sorted () { + guard let (methodName, methodDef) = virtuals [k] else { + print ("Internal error: in processClass \(cdef.name)") + continue + } + if !skipList.contains (cdef.name) && (okList.count == 0 || okList.contains (cdef.name)) { + generateVirtualProxy(p, cdef: cdef, methodName: methodName, method: methodDef) + } + } } - } } extension Generator { - func generateCtorPointers(_ p: Printer) { - p("var godotFrameworkCtors = [") - for x in classMap.keys.sorted() { - p(" \"\(x)\": \(x).self, //(nativeHandle:),") + func generateCtorPointers (_ p: Printer) { + p ("var godotFrameworkCtors = [") + for x in classMap.keys.sorted() { + p (" \"\(x)\": \(x).self, //(nativeHandle:),") + } + p ("]") } - p("]") - } } diff --git a/Generator/Generator/Printer.swift b/Generator/Generator/Printer.swift index 2f3183b17..4a2d49a4b 100644 --- a/Generator/Generator/Printer.swift +++ b/Generator/Generator/Printer.swift @@ -8,157 +8,157 @@ import Foundation class Printer { - let name: String - // Where we accumulate our output for the p/b routines - var result = "" - var indentStr = "" // The current indentation string, based on `indent` - let addPreamble: Bool - var indent = 0 { - didSet { - indentStr = String(repeating: " ", count: indent) + let name: String + // Where we accumulate our output for the p/b routines + var result = "" + var indentStr = "" // The current indentation string, based on `indent` + let addPreamble: Bool + var indent = 0 { + didSet { + indentStr = String(repeating: " ", count: indent) + } } - } - - fileprivate init(name: String, addPreamble: Bool) { - self.name = name - self.addPreamble = addPreamble - } - - fileprivate static let preamble = - """ - // This file is autogenerated, do not edit - @_implementationOnly import GDExtension - - #if CUSTOM_BUILTIN_IMPLEMENTATIONS - #if canImport(Darwin) - import Darwin - #elseif os(Windows) - import ucrt - import WinSDK - #elseif canImport(Glibc) - import Glibc - #elseif canImport(Musl) - import Musl - #else - #error("Unable to identify your C library.") - #endif - #endif - - - - """ - - // Prints the string, indenting any newlines with the current indentation - func p(_ str: String) { - for x in str.split(separator: "\n", omittingEmptySubsequences: false) { - print("\(indentStr)\(x)", to: &result) + + fileprivate init(name: String, addPreamble: Bool) { + self.name = name + self.addPreamble = addPreamble } - } - - func `if`(_ `if`: String, then: () -> Void, else: () -> Void) { - p("if \(`if`) {") - indent += 1 - then() - indent -= 1 - p("} else {") - indent += 1 - `else`() - indent -= 1 - p("}") - } - - // Prints a variable definition - func staticVar(visibility: String = "", name: String, type: String, block: () -> Void) { - if generateResettableCache { - p("fileprivate static var _c_\(name): \(type)? = nil") - p("fileprivate static var _g_\(name): UInt16 = 0") - b("\(visibility)static var \(name): \(type) ") { - self("if _g_\(name) == swiftGodotLibraryGeneration") { - self("if let _c_\(name)") { - self("return _c_\(name)") - } + + fileprivate static let preamble = + """ + // This file is autogenerated, do not edit + @_implementationOnly import GDExtension + + #if CUSTOM_BUILTIN_IMPLEMENTATIONS + #if canImport(Darwin) + import Darwin + #elseif os(Windows) + import ucrt + import WinSDK + #elseif canImport(Glibc) + import Glibc + #elseif canImport(Musl) + import Musl + #else + #error("Unable to identify your C library.") + #endif + #endif + + + + """ + + // Prints the string, indenting any newlines with the current indentation + func p (_ str: String) { + for x in str.split(separator: "\n", omittingEmptySubsequences: false) { + print("\(indentStr)\(x)", to: &result) } - p("_g_\(name) = swiftGodotLibraryGeneration") - self("func load () -> \(type)") { - block() + } + + func `if`(_ `if`: String, then: () -> (), else: () -> ()) { + p ("if \(`if`) {") + indent += 1 + then() + indent -= 1 + p ("} else {") + indent += 1 + `else`() + indent -= 1 + p ("}") + } + + // Prints a variable definition + func staticVar(visibility: String = "", name: String, type: String, block: () -> ()) { + if generateResettableCache { + p ("fileprivate static var _c_\(name): \(type)? = nil") + p ("fileprivate static var _g_\(name): UInt16 = 0") + b("\(visibility)static var \(name): \(type) ") { + self("if _g_\(name) == swiftGodotLibraryGeneration") { + self("if let _c_\(name)") { + self("return _c_\(name)") + } + } + p ("_g_\(name) = swiftGodotLibraryGeneration") + self("func load () -> \(type)") { + block() + } + self("let ret = load ()") + self("_c_\(name) = ret") + self("return ret") + } + } else { + b("\(visibility)static var \(name): \(type) =", suffix: "()", block: block) } - self("let ret = load ()") - self("_c_\(name) = ret") - self("return ret") - } - } else { - b("\(visibility)static var \(name): \(type) =", suffix: "()", block: block) } - } - - // Prints a block, automatically indents the code in the closure - func b(_ str: String, arg: String? = nil, suffix: String = "", block: () -> Void) { - p(str + " {" + (arg ?? "")) - indent += 1 - let saved = indent - block() - if indent != saved { - print("Indentation out of sync, the nested block messed with indentation") + + // Prints a block, automatically indents the code in the closure + func b(_ str: String, arg: String? = nil, suffix: String = "", block: () -> ()) { + p (str + " {" + (arg ?? "")) + indent += 1 + let saved = indent + block() + if indent != saved { + print("Indentation out of sync, the nested block messed with indentation") + } + indent -= 1 + p ("}\(suffix)\n") } - indent -= 1 - p("}\(suffix)\n") - } - func callAsFunction(_ str: String) { - p(str) - } + func callAsFunction(_ str: String) { + p (str) + } - func callAsFunction(_ str: String, arg: String? = nil, suffix: String = "", block: () -> Void) { - b(str, arg: arg, suffix: suffix, block: block) - } + func callAsFunction(_ str: String, arg: String? = nil, suffix: String = "", block: () -> ()) { + b(str, arg: arg, suffix: suffix, block: block) + } - func save(_ file: String) { - let output = (addPreamble ? Self.preamble : "") + result + func save(_ file: String) { + let output = (addPreamble ? Self.preamble : "") + result - let existing = try? String(contentsOfFile: file) - if existing != output { - try! output.write(toFile: file, atomically: false, encoding: .utf8) + let existing = try? String(contentsOfFile: file) + if existing != output { + try! output.write(toFile: file, atomically: false, encoding: .utf8) + } } - } } actor PrinterFactory { - static let shared = PrinterFactory() + static let shared = PrinterFactory() - private var printers: [Printer] = [] + private var printers: [Printer] = [] - func initPrinter(_ name: String, withPreamble: Bool) -> Printer { - let printer = Printer(name: name, addPreamble: withPreamble) - printers.append(printer) - return printer - } + func initPrinter(_ name: String, withPreamble: Bool) -> Printer { + let printer = Printer(name: name, addPreamble: withPreamble) + printers.append(printer) + return printer + } - func save(_ file: String) { - let combined = printers.sorted(by: { $0.name < $1.name }).map({ $0.result }).joined(separator: "\n") - let output = Printer.preamble + combined + func save(_ file: String) { + let combined = printers.sorted(by: { $0.name < $1.name }).map ({ $0.result }).joined(separator: "\n") + let output = Printer.preamble + combined - let existing = try? String(contentsOf: URL(fileURLWithPath: file), encoding: .utf8) - if existing != output { - try! output.write(toFile: file, atomically: false, encoding: .utf8) + let existing = try? String(contentsOf: URL(fileURLWithPath: file), encoding: .utf8) + if existing != output { + try! output.write(toFile: file, atomically: false, encoding: .utf8) + } } - } - - func saveMultiplexed(_ root: String) { - for letter in "ABCDEFGHIJKLMNOPQRSTUVWXYZ" { - let combined = - printers - .filter({ $0.name.uppercased().first == letter }) - .sorted(by: { $0.name < $1.name }) - .map({ $0.result }) - .joined(separator: "\n") - let output = Printer.preamble + combined - - let url = URL(fileURLWithPath: root).appending(path: "SwiftGodot\(letter).swift") - let existing = try? String(contentsOf: url, encoding: .utf8) - if existing != output { - try? output.write(to: url, atomically: false, encoding: .utf8) - } + + func saveMultiplexed(_ root: String) { + for letter in "ABCDEFGHIJKLMNOPQRSTUVWXYZ" { + let combined = + printers + .filter({ $0.name.uppercased().first == letter }) + .sorted(by: { $0.name < $1.name }) + .map ({ $0.result }) + .joined(separator: "\n") + let output = Printer.preamble + combined + + let url = URL(fileURLWithPath: root).appending(path: "SwiftGodot\(letter).swift") + let existing = try? String(contentsOf: url, encoding: .utf8) + if existing != output { + try? output.write(to: url, atomically: false, encoding: .utf8) + } + } } - } } diff --git a/Generator/Generator/UtilityGen.swift b/Generator/Generator/UtilityGen.swift index 6783927f3..2fbf643c0 100644 --- a/Generator/Generator/UtilityGen.swift +++ b/Generator/Generator/UtilityGen.swift @@ -9,25 +9,25 @@ import ExtensionApi import Foundation func generateUtility(values: [JGodotUtilityFunction], outputDir: String?) async { - let p = await PrinterFactory.shared.initPrinter("utility", withPreamble: true) - defer { - if let outputDir { - p.save(outputDir + "utility.swift") + let p = await PrinterFactory.shared.initPrinter("utility", withPreamble: true) + defer { + if let outputDir { + p.save(outputDir + "utility.swift") + } } - } - let emptyUsedMethods = Set() + let emptyUsedMethods = Set() - p("public class GD") { - for method in values { - // We ignore the request for virtual methods, should not happen for these - if omittedMethodsList["utility_functions"]?.contains(method.name) == true { - continue - } + p("public class GD") { + for method in values { + // We ignore the request for virtual methods, should not happen for these + if omittedMethodsList["utility_functions"]?.contains(method.name) == true { + continue + } - performExplaniningNonCriticalErrors { - _ = try generateMethod(p, method: method, className: "Godot", cdef: nil, usedMethods: emptyUsedMethods, generatedMethodKind: .utilityFunction, asSingleton: false) - } + performExplaniningNonCriticalErrors { + _ = try generateMethod(p, method: method, className: "Godot", cdef: nil, usedMethods: emptyUsedMethods, generatedMethodKind: .utilityFunction, asSingleton: false) + } + } } - } } diff --git a/Generator/Generator/main.swift b/Generator/Generator/main.swift index a7b06843c..19aef7fb6 100644 --- a/Generator/Generator/main.swift +++ b/Generator/Generator/main.swift @@ -1,5 +1,4 @@ import ExtensionApi -// // main.swift // SwiftGodot/Generator // @@ -11,30 +10,30 @@ import Foundation var args = CommandLine.arguments var rootUrl: URL { - let url = URL(fileURLWithPath: #file) // SwiftGodot/Generator/Generator/main.swift - .deletingLastPathComponent() // SwiftGodot/Generator/Generator - .deletingLastPathComponent() // SwiftGodot/Generator - .deletingLastPathComponent() // SwiftGodot - return url + let url = URL(fileURLWithPath: #file) // SwiftGodot/Generator/Generator/main.swift + .deletingLastPathComponent() // SwiftGodot/Generator/Generator + .deletingLastPathComponent() // SwiftGodot/Generator + .deletingLastPathComponent() // SwiftGodot + return url } var defaultExtensionApiJsonUrl: URL { - rootUrl - .appendingPathComponent("Sources") - .appendingPathComponent("ExtensionApi") - .appendingPathComponent("extension_api.json") + rootUrl + .appendingPathComponent("Sources") + .appendingPathComponent("ExtensionApi") + .appendingPathComponent("extension_api.json") } var defaultGeneratorOutputlUrl: URL { - rootUrl - .appendingPathComponent("GeneratedForDebug") - .appendingPathComponent("Sources") + rootUrl + .appendingPathComponent("GeneratedForDebug") + .appendingPathComponent("Sources") } var defaultDocRootUrl: URL { - rootUrl - .appendingPathComponent("GeneratedForDebug") - .appendingPathComponent("Docs") + rootUrl + .appendingPathComponent("GeneratedForDebug") + .appendingPathComponent("Docs") } let jsonFile = args.count > 1 ? args[1] : defaultExtensionApiJsonUrl.path @@ -48,40 +47,40 @@ let generateResettableCache = false var combineOutput = args.contains("--combined") if args.count < 2 { - print( - """ - Usage is: generator path-to-extension-api output-directory doc-directory - - path-to-extension-api is the full path to extension_api.json from Godot - - output-directory is where the files will be placed - - doc-directory is the Godot documentation resides (godot/doc) - Running with defaults: - path-to-extension-api = "\(jsonFile)" - output-directory = "\(outputDir)" - doc-directory = "\(docRoot)" - """) + print( + """ + Usage is: generator path-to-extension-api output-directory doc-directory + - path-to-extension-api is the full path to extension_api.json from Godot + - output-directory is where the files will be placed + - doc-directory is the Godot documentation resides (godot/doc) + Running with defaults: + path-to-extension-api = "\(jsonFile)" + output-directory = "\(outputDir)" + doc-directory = "\(docRoot)" + """) } let jsonData = try! Data(url: URL(fileURLWithPath: jsonFile)) let jsonApi = try! JSONDecoder().decode(JGodotExtensionAPI.self, from: jsonData) func dropMatchingPrefix(_ enumName: String, _ enumKey: String) -> String { - let snake = snakeToCamel(enumKey) - if snake.lowercased().starts(with: enumName.lowercased()) { - if snake.count == enumName.count { - return snake - } - let ret = String(snake[snake.index(snake.startIndex, offsetBy: enumName.count)...]) - if let f = ret.first { - if f.isNumber { - return snake - } + let snake = snakeToCamel(enumKey) + if snake.lowercased().starts(with: enumName.lowercased()) { + if snake.count == enumName.count { + return snake + } + let ret = String(snake[snake.index(snake.startIndex, offsetBy: enumName.count)...]) + if let f = ret.first { + if f.isNumber { + return snake + } + } + if ret == "" { + return snake + } + return ret.first!.lowercased() + ret.dropFirst() } - if ret == "" { - return snake - } - return ret.first!.lowercased() + ret.dropFirst() - } - return snake + return snake } var globalEnums: [String: JGodotGlobalEnumElement] = [:] @@ -96,22 +95,22 @@ var classMap: [String: JGodotExtensionAPIClass] = [:] var hasSubclasses = Set() for x in jsonApi.classes { - classMap[x.name] = x - if let parentClass = x.inherits { - hasSubclasses.insert(parentClass) - } + classMap[x.name] = x + if let parentClass = x.inherits { + hasSubclasses.insert(parentClass) + } } private var structTypes: Set = [ - "const void*", - "AudioFrame*", - "Float", - "Int", - "float", - "int", - "Int32", - "Bool", - "bool", + "const void*", + "AudioFrame*", + "Float", + "Int", + "float", + "int", + "Int32", + "Bool", + "bool", ] /// - parameter type: A type name as found in `extension_api.json`. @@ -121,38 +120,38 @@ func isStruct(_ type: String) -> Bool { structTypes.contains(type) } var builtinMap: [String: JGodotBuiltinClass] = [:] for x in jsonApi.builtinClasses { - if x.members?.count ?? 0 > 0 { - structTypes.insert(x.name) - } - builtinMap[x.name] = x + if x.members?.count ?? 0 > 0 { + structTypes.insert(x.name) + } + builtinMap[x.name] = x } let buildConfiguration: String = "float_64" var builtinSizes: [String: Int] = [:] for cs in jsonApi.builtinClassSizes { - if cs.buildConfiguration == buildConfiguration { - for c in cs.sizes { - builtinSizes[c.name] = c.size + if cs.buildConfiguration == buildConfiguration { + for c in cs.sizes { + builtinSizes[c.name] = c.size + } } - } } var builtinMemberOffsets: [String: [JGodotMember]] = [:] for mo in jsonApi.builtinClassMemberOffsets { - if mo.buildConfiguration == buildConfiguration { - for c in mo.classes { - builtinMemberOffsets[c.name.rawValue] = c.members + if mo.buildConfiguration == buildConfiguration { + for c in mo.classes { + builtinMemberOffsets[c.name.rawValue] = c.members + } } - } } let generatedBuiltinDir: String? = combineOutput ? nil : (outputDir + "/generated-builtin/") let generatedDir: String? = combineOutput ? nil : (outputDir + "/generated/") if combineOutput { - try! FileManager.default.createDirectory(atPath: outputDir + "/generated/", withIntermediateDirectories: true) + try! FileManager.default.createDirectory(atPath: outputDir + "/generated/", withIntermediateDirectories: true) } else if let generatedBuiltinDir, let generatedDir { - try! FileManager.default.createDirectory(atPath: generatedBuiltinDir, withIntermediateDirectories: true) - try! FileManager.default.createDirectory(atPath: generatedDir, withIntermediateDirectories: true) + try! FileManager.default.createDirectory(atPath: generatedBuiltinDir, withIntermediateDirectories: true) + try! FileManager.default.createDirectory(atPath: generatedDir, withIntermediateDirectories: true) } //#if os(Windows) @@ -165,32 +164,32 @@ if combineOutput { //#endif struct Generator { - func run() async throws { - let coreDefPrinter = await PrinterFactory.shared.initPrinter("core-defs", withPreamble: true) - generateUnsafePointerHelpers(coreDefPrinter) - generateEnums(coreDefPrinter, cdef: nil, values: jsonApi.globalEnums, prefix: "") - await generateBuiltinClasses(values: jsonApi.builtinClasses, outputDir: generatedBuiltinDir) - await generateUtility(values: jsonApi.utilityFunctions, outputDir: generatedBuiltinDir) - await generateClasses(values: jsonApi.classes, outputDir: generatedDir) - - generateCtorPointers(coreDefPrinter) - generateNativeStructures(coreDefPrinter, values: jsonApi.nativeStructures) - - if let generatedBuiltinDir { - coreDefPrinter.save(generatedBuiltinDir + "/core-defs.swift") - } - - if combineOutput { - await PrinterFactory.shared.saveMultiplexed(outputDir) + func run() async throws { + let coreDefPrinter = await PrinterFactory.shared.initPrinter("core-defs", withPreamble: true) + generateUnsafePointerHelpers(coreDefPrinter) + generateEnums(coreDefPrinter, cdef: nil, values: jsonApi.globalEnums, prefix: "") + await generateBuiltinClasses(values: jsonApi.builtinClasses, outputDir: generatedBuiltinDir) + await generateUtility(values: jsonApi.utilityFunctions, outputDir: generatedBuiltinDir) + await generateClasses(values: jsonApi.classes, outputDir: generatedDir) + + generateCtorPointers(coreDefPrinter) + generateNativeStructures(coreDefPrinter, values: jsonApi.nativeStructures) + + if let generatedBuiltinDir { + coreDefPrinter.save(generatedBuiltinDir + "/core-defs.swift") + } + + if combineOutput { + await PrinterFactory.shared.saveMultiplexed(outputDir) + } } - } } let semaphore = DispatchSemaphore(value: 0) let _ = Task { - let generator = Generator() - try! await generator.run() - semaphore.signal() + let generator = Generator() + try! await generator.run() + semaphore.signal() } semaphore.wait() diff --git a/Sources/SwiftGodot/EntryPoint.swift b/Sources/SwiftGodot/EntryPoint.swift index f3031783c..2bb9153c9 100644 --- a/Sources/SwiftGodot/EntryPoint.swift +++ b/Sources/SwiftGodot/EntryPoint.swift @@ -9,54 +9,54 @@ public protocol ExtensionInterface { - func variantShouldDeinit(content: UnsafeRawPointer) -> Bool + func variantShouldDeinit(content: UnsafeRawPointer) -> Bool - func objectShouldDeinit(handle: UnsafeRawPointer) -> Bool + func objectShouldDeinit(handle: UnsafeRawPointer) -> Bool - func objectInited(object: Wrapped) + func objectInited(object: Wrapped) - func objectDeinited(object: Wrapped) + func objectDeinited(object: Wrapped) - func getLibrary() -> UnsafeMutableRawPointer + func getLibrary() -> UnsafeMutableRawPointer - func getProcAddr() -> OpaquePointer + func getProcAddr() -> OpaquePointer } class LibGodotExtensionInterface: ExtensionInterface { - /// If your application is crashing due to the Variant leak fixes, please - /// enable this flag, and provide me with a test case, so I can find that - /// pesky scenario. - public let experimentalDisableVariantUnref = false + /// If your application is crashing due to the Variant leak fixes, please + /// enable this flag, and provide me with a test case, so I can find that + /// pesky scenario. + public let experimentalDisableVariantUnref = false - private let library: GDExtensionClassLibraryPtr - private let getProcAddrFun: GDExtensionInterfaceGetProcAddress + private let library: GDExtensionClassLibraryPtr + private let getProcAddrFun: GDExtensionInterfaceGetProcAddress - public init(library: GDExtensionClassLibraryPtr, getProcAddrFun: GDExtensionInterfaceGetProcAddress) { - self.library = library - self.getProcAddrFun = getProcAddrFun - } + public init(library: GDExtensionClassLibraryPtr, getProcAddrFun: GDExtensionInterfaceGetProcAddress) { + self.library = library + self.getProcAddrFun = getProcAddrFun + } - public func variantShouldDeinit(content: UnsafeRawPointer) -> Bool { - return !experimentalDisableVariantUnref - } + public func variantShouldDeinit(content: UnsafeRawPointer) -> Bool { + return !experimentalDisableVariantUnref + } - public func objectShouldDeinit(handle: UnsafeRawPointer) -> Bool { - return true - } + public func objectShouldDeinit(handle: UnsafeRawPointer) -> Bool { + return true + } - public func objectInited(object: Wrapped) {} + public func objectInited(object: Wrapped) {} - public func objectDeinited(object: Wrapped) {} + public func objectDeinited(object: Wrapped) {} - public func getLibrary() -> UnsafeMutableRawPointer { - return UnsafeMutableRawPointer(mutating: library) - } + public func getLibrary() -> UnsafeMutableRawPointer { + return UnsafeMutableRawPointer(mutating: library) + } - public func getProcAddr() -> OpaquePointer { - return unsafeBitCast(getProcAddrFun, to: OpaquePointer.self) - } + public func getProcAddr() -> OpaquePointer { + return unsafeBitCast(getProcAddrFun, to: OpaquePointer.self) + } } @@ -80,298 +80,298 @@ func loadFunctions(loader: GDExtensionInterfaceGetProcAddress) { /// application - as opposed to using SwiftGodot purely as an extension /// public func setExtensionInterface(interface: ExtensionInterface) { - extensionInterface = interface - loadGodotInterface(unsafeBitCast(interface.getProcAddr(), to: GDExtensionInterfaceGetProcAddress.self)) + extensionInterface = interface + loadGodotInterface(unsafeBitCast(interface.getProcAddr(), to: GDExtensionInterfaceGetProcAddress.self)) } // Extension initialization callback func extension_initialize(userData: UnsafeMutableRawPointer?, l: GDExtensionInitializationLevel) { - //print ("SWIFT: extension_initialize") - guard let level = GDExtension.InitializationLevel(rawValue: Int64(exactly: l.rawValue)!) else { return } - guard let userData else { return } - guard let callback = extensionInitCallbacks[OpaquePointer(userData)] else { return } - callback(level) + //print ("SWIFT: extension_initialize") + guard let level = GDExtension.InitializationLevel(rawValue: Int64(exactly: l.rawValue)!) else { return } + guard let userData else { return } + guard let callback = extensionInitCallbacks[OpaquePointer(userData)] else { return } + callback(level) } // Extension deinitialization callback func extension_deinitialize(userData: UnsafeMutableRawPointer?, l: GDExtensionInitializationLevel) { - //print ("SWIFT: extension_deinitialize") - guard let userData else { return } - let key = OpaquePointer(userData) - guard let callback = extensionDeInitCallbacks[key] else { return } - guard let level = GDExtension.InitializationLevel(rawValue: Int64(exactly: l.rawValue)!) else { return } - callback(level) - if level == .core { - // Last one, remove - extensionDeInitCallbacks.removeValue(forKey: key) - } + //print ("SWIFT: extension_deinitialize") + guard let userData else { return } + let key = OpaquePointer(userData) + guard let callback = extensionDeInitCallbacks[key] else { return } + guard let level = GDExtension.InitializationLevel(rawValue: Int64(exactly: l.rawValue)!) else { return } + callback(level) + if level == .core { + // Last one, remove + extensionDeInitCallbacks.removeValue(forKey: key) + } } /// Error types returned by Godot when invoking a method public enum CallErrorType: Error { - /// No error - case ok - case invalidMethod - case invalidArgument - case tooFewArguments - case tooManyArguments - case instanceIsNull - case methodNotConst - - /// A new error was introduced into Godot, and the SwiftGodot bindings are out of sync - case unknown + /// No error + case ok + case invalidMethod + case invalidArgument + case tooFewArguments + case tooManyArguments + case instanceIsNull + case methodNotConst + + /// A new error was introduced into Godot, and the SwiftGodot bindings are out of sync + case unknown } func toCallErrorType(_ godotCallError: GDExtensionCallErrorType) -> CallErrorType { - switch godotCallError { - case GDEXTENSION_CALL_OK: - return .ok - case GDEXTENSION_CALL_ERROR_INVALID_METHOD: - return .invalidMethod - case GDEXTENSION_CALL_ERROR_INVALID_ARGUMENT: - return .invalidArgument - case GDEXTENSION_CALL_ERROR_INSTANCE_IS_NULL: - return .instanceIsNull - case GDEXTENSION_CALL_ERROR_METHOD_NOT_CONST: - return .methodNotConst - case GDEXTENSION_CALL_ERROR_TOO_FEW_ARGUMENTS: - return .tooFewArguments - case GDEXTENSION_CALL_ERROR_TOO_MANY_ARGUMENTS: - return .tooManyArguments - default: - return .unknown - } + switch godotCallError { + case GDEXTENSION_CALL_OK: + return .ok + case GDEXTENSION_CALL_ERROR_INVALID_METHOD: + return .invalidMethod + case GDEXTENSION_CALL_ERROR_INVALID_ARGUMENT: + return .invalidArgument + case GDEXTENSION_CALL_ERROR_INSTANCE_IS_NULL: + return .instanceIsNull + case GDEXTENSION_CALL_ERROR_METHOD_NOT_CONST: + return .methodNotConst + case GDEXTENSION_CALL_ERROR_TOO_FEW_ARGUMENTS: + return .tooFewArguments + case GDEXTENSION_CALL_ERROR_TOO_MANY_ARGUMENTS: + return .tooManyArguments + default: + return .unknown + } } struct GodotInterface { - let mem_alloc: GDExtensionInterfaceMemAlloc - let mem_realloc: GDExtensionInterfaceMemRealloc - let mem_free: GDExtensionInterfaceMemFree - - let print_error: GDExtensionInterfacePrintError - let print_error_with_message: GDExtensionInterfacePrintErrorWithMessage - let print_warning: GDExtensionInterfacePrintWarning - let print_warning_with_message: GDExtensionInterfacePrintWarningWithMessage - let print_script_error: GDExtensionInterfacePrintScriptError - let print_script_error_with_message: GDExtensionInterfacePrintScriptErrorWithMessage - let string_new_with_utf8_chars: GDExtensionInterfaceStringNewWithUtf8Chars - let string_to_utf8_chars: GDExtensionInterfaceStringToUtf8Chars - - let get_native_struct_size: GDExtensionInterfaceGetNativeStructSize - - let classdb_construct_object: GDExtensionInterfaceClassdbConstructObject - let classdb_get_method_bind: GDExtensionInterfaceClassdbGetMethodBind - let classdb_get_class_tag: GDExtensionInterfaceClassdbGetClassTag - let classdb_register_extension_class: GDExtensionInterfaceClassdbRegisterExtensionClass2 - let classdb_register_extension_class_signal: GDExtensionInterfaceClassdbRegisterExtensionClassSignal - let classdb_register_extension_class_method: GDExtensionInterfaceClassdbRegisterExtensionClassMethod - let classdb_register_extension_class_property: GDExtensionInterfaceClassdbRegisterExtensionClassProperty - let classdb_register_extension_class_property_group: GDExtensionInterfaceClassdbRegisterExtensionClassPropertyGroup - let classdb_register_extension_class_property_subgroup: GDExtensionInterfaceClassdbRegisterExtensionClassPropertySubgroup - let classdb_unregister_extension_class: GDExtensionInterfaceClassdbUnregisterExtensionClass - - let object_set_instance: GDExtensionInterfaceObjectSetInstance - let object_set_instance_binding: GDExtensionInterfaceObjectSetInstanceBinding - let object_get_class_name: GDExtensionInterfaceObjectGetClassName - - let object_method_bind_ptrcall: GDExtensionInterfaceObjectMethodBindPtrcall - let object_destroy: GDExtensionInterfaceObjectDestroy - let object_has_script_method: GDExtensionInterfaceObjectHasScriptMethod - let object_call_script_method: GDExtensionInterfaceObjectCallScriptMethod - - // @convention(c) (GDExtensionMethodBindPtr?, GDExtensionObjectPtr?, UnsafePointer?, GDExtensionTypePtr?) -> Void - @inline(__always) - func object_method_bind_ptrcall_v( - _ method: GDExtensionMethodBindPtr?, - _ object: GDExtensionObjectPtr?, - _ result: GDExtensionTypePtr?, - _ _args: UnsafeMutableRawPointer?... - ) { - object_method_bind_ptrcall(method, object, unsafeBitCast(_args, to: [UnsafeRawPointer?].self), result) - } - - let global_get_singleton: GDExtensionInterfaceGlobalGetSingleton - let ref_get_object: GDExtensionInterfaceRefGetObject - let object_method_bind_call: GDExtensionInterfaceObjectMethodBindCall - - // @convention(c) (GDExtensionMethodBindPtr?, GDExtensionObjectPtr?, UnsafePointer?, GDExtensionInt, GDExtensionUninitializedVariantPtr?, UnsafeMutablePointer?) -> Void - @inline(__always) - func object_method_bind_call_v( - _ method: GDExtensionMethodBindPtr?, - _ object: GDExtensionObjectPtr?, - _ result: GDExtensionUninitializedVariantPtr?, - _ error: UnsafeMutablePointer?, - _ _args: UnsafeMutableRawPointer?... - ) { - object_method_bind_call(method, object, unsafeBitCast(_args, to: [UnsafeRawPointer?].self), GDExtensionInt(_args.count), result, error) - } - - let variant_new_nil: GDExtensionInterfaceVariantNewNil - let variant_new_copy: GDExtensionInterfaceVariantNewCopy - let variant_evaluate: GDExtensionInterfaceVariantEvaluate - let variant_hash: GDExtensionInterfaceVariantHash - let variant_destroy: GDExtensionInterfaceVariantDestroy - let variant_get_type: GDExtensionInterfaceVariantGetType - let variant_get_type_name: GDExtensionInterfaceVariantGetTypeName - let variant_stringify: GDExtensionInterfaceVariantStringify - let variant_call: GDExtensionInterfaceVariantCall - let variant_call_static: GDExtensionInterfaceVariantCallStatic - let variant_get_indexed: GDExtensionInterfaceVariantGetIndexed - let variant_set_indexed: GDExtensionInterfaceVariantSetIndexed - - let variant_get_ptr_constructor: GDExtensionInterfaceVariantGetPtrConstructor - let variant_get_ptr_builtin_method: GDExtensionInterfaceVariantGetPtrBuiltinMethod - let variant_get_ptr_operator_evaluator: GDExtensionInterfaceVariantGetPtrOperatorEvaluator - let variant_get_ptr_utility_function: GDExtensionInterfaceVariantGetPtrUtilityFunction - let variant_get_ptr_destructor: GDExtensionInterfaceVariantGetPtrDestructor - let variant_get_ptr_indexed_getter: GDExtensionInterfaceVariantGetPtrIndexedGetter - let variant_get_ptr_indexed_setter: GDExtensionInterfaceVariantGetPtrIndexedSetter - let variant_get_ptr_keyed_checker: GDExtensionInterfaceVariantGetPtrKeyedChecker - let variant_get_ptr_keyed_getter: GDExtensionInterfaceVariantGetPtrKeyedGetter - let variant_get_ptr_keyed_setter: GDExtensionInterfaceVariantGetPtrKeyedSetter - let get_variant_from_type_constructor: GDExtensionInterfaceGetVariantFromTypeConstructor - let get_variant_to_type_constructor: GDExtensionInterfaceGetVariantToTypeConstructor - - let array_operator_index: GDExtensionInterfaceArrayOperatorIndex - let array_set_typed: GDExtensionInterfaceArraySetTyped - - let packed_string_array_operator_index: GDExtensionInterfacePackedStringArrayOperatorIndex - let packed_string_array_operator_index_const: GDExtensionInterfacePackedStringArrayOperatorIndexConst - let packed_byte_array_operator_index: GDExtensionInterfacePackedByteArrayOperatorIndex - let packed_byte_array_operator_index_const: GDExtensionInterfacePackedByteArrayOperatorIndexConst - let packed_color_array_operator_index: GDExtensionInterfacePackedColorArrayOperatorIndex - let packed_color_array_operator_index_const: GDExtensionInterfacePackedColorArrayOperatorIndexConst - let packed_float32_array_operator_index: GDExtensionInterfacePackedFloat32ArrayOperatorIndex - let packed_float32_array_operator_index_const: GDExtensionInterfacePackedFloat32ArrayOperatorIndexConst - let packed_float64_array_operator_index: GDExtensionInterfacePackedFloat64ArrayOperatorIndex - let packed_float64_array_operator_index_const: GDExtensionInterfacePackedFloat64ArrayOperatorIndexConst - let packed_int32_array_operator_index: GDExtensionInterfacePackedInt32ArrayOperatorIndex - let packed_int32_array_operator_index_const: GDExtensionInterfacePackedInt32ArrayOperatorIndexConst - let packed_int64_array_operator_index: GDExtensionInterfacePackedInt64ArrayOperatorIndex - let packed_int64_array_operator_index_const: GDExtensionInterfacePackedInt64ArrayOperatorIndexConst - let packed_vector2_array_operator_index: GDExtensionInterfacePackedVector2ArrayOperatorIndex - let packed_vector2_array_operator_index_const: GDExtensionInterfacePackedVector2ArrayOperatorIndexConst - let packed_vector3_array_operator_index: GDExtensionInterfacePackedVector3ArrayOperatorIndex - let packed_vector3_array_operator_index_const: GDExtensionInterfacePackedVector3ArrayOperatorIndexConst - let packed_vector4_array_operator_index: GDExtensionInterfacePackedVector4ArrayOperatorIndex - let packed_vector4_array_operator_index_const: GDExtensionInterfacePackedVector4ArrayOperatorIndexConst - - let callable_custom_create: GDExtensionInterfaceCallableCustomCreate - - let editor_add_plugin: GDExtensionInterfaceEditorAddPlugin - let editor_remove_plugin: GDExtensionInterfaceEditorRemovePlugin + let mem_alloc: GDExtensionInterfaceMemAlloc + let mem_realloc: GDExtensionInterfaceMemRealloc + let mem_free: GDExtensionInterfaceMemFree + + let print_error: GDExtensionInterfacePrintError + let print_error_with_message: GDExtensionInterfacePrintErrorWithMessage + let print_warning: GDExtensionInterfacePrintWarning + let print_warning_with_message: GDExtensionInterfacePrintWarningWithMessage + let print_script_error: GDExtensionInterfacePrintScriptError + let print_script_error_with_message: GDExtensionInterfacePrintScriptErrorWithMessage + let string_new_with_utf8_chars: GDExtensionInterfaceStringNewWithUtf8Chars + let string_to_utf8_chars: GDExtensionInterfaceStringToUtf8Chars + + let get_native_struct_size: GDExtensionInterfaceGetNativeStructSize + + let classdb_construct_object: GDExtensionInterfaceClassdbConstructObject + let classdb_get_method_bind: GDExtensionInterfaceClassdbGetMethodBind + let classdb_get_class_tag: GDExtensionInterfaceClassdbGetClassTag + let classdb_register_extension_class: GDExtensionInterfaceClassdbRegisterExtensionClass2 + let classdb_register_extension_class_signal: GDExtensionInterfaceClassdbRegisterExtensionClassSignal + let classdb_register_extension_class_method: GDExtensionInterfaceClassdbRegisterExtensionClassMethod + let classdb_register_extension_class_property: GDExtensionInterfaceClassdbRegisterExtensionClassProperty + let classdb_register_extension_class_property_group: GDExtensionInterfaceClassdbRegisterExtensionClassPropertyGroup + let classdb_register_extension_class_property_subgroup: GDExtensionInterfaceClassdbRegisterExtensionClassPropertySubgroup + let classdb_unregister_extension_class: GDExtensionInterfaceClassdbUnregisterExtensionClass + + let object_set_instance: GDExtensionInterfaceObjectSetInstance + let object_set_instance_binding: GDExtensionInterfaceObjectSetInstanceBinding + let object_get_class_name: GDExtensionInterfaceObjectGetClassName + + let object_method_bind_ptrcall: GDExtensionInterfaceObjectMethodBindPtrcall + let object_destroy: GDExtensionInterfaceObjectDestroy + let object_has_script_method: GDExtensionInterfaceObjectHasScriptMethod + let object_call_script_method: GDExtensionInterfaceObjectCallScriptMethod + + // @convention(c) (GDExtensionMethodBindPtr?, GDExtensionObjectPtr?, UnsafePointer?, GDExtensionTypePtr?) -> Void + @inline(__always) + func object_method_bind_ptrcall_v( + _ method: GDExtensionMethodBindPtr?, + _ object: GDExtensionObjectPtr?, + _ result: GDExtensionTypePtr?, + _ _args: UnsafeMutableRawPointer?... + ) { + object_method_bind_ptrcall(method, object, unsafeBitCast(_args, to: [UnsafeRawPointer?].self), result) + } + + let global_get_singleton: GDExtensionInterfaceGlobalGetSingleton + let ref_get_object: GDExtensionInterfaceRefGetObject + let object_method_bind_call: GDExtensionInterfaceObjectMethodBindCall + + // @convention(c) (GDExtensionMethodBindPtr?, GDExtensionObjectPtr?, UnsafePointer?, GDExtensionInt, GDExtensionUninitializedVariantPtr?, UnsafeMutablePointer?) -> Void + @inline(__always) + func object_method_bind_call_v( + _ method: GDExtensionMethodBindPtr?, + _ object: GDExtensionObjectPtr?, + _ result: GDExtensionUninitializedVariantPtr?, + _ error: UnsafeMutablePointer?, + _ _args: UnsafeMutableRawPointer?... + ) { + object_method_bind_call(method, object, unsafeBitCast(_args, to: [UnsafeRawPointer?].self), GDExtensionInt(_args.count), result, error) + } + + let variant_new_nil: GDExtensionInterfaceVariantNewNil + let variant_new_copy: GDExtensionInterfaceVariantNewCopy + let variant_evaluate: GDExtensionInterfaceVariantEvaluate + let variant_hash: GDExtensionInterfaceVariantHash + let variant_destroy: GDExtensionInterfaceVariantDestroy + let variant_get_type: GDExtensionInterfaceVariantGetType + let variant_get_type_name: GDExtensionInterfaceVariantGetTypeName + let variant_stringify: GDExtensionInterfaceVariantStringify + let variant_call: GDExtensionInterfaceVariantCall + let variant_call_static: GDExtensionInterfaceVariantCallStatic + let variant_get_indexed: GDExtensionInterfaceVariantGetIndexed + let variant_set_indexed: GDExtensionInterfaceVariantSetIndexed + + let variant_get_ptr_constructor: GDExtensionInterfaceVariantGetPtrConstructor + let variant_get_ptr_builtin_method: GDExtensionInterfaceVariantGetPtrBuiltinMethod + let variant_get_ptr_operator_evaluator: GDExtensionInterfaceVariantGetPtrOperatorEvaluator + let variant_get_ptr_utility_function: GDExtensionInterfaceVariantGetPtrUtilityFunction + let variant_get_ptr_destructor: GDExtensionInterfaceVariantGetPtrDestructor + let variant_get_ptr_indexed_getter: GDExtensionInterfaceVariantGetPtrIndexedGetter + let variant_get_ptr_indexed_setter: GDExtensionInterfaceVariantGetPtrIndexedSetter + let variant_get_ptr_keyed_checker: GDExtensionInterfaceVariantGetPtrKeyedChecker + let variant_get_ptr_keyed_getter: GDExtensionInterfaceVariantGetPtrKeyedGetter + let variant_get_ptr_keyed_setter: GDExtensionInterfaceVariantGetPtrKeyedSetter + let get_variant_from_type_constructor: GDExtensionInterfaceGetVariantFromTypeConstructor + let get_variant_to_type_constructor: GDExtensionInterfaceGetVariantToTypeConstructor + + let array_operator_index: GDExtensionInterfaceArrayOperatorIndex + let array_set_typed: GDExtensionInterfaceArraySetTyped + + let packed_string_array_operator_index: GDExtensionInterfacePackedStringArrayOperatorIndex + let packed_string_array_operator_index_const: GDExtensionInterfacePackedStringArrayOperatorIndexConst + let packed_byte_array_operator_index: GDExtensionInterfacePackedByteArrayOperatorIndex + let packed_byte_array_operator_index_const: GDExtensionInterfacePackedByteArrayOperatorIndexConst + let packed_color_array_operator_index: GDExtensionInterfacePackedColorArrayOperatorIndex + let packed_color_array_operator_index_const: GDExtensionInterfacePackedColorArrayOperatorIndexConst + let packed_float32_array_operator_index: GDExtensionInterfacePackedFloat32ArrayOperatorIndex + let packed_float32_array_operator_index_const: GDExtensionInterfacePackedFloat32ArrayOperatorIndexConst + let packed_float64_array_operator_index: GDExtensionInterfacePackedFloat64ArrayOperatorIndex + let packed_float64_array_operator_index_const: GDExtensionInterfacePackedFloat64ArrayOperatorIndexConst + let packed_int32_array_operator_index: GDExtensionInterfacePackedInt32ArrayOperatorIndex + let packed_int32_array_operator_index_const: GDExtensionInterfacePackedInt32ArrayOperatorIndexConst + let packed_int64_array_operator_index: GDExtensionInterfacePackedInt64ArrayOperatorIndex + let packed_int64_array_operator_index_const: GDExtensionInterfacePackedInt64ArrayOperatorIndexConst + let packed_vector2_array_operator_index: GDExtensionInterfacePackedVector2ArrayOperatorIndex + let packed_vector2_array_operator_index_const: GDExtensionInterfacePackedVector2ArrayOperatorIndexConst + let packed_vector3_array_operator_index: GDExtensionInterfacePackedVector3ArrayOperatorIndex + let packed_vector3_array_operator_index_const: GDExtensionInterfacePackedVector3ArrayOperatorIndexConst + let packed_vector4_array_operator_index: GDExtensionInterfacePackedVector4ArrayOperatorIndex + let packed_vector4_array_operator_index_const: GDExtensionInterfacePackedVector4ArrayOperatorIndexConst + + let callable_custom_create: GDExtensionInterfaceCallableCustomCreate + + let editor_add_plugin: GDExtensionInterfaceEditorAddPlugin + let editor_remove_plugin: GDExtensionInterfaceEditorRemovePlugin } var gi: GodotInterface! func loadGodotInterface(_ godotGetProcAddrPtr: GDExtensionInterfaceGetProcAddress) { - func load(_ name: String) -> T { - let rawPtr = godotGetProcAddrPtr(name) - - guard let rawPtr else { - fatalError("Can not load method \(name) from Godot's interface") + func load(_ name: String) -> T { + let rawPtr = godotGetProcAddrPtr(name) + + guard let rawPtr else { + fatalError("Can not load method \(name) from Godot's interface") + } + return unsafeBitCast(rawPtr, to: T.self) + // + // let ass = rawPtr.assumingMemoryBound(to: T.self).pointee + // print ("For \(name) got the address \(rawPtr) and assigning \(ass)") + // return rawPtr.assumingMemoryBound(to: T.self).pointee } - return unsafeBitCast(rawPtr, to: T.self) - // - // let ass = rawPtr.assumingMemoryBound(to: T.self).pointee - // print ("For \(name) got the address \(rawPtr) and assigning \(ass)") - // return rawPtr.assumingMemoryBound(to: T.self).pointee - } - - gi = GodotInterface( - mem_alloc: load("mem_alloc"), - mem_realloc: load("mem_realloc"), - mem_free: load("mem_free"), - - print_error: load("print_error"), - print_error_with_message: load("print_error_with_message"), - print_warning: load("print_warning"), - print_warning_with_message: load("print_warning_with_message"), - print_script_error: load("print_script_error"), - print_script_error_with_message: load("print_script_error_with_message"), - - string_new_with_utf8_chars: load("string_new_with_utf8_chars"), - string_to_utf8_chars: load("string_to_utf8_chars"), - - get_native_struct_size: load("get_native_struct_size"), - - classdb_construct_object: load("classdb_construct_object"), - classdb_get_method_bind: load("classdb_get_method_bind"), - classdb_get_class_tag: load("classdb_get_class_tag"), - classdb_register_extension_class: load("classdb_register_extension_class2"), - classdb_register_extension_class_signal: load("classdb_register_extension_class_signal"), - classdb_register_extension_class_method: load("classdb_register_extension_class_method"), - classdb_register_extension_class_property: load("classdb_register_extension_class_property"), - classdb_register_extension_class_property_group: load("classdb_register_extension_class_property_group"), - classdb_register_extension_class_property_subgroup: load("classdb_register_extension_class_property_subgroup"), - classdb_unregister_extension_class: load("classdb_unregister_extension_class"), - - object_set_instance: load("object_set_instance"), - object_set_instance_binding: load("object_set_instance_binding"), - object_get_class_name: load("object_get_class_name"), - object_method_bind_ptrcall: load("object_method_bind_ptrcall"), - object_destroy: load("object_destroy"), - object_has_script_method: load("object_has_script_method"), - object_call_script_method: load("object_call_script_method"), - - global_get_singleton: load("global_get_singleton"), - ref_get_object: load("ref_get_object"), - object_method_bind_call: load("object_method_bind_call"), - - variant_new_nil: load("variant_new_nil"), - variant_new_copy: load("variant_new_copy"), - variant_evaluate: load("variant_evaluate"), - variant_hash: load("variant_hash"), - variant_destroy: load("variant_destroy"), - variant_get_type: load("variant_get_type"), - variant_get_type_name: load("variant_get_type_name"), - variant_stringify: load("variant_stringify"), - variant_call: load("variant_call"), - variant_call_static: load("variant_call_static"), - variant_get_indexed: load("variant_get_indexed"), - variant_set_indexed: load("variant_set_indexed"), - - variant_get_ptr_constructor: load("variant_get_ptr_constructor"), - variant_get_ptr_builtin_method: load("variant_get_ptr_builtin_method"), - variant_get_ptr_operator_evaluator: load("variant_get_ptr_operator_evaluator"), - variant_get_ptr_utility_function: load("variant_get_ptr_utility_function"), - variant_get_ptr_destructor: load("variant_get_ptr_destructor"), - variant_get_ptr_indexed_getter: load("variant_get_ptr_indexed_getter"), - variant_get_ptr_indexed_setter: load("variant_get_ptr_indexed_setter"), - variant_get_ptr_keyed_checker: load("variant_get_ptr_keyed_checker"), - variant_get_ptr_keyed_getter: load("variant_get_ptr_keyed_getter"), - variant_get_ptr_keyed_setter: load("variant_get_ptr_keyed_setter"), - get_variant_from_type_constructor: load("get_variant_from_type_constructor"), - get_variant_to_type_constructor: load("get_variant_to_type_constructor"), - array_operator_index: load("array_operator_index"), - array_set_typed: load("array_set_typed"), - - packed_string_array_operator_index: load("packed_string_array_operator_index"), - packed_string_array_operator_index_const: load("packed_string_array_operator_index_const"), - packed_byte_array_operator_index: load("packed_byte_array_operator_index"), - packed_byte_array_operator_index_const: load("packed_byte_array_operator_index_const"), - packed_color_array_operator_index: load("packed_color_array_operator_index"), - packed_color_array_operator_index_const: load("packed_color_array_operator_index_const"), - packed_float32_array_operator_index: load("packed_float32_array_operator_index"), - packed_float32_array_operator_index_const: load("packed_float32_array_operator_index_const"), - packed_float64_array_operator_index: load("packed_float64_array_operator_index"), - packed_float64_array_operator_index_const: load("packed_float64_array_operator_index_const"), - packed_int32_array_operator_index: load("packed_int32_array_operator_index"), - packed_int32_array_operator_index_const: load("packed_int32_array_operator_index_const"), - packed_int64_array_operator_index: load("packed_int64_array_operator_index"), - packed_int64_array_operator_index_const: load("packed_int64_array_operator_index_const"), - packed_vector2_array_operator_index: load("packed_vector2_array_operator_index"), - packed_vector2_array_operator_index_const: load("packed_vector2_array_operator_index_const"), - packed_vector3_array_operator_index: load("packed_vector3_array_operator_index"), - packed_vector3_array_operator_index_const: load("packed_vector3_array_operator_index_const"), - packed_vector4_array_operator_index: load("packed_vector4_array_operator_index"), - packed_vector4_array_operator_index_const: load("packed_vector4_array_operator_index_const"), - - callable_custom_create: load("callable_custom_create"), - editor_add_plugin: load("editor_add_plugin"), - editor_remove_plugin: load("editor_remove_plugin") - ) + + gi = GodotInterface( + mem_alloc: load("mem_alloc"), + mem_realloc: load("mem_realloc"), + mem_free: load("mem_free"), + + print_error: load("print_error"), + print_error_with_message: load("print_error_with_message"), + print_warning: load("print_warning"), + print_warning_with_message: load("print_warning_with_message"), + print_script_error: load("print_script_error"), + print_script_error_with_message: load("print_script_error_with_message"), + + string_new_with_utf8_chars: load("string_new_with_utf8_chars"), + string_to_utf8_chars: load("string_to_utf8_chars"), + + get_native_struct_size: load("get_native_struct_size"), + + classdb_construct_object: load("classdb_construct_object"), + classdb_get_method_bind: load("classdb_get_method_bind"), + classdb_get_class_tag: load("classdb_get_class_tag"), + classdb_register_extension_class: load("classdb_register_extension_class2"), + classdb_register_extension_class_signal: load("classdb_register_extension_class_signal"), + classdb_register_extension_class_method: load("classdb_register_extension_class_method"), + classdb_register_extension_class_property: load("classdb_register_extension_class_property"), + classdb_register_extension_class_property_group: load("classdb_register_extension_class_property_group"), + classdb_register_extension_class_property_subgroup: load("classdb_register_extension_class_property_subgroup"), + classdb_unregister_extension_class: load("classdb_unregister_extension_class"), + + object_set_instance: load("object_set_instance"), + object_set_instance_binding: load("object_set_instance_binding"), + object_get_class_name: load("object_get_class_name"), + object_method_bind_ptrcall: load("object_method_bind_ptrcall"), + object_destroy: load("object_destroy"), + object_has_script_method: load("object_has_script_method"), + object_call_script_method: load("object_call_script_method"), + + global_get_singleton: load("global_get_singleton"), + ref_get_object: load("ref_get_object"), + object_method_bind_call: load("object_method_bind_call"), + + variant_new_nil: load("variant_new_nil"), + variant_new_copy: load("variant_new_copy"), + variant_evaluate: load("variant_evaluate"), + variant_hash: load("variant_hash"), + variant_destroy: load("variant_destroy"), + variant_get_type: load("variant_get_type"), + variant_get_type_name: load("variant_get_type_name"), + variant_stringify: load("variant_stringify"), + variant_call: load("variant_call"), + variant_call_static: load("variant_call_static"), + variant_get_indexed: load("variant_get_indexed"), + variant_set_indexed: load("variant_set_indexed"), + + variant_get_ptr_constructor: load("variant_get_ptr_constructor"), + variant_get_ptr_builtin_method: load("variant_get_ptr_builtin_method"), + variant_get_ptr_operator_evaluator: load("variant_get_ptr_operator_evaluator"), + variant_get_ptr_utility_function: load("variant_get_ptr_utility_function"), + variant_get_ptr_destructor: load("variant_get_ptr_destructor"), + variant_get_ptr_indexed_getter: load("variant_get_ptr_indexed_getter"), + variant_get_ptr_indexed_setter: load("variant_get_ptr_indexed_setter"), + variant_get_ptr_keyed_checker: load("variant_get_ptr_keyed_checker"), + variant_get_ptr_keyed_getter: load("variant_get_ptr_keyed_getter"), + variant_get_ptr_keyed_setter: load("variant_get_ptr_keyed_setter"), + get_variant_from_type_constructor: load("get_variant_from_type_constructor"), + get_variant_to_type_constructor: load("get_variant_to_type_constructor"), + array_operator_index: load("array_operator_index"), + array_set_typed: load("array_set_typed"), + + packed_string_array_operator_index: load("packed_string_array_operator_index"), + packed_string_array_operator_index_const: load("packed_string_array_operator_index_const"), + packed_byte_array_operator_index: load("packed_byte_array_operator_index"), + packed_byte_array_operator_index_const: load("packed_byte_array_operator_index_const"), + packed_color_array_operator_index: load("packed_color_array_operator_index"), + packed_color_array_operator_index_const: load("packed_color_array_operator_index_const"), + packed_float32_array_operator_index: load("packed_float32_array_operator_index"), + packed_float32_array_operator_index_const: load("packed_float32_array_operator_index_const"), + packed_float64_array_operator_index: load("packed_float64_array_operator_index"), + packed_float64_array_operator_index_const: load("packed_float64_array_operator_index_const"), + packed_int32_array_operator_index: load("packed_int32_array_operator_index"), + packed_int32_array_operator_index_const: load("packed_int32_array_operator_index_const"), + packed_int64_array_operator_index: load("packed_int64_array_operator_index"), + packed_int64_array_operator_index_const: load("packed_int64_array_operator_index_const"), + packed_vector2_array_operator_index: load("packed_vector2_array_operator_index"), + packed_vector2_array_operator_index_const: load("packed_vector2_array_operator_index_const"), + packed_vector3_array_operator_index: load("packed_vector3_array_operator_index"), + packed_vector3_array_operator_index_const: load("packed_vector3_array_operator_index_const"), + packed_vector4_array_operator_index: load("packed_vector4_array_operator_index"), + packed_vector4_array_operator_index_const: load("packed_vector4_array_operator_index_const"), + + callable_custom_create: load("callable_custom_create"), + editor_add_plugin: load("editor_add_plugin"), + editor_remove_plugin: load("editor_remove_plugin") + ) } /// @@ -416,35 +416,35 @@ func loadGodotInterface(_ godotGetProcAddrPtr: GDExtensionInterfaceGetProcAddres /// - minimumInitializationLevel: How early does this extension need to be activated? The default "scene" level should be sufficient for most cases, /// but if your Extension is only an Editor tool you could set this higher to .tool. If you need to extend base functionality set .core or .server. public func initializeSwiftModule( - _ godotGetProcAddrPtr: OpaquePointer, - _ libraryPtr: OpaquePointer, - _ extensionPtr: OpaquePointer, - initHook: @escaping (GDExtension.InitializationLevel) -> Void, - deInitHook: @escaping (GDExtension.InitializationLevel) -> Void, - minimumInitializationLevel: GDExtension.InitializationLevel = .scene + _ godotGetProcAddrPtr: OpaquePointer, + _ libraryPtr: OpaquePointer, + _ extensionPtr: OpaquePointer, + initHook: @escaping (GDExtension.InitializationLevel) -> (), + deInitHook: @escaping (GDExtension.InitializationLevel) -> (), + minimumInitializationLevel: GDExtension.InitializationLevel = .scene ) { - let getProcAddrFun = unsafeBitCast(godotGetProcAddrPtr, to: GDExtensionInterfaceGetProcAddress.self) - loadGodotInterface(getProcAddrFun) - - // For now, we will only initialize the library once, so all of the SwiftGodot - // modules are bundled together. This is not optimal, see this bug - // with a description of what we should be doing: - // https://github.com/migueldeicaza/SwiftGodot/issues/72 - if extensionInterface == nil { - extensionInterface = LibGodotExtensionInterface(library: GDExtensionClassLibraryPtr(libraryPtr), getProcAddrFun: getProcAddrFun) - } - extensionInitCallbacks[libraryPtr] = initHook - extensionDeInitCallbacks[libraryPtr] = deInitHook - let initialization = UnsafeMutablePointer(extensionPtr) - initialization.pointee.deinitialize = extension_deinitialize - initialization.pointee.initialize = extension_initialize - #if os(Windows) - typealias RawType = Int32 - #else - typealias RawType = UInt32 - #endif - initialization.pointee.minimum_initialization_level = GDExtensionInitializationLevel(RawType(minimumInitializationLevel.rawValue)) - initialization.pointee.userdata = UnsafeMutableRawPointer(libraryPtr) + let getProcAddrFun = unsafeBitCast(godotGetProcAddrPtr, to: GDExtensionInterfaceGetProcAddress.self) + loadGodotInterface(getProcAddrFun) + + // For now, we will only initialize the library once, so all of the SwiftGodot + // modules are bundled together. This is not optimal, see this bug + // with a description of what we should be doing: + // https://github.com/migueldeicaza/SwiftGodot/issues/72 + if extensionInterface == nil { + extensionInterface = LibGodotExtensionInterface(library: GDExtensionClassLibraryPtr(libraryPtr), getProcAddrFun: getProcAddrFun) + } + extensionInitCallbacks[libraryPtr] = initHook + extensionDeInitCallbacks[libraryPtr] = deInitHook + let initialization = UnsafeMutablePointer(extensionPtr) + initialization.pointee.deinitialize = extension_deinitialize + initialization.pointee.initialize = extension_initialize + #if os(Windows) + typealias RawType = Int32 + #else + typealias RawType = UInt32 + #endif + initialization.pointee.minimum_initialization_level = GDExtensionInitializationLevel(RawType(minimumInitializationLevel.rawValue)) + initialization.pointee.userdata = UnsafeMutableRawPointer(libraryPtr) } /* @@ -454,5 +454,5 @@ public func initializeSwiftModule( */ func withArgPointers(_ _args: UnsafeMutableRawPointer?..., body: ([UnsafeRawPointer?]) -> Void) { - body(unsafeBitCast(_args, to: [UnsafeRawPointer?].self)) + body(unsafeBitCast(_args, to: [UnsafeRawPointer?].self)) }