Pulled library hot-reloading code into a separate crate and removed duplicated code from anim and egui crates

This commit is contained in:
Ben Wallis 2021-05-09 21:55:29 +01:00
parent 6163ddbb68
commit 24134af4a7
15 changed files with 182 additions and 361 deletions

14
Cargo.lock generated
View File

@ -6138,6 +6138,7 @@ dependencies = [
"veloren-i18n",
"veloren-server",
"veloren-voxygen-anim",
"veloren-voxygen-dynlib",
"veloren-voxygen-egui",
"veloren-world",
"wgpu",
@ -6159,6 +6160,7 @@ dependencies = [
"tracing",
"vek",
"veloren-common",
"veloren-voxygen-dynlib",
]
[[package]]
@ -6168,6 +6170,17 @@ dependencies = [
"veloren-voxygen-anim",
]
[[package]]
name = "veloren-voxygen-dynlib"
version = "0.1.0"
dependencies = [
"find_folder",
"lazy_static",
"libloading 0.7.0",
"notify 5.0.0-pre.6",
"tracing",
]
[[package]]
name = "veloren-voxygen-egui"
version = "0.9.0"
@ -6181,6 +6194,7 @@ dependencies = [
"tracing",
"veloren-client",
"veloren-common",
"veloren-voxygen-dynlib",
]
[[package]]

View File

@ -20,6 +20,7 @@ members = [
"voxygen/anim",
"voxygen/anim/dyn",
"voxygen/i18n",
"voxygen/dynlib",
"voxygen/egui",
"voxygen/egui/dyn",
"world",

View File

@ -59,6 +59,7 @@ where
.add_directive("rustls=info".parse().unwrap())
.add_directive("wgpu_core=info".parse().unwrap())
.add_directive("wgpu_core::device=warn".parse().unwrap())
.add_directive("wgpu_core::swap_chain=info".parse().unwrap())
.add_directive("veloren_network_protocol=info".parse().unwrap())
.add_directive("quinn_proto::connection=info".parse().unwrap())
.add_directive(

View File

@ -22,8 +22,8 @@ runtimeLibs = ["libGL", "xorg.libX11", "xorg.libXcursor", "xorg.libXrandr", "xor
buildInputs = ["xorg.libxcb"]
[features]
hot-anim = ["anim/use-dyn-lib"]
hot-egui = ["voxygen-egui/use-dyn-lib"]
hot-anim = ["voxygen-dynlib", "anim/use-dyn-lib"]
hot-egui = ["voxygen-dynlib", "voxygen-egui/use-dyn-lib"]
singleplayer = ["server"]
simd = ["vek/platform_intrinsics"]
tracy = ["profiling", "profiling/profile-with-tracy", "common/tracy", "common-ecs/tracy", "common-frontend/tracy", "common-net/tracy", "common-systems/tracy", "common-state/tracy", "client/tracy"]
@ -44,6 +44,7 @@ common-state = {package = "veloren-common-state", path = "../common/state"}
anim = {package = "veloren-voxygen-anim", path = "anim"}
i18n = {package = "veloren-i18n", path = "i18n"}
voxygen-egui = {package = "veloren-voxygen-egui", path = "egui"}
voxygen-dynlib = {package = "veloren-voxygen-dynlib", path = "dynlib", optional=true}
# Graphics
winit = {version = "0.24.0", features = ["serde"]}

View File

@ -21,3 +21,4 @@ notify = {version = "5.0.0-pre.2", optional = true}
tracing = {version = "0.1", optional = true}
vek = {version = "=0.14.1", features = ["serde"]}
bytemuck = { version="1.4", features=["derive"] }
voxygen-dynlib = {package = "veloren-voxygen-dynlib", path = "../dynlib"}

View File

@ -8,7 +8,7 @@
//! start earlier since a cdylib doesn't pipeline with it's dependencies.
//!
//! NOTE: the `be-dyn-lib` feature must be used for this crate to be useful, it
//! is not on by default becaue this causes cargo to switch the feature on in
//! is not on by default because this causes cargo to switch the feature on in
//! the anim crate when compiling the static lib into voxygen.
#[cfg(feature = "be-dyn-lib")]
pub use veloren_voxygen_anim::*;

View File

@ -1,258 +0,0 @@
use lazy_static::lazy_static;
use libloading::Library;
use notify::{immediate_watcher, EventKind, RecursiveMode, Watcher};
use std::{
process::{Command, Stdio},
sync::{mpsc, Mutex},
time::Duration,
};
use find_folder::Search;
use std::{env, path::PathBuf};
use tracing::{debug, error, info};
#[cfg(target_os = "windows")]
const COMPILED_FILE: &str = "veloren_voxygen_anim_dyn.dll";
#[cfg(target_os = "windows")]
const ACTIVE_FILE: &str = "veloren_voxygen_anim_dyn_active.dll";
#[cfg(not(target_os = "windows"))]
const COMPILED_FILE: &str = "libveloren_voxygen_anim_dyn.so";
#[cfg(not(target_os = "windows"))]
const ACTIVE_FILE: &str = "libveloren_voxygen_anim_dyn_active.so";
// This option is required as `hotreload()` moves the `LoadedLib`.
lazy_static! {
pub static ref LIB: Mutex<Option<LoadedLib>> = Mutex::new(Some(LoadedLib::compile_load()));
}
/// LoadedLib holds a loaded dynamic library and the location of library file
/// with the appropriate OS specific name and extension i.e.
/// `libvoxygen_anim_dyn_active.dylib`, `voxygen_anim_dyn_active.dll`.
///
/// # NOTE
/// DOES NOT WORK ON MACOS, due to some limitations with hot-reloading the
/// `.dylib`.
pub struct LoadedLib {
/// Loaded library.
pub lib: Library,
/// Path to the library.
pub lib_path: PathBuf,
}
impl LoadedLib {
/// Compile and load the dynamic library
///
/// This is necessary because the very first time you use hot reloading you
/// wont have the library, so you can't load it until you have compiled it!
fn compile_load() -> Self {
#[cfg(target_os = "macos")]
error!("The hot reloading feature does not work on macos.");
// Compile
if !compile() {
panic!("Animation compile failed.");
} else {
info!("Animation compile succeeded.");
}
copy(&LoadedLib::determine_path());
Self::load()
}
/// Load a library from disk.
///
/// Currently this is pretty fragile, it gets the path of where it thinks
/// the dynamic library should be and tries to load it. It will panic if it
/// is missing.
fn load() -> Self {
let lib_path = LoadedLib::determine_path();
// Try to load the library.
let lib = match unsafe { Library::new(lib_path.clone()) } {
Ok(lib) => lib,
Err(e) => panic!(
"Tried to load dynamic library from {:?}, but it could not be found. A potential \
reason is we may require a special case for your OS so we can find it. {:?}",
lib_path, e
),
};
Self { lib, lib_path }
}
/// Determine the path to the dynamic library based on the path of the
/// current executable.
fn determine_path() -> PathBuf {
let current_exe = env::current_exe();
// If we got the current_exe, we need to go up a level and then down
// in to debug (in case we were in release or another build dir).
let mut lib_path = match current_exe {
Ok(mut path) => {
// Remove the filename to get the directory.
path.pop();
// Search for the debug directory.
let dir = Search::ParentsThenKids(1, 1)
.of(path)
.for_folder("debug")
.expect(
"Could not find the debug build directory relative to the current \
executable.",
);
debug!(?dir, "Found the debug build directory.");
dir
},
Err(e) => {
panic!(
"Could not determine the path of the current executable, this is needed to \
hotreload the dynamic library. {:?}",
e
);
},
};
// Determine the platform specific path and push it onto our already
// established target/debug dir.
lib_path.push(ACTIVE_FILE);
lib_path
}
}
/// Initialise a watcher.
///
/// The assumption is that this is run from the voxygen crate's root directory
/// as it will watch the relative path `anim` for any changes to `.rs`
/// files. Upon noticing changes it will wait a moment and then recompile.
pub fn init() {
// Make sure first compile is done by accessing the lazy_static and then
// immediately dropping (because we don't actually need it).
drop(LIB.lock());
// TODO: use crossbeam
let (reload_send, reload_recv) = mpsc::channel();
// Start watcher
let mut watcher = immediate_watcher(move |res| event_fn(res, &reload_send)).unwrap();
// Search for the anim directory.
let anim_dir = Search::Kids(1)
.for_folder("anim")
.expect("Could not find the anim crate directory relative to the current directory");
watcher.watch(anim_dir, RecursiveMode::Recursive).unwrap();
// Start reloader that watcher signals
// "Debounces" events since I can't find the option to do this in the latest
// `notify`
std::thread::Builder::new()
.name("voxygen_anim_watcher".into())
.spawn(move || {
let mut modified_paths = std::collections::HashSet::new();
while let Ok(path) = reload_recv.recv() {
modified_paths.insert(path);
// Wait for any additional modify events before reloading
while let Ok(path) = reload_recv.recv_timeout(Duration::from_millis(300)) {
modified_paths.insert(path);
}
info!(
?modified_paths,
"Hot reloading animations because files in `anim` modified."
);
hotreload();
}
})
.unwrap();
// Let the watcher live forever
std::mem::forget(watcher);
}
/// Event function to hotreload the dynamic library
///
/// This is called by the watcher to filter for modify events on `.rs` files
/// before sending them back.
fn event_fn(res: notify::Result<notify::Event>, sender: &mpsc::Sender<String>) {
match res {
Ok(event) => match event.kind {
EventKind::Modify(_) => {
event
.paths
.iter()
.filter(|p| p.extension().map(|e| e == "rs").unwrap_or(false))
.map(|p| p.to_string_lossy().into_owned())
// Signal reloader
.for_each(|p| { let _ = sender.send(p); });
},
_ => {},
},
Err(e) => error!(?e, "Animation hotreload watcher error."),
}
}
/// Hotreload the dynamic library
///
/// This will reload the dynamic library by first internally calling compile
/// and then reloading the library.
fn hotreload() {
// Do nothing if recompile failed.
if compile() {
let mut lock = LIB.lock().unwrap();
// Close lib.
let loaded_lib = lock.take().unwrap();
loaded_lib.lib.close().unwrap();
copy(&loaded_lib.lib_path);
// Open new lib.
*lock = Some(LoadedLib::load());
info!("Updated animations.");
}
}
/// Recompile the anim package
///
/// Returns `false` if the compile failed.
fn compile() -> bool {
let output = Command::new("cargo")
.stderr(Stdio::inherit())
.stdout(Stdio::inherit())
.arg("build")
.arg("--package")
.arg("veloren-voxygen-anim-dyn")
.arg("--features")
.arg("veloren-voxygen-anim-dyn/be-dyn-lib")
.output()
.unwrap();
output.status.success()
}
/// Copy the lib file, so we have an `_active` copy.
///
/// We do this for all OS's although it is only strictly necessary for windows.
/// The reason we do this is to make the code easier to understand and debug.
fn copy(lib_path: &PathBuf) {
// Use the platform specific names.
let lib_compiled_path = lib_path.with_file_name(COMPILED_FILE);
let lib_output_path = lib_path.with_file_name(ACTIVE_FILE);
// Get the path to where the lib was compiled to.
debug!(?lib_compiled_path, ?lib_output_path, "Moving.");
// Copy the library file from where it is output, to where we are going to
// load it from i.e. lib_path.
std::fs::copy(&lib_compiled_path, &lib_output_path).unwrap_or_else(|err| {
panic!(
"Failed to rename dynamic library from {:?} to {:?}. {:?}",
lib_compiled_path, lib_output_path, err
)
});
}

View File

@ -54,7 +54,6 @@ pub mod bird_large;
pub mod bird_medium;
pub mod character;
pub mod dragon;
#[cfg(feature = "use-dyn-lib")] pub mod dyn_lib;
pub mod fish_medium;
pub mod fish_small;
pub mod fixture;
@ -67,14 +66,19 @@ pub mod ship;
pub mod theropod;
pub mod vek;
#[cfg(feature = "use-dyn-lib")]
pub use dyn_lib::init;
#[cfg(feature = "use-dyn-lib")]
use std::ffi::CStr;
use self::vek::*;
use bytemuck::{Pod, Zeroable};
#[cfg(feature = "use-dyn-lib")]
use lazy_static::lazy_static;
#[cfg(feature = "use-dyn-lib")]
use std::sync::Arc;
#[cfg(feature = "use-dyn-lib")]
use std::sync::Mutex;
#[cfg(feature = "use-dyn-lib")]
use voxygen_dynlib::LoadedLib;
type MatRaw = [[f32; 4]; 4];
@ -91,6 +95,11 @@ fn make_bone(mat: Mat4<f32>) -> FigureBoneData {
pub type Bone = Transform<f32, f32, f32>;
#[cfg(feature = "use-dyn-lib")]
lazy_static! {
pub static ref LIB: Arc<Mutex<Option<LoadedLib>>> = Arc::new(Mutex::new(None));
}
pub trait Skeleton: Send + Sync + 'static {
type Attr;
type Body;
@ -118,9 +127,10 @@ pub fn compute_matrices<S: Skeleton>(
}
#[cfg(feature = "use-dyn-lib")]
{
let lock = dyn_lib::LIB.lock().unwrap();
let lock = LIB.lock().unwrap();
let lib = &lock.as_ref().unwrap().lib;
#[allow(clippy::type_complexity)]
let compute_fn: libloading::Symbol<
fn(&S, Mat4<f32>, &mut [FigureBoneData; MAX_BONE_COUNT]) -> Vec3<f32>,
> = unsafe { lib.get(S::COMPUTE_FN) }.unwrap_or_else(|e| {
@ -169,9 +179,10 @@ pub trait Animation {
}
#[cfg(feature = "use-dyn-lib")]
{
let lock = dyn_lib::LIB.lock().unwrap();
let lock = LIB.lock().unwrap();
let lib = &lock.as_ref().unwrap().lib;
#[allow(clippy::type_complexity)]
let update_fn: libloading::Symbol<
fn(
&Self::Skeleton,
@ -183,9 +194,8 @@ pub trait Animation {
> = unsafe {
//let start = std::time::Instant::now();
// Overhead of 0.5-5 us (could use hashmap to mitigate if this is an issue)
let f = lib.get(Self::UPDATE_FN);
lib.get(Self::UPDATE_FN)
//println!("{}", start.elapsed().as_nanos());
f
}
.unwrap_or_else(|e| {
panic!(

12
voxygen/dynlib/Cargo.toml Normal file
View File

@ -0,0 +1,12 @@
[package]
name = "veloren-voxygen-dynlib"
version = "0.1.0"
authors = ["Ben Wallis <atomyc@gmail.com>"]
edition = "2018"
[dependencies]
find_folder = {version = "0.3.0"}
lazy_static = {version = "1.4.0"}
libloading = {version = "0.7"}
notify = {version = "5.0.0-pre.2"}
tracing = "0.1"

View File

@ -1,4 +1,3 @@
use lazy_static::lazy_static;
use libloading::Library;
use notify::{immediate_watcher, EventKind, RecursiveMode, Watcher};
use std::{
@ -8,24 +7,13 @@ use std::{
};
use find_folder::Search;
use std::{env, path::PathBuf};
use std::{
env,
path::{Path, PathBuf},
sync::Arc,
};
use tracing::{debug, error, info};
#[cfg(target_os = "windows")]
const COMPILED_FILE: &str = "veloren_voxygen_egui_dyn.dll";
#[cfg(target_os = "windows")]
const ACTIVE_FILE: &str = "veloren_voxygen_egui_dyn_active.dll";
#[cfg(not(target_os = "windows"))]
const COMPILED_FILE: &str = "libveloren_voxygen_anim_dyn.so";
#[cfg(not(target_os = "windows"))]
const ACTIVE_FILE: &str = "libveloren_voxygen_anim_dyn_active.so";
// This option is required as `hotreload()` moves the `LoadedLib`.
lazy_static! {
pub static ref LIB: Mutex<Option<LoadedLib>> = Mutex::new(Some(LoadedLib::compile_load()));
}
/// LoadedLib holds a loaded dynamic library and the location of library file
/// with the appropriate OS specific name and extension i.e.
/// `libvoxygen_anim_dyn_active.dylib`, `voxygen_anim_dyn_active.dll`.
@ -45,20 +33,20 @@ impl LoadedLib {
///
/// This is necessary because the very first time you use hot reloading you
/// wont have the library, so you can't load it until you have compiled it!
fn compile_load() -> Self {
fn compile_load(dyn_package: &str) -> Self {
#[cfg(target_os = "macos")]
error!("The hot reloading feature does not work on macos.");
// Compile
if !compile() {
panic!("Animation compile failed.");
if !compile(dyn_package) {
panic!("{} compile failed.", dyn_package);
} else {
info!("Animation compile succeeded.");
info!("{} compile succeeded.", dyn_package);
}
copy(&LoadedLib::determine_path());
copy(&LoadedLib::determine_path(dyn_package), dyn_package);
Self::load()
Self::load(dyn_package)
}
/// Load a library from disk.
@ -66,8 +54,8 @@ impl LoadedLib {
/// Currently this is pretty fragile, it gets the path of where it thinks
/// the dynamic library should be and tries to load it. It will panic if it
/// is missing.
fn load() -> Self {
let lib_path = LoadedLib::determine_path();
fn load(dyn_package: &str) -> Self {
let lib_path = LoadedLib::determine_path(dyn_package);
// Try to load the library.
let lib = match unsafe { Library::new(lib_path.clone()) } {
@ -84,7 +72,7 @@ impl LoadedLib {
/// Determine the path to the dynamic library based on the path of the
/// current executable.
fn determine_path() -> PathBuf {
fn determine_path(dyn_package: &str) -> PathBuf {
let current_exe = env::current_exe();
// If we got the current_exe, we need to go up a level and then down
@ -109,7 +97,7 @@ impl LoadedLib {
Err(e) => {
panic!(
"Could not determine the path of the current executable, this is needed to \
hotreload the dynamic library. {:?}",
hot-reload the dynamic library. {:?}",
e
);
},
@ -117,21 +105,20 @@ impl LoadedLib {
// Determine the platform specific path and push it onto our already
// established target/debug dir.
lib_path.push(ACTIVE_FILE);
lib_path.push(active_file(dyn_package));
lib_path
}
}
/// Initialise a watcher.
///
/// The assumption is that this is run from the voxygen crate's root directory
/// as it will watch the relative path `egui` for any changes to `.rs`
/// files. Upon noticing changes it will wait a moment and then recompile.
pub fn init() {
// Make sure first compile is done by accessing the lazy_static and then
// immediately dropping (because we don't actually need it).
drop(LIB.lock());
pub fn init(
lib_storage: Arc<Mutex<Option<LoadedLib>>>,
package: &'static str,
dyn_package: &'static str,
package_source_dir: &'static str,
) {
let mut lock = lib_storage.lock().unwrap();
*lock = Some(LoadedLib::compile_load(package));
// TODO: use crossbeam
let (reload_send, reload_recv) = mpsc::channel();
@ -139,18 +126,24 @@ pub fn init() {
// Start watcher
let mut watcher = immediate_watcher(move |res| event_fn(res, &reload_send)).unwrap();
// Search for the anim directory.
let anim_dir = Search::Kids(1)
.for_folder("egui")
.expect("Could not find the egui crate directory relative to the current directory");
// Search for the source directory of the package being hot-reloaded.
let watch_dir = Search::Kids(1)
.for_folder(package_source_dir)
.unwrap_or_else(|_| {
panic!(
"Could not find the {} crate directory relative to the current directory",
package_source_dir
)
});
watcher.watch(anim_dir, RecursiveMode::Recursive).unwrap();
watcher.watch(watch_dir, RecursiveMode::Recursive).unwrap();
let loaded_lib_clone = Arc::clone(&lib_storage);
// Start reloader that watcher signals
// "Debounces" events since I can't find the option to do this in the latest
// `notify`
std::thread::Builder::new()
.name("voxygen_egui_watcher".into())
.name(format!("{}_hotreload_watcher", package))
.spawn(move || {
let mut modified_paths = std::collections::HashSet::new();
while let Ok(path) = reload_recv.recv() {
@ -162,10 +155,10 @@ pub fn init() {
info!(
?modified_paths,
"Hot reloading egui because files in `egui` modified."
"Hot reloading {} because files in `{}` modified.", package, package_source_dir
);
hotreload();
hotreload(dyn_package, loaded_lib_clone.clone());
}
})
.unwrap();
@ -174,14 +167,31 @@ pub fn init() {
std::mem::forget(watcher);
}
fn compiled_file(dyn_package: &str) -> String { dyn_lib_file(dyn_package, false) }
fn active_file(dyn_package: &str) -> String { dyn_lib_file(dyn_package, true) }
fn dyn_lib_file(dyn_package: &str, active: bool) -> String {
#[cfg(target_os = "windows")]
const FILE_EXT: &str = ".dll";
#[cfg(not(target_os = "windows"))]
const FILE_EXT: &str = ".so";
format!(
"{}{}{}",
dyn_package.replace("-", "_"),
if active { "_active" } else { "" },
FILE_EXT
)
}
/// Event function to hotreload the dynamic library
///
/// This is called by the watcher to filter for modify events on `.rs` files
/// before sending them back.
fn event_fn(res: notify::Result<notify::Event>, sender: &mpsc::Sender<String>) {
match res {
Ok(event) => match event.kind {
EventKind::Modify(_) => {
Ok(event) => {
if let EventKind::Modify(_) = event.kind {
event
.paths
.iter()
@ -189,8 +199,7 @@ fn event_fn(res: notify::Result<notify::Event>, sender: &mpsc::Sender<String>) {
.map(|p| p.to_string_lossy().into_owned())
// Signal reloader
.for_each(|p| { let _ = sender.send(p); });
},
_ => {},
}
},
Err(e) => error!(?e, "egui hotreload watcher error."),
}
@ -200,18 +209,18 @@ fn event_fn(res: notify::Result<notify::Event>, sender: &mpsc::Sender<String>) {
///
/// This will reload the dynamic library by first internally calling compile
/// and then reloading the library.
fn hotreload() {
fn hotreload(dyn_package: &str, loaded_lib: Arc<Mutex<Option<LoadedLib>>>) {
// Do nothing if recompile failed.
if compile() {
let mut lock = LIB.lock().unwrap();
if compile(dyn_package) {
let mut lock = loaded_lib.lock().unwrap();
// Close lib.
let loaded_lib = lock.take().unwrap();
loaded_lib.lib.close().unwrap();
copy(&loaded_lib.lib_path);
copy(&loaded_lib.lib_path, dyn_package);
// Open new lib.
*lock = Some(LoadedLib::load());
*lock = Some(LoadedLib::load(dyn_package));
info!("Updated egui.");
}
@ -220,15 +229,17 @@ fn hotreload() {
/// Recompile the anim package
///
/// Returns `false` if the compile failed.
fn compile() -> bool {
fn compile(dyn_package: &str) -> bool {
let output = Command::new("cargo")
.stderr(Stdio::inherit())
.stdout(Stdio::inherit())
.arg("build")
.arg("-v")
.arg("-v")
.arg("--package")
.arg("veloren-voxygen-egui-dyn")
.arg(dyn_package)
.arg("--features")
.arg("veloren-voxygen-egui-dyn/be-dyn-lib")
.arg(format!("{}/be-dyn-lib", dyn_package))
.output()
.unwrap();
@ -239,10 +250,10 @@ fn compile() -> bool {
///
/// We do this for all OS's although it is only strictly necessary for windows.
/// The reason we do this is to make the code easier to understand and debug.
fn copy(lib_path: &PathBuf) {
fn copy(lib_path: &Path, dyn_package: &str) {
// Use the platform specific names.
let lib_compiled_path = lib_path.with_file_name(COMPILED_FILE);
let lib_output_path = lib_path.with_file_name(ACTIVE_FILE);
let lib_compiled_path = lib_path.with_file_name(compiled_file(dyn_package));
let lib_output_path = lib_path.with_file_name(active_file(dyn_package));
// Get the path to where the lib was compiled to.
debug!(?lib_compiled_path, ?lib_output_path, "Moving.");

View File

@ -13,6 +13,7 @@ client = {package = "veloren-client", path = "../../client"}
common = {package = "veloren-common", path = "../../common"}
egui = "0.11"
egui_winit_platform = "0.6"
voxygen-dynlib = {package = "veloren-voxygen-dynlib", path = "../dynlib"}
# Hot Reloading
find_folder = {version = "0.3.0", optional = true}

View File

@ -8,7 +8,7 @@
//! start earlier since a cdylib doesn't pipeline with it's dependencies.
//!
//! NOTE: the `be-dyn-lib` feature must be used for this crate to be useful, it
//! is not on by default becaue this causes cargo to switch the feature on in
//! is not on by default because this causes cargo to switch the feature on in
//! the anim crate when compiling the static lib into voxygen.
#[cfg(feature = "be-dyn-lib")]
pub use veloren_voxygen_egui::*;
pub use veloren_voxygen_egui::*;

View File

@ -1,27 +1,35 @@
use client::{Client, Join, WorldExt};
use common::debug_info::DebugInfo;
use egui_winit_platform::Platform;
#[cfg(all(feature = "be-dyn-lib", feature = "use-dyn-lib"))]
compile_error!("Can't use both \"be-dyn-lib\" and \"use-dyn-lib\" features at once");
#[cfg(feature = "use-dyn-lib")] pub mod dyn_lib;
use client::{Client, Join, WorldExt};
use common::{
comp,
comp::{Poise, PoiseState},
debug_info::DebugInfo,
};
use core::mem;
#[cfg(feature = "use-dyn-lib")]
pub use dyn_lib::init;
use egui::{
plot::{Plot, Value},
widgets::plot::Curve,
Color32, Grid, ScrollArea, Slider, Ui,
};
use std::{cmp::Ordering, ffi::CStr};
use egui_winit_platform::Platform;
#[cfg(feature = "use-dyn-lib")]
use lazy_static::lazy_static;
use std::ffi::CStr;
#[cfg(feature = "use-dyn-lib")]
use std::sync::Arc;
#[cfg(feature = "use-dyn-lib")]
use std::sync::Mutex;
#[cfg(feature = "use-dyn-lib")]
use voxygen_dynlib::LoadedLib;
#[cfg(feature = "use-dyn-lib")]
const MAINTAIN_EGUI_FN: &'static [u8] = b"maintain_egui_inner\0";
lazy_static! {
pub static ref LIB: Arc<Mutex<Option<LoadedLib>>> = Arc::new(Mutex::new(None));
}
#[cfg(feature = "use-dyn-lib")]
const MAINTAIN_EGUI_FN: &[u8] = b"maintain_egui_inner\0";
pub fn maintain(
platform: &mut Platform,
@ -32,20 +40,21 @@ pub fn maintain(
) -> EguiActions {
#[cfg(not(feature = "use-dyn-lib"))]
{
return maintain_egui_inner(
maintain_egui_inner(
platform,
egui_state,
client,
debug_info,
added_cylinder_shape_id,
);
)
}
#[cfg(feature = "use-dyn-lib")]
{
let lock = dyn_lib::LIB.lock().unwrap();
let lock = LIB.lock().unwrap();
let lib = &lock.as_ref().unwrap().lib;
#[allow(clippy::type_complexity)]
let maintain_fn: libloading::Symbol<
fn(
&mut Platform,
@ -65,13 +74,13 @@ pub fn maintain(
)
});
return maintain_fn(
maintain_fn(
platform,
egui_state,
client,
debug_info,
added_cylinder_shape_id,
);
)
}
}
@ -97,8 +106,8 @@ pub struct EguiInnerState {
frame_times: Vec<f32>,
}
impl EguiInnerState {
pub fn new() -> Self {
impl Default for EguiInnerState {
fn default() -> Self {
Self {
read_ecs: false,
selected_entity_info: None,
@ -149,12 +158,14 @@ pub fn maintain_egui_inner(
}
}
debug_info.as_ref().map(|x| {
egui_state.frame_times.push(x.frame_time.as_nanos() as f32);
if let Some(debug_info) = debug_info.as_ref() {
egui_state
.frame_times
.push(debug_info.frame_time.as_nanos() as f32);
if egui_state.frame_times.len() > 250 {
egui_state.frame_times.remove(0);
}
});
};
if egui_state.read_ecs {
let ecs = client.state().ecs();
@ -181,8 +192,8 @@ pub fn maintain_egui_inner(
.text("Cylinder height"),
);
let mut scroll_area = ScrollArea::from_max_height(800.0);
let (current_scroll, max_scroll) = scroll_area.show(ui, |ui| {
let scroll_area = ScrollArea::from_max_height(800.0);
let (_current_scroll, _max_scroll) = scroll_area.show(ui, |ui| {
// if scroll_top {
// ui.scroll_to_cursor(Align::TOP);
// }
@ -198,7 +209,7 @@ pub fn maintain_egui_inner(
ui.label("Body");
ui.label("Poise");
ui.end_row();
for (entity, body, stats, pos, ori, vel, poise) in (
for (entity, _body, stats, pos, _ori, vel, poise) in (
&ecs.entities(),
ecs.read_storage::<comp::Body>().maybe(),
ecs.read_storage::<comp::Stats>().maybe(),
@ -282,7 +293,7 @@ pub fn maintain_egui_inner(
if !selected_entity.gen().is_alive() {
previous_selected_entity = mem::take(&mut egui_state.selected_entity_info);
} else {
for (entity, body, stats, pos, ori, vel, poise, buffs) in (
for (_entity, _body, stats, pos, _ori, _vel, poise, buffs) in (
&ecs.entities(),
ecs.read_storage::<comp::Body>().maybe(),
ecs.read_storage::<comp::Stats>().maybe(),
@ -371,7 +382,7 @@ pub fn maintain_egui_inner(
ui.label("Time");
ui.label("Source");
ui.end_row();
buffs.buffs.iter().for_each(|(k, v)| {
buffs.buffs.iter().for_each(|(_, v)| {
ui.label(format!("{:?}", v.kind));
ui.label(
v.time.map_or("-".to_string(), |time| {
@ -432,7 +443,9 @@ pub fn maintain_egui_inner(
if let Some(selected_entity) = &egui_state.selected_entity_info {
if let Some(debug_shape_id) = selected_entity.debug_shape_id {
if egui_state.selected_entity_cylinder_height != selected_entity_cylinder_height {
if (egui_state.selected_entity_cylinder_height - selected_entity_cylinder_height).abs()
> f32::EPSILON
{
egui_actions
.actions
.push(DebugShapeAction::RemoveCylinder(debug_shape_id));

View File

@ -149,11 +149,25 @@ fn main() {
// Initialise watcher for animation hotreloading
#[cfg(feature = "hot-anim")]
anim::init();
{
voxygen_dynlib::init(
Arc::clone(&anim::LIB),
"veloren-voxygen-anim",
"veloren-voxygen-anim-dyn",
"anim",
);
}
// Initialise watcher for egui hotreloading
#[cfg(feature = "hot-egui")]
voxygen_egui::init();
{
voxygen_dynlib::init(
Arc::clone(&voxygen_egui::LIB),
"veloren-voxygen-egui",
"veloren-voxygen-egui-dyn",
"egui",
);
}
// Setup audio
let mut audio = match settings.audio.output {

View File

@ -27,7 +27,7 @@ impl EguiState {
Self {
platform,
egui_inner_state: EguiInnerState::new(),
egui_inner_state: EguiInnerState::default(),
new_debug_shape_id: None,
}
}
@ -55,7 +55,7 @@ impl EguiState {
DebugShapeAction::SetPosAndColor { id, pos, color } => {
scene
.debug
.set_pos_and_color(DebugShapeId(*id), pos.clone(), color.clone());
.set_pos_and_color(DebugShapeId(*id), *pos, *color);
},
})
}