Skip to content

Commit

Permalink
Merge branch 'main' into represent-variant-containing-nil-as-swift-nil
Browse files Browse the repository at this point in the history
  • Loading branch information
migueldeicaza authored Nov 15, 2024
2 parents de649e3 + fa8289f commit 07325cd
Show file tree
Hide file tree
Showing 6 changed files with 39 additions and 83 deletions.
10 changes: 5 additions & 5 deletions Sources/SwiftGodot/Core/ClassServices.swift
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ public class ClassInfo<T:Object> {
propPtr [i] = prop.makeNativeStruct()
i += 1
}
gi.classdb_register_extension_class_signal (extensionInterface.getLibrary(), &self.name.content, &name.content, propPtr, GDExtensionInt(propInfo.count))
gi.classdb_register_extension_class_signal (library, &self.name.content, &name.content, propPtr, GDExtensionInt(propInfo.count))
propPtr.deallocate()
}

Expand Down Expand Up @@ -153,7 +153,7 @@ public class ClassInfo<T:Object> {
default_argument_count: 0,
default_arguments: nil) // GDExtensionVariantPtr)
withUnsafePointer(to: &self.name.content) { namePtr in
gi.classdb_register_extension_class_method (extensionInterface.getLibrary(), namePtr, &info)
gi.classdb_register_extension_class_method (library, namePtr, &info)
}
}
}
Expand All @@ -166,7 +166,7 @@ public class ClassInfo<T:Object> {
let gname = GString(stringLiteral: name)
let gprefix = GString(stringLiteral: prefix)

gi.classdb_register_extension_class_property_group (extensionInterface.getLibrary(), &self.name.content, &gname.content, &gprefix.content)
gi.classdb_register_extension_class_property_group (library, &self.name.content, &gname.content, &gprefix.content)
}

/// Starts a new property sub-group, all the properties declared after calling this method
Expand All @@ -175,7 +175,7 @@ public class ClassInfo<T:Object> {
let gname = GString(stringLiteral: name)
let gprefix = GString(stringLiteral: prefix)

gi.classdb_register_extension_class_property_subgroup (extensionInterface.getLibrary(), &self.name.content, &gname.content, &gprefix.content)
gi.classdb_register_extension_class_property_subgroup (library, &self.name.content, &gname.content, &gprefix.content)
}

/// Registers the property in the class with the information provided in `info`.
Expand All @@ -190,7 +190,7 @@ public class ClassInfo<T:Object> {
var pinfo = GDExtensionPropertyInfo ()
pinfo = info.makeNativeStruct()

gi.classdb_register_extension_class_property (extensionInterface.getLibrary(), &self.name.content, &pinfo, &setter.content, &getter.content)
gi.classdb_register_extension_class_property (library, &self.name.content, &pinfo, &setter.content, &getter.content)
}
}

