godotengine / godot-cpp

C++ bindings for the Godot script API
MIT License
1.7k stars 525 forks source link

Android: Failed loading resource, Make sure resources have been imported by opening the project in the editor at least once. #1540

Closed DexterFstone closed 1 month ago

DexterFstone commented 1 month ago

Godot version

4.2.2.stable

godot-cpp version

4.2

System information

Godot v4.2.2.stable - Windows 10.0.19045 - GLES3 (Compatibility) - ANGLE (AMD, AMD Radeon HD 5570 (0x000068D9) Direct3D11 vs_5_0 ps_5_0, D3D11-8.17.10.1433) () - Intel(R) Pentium(R) CPU G2030 @ 3.00GHz (2 Threads)

Issue description

Hi, I created a GDExtension, but when I run it on Android it gives me an error:

at: load (core/io/resource_format_binary.cpp:762)
08-02 10:52:17.716 10664 10826 E godot   : USER ERROR: Failed loading resource: res://.godot/exported/133200997/export-f47528efc383e396a0647f9294453713-a.scn. Make sure resources have been imported by opening the project in the editor at least once.
08-02 10:52:17.716 10664 10826 E godot   :    at: _load (core/io/resource_loader.cpp:275)
08-02 10:52:17.716 10664 10826 E godot   : USER ERROR: Failed loading scene: res://a.tscn.
08-02 10:52:17.716 10664 10826 E godot   :    at: start (main/main.cpp:3475)

my src: Class A:

namespace godot {

class A: public Node {
    GDCLASS(A, Node)

protected:
    static void _bind_methods();

public:
    TypedArray<B> bs;

    A();
    ~A();

    void set_bs(const TypedArray<B> bs);
    TypedArray<B> get_bs() const;
};

}

#endif

Class B:

namespace godot {

class B: public  Resource {
    GDCLASS(B, Resource)

protected:
    static void _bind_methods();

public:
    enum Type {
        NONE = 0,
        TEST = 1,
    };

    B::Type type;

    B::Type get_type() const;

    B();
    ~B();
};

}

VARIANT_ENUM_CAST(B::Type)

#endif

cpp A:

void Adivery::_bind_methods() {
    ClassDB::bind_method(D_METHOD("set_bs", "bs"), &A::set_bs);
    ClassDB::bind_method(D_METHOD("get_bs"), &A::get_bs);
    ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "bs", PROPERTY_HINT_ARRAY_TYPE, String::num(Variant::OBJECT) + "/" + String::num(PROPERTY_HINT_RESOURCE_TYPE) + ":B"), "set_bs", "get_bs");
}

void A::set_bs(const TypedArray<B> bs) {
    this->bs= bs;
}

TypedArray<B> A::get_bs() const {
    return bs;
}

Steps to reproduce

  1. Create Class B
  2. Create Class A
  3. Create register_types
  4. Compile
  5. Add to Godot
  6. Add Node to Scene
  7. Create a New B Resource in the Inspector
  8. Run on Android

Minimal reproduction project

N/A

AThousandShips commented 1 month ago

Please upload an MRP with all your code, this could be caused by some issue that isn't visible here

DexterFstone commented 1 month ago

Please upload an MRP with all your code, this could be caused by some issue that isn't visible here

src.zip

sample.zip

DexterFstone commented 1 month ago

any progress?

AThousandShips commented 1 month ago

It's only been a day so no, please have patience

dsnopek commented 1 month ago

Thanks!

The code and project uploaded above were more than an MRP, so instead I patched the godot-cpp test project to use code very similar to what is given in the issue description. See the attached patch for the exact changes I made.

Unfortunately, I'm not able to reproduce the error you encountered. After building the test project for Android, and deploying to my phone (Samsung Galaxy S21 Ultra) using Godot's "Remote Debug" feature, it ran just fine.

Maybe I didn't recreate the issue correctly in my patch? If so, I'd welcome another patch or MRP that does reproduce the issue.

Are you seeing any other errors? I'd look perhaps for an error about having issues loading the extension. Perhaps the extension wasn't compiled for Android correctly?

DexterFstone commented 1 month ago

I recreate my project to MRP and get same error: BaseA.h:

#ifndef BASE_A_H
#define BASE_A_H

#include "BaseB.h"

#include <godot_cpp/variant/array.hpp>
#include <godot_cpp/classes/node.hpp>
#include <godot_cpp/core/class_db.hpp>
#include <godot_cpp/godot.hpp>

