Release 0.60.1
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 viaCallable
- Make
Callable
constructor taking an arbitrary Swift closure, where arguments and return types are bridgeable Gogot types. No manual working withArguments
anymore! :) - Godot -> Swift calls are now heap-allocation free. We no longer need heap-allocated
Variant
s 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 GodotSignal
. - Deprecate
SignalWithArguments.emitted
, it's unsafe and will leak coroutine state referenced bycontinuation
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
toVariantArray
. Leave deprecated typealias. - Introduces
TypedArray
uniting functionality ofObjectCollection
andVariantCollection
. It's almost fully source compatible but will require inserting some?
in existing code, but Swift didn't allow to avoid it.ObjectCollection
andVariantCollection
are deprecated type aliases toTypedArray
. Migrating requires changing occurrences ofObjectCollection<Type>
toTypedArray<Type?>
- Introduce
GodotBuiltinConvertible
, a happy sibling ofVariantConvertible
that can proxy user type via specific Godot builtin instead of general purposeVariant
. - Remove all special treatments of
Swift.Array
. It's simply conforming toGodotBuiltinConvertible
if its elements are validTypedArray
elements ( builtin types, orOptional
Object
-derived types). - Change semantics of
VariantArray
toTypedArray
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 ofWrapped.Type
. It allows us to storeObject
-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 likeXogot
. Later thisenum
with static storage (or computed properties in case of Xogot) can be converted into astruct
with instance properties stored into a global variables likevar giNode: GodotInterfaceForNode!
, similar to how generalGodotInterface
is stored invar gi: GodotInterface!
. - Rename
Dictionary
toVariantDictionary
. Leave deprecated typealias. - Implement
TypedDictionary
which behaves similar toTypedArray
and facades Godot typed dictionary. - Make
Swift.Dictionary
a bridgeable type viaGodotBuiltinConvertible
. - Make Godot
class
builtinsHashable
if they havehash()
function.
Strings
String
marshaling directly to and fromFastVariant
andVariant
avoid allocation ofGString
class instance- Introduce
FastStringName
, a special kind ofStringName
that allows wrappingStaticString
(Swift string with static storage), which allows avoiding allocations whenStringName
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 inferringPropInfo
. 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 andVariant
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 useMemberTypeSyntax
(aka qualified names). -
VariantStorable
andVariantRepresentable
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, exceptObject(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 fromArguments
. No heap allocations for each extracted argument,FastVariant
temporarily borrowsVariantContent
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 asVariant
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 ofEntryPointGeneratorPlugin
, 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 ofGenerator.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 astatic 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.