Skip to content
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鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Failed to load class method XXX #746

Open
QuentinPerez opened this issue Jun 9, 2024 · 3 comments
Open

Failed to load class method XXX #746

QuentinPerez opened this issue Jun 9, 2024 · 3 comments

Comments

@QuentinPerez
Copy link

馃憢
I am trying to integrate a Godot view into an iOS project using libgodot_project. Below is the Rust code that I use to configure the engine. However, load_class_method_table crashes with the error Failed to load class method AnimatedSprite2D. I dumped all the registered classes, and it's true that this one is not loaded.

I tried to register it, but I got a compilation error saying that AnimatedSprite2D does not implement GodotRegisterClass + GodotNotification + GodotToString + ImplementsGodotVirtual. Is this normal? Is there a way to fix it or work around it?

use godot_core::init::{ExtensionLibrary, InitLevel};
use godot_ffi::{
    ClassApiLevel, GDExtensionBool, GDExtensionClassLibraryPtr, GDExtensionInitialization,
    GDExtensionInterfaceGetProcAddress,
};
use std::ffi::{c_char, CStr, CString};

extern "C" fn godot_init(
    p_get_proc_address: GDExtensionInterfaceGetProcAddress,
    p_library: GDExtensionClassLibraryPtr,
    r_initialization: *mut GDExtensionInitialization,
) -> GDExtensionBool {
    struct MyExtension;

    unsafe impl ExtensionLibrary for MyExtension {
        fn editor_run_behavior() -> godot_core::init::EditorRunBehavior {
            godot_core::init::EditorRunBehavior::AllClasses
        }

        fn min_level() -> godot_core::init::InitLevel {
            godot_core::init::InitLevel::Scene
        }

        fn on_level_init(level: godot_core::init::InitLevel) {
            // Nothing by default.
        }

        fn on_level_deinit(level: godot_core::init::InitLevel) {
            // Nothing by default.
        }

        fn override_hot_reload() -> Option<bool> {
            None
        }
    }

    unsafe {
        godot_core::init::__gdext_load_library::<MyExtension>(
            p_get_proc_address,
            p_library,
            r_initialization,
        )
    }
}

#[no_mangle]
pub extern "C" fn godot_setup(path: *const c_char) {
    let c_str = unsafe { CStr::from_ptr(path) };
    let path = c_str.to_str().unwrap();

    let args = vec![
        CString::new("").unwrap(),
        CString::new("--path").unwrap(),
        CString::new(path).unwrap(),
        CString::new("--rendering-driver").unwrap(),
        CString::new("vulkan").unwrap(),
        CString::new("--rendering-method").unwrap(),
        CString::new("mobile").unwrap(),
        CString::new("--display-driver").unwrap(),
        CString::new("embedded").unwrap(),
        CString::new("--verbose").unwrap(),
    ];

    let c_string_ptrs: Vec<*const c_char> = args.iter().map(|s| s.as_ptr()).collect();
    let c_string_ptrs_ptr = c_string_ptrs.as_ptr() as *mut *mut c_char;

    unsafe {
        godot_ffi::r#gen::gdextension_interface::libgodot_create_godot_instance(
            args.len() as i32,
            c_string_ptrs_ptr,
            Some(godot_init),
        );

        // godot_core::registry::class::register_class::<godot_core::classes::AnimatedSprite2D>();

        godot_ffi::load_class_method_table(ClassApiLevel::Scene);
    };
}
@Bromeon
Copy link
Member

Bromeon commented Jun 9, 2024

However, load_class_method_table crashes with the error Failed to load class method AnimatedSprite2D.

That's probably not the entire error message, is it? Where is the method name?


Regarding the code you posted, where is this from? It's using a ton of private/undocumented features, i.e. not a workflow we officially support. To register classes, you currently need #[derive(GodotClass)] -- but you can use classes that Godot already provides, via godot::classes module.


However, load_class_method_table crashes with the error Failed to load class method AnimatedSprite2D. I dumped all the registered classes, and it's true that this one is not loaded.

Do you know why it's missing?

A quick "fix" is to use the lazy-function-tables feature, which delays the problem until runtime. It doesn't crash at startup, but it will panic if someone tries to call the method.

Are you using the latest stable Godot version 4.2.2 and its corresponding extension_api.json?

@QuentinPerez
Copy link
Author

QuentinPerez commented Jun 9, 2024

Regarding the code you posted, where is this from? It's using a ton of private/undocumented features, i.e. not a workflow we officially support. To register classes, you currently need #[derive(GodotClass)] -- but you can use classes that Godot already provides, via godot::classes module.

The libgodot_project allows us to compile Godot as a static library and embed it in an iOS app. The idea is to have a mix of native Swift and a 3D view powered by Godot (rather than having the entire app in Godot). For the code, I created it after exploring the godot-rust codebase. I tried to use the classes provided by godot::classes, like this: godot_core::registry::class::register_class::<godot_core::classes::AnimatedSprite2D>();, but it does not implement all the required traits.

However, load_class_method_table crashes with the error Failed to load class method AnimatedSprite2D. I dumped all the registered classes, and it's true that this one is not loaded.

Here is the full message: ERROR: 'AnimatedSprite2D.set_sprite_frames at: gdextension_classdb_get_method_bind (./core/extension/gdextension_interface.cpp:1478)

A quick "fix" is to use the lazy-function-tables feature, which delays the problem until runtime. It doesn't crash at startup, but it will panic if someone tries to call the method.

Yes, this is not ideal.

Are you using the latest stable Godot version 4.2.2 and its corresponding extension_api.json?

I use Godot 4.3 with the patch to create the static library from this repository.

You can find the extension_api.json in my hackish fork (I had to fork it because I use Bazel) here.

BTW: I have another POC that uses godot-cpp, via https://github.com/migeran/godot-cpp/blob/master/src/godot.cpp#L231 and it works fine.

@Bromeon
Copy link
Member

Bromeon commented Jun 9, 2024

I tried to use the classes provided by godot::classes, like this: godot_core::registry::class::register_class::<godot_core::classes::AnimatedSprite2D>();, but it does not implement all the required traits.

As mentioned, these things are not part of the public API, as per our documentation. So you can try to get it running, but it may be overly verbose (this is accessed by generated code after all) and it can break at any time.

But my point is: you should not need to do this in the first place.

First, you should find out why AnimatedSprite2D.set_sprite_frames is absent, and not try to work around it by using weird gdext internal APIs 馃檪


I use Godot 4.3 with the patch to create the static library from this repository.

Do you use api-custom? See also https://godot-rust.github.io/book/toolchain/godot-version.html.

gdext relies on GDExtension's compatibility guarantees, which only exist for stable versions.


BTW: I have another POC that uses godot-cpp [...] and it works fine.

Do you have to manually register Godot classes here too? If not, then it shouldn't be necessary in godot-rust either. Let's try to find out what's happening 馃槈

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants