I implemented a spawner class that is supposed to spawn mobs in a level in my game. One of the exported variables is the PackedScene to be spawned by the spawner. I also wanted to add a check whether the set PackedScene is of a certain type, so the users would get a warning icon in their editor if they set the wrong PackedScene. In order to do that, I need to get information on the class_name type of the script of the root node of the PackedScene which I would then want to check if it extends my Mobclass_name.
Is there a good general way to do this?
I’ve tried using the packed_scene.get_state().get_node_type(0) but that returns the native type (e.g. CharacterBody2D) not the type of the script attached to the node.
I also tried using groups and packed_scene.get_state().get_node_groups(0), but that doesn’t work for scenes that inherited the Mob scene., in which case I need to use packed_scene.get_state().get_node_instance(0).get_state().get_node_groups(0). Now, I can work with this option for now, but it feels quite hacky. Is there a better way to do this?
@wyattbiker While that’s good to know, I don’t know how I would get the script of the root node in the PackedScene (at least not without instancing it, which I don’t want to do here). Would you happen to know how I can do that?
If so, then this would be the complete solution.
Try this. First line gets the top node in your scene. Second line gets the script. If no class_name then it gets the top node of scene name:
# Get top scene node
var current_scene=get_tree().get_current_scene()
# Get script attached to it
var o_script=current_scene.get_script()
# Get the class_name r if nill get node name
var s_class_name:StringName=o_script.get_global_name()
print(s_class_name)
But if you have to instance the scene then you only need to add an ID string property with the name or ostensibly, just do a type check if my_scene_instance is MyClass.
(the way I read it) OP is asking how to tell if the scene is the desired type when a user drags a scene into the export variable (inside a tool script).
It doesn’t seem possible without instancing it at least once.
@wyattbiker @sancho2 is correct. I’m talking about the case when I don’t have a scene instance, but a PackedScene set by the user in editor and I’d like to do a check before I do any instancing.
I think I figured out a solution, but I’m not 100% sure of how stable it is. It assumes that the root node is always at index 0 in the packed scene and its potentially added script is the first property of the node. It does seem quite reasonable to me though.
@tool
extends EditorResourcePicker
class_name GridNodePicker
const SCENE_ROOT_TYPE: String = "GridNode"
func _ready() -> void:
base_type = "PackedScene"
toggle_mode = true
func is_valid(resource: Resource) -> bool:
if resource is PackedScene:
var scene: PackedScene = resource
var root_script_raw: Variant = scene.get_state().get_node_property_value(0, 0)
if root_script_raw is Script:
return root_script_raw.get_global_name() == SCENE_ROOT_TYPE
return false
Note that in this use case the editor resource picker doesn’t filter the packed scenes automatically, but if is_valid called with the selected resource will say if the root node of the selected scene has an attached scripted with the expected class_name
The way I read the original post is that it must work with inherited scenes.
Did you test this with scenes that inherit from another and don’t have their own script?
I don’t think it will work as it requires the first property to be the external resource line similar to this one: [ext_resource type="Script" uid="uid://bwmku332ymqud" path="res://Inventory/item_ui.gd" id="1_11i0j"]
Whereas an inherited scene will not have that line. Instead its first property will link to the parent scene: [ext_resource type="PackedScene" uid="uid://csrlcv4q6068y" path="res://Inventory/item_ui.tscn" id="1_0lddw"]
However, I did not test this fully so I may be off base.