What would cause <Object#null>?

Godot Version

Godot 4.3 stable

Question

So I followed this tutorial, and in it, there is a call during map generation (randomly creates maps) and it generates items.

At a later step, when you go to grab it off the ground, it calls item.get_parent().remove_child(item) to remove it from the map and put it into your inventory.

So I basically copied the code, used to generate the item at map creation, to create an item drop system for entities. I got no errors from generating the item, picking it up has no issues, and using the item, has no issues.

However, there is three problems I’ve noticed with this method. 1) The item generated is invisible on the ground. 2) If you try to drop the item from the inventory, the game crashes with an obtuse error. 3) If you go to the next floor and try to open the inventory, the game crashes with a different error.

Now, when I try to call an item created by the map, there is no issue with item.get_parent().remove_child(item). But when I try it with a monster drop, it crashes with an error. So I wanted to see what might be the issue so I did print(item.get_parent()) to see what the output was.

With a regular item its like Entity:Node#29128312319 or something. With a monster dropped item, its <Object#null>. Now when I go to create the item, it appears to acquire all the data that it should be getting, such as its texture, color/alpha value, so it should in theory be visible but it isn’t. It also has all the data for an equipment or a consumable, allowing you to use them like a normal map generated item, so clearly it received some important data.

So what would cause <Object#null> and how might I try to prevent it?

I’d post the code, but it looks like there is multiple godot scripts involved in generating the actual items, but can try to get it if you think it is important.

For now, I disabled the item drop system for monsters, so it doesn’t affect my game for now (as you still get items generated on the ground), but I do want an item drop system at some point.

What do you expect the parent to be other than null? Are the monster drop items actually added to the tree with add_child()?

Generally if a node’s parent is null, it means that node isn’t in the tree yet, or was removed.

Well, the method that the items are generated at map creation, is giving them the the class Entity (or I should say they are objects of the class Entity).

var new_entity := Entity.new(dungeon, new_entity_position, entity_key)

dungeon is the map itself, new_entity_position is a vector2i coordinate, and entity_key is the preloaded tres files, containing all the important data for the Entity.

So I copied this code, to my item generator, which was put at the stage the entity dies, right before it is removed entirely from the game.

The items created in this manner I expected to be Entity objects, as I did the whole Entity.new(…). Now I’m not sure if add_child was called, as after they are generated, they are appended to a list of entities, attached to the “dungeon” (hence why its transferred over). Looking at the search function, apparently a call to add_child is added:

func _place_entities() → void:
for entity in map_data.entities:
entity.map_data = map_data
entities.add_child(entity)

I’m not entirely sure what that does. But when I received the errors that I had gotten, it never took me to this step as being a problematic area of the codebase.

The odd thing is, calling variables or functions of the class Entity, does work, its just that anytime the parent is modified or messed with, it causes the game to crash. But I didn’t intend for the parent to removed, hence the need for answers in this thread.

Thanks for responding!

So I think I know what the issue is.

When entities are created, they are given a copy of the map_data, and each time the map is updated, they are given a fresh copy of it, so that they can make pathfinding and attack decisions based on their copy of the map. Not sure I’ll keep it that way, but that would require a large overhaul, so I’ll consider it later, but I digress.

When I created the item dropped by the entity, it uses its copy of map_data to place the item. So it gets added to that map_data. Then the entity is culled. Since the map it has is considered call by value, rather than call by reference, the item is on the map, but at the same time is in limbo. Because some of its data it relies on gets culled when the entity is removed from the game, and that likely causes some parent or a grandparent to get deleted, so it doesn’t have all the data it needs to be “stable”.

So if all I’m doing is using it as a consumable, there is no issue. But any time it requires accessing some property or function of one of the classes it is supposed to have, it crashes the game.

So that just means that for me, to get my item dropping system to work, is to return the entity’s grid position on death, to a more central part of the codebase, where the main map data is available, and place the item on that map data instead of the copied map data.

I’ll try that out later and update the thread, in case that was the proper solution.

So figured out the issue.

Turns out there are a few extra steps that are missed, which is ultimately what caused the issue. So I looked at how the code handles dropping of items from the inventory, and found 3 steps that were needed. Adding those three steps, makes the item visible and grabbable with no errors.