namespace godot {

class BaseA : public Node {
    GDCLASS(BaseA, Node)

protected:
    static void _bind_methods();

public:
    TypedArray<BaseB> bs;

    BaseA();
    ~BaseA();

    void set_bs(const TypedArray<BaseB> bs);
    TypedArray<BaseB> get_bs() const;
};

}

#endif

BaseA.cpp:

#include "BaseA.h"

using namespace godot;

void BaseA::_bind_methods() {
    ClassDB::bind_method(D_METHOD("set_bs", "bs"), &BaseA::set_bs);
    ClassDB::bind_method(D_METHOD("get_bs"), &BaseA::get_bs);
    ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "bs", PROPERTY_HINT_ARRAY_TYPE, String::num(Variant::OBJECT) + "/" + String::num(PROPERTY_HINT_RESOURCE_TYPE) + ":BaseB"), "set_bs", "get_bs");
}

BaseA::BaseA() {

}

BaseA::~BaseA() {
    // Add your cleanup here.
}

void BaseA::set_bs(const TypedArray<BaseB> bs) {
    this->bs = bs;
}

TypedArray<BaseB> BaseA::get_bs() const {
    return bs;
}

BaseB.h:

#ifndef BASE_B_H
#define BASE_B_H

#include <godot_cpp/classes/resource.hpp>
#include <godot_cpp/core/class_db.hpp>
#include <godot_cpp/godot.hpp>

namespace godot {

class BaseB : public Resource {
    GDCLASS(BaseB, Resource)

protected:
    static void _bind_methods();

public:
    enum Type {
        NONE = 0,
        TEST = 1,
    };

    BaseB::Type type;

    BaseB::Type get_type() const;

    BaseB();
    ~BaseB();
};

}

VARIANT_ENUM_CAST(BaseB::Type)

#endif

BaseB.cpp:

#include "BaseB.h"

using namespace godot;

void BaseB::_bind_methods() {
    ClassDB::bind_method(D_METHOD("get_type"), &BaseB::get_type);
    ADD_PROPERTY(PropertyInfo(Variant::INT, "type", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR, "type"), "", "get_type");
}

BaseB::BaseB() {
    type = BaseB::Type::NONE;
}

BaseB::~BaseB() {
    // Add your cleanup here.
}

BaseB::Type BaseB::get_type() const {
    return type;
}

BaseB1.h:

#ifndef BASE_B1_H
#define BASE_B1_H

#include "BaseB.h"

#include <godot_cpp/core/class_db.hpp>
#include <godot_cpp/godot.hpp>

namespace godot {

class BaseB1 : public BaseB {
    GDCLASS(BaseB1, BaseB)

protected:
    static void _bind_methods();

public:
    BaseB1();
    ~BaseB1();
};

}

#endif

BaseB1.cpp:

#include "BaseB1.h"

using namespace godot;

void BaseB1::_bind_methods() {

}

BaseB1::BaseB1() {
    type = BaseB::Type::TEST;
}

BaseB1::~BaseB1() {
    // Add your cleanup here.
}

register_types.h:

#ifndef GDEXAMPLE_REGISTER_TYPES_H
#define GDEXAMPLE_REGISTER_TYPES_H

#include <godot_cpp/core/class_db.hpp>

using namespace godot;

void initialize_base_a(ModuleInitializationLevel p_level);
void uninitialize_base_a(ModuleInitializationLevel p_level);

#endif // GDEXAMPLE_REGISTER_TYPES_H

register_types.cpp:

#include "register_types.h"

#include "BaseA.h"
#include "BaseB.h"
#include "BaseB1.h"

#include <gdextension_interface.h>
#include <godot_cpp/core/defs.hpp>
#include <godot_cpp/godot.hpp>

using namespace godot;

void initialize_base_a(ModuleInitializationLevel p_level) {
    if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
        return;
    }
    GDREGISTER_CLASS(BaseA);
    GDREGISTER_ABSTRACT_CLASS(BaseB);
    GDREGISTER_CLASS(BaseB1);
}
void uninitialize_base_a(ModuleInitializationLevel p_level) {
    if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
        return;
    }
}

