🚧 neat!
parent
f98d5138ff
commit
2059e5a237
File diff suppressed because it is too large
Load Diff
|
@ -11,14 +11,21 @@ edition = "2018"
|
||||||
anyhow = "1.0.36"
|
anyhow = "1.0.36"
|
||||||
byteorder = "1.3.2"
|
byteorder = "1.3.2"
|
||||||
float-ord = "0.2.0"
|
float-ord = "0.2.0"
|
||||||
|
futures = "0.3.8"
|
||||||
|
futures-util = "0.3.9"
|
||||||
gl = "0.14.0"
|
gl = "0.14.0"
|
||||||
glam = "0.8.5"
|
glam = "0.8.5"
|
||||||
iota = "0.2.1"
|
iota = "0.2.1"
|
||||||
maplit = "1.0.2"
|
maplit = "1.0.2"
|
||||||
partial-min-max = "0.4.0"
|
partial-min-max = "0.4.0"
|
||||||
png = "0.15.3"
|
png = "0.15.3"
|
||||||
|
quinn = "0.7.2"
|
||||||
rand = "0.6.5"
|
rand = "0.6.5"
|
||||||
|
rcgen = "0.8.11"
|
||||||
|
rmp-serde = "0.15.4"
|
||||||
|
serde = { version = "1.0.125", features = ["derive"] }
|
||||||
sdl2 = "0.32.2"
|
sdl2 = "0.32.2"
|
||||||
|
tokio = { version = "1.5.0", features = ["full"] }
|
||||||
tracing = "0.1.22"
|
tracing = "0.1.22"
|
||||||
tracing-subscriber = "0.2.15"
|
tracing-subscriber = "0.2.15"
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,125 @@
|
||||||
|
use std::{
|
||||||
|
sync::Arc,
|
||||||
|
};
|
||||||
|
|
||||||
|
use futures::StreamExt;
|
||||||
|
use tokio::sync::Mutex;
|
||||||
|
|
||||||
|
use opengl_rust::{
|
||||||
|
network_protocol::*,
|
||||||
|
quinn_common::make_server_endpoint,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main () -> anyhow::Result <()> {
|
||||||
|
let server_addr = "127.0.0.1:5000".parse().unwrap();
|
||||||
|
let (mut incoming, server_cert) = make_server_endpoint(server_addr)?;
|
||||||
|
|
||||||
|
let state = NetworkedState {
|
||||||
|
positions: vec! [
|
||||||
|
(32.0, 32.0),
|
||||||
|
],
|
||||||
|
};
|
||||||
|
let state = Arc::new (Mutex::new (state));
|
||||||
|
// let connected_players = Arc::new (Mutex::new (vec! []));
|
||||||
|
|
||||||
|
// accept a single connection
|
||||||
|
let server_task = tokio::spawn (async move {
|
||||||
|
use opengl_rust::timestep::TimeStep;
|
||||||
|
|
||||||
|
let incoming_conn = incoming.next().await.unwrap();
|
||||||
|
let new_conn = incoming_conn.await.unwrap();
|
||||||
|
println!(
|
||||||
|
"[server] connection accepted: addr={}",
|
||||||
|
new_conn.connection.remote_address()
|
||||||
|
);
|
||||||
|
|
||||||
|
let quinn::NewConnection {
|
||||||
|
connection,
|
||||||
|
mut datagrams,
|
||||||
|
..
|
||||||
|
} = new_conn;
|
||||||
|
|
||||||
|
let mut i = 0_u64;
|
||||||
|
|
||||||
|
let cmd = Arc::new (Mutex::new (NetworkCommand::default ()));
|
||||||
|
let cmd_2 = Arc::clone (&cmd);
|
||||||
|
|
||||||
|
// Read player commands
|
||||||
|
tokio::spawn (async move {
|
||||||
|
while let Some (Ok (datagram)) = datagrams.next ().await {
|
||||||
|
let cmd: NetworkCommand = rmp_serde::from_slice (&datagram)?;
|
||||||
|
let mut guard = cmd_2.lock ().await;
|
||||||
|
*guard = cmd;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok::<_, anyhow::Error> (())
|
||||||
|
});
|
||||||
|
|
||||||
|
let mut time_step = TimeStep::new (120, 1000);
|
||||||
|
let mut state = NetworkedState {
|
||||||
|
positions: vec! [
|
||||||
|
(32.0, 32.0),
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let cmd = {
|
||||||
|
let guard = cmd.lock ().await;
|
||||||
|
guard.clone ()
|
||||||
|
};
|
||||||
|
let frames_to_do = time_step.step ();
|
||||||
|
for _ in 0..frames_to_do {
|
||||||
|
let speed = 0.25;
|
||||||
|
if cmd.left {
|
||||||
|
state.positions [0].0 -= speed;
|
||||||
|
}
|
||||||
|
if cmd.right {
|
||||||
|
state.positions [0].0 += speed;
|
||||||
|
}
|
||||||
|
if cmd.up {
|
||||||
|
state.positions [0].1 += speed;
|
||||||
|
}
|
||||||
|
if cmd.down {
|
||||||
|
state.positions [0].1 -= speed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let bytes = rmp_serde::to_vec (&state)?;
|
||||||
|
connection.send_datagram (bytes.into ())?;
|
||||||
|
|
||||||
|
i += 1;
|
||||||
|
tokio::time::sleep (std::time::Duration::from_millis(16)).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dropping all handles associated with a connection implicitly closes it
|
||||||
|
Ok::<_, anyhow::Error> (())
|
||||||
|
});
|
||||||
|
|
||||||
|
tokio::fs::write ("quic_server.crt", &server_cert).await?;
|
||||||
|
|
||||||
|
/*
|
||||||
|
let endpoint = make_client_endpoint("0.0.0.0:0".parse().unwrap(), &[&server_cert])?;
|
||||||
|
// connect to server
|
||||||
|
let quinn::NewConnection {
|
||||||
|
connection,
|
||||||
|
mut uni_streams,
|
||||||
|
..
|
||||||
|
} = endpoint
|
||||||
|
.connect(&server_addr, "localhost")
|
||||||
|
.unwrap()
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
println!("[client] connected: addr={}", connection.remote_address());
|
||||||
|
|
||||||
|
// Waiting for a stream will complete with an error when the server closes the connection
|
||||||
|
let _ = uni_streams.next().await;
|
||||||
|
|
||||||
|
// Give the server has a chance to clean up
|
||||||
|
endpoint.wait_idle().await;
|
||||||
|
*/
|
||||||
|
|
||||||
|
server_task.await??;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
|
@ -27,6 +27,8 @@ use tracing::{
|
||||||
use opengl_rust::{
|
use opengl_rust::{
|
||||||
glezz,
|
glezz,
|
||||||
gpu_buffers,
|
gpu_buffers,
|
||||||
|
network_protocol::*,
|
||||||
|
quinn_common::make_client_endpoint,
|
||||||
shader,
|
shader,
|
||||||
timestep::TimeStep,
|
timestep::TimeStep,
|
||||||
};
|
};
|
||||||
|
@ -69,7 +71,11 @@ impl ShaderLocations {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument (level = "trace", skip (ctx, state))]
|
#[instrument (level = "trace", skip (ctx, state))]
|
||||||
fn draw_graphics (ctx: &GraphicsContext, state: &GameState)
|
fn draw_graphics (
|
||||||
|
ctx: &GraphicsContext,
|
||||||
|
state: &GameState,
|
||||||
|
bumps: &[(f32, f32)],
|
||||||
|
)
|
||||||
-> anyhow::Result <()>
|
-> anyhow::Result <()>
|
||||||
{
|
{
|
||||||
let shader_locs = &ctx.shader_locations;
|
let shader_locs = &ctx.shader_locations;
|
||||||
|
@ -94,7 +100,7 @@ fn draw_graphics (ctx: &GraphicsContext, state: &GameState)
|
||||||
let view_mat = proj_mat *
|
let view_mat = proj_mat *
|
||||||
Mat4::from_translation (Vec3::from ((0.0, 0.0, -80.0))) *
|
Mat4::from_translation (Vec3::from ((0.0, 0.0, -80.0))) *
|
||||||
Mat4::from_rotation_x (-60.0 * 3.14159 / 180.0) *
|
Mat4::from_rotation_x (-60.0 * 3.14159 / 180.0) *
|
||||||
Mat4::from_rotation_z ((state.logic_frames % spin_period) as f32 * 3.1415926535 * 2.0 / spin_period as f32) *
|
// Mat4::from_rotation_z ((state.logic_frames % spin_period) as f32 * 3.1415926535 * 2.0 / spin_period as f32) *
|
||||||
Mat4::from_translation (Vec3::from ((-32.0, -32.0, -5.0)));
|
Mat4::from_translation (Vec3::from ((-32.0, -32.0, -5.0)));
|
||||||
|
|
||||||
let mvp = view_mat;
|
let mvp = view_mat;
|
||||||
|
@ -115,10 +121,7 @@ fn draw_graphics (ctx: &GraphicsContext, state: &GameState)
|
||||||
let ClientArrays {
|
let ClientArrays {
|
||||||
vertexes,
|
vertexes,
|
||||||
indexes,
|
indexes,
|
||||||
} = make_heightmap_arrays (&[
|
} = make_heightmap_arrays (bumps);
|
||||||
(32.0, 48.0),
|
|
||||||
(32.0 + 16.0 * bump_theta.cos (), 32.0 + 16.0 * bump_theta.sin ()),
|
|
||||||
]);
|
|
||||||
|
|
||||||
upload_vertexes (&vertexes)?;
|
upload_vertexes (&vertexes)?;
|
||||||
|
|
||||||
|
@ -241,7 +244,13 @@ fn upload_vertexes (vertexes: &[f32]) -> anyhow::Result <()> {
|
||||||
Ok (())
|
Ok (())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main () -> anyhow::Result <()> {
|
#[tokio::main]
|
||||||
|
async fn main () -> anyhow::Result <()> {
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use futures_util::StreamExt;
|
||||||
|
use tokio::sync::Mutex;
|
||||||
|
|
||||||
tracing_subscriber::fmt::fmt ()
|
tracing_subscriber::fmt::fmt ()
|
||||||
.with_env_filter (tracing_subscriber::EnvFilter::from_default_env())
|
.with_env_filter (tracing_subscriber::EnvFilter::from_default_env())
|
||||||
.with_span_events (tracing_subscriber::fmt::format::FmtSpan::CLOSE)
|
.with_span_events (tracing_subscriber::fmt::format::FmtSpan::CLOSE)
|
||||||
|
@ -314,26 +323,86 @@ fn main () -> anyhow::Result <()> {
|
||||||
logic_frames: 0,
|
logic_frames: 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let server_cert = tokio::fs::read ("quic_server.crt").await?;
|
||||||
|
let server_addr = "127.0.0.1:5000".parse().unwrap();
|
||||||
|
let endpoint = make_client_endpoint("0.0.0.0:0".parse().unwrap(), &[&server_cert])?;
|
||||||
|
// connect to server
|
||||||
|
let quinn::NewConnection {
|
||||||
|
connection,
|
||||||
|
mut datagrams,
|
||||||
|
..
|
||||||
|
} = endpoint
|
||||||
|
.connect(&server_addr, "localhost")
|
||||||
|
.unwrap()
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
println!("[client] connected: addr={}", connection.remote_address());
|
||||||
|
|
||||||
|
let networked_state = Arc::new (Mutex::new (NetworkedState::default ()));
|
||||||
|
let networked_state_2 = Arc::clone (&networked_state);
|
||||||
|
|
||||||
|
tokio::spawn (async move {
|
||||||
|
while let Some (Ok (datagram)) = datagrams.next ().await {
|
||||||
|
let state = rmp_serde::from_slice (&datagram)?;
|
||||||
|
let mut guard = networked_state_2.lock ().await;
|
||||||
|
*guard = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok::<_, anyhow::Error> (())
|
||||||
|
});
|
||||||
|
|
||||||
'running: loop {
|
'running: loop {
|
||||||
let frames_to_do = time_step.step ();
|
let frames_to_do = time_step.step ();
|
||||||
|
|
||||||
let _mouse = event_pump.mouse_state ();
|
let _mouse = event_pump.mouse_state ();
|
||||||
|
|
||||||
|
let mut cmd = NetworkCommand::default ();
|
||||||
|
|
||||||
for event in event_pump.poll_iter() {
|
for event in event_pump.poll_iter() {
|
||||||
match event {
|
match event {
|
||||||
Event::Quit {..} |
|
Event::Quit {..} |
|
||||||
Event::KeyDown { keycode: Some (Keycode::Escape), .. } => {
|
Event::KeyDown { keycode: Some (Keycode::Escape), .. } => {
|
||||||
break 'running
|
break 'running
|
||||||
},
|
},
|
||||||
|
Event::KeyDown { keycode: Some (keycode), .. } => {
|
||||||
|
match keycode {
|
||||||
|
Keycode::Left => cmd.left = true,
|
||||||
|
Keycode::Right => cmd.right = true,
|
||||||
|
Keycode::Up => cmd.up = true,
|
||||||
|
Keycode::Down => cmd.right = true,
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
},
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let keyboard_state = event_pump.keyboard_state ();
|
||||||
|
if keyboard_state.is_scancode_pressed (Scancode::Left) {
|
||||||
|
cmd.left = true
|
||||||
|
}
|
||||||
|
if keyboard_state.is_scancode_pressed (Scancode::Right) {
|
||||||
|
cmd.right = true
|
||||||
|
}
|
||||||
|
if keyboard_state.is_scancode_pressed (Scancode::Up) {
|
||||||
|
cmd.up = true
|
||||||
|
}
|
||||||
|
if keyboard_state.is_scancode_pressed (Scancode::Down) {
|
||||||
|
cmd.down = true
|
||||||
|
}
|
||||||
|
|
||||||
|
let bytes = rmp_serde::to_vec (&cmd)?;
|
||||||
|
connection.send_datagram (bytes.into ())?;
|
||||||
|
|
||||||
for _ in 0..frames_to_do {
|
for _ in 0..frames_to_do {
|
||||||
game_state.logic_frames += 1;
|
game_state.logic_frames += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
draw_graphics (&graphics_ctx, &game_state)?;
|
let state = {
|
||||||
|
let guard = networked_state.lock ().await;
|
||||||
|
guard.clone ()
|
||||||
|
};
|
||||||
|
draw_graphics (&graphics_ctx, &game_state, &state.positions)?;
|
||||||
graphics_frames += 1;
|
graphics_frames += 1;
|
||||||
|
|
||||||
std::thread::sleep (Duration::from_millis (15));
|
std::thread::sleep (Duration::from_millis (15));
|
||||||
|
|
|
@ -8,7 +8,9 @@ pub mod file;
|
||||||
pub mod glezz;
|
pub mod glezz;
|
||||||
pub mod gl_state;
|
pub mod gl_state;
|
||||||
pub mod gpu_buffers;
|
pub mod gpu_buffers;
|
||||||
|
pub mod network_protocol;
|
||||||
pub mod physics;
|
pub mod physics;
|
||||||
|
pub mod quinn_common;
|
||||||
pub mod renderable_model;
|
pub mod renderable_model;
|
||||||
pub mod shader;
|
pub mod shader;
|
||||||
pub mod shader_closure;
|
pub mod shader_closure;
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[derive (Clone, Default, Deserialize, Serialize)]
|
||||||
|
pub struct NetworkedState {
|
||||||
|
pub positions: Vec <(f32, f32)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive (Clone, Default, Deserialize, Serialize)]
|
||||||
|
pub struct NetworkCommand {
|
||||||
|
pub left: bool,
|
||||||
|
pub right: bool,
|
||||||
|
pub up: bool,
|
||||||
|
pub down: bool,
|
||||||
|
}
|
|
@ -0,0 +1,73 @@
|
||||||
|
use quinn::{
|
||||||
|
Certificate, CertificateChain, ClientConfig, ClientConfigBuilder, Endpoint, Incoming,
|
||||||
|
PrivateKey, ServerConfig, ServerConfigBuilder, TransportConfig,
|
||||||
|
};
|
||||||
|
use std::{error::Error, net::SocketAddr, sync::Arc};
|
||||||
|
|
||||||
|
/// Constructs a QUIC endpoint configured for use a client only.
|
||||||
|
///
|
||||||
|
/// ## Args
|
||||||
|
///
|
||||||
|
/// - server_certs: list of trusted certificates.
|
||||||
|
#[allow(unused)]
|
||||||
|
pub fn make_client_endpoint(
|
||||||
|
bind_addr: SocketAddr,
|
||||||
|
server_certs: &[&[u8]],
|
||||||
|
) -> anyhow::Result<Endpoint> {
|
||||||
|
let client_cfg = configure_client(server_certs)?;
|
||||||
|
let mut endpoint_builder = Endpoint::builder();
|
||||||
|
endpoint_builder.default_client_config(client_cfg);
|
||||||
|
let (endpoint, _incoming) = endpoint_builder.bind(&bind_addr)?;
|
||||||
|
Ok(endpoint)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Constructs a QUIC endpoint configured to listen for incoming connections on a certain address
|
||||||
|
/// and port.
|
||||||
|
///
|
||||||
|
/// ## Returns
|
||||||
|
///
|
||||||
|
/// - a stream of incoming QUIC connections
|
||||||
|
/// - server certificate serialized into DER format
|
||||||
|
#[allow(unused)]
|
||||||
|
pub fn make_server_endpoint(bind_addr: SocketAddr) -> anyhow::Result<(Incoming, Vec<u8>)> {
|
||||||
|
let (server_config, server_cert) = configure_server()?;
|
||||||
|
let mut endpoint_builder = Endpoint::builder();
|
||||||
|
endpoint_builder.listen(server_config);
|
||||||
|
let (_endpoint, incoming) = endpoint_builder.bind(&bind_addr)?;
|
||||||
|
Ok((incoming, server_cert))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Builds default quinn client config and trusts given certificates.
|
||||||
|
///
|
||||||
|
/// ## Args
|
||||||
|
///
|
||||||
|
/// - server_certs: a list of trusted certificates in DER format.
|
||||||
|
fn configure_client(server_certs: &[&[u8]]) -> anyhow::Result<ClientConfig> {
|
||||||
|
let mut cfg_builder = ClientConfigBuilder::default();
|
||||||
|
for cert in server_certs {
|
||||||
|
cfg_builder.add_certificate_authority(Certificate::from_der(&cert)?)?;
|
||||||
|
}
|
||||||
|
Ok(cfg_builder.build())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns default server configuration along with its certificate.
|
||||||
|
#[allow(clippy::field_reassign_with_default)] // https://github.com/rust-lang/rust-clippy/issues/6527
|
||||||
|
fn configure_server() -> anyhow::Result<(ServerConfig, Vec<u8>)> {
|
||||||
|
let cert = rcgen::generate_simple_self_signed(vec!["localhost".into()]).unwrap();
|
||||||
|
let cert_der = cert.serialize_der().unwrap();
|
||||||
|
let priv_key = cert.serialize_private_key_der();
|
||||||
|
let priv_key = PrivateKey::from_der(&priv_key)?;
|
||||||
|
|
||||||
|
let mut transport_config = TransportConfig::default();
|
||||||
|
transport_config.max_concurrent_uni_streams(0).unwrap();
|
||||||
|
let mut server_config = ServerConfig::default();
|
||||||
|
server_config.transport = Arc::new(transport_config);
|
||||||
|
let mut cfg_builder = ServerConfigBuilder::new(server_config);
|
||||||
|
let cert = Certificate::from_der(&cert_der)?;
|
||||||
|
cfg_builder.certificate(CertificateChain::from_certs(vec![cert]), priv_key)?;
|
||||||
|
|
||||||
|
Ok((cfg_builder.build(), cert_der))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
|
pub const ALPN_QUIC_HTTP: &[&[u8]] = &[b"hq-29"];
|
Loading…
Reference in New Issue