godot-proposals
godot-proposals copied to clipboard
Add a signal for when scripts reload
Describe the project you are working on
Prototyping a project. Hot reloading is great for fast iterations.
Describe the problem or limitation you are having in your project
Godot can hot reload edited scripts in both the editor and game running but there is no way to know if it happened.
I often want to call a re-init function when a script reloads but there are no signals or callbacks for this event in Script
or the various Editor interfaces and plugin extensions.
We can't get notified from outside too like catching GDScript reloads from C# and GDExtension.
Describe the feature / enhancement and how it helps to overcome the problem or limitation
Script
will emit a reloaded
signal so we can be notified.
It could be used like this:
var script = get_script() as Script
script.reloaded.connect(print.bind("%s reloaded" % script))
Describe how your proposal will work, with code, pseudo-code, mock-ups, and/or diagrams
Update: I implemented it in https://github.com/godotengine/godot/pull/91319
Emit it at the end of Script::reload
Script.reload()
can be used both at the editor and runtime so this signal shouldn't be an editor-only feature.
If this enhancement will not be used often, can it be worked around with a few lines of script?
I have to re-implement the file-watching system, dynamic source loading, and synchronization the editor already does.
Is there a reason why this should be core and not an add-on in the asset library?
There are no signals or callbacks for script reloading.
Due to reload
being an abstract virtual method internally, it looks like it will have to modify GDScript and CSharp as well for this to work.
This also requires modifying GDExtension to have it emit this.
It appears to me like the script's _static_init
gets called as part of the Script::reload. Have you tried to see if this is the case and can be used?
It's a static func, but you can find a way to get a list of instances of your script e.g. via a static var tracking the objects (add to list on _init), or through an Autoload Singleton that tracks all interesting reload events as global signals that the script listens to.
Due to
reload
being an abstract virtual method internally, it looks like it will have to modify GDScript and CSharp as well for this to work.
I don't think the C# module supports individual script reloading yet, it reloads the whole assembly so the signal will be triggered for all scripts. It also doesn't restore the previous state like in GDScript so signal connections are lost after reloading. GDExtension doesn't work like managed scripts, we can't compile a C++ class at runtime using Godot's API.
It appears to me like the script's
_static_init
gets called as part of the Script::reload. Have you tried to see if this is the case and can be used?
I didn't notice I could use _static_init
since it doesn't appear in the class reference. This could be a solution but it is called before the reloading process restores the state so static vars aren't assigned to previous values yet.
This will always print an empty array.
static var instances = []
static func _static_init() -> void:
print(instances)
func _init() -> void:
instances.append(self)
call_deferred
has the same result. It will need to depend on other scripts and extra variables as you suggested. We can't get notified from outside too without modifying the script or catching GDScript reloads from C# or GDExtension. A post-reload signal would be more convenient.
Have you tried the Resource.changed
signal? A script is a resource too.
Have you tried the
Resource.changed
signal? A script is a resource too.
That's for changes in properties, it doesn't emit on script reload which is a different process: parsing, compiling, and restoring state.