-
-
Notifications
You must be signed in to change notification settings - Fork 97
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Emit a freeing
signal when queue_free
is called on a Node
#7441
Comments
You can use the |
I see what you mean about With that said, be aware that there is a
The reason for ※1: which would require either: go over all the variables and update them, or hide the logic ※2: as when they are freed, we assume there are no variables pointing to them, barring Please notice that what we have is performant and does not hide logic. |
signal freeing
func _notification(what):
if what == NOTIFICATION_PREDELETE:
freeing.emit()
Understood, that's why a signal would enable references to be nulled by the user. To clarify, this is not a suggestion to auto-null references, but to provide a new capability for the user: _target.freeing.connect(func(): _target = null) TIL about _target.tree_exiting.connect(func(): if _target.is_queued_for_deletion(): _target = null) ... which is nearly as good as a |
Sure it can be seen as an anti-pattern, but having multiple references to a non-refcounted type isn't really recommended, I don't see adding a signal to handle this over just using Having this check is a bit of a luxury tbh, there's no equivalent in c++ and there's no safe way to check if a non-null pointer points to valid memory or not |
I'm not sure that comparing Godot to C++ is useful, since of course Godot's value proposition is operating at a much higher level of abstraction than C++. By definition, it offers "luxuries" that C++ doesn't have.
What is the alternative in Godot for nodes that need to interact with one another? I'd like to use whatever the recommended pattern is here, but I haven't seen any recommendation documented anywhere. |
Using I'd say that if you aren't able to make sure that your references are tracked clearly, by making sure you do the freeing with clear intent I don't see the value in adding new signals, which reduces performance, to handle usage that isn't IMO recommended, emitting signals isn't free |
Yes, this is the purpose of the Do you have another mechanism in mind for clearing references whenever something is freed, in a system that has no "freeing" signal to listen to? |
Have what ever mechanisms calls the freeing also perform this, since you're suggesting a new method anyway that won't be fired by the general freeing, which deals with the performance, but then you're already making the manual decision so you can just work around this instead, for these cases (that most users won't be dealing with AFAIK) |
Searching for answers to the issue has led me to dozens of people posting about the same problem, all seemingly looking for a good solution from godot: https://www.reddit.com/r/godot/comments/s6g1mw/psa_question_use_is_instance_valid_instead_of/ ...but if it's not a priority, I will continue to work around it as I'm already doing. This was just a suggestion for a general-purpose solution. |
Well the solution is |
I have been warned away from |
It ensures that the pointer is valid and points to the same pointer, so it would require an extremely unlikely event, i.e. the |
See godotengine/godot#36189 for Godot 4, and godotengine/godot#51796 for Godot 3. |
I support this proposal because such cases exist: node.freeing.connect(func():
if xxx:
node.cancel_free()
) The point is that sometimes the freeing node doesn't have a script in which we can add some code like: func _notification(what):
if what == NOTIFICATION_PREDELETE:
cancel_free() or even if we can attach a script to this script only to add such code above, it's too heavy and clumsy. |
One example is void SceneReplicationInterface::_free_remotes(const PeerInfo &p_info) {
for (const KeyValue<uint32_t, ObjectID> &E : p_info.recv_nodes) {
Node *node = tracked_nodes.has(E.value) ? get_id_as<Node>(E.value) : nullptr;
ERR_CONTINUE(!node);
node->queue_free();
}
} Currently func _notification(what):
if what == NOTIFICATION_PREDELETE:
if xxxx: # user's choice whether to retain this node
cancel_free() I'm working on a multiplayer add-on to simplify multiplayer playing, so it's unacceptable that users must add these codes to their spawnabel scenes. If there is a freeing signal, the cancel_free() code can achieved within the scope of the add-on. |
Describe the project you are working on
A 2D game with large, procedurally-generated levels with lots of entities being spawned, added, removed, re-added, & freed over the lifetime of each top-level scene.
Describe the problem or limitation you are having in your project
Many nodes create dynamic references to other nodes in the game. For example:
The referenced nodes may be freed. Enemies, Wielders, and Items can all be destroyed. They can also be removed from the scene tree temporarily, and moved to other locations in the scene tree.
Initially, this led to runtime crashes when I tried to work with the original references. I patched that with
is_instance_valid
, but that's unreliable and can leave things in a weird state. I checked for a Node signal that I could listen to instead, but the closest one -tree_exiting
- sends false-positives:So, I've ended up adding this everywhere:
Describe the feature / enhancement and how it helps to overcome the problem or limitation
Add a
freeing
signal toNode
s that will fill the gap. In addition to this specific use case, it would generally allow developers to stop leaning onis_instance_valid()
, which is a slow anti-pattern.Describe how your proposal will work, with code, pseudo-code, mock-ups, and/or diagrams
It would be used by the nodes that hold references to potentially-freed objects, like:
If this enhancement will not be used often, can it be worked around with a few lines of script?
Given how commonly this is asked about on discord/reddit/Q&A/stackoverflow/etc, I expect it will be used often. Godot doesn't really have a canonical answer for dealing with freed nodes, and
is_instance_valid
is a bandaid.Is there a reason why this should be core and not an add-on in the asset library?
Design-wise, it's a corollary to the
queue_free
method defined on Node. The signal that a behavior is about to occur should be defined alongside the behavior.The text was updated successfully, but these errors were encountered: