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’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FIX] [WASM-Export] Unable to use multiple rust GDExtensions at the same time #973

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 39 additions & 5 deletions godot-core/src/init/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,14 @@ use godot_ffi as sys;
use sys::GodotFfi;

use crate::builtin::{GString, StringName};
use crate::meta::ClassName;
use crate::out;
use crate::private::ClassPlugin;

pub use sys::GdextBuild;

static mut ENGINE_INITIALIZED: bool = false;

#[doc(hidden)]
#[deny(unsafe_op_in_unsafe_fn)]
pub unsafe fn __gdext_load_library<E: ExtensionLibrary>(
Expand All @@ -41,9 +45,21 @@ pub unsafe fn __gdext_load_library<E: ExtensionLibrary>(

let config = sys::GdextConfig::new(tool_only_in_editor);

out!("Is engine initialized? {}", unsafe {
if ENGINE_INITIALIZED {
"yes"
} else {
"nope"
}
});

// SAFETY: no custom code has run yet + no other thread is accessing global handle.
unsafe {
sys::initialize(get_proc_address, library, config);
if !ENGINE_INITIALIZED {
sys::initialize(get_proc_address, library, config);
}

ENGINE_INITIALIZED = true;
}

// Currently no way to express failure; could be exposed to E if necessary.
Expand Down Expand Up @@ -158,6 +174,24 @@ unsafe fn gdext_on_level_init(level: InitLevel) {
_ => (),
}

crate::private::iterate_plugins(|elem: &ClassPlugin| {
// Filter per ClassPlugin and not PluginItem, because all components of all classes are mixed together in one huge list.
if elem.init_level != level {
return;
}

out!("Pre::auto_register_classes: {}", &elem.class_name);

out!("All class names: ");
ClassName::iter_all(|entry| {
let string_name = entry
.godot_str
.get_or_init(|| entry.rust_str.to_string_name());

out!("\tClass name: {}", string_name);
});
});

crate::registry::class::auto_register_classes(level);
}

Expand Down Expand Up @@ -364,9 +398,9 @@ unsafe fn ensure_godot_features_compatible() {

if godot_is_double != gdext_is_double {
panic!(
"Godot runs with {} precision, but gdext was compiled with {} precision.\n\
Cargo feature `double-precision` must be used if and only if Godot is compiled with `precision=double`.\n",
s(godot_is_double), s(gdext_is_double),
);
"Godot runs with {} precision, but gdext was compiled with {} precision.\n\
Cargo feature `double-precision` must be used if and only if Godot is compiled with `precision=double`.\n",
s(godot_is_double), s(gdext_is_double),
);
}
}
21 changes: 16 additions & 5 deletions godot-core/src/meta/class_name.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,9 @@ pub unsafe fn cleanup() {
/// Entry in the class name cache.
///
/// `StringName` needs to be lazy-initialized because the Godot binding may not be initialized yet.
struct ClassNameEntry {
rust_str: ClassNameSource,
godot_str: OnceCell<StringName>,
pub struct ClassNameEntry {
pub rust_str: ClassNameSource,
pub godot_str: OnceCell<StringName>,
}

impl ClassNameEntry {
Expand All @@ -62,13 +62,13 @@ impl ClassNameEntry {
// ----------------------------------------------------------------------------------------------------------------------------------------------

/// `Cow`-like enum for class names, but with C strings as the borrowed variant.
enum ClassNameSource {
pub enum ClassNameSource {
Owned(String),
Borrowed(&'static CStr),
}

impl ClassNameSource {
fn to_string_name(&self) -> StringName {
pub fn to_string_name(&self) -> StringName {
match self {
ClassNameSource::Owned(s) => StringName::from(s),

Expand Down Expand Up @@ -107,6 +107,17 @@ pub struct ClassName {
}

impl ClassName {
pub fn iter_all<F>(f: F)
where
F: Fn(&ClassNameEntry),
{
let guard = CLASS_NAMES.lock();

for name in guard.iter() {
f(name);
}
}

/// Construct a new class name.
///
/// This is expensive the first time it called for a given `T`, but will be cached for subsequent calls.
Expand Down
8 changes: 8 additions & 0 deletions godot-ffi/src/binding/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ use crate::{
GdextRuntimeMetadata, ManualInitCell, UtilityFunctionTable,
};

#[macro_use]
use crate::out;

#[cfg(feature = "experimental-threads")]
mod multi_threaded;
#[cfg(not(feature = "experimental-threads"))]
Expand Down Expand Up @@ -84,6 +87,11 @@ unsafe impl Send for ClassLibraryPtr {}
/// # Safety
/// The table must not have been initialized yet.
unsafe fn initialize_table<T>(table: &ManualInitCell<T>, value: T, what: &str) {
if table.is_initialized() {
out!("Table for {} is already initialized!", what);
return;
}

debug_assert!(
!table.is_initialized(),
"method table for {what} should only be initialized once"
Expand Down