mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Merge branch 'xMAC94x/fix_1165' into 'master'
remove futures_executor from renderer and rather pass tokio runtime to it... See merge request veloren/veloren!2755
This commit is contained in:
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -6161,7 +6161,6 @@ dependencies = [
|
|||||||
"egui_winit_platform",
|
"egui_winit_platform",
|
||||||
"enum-iterator",
|
"enum-iterator",
|
||||||
"euc",
|
"euc",
|
||||||
"futures-executor",
|
|
||||||
"gilrs",
|
"gilrs",
|
||||||
"glyph_brush",
|
"glyph_brush",
|
||||||
"guillotiere",
|
"guillotiere",
|
||||||
|
@ -98,7 +98,6 @@ crossbeam-channel = "0.5"
|
|||||||
directories-next = "2.0"
|
directories-next = "2.0"
|
||||||
dot_vox = "4.0"
|
dot_vox = "4.0"
|
||||||
enum-iterator = "0.6"
|
enum-iterator = "0.6"
|
||||||
futures-executor = "0.3"
|
|
||||||
guillotiere = "0.6"
|
guillotiere = "0.6"
|
||||||
hashbrown = {version = "0.11", features = ["rayon", "serde", "nightly"]}
|
hashbrown = {version = "0.11", features = ["rayon", "serde", "nightly"]}
|
||||||
image = {version = "0.23.12", default-features = false, features = ["ico", "png"]}
|
image = {version = "0.23.12", default-features = false, features = ["ico", "png"]}
|
||||||
|
@ -51,6 +51,9 @@ use common_base::span;
|
|||||||
use i18n::LocalizationHandle;
|
use i18n::LocalizationHandle;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
use std::sync::Arc;
|
||||||
|
use tokio::runtime::Runtime;
|
||||||
|
|
||||||
/// A type used to store state that is shared between all play states.
|
/// A type used to store state that is shared between all play states.
|
||||||
pub struct GlobalState {
|
pub struct GlobalState {
|
||||||
pub userdata_dir: PathBuf,
|
pub userdata_dir: PathBuf,
|
||||||
@ -58,6 +61,7 @@ pub struct GlobalState {
|
|||||||
pub settings: Settings,
|
pub settings: Settings,
|
||||||
pub profile: Profile,
|
pub profile: Profile,
|
||||||
pub window: Window,
|
pub window: Window,
|
||||||
|
pub tokio_runtime: Arc<Runtime>,
|
||||||
#[cfg(feature = "egui-ui")]
|
#[cfg(feature = "egui-ui")]
|
||||||
pub egui_state: EguiState,
|
pub egui_state: EguiState,
|
||||||
pub lazy_init: scene::terrain::SpriteRenderContextLazy,
|
pub lazy_init: scene::terrain::SpriteRenderContextLazy,
|
||||||
|
@ -165,6 +165,29 @@ fn main() {
|
|||||||
default_hook(panic_info);
|
default_hook(panic_info);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
// Setup tokio runtime
|
||||||
|
use common::consts::MIN_RECOMMENDED_TOKIO_THREADS;
|
||||||
|
use std::sync::{
|
||||||
|
atomic::{AtomicUsize, Ordering},
|
||||||
|
Arc,
|
||||||
|
};
|
||||||
|
use tokio::runtime::Builder;
|
||||||
|
|
||||||
|
// TODO: evaluate std::thread::available_concurrency as a num_cpus replacement
|
||||||
|
let cores = num_cpus::get();
|
||||||
|
let tokio_runtime = Arc::new(
|
||||||
|
Builder::new_multi_thread()
|
||||||
|
.enable_all()
|
||||||
|
.worker_threads((cores / 4).max(MIN_RECOMMENDED_TOKIO_THREADS))
|
||||||
|
.thread_name_fn(|| {
|
||||||
|
static ATOMIC_ID: AtomicUsize = AtomicUsize::new(0);
|
||||||
|
let id = ATOMIC_ID.fetch_add(1, Ordering::SeqCst);
|
||||||
|
format!("tokio-voxygen-{}", id)
|
||||||
|
})
|
||||||
|
.build()
|
||||||
|
.unwrap(),
|
||||||
|
);
|
||||||
|
|
||||||
#[cfg(feature = "hot-reloading")]
|
#[cfg(feature = "hot-reloading")]
|
||||||
assets::start_hot_reloading();
|
assets::start_hot_reloading();
|
||||||
|
|
||||||
@ -210,7 +233,7 @@ fn main() {
|
|||||||
|
|
||||||
// Create window
|
// Create window
|
||||||
use veloren_voxygen::{error::Error, render::RenderError};
|
use veloren_voxygen::{error::Error, render::RenderError};
|
||||||
let (mut window, event_loop) = match Window::new(&settings) {
|
let (mut window, event_loop) = match Window::new(&settings, &tokio_runtime) {
|
||||||
Ok(ok) => ok,
|
Ok(ok) => ok,
|
||||||
// Custom panic message when a graphics backend could not be found
|
// Custom panic message when a graphics backend could not be found
|
||||||
Err(Error::RenderError(RenderError::CouldNotFindAdapter)) => {
|
Err(Error::RenderError(RenderError::CouldNotFindAdapter)) => {
|
||||||
@ -247,6 +270,7 @@ fn main() {
|
|||||||
audio,
|
audio,
|
||||||
profile,
|
profile,
|
||||||
window,
|
window,
|
||||||
|
tokio_runtime,
|
||||||
#[cfg(feature = "egui-ui")]
|
#[cfg(feature = "egui-ui")]
|
||||||
egui_state,
|
egui_state,
|
||||||
lazy_init,
|
lazy_init,
|
||||||
|
@ -3,11 +3,10 @@ use client::{
|
|||||||
error::{Error as ClientError, NetworkConnectError, NetworkError},
|
error::{Error as ClientError, NetworkConnectError, NetworkError},
|
||||||
Client, ServerInfo,
|
Client, ServerInfo,
|
||||||
};
|
};
|
||||||
use common::consts::MIN_RECOMMENDED_TOKIO_THREADS;
|
|
||||||
use crossbeam_channel::{unbounded, Receiver, Sender, TryRecvError};
|
use crossbeam_channel::{unbounded, Receiver, Sender, TryRecvError};
|
||||||
use std::{
|
use std::{
|
||||||
sync::{
|
sync::{
|
||||||
atomic::{AtomicBool, AtomicUsize, Ordering},
|
atomic::{AtomicBool, Ordering},
|
||||||
Arc,
|
Arc,
|
||||||
},
|
},
|
||||||
time::Duration,
|
time::Duration,
|
||||||
@ -47,29 +46,13 @@ impl ClientInit {
|
|||||||
connection_args: ConnectionArgs,
|
connection_args: ConnectionArgs,
|
||||||
username: String,
|
username: String,
|
||||||
password: String,
|
password: String,
|
||||||
runtime: Option<Arc<runtime::Runtime>>,
|
runtime: Arc<runtime::Runtime>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let (tx, rx) = unbounded();
|
let (tx, rx) = unbounded();
|
||||||
let (trust_tx, trust_rx) = unbounded();
|
let (trust_tx, trust_rx) = unbounded();
|
||||||
let cancel = Arc::new(AtomicBool::new(false));
|
let cancel = Arc::new(AtomicBool::new(false));
|
||||||
let cancel2 = Arc::clone(&cancel);
|
let cancel2 = Arc::clone(&cancel);
|
||||||
|
|
||||||
let runtime = runtime.unwrap_or_else(|| {
|
|
||||||
// TODO: evaluate std::thread::available_concurrency as a num_cpus replacement
|
|
||||||
let cores = num_cpus::get();
|
|
||||||
Arc::new(
|
|
||||||
runtime::Builder::new_multi_thread()
|
|
||||||
.enable_all()
|
|
||||||
.worker_threads((cores / 4).max(MIN_RECOMMENDED_TOKIO_THREADS))
|
|
||||||
.thread_name_fn(|| {
|
|
||||||
static ATOMIC_ID: AtomicUsize = AtomicUsize::new(0);
|
|
||||||
let id = ATOMIC_ID.fetch_add(1, Ordering::SeqCst);
|
|
||||||
format!("tokio-voxygen-{}", id)
|
|
||||||
})
|
|
||||||
.build()
|
|
||||||
.unwrap(),
|
|
||||||
)
|
|
||||||
});
|
|
||||||
let runtime2 = Arc::clone(&runtime);
|
let runtime2 = Arc::clone(&runtime);
|
||||||
|
|
||||||
runtime.spawn(async move {
|
runtime.spawn(async move {
|
||||||
|
@ -93,7 +93,7 @@ impl PlayState for MainMenuState {
|
|||||||
{
|
{
|
||||||
if let Some(singleplayer) = &global_state.singleplayer {
|
if let Some(singleplayer) = &global_state.singleplayer {
|
||||||
match singleplayer.receiver.try_recv() {
|
match singleplayer.receiver.try_recv() {
|
||||||
Ok(Ok(runtime)) => {
|
Ok(Ok(())) => {
|
||||||
// Attempt login after the server is finished initializing
|
// Attempt login after the server is finished initializing
|
||||||
attempt_login(
|
attempt_login(
|
||||||
&mut global_state.info_message,
|
&mut global_state.info_message,
|
||||||
@ -101,7 +101,7 @@ impl PlayState for MainMenuState {
|
|||||||
"".to_owned(),
|
"".to_owned(),
|
||||||
ConnectionArgs::Mpsc(14004),
|
ConnectionArgs::Mpsc(14004),
|
||||||
&mut self.init,
|
&mut self.init,
|
||||||
Some(runtime),
|
&global_state.tokio_runtime,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
Ok(Err(e)) => {
|
Ok(Err(e)) => {
|
||||||
@ -261,7 +261,7 @@ impl PlayState for MainMenuState {
|
|||||||
password,
|
password,
|
||||||
connection_args,
|
connection_args,
|
||||||
&mut self.init,
|
&mut self.init,
|
||||||
None,
|
&global_state.tokio_runtime,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
MainMenuEvent::CancelLoginAttempt => {
|
MainMenuEvent::CancelLoginAttempt => {
|
||||||
@ -290,7 +290,7 @@ impl PlayState for MainMenuState {
|
|||||||
},
|
},
|
||||||
#[cfg(feature = "singleplayer")]
|
#[cfg(feature = "singleplayer")]
|
||||||
MainMenuEvent::StartSingleplayer => {
|
MainMenuEvent::StartSingleplayer => {
|
||||||
let singleplayer = Singleplayer::new();
|
let singleplayer = Singleplayer::new(&global_state.tokio_runtime);
|
||||||
|
|
||||||
global_state.singleplayer = Some(singleplayer);
|
global_state.singleplayer = Some(singleplayer);
|
||||||
},
|
},
|
||||||
@ -450,7 +450,7 @@ fn attempt_login(
|
|||||||
password: String,
|
password: String,
|
||||||
connection_args: ConnectionArgs,
|
connection_args: ConnectionArgs,
|
||||||
init: &mut InitState,
|
init: &mut InitState,
|
||||||
runtime: Option<Arc<runtime::Runtime>>,
|
runtime: &Arc<runtime::Runtime>,
|
||||||
) {
|
) {
|
||||||
if let Err(err) = comp::Player::alias_validate(&username) {
|
if let Err(err) = comp::Player::alias_validate(&username) {
|
||||||
*info_message = Some(err.to_string());
|
*info_message = Some(err.to_string());
|
||||||
@ -463,7 +463,7 @@ fn attempt_login(
|
|||||||
connection_args,
|
connection_args,
|
||||||
username,
|
username,
|
||||||
password,
|
password,
|
||||||
runtime,
|
Arc::clone(runtime),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -183,7 +183,11 @@ pub struct Renderer {
|
|||||||
impl Renderer {
|
impl Renderer {
|
||||||
/// Create a new `Renderer` from a variety of backend-specific components
|
/// Create a new `Renderer` from a variety of backend-specific components
|
||||||
/// and the window targets.
|
/// and the window targets.
|
||||||
pub fn new(window: &winit::window::Window, mode: RenderMode) -> Result<Self, RenderError> {
|
pub fn new(
|
||||||
|
window: &winit::window::Window,
|
||||||
|
mode: RenderMode,
|
||||||
|
runtime: &tokio::runtime::Runtime,
|
||||||
|
) -> Result<Self, RenderError> {
|
||||||
let (pipeline_modes, mut other_modes) = mode.split();
|
let (pipeline_modes, mut other_modes) = mode.split();
|
||||||
// Enable seamless cubemaps globally, where available--they are essentially a
|
// Enable seamless cubemaps globally, where available--they are essentially a
|
||||||
// strict improvement on regular cube maps.
|
// strict improvement on regular cube maps.
|
||||||
@ -220,13 +224,12 @@ impl Renderer {
|
|||||||
#[allow(unsafe_code)]
|
#[allow(unsafe_code)]
|
||||||
let surface = unsafe { instance.create_surface(window) };
|
let surface = unsafe { instance.create_surface(window) };
|
||||||
|
|
||||||
let adapter = futures_executor::block_on(instance.request_adapter(
|
let adapter = runtime
|
||||||
&wgpu::RequestAdapterOptionsBase {
|
.block_on(instance.request_adapter(&wgpu::RequestAdapterOptionsBase {
|
||||||
power_preference: wgpu::PowerPreference::HighPerformance,
|
power_preference: wgpu::PowerPreference::HighPerformance,
|
||||||
compatible_surface: Some(&surface),
|
compatible_surface: Some(&surface),
|
||||||
},
|
}))
|
||||||
))
|
.ok_or(RenderError::CouldNotFindAdapter)?;
|
||||||
.ok_or(RenderError::CouldNotFindAdapter)?;
|
|
||||||
|
|
||||||
let info = adapter.get_info();
|
let info = adapter.get_info();
|
||||||
info!(
|
info!(
|
||||||
@ -244,7 +247,33 @@ impl Renderer {
|
|||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
let (device, queue) = futures_executor::block_on(adapter.request_device(
|
let trace_env = std::env::var_os("WGPU_TRACE_DIR");
|
||||||
|
let trace_path = trace_env.as_ref().map(|v| {
|
||||||
|
let path = std::path::Path::new(v);
|
||||||
|
// We don't want to continue if we can't actually collect the api trace
|
||||||
|
assert!(
|
||||||
|
path.exists(),
|
||||||
|
"WGPU_TRACE_DIR is set to the path \"{}\" which doesn't exist",
|
||||||
|
path.display()
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
path.is_dir(),
|
||||||
|
"WGPU_TRACE_DIR is set to the path \"{}\" which is not a directory",
|
||||||
|
path.display()
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
path.read_dir()
|
||||||
|
.expect("Could not read the directory that is specified by WGPU_TRACE_DIR")
|
||||||
|
.next()
|
||||||
|
.is_some(),
|
||||||
|
"WGPU_TRACE_DIR is set to the path \"{}\" which already contains other files",
|
||||||
|
path.display()
|
||||||
|
);
|
||||||
|
|
||||||
|
path
|
||||||
|
});
|
||||||
|
|
||||||
|
let (device, queue) = runtime.block_on(adapter.request_device(
|
||||||
&wgpu::DeviceDescriptor {
|
&wgpu::DeviceDescriptor {
|
||||||
// TODO
|
// TODO
|
||||||
label: None,
|
label: None,
|
||||||
@ -254,36 +283,7 @@ impl Renderer {
|
|||||||
| (adapter.features() & wgpu_profiler::GpuProfiler::REQUIRED_WGPU_FEATURES),
|
| (adapter.features() & wgpu_profiler::GpuProfiler::REQUIRED_WGPU_FEATURES),
|
||||||
limits,
|
limits,
|
||||||
},
|
},
|
||||||
std::env::var_os("WGPU_TRACE_DIR").as_ref().map(|v| {
|
trace_path.as_deref(),
|
||||||
let path = std::path::Path::new(v);
|
|
||||||
// We don't want to continue if we can't actually collect the api trace
|
|
||||||
if !path.exists() {
|
|
||||||
panic!(
|
|
||||||
"WGPU_TRACE_DIR is set to the path \"{}\" which doesn't exist",
|
|
||||||
path.display()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if !path.is_dir() {
|
|
||||||
panic!(
|
|
||||||
"WGPU_TRACE_DIR is set to the path \"{}\" which is not a directory",
|
|
||||||
path.display()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if path
|
|
||||||
.read_dir()
|
|
||||||
.expect("Could not read the directory that is specified by WGPU_TRACE_DIR")
|
|
||||||
.next()
|
|
||||||
.is_some()
|
|
||||||
{
|
|
||||||
panic!(
|
|
||||||
"WGPU_TRACE_DIR is set to the path \"{}\" which already contains other \
|
|
||||||
files",
|
|
||||||
path.display()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
path
|
|
||||||
}),
|
|
||||||
))?;
|
))?;
|
||||||
|
|
||||||
// Set error handler for wgpu errors
|
// Set error handler for wgpu errors
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use common::{clock::Clock, consts::MIN_RECOMMENDED_TOKIO_THREADS};
|
use common::clock::Clock;
|
||||||
use crossbeam_channel::{bounded, unbounded, Receiver, Sender, TryRecvError};
|
use crossbeam_channel::{bounded, unbounded, Receiver, Sender, TryRecvError};
|
||||||
use server::{
|
use server::{
|
||||||
persistence::{DatabaseSettings, SqlLogMode},
|
persistence::{DatabaseSettings, SqlLogMode},
|
||||||
@ -6,14 +6,14 @@ use server::{
|
|||||||
};
|
};
|
||||||
use std::{
|
use std::{
|
||||||
sync::{
|
sync::{
|
||||||
atomic::{AtomicBool, AtomicUsize, Ordering},
|
atomic::{AtomicBool, Ordering},
|
||||||
Arc,
|
Arc,
|
||||||
},
|
},
|
||||||
thread::{self, JoinHandle},
|
thread::{self, JoinHandle},
|
||||||
time::Duration,
|
time::Duration,
|
||||||
};
|
};
|
||||||
use tokio::runtime::Runtime;
|
use tokio::runtime::Runtime;
|
||||||
use tracing::{debug, error, info, trace, warn};
|
use tracing::{error, info, trace, warn};
|
||||||
|
|
||||||
const TPS: u64 = 30;
|
const TPS: u64 = 30;
|
||||||
|
|
||||||
@ -22,7 +22,7 @@ const TPS: u64 = 30;
|
|||||||
pub struct Singleplayer {
|
pub struct Singleplayer {
|
||||||
_server_thread: JoinHandle<()>,
|
_server_thread: JoinHandle<()>,
|
||||||
stop_server_s: Sender<()>,
|
stop_server_s: Sender<()>,
|
||||||
pub receiver: Receiver<Result<Arc<Runtime>, ServerError>>,
|
pub receiver: Receiver<Result<(), ServerError>>,
|
||||||
// Wether the server is stopped or not
|
// Wether the server is stopped or not
|
||||||
paused: Arc<AtomicBool>,
|
paused: Arc<AtomicBool>,
|
||||||
// Settings that the server was started with
|
// Settings that the server was started with
|
||||||
@ -30,8 +30,7 @@ pub struct Singleplayer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Singleplayer {
|
impl Singleplayer {
|
||||||
#[allow(clippy::new_without_default)]
|
pub fn new(runtime: &Arc<Runtime>) -> Self {
|
||||||
pub fn new() -> Self {
|
|
||||||
let (stop_server_s, stop_server_r) = unbounded();
|
let (stop_server_s, stop_server_r) = unbounded();
|
||||||
|
|
||||||
// Determine folder to save server data in
|
// Determine folder to save server data in
|
||||||
@ -82,22 +81,6 @@ impl Singleplayer {
|
|||||||
let settings = server::Settings::singleplayer(&server_data_dir);
|
let settings = server::Settings::singleplayer(&server_data_dir);
|
||||||
let editable_settings = server::EditableSettings::singleplayer(&server_data_dir);
|
let editable_settings = server::EditableSettings::singleplayer(&server_data_dir);
|
||||||
|
|
||||||
// TODO: evaluate std::thread::available_concurrency as a num_cpus replacement
|
|
||||||
let cores = num_cpus::get();
|
|
||||||
debug!("Creating a new runtime for server");
|
|
||||||
let runtime = Arc::new(
|
|
||||||
tokio::runtime::Builder::new_multi_thread()
|
|
||||||
.enable_all()
|
|
||||||
.worker_threads((cores / 4).max(MIN_RECOMMENDED_TOKIO_THREADS))
|
|
||||||
.thread_name_fn(|| {
|
|
||||||
static ATOMIC_ID: AtomicUsize = AtomicUsize::new(0);
|
|
||||||
let id = ATOMIC_ID.fetch_add(1, Ordering::SeqCst);
|
|
||||||
format!("tokio-sp-{}", id)
|
|
||||||
})
|
|
||||||
.build()
|
|
||||||
.unwrap(),
|
|
||||||
);
|
|
||||||
|
|
||||||
let settings2 = settings.clone();
|
let settings2 = settings.clone();
|
||||||
|
|
||||||
// Relative to data_dir
|
// Relative to data_dir
|
||||||
@ -117,39 +100,32 @@ impl Singleplayer {
|
|||||||
let (result_sender, result_receiver) = bounded(1);
|
let (result_sender, result_receiver) = bounded(1);
|
||||||
|
|
||||||
let builder = thread::Builder::new().name("singleplayer-server-thread".into());
|
let builder = thread::Builder::new().name("singleplayer-server-thread".into());
|
||||||
|
let runtime = Arc::clone(runtime);
|
||||||
let thread = builder
|
let thread = builder
|
||||||
.spawn(move || {
|
.spawn(move || {
|
||||||
trace!("starting singleplayer server thread");
|
trace!("starting singleplayer server thread");
|
||||||
let mut server = None;
|
|
||||||
if let Err(e) = result_sender.send(
|
let (server, init_result) = match Server::new(
|
||||||
match Server::new(
|
settings2,
|
||||||
settings2,
|
editable_settings,
|
||||||
editable_settings,
|
database_settings,
|
||||||
database_settings,
|
&server_data_dir,
|
||||||
&server_data_dir,
|
runtime,
|
||||||
Arc::clone(&runtime),
|
|
||||||
) {
|
|
||||||
Ok(s) => {
|
|
||||||
server = Some(s);
|
|
||||||
Ok(runtime)
|
|
||||||
},
|
|
||||||
Err(e) => Err(e),
|
|
||||||
},
|
|
||||||
) {
|
) {
|
||||||
warn!(
|
Ok(server) => (Some(server), Ok(())),
|
||||||
|
Err(err) => (None, Err(err)),
|
||||||
|
};
|
||||||
|
|
||||||
|
match (result_sender.send(init_result), server) {
|
||||||
|
(Err(e), _) => warn!(
|
||||||
?e,
|
?e,
|
||||||
"Failed to send singleplayer server initialization result. Most likely \
|
"Failed to send singleplayer server initialization result. Most likely \
|
||||||
the channel was closed by cancelling server creation. Stopping Server"
|
the channel was closed by cancelling server creation. Stopping Server"
|
||||||
);
|
),
|
||||||
return;
|
(Ok(()), None) => (),
|
||||||
};
|
(Ok(()), Some(server)) => run_server(server, stop_server_r, paused1),
|
||||||
|
}
|
||||||
|
|
||||||
let server = match server {
|
|
||||||
Some(s) => s,
|
|
||||||
None => return,
|
|
||||||
};
|
|
||||||
|
|
||||||
run_server(server, stop_server_r, paused1);
|
|
||||||
trace!("ending singleplayer server thread");
|
trace!("ending singleplayer server thread");
|
||||||
})
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
@ -398,7 +398,10 @@ pub struct Window {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Window {
|
impl Window {
|
||||||
pub fn new(settings: &Settings) -> Result<(Window, EventLoop), Error> {
|
pub fn new(
|
||||||
|
settings: &Settings,
|
||||||
|
runtime: &tokio::runtime::Runtime,
|
||||||
|
) -> Result<(Window, EventLoop), Error> {
|
||||||
let event_loop = EventLoop::new();
|
let event_loop = EventLoop::new();
|
||||||
|
|
||||||
let size = settings.graphics.window_size;
|
let size = settings.graphics.window_size;
|
||||||
@ -418,7 +421,7 @@ impl Window {
|
|||||||
|
|
||||||
let window = win_builder.build(&event_loop).unwrap();
|
let window = win_builder.build(&event_loop).unwrap();
|
||||||
|
|
||||||
let renderer = Renderer::new(&window, settings.graphics.render_mode.clone())?;
|
let renderer = Renderer::new(&window, settings.graphics.render_mode.clone(), runtime)?;
|
||||||
|
|
||||||
let keypress_map = HashMap::new();
|
let keypress_map = HashMap::new();
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user