Skip to content

Commit

Permalink
Start to figure out modding
Browse files Browse the repository at this point in the history
Currently this doesn't work. The TypeIds of things in different binaries are different, so all the bevy reflecty things break.

Depends on:
- bevyengine/bevy#13080
- bevyengine/bevy#8390
- bevyengine/bevy#32
  • Loading branch information
jwright159 committed Sep 20, 2024
1 parent 1840af0 commit 87bf765
Show file tree
Hide file tree
Showing 5 changed files with 104 additions and 1 deletion.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[workspace]
members = ["sbepis", "marching_cubes", "jack_noir"]
members = ["sbepis", "marching_cubes", "jack_noir", "mod_lib", "mod_bin"]
default-members = ["sbepis"]
resolver = "2"

Expand Down
11 changes: 11 additions & 0 deletions mod_bin/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[package]
name = "mod_bin"
version = "0.1.0"
edition = "2021"

[dependencies]
bevy_dylib = "0.14.2"
bevy = { version = "0.14.2", features = ["dynamic_linking"] }
bevy-inspector-egui = "0.26.0"
bevy_mod_debugdump = "0.11.1"
libloading = "0.8.5"
50 changes: 50 additions & 0 deletions mod_bin/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
#![allow(deprecated)]

use std::any::TypeId;
use std::ffi::OsStr;

use bevy::prelude::*;
use libloading::{Library, Symbol};

fn main() {
let mut app = App::new();
app.add_plugins((
DefaultPlugins,
bevy_inspector_egui::quick::WorldInspectorPlugin::new(),
));
unsafe {
// app.load_plugin("./target/debug/libmod_lib.so");

match dynamically_load_plugin("./target/debug/libmod_lib.so") {
Ok((lib, plugin)) => {
info!(
"Plugin loaded! {:?} {:?}",
app.world(),
TypeId::of::<Schedules>()
);
std::mem::forget(lib);
plugin.build(&mut app);
}
Err(e) => error!("Failed to load plugin: {:?}", e),
}
}
bevy_mod_debugdump::print_schedule_graph(&mut app, Update);
app.run();
}

pub unsafe fn dynamically_load_plugin<P: AsRef<OsStr>>(
path: P,
) -> Result<(Library, Box<dyn Plugin>), libloading::Error> {
// SAFETY: Caller must follow the safety requirements of Library::new.
let lib = unsafe { Library::new(path)? };

// SAFETY: Loaded plugins are not allowed to specify `_bevy_create_plugin` symbol manually, but
// must instead automatically generate it through `DynamicPlugin`.
let func: Symbol<unsafe fn() -> *mut dyn Plugin> = unsafe { lib.get(b"_bevy_create_plugin")? };

// SAFETY: `func` is automatically generated and is guaranteed to return a pointer created using
// `Box::into_raw`.
let plugin = unsafe { Box::from_raw(func()) };

Ok((lib, plugin))
}
11 changes: 11 additions & 0 deletions mod_lib/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[package]
name = "mod_lib"
version = "0.1.0"
edition = "2021"

[lib]
crate-type = ["dylib"]

[dependencies]
bevy_dylib = "0.14.2"
bevy = { version = "0.14.2", features = ["dynamic_linking"] }
31 changes: 31 additions & 0 deletions mod_lib/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#![allow(deprecated)]

use bevy::prelude::*;
use std::any::TypeId;

#[no_mangle]
pub fn _bevy_create_plugin() -> *mut dyn Plugin {
// make sure the constructor is the correct type.
let object = ModLib {};
let boxed = Box::new(object);
Box::into_raw(boxed)
}

pub struct ModLib;

impl Plugin for ModLib {
fn build(&self, app: &mut App) {
println!(
"ModLib loaded! {:?} {:?}",
app.world(),
TypeId::of::<Schedules>()
);
app.add_systems(Update, setup);
println!("ModLib system added!");
}
}

fn setup(mut commands: Commands) {
println!("Hello from mod_lib!");
commands.spawn(Name::new("Sample modded entity"));
}

0 comments on commit 87bf765

Please sign in to comment.