Add child not working in what should be a functionally exact same script

I’ve made a room script for my procedural dungeon and then duplicated the scene and made some changes but everything broke. I don’t know why because everything should be functionally the same. Here’s the working code:

extends spawner

var triggered = false

var connectingrooms : Array[PackedScene] = [
	preload("res://scenes/Room Manager/Rooms/Test Room.tscn"),
	preload("res://scenes/Room Manager/Rooms/Test Corridor.tscn")
]
var spawnDoors := false
func _ready() -> void:
	print("added to scene")
	$"../Doors".position.y -= 10
	print($"../Doors".position.y)
func _process(_delta: float) -> void:
	if get_child_count() == 0 && get_parent().has_node("Doors") && triggered && !spawnDoors:
		spawnDoors = true
		for i in range($"../Doors".get_child_count()):
			var doorchild : CSGBox3D = $"../Doors".get_child(i)
			var roominst : Node3D = connectingrooms[randi_range(0, connectingrooms.size() - 1)].instantiate()
			get_parent().get_parent().add_child(roominst)
			var t := doorchild.global_transform
			t.origin -= t.basis.y * (doorchild.size.y * 0.5)
			roominst.global_transform = t
			print(roominst.global_position)
		$"../Doors".queue_free()


func _on_player_enter_area_body_entered(_body: Node3D) -> void:
	if !triggered:
		super.createenemies()
		DungeonMain.currentroom = self
		$"../Doors".position.y += 10
		triggered = true

and the broken:

extends spawner

var triggered = false

var connectingrooms : Array = [
	preload("res://scenes/Room Manager/Rooms/Test Room.tscn"),
]
var spawnDoors := false
func _ready() -> void:
	print("added to scene")
	$"../Doors".position.y -= 10
	print($"../Doors".position.y)
func _process(_delta: float) -> void:
	if get_parent().has_node("Doors") && triggered && !spawnDoors:
		spawnDoors = true
		for i in range($"../Doors".get_child_count()):
			var doorchild : CSGBox3D = $"../Doors".get_child(i)
			var roominst : Node3D = connectingrooms[randi_range(0, connectingrooms.size() - 1)].instantiate()
			get_parent().get_parent().add_child(roominst)
			var t := doorchild.global_transform
			t.origin -= t.basis.y * (doorchild.size.y * 0.5)
			roominst.global_transform = t
			print(roominst.global_position)
		$"../Doors".queue_free()


func _on_player_enter_area_body_entered(_body: Node3D) -> void:
	if !triggered:
		DungeonMain.currentroom = self
		triggered = true

all extending spawner does is let it super spawn enemies so it can… spawn enemies.
The issue I’m getting is:
E 0:00:03:561 Test Corridor.gd:18 @ _process(): Failed to instantiate scene state of “”, node count is 0. Make sure the PackedScene resource is valid.
<C++ Error> Condition “nc == 0” is true. Returning: nullptr
<C++ Source> scene/resources/packed_scene.cpp:142 @ instantiate()
Test Corridor.gd:18 @ _process()
and then a few more as a result of add child not working.

it seems like the packedscene-resource is corrupted. Can you try to open the “Test Room.tscn” in the editor?

Yeah, the test room works just fine, it’s when the test corridor tries to instantiate something that it crashes

Why is spawner script called “Test Corridor.gd”?

Probably nor related to this, but don’t have spaces in file or folder names.

Just one of the many habits I developed from leading GdDcript from tutorials of random things rather than a more structured reading of the docs

This is a shameful bump since I can’t figure out the solution and I don’t want this topic to get lost

I presume this is the offending line.
It is incredibly difficult to debug code that uses random numbers. Until your code is working start with known numbers. In this case simply using seed(n) will still give you random numbers but they will be the same random numbers every run.
Dismember the quoted line and check what you have.

func _ready()->void:
   seed(1)
func _process(_delta:float)->void:  
   ...
   print(connectingrooms)
   var n:int = randi_range(0, connectingrooms.size()-1) 
   print(n)
   var roominst:Node3D = connectingrooms[n].instantiate()  
   print(roominst)

print(get_parent().get_parent())

Test corridor still has the same issues with the index set to always be zero in case that’s the issue. When I do super create enemies it works fine oddly but this is the create enemies code:

extends Node

class_name spawner

var flyingenemy := preload("res://scenes/enemies/enemy.tscn")
var explosiveguy := preload("res://scenes/enemies/explosive_guy.tscn")
var golem := preload("res://scenes/enemies/golem.tscn")
var bomber := preload("res://scenes/enemies/bomber.tscn")
var basicenemy := preload("res://scenes/enemies/basic_enemy.tscn")
var turret := preload("res://scenes/enemies/turret.tscn")