extern "C" {
// Initialization.
    GDExtensionBool GDE_EXPORT base_a_init(GDExtensionInterfaceGetProcAddress p_get_proc_address, const GDExtensionClassLibraryPtr p_library, GDExtensionInitialization *r_initialization) {
        godot::GDExtensionBinding::InitObject init_obj(p_get_proc_address, p_library, r_initialization);

        init_obj.register_initializer(initialize_base_a);
        init_obj.register_terminator(uninitialize_base_a);
        init_obj.set_minimum_library_initialization_level(MODULE_INITIALIZATION_LEVEL_SCENE);

        return init_obj.init();
    }
}

image image

dsnopek commented 1 month ago

I recreate my project to MRP

Thanks, this code matches the "Minimal" part of MRP (Minimal Reproduction Project). However, the intention is for an MRP to be a full project that we can simply download, build and run, without having to manually setup anything.

That said, I have copied your new code into the godot-cpp test project - here is the new patch that does that. (If you'd like, you can apply this patch to godot-cpp and try it yourself - if I'm missing a necessary piece in order to reproduce the issue, please let me know.)

I'm still unable to reproduce the issue in my testing on Android: the test project loads and runs fine, despite the main scene containing a BaseA node with a BaseB1 resource on it, like you show in your screenshot.

So, I suspect the problem is elsewhere, which brings me back to my previous questions:

Are you seeing any other errors? I'd look perhaps for an error about having issues loading the extension. Perhaps the extension wasn't compiled for Android correctly?

DexterFstone commented 1 month ago

Are you seeing any other errors?

Untitled

Perhaps the extension wasn't compiled for Android correctly?

scons platform=android
scons: Reading SConscript files ...
Auto-detected 2 CPU cores available for build parallelism. Using 2 cores by default. You can override it with the -j argument.
Building for architecture arm64 on platform android
scons: done reading SConscript files.
scons: Building targets ...
scons: `godot-cpp\bin\libgodot-cpp.android.template_debug.arm64.a' is up to date.
Compiling shared src\BaseA.cpp ...
Compiling shared src\BaseB.cpp ...
Compiling shared src\BaseB1.cpp ...
Compiling shared src\register_types.cpp ...
Linking Shared Library bin\adivery.android.template_debug.arm64.so ...
scons: done building targets.
dsnopek commented 1 month ago

Are there any errors about failing to load your GDExtension? They would probably come much earlier in the log than the subset of the errors you've shown so far

DexterFstone commented 1 month ago

Are there any errors about failing to load your GDExtension? They would probably come much earlier in the log than the subset of the errors you've shown so far

No

dsnopek commented 1 month ago

Hm. Well, without any more information or being able to reproduce the issue, I don't think there's anything else we can do to track down the bug.

dsnopek commented 1 month ago

It looks like you deleted the comment, I'd like to point out something in the further errors you shared:

When exporting for Android, I get this error

No suitable library found for GDExtension: res://addons/base_a/base_a.gdextension. Possible feature flags for your platform: mobile, android, etc2, astc, arm32, template, debug, template_debug

Based on the above, it looks like you're exporting for arm32, however, in your .gdextension file you only provide libraries for arm64 and x86_64:

android.debug.x86_64 = "res://addons/base_a/bin/base_a.android.template_debug.x86_64.so"
android.release.x86_64 = "res://addons/base_a/bin/base_a.android.template_release.x86_64.so"
android.debug.arm64 = "res://addons/base_a/bin/base_a.android.template_debug.arm64.so"
android.release.arm64 = "res://addons/base_a/bin/base_a.android.template_release.arm64.so"

Perhaps this mismatch is related to the problems you are experiencing?

DexterFstone commented 1 month ago

It looks like you deleted the comment, I'd like to point out something in the further errors you shared:

When exporting for Android, I get this error

No suitable library found for GDExtension: res://addons/base_a/base_a.gdextension. Possible feature flags for your platform: mobile, android, etc2, astc, arm32, template, debug, template_debug

Based on the above, it looks like you're exporting for arm32, however, in your .gdextension file you only provide libraries for arm64 and x86_64:

android.debug.x86_64 = "res://addons/base_a/bin/base_a.android.template_debug.x86_64.so"
android.release.x86_64 = "res://addons/base_a/bin/base_a.android.template_release.x86_64.so"
android.debug.arm64 = "res://addons/base_a/bin/base_a.android.template_debug.arm64.so"
android.release.arm64 = "res://addons/base_a/bin/base_a.android.template_release.arm64.so"

Perhaps this mismatch is related to the problems you are experiencing?

I Compile for arm32 but the error still exist For now I try to run it in different phone

DexterFstone commented 1 month ago

I tested on more phones and still nothing