Expand Down
16 changes: 6 additions & 10 deletions Sources/SwiftGodot/Core/Wrapped.swift
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,6 @@ open class Wrapped: Equatable, Identifiable, Hashable {
deinit {
if ownsHandle {
if let handle {
guard extensionInterface.objectShouldDeinit(handle: handle) else { return }
#if DEBUG_INSTANCES
let type = xmap[handle] ?? "unknown"
let txt = "DEINIT for object=\(type) handle=\(handle)"
Expand Down Expand Up @@ -170,7 +169,6 @@ open class Wrapped: Equatable, Identifiable, Hashable {
print ("deinit: we do not own this object, nothing to do: object=\(txt) handle=\(handle)")
#endif
}
extensionInterface.objectDeinited(object: self)
}
static var userTypeBindingCallback = GDExtensionInstanceBindingCallbacks(
create_callback: userTypeBindingCreate,
Expand All @@ -187,7 +185,7 @@ open class Wrapped: Equatable, Identifiable, Hashable {
public var godotClassName: StringName {
var sc: StringName.ContentType = StringName.zero

if gi.object_get_class_name (handle, extensionInterface.getLibrary(), &sc) != 0 {
if gi.object_get_class_name (handle, library, &sc) != 0 {
let sn = StringName(content: sc)
return sn
}
Expand Down Expand Up @@ -239,7 +237,6 @@ open class Wrapped: Equatable, Identifiable, Hashable {
public required init (nativeHandle: UnsafeRawPointer) {
handle = nativeHandle
ownsHandle = false
extensionInterface.objectInited(object: self)
#if DEBUG_INSTANCES
xmap [nativeHandle] = "\(self)"
print ("Init Object From Handle: \(nativeHandle) -> \(self)")
Expand Down Expand Up @@ -271,7 +268,6 @@ open class Wrapped: Equatable, Identifiable, Hashable {
#endif
bindGodotInstance(instance: self, handle: handle)
let _ = Self.classInitializer
extensionInterface.objectInited(object: self)
}

open class var godotClassName: StringName {
Expand Down Expand Up @@ -313,7 +309,7 @@ func bindGodotInstance(instance: some Wrapped, handle: UnsafeRawPointer) {
}
}

gi.object_set_instance_binding(UnsafeMutableRawPointer (mutating: handle), extensionInterface.getLibrary(), retain.toOpaque(), &callbacks)
gi.object_set_instance_binding(UnsafeMutableRawPointer (mutating: handle), token, retain.toOpaque(), &callbacks)
}

var userTypes: [String:(UnsafeRawPointer)->Wrapped] = [:]
Expand Down Expand Up @@ -361,7 +357,7 @@ func register<T:Wrapped> (type name: StringName, parent: StringName, type: T.Typ
info.class_userdata = retained.toOpaque()

withUnsafePointer(to: &parent.content) { parentPtr in
gi.classdb_register_extension_class (extensionInterface.getLibrary(), &nameContent, parentPtr, &info)
gi.classdb_register_extension_class (library, &nameContent, parentPtr, &info)
}
}

Expand All @@ -383,7 +379,7 @@ public func unregister<T:Wrapped> (type: T.Type) {
let name = StringName (typeStr)
pd ("Unregistering \(typeStr)")
withUnsafePointer (to: &name.content) { namePtr in
gi.classdb_unregister_extension_class (extensionInterface.getLibrary(), namePtr)
gi.classdb_unregister_extension_class (library, namePtr)
}
}

Expand Down Expand Up @@ -443,7 +439,7 @@ func lookupObject<T: Object> (nativeHandle: UnsafeRawPointer) -> T? {
}
var className: String = ""
var sc: StringName.ContentType = StringName.zero
if gi.object_get_class_name (nativeHandle, extensionInterface.getLibrary(), &sc) != 0 {
if gi.object_get_class_name (nativeHandle, library, &sc) != 0 {
let sn = StringName(content: sc)
className = String(sn)
} else {
Expand Down Expand Up @@ -630,7 +626,7 @@ struct CallableWrapper {

var cci = GDExtensionCallableCustomInfo(
callable_userdata: wrapperPtr,
token: extensionInterface.getLibrary(),
token: token,
object_id: 0,
call_func: invokeWrappedCallable,
is_valid_func: nil,
Expand Down
79 changes: 17 additions & 62 deletions Sources/SwiftGodot/EntryPoint.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,63 +5,14 @@
//
//

import GDExtension

public protocol ExtensionInterface {

func variantShouldDeinit(content: GDExtensionVariantPtr) -> Bool

func objectShouldDeinit(handle: UnsafeRawPointer) -> Bool

func objectInited(object: Wrapped)

func objectDeinited(object: Wrapped)

func getLibrary() -> GDExtensionClassLibraryPtr

func getProcAddr() -> GDExtensionInterfaceGetProcAddress

}

public 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

private let library: GDExtensionClassLibraryPtr
private let getProcAddrFun: GDExtensionInterfaceGetProcAddress

public init(library: GDExtensionClassLibraryPtr, getProcAddrFun: GDExtensionInterfaceGetProcAddress) {
self.library = library
self.getProcAddrFun = getProcAddrFun
}

public func variantShouldDeinit(content: GDExtensionVariantPtr) -> Bool {
return !experimentalDisableVariantUnref
}

public func objectShouldDeinit(handle: UnsafeRawPointer) -> Bool {
return true
}

public func objectInited(object: Wrapped) {}

public func objectDeinited(object: Wrapped) {}

public func getLibrary() -> GDExtensionClassLibraryPtr {
return library
}

public func getProcAddr() -> GDExtensionInterfaceGetProcAddress {
return getProcAddrFun
}

}
@_implementationOnly import GDExtension

/// The pointer to the Godot Extension Interface
var extensionInterface: ExtensionInterface!
/// The library pointer we received at startup
var library: GDExtensionClassLibraryPtr!
var token: GDExtensionClassLibraryPtr! {
return library
}

/// This variable is used to trigger a reloading of the method definitions in Godot, this is only needed
/// for scenarios where SwiftGodot is being used with multiple active Godot runtimes in the same process
Expand All @@ -79,9 +30,13 @@ func loadFunctions (loader: GDExtensionInterfaceGetProcAddress) {
/// operate. It is only used when you use SwiftGodot embedded into an
/// application - as opposed to using SwiftGodot purely as an extension
///
public func setExtensionInterface (interface: ExtensionInterface) {
extensionInterface = interface
loadGodotInterface(interface.getProcAddr())
public func setExtensionInterface (to: OpaquePointer?, library lib: OpaquePointer?) {
guard let to else {
print ("Expected a pointer to a GDExtensionInterfaceGetProcAddress")
return
}
loadGodotInterface(unsafeBitCast(to, to: GDExtensionInterfaceGetProcAddress.self))
library = GDExtensionClassLibraryPtr (lib)
}

// Extension initialization callback
Expand Down Expand Up @@ -417,15 +372,15 @@ public func initializeSwiftModule (
initHook: @escaping (GDExtension.InitializationLevel)->(),
deInitHook: @escaping (GDExtension.InitializationLevel)->())
{
let getProcAddrFun = unsafeBitCast(godotGetProcAddrPtr, to: GDExtensionInterfaceGetProcAddress.self)
loadGodotInterface (getProcAddrFun)
loadGodotInterface (unsafeBitCast(godotGetProcAddrPtr, to: GDExtensionInterfaceGetProcAddress.self)
)

// 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)
if library == nil {
library = GDExtensionClassLibraryPtr(libraryPtr)
}
extensionInitCallbacks [libraryPtr] = initHook
extensionDeInitCallbacks [libraryPtr] = deInitHook
Expand Down
2 changes: 1 addition & 1 deletion Sources/SwiftGodot/Export.swift
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ func additionalRegistations (name: StringName) {
// minfo.arguments_metadata = UnsafeMutablePointer (mutating: argMetaPtr.baseAddress)
// minfo.arguments_info = UnsafeMutablePointer (mutating: argInfoPtr.baseAddress)
//
// gi.classdb_register_extension_class_method (extensionInterface.getLibrary(), UnsafePointer(&name.content), &minfo)
// gi.classdb_register_extension_class_method (library, UnsafePointer(&name.content), &minfo)
// }
// }
// }
Expand Down
11 changes: 8 additions & 3 deletions Sources/SwiftGodot/Variant.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@

@_implementationOnly import GDExtension

/// 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 var experimentalDisableVariantUnref = false

/// Variant objects box various Godot Objects, you create them with one of the
/// constructors, and you can retrieve the contents using the various extension
/// constructors that are declared on the various types that are wrapped.
Expand Down Expand Up @@ -84,10 +89,10 @@ public class Variant: Hashable, Equatable, CustomDebugStringConvertible {
}

deinit {
if !extensionInterface.variantShouldDeinit(content: &content) { return }
gi.variant_destroy(&content)
if experimentalDisableVariantUnref { return }
gi.variant_destroy (&content)
}

/// Compares two variants, does this by delegating the comparison to Godot
public static func == (lhs: Variant, rhs: Variant) -> Bool {
var valid = GDExtensionBool (0)
Expand Down
4 changes: 2 additions & 2 deletions Sources/SwiftGodotTestability/GodotRuntime.swift
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,8 @@ private extension GodotRuntime {
guard let godotGetProcAddr else {
return 0
}
let interface = LibGodotExtensionInterface(library: libraryPtr, getProcAddrFun: godotGetProcAddr)
setExtensionInterface(interface: interface)
let bit = unsafeBitCast (godotGetProcAddr, to: OpaquePointer.self)
setExtensionInterface (to: bit, library: OpaquePointer (libraryPtr!))
godotLibrary = OpaquePointer (libraryPtr)!
extensionInit?.pointee = GDExtensionInitialization (
minimum_initialization_level: GDEXTENSION_INITIALIZATION_CORE,
Expand Down

0 comments on commit 07325cd

Please sign in to comment.