Skip to content

Releases: migueldeicaza/SwiftGodot

Release 0.60.1

26 Apr 16:07
20d2d7a
Compare
Choose a tag to compare

Swift bindings for Godot 0.60.1 release

We did a big jump from version 0.50 to 0.60 as this contains a large set of improvements to the binding thanks to Elijah Semyonov. Unless otherwise noted, the contributions were done by Elijah.

This is a large set of improvements that vastly improve the performance, reliability, usability and correctness of SwiftGodot andwe have tested this on a very large SwiftGodot app (Xogot). There are some changes required to your code, but the changes required are
simple, and detailed below.

Perhaps the biggest surprise is that the new TypedArray needs the T to be optional whenever you are dealing with a Godot Object, so you can now have things like: TypedArray<Int> and TypedArray<Node?> as well as the signal connection operations no longer returning an Object token that you pass to disconnect, but instead a Callable token that you must pass to disconnect.

Changes

Callable and Signals

  • @Export-able Swift closures properties proxied via Callable
  • Make Callable constructor taking an arbitrary Swift closure, where arguments and return types are bridgeable Gogot types. No manual working with Arguments anymore! :)
  • Godot -> Swift calls are now heap-allocation free. We no longer need heap-allocated Variants neither for argument extraction, nor returned value. FastVariant is nice!
  • Refine SignalWithArguments make it a struct. Make it reference wrapped object weakly (not preventing Swift from destroying it). That prevents signals from retaining the target object, which could lead to unexpected memory leaks. This behavior aligns with Godot Signal.
  • Deprecate SignalWithArguments.emitted, it's unsafe and will leak coroutine state referenced by continuation and captured context if it's never fired.
  • @callable macro now supports an autoSnakeCase parameter if you want to have this applied directly to your function to surface in a Godot-friendly way.

Collection Changes

  • Rename GArray to VariantArray. Leave deprecated typealias.
  • Introduces TypedArray uniting functionality of ObjectCollection and VariantCollection. It's almost fully source compatible but will require inserting some ? in existing code, but Swift didn't allow to avoid it. ObjectCollection and VariantCollection are deprecated type aliases to TypedArray. Migrating requires changing occurrences of ObjectCollection<Type> to TypedArray<Type?>
  • Introduce GodotBuiltinConvertible, a happy sibling of VariantConvertible that can proxy user type via specific Godot builtin instead of general purpose Variant.
  • Remove all special treatments of Swift.Array. It's simply conforming to GodotBuiltinConvertible if its elements are valid TypedArray elements ( builtin types, or Optional Object-derived types).
  • Change semantics of VariantArray to TypedArray conversion slightly. Now it follows the Godot rules: if conversion fails, it returns an empty (but typed!) array.
  • Constrain registration API to Object.Type instead of Wrapped.Type. It allows us to store Object-inherited classes metatypes of both framework types and user types for future improvements.
  • Godot proc addresses static storage is moved to a separate case-less enum for each builtin type. It is called GodotInterfaceFor{TypeName}. This is also a groundwork for per-class procs caches that should be manually flushed in projects like Xogot. Later this enum with static storage (or computed properties in case of Xogot) can be converted into a struct with instance properties stored into a global variables like var giNode: GodotInterfaceForNode!, similar to how general GodotInterface is stored in var gi: GodotInterface!.
  • Rename Dictionary to VariantDictionary. Leave deprecated typealias.
  • Implement TypedDictionary which behaves similar to TypedArray and facades Godot typed dictionary.
  • Make Swift.Dictionary a bridgeable type via GodotBuiltinConvertible.
  • Make Godot class builtins Hashable if they have hash() function.

Strings

  • String marshaling directly to and from FastVariant and Variant avoid allocation of GString class instance
  • Introduce FastStringName, a special kind of StringName that allows wrapping StaticString (Swift string with static storage), which allows avoiding allocations when StringName is constructed from non-interpolated String literal.
  • Use FastStringName in generated code during proc address retrieval.
  • Throw diagnostics error for an attempt to macro static members (was never supported).

Core - Variants

Internally, the VariantStorable and VariantRepresentable were replaced with the new VariantConvertible and a family of operations that simplified plenty of the operations on variants, removed boilerplate and ad-hoc hacks in various places.

