Skip to content

Commit 945a905

Browse files
committed
feat: Remove need for .cast
By adding the script instance check to `gd_object_to_dart_object`, that method can do all casting for us properly. Minor: fix generator to not have RPC method class be private (preventing a warning from the analyzer).
1 parent d4d8d61 commit 945a905

File tree

7 files changed

+28
-51
lines changed

7 files changed

+28
-51
lines changed

README.md

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ class SimpleScript extends Sprite2D {
100100
// Any method that needs to be seen by a signal needs to be exported
101101
@GodotExport()
102102
void onSignal() {
103-
// To call and RPC as an RPC you use the $rpc variable
103+
// To call an RPC as an RPC you use the $rpc variable
104104
$rpc.rpcMessage('message');
105105
}
106106
}
@@ -133,8 +133,7 @@ class Simple extends Sprite2D {
133133
StringName.fromString('Simple'),
134134
parentClass: StringName.fromString('Sprite2D'),
135135
// a vTable getter is required for classes that will be used from extensions.
136-
// If you are not adding any virtual functions, just return the base class's vTable.
137-
// If the class is only used from scripts, this is likely not necessary.
136+
// If you are not adding any virtual functions, just return the base class's vTable.
138137
vTable: Sprite2D.sTypeInfo.vTable;
139138
);
140139
// An override of [typeInfo] is required. This is how
@@ -184,9 +183,9 @@ void main() {
184183

185184
### Casting
186185

187-
When you are working with a Godot object, do not use `is` or `as` to perform downcasting. This will
188-
always fail because of how Godot extension works. Instead, use `.cast<T>`, which will return `null`
189-
if the cast fails.
186+
Early versions of Godot Dart required using `.cast<T>` to perform downcasting. This is no longer
187+
necessary. Dart's built in `is` and `as` operators should now work to perform downcasting. `cast<T>`
188+
has also been removed and replaced with `.as<T>`, which is an implementation of `as?` or `dynamic_cast`.
190189

191190
### Virtual functions
192191

example/2d_tutorial/src/lib/game_logic.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ class GameLogic extends Node {
7575

7676
@GodotExport()
7777
void onMobTimerTimeout() {
78-
final mob = mobScene?.instantiate()?.cast<Mob>();
78+
final mob = mobScene?.instantiate()?.as<Mob>();
7979
if (mob != null) {
8080
var mobSpawnLocation =
8181
getNodeT<PathFollow2D>('MobPath/MobSpawnLocation')!;

src/cpp/dart_bindings.cpp

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -397,18 +397,18 @@ void GodotDartBindings::bind_method(const TypeInfo &bind_type, const char *metho
397397
Dart_Handle GodotDartBindings::find_dart_type(Dart_Handle type_name) {
398398
DartBlockScope scope;
399399

400-
uint8_t* c_type_name = nullptr;
400+
uint8_t *c_type_name = nullptr;
401401
intptr_t length = 0;
402402
Dart_StringToUTF8(type_name, &c_type_name, &length);
403-
if (0 == strncmp(reinterpret_cast<const char*>(c_type_name), "Object", length)) {
403+
if (0 == strncmp(reinterpret_cast<const char *>(c_type_name), "Object", length)) {
404404
type_name = Dart_NewStringFromCString("GodotObject");
405405
}
406406

407407
DART_CHECK_RET(engine_classes_library, Dart_HandleFromPersistent(_engine_classes_library), Dart_Null(),
408-
"Error getting class class library.")
408+
"Error getting class class library.")
409409

410410
DART_CHECK_RET(type, Dart_GetNonNullableType(engine_classes_library, type_name, 0, nullptr), Dart_Null(),
411-
"Could not find type in the engine_classes_library.");
411+
"Could not find type in the engine_classes_library.");
412412

413413
return type;
414414
}
@@ -815,9 +815,17 @@ void gd_object_to_dart_object(Dart_NativeArguments args) {
815815
}
816816

817817
GDEWrapper *gde = GDEWrapper::instance();
818+
GDExtensionScriptInstanceDataPtr script_instance = gde_object_get_script_instance(
819+
reinterpret_cast<GDExtensionObjectPtr>(object_ptr), DartScriptLanguage::instance()->_owner);
820+
if (script_instance) {
821+
Dart_Handle obj = reinterpret_cast<DartScriptInstance *>(script_instance)->get_dart_object();
822+
Dart_SetReturnValue(args, obj);
823+
return;
824+
}
818825

819826
DartGodotInstanceBinding *binding = (DartGodotInstanceBinding *)gde_object_get_instance_binding(
820-
reinterpret_cast<GDExtensionObjectPtr>(object_ptr), bindings, &DartGodotInstanceBinding::engine_binding_callbacks);
827+
reinterpret_cast<GDExtensionObjectPtr>(object_ptr), bindings,
828+
&DartGodotInstanceBinding::engine_binding_callbacks);
821829
if (binding == nullptr) {
822830
Dart_SetReturnValue(args, Dart_Null());
823831
} else {
@@ -905,7 +913,7 @@ void type_info_from_dart(TypeInfo *type_info, Dart_Handle dart_type_info) {
905913

906914
Dart_Handle class_name = Dart_GetField(dart_type_info, Dart_NewStringFromCString("className"));
907915
Dart_Handle parent_type = Dart_GetField(dart_type_info, Dart_NewStringFromCString("parentType"));
908-
Dart_Handle variant_type = Dart_GetField(dart_type_info, Dart_NewStringFromCString("variantType"));
916+
Dart_Handle variant_type = Dart_GetField(dart_type_info, Dart_NewStringFromCString("variantType"));
909917

910918
type_info->type_name = get_object_address(class_name);
911919
type_info->parent_type = parent_type;
@@ -938,8 +946,8 @@ GDE_EXPORT void tie_dart_to_native(Dart_Handle dart_object, GDExtensionObjectPtr
938946
type_info_from_dart(&class_type_info, d_class_type_info);
939947

940948
const GDExtensionInstanceBindingCallbacks *callbacks = &DartGodotInstanceBinding::engine_binding_callbacks;
941-
DartGodotInstanceBinding *binding = (DartGodotInstanceBinding *)gde_object_get_instance_binding(
942-
godot_object, bindings, callbacks);
949+
DartGodotInstanceBinding *binding =
950+
(DartGodotInstanceBinding *)gde_object_get_instance_binding(godot_object, bindings, callbacks);
943951
if (!binding->is_initialized()) {
944952
binding->initialize(dart_object, is_refcounted);
945953
}

src/dart/godot_dart/lib/src/core/gdextension.dart

Lines changed: 3 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -212,37 +212,8 @@ class GodotDart {
212212
}
213213

214214
extension GodotObjectCast on GodotObject {
215-
// TODO: We might not need this if gdObjectToDartObject checks
216-
// if something has a script instance, than casts it directly.
217-
T? cast<T>() {
218-
var typeInfo = gde.dartBindings.getGodotTypeInfo(T);
219-
final classTag = gde.getClassTag(typeInfo.className);
220-
Pointer<Void> casted;
221-
if (classTag != nullptr) {
222-
casted = gde.ffiBindings.gde_object_cast_to(nativePtr, classTag);
223-
if (casted == nullptr) {
224-
return null;
225-
}
226-
227-
final persistent = gde.ffiBindings.gde_object_get_instance_binding(
228-
casted,
229-
gde.extensionToken,
230-
gde.engineBindingCallbacks,
231-
);
232-
final dartObject = gde.dartBindings.objectFromInstanceBinding(persistent);
233-
234-
return dartObject as T;
235-
} else {
236-
// Try getting the script instance, and casting from that
237-
final scriptInstance = gde.dartBindings.getScriptInstance(nativePtr);
238-
if (scriptInstance != nullptr) {
239-
final o = gde.dartBindings.objectFromScriptInstance(scriptInstance);
240-
if (o is T) {
241-
return o;
242-
}
243-
}
244-
}
245-
246-
return null;
215+
// Implementation of as? or dynamic_cast
216+
T? as<T>() {
217+
return this is T ? this as T : null;
247218
}
248219
}

src/dart/godot_dart/lib/src/core/type_info.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ class TypeInfo {
120120
this.size = 0,
121121
this.vTable = const {},
122122
this.scriptInfo,
123-
}) {}
123+
});
124124

125125
static late Map<Type?, TypeInfo> _typeMapping;
126126
static void initTypeMappings() {

src/dart/godot_dart/lib/src/extensions/core_extensions.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ extension TNode on Node {
1515
name = GDString.fromStringName(typeInfo.className);
1616
}
1717
var node = getNode(NodePath.fromGDString(name));
18-
return node?.cast<T>();
18+
return node?.as<T>();
1919
}
2020
}
2121

src/dart/godot_dart_build/lib/src/godot_script_generator.dart

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,6 @@ class GodotScriptAnnotationGenerator
149149
buffer.writeln(' name: \'$exportName\',');
150150
buffer.writeln(' dartMethodName: \'${element.name}\',');
151151
} else if (element.hasOverride) {
152-
// TODO - I might change the naming scheme here
153152
final godotMethodName = _convertVirtualMethodName(element.name);
154153
buffer.writeln(' name: \'$godotMethodName\',');
155154
buffer.writeln(' dartMethodName: \'${element.name}\',');
@@ -311,7 +310,7 @@ class GodotScriptAnnotationGenerator
311310
StringBuffer buffer = StringBuffer();
312311

313312
final className = element.name;
314-
final rpcMethodsClass = '_\$${className}RpcMethods';
313+
final rpcMethodsClass = '\$${className}RpcMethods';
315314
buffer.writeln('class $rpcMethodsClass {');
316315
buffer.writeln(' $className self;');
317316
buffer.writeln(' $rpcMethodsClass(this.self);');

0 commit comments

Comments
 (0)