🚧 neat!

main
_ 2021-05-08 23:16:04 +00:00
parent f98d5138ff
commit 2059e5a237
7 changed files with 1030 additions and 32 deletions

756
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -11,14 +11,21 @@ edition = "2018"
anyhow = "1.0.36"
byteorder = "1.3.2"
float-ord = "0.2.0"
futures = "0.3.8"
futures-util = "0.3.9"
gl = "0.14.0"
glam = "0.8.5"
iota = "0.2.1"
maplit = "1.0.2"
partial-min-max = "0.4.0"
png = "0.15.3"
quinn = "0.7.2"
rand = "0.6.5"
rcgen = "0.8.11"
rmp-serde = "0.15.4"
serde = { version = "1.0.125", features = ["derive"] }
sdl2 = "0.32.2"
tokio = { version = "1.5.0", features = ["full"] }
tracing = "0.1.22"
tracing-subscriber = "0.2.15"

125
src/bin/quic_server.rs Normal file
View File

@ -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(())
}

View File

@ -27,6 +27,8 @@ use tracing::{
use opengl_rust::{
glezz,
gpu_buffers,
network_protocol::*,
quinn_common::make_client_endpoint,
shader,
timestep::TimeStep,
};
@ -69,7 +71,11 @@ impl ShaderLocations {
}
#[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 <()>
{
let shader_locs = &ctx.shader_locations;
@ -94,7 +100,7 @@ fn draw_graphics (ctx: &GraphicsContext, state: &GameState)
let view_mat = proj_mat *
Mat4::from_translation (Vec3::from ((0.0, 0.0, -80.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)));
let mvp = view_mat;
@ -115,10 +121,7 @@ fn draw_graphics (ctx: &GraphicsContext, state: &GameState)
let ClientArrays {
vertexes,
indexes,
} = make_heightmap_arrays (&[
(32.0, 48.0),
(32.0 + 16.0 * bump_theta.cos (), 32.0 + 16.0 * bump_theta.sin ()),
]);
} = make_heightmap_arrays (bumps);
upload_vertexes (&vertexes)?;
@ -241,7 +244,13 @@ fn upload_vertexes (vertexes: &[f32]) -> anyhow::Result <()> {
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 ()
.with_env_filter (tracing_subscriber::EnvFilter::from_default_env())
.with_span_events (tracing_subscriber::fmt::format::FmtSpan::CLOSE)
@ -314,26 +323,86 @@ fn main () -> anyhow::Result <()> {
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 {
let frames_to_do = time_step.step ();
let _mouse = event_pump.mouse_state ();
let mut cmd = NetworkCommand::default ();
for event in event_pump.poll_iter() {
match event {
Event::Quit {..} |
Event::KeyDown { keycode: Some (Keycode::Escape), .. } => {
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 {
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;
std::thread::sleep (Duration::from_millis (15));

View File

@ -8,7 +8,9 @@ pub mod file;
pub mod glezz;
pub mod gl_state;
pub mod gpu_buffers;
pub mod network_protocol;
pub mod physics;
pub mod quinn_common;
pub mod renderable_model;
pub mod shader;
pub mod shader_closure;

14
src/network_protocol.rs Normal file
View File

@ -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,
}

73
src/quinn_common.rs Normal file
View File

@ -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"];