This allowed the various macros in the SwiftGodot family to rely on the compiler and its type inference system to do the heavy-lifting when exposing types rather than rely on processing the syntax and attempting to cover various type scenarios.

This means that we now have a more reliable, more Swift-y way of working and will reduce surprised in the future for corner cases, as it is now the compiler doing the work, not relying on the macro to perform good guesses (Elijah)

  • All macro logic related to @Export, @Callable and @Godot relies on static dispatch into correctly selected overloaded functions for inferring PropInfo. That effectively removes a need for our handicapped attempt of type analysis based on SwiftSyntax.

  • .enum hints are filled automatically for @Export when eligible.

  • No explicit type information is needed for Node, @Export-ed properties anymore.

  • All places that need to distinguish nullability of marshalled types now do it according to Godot rules. Builtin types are never
    null. Objects subclasses and Variant are nullable and can be
    constrained to non-nullable on Swift side.

  • Code-generated SignalWithArguments now properly infers nullability
    according to these rules.

  • Names of arguments of @Callable are now correctly processed if they use MemberTypeSyntax (aka qualified names).

  • VariantStorable and VariantRepresentable are removed. Source-compatibility still stays, if they were not used directly.

  • Nice APIs to tackle Variant conversions. variant.to(Int.self), 50.toVariant(), Variant("Hello"), String(variant), everything is possible, except Object(variant) that won't crash runtime anymore, it simply doesn't exist.

  • Introduce lightweight FastVariant that doesn't require a heap allocation.

  • Integrate FastVariant for extraction specific types from Arguments. No heap allocations for each extracted argument, FastVariant temporarily borrows VariantContent provided by Godot to extract types we are interested in.

  • Make a lot of Variant APIs @inlinable so that compilation of user projects can optimise access to those APIs.

  • All VariantConvertible types are compatible with macros. They will surface as Variant in Godot.

Interoperability

  • The @godot Macro generates fully qualified typenames to avoid clash with user
    typenames.

Initialization

  • #initSwiftExtension macro will topologically sort the classes to register and deregister them in the right order. This is especially important for proper functioning of EntryPointGeneratorPlugin, which emits meta type elements in the order of files and syntax traversal.

Internals

  • Cleaned up macro library. Dead code for type analysis was removed. SwiftSyntax queries specific to Godot were moved to corresponding *Syntax extensions. Now code is much easier to follow. A little brother of Generator.Printer was brought to macro library to avoid indentation mess during code generation.
  • Macro-generated code is completely detached from ClassInfo. It's a prerequisite for a future improvement, where registration and reregistration happens proactively during extension initialisation. classInitializer will be replaced with a static var classDescriptor allowing topological sorting and and other lazy inference where information about all generated classes is available.

4.4 Support

  • This bring support for the 4.4 API update (Gabor Koncz, Miguel de Icaza)

  • Godot 4.4 Typed Dictionaries are now supported (Elijah)

Note

Release 0.60 was tagged, but there were a handful of small issues that prevented from this being a glorious release, so we added a couple of fixes.

Release 0.50

18 Apr 20:28
7e4c34c
Compare
Choose a tag to compare

New memory management system

A new document MemoryManagement.md document the new system, but for
existing users of SwiftGodot, there are a number of important
considerations:

  • As we have explored in the past, SwiftGodot objects that point to
    Godot objects could be destroyed by Godot behind our back. For
    example, if you create a Node, give it to Godot, and Godot destroys
    it, but you still had a pointer left to it.

    There was no way of determining that this had happened, so you could
    get a crash. Now, when this scenario ocurs, we clear the handle
    in the Godot object, which will do two things: you can now call
    isValid on these objects to determine if the object is still
    valid, and if you forget, a new exception will be raised for you to
    be able to pinpoint those cases.

  • In the past, it was possible for tthe same Godot object would be
    surfaced to Swift with different wrapper objects. This worked fine
    because we kept no state on them.

  • In the past, SwiftGodot released all objects when they went out of
    scope, following the idiom of Swift and automatic reference
    counting.

    This was not quite correct. With this release, only RefCounted
    objects (Resources-subclasses are one of the main users) get the
    automatic reference counting behavior. Subclasses of Node need to
    be manually released with Node.queueFree, and other non-Node,
    non-RefCounted objects must be manually released with Object.free.

