Godot Version
4.6.2 Stable
Question
And so, the essence of the error is stated in the title - when testing the game, it periodically just freezes forever, without reporting any recursion errors or anything like that. The problem is that the game I’m working on is very, very complex (it’s kind of a mix of Kenshi and Terraria) so actually, I can’t provide any code, because I have no idea which of the code snippets of the codebase itself is causing the error (there are currently 36.000 lines of code in the project) - just the Gdscript. I suspect that the error has something to do with the UI and the recalculation of Control’s sizes and containers, since the UI in the game is complex and it looks like the problem appeared somewhere at the stage of adding its ui logic, but since it is impossible to debug the problem, I actually do not know what exactly I should fix.
Therefore, my question down to the following: is there a way to constantly monitor the processes taking place inside the game so that, in the event of an infinity freeze, I can see in some third-party analyzer the current task that the game is trying to complete?
UPD:
Okay, it seems to be related to the fact that Godot cannot handle a reference to a node that has already been free. The problem occurs when I iterate over objects in an array where the object may already have been freed using queue_free() and is therefore null. When I attempt to interact with such an array element, the game freezes indefinitely without any errors. Even a simple check like (if obj == null) causes the game to freeze (after removing the check, I instantly received an error about a previously freed object). I don’t know if this is the right thing to do, and I might have made a mistake somewhere, but it’s confusing me.
Basically, here’s what’s happening:
- I have a Thing (Sprite2D) object that’s being added to the world. It’s also being added to the object_pool array for the TileData of the nearest tile (TileData is a Resource)
- Removing the Thing via queue_free() without manually removing it from the tile’s object_pool results in a reference to the previous free null remaining in the object_pool.
- When iterating through the array elements, any attempt to interact with this null causes an infinite loop for some reason. For example, I originally did is_instance_valid(obj) and it caused a hang. However, even a simple if obj == null is sufficient.
- If I remove any checks and directly interact with the object, I get the error previous free object.
The solution is obviously to manually remove the object from the object_pool, but I’m curious about the reason for the freeze.
Here’s more information.
1.The player interacts with the object:
func execute_use(obj : ThingBody):
var user = Cursor.tile_core.control_entity
if obj.thing and user:
await obj.thing.execute_modules(user,obj)
-
In Item module i call destroy object
func execute_action(user : EntityBody, body : ThingBody): if not user or not user.entity or not body.thing or not item: return var inv = user.entity.inventory_core if not inv: return if inv.add_item(InventoryCore.GET_TYPE.STASH_CORE, item): body.thing_free() -
In ThingBody i destory object:
# Destroy func thing_free(): if thing: if thing.on_tiles_dict.size() > 0: for tile: TileWorldData in thing.on_tiles_dict.keys(): tile.remove_thing(thing) #tile.objects_pool.erase(self) # Here problem fix var sec_data = Cursor.location_manager.sector_data if sec_data: sec_data.remove_thing(thing) if Cursor.hovered_thing == thing: Cursor.hovered_thing = null queue_free()
As you can see, I have commented out the line with object_pool. If I do this, the object_pool will retain a reference to this object. In this case, checking in this method will cause an eternal freeze without eny errors:
# 4. Objects
if !tile.objects_pool.is_empty():
for obj in tile.objects_pool:
var ref = weakref(obj)
var instance = ref.get_ref()
if instance == null:
continue
if !instance.thing:
continue
var thing_ref = weakref(instance.thing)
var thing = thing_ref.get_ref()
if thing == null:
continue
var n_obj_button: Button = object_button_prefub.instantiate()
n_obj_button.icon = ResourceGod.get_object_list_icon("thing")
n_obj_button.text = thing.t_name
object_list_holder.add_child(n_obj_button)
if !n_obj_button.pressed.is_connected(select_object_from_list):
n_obj_button.pressed.connect(select_object_from_list.bind(n_obj_button, instance, {"name": n_obj_button.text}))
At the same time, the freeze occurs on this line. The ref itself exists, but it is empty and does not have a script.
var instance = ref.get_ref()
You can also see all these weakref things that I added just to try to fix the error. In fact, the error occurred even without creating any weakrefs when trying to access the object (so that no one gets confused)


