0 votes

As part of working out a modding framework for a game, I'm trying to replace an auto-loaded singleton with a different object instance at runtime (when a mod is loaded).

According to https://godotengine.org/qa/95097/engine-has_singleton-engine-get_singleton-behaving-expected?show=95163#a95163 , singletons are nodes on the /root node, so I tried replacing e.g. SomeSingleton as follows:

var tmpResource = ResourceLoader.load("res://my-mod/SomeSingleton.gd", "", true)
var inst = tmpResource.new()
inst.name = 'SomeSingleton'
$"/root".call_deferred('remove_child', $'/root/SomeSingleton')
$"/root".call_deferred('add_child', inst)

However, this does not affect the game's code which refers to SomeSingleton directly - it still accesses the original instance.

I tried adding

ResourceLoader.load("res://path/to/SomethingThatUsesSomeSingleton.gd", "", true)

in the subclass's _enter_tree to reload a game code file, hoping that would make it use the new $"/root/SomeSingleton" but that did not have any effect.

Godot version 3.4
in Engine by (32 points)

1 Answer

0 votes
Best answer

The solution I ended up using is to place the code (which is to replace the singleton) in the _init another singleton, placed earlier in the auto-load list. At this point, Resource.take_over_path will affect the singleton's creation.

https://gitlab.com/Delta-V-Modding/Mods/-/blob/eedfe4716020873557b63ea7dce652581de7c7c8/game/ModLoader.gd#L89-104

by (32 points)
Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read How to use this Q&A? before posting your first questions.
Social login is currently unavailable. If you've previously logged in with a Facebook or GitHub account, use the I forgot my password link in the login box to set a password for your account. If you still can't access your account, send an email to webmaster@godotengine.org with your username.