The above was implemented by Gabor Koncz, Miguel de Icaza.

New Variant Binding

In the past, our Variant type would contain the special .nil type,
so when you got a Variant, to test for this, you would need to check
this value. In some APIs that meant first checking Variant was
non-nil, then checking for the .nil state in the Variant. It felt
bad.

This new version of the binding maps a Godot .nil value in a Variant
to Swift's nil, ensuring that if you ever have a Variant, it will
never contain the nil value. This does impact many existing
signatures that took Variant or [Variant], as they become
Variant? and [Variant?].

I have deployed this on a large app, and the results are very pleasant.

This was a contribution that was carefully developed over many weeks
by Elijah Semyonov. Thank you Elijah!

Signals

New @node Macro

Sam Deane contributed a new @Node macro that replaces the old
@SceneTree macro and should be used instead of the flaky BindNode
property wrapper.

Requiring the variable type to be optional or implicitly unwrapped
also doesn't quite make sense - we may as well support it being
non-optional. For non optional variables we'll get a runtime error if
the node is missing, which is also true for implicitly unwrapped vars.

It works like this:

@Node("nodePath") var myRequiredNode: SomeNodeType
@Node("nodePath") var myOptionalNode: SomeNodeType?

The scene tree macro implementation has been tweaked to support
non-optional type definitions, rather than complaining about them. It
does still support implicitly unwrapped types, for backwards
compatibility with @SceneTree, which remains unchanged.

Generic Signal

A new approach to signals that unifies the signals generated by
SwiftGodot. Fixes a long-standing bug #587, and long-standing #42.
Lovely contribution by Sam Deane.

New @signal Macro

Adds a new @signal macro, giving a cleaner and more consistent way to
add user-defined signals from Swift.

@Godot
class MyNode: Node {
  @Signal var mySignal: SimpleSignal
  @Signal var signalWithArgs: SignalWithArguments<Int, String>
}

These signals can be used in the same way as built-in signals:

node.mySignal.connect { /* do something */ }

node.signalWithArgs.connect { intArg, stringArg in
  // do something
}

node.mySignal.emit()
node.signalWithArgs.emit(1, "foo")

The existing #signal macro defines the signal as a static property on the class that contains it.

This is different from the generated implementation of built-in
signals, and means that we have to use a different syntax to work with
them -- which was non-optimal.

Changes

  • Now requires Swift 6.0 (Sam Deane)

  • Windows build improvements by Sam Deane

  • Surfaced support for editorAddPlugin and editorRemovePlugin to
    allow developers to create Godot editor plugins.

  • Introduces a new EntryPointGenerator
    plugin
    for
    all @godot classes in the project (Elijah)

  • Various documentation, test suite improvements, warning fixes and
    generator, refactoring changes and internal maintenance and quality
    of life improvements (Chris Backas, Sam Deane, Elijah Semyonov, Rob
    Mayoff, Gabor Koncz, Gianluc Lui, Miguel de Icaza).

  • Plenty of new convenience initializers for the Packed*Array types by
    Gianluc Lui.

  • New Variant.getNamed(key:) API

  • Small cleanups to our sample code (Sam Deane)

  • Enumerations no longer generate debugDescription as it was not
    necessary - reducing the API surface (Sam Deane)

  • Android support by Marc Prud'hommeaux. Nice tutorial on how to use
    SwiftGodot on the Meta Quest by Tomasz Wyrowiński is here:
    https://github.com/tomwyr/godot-swift-meta-quest-minimal/

  • @callable methods now can take optional values #669

  • The @export attribute can now specify PropertyUsage flags, if none
    is provided, it will continue to default to .default.

  • New support for overwriting the Godot _validate_property method,
    in SwiftGodot, the method to overwrite is _validateProperty and it
    can be used to change the property usage flags of a dynamic
    property.

Fixes

0.46

26 Apr 19:44
Compare
Choose a tag to compare

SwiftGogot 0.46

This version of SwiftGodot includes the following changes:

Features

  • Support for Godot 4.3 APIs, apologies for the delay.

