diff --git a/Cargo.lock b/Cargo.lock index 814594b8b2..a760d441ac 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7168,6 +7168,7 @@ dependencies = [ "kiddo 0.2.4", "lazy_static", "lz-fear", + "mimalloc", "minifb", "noise", "num 0.4.0", @@ -7189,6 +7190,7 @@ dependencies = [ "vek 0.15.8", "veloren-common", "veloren-common-base", + "veloren-common-dynlib", "veloren-common-frontend", "veloren-common-net", ] diff --git a/server-cli/src/main.rs b/server-cli/src/main.rs index 16742e2c4f..8c2e97ce41 100644 --- a/server-cli/src/main.rs +++ b/server-cli/src/main.rs @@ -91,6 +91,10 @@ fn main() -> io::Result<()> { { agent::init(); } + #[cfg(feature = "hot-site2")] + { + world::init(); + } // Load server settings let mut server_settings = server::Settings::load(&server_data_dir); diff --git a/server/Cargo.toml b/server/Cargo.toml index cfb00e4369..c6058ded41 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -11,6 +11,7 @@ plugins = ["common-state/plugins"] persistent_world = [] hot-reloading = ["common/hot-reloading"] hot-agent = ["server-agent/use-dyn-lib"] +hot-site2 = ["world/use-dyn-lib"] default = ["worldgen", "plugins", "persistent_world", "simd"] diff --git a/world/Cargo.toml b/world/Cargo.toml index 6088ab03df..9b552d65f7 100644 --- a/world/Cargo.toml +++ b/world/Cargo.toml @@ -5,6 +5,8 @@ authors = ["Joshua Barretto "] edition = "2021" [features] +use-dyn-lib = ["common-dynlib"] +be-dyn-lib = [] simd = ["vek/platform_intrinsics", "packed_simd"] bin_compression = ["lz-fear", "deflate", "flate2", "image/jpeg", "num-traits", "fallible-iterator", "clap", "rstar"] @@ -14,6 +16,7 @@ default = ["simd"] common = { package = "veloren-common", path = "../common" } common_base = { package = "veloren-common-base", path = "../common/base"} common-net = { package = "veloren-common-net", path = "../common/net" } +common-dynlib = {package = "veloren-common-dynlib", path = "../common/dynlib", optional = true} bincode = "1.3.1" bitvec = "1.0.1" @@ -39,6 +42,9 @@ inline_tweak = "1.0.2" kiddo = "0.2" strum = "0.24.0" +[target.'cfg(windows)'.dependencies] +mimalloc = "0.1.29" + # compression benchmarks lz-fear = { version = "0.1.1", optional = true } deflate = { version = "1.0.0", optional = true } diff --git a/world/src/lib.rs b/world/src/lib.rs index d8cf0b2bb9..aebfdad4ba 100644 --- a/world/src/lib.rs +++ b/world/src/lib.rs @@ -1,4 +1,3 @@ -#![deny(unsafe_code)] #![allow(incomplete_features)] #![allow( clippy::option_map_unit_fn, @@ -63,6 +62,25 @@ use serde::Deserialize; use std::time::Duration; use vek::*; +#[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(all(target_os = "windows", feature = "be-dyn-lib"))] +#[global_allocator] +static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc; + +#[cfg(feature = "use-dyn-lib")] +use {common_dynlib::LoadedLib, lazy_static::lazy_static, std::sync::Arc, std::sync::Mutex}; + +#[cfg(feature = "use-dyn-lib")] +lazy_static! { + pub static ref LIB: Arc>> = + common_dynlib::init("veloren-world", "world"); +} + +#[cfg(feature = "use-dyn-lib")] +pub fn init() { lazy_static::initialize(&LIB); } + #[derive(Debug)] pub enum Error { Other(String), diff --git a/world/src/site2/gen.rs b/world/src/site2/gen.rs index d1bf51aea9..a5426e062c 100644 --- a/world/src/site2/gen.rs +++ b/world/src/site2/gen.rs @@ -1,3 +1,6 @@ +#[cfg(feature = "use-dyn-lib")] +use {crate::LIB, std::ffi::CStr}; + use super::*; use crate::{ block::block_from_structure, @@ -1339,7 +1342,41 @@ impl PrimitiveGroupFill for [PrimitiveRef<'_>; N] { } pub trait Structure { - fn render(&self, site: &Site, land: &Land, painter: &Painter); + #[cfg(feature = "use-dyn-lib")] + const UPDATE_FN: &'static [u8]; + + fn render_inner(&self, site: &Site, land: &Land, painter: &Painter); + + fn render(&self, site: &Site, land: &Land, painter: &Painter) { + #[cfg(not(feature = "use-dyn-lib"))] + { + self.render_inner(site, land, painter); + } + #[cfg(feature = "use-dyn-lib")] + { + let lock = LIB.lock().unwrap(); + let lib = &lock.as_ref().unwrap().lib; + + let update_fn: common_dynlib::Symbol = unsafe { + //let start = std::time::Instant::now(); + // Overhead of 0.5-5 us (could use hashmap to mitigate if this is an issue) + lib.get(Self::UPDATE_FN) + //println!("{}", start.elapsed().as_nanos()); + } + .unwrap_or_else(|e| { + panic!( + "Trying to use: {} but had error: {:?}", + CStr::from_bytes_with_nul(Self::UPDATE_FN) + .map(CStr::to_str) + .unwrap() + .unwrap(), + e + ) + }); + + update_fn(self, site, land, painter); + } + } // Generate a primitive tree and fills for this structure fn render_collect( diff --git a/world/src/site2/plot/bridge.rs b/world/src/site2/plot/bridge.rs index 8e668b8ae5..fb4ab87735 100644 --- a/world/src/site2/plot/bridge.rs +++ b/world/src/site2/plot/bridge.rs @@ -944,7 +944,11 @@ impl Bridge { } impl Structure for Bridge { - fn render(&self, _site: &Site, _land: &Land, painter: &Painter) { + #[cfg(feature = "use-dyn-lib")] + const UPDATE_FN: &'static [u8] = b"render_bridge\0"; + + #[cfg_attr(feature = "be-dyn-lib", export_name = "render_bridge")] + fn render_inner(&self, _site: &Site, _land: &Land, painter: &Painter) { match &self.kind { BridgeKind::Flat => render_flat(self, painter), BridgeKind::Tower(roof) => render_tower(self, painter, roof), diff --git a/world/src/site2/plot/castle.rs b/world/src/site2/plot/castle.rs index 4d8dddda46..df82dbf289 100644 --- a/world/src/site2/plot/castle.rs +++ b/world/src/site2/plot/castle.rs @@ -42,7 +42,11 @@ impl Castle { } impl Structure for Castle { - fn render(&self, site: &Site, _land: &Land, painter: &Painter) { + #[cfg(feature = "use-dyn-lib")] + const UPDATE_FN: &'static [u8] = b"render_castle\0"; + + #[cfg_attr(feature = "be-dyn-lib", export_name = "render_castle")] + fn render_inner(&self, site: &Site, _land: &Land, painter: &Painter) { let wall_height = 24; let parapet_height = 2; let parapet_gap = 2; diff --git a/world/src/site2/plot/citadel.rs b/world/src/site2/plot/citadel.rs index c6e4860bf7..b592a708b5 100644 --- a/world/src/site2/plot/citadel.rs +++ b/world/src/site2/plot/citadel.rs @@ -101,7 +101,11 @@ impl Citadel { } impl Structure for Citadel { - fn render(&self, _site: &Site, land: &Land, painter: &Painter) { + #[cfg(feature = "use-dyn-lib")] + const UPDATE_FN: &'static [u8] = b"render_citadel\0"; + + #[cfg_attr(feature = "be-dyn-lib", export_name = "render_citadel")] + fn render_inner(&self, _site: &Site, land: &Land, painter: &Painter) { for (pos, cell) in self.grid.iter_area( self.wpos_cell(painter.render_aabr().min) - 1, Vec2::::from(painter.render_aabr().size()) / CELL_SIZE + 2, diff --git a/world/src/site2/plot/cliff_tower.rs b/world/src/site2/plot/cliff_tower.rs index 90ecd5c784..1a78662b9e 100644 --- a/world/src/site2/plot/cliff_tower.rs +++ b/world/src/site2/plot/cliff_tower.rs @@ -43,7 +43,11 @@ impl CliffTower { } impl Structure for CliffTower { - fn render(&self, _site: &Site, _land: &Land, painter: &Painter) { + #[cfg(feature = "use-dyn-lib")] + const UPDATE_FN: &'static [u8] = b"render_clifftower\0"; + + #[cfg_attr(feature = "be-dyn-lib", export_name = "render_clifftower")] + fn render_inner(&self, _site: &Site, _land: &Land, painter: &Painter) { let base = self.alt + 1; let center = self.bounds.center(); let variant_pos = center.with_z(base); diff --git a/world/src/site2/plot/desert_city_multiplot.rs b/world/src/site2/plot/desert_city_multiplot.rs index 5bcbd03e89..5c7b9cd4d5 100644 --- a/world/src/site2/plot/desert_city_multiplot.rs +++ b/world/src/site2/plot/desert_city_multiplot.rs @@ -129,7 +129,11 @@ impl DesertCityMultiPlot { } impl Structure for DesertCityMultiPlot { - fn render(&self, _site: &Site, _land: &Land, painter: &Painter) { + #[cfg(feature = "use-dyn-lib")] + const UPDATE_FN: &'static [u8] = b"render_desertcitymultiplot\0"; + + #[cfg_attr(feature = "be-dyn-lib", export_name = "render_desertcitymultiplot")] + fn render_inner(&self, _site: &Site, _land: &Land, painter: &Painter) { let sandstone = Fill::Sampling(Arc::new(|center| { Some(match (RandomField::new(0).get(center)) % 37 { 0..=8 => Block::new(BlockKind::Rock, Rgb::new(245, 212, 129)), diff --git a/world/src/site2/plot/desert_city_temple.rs b/world/src/site2/plot/desert_city_temple.rs index c30e516808..c62c5d0eaf 100644 --- a/world/src/site2/plot/desert_city_temple.rs +++ b/world/src/site2/plot/desert_city_temple.rs @@ -38,7 +38,11 @@ impl DesertCityTemple { } impl Structure for DesertCityTemple { - fn render(&self, _site: &Site, _land: &Land, painter: &Painter) { + #[cfg(feature = "use-dyn-lib")] + const UPDATE_FN: &'static [u8] = b"render_desertcitytemple\0"; + + #[cfg_attr(feature = "be-dyn-lib", export_name = "render_desertcitytemple")] + fn render_inner(&self, _site: &Site, _land: &Land, painter: &Painter) { let sandstone = Fill::Sampling(Arc::new(|center| { Some(match (RandomField::new(0).get(center)) % 37 { 0..=8 => Block::new(BlockKind::Rock, Rgb::new(245, 212, 129)), diff --git a/world/src/site2/plot/dungeon.rs b/world/src/site2/plot/dungeon.rs index 072b97d07c..8b6d2d0a99 100644 --- a/world/src/site2/plot/dungeon.rs +++ b/world/src/site2/plot/dungeon.rs @@ -1377,7 +1377,11 @@ impl Floor { } impl SiteStructure for Dungeon { - fn render(&self, _site: &Site, land: &Land, painter: &Painter) { + #[cfg(feature = "use-dyn-lib")] + const UPDATE_FN: &'static [u8] = b"render_dungeon\0"; + + #[cfg_attr(feature = "be-dyn-lib", export_name = "render_dungeon")] + fn render_inner(&self, _site: &Site, land: &Land, painter: &Painter) { let origin = (self.origin + Vec2::broadcast(TILE_SIZE / 2)).with_z(self.alt + ALT_OFFSET); lazy_static! { diff --git a/world/src/site2/plot/giant_tree.rs b/world/src/site2/plot/giant_tree.rs index 08a47c4ba4..87a8efc549 100644 --- a/world/src/site2/plot/giant_tree.rs +++ b/world/src/site2/plot/giant_tree.rs @@ -79,7 +79,11 @@ impl GiantTree { } impl Structure for GiantTree { - fn render(&self, _site: &Site, _land: &Land, painter: &Painter) { + #[cfg(feature = "use-dyn-lib")] + const UPDATE_FN: &'static [u8] = b"render_gianttree\0"; + + #[cfg_attr(feature = "be-dyn-lib", export_name = "render_gianttree")] + fn render_inner(&self, _site: &Site, _land: &Land, painter: &Painter) { let fast_noise = FastNoise::new(self.seed); let dark = Rgb::new(10, 70, 50).map(|e| e as f32); let light = Rgb::new(80, 140, 10).map(|e| e as f32); diff --git a/world/src/site2/plot/gnarling.rs b/world/src/site2/plot/gnarling.rs index 5a0d113a8c..9606622410 100644 --- a/world/src/site2/plot/gnarling.rs +++ b/world/src/site2/plot/gnarling.rs @@ -436,7 +436,11 @@ impl GnarlingFortification { } impl Structure for GnarlingFortification { - fn render(&self, _site: &Site, land: &Land, painter: &Painter) { + #[cfg(feature = "use-dyn-lib")] + const UPDATE_FN: &'static [u8] = b"render_gnarlingfortification\0"; + + #[cfg_attr(feature = "be-dyn-lib", export_name = "render_gnarlingfortification")] + fn render_inner(&self, _site: &Site, land: &Land, painter: &Painter) { // Create outer wall for (point, next_point) in self.wall_segments.iter() { // This adds additional points for the wall on the line between two points, diff --git a/world/src/site2/plot/house.rs b/world/src/site2/plot/house.rs index f6e99b722b..2a54ae1363 100644 --- a/world/src/site2/plot/house.rs +++ b/world/src/site2/plot/house.rs @@ -92,7 +92,11 @@ impl House { const STOREY: i32 = 5; impl Structure for House { - fn render(&self, site: &Site, _land: &Land, painter: &Painter) { + #[cfg(feature = "use-dyn-lib")] + const UPDATE_FN: &'static [u8] = b"render_house\0"; + + #[cfg_attr(feature = "be-dyn-lib", export_name = "render_house")] + fn render_inner(&self, site: &Site, _land: &Land, painter: &Painter) { let storey = STOREY; let roof = storey * self.levels as i32 - 1; let foundations = 12; diff --git a/world/src/site2/plot/savannah_pit.rs b/world/src/site2/plot/savannah_pit.rs index d6357565b1..130154d181 100644 --- a/world/src/site2/plot/savannah_pit.rs +++ b/world/src/site2/plot/savannah_pit.rs @@ -35,7 +35,11 @@ impl SavannahPit { } impl Structure for SavannahPit { - fn render(&self, _site: &Site, _land: &Land, painter: &Painter) { + #[cfg(feature = "use-dyn-lib")] + const UPDATE_FN: &'static [u8] = b"render_savannahpit\0"; + + #[cfg_attr(feature = "be-dyn-lib", export_name = "render_savannahpit")] + fn render_inner(&self, _site: &Site, _land: &Land, painter: &Painter) { let base = self.alt + 1; let center = self.bounds.center(); let sprite_fill = Fill::Sampling(Arc::new(|wpos| { diff --git a/world/src/site2/plot/sea_chapel.rs b/world/src/site2/plot/sea_chapel.rs index b5b79ebb94..88fbef0b05 100644 --- a/world/src/site2/plot/sea_chapel.rs +++ b/world/src/site2/plot/sea_chapel.rs @@ -31,7 +31,11 @@ impl SeaChapel { } impl Structure for SeaChapel { - fn render(&self, _site: &Site, _land: &Land, painter: &Painter) { + #[cfg(feature = "use-dyn-lib")] + const UPDATE_FN: &'static [u8] = b"render_seachapel\0"; + + #[cfg_attr(feature = "be-dyn-lib", export_name = "render_seachapel")] + fn render_inner(&self, _site: &Site, _land: &Land, painter: &Painter) { let base = self.alt + 1; let center = self.bounds.center(); let diameter = 54; diff --git a/world/src/site2/plot/workshop.rs b/world/src/site2/plot/workshop.rs index d8416b1379..9ac64acb1f 100644 --- a/world/src/site2/plot/workshop.rs +++ b/world/src/site2/plot/workshop.rs @@ -40,7 +40,11 @@ impl Workshop { } impl Structure for Workshop { - fn render(&self, _site: &Site, _land: &Land, painter: &Painter) { + #[cfg(feature = "use-dyn-lib")] + const UPDATE_FN: &'static [u8] = b"render_workshop\0"; + + #[cfg_attr(feature = "be-dyn-lib", export_name = "render_workshop")] + fn render_inner(&self, _site: &Site, _land: &Land, painter: &Painter) { let brick = Fill::Brick(BlockKind::Rock, Rgb::new(80, 75, 85), 24); let base = self.alt + 1;