Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/tests/scene/test_instance_placeholder.h
10277 views
1
/**************************************************************************/
2
/* test_instance_placeholder.h */
3
/**************************************************************************/
4
/* This file is part of: */
5
/* GODOT ENGINE */
6
/* https://godotengine.org */
7
/**************************************************************************/
8
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10
/* */
11
/* Permission is hereby granted, free of charge, to any person obtaining */
12
/* a copy of this software and associated documentation files (the */
13
/* "Software"), to deal in the Software without restriction, including */
14
/* without limitation the rights to use, copy, modify, merge, publish, */
15
/* distribute, sublicense, and/or sell copies of the Software, and to */
16
/* permit persons to whom the Software is furnished to do so, subject to */
17
/* the following conditions: */
18
/* */
19
/* The above copyright notice and this permission notice shall be */
20
/* included in all copies or substantial portions of the Software. */
21
/* */
22
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29
/**************************************************************************/
30
31
#pragma once
32
33
#include "scene/main/instance_placeholder.h"
34
#include "scene/resources/packed_scene.h"
35
36
#include "tests/test_macros.h"
37
38
class _TestInstancePlaceholderNode : public Node {
39
GDCLASS(_TestInstancePlaceholderNode, Node);
40
41
protected:
42
static void _bind_methods() {
43
ClassDB::bind_method(D_METHOD("set_int_property", "int_property"), &_TestInstancePlaceholderNode::set_int_property);
44
ClassDB::bind_method(D_METHOD("get_int_property"), &_TestInstancePlaceholderNode::get_int_property);
45
46
ADD_PROPERTY(PropertyInfo(Variant::INT, "int_property"), "set_int_property", "get_int_property");
47
48
ClassDB::bind_method(D_METHOD("set_reference_property", "reference_property"), &_TestInstancePlaceholderNode::set_reference_property);
49
ClassDB::bind_method(D_METHOD("get_reference_property"), &_TestInstancePlaceholderNode::get_reference_property);
50
51
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "reference_property", PROPERTY_HINT_NODE_TYPE), "set_reference_property", "get_reference_property");
52
53
ClassDB::bind_method(D_METHOD("set_reference_array_property", "reference_array_property"), &_TestInstancePlaceholderNode::set_reference_array_property);
54
ClassDB::bind_method(D_METHOD("get_reference_array_property"), &_TestInstancePlaceholderNode::get_reference_array_property);
55
56
// The hint string value "24/34:Node" is determined from existing PackedScenes with typed Array properties.
57
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "reference_array_property", PROPERTY_HINT_TYPE_STRING, "24/34:Node"), "set_reference_array_property", "get_reference_array_property");
58
}
59
60
public:
61
int int_property = 0;
62
63
void set_int_property(int p_int) {
64
int_property = p_int;
65
}
66
67
int get_int_property() const {
68
return int_property;
69
}
70
71
Variant reference_property;
72
73
void set_reference_property(const Variant &p_node) {
74
reference_property = p_node;
75
}
76
77
Variant get_reference_property() const {
78
return reference_property;
79
}
80
81
Array reference_array_property;
82
83
void set_reference_array_property(const Array &p_array) {
84
reference_array_property = p_array;
85
}
86
87
Array get_reference_array_property() const {
88
return reference_array_property;
89
}
90
91
_TestInstancePlaceholderNode() {
92
reference_array_property.set_typed(Variant::OBJECT, "Node", Variant());
93
}
94
};
95
96
namespace TestInstancePlaceholder {
97
98
TEST_CASE("[SceneTree][InstancePlaceholder] Instantiate from placeholder with no overrides") {
99
GDREGISTER_CLASS(_TestInstancePlaceholderNode);
100
101
SUBCASE("with non-node values") {
102
InstancePlaceholder *ip = memnew(InstancePlaceholder);
103
ip->set_name("TestScene");
104
Node *root = memnew(Node);
105
SceneTree::get_singleton()->get_root()->add_child(root);
106
107
root->add_child(ip);
108
// Create a scene to instance.
109
_TestInstancePlaceholderNode *scene = memnew(_TestInstancePlaceholderNode);
110
scene->set_int_property(12);
111
112
// Pack the scene.
113
PackedScene *packed_scene = memnew(PackedScene);
114
const Error err = packed_scene->pack(scene);
115
REQUIRE(err == OK);
116
117
// Instantiate the scene.
118
_TestInstancePlaceholderNode *created = Object::cast_to<_TestInstancePlaceholderNode>(ip->create_instance(true, packed_scene));
119
REQUIRE(created != nullptr);
120
CHECK(created->get_name() == "TestScene");
121
CHECK(created->get_int_property() == 12);
122
123
root->queue_free();
124
memdelete(scene);
125
}
126
127
SUBCASE("with node value") {
128
InstancePlaceholder *ip = memnew(InstancePlaceholder);
129
ip->set_name("TestScene");
130
Node *root = memnew(Node);
131
SceneTree::get_singleton()->get_root()->add_child(root);
132
133
root->add_child(ip);
134
// Create a scene to instance.
135
_TestInstancePlaceholderNode *scene = memnew(_TestInstancePlaceholderNode);
136
Node *referenced = memnew(Node);
137
scene->add_child(referenced);
138
referenced->set_owner(scene);
139
scene->set_reference_property(referenced);
140
// Pack the scene.
141
PackedScene *packed_scene = memnew(PackedScene);
142
const Error err = packed_scene->pack(scene);
143
REQUIRE(err == OK);
144
145
// Instantiate the scene.
146
_TestInstancePlaceholderNode *created = Object::cast_to<_TestInstancePlaceholderNode>(ip->create_instance(true, packed_scene));
147
REQUIRE(created != nullptr);
148
CHECK(created->get_name() == "TestScene");
149
CHECK(created->get_child_count() == 1);
150
CHECK(created->get_reference_property().identity_compare(created->get_child(0, false)));
151
CHECK_FALSE(created->get_reference_property().identity_compare(referenced));
152
153
root->queue_free();
154
memdelete(scene);
155
}
156
157
SUBCASE("with node-array value") {
158
InstancePlaceholder *ip = memnew(InstancePlaceholder);
159
ip->set_name("TestScene");
160
Node *root = memnew(Node);
161
SceneTree::get_singleton()->get_root()->add_child(root);
162
163
root->add_child(ip);
164
// Create a scene to instance.
165
_TestInstancePlaceholderNode *scene = memnew(_TestInstancePlaceholderNode);
166
Node *referenced1 = memnew(Node);
167
Node *referenced2 = memnew(Node);
168
scene->add_child(referenced1);
169
scene->add_child(referenced2);
170
referenced1->set_owner(scene);
171
referenced2->set_owner(scene);
172
Array node_array;
173
node_array.set_typed(Variant::OBJECT, "Node", Variant());
174
node_array.push_back(referenced1);
175
node_array.push_back(referenced2);
176
scene->set_reference_array_property(node_array);
177
// Pack the scene.
178
PackedScene *packed_scene = memnew(PackedScene);
179
const Error err = packed_scene->pack(scene);
180
REQUIRE(err == OK);
181
182
// Instantiate the scene.
183
_TestInstancePlaceholderNode *created = Object::cast_to<_TestInstancePlaceholderNode>(ip->create_instance(true, packed_scene));
184
REQUIRE(created != nullptr);
185
CHECK(created->get_name() == "TestScene");
186
CHECK(created->get_child_count() == 2);
187
Array created_array = created->get_reference_array_property();
188
REQUIRE(created_array.size() == node_array.size());
189
REQUIRE(created_array.size() == created->get_child_count());
190
191
// Iterate over all nodes, since the ordering is not guaranteed.
192
for (int i = 0; i < node_array.size(); i++) {
193
bool node_found = false;
194
for (int j = 0; j < created->get_child_count(); j++) {
195
if (created_array[i].identity_compare(created->get_child(j, true))) {
196
node_found = true;
197
}
198
}
199
CHECK(node_found);
200
}
201
root->queue_free();
202
memdelete(scene);
203
}
204
}
205
206
TEST_CASE("[SceneTree][InstancePlaceholder] Instantiate from placeholder with overrides") {
207
GDREGISTER_CLASS(_TestInstancePlaceholderNode);
208
209
SUBCASE("with non-node values") {
210
InstancePlaceholder *ip = memnew(InstancePlaceholder);
211
Node *root = memnew(Node);
212
SceneTree::get_singleton()->get_root()->add_child(root);
213
214
root->add_child(ip);
215
ip->set_name("TestScene");
216
ip->set("int_property", 45);
217
// Create a scene to pack.
218
_TestInstancePlaceholderNode *scene = memnew(_TestInstancePlaceholderNode);
219
scene->set_int_property(12);
220
221
// Pack the scene.
222
PackedScene *packed_scene = memnew(PackedScene);
223
packed_scene->pack(scene);
224
225
// Instantiate the scene.
226
_TestInstancePlaceholderNode *created = Object::cast_to<_TestInstancePlaceholderNode>(ip->create_instance(true, packed_scene));
227
REQUIRE(created != nullptr);
228
CHECK(created->get_int_property() == 45);
229
230
root->queue_free();
231
memdelete(scene);
232
}
233
234
SUBCASE("with node values") {
235
InstancePlaceholder *ip = memnew(InstancePlaceholder);
236
ip->set_name("TestScene");
237
Node *root = memnew(Node);
238
Node *overriding = memnew(Node);
239
SceneTree::get_singleton()->get_root()->add_child(root);
240
241
root->add_child(ip);
242
root->add_child(overriding);
243
ip->set("reference_property", overriding);
244
// Create a scene to instance.
245
_TestInstancePlaceholderNode *scene = memnew(_TestInstancePlaceholderNode);
246
Node *referenced = memnew(Node);
247
scene->add_child(referenced);
248
referenced->set_owner(scene);
249
scene->set_reference_property(referenced);
250
// Pack the scene.
251
PackedScene *packed_scene = memnew(PackedScene);
252
const Error err = packed_scene->pack(scene);
253
REQUIRE(err == OK);
254
255
// Instantiate the scene.
256
_TestInstancePlaceholderNode *created = Object::cast_to<_TestInstancePlaceholderNode>(ip->create_instance(true, packed_scene));
257
REQUIRE(created != nullptr);
258
CHECK(created->get_name() == "TestScene");
259
CHECK(created->get_child_count() == 1);
260
CHECK(created->get_reference_property().identity_compare(overriding));
261
CHECK_FALSE(created->get_reference_property().identity_compare(referenced));
262
263
root->queue_free();
264
memdelete(scene);
265
}
266
267
SUBCASE("with node-array value") {
268
InstancePlaceholder *ip = memnew(InstancePlaceholder);
269
ip->set_name("TestScene");
270
Node *root = memnew(Node);
271
SceneTree::get_singleton()->get_root()->add_child(root);
272
273
Node *override1 = memnew(Node);
274
Node *override2 = memnew(Node);
275
Node *override3 = memnew(Node);
276
root->add_child(ip);
277
root->add_child(override1);
278
root->add_child(override2);
279
root->add_child(override3);
280
281
Array override_node_array;
282
override_node_array.set_typed(Variant::OBJECT, "Node", Variant());
283
override_node_array.push_back(override1);
284
override_node_array.push_back(override2);
285
override_node_array.push_back(override3);
286
287
ip->set("reference_array_property", override_node_array);
288
289
// Create a scene to instance.
290
_TestInstancePlaceholderNode *scene = memnew(_TestInstancePlaceholderNode);
291
Node *referenced1 = memnew(Node);
292
Node *referenced2 = memnew(Node);
293
294
scene->add_child(referenced1);
295
scene->add_child(referenced2);
296
297
referenced1->set_owner(scene);
298
referenced2->set_owner(scene);
299
Array referenced_array;
300
referenced_array.set_typed(Variant::OBJECT, "Node", Variant());
301
referenced_array.push_back(referenced1);
302
referenced_array.push_back(referenced2);
303
304
scene->set_reference_array_property(referenced_array);
305
// Pack the scene.
306
PackedScene *packed_scene = memnew(PackedScene);
307
const Error err = packed_scene->pack(scene);
308
REQUIRE(err == OK);
309
310
// Instantiate the scene.
311
_TestInstancePlaceholderNode *created = Object::cast_to<_TestInstancePlaceholderNode>(ip->create_instance(true, packed_scene));
312
REQUIRE(created != nullptr);
313
CHECK(created->get_name() == "TestScene");
314
CHECK(created->get_child_count() == 2);
315
Array created_array = created->get_reference_array_property();
316
REQUIRE_FALSE(created_array.size() == referenced_array.size());
317
REQUIRE(created_array.size() == override_node_array.size());
318
REQUIRE_FALSE(created_array.size() == created->get_child_count());
319
320
// Iterate over all nodes, since the ordering is not guaranteed.
321
for (int i = 0; i < override_node_array.size(); i++) {
322
bool node_found = false;
323
for (int j = 0; j < created_array.size(); j++) {
324
if (override_node_array[i].identity_compare(created_array[j])) {
325
node_found = true;
326
}
327
}
328
CHECK(node_found);
329
}
330
root->queue_free();
331
memdelete(scene);
332
}
333
}
334
335
#ifdef TOOLS_ENABLED
336
TEST_CASE("[SceneTree][InstancePlaceholder] Instance a PackedScene containing an InstancePlaceholder with no overrides") {
337
GDREGISTER_CLASS(_TestInstancePlaceholderNode);
338
339
// Create the internal scene.
340
_TestInstancePlaceholderNode *internal = memnew(_TestInstancePlaceholderNode);
341
internal->set_name("InternalNode");
342
Node *referenced = memnew(Node);
343
referenced->set_name("OriginalReference");
344
internal->add_child(referenced);
345
referenced->set_owner(internal);
346
internal->set_reference_property(referenced);
347
348
// Pack the internal scene.
349
PackedScene *internal_scene = memnew(PackedScene);
350
Error err = internal_scene->pack(internal);
351
REQUIRE(err == OK);
352
353
const String internal_path = TestUtils::get_temp_path("instance_placeholder_test_internal.tscn");
354
err = ResourceSaver::save(internal_scene, internal_path);
355
REQUIRE(err == OK);
356
357
Ref<PackedScene> internal_scene_loaded = ResourceLoader::load(internal_path, "PackedScene", ResourceFormatLoader::CacheMode::CACHE_MODE_IGNORE, &err);
358
REQUIRE(err == OK);
359
360
// Create the main scene.
361
Node *root = memnew(Node);
362
root->set_name("MainNode");
363
Node *overriding = memnew(Node);
364
overriding->set_name("OverridingReference");
365
366
_TestInstancePlaceholderNode *internal_created = Object::cast_to<_TestInstancePlaceholderNode>(internal_scene_loaded->instantiate(PackedScene::GEN_EDIT_STATE_MAIN_INHERITED));
367
internal_created->set_scene_instance_load_placeholder(true);
368
root->add_child(internal_created);
369
internal_created->set_owner(root);
370
371
root->add_child(overriding);
372
overriding->set_owner(root);
373
// Here we introduce an error, we override the property with an internal node to the instance placeholder.
374
// The InstancePlaceholder is now forced to properly resolve the Node.
375
internal_created->set("reference_property", NodePath("OriginalReference"));
376
377
// Pack the main scene.
378
PackedScene *main_scene = memnew(PackedScene);
379
err = main_scene->pack(root);
380
REQUIRE(err == OK);
381
382
const String main_path = TestUtils::get_temp_path("instance_placeholder_test_main.tscn");
383
err = ResourceSaver::save(main_scene, main_path);
384
REQUIRE(err == OK);
385
386
// // Instantiate the scene.
387
Ref<PackedScene> main_scene_loaded = ResourceLoader::load(main_path, "PackedScene", ResourceFormatLoader::CacheMode::CACHE_MODE_IGNORE, &err);
388
REQUIRE(err == OK);
389
390
Node *instanced_main_node = main_scene_loaded->instantiate();
391
REQUIRE(instanced_main_node != nullptr);
392
SceneTree::get_singleton()->get_root()->add_child(instanced_main_node);
393
CHECK(instanced_main_node->get_name() == "MainNode");
394
REQUIRE(instanced_main_node->get_child_count() == 2);
395
InstancePlaceholder *instanced_placeholder = Object::cast_to<InstancePlaceholder>(instanced_main_node->get_child(0, true));
396
REQUIRE(instanced_placeholder != nullptr);
397
398
_TestInstancePlaceholderNode *final_node = Object::cast_to<_TestInstancePlaceholderNode>(instanced_placeholder->create_instance(true));
399
REQUIRE(final_node != nullptr);
400
REQUIRE(final_node->get_child_count() == 1);
401
REQUIRE(final_node->get_reference_property().identity_compare(final_node->get_child(0, true)));
402
403
instanced_main_node->queue_free();
404
memdelete(overriding);
405
memdelete(root);
406
memdelete(internal);
407
DirAccess::remove_file_or_error(internal_path);
408
DirAccess::remove_file_or_error(main_path);
409
}
410
411
TEST_CASE("[SceneTree][InstancePlaceholder] Instance a PackedScene containing an InstancePlaceholder with overrides") {
412
GDREGISTER_CLASS(_TestInstancePlaceholderNode);
413
414
// Create the internal scene.
415
_TestInstancePlaceholderNode *internal = memnew(_TestInstancePlaceholderNode);
416
internal->set_name("InternalNode");
417
Node *referenced = memnew(Node);
418
referenced->set_name("OriginalReference");
419
internal->add_child(referenced);
420
referenced->set_owner(internal);
421
internal->set_reference_property(referenced);
422
423
Node *array_ref1 = memnew(Node);
424
array_ref1->set_name("ArrayRef1");
425
internal->add_child(array_ref1);
426
array_ref1->set_owner(internal);
427
Node *array_ref2 = memnew(Node);
428
array_ref2->set_name("ArrayRef2");
429
internal->add_child(array_ref2);
430
array_ref2->set_owner(internal);
431
Array referenced_array;
432
referenced_array.set_typed(Variant::OBJECT, "Node", Variant());
433
referenced_array.push_back(array_ref1);
434
referenced_array.push_back(array_ref2);
435
internal->set_reference_array_property(referenced_array);
436
437
// Pack the internal scene.
438
PackedScene *internal_scene = memnew(PackedScene);
439
Error err = internal_scene->pack(internal);
440
REQUIRE(err == OK);
441
442
const String internal_path = TestUtils::get_temp_path("instance_placeholder_test_internal_override.tscn");
443
err = ResourceSaver::save(internal_scene, internal_path);
444
REQUIRE(err == OK);
445
446
Ref<PackedScene> internal_scene_loaded = ResourceLoader::load(internal_path, "PackedScene", ResourceFormatLoader::CacheMode::CACHE_MODE_IGNORE, &err);
447
REQUIRE(err == OK);
448
449
// Create the main scene.
450
Node *root = memnew(Node);
451
root->set_name("MainNode");
452
Node *overriding = memnew(Node);
453
overriding->set_name("OverridingReference");
454
Node *array_ext = memnew(Node);
455
array_ext->set_name("ExternalArrayMember");
456
457
_TestInstancePlaceholderNode *internal_created = Object::cast_to<_TestInstancePlaceholderNode>(internal_scene_loaded->instantiate(PackedScene::GEN_EDIT_STATE_MAIN_INHERITED));
458
internal_created->set_scene_instance_load_placeholder(true);
459
root->add_child(internal_created);
460
internal_created->set_owner(root);
461
462
root->add_child(overriding);
463
overriding->set_owner(root);
464
root->add_child(array_ext);
465
array_ext->set_owner(root);
466
// Here we introduce an error, we override the property with an internal node to the instance placeholder.
467
// The InstancePlaceholder is now forced to properly resolve the Node.
468
internal_created->set_reference_property(overriding);
469
Array internal_array = internal_created->get_reference_array_property();
470
Array override_array;
471
override_array.set_typed(Variant::OBJECT, "Node", Variant());
472
for (int i = 0; i < internal_array.size(); i++) {
473
override_array.push_back(internal_array[i]);
474
}
475
override_array.push_back(array_ext);
476
internal_created->set_reference_array_property(override_array);
477
478
// Pack the main scene.
479
PackedScene *main_scene = memnew(PackedScene);
480
err = main_scene->pack(root);
481
REQUIRE(err == OK);
482
483
const String main_path = TestUtils::get_temp_path("instance_placeholder_test_main_override.tscn");
484
err = ResourceSaver::save(main_scene, main_path);
485
REQUIRE(err == OK);
486
487
// // Instantiate the scene.
488
Ref<PackedScene> main_scene_loaded = ResourceLoader::load(main_path, "PackedScene", ResourceFormatLoader::CacheMode::CACHE_MODE_IGNORE, &err);
489
REQUIRE(err == OK);
490
491
Node *instanced_main_node = main_scene_loaded->instantiate();
492
REQUIRE(instanced_main_node != nullptr);
493
SceneTree::get_singleton()->get_root()->add_child(instanced_main_node);
494
CHECK(instanced_main_node->get_name() == "MainNode");
495
REQUIRE(instanced_main_node->get_child_count() == 3);
496
InstancePlaceholder *instanced_placeholder = Object::cast_to<InstancePlaceholder>(instanced_main_node->get_child(0, true));
497
REQUIRE(instanced_placeholder != nullptr);
498
499
_TestInstancePlaceholderNode *final_node = Object::cast_to<_TestInstancePlaceholderNode>(instanced_placeholder->create_instance(true));
500
REQUIRE(final_node != nullptr);
501
REQUIRE(final_node->get_child_count() == 3);
502
REQUIRE(final_node->get_reference_property().identity_compare(instanced_main_node->get_child(1, true)));
503
Array final_array = final_node->get_reference_array_property();
504
REQUIRE(final_array.size() == 3);
505
Array wanted_node_array = {
506
instanced_main_node->get_child(2, true), // ExternalArrayMember
507
final_node->get_child(1, true), // ArrayRef1
508
final_node->get_child(2, true) // ArrayRef2
509
};
510
511
// Iterate over all nodes, since the ordering is not guaranteed.
512
for (int i = 0; i < wanted_node_array.size(); i++) {
513
bool node_found = false;
514
for (int j = 0; j < final_array.size(); j++) {
515
if (wanted_node_array[i].identity_compare(final_array[j])) {
516
node_found = true;
517
}
518
}
519
CHECK(node_found);
520
}
521
522
instanced_main_node->queue_free();
523
memdelete(array_ext);
524
memdelete(overriding);
525
memdelete(root);
526
memdelete(internal);
527
DirAccess::remove_file_or_error(internal_path);
528
DirAccess::remove_file_or_error(main_path);
529
}
530
#endif // TOOLS_ENABLED
531
532
} //namespace TestInstancePlaceholder
533
534