Performance

  • Allocation-less marshaling for built-in and class types methods.
    The runtime no longer needs to allocate temporary variables to call
    into Godot, we now pass data directly from the stack (Elijah
    Semyonov)

  • More progress to perform Vector3 operations in Swift-land, without
    having to call into Godot to do the (Elijah Semyonov)

  • Arguments are now borrowed, without being copied (Elijah Semyonov)

Quality of Life Improvements

  • Warn users if they declare types that conflict with Godot types (Rob
    Mayoff)

  • Large class of memory leaks with variants have been fixed in a
    multi-week effort by Elijah Semyonov that tracked every single
    dangling reference to their root cause. This is truly a gift of the
    gods for all SwiftGodot users.

    #545, #541, #542, #548, #550, #552, #551

    And also a great test suite to ensure we do not regress.

  • New marshalling infrastructure that works on Windows, and removes
    the previous optimization that was failing to compile on Windows.

Fundamentals

  • Fix deprecated code usage (Luke Puchner-Hardman, Elijah Semyonov)

  • Fix a scenario where we did not lookup the most-derived type (Justin
    Anderson)

  • Fix crashes on some indexer operation (Elijah Semyonov)

Maintenance

  • Avoid name clashes with swift language keywords (Jakob
    Winkler)

  • Remove hard-coded values on my development system so everyone can
    enjoy it (Elijah Semyonov)