@export var roomx : float
@export var roomz : float
@export var roomy : float

@export var Enemies : Array[PackedScene] = [
flyingenemy,
explosiveguy,
golem,
bomber,
basicenemy,
turret,
]

func createenemies() -> void:
	for i in range(randi_range(2, 4)):
		var enemyIndex = randi_range(0, Enemies.size() - 1)
		while  enemyIndex == 0 && has_node("enemy"):
			enemyIndex = randi_range(0, Enemies.size() - 1)
		spawnEnemy(enemyIndex)
		if Enemies[enemyIndex] == turret:
			i -= 1

func spawnEnemy(enemyIndex: int):
	if Enemies[enemyIndex] == flyingenemy:
		var enemySpawn : Node3D = Enemies[enemyIndex].instantiate()
		add_child(enemySpawn)
		enemySpawn.position = Vector3(randf_range(-roomx, roomx), randf_range(2, 4), randf_range(-roomz, roomz))
	elif Enemies[enemyIndex] == explosiveguy:
		var enemySpawn : Node3D = Enemies[enemyIndex].instantiate()
		add_child(enemySpawn)
		enemySpawn.position = Vector3(randf_range(-roomx, roomx), roomy, randf_range(-roomz, roomz))
	elif Enemies[enemyIndex] == golem:
		var position_chosen :Vector3 = Vector3(randf_range(-roomx, roomx), roomy, randf_range(-roomz, roomz))
		for i in range(randi_range(1, 3)):
			var enemySpawn : Node3D = Enemies[enemyIndex].instantiate()
			add_child(enemySpawn)
			enemySpawn.position = position_chosen + Vector3(randf_range(-7, 7), roomy, randf_range(-7, 7))
	elif Enemies[enemyIndex] == bomber:
		var enemySpawn : Node3D = Enemies[enemyIndex].instantiate()
		add_child(enemySpawn)
		enemySpawn.position = Vector3(randf_range(-roomx, roomx), 4, randf_range(-roomz, roomz))
	elif Enemies[enemyIndex] == basicenemy:
		var position_chosen :Vector3 = Vector3(randf_range(-roomx, roomx), roomy, randf_range(-roomz, roomz))

		for i in range(randi_range(3, 6)):
			var enemySpawn : Node3D = Enemies[enemyIndex].instantiate()
			add_child(enemySpawn)
			enemySpawn.position = position_chosen + Vector3(randf_range(-7, 7), roomy, randf_range(-7, 7))
	elif Enemies[enemyIndex] == turret:
		var enemySpawn : Node3D = Enemies[enemyIndex].instantiate()
		add_child(enemySpawn)
		enemySpawn.position = Vector3(randf_range(-roomx, roomx), roomy, randf_range(-roomz, roomz))

Yes, I know more random numbers, sorry if that makes your life more difficult but all it’s spawning is just the basic enemy. All it should do is add children to the node to delay the spawning of the room in the test room (not corridor).

Edit: Supering create enemies fixes it kind of. It crashes when creating the room still, it’s just delayed when it does it.

I know that it has to do with the add child or instantiating. When just instantiating a preload of Test Room it still has the same error but t isn’t null and neither is get_parent().get_parent()

Edit:
$“../Doors”.get_child(i) is normal
room inst is null.
Another Edit:
The procedure for creating this was taking the Test Room .tscn file then duplicating it and making changes.

what changes did you make?

I changed the room dimensions, removed the superc of spawn enemies, and that’s pretty much it.

can you open this Test Room.tscn in a text editor and post the content here?

Can you post a minimal reproduction project?

I don’t really have the time to make a mrp but I can get the script files. There shouldn’t be a bug in the code since It’s directly copied over from a working version but missing two lines that don’t break the working one and the issue shouldn’t be some corruption since I recreated the scene and it has the same error.

this is the broken node

[gd_scene load_steps=10 format=3 uid="uid://dxno8t5j2l1dx"]

[ext_resource type="Script" uid="uid://b73swtldn0ut5" path="res://Nodes/Room.gd" id="1_jqgls"]
[ext_resource type="Texture2D" uid="uid://bnql1rv5vvqnb" path="res://Unused/PlaceHolderGround.png" id="2_xiibo"]
[ext_resource type="Script" uid="uid://61ptvs4q0n3t" path="res://scripts/Dungeons/Rooms/Test Corridor.gd" id="3_ugk4v"]

