Skip to content

Commit a3b5cc7

Browse files
committed
Bypass the network in singleplayer
1 parent b80d16c commit a3b5cc7

File tree

4 files changed

+80
-78
lines changed

4 files changed

+80
-78
lines changed

client/Cargo.toml

-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@ quinn = { workspace = true }
3535
futures-util = "0.3.1"
3636
webpki = "0.22.0"
3737
hecs = { workspace = true }
38-
rcgen = { version = "0.13.1", default-features = false, features = ["ring"] }
3938
memoffset = "0.9"
4039
gltf = { version = "1.0.0", default-features = false, features = ["utils"] }
4140
metrics = "0.23.0"

client/src/main.rs

+58-62
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,12 @@
1-
use std::{
2-
net::{SocketAddr, UdpSocket},
3-
sync::Arc,
4-
};
1+
use std::{sync::Arc, thread};
52

63
use client::{graphics, metrics, net, Config};
7-
use quinn::rustls::pki_types::{CertificateDer, PrivatePkcs8KeyDer};
4+
use common::proto;
85
use save::Save;
96

107
use ash::khr;
118
use server::Server;
12-
use tracing::{error, error_span, info};
9+
use tracing::{debug, error, error_span, info, Instrument};
1310
use winit::{
1411
application::ApplicationHandler,
1512
event_loop::{ActiveEventLoop, EventLoop},
@@ -21,62 +18,58 @@ fn main() {
2118
let metrics = crate::metrics::init();
2219

2320
let dirs = directories::ProjectDirs::from("", "", "hypermine").unwrap();
24-
let mut config = Config::load(&dirs);
25-
26-
if config.server.is_none() {
27-
// spawn an in-process server
28-
let socket =
29-
UdpSocket::bind("[::1]:0".parse::<SocketAddr>().unwrap()).expect("binding socket");
30-
config.server = Some(socket.local_addr().unwrap());
31-
32-
let certified_key = rcgen::generate_simple_self_signed(vec!["localhost".into()]).unwrap();
33-
let key = certified_key.key_pair.serialize_der();
34-
let cert = certified_key.cert.der().to_vec();
35-
let sim_cfg = config.local_simulation.clone();
36-
37-
let save = dirs.data_local_dir().join(&config.save);
38-
info!("using save file {}", save.display());
39-
std::fs::create_dir_all(save.parent().unwrap()).unwrap();
40-
let save = match Save::open(&save, config.local_simulation.chunk_size) {
41-
Ok(x) => x,
42-
Err(e) => {
43-
error!("couldn't open save: {}", e);
44-
return;
45-
}
46-
};
47-
48-
let server = match Server::new(
49-
server::NetParams {
50-
certificate_chain: vec![CertificateDer::from(cert)],
51-
private_key: PrivatePkcs8KeyDer::from(key).into(),
52-
socket,
53-
},
54-
sim_cfg,
55-
save,
56-
) {
57-
Ok(server) => server,
58-
Err(e) => {
59-
eprintln!("{e:#}");
60-
std::process::exit(1);
61-
}
62-
};
63-
64-
std::thread::spawn(move || {
65-
#[tokio::main(flavor = "current_thread")]
66-
async fn run_server(server: Server) {
67-
server.run().await;
68-
}
69-
70-
let span = error_span!("server");
71-
let _guard = span.enter();
72-
run_server(server);
73-
});
74-
}
21+
let config = Arc::new(Config::load(&dirs));
22+
23+
let net = match config.server {
24+
None => {
25+
// spawn an in-process server
26+
let sim_cfg = config.local_simulation.clone();
27+
28+
let save = dirs.data_local_dir().join(&config.save);
29+
info!("using save file {}", save.display());
30+
std::fs::create_dir_all(save.parent().unwrap()).unwrap();
31+
let save = match Save::open(&save, config.local_simulation.chunk_size) {
32+
Ok(x) => x,
33+
Err(e) => {
34+
error!("couldn't open save: {}", e);
35+
return;
36+
}
37+
};
38+
39+
let mut server = match Server::new(None, sim_cfg, save) {
40+
Ok(server) => server,
41+
Err(e) => {
42+
eprintln!("{e:#}");
43+
std::process::exit(1);
44+
}
45+
};
46+
47+
let (handle, backend) = server::Handle::loopback();
48+
let name = (*config.name).into();
49+
50+
thread::spawn(move || {
51+
let runtime = tokio::runtime::Builder::new_current_thread()
52+
.enable_time()
53+
.build()
54+
.unwrap();
55+
let _guard = runtime.enter();
56+
server
57+
.connect(proto::ClientHello { name }, backend)
58+
.unwrap();
59+
runtime.block_on(server.run().instrument(error_span!("server")));
60+
debug!("server thread terminated");
61+
});
62+
63+
handle
64+
}
65+
Some(_) => net::spawn(config.clone()),
66+
};
7567
let mut app = App {
76-
config: Arc::new(config),
68+
config,
7769
dirs,
7870
metrics,
7971
window: None,
72+
net: Some(net),
8073
};
8174

8275
let event_loop = EventLoop::new().unwrap();
@@ -89,6 +82,7 @@ struct App {
8982
dirs: directories::ProjectDirs,
9083
metrics: Arc<metrics::Recorder>,
9184
window: Option<graphics::Window>,
85+
net: Option<server::Handle>,
9286
}
9387

9488
impl ApplicationHandler for App {
@@ -98,11 +92,13 @@ impl ApplicationHandler for App {
9892
// Initialize Vulkan with the extensions needed to render to the window
9993
let core = Arc::new(graphics::Core::new(window.required_extensions()));
10094

101-
// Kick off networking
102-
let net = net::spawn(self.config.clone());
103-
10495
// Finish creating the window, including the Vulkan resources used to render to it
105-
let mut window = graphics::Window::new(window, core.clone(), self.config.clone(), net);
96+
let mut window = graphics::Window::new(
97+
window,
98+
core.clone(),
99+
self.config.clone(),
100+
self.net.take().unwrap(),
101+
);
106102

107103
// Initialize widely-shared graphics resources
108104
let gfx = Arc::new(

server/src/lib.rs

+20-13
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ pub struct Server {
3434
sim: Sim,
3535
clients: DenseSlotMap<ClientId, Client>,
3636
save: Save,
37-
endpoint: quinn::Endpoint,
37+
endpoint: Option<quinn::Endpoint>,
3838

3939
new_clients_send: mpsc::UnboundedSender<(quinn::Connection, proto::ClientHello)>,
4040
new_clients_recv: mpsc::UnboundedReceiver<(quinn::Connection, proto::ClientHello)>,
@@ -43,18 +43,23 @@ pub struct Server {
4343
}
4444

4545
impl Server {
46-
pub fn new(net: NetParams, mut cfg: SimConfig, save: Save) -> Result<Self> {
46+
pub fn new(net: Option<NetParams>, mut cfg: SimConfig, save: Save) -> Result<Self> {
4747
cfg.chunk_size = save.meta().chunk_size as u8;
48-
let server_config =
49-
quinn::ServerConfig::with_single_cert(net.certificate_chain, net.private_key)
50-
.context("parsing certificate")?;
51-
let endpoint = quinn::Endpoint::new(
52-
quinn::EndpointConfig::default(),
53-
Some(server_config),
54-
net.socket,
55-
quinn::default_runtime().unwrap(),
56-
)?;
57-
info!(address = %endpoint.local_addr().unwrap(), "listening");
48+
let endpoint = net
49+
.map(|net| {
50+
let server_config =
51+
quinn::ServerConfig::with_single_cert(net.certificate_chain, net.private_key)
52+
.context("parsing certificate")?;
53+
let endpoint = quinn::Endpoint::new(
54+
quinn::EndpointConfig::default(),
55+
Some(server_config),
56+
net.socket,
57+
quinn::default_runtime().unwrap(),
58+
)?;
59+
info!(address = %endpoint.local_addr().unwrap(), "listening");
60+
Ok::<_, Error>(endpoint)
61+
})
62+
.transpose()?;
5863

5964
let (new_clients_send, new_clients_recv) = mpsc::unbounded_channel();
6065
let (client_events_send, client_events_recv) = mpsc::channel(128);
@@ -143,7 +148,9 @@ impl Server {
143148

144149
fn handle_incoming(&self) -> mpsc::Receiver<quinn::Connection> {
145150
let (incoming_send, incoming_recv) = mpsc::channel(16);
146-
let endpoint = self.endpoint.clone();
151+
let Some(endpoint) = self.endpoint.clone() else {
152+
return incoming_recv;
153+
};
147154
tokio::spawn(async move {
148155
while let Some(conn) = endpoint.accept().await {
149156
trace!(address = %conn.remote_address(), "connection incoming");

server/src/main.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -74,11 +74,11 @@ pub async fn run() -> Result<()> {
7474
let save = Save::open(&save, sim_cfg.chunk_size)?;
7575

7676
let server = server::Server::new(
77-
server::NetParams {
77+
Some(server::NetParams {
7878
certificate_chain,
7979
private_key,
8080
socket: UdpSocket::bind(cfg.listen).context("binding socket")?,
81-
},
81+
}),
8282
sim_cfg,
8383
save,
8484
)?;

0 commit comments

Comments
 (0)