+1 vote

I often have a situation when bot shoot to another bot and then died when bullet is flied still. But then, after bot was removed from scene by queue_free, bullet can hit some bot and try to access pointer that points to died bot (each bullet has pointer to shooter).

So, is it possible to check that pointer is not valid anymore?

Godot version 3.2.3
in Engine by (246 points)

There is a function in GDScript called, isqueuedfor_deletion().
Check if there is a GDNative equivalent function.

No, this function will not work in this case, because object can be deleted a long time ago but something still has pointer to it that is not valid. So, calling isqueuedfor_deleting will cause the crash.

I solved this problem, I'll add answer

1 Answer

0 votes
Best answer

I solved this problem by replacing all pointers by instance_id.

Then, I added a manager that returns pointer by instance_id if object is still alive or nullptr if not.

Now, everything works excellent

// SceneObjectsManager.h
#pragma once

#include "Core/Types.h"
#include "GameAgent.h"

#include <Dictionary.hpp>
#include <Node.hpp>

class SceneObjectsManager
{
public:
    SceneObjectsManager();

    template <class T>
    void registerObject(T* gameAgent);

    void destroyObject(int instance_id);

    bool isInstanceExists(int instance_id);

    void registerAgent(godot::GameAgent* gameAgent);
    void registerNode(godot::Node* node);

    godot::GameAgent* getAgentByInstanceId(int instance_id);
    godot::Node* getNodeByInstanceId(int instance_id);

public:
    static constexpr s64 NULL_REFERENCE = -1;

protected:
    godot::Dictionary sceneObjects;
};

template<class T>
inline void SceneObjectsManager::registerObject(T* object)
{
    if (object) {
        sceneObjects[object->get_instance_id()] = object;
    }
}

// SceneObjectsManager.cpp
#include "SceneObjectsManager.h"

SceneObjectsManager::SceneObjectsManager()
{
    sceneObjects.clear();
}

void SceneObjectsManager::registerAgent(godot::GameAgent* gameAgent)
{
    registerObject<godot::GameAgent>(gameAgent);
}

void SceneObjectsManager::registerNode(godot::Node* node)
{
    registerObject<godot::Node>(node);
}

void SceneObjectsManager::destroyObject(int instance_id)
{
    if (sceneObjects.has(instance_id)) {
        sceneObjects[instance_id].call("queue_free", nullptr, 0);
        sceneObjects.erase(instance_id);
    }
}

godot::GameAgent* SceneObjectsManager::getAgentByInstanceId(int instance_id)
{
    if (!sceneObjects.has(instance_id)) {
        return nullptr;
    } else {
        return sceneObjects[instance_id];
    }
}

godot::Node* SceneObjectsManager::getNodeByInstanceId(int instance_id)
{
    if (!sceneObjects.has(instance_id)) {
        return nullptr;
    }
    else {
        return sceneObjects[instance_id];
    }
}

bool SceneObjectsManager::isInstanceExists(int instance_id)
{
    return sceneObjects.has(instance_id);
}
by (246 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.