[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_uw1xy"]
albedo_texture = ExtResource("2_xiibo")

[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_1w1h1"]
albedo_texture = ExtResource("2_xiibo")

[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_m2h87"]
albedo_texture = ExtResource("2_xiibo")

[sub_resource type="Environment" id="Environment_1qyfn"]
ambient_light_source = 3
ambient_light_color = Color(1, 1, 1, 1)
ambient_light_sky_contribution = 0.4

[sub_resource type="BoxShape3D" id="BoxShape3D_77aqr"]
size = Vector3(37, 10, 60)

[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_yd6f3"]
albedo_texture = ExtResource("2_xiibo")

[node name="Test Corridor" type="Node3D"]
script = ExtResource("1_jqgls")
metadata/_custom_type_script = "uid://b73swtldn0ut5"

[node name="Floor" type="CSGBox3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 30)
material_override = SubResource("StandardMaterial3D_uw1xy")
use_collision = true
collision_layer = 98
collision_mask = 0
size = Vector3(40, 1, 60)

[node name="Celing" type="CSGBox3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 10, 30)
material_override = SubResource("StandardMaterial3D_1w1h1")
use_collision = true
collision_layer = 98
collision_mask = 0
size = Vector3(40, 1, 60)

[node name="Right" type="CSGPolygon3D" parent="."]
transform = Transform3D(0.0017619767, -0.0014222914, -0.9999974, 0.0019184909, 0.99999714, -0.0014189038, 0.9999966, -0.0019159808, 0.001764706, 19, -0.019, 0.0020008087)
material_override = SubResource("StandardMaterial3D_m2h87")
use_collision = true
collision_layer = 98
collision_mask = 0
polygon = PackedVector2Array(0, 0, 0, 0, 0, 10, 60, 10, 60, 0, 23, 0, 23, 6, 17, 6, 17, 0)

[node name="Left" type="CSGPolygon3D" parent="."]
transform = Transform3D(0.0017619767, -0.0014222914, -0.9999974, 0.0019184909, 0.99999714, -0.0014189038, 0.9999966, -0.0019159808, 0.001764706, -20, 0, 0)
material_override = SubResource("StandardMaterial3D_m2h87")
use_collision = true
collision_layer = 98
collision_mask = 0
polygon = PackedVector2Array(0, 0, 0, 0, 0, 10, 60, 10, 60, 0, 23, 0, 23, 6, 17, 6, 17, 0)

[node name="Front" type="CSGPolygon3D" parent="."]
transform = Transform3D(-1, 0, 8.742278e-08, 0, 1, 0, -8.742278e-08, 0, -1, 20, 0, 0)
material_override = SubResource("StandardMaterial3D_m2h87")
use_collision = true
collision_layer = 98
collision_mask = 0
polygon = PackedVector2Array(0, 0, 0, 0, 0, 40, 40, 40, 40, 0, 23, 0, 23, 6, 17, 6, 17, 0)

[node name="Back" type="CSGPolygon3D" parent="."]
transform = Transform3D(-1, 0, 8.742278e-08, 0, 1, 0, -8.742278e-08, 0, -1, 20, 0, 59)
material_override = SubResource("StandardMaterial3D_m2h87")
use_collision = true
collision_layer = 98
collision_mask = 0
polygon = PackedVector2Array(0, 0, 0, 0, 0, 40, 40, 40, 40, 0, 23, 0, 23, 6, 17, 6, 17, 0)

[node name="Node" type="Node3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 30)
script = ExtResource("3_ugk4v")

[node name="WorldEnvironment" type="WorldEnvironment" parent="."]
environment = SubResource("Environment_1qyfn")

[node name="PlayerEnterArea" type="Area3D" parent="."]
collision_layer = 0
monitorable = false

[node name="CollisionShape3D" type="CollisionShape3D" parent="PlayerEnterArea"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 5, 30)
shape = SubResource("BoxShape3D_77aqr")

[node name="Doors" type="Node3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 20)

[node name="frontDoor" type="CSGBox3D" parent="Doors"]
transform = Transform3D(0.99999994, 0, 0, 0, 1, 0, 0, 0, 1, 0, 3, 40)
material_override = SubResource("StandardMaterial3D_yd6f3")
use_collision = true
collision_layer = 98
collision_mask = 0
size = Vector3(6, 6, 1)

[node name="backDoor" type="CSGBox3D" parent="Doors"]
transform = Transform3D(-0.99999994, 0, -8.742278e-08, 0, 1, 0, 8.742277e-08, 0, -1, 0, 3, -20)
material_override = SubResource("StandardMaterial3D_yd6f3")
use_collision = true
collision_layer = 98
collision_mask = 0
size = Vector3(6, 6, 1)

[node name="rightDoor" type="CSGBox3D" parent="Doors"]
transform = Transform3D(1.1924879e-08, 0, -0.99999994, 0, 1, 0, 0.9999999, 0, 1.192488e-08, -20, 3, 0)
material_override = SubResource("StandardMaterial3D_yd6f3")
use_collision = true
collision_layer = 98
collision_mask = 0
size = Vector3(6, 6, 1)

[node name="leftDoor" type="CSGBox3D" parent="Doors"]
transform = Transform3D(-4.3711385e-08, 0, 0.99999994, 0, 1, 0, -0.9999999, 0, -4.3711385e-08, 20, 3, 0)
material_override = SubResource("StandardMaterial3D_yd6f3")
use_collision = true
collision_layer = 98
collision_mask = 0
size = Vector3(6, 6, 1)

[connection signal="body_entered" from="PlayerEnterArea" to="Node" method="_on_player_enter_area_body_entered"]

and this is the functional one

[gd_scene load_steps=11 format=3 uid="uid://c1hr1d1g6okh3"]

[ext_resource type="Texture2D" uid="uid://bnql1rv5vvqnb" path="res://Unused/PlaceHolderGround.png" id="1_1qyfn"]
[ext_resource type="Script" uid="uid://2oneuih4konu" path="res://scripts/Dungeons/Rooms/Test Room.gd" id="1_iqmsk"]
[ext_resource type="Script" uid="uid://b73swtldn0ut5" path="res://Nodes/Room.gd" id="1_uw1xy"]
[ext_resource type="PackedScene" uid="uid://bkumq8svryca6" path="res://scenes/enemies/basic_enemy.tscn" id="2_ifw3u"]

[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_uw1xy"]
albedo_texture = ExtResource("1_1qyfn")

[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_1w1h1"]
albedo_texture = ExtResource("1_1qyfn")

[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_m2h87"]
albedo_texture = ExtResource("1_1qyfn")

[sub_resource type="Environment" id="Environment_1qyfn"]
ambient_light_source = 3
ambient_light_color = Color(1, 1, 1, 1)
ambient_light_sky_contribution = 0.4

[sub_resource type="BoxShape3D" id="BoxShape3D_77aqr"]
size = Vector3(37, 40, 37)

[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_yd6f3"]
albedo_texture = ExtResource("1_1qyfn")

[node name="Test Room" type="Node3D"]
script = ExtResource("1_uw1xy")
metadata/_custom_type_script = "uid://b73swtldn0ut5"

[node name="Floor" type="CSGBox3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 20)
material_override = SubResource("StandardMaterial3D_uw1xy")
use_collision = true
collision_layer = 98
collision_mask = 0
size = Vector3(40, 1, 40)

[node name="Celing" type="CSGBox3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 40, 20)
material_override = SubResource("StandardMaterial3D_1w1h1")
use_collision = true
collision_layer = 98
collision_mask = 0
size = Vector3(40, 1, 40)

[node name="Left" type="CSGPolygon3D" parent="."]
transform = Transform3D(-4.371139e-08, 0, -1, 0, 1, 0, 1, 0, -4.371139e-08, -20, 0, 0)
material_override = SubResource("StandardMaterial3D_m2h87")
use_collision = true
collision_layer = 98
collision_mask = 0
polygon = PackedVector2Array(0, 0, 0, 0, 0, 40, 40, 40, 40, 0, 23, 0, 23, 6, 17, 6, 17, 0)

[node name="Right" type="CSGPolygon3D" parent="."]
transform = Transform3D(0.0017619767, -0.0014222914, -0.9999974, 0.0019184909, 0.99999714, -0.0014189038, 0.9999966, -0.0019159808, 0.001764706, 19, -0.019, 0.0020008087)
material_override = SubResource("StandardMaterial3D_m2h87")
use_collision = true
collision_layer = 98
collision_mask = 0
polygon = PackedVector2Array(0, 0, 0, 0, 0, 40, 40, 40, 40, 0, 23, 0, 23, 6, 17, 6, 17, 0)

[node name="Front" type="CSGPolygon3D" parent="."]
transform = Transform3D(-1, 0, 8.742278e-08, 0, 1, 0, -8.742278e-08, 0, -1, 20, 0, 0)
material_override = SubResource("StandardMaterial3D_m2h87")
use_collision = true
collision_layer = 98
collision_mask = 0
polygon = PackedVector2Array(0, 0, 0, 0, 0, 40, 40, 40, 40, 0, 23, 0, 23, 6, 17, 6, 17, 0)

[node name="Back" type="CSGPolygon3D" parent="."]
transform = Transform3D(-1, 0, 8.742278e-08, 0, 1, 0, -8.742278e-08, 0, -1, 20, 0, 39)
material_override = SubResource("StandardMaterial3D_m2h87")
use_collision = true
collision_layer = 98
collision_mask = 0
polygon = PackedVector2Array(0, 0, 0, 0, 0, 40, 40, 40, 40, 0, 23, 0, 23, 6, 17, 6, 17, 0)

[node name="Node" type="Node3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 20)
script = ExtResource("1_iqmsk")
roomx = 10.0
roomz = 10.0
roomy = 1.0
Enemies = [ExtResource("2_ifw3u")]

[node name="WorldEnvironment" type="WorldEnvironment" parent="."]
environment = SubResource("Environment_1qyfn")

[node name="PlayerEnterArea" type="Area3D" parent="."]
collision_layer = 0
monitorable = false

[node name="CollisionShape3D" type="CollisionShape3D" parent="PlayerEnterArea"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 20, 20)
shape = SubResource("BoxShape3D_77aqr")

[node name="Doors" type="Node3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 20)

[node name="frontDoor" type="CSGBox3D" parent="Doors"]
transform = Transform3D(0.99999994, 0, 0, 0, 1, 0, 0, 0, 1, 0, 3, 20)
material_override = SubResource("StandardMaterial3D_yd6f3")
use_collision = true
collision_layer = 98
collision_mask = 0
size = Vector3(6, 6, 1)

[node name="backDoor" type="CSGBox3D" parent="Doors"]
transform = Transform3D(-0.99999994, 0, -8.742278e-08, 0, 1, 0, 8.742277e-08, 0, -1, 0, 3, -20)
material_override = SubResource("StandardMaterial3D_yd6f3")
use_collision = true
collision_layer = 98
collision_mask = 0
size = Vector3(6, 6, 1)

[node name="rightDoor" type="CSGBox3D" parent="Doors"]
transform = Transform3D(1.1924879e-08, 0, -0.99999994, 0, 1, 0, 0.9999999, 0, 1.192488e-08, -20, 3, 0)
material_override = SubResource("StandardMaterial3D_yd6f3")
use_collision = true
collision_layer = 98
collision_mask = 0
size = Vector3(6, 6, 1)

[node name="leftDoor" type="CSGBox3D" parent="Doors"]
transform = Transform3D(-4.3711385e-08, 0, 0.99999994, 0, 1, 0, -0.9999999, 0, -4.3711385e-08, 20, 3, 0)
material_override = SubResource("StandardMaterial3D_yd6f3")
use_collision = true
collision_layer = 98
collision_mask = 0
size = Vector3(6, 6, 1)

[connection signal="body_entered" from="PlayerEnterArea" to="Node" method="_on_player_enter_area_body_entered"]

this is the root node that they are all added to

[gd_scene load_steps=4 format=3 uid="uid://c8ycmhw2c01u4"]

[ext_resource type="Script" uid="uid://yltwto3k78jp" path="res://scripts/Dungeons/dungeon_main.gd" id="1_u13jm"]
[ext_resource type="PackedScene" uid="uid://c1hr1d1g6okh3" path="res://scenes/Room Manager/Rooms/Test Room.tscn" id="2_52bp2"]
[ext_resource type="PackedScene" uid="uid://cld0n5ymrtut1" path="res://scenes/player/player.tscn" id="3_crfio"]

[node name="Dungeon Main" type="Node3D"]
script = ExtResource("1_u13jm")

[node name="Test Room" parent="." instance=ExtResource("2_52bp2")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -20)

[node name="Player" parent="." instance=ExtResource("3_crfio")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.48966694, 1.45, 1.7631502)

Are Test Corridor and Test Room trying to preload each other? The error message looks like the typical cyclical reference issue.

1 Like

What would that look like? I’ve attached the code is what I’m doing and I don’t think so.

The broken script you shared contains preload("res://scenes/Room Manager/Rooms/Test Room.tscn"). So the question is, what preloads are in the scripts of “Test Room.tscn”? (“Room.gd” and “Test Room.gd”, I assume?) Is the broken scene (=“Test Corridor.tscn”?) among their preloads?

As soon as two scenes try to preload the other in any of their scripts, you have a cyclical reference. In that case, instantiating one of those scenes in the other might work in one direction, but not in both. Using load instead of preload should prevent the error, but it’s usually a reason to reconsider how the scenes are structured.

switching to load did fix the issue but I’m just curious about what that issue is. Test Room preloads another test room and test corridor while test corridor preloads test room. Room manager just loops over and deletes where the player isn’t actively and to know what’s supposed to be deleted in that purge I mark some of the nodes as rooms. I do that through Room.gd which is just a class_name.