0.45: remove GodotObject protocol (#525)

20 Aug 17:44
f521910
Compare
Choose a tag to compare

SwiftGodot 0.45 is out!

This release works with both Godot 4.2 and Godot 4.3, but does not
surface yet any of the Godot 4.3 features, that is a patch I will
merge shortly after this release goes out.

Changes in this release:

  • Major upgrade to how we manage the lifecyle of object, which fixes
    some long-standing memory leaks in SwiftGodot, I did the initial
    pass, but Rob Mayoff found and fixed some hartd scenarios with
    Variants - and they should now all be handled correctly. Thank you
    Rob! (the major changes did not have a bug logged, but the commit
    is 738579a, the other fixes are for
    #513, #524).

  • PropInfo implements CustomDebugStringConvertible (miguel).

  • Arrays*.resize now have a @discardableResult and Array has it for
    append and push_back as well (miguel).

  • Arrays now conform to RandomAccessCollection (miguel)

  • Various warning fixes by Rob Mayoff (Fixes #516 and #520 for Xcode
    16 beta4)

  • Rob Mayoff also fixed a crash on startup on MacOS when launching the
    app (Fixes #517)

  • We now reference the new home for a few dependencies, (Rob Mayoff,
    #518)

  • Eliminated the GodotObject protocol that provided no value (Rob
    Mayoff, #525).

0.44.0: Drop the `value:` parameter name from the various PackedArray.* append

10 Jul 18:45
Compare
Choose a tag to compare
  • New IntersectRayResult strong type from Estevan Hernandez

  • Generates various native_structures, and also surfaces a handful of
    APIs that take pointers (those that exposed 'const void*' and
    'AudioFrame*') and were not available before. Additioanl
    pointer-based APIs will come, but there are some ambiguities and
    areas where we could surface a better API than just pointers, so I
    am explicitly going slow here, to avoid having to write a lot of
    additional compatibility hacks later.

  • The append methods in PackedArray classes no longer take a "value: "
    parameter, although a version is kept for compatibility.

  • The append methods now use the natural type for the array they
    contain, which should reduce the amount of casts necessary. That
    is, in the past we surfaced "append(value: Int64)" for the
    PackedArrayInt32, which was odd.

    Now:

    • PackedByteArray.append takes a UInt8
    • PackedFloat32Array.append takes a Float
    • PackedInt32Array.append takes a Int32

0.43.0

16 Jun 16:21
Compare
Choose a tag to compare
  • Optimization, BindNode will now cache the resolution of a node (Alex Loren)

  • BindNode now allows a path to be provided (Alex Loren)

  • GArray.append no longer takes a named "value:" parameter, to be
    closer to the Swift idiom on arrays (Joey Nelson)

  • Now the GodotError's localizedDescription uses Godot's own localized
    description rather than being a dump of the enumeration values
    (Miguel). Turns it into a more useful Swift Error.

  • Fixes the initialization process, so multiple Swift extensions can
    be added to a project (Miguel).

  • Fixes the deinitializtaion process (Miguel)

  • Brings support for Godot's built-in methods that take variable
    arguments, which were previoulsy not supported, and worked as if there had been no additional arguments provided, this brings:

    func Callable.call (_ args: Variant...)
    func Callable.callDeferred(_ args: Variant...)
    func Callable.rpc(_ args: Variant...)
    func Callable.rpcId(peerId: Int64, _ args: Variant...)
    func Callable.bind(_ args: Variant...)
    func Signal.emit(_ args: Variant...)
  • Fix resolution of dynamic types when only proper supertypes are exposed through GDExtension (#493, Gabor Koncz)

  • New documentation on how to launch extensions directly from VSCode,
    as an alternative to attach (Zacaria Guenna)

0.42.0: Export enum (#476)

21 May 18:58
04e47f5
Compare
Choose a tag to compare
  • Support for Exporting enumerations to Godot, to do this, flag your
    enumerations with CaseIterable, and then use @Export(.enum).
    See the Exports
    Documentation

    for additional information - Miguel.

  • Fix compilation when used with codebases that define their own
    Variant type, fix from Stefan Urbanek.

  • Fixes Godot documentation conversion by handling url fragments.
    Miguel.

  • Fix dynamic type of singletons (Gergely Kis, Gabor Koncz)

  • Performance: Exposed withUnsafeConstAccessToData for
    PackedByteArray, which avoids a data copy of the underlying buffer.
    Improvement by Kevin Watters.

  • Performance, all accessors to Packed data arrays now avoid copies, improvement by Kevin Watters.

  • Handle return as a special keyword, to fix compilation for some
    scenarios, fix by Josh Bromberg.

  • Various documentation updates, Miguel, Mikhail Tishin, Dolapo Falola

0.41.0

20 Mar 22:41
Compare
Choose a tag to compare

Version 0.41 is out, with lots of small improvements:

  • Wrapped.isValid can now be used to determine if an object has been
    released, this is the case when you might have called the
    queueFree method, use this on those objects to check if the object
    has alreayd been released or not.

    This helps alleviate the issue discussed in:
    #416

    Miguel

  • New helper method Variant.typeName (GType) which can be used to get
    the underlying type name (Miguel)

  • Add support for Swift 5.10 on Windows, which had a handful of
    breaking issues (Mikhail Tishin)

  • Upgraded Swift Syntax to a newer version (Mikhail Tishin)

  • GDictionary now supports debugDescription which will return the
    dictionary contents (Miguel)

  • Updates the documentation to reflect some recent API changes
    (Mikhail Tishin, Miguel).

  • We no longer depend on Foundation to build SwiftGodot, which should
    help users that do not want to pay the price of using it. The
    downside is that we lost the PackedByteArray.asData() method (as
    Data is defined in Foundation). But in exchange, we got an
    asBytes that reutnrs a byte array, and two unsafe with* methods
    that can be used to access the underlying buffer directly) - Mikhail
    Tishin and Miguel.

  • Packed Byte, Int32, Int64, Double and Float can now be initialized
    from arrays of those types without using an intermediary GArray of
    Variants (Miguel)

  • Now we have a static library of SwiftGodot in the build for those
    that need it (Mikhail Tishin)

  • Fixes a leak in returned VariatnCollections (Miguel).

0.40.0

27 Feb 15:48
Compare
Choose a tag to compare
  • Makes @export work with GArray and Variant types, fixes #410 by Miguel

  • API typo fix for degreesToRadians, spotted by @jbromberg

  • Fixes Exported VariantCollection and ObjectCollection types do not
    appear in the Editor (#408) by Estevan Hernandez.

  • Enumerations now conform to CustomDebugStringConvertible to assist
    in your debugging and GodotError exposes localizedDescription by Miguel)

  • Fixes running tests with swift test when using --verbose mode
    (Issue #407) by Mikhail Tishin

  • Fixes Unable to use await for Timer.timeout signal (#403) by Mikhail Tishin.

0.39.0

18 Feb 16:32
088b001
Compare
Choose a tag to compare

Bug fixes from Mikhail:

  • Make SceneTree macro path optional (#402)

  • Restructure VariantRepresentable conformances (#394)

  • Add AStar engine tests (#400)