Skip to content

Commit a24ca47

Browse files
committed
Provide safe way for implementing IScriptExtension::instance_has
1 parent 7461251 commit a24ca47

File tree

4 files changed

+211
-22
lines changed

4 files changed

+211
-22
lines changed

godot-codegen/src/special_cases/codegen_special_cases.rs

+2
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,9 @@ const SELECTED_CLASSES: &[&str] = &[
173173
"SceneTreeTimer",
174174
"Script",
175175
"ScriptExtension",
176+
"ScriptNameCasing",
176177
"ScriptLanguage",
178+
"ScriptLanguageExtension",
177179
"Sprite2D",
178180
"SpriteFrames",
179181
"TextServer",

godot-core/src/obj/script.rs

+29-2
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,9 @@ use godot_cell::panicking::{GdCell, MutGuard, RefGuard};
2525
use godot_cell::blocking::{GdCell, MutGuard, RefGuard};
2626

2727
use crate::builtin::{GString, StringName, Variant, VariantType};
28-
use crate::classes::{Script, ScriptLanguage};
28+
use crate::classes::{Object, Script, ScriptLanguage};
2929
use crate::meta::{MethodInfo, PropertyInfo};
30-
use crate::obj::{Base, Gd, GodotClass};
30+
use crate::obj::{Base, Gd, GodotClass, Inherits};
3131
use crate::sys;
3232

3333
#[cfg(before_api = "4.3")]
@@ -337,6 +337,33 @@ pub unsafe fn create_script_instance<T: ScriptInstance>(
337337
}
338338
}
339339

340+
/// Checks if a script instance exists for a given object.
341+
///
342+
/// The engine does not expose the [`ScriptLanguage`] of a [`Script`] (as of 4.3) and it's therefore necessary to pass the expected
343+
/// language as well.
344+
///
345+
/// Use this function to implement [`IScriptExtension::instance_has`](crate::classes::IScriptExtension::instance_has).
346+
#[cfg(since_api = "4.2")]
347+
pub fn script_instance_exists<O, S, L>(object: &Gd<O>, script: &Gd<S>, language: &Gd<L>) -> bool
348+
where
349+
O: Inherits<Object>,
350+
S: Inherits<Script>,
351+
L: Inherits<ScriptLanguage>,
352+
{
353+
let get_instance_fn = sys::interface_fn!(object_get_script_instance);
354+
355+
let object_script_variant = object.upcast_ref().get_script();
356+
357+
if object_script_variant.is_nil() {
358+
return false;
359+
}
360+
361+
let object_script: Gd<Script> = object_script_variant.to();
362+
let instance = unsafe { get_instance_fn(object.obj_sys(), language.obj_sys()) };
363+
364+
!instance.is_null() && object_script == script.clone().upcast()
365+
}
366+
340367
/// Mutable/exclusive reference guard for a `T` where `T` implements [`ScriptInstance`].
341368
///
342369
/// This can be used to access the base object of a [`ScriptInstance`], which in turn can be used to make reentrant calls to engine APIs.

itest/godot/ScriptInstanceTests.gd

+43-13
Original file line numberDiff line numberDiff line change
@@ -5,103 +5,133 @@
55

66
extends TestSuite
77

8-
func create_script_instance() -> RefCounted:
9-
var script = TestScript.new()
8+
func create_script_instance() -> Array:
9+
var language: TestScriptLanguage = TestScriptLanguage.new()
10+
var script: TestScript = language.new_script()
1011
var script_owner = RefCounted.new()
1112

1213
script_owner.script = script
1314

14-
return script_owner
15+
return [script_owner, language]
1516

1617

1718
func test_script_instance_get_property():
18-
var object = create_script_instance()
19+
var tuple := create_script_instance()
20+
var object: RefCounted = tuple[0]
21+
var language: TestScriptLanguage = tuple[1]
1922

2023
var value: int = object.script_property_a
2124

2225
assert_eq(value, 10)
26+
language.free()
2327

2428

2529
func test_script_instance_set_property():
26-
var object = create_script_instance()
30+
var tuple := create_script_instance()
31+
var object: RefCounted = tuple[0]
32+
var language: TestScriptLanguage = tuple[1]
2733

2834
assert_eq(object.script_property_b, false)
2935

3036
object.script_property_b = true
3137

3238
assert_eq(object.script_property_b, true)
39+
language.free()
3340

3441

3542
func test_script_instance_call():
36-
var object = create_script_instance()
43+
var tuple := create_script_instance()
44+
var object: RefCounted = tuple[0]
45+
var language: TestScriptLanguage = tuple[1]
3746

3847
var arg_a = "test string"
3948
var arg_b = 5
4049

4150
var result = object.script_method_a(arg_a, arg_b)
4251

4352
assert_eq(result, "{0}{1}".format([arg_a, arg_b]))
53+
language.free()
4454

4555

4656
func test_script_instance_property_list():
47-
var object = create_script_instance()
57+
var tuple := create_script_instance()
58+
var object: RefCounted = tuple[0]
59+
var language: TestScriptLanguage = tuple[1]
4860

4961
var list = object.get_property_list()
5062

5163
assert_eq(list[-1]["name"], "script_property_a");
5264
assert_eq(list[-1]["type"], Variant.Type.TYPE_INT)
65+
language.free()
5366

5467

5568
func test_script_instance_method_list():
56-
var object = create_script_instance()
69+
var tuple := create_script_instance()
70+
var object: RefCounted = tuple[0]
71+
var language: TestScriptLanguage = tuple[1]
5772

5873
var list = object.get_method_list()
5974

6075
assert_eq(list[-1]["name"], "script_method_a")
6176
assert_eq(list[-1]["args"][0]["type"], Variant.Type.TYPE_STRING)
6277
assert_eq(list[-1]["args"][1]["type"], Variant.Type.TYPE_INT)
78+
language.free()
6379

6480

6581
func test_script_instance_has_method():
66-
var object = create_script_instance()
82+
var tuple := create_script_instance()
83+
var object: RefCounted = tuple[0]
84+
var language: TestScriptLanguage = tuple[1]
6785

6886
assert(object.has_method("script_method_a"));
6987
assert(!object.has_method("script_method_z"));
88+
language.free()
7089

7190

7291
func test_script_instance_to_string():
73-
var object = create_script_instance()
92+
var tuple := create_script_instance()
93+
var object: RefCounted = tuple[0]
94+
var language: TestScriptLanguage = tuple[1]
7495

7596
assert_eq(object.to_string(), "script instance to string")
97+
language.free()
7698

7799

78100
func test_script_instance_mut_call():
79-
var object = create_script_instance()
101+
var tuple := create_script_instance()
102+
var object: RefCounted = tuple[0]
103+
var language: TestScriptLanguage = tuple[1]
80104
var before = object.script_property_b
81105

82106
var result = object.script_method_toggle_property_b()
83107

84108
assert(result)
85109
assert_eq(object.script_property_b, !before)
110+
language.free()
86111

87112

88113
func test_script_instance_re_entering_call():
89-
var object = create_script_instance()
114+
var tuple := create_script_instance()
115+
var object: RefCounted = tuple[0]
116+
var language: TestScriptLanguage = tuple[1]
90117
var before = object.script_property_b
91118

92119
var result = object.script_method_re_entering()
93120

94121
assert(result)
95122
assert_eq(object.script_property_b, !before)
123+
language.free()
96124

97125

98126
func test_object_script_instance():
99127
var object = Node.new()
100-
var script = TestScript.new()
128+
var language: TestScriptLanguage = TestScriptLanguage.new()
129+
var script: TestScript = language.new_script()
101130

102131
object.script = script
103132

104133
var result = object.script_method_re_entering()
105134

106135
assert(result)
107136
object.free()
137+
language.free()

0 commit comments

Comments
 (0)