Files
MovementTests/addons/guide/editor/class_scanner.gd
2025-05-27 19:20:46 +02:00

92 lines
2.6 KiB
GDScript

## Scanner to find inheriting classes. Used to detect inheritors of
## modifiers and triggers. Ideally this would be built into the editor
## but sometimes one has to hack their way around the limitations.
## This only scans to the extent needed to drive the UI, it's not a general
## purpose implementation.
@tool
const GUIDESet = preload("../guide_set.gd")
var _dirty:bool = true
# looks like we only get very limited access to the script's inheritance tree,
# so we need to do a little caching ourselves
var _script_lut:Dictionary = {}
func _init():
EditorInterface.get_resource_filesystem().script_classes_updated.connect(_mark_dirty)
func _mark_dirty():
_dirty = true
## Returns all classes that directly or indirectly inherit from the
## given class. Only works for scripts in the project, e.g. doesn't
## scan the whole class_db. Key is class name, value is the Script instance
func find_inheritors(clazz_name:StringName) -> Dictionary:
var result:Dictionary = {}
var root := EditorInterface.get_resource_filesystem().get_filesystem()
# rebuild the LUT when needed
if _dirty:
_script_lut.clear()
_scan(root)
_dirty = false
var open_set:GUIDESet = GUIDESet.new()
# a closed set just to avoid infinite loops, we'll never
# look at the same class more than once.
var closed_set:GUIDESet = GUIDESet.new()
open_set.add(clazz_name)
while not open_set.is_empty():
var next = open_set.pull()
closed_set.add(next)
if not _script_lut.has(next):
# we don't know this script, ignore, move on
continue
# now find all scripts that extend the one we
# are looking at
for item:ScriptInfo in _script_lut.values():
if item.extendz == next:
# put them into the result
result[item.clazz_name] = item.clazz_script
# and put their class in the open set
# unless we already looked at it.
if not closed_set.has(item.clazz_name):
open_set.add(item.clazz_name)
return result
func _scan(folder:EditorFileSystemDirectory):
for i in folder.get_file_count():
var script_clazz = folder.get_file_script_class_name(i)
if script_clazz != "":
var info := _script_lut.get(script_clazz)
if info == null:
info = ScriptInfo.new()
info.clazz_name = script_clazz
info.clazz_script = ResourceLoader.load(folder.get_file_path(i))
_script_lut[script_clazz] = info
var script_extendz = folder.get_file_script_class_extends(i)
info.extendz = script_extendz
for i in folder.get_subdir_count():
_scan(folder.get_subdir(i))
class ScriptInfo:
var clazz_name:StringName
var extendz:StringName
var clazz_script:Script
func _to_string() -> String:
return clazz_name + ":" + extendz