Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: implement p2p based networking using iroh-net #404

Merged
merged 19 commits into from
May 17, 2024
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3,029 changes: 2,820 additions & 209 deletions Cargo.lock

Large diffs are not rendered by default.

5 changes: 3 additions & 2 deletions framework_crates/bones_framework/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -129,5 +129,6 @@ postcard = { version = "1.0", features = ["alloc"] }
rcgen = "0.12"
rustls = { version = "0.21", features = ["dangerous_configuration", "quic"] }
smallvec = "1.10"
quinn = { version = "0.10", default-features = false, features = ["native-certs", "tls-rustls"] }
quinn_runtime_bevy = { version = "0.3", path = "../../other_crates/quinn_runtime_bevy" }
iroh-quinn = { version = "0.10" }
iroh-net = { version = "0.16" }
tokio = { version = "1", features = ["full"] }
77 changes: 35 additions & 42 deletions framework_crates/bones_framework/src/networking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

use std::{fmt::Debug, marker::PhantomData, sync::Arc};

use bones_matchmaker_proto::{MATCH_ALPN, PLAY_ALPN};
use ggrs::{NetworkStats, P2PSession, PlayerHandle};
use instant::Duration;
use once_cell::sync::Lazy;
Expand All @@ -15,12 +16,16 @@ use self::{
};
use crate::input::PlayerControls as PlayerControlsTrait;

pub mod certs;
pub mod debug;
pub mod input;
pub mod lan;
pub mod online;
pub mod proto;
pub mod socket;

/// Runtime, needed to execute network related calls.
pub static RUNTIME: Lazy<tokio::runtime::Runtime> =
Lazy::new(|| tokio::runtime::Runtime::new().expect("unable to crate tokio runtime"));

/// Indicates if input from networking is confirmed, predicted, or if player is disconnected.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
Expand All @@ -45,7 +50,7 @@ impl From<ggrs::InputStatus> for NetworkInputStatus {

/// Module prelude.
pub mod prelude {
pub use super::{certs, debug::prelude::*, input, lan, online, proto, NetworkInfo};
pub use super::{debug::prelude::*, input, lan, online, proto, NetworkInfo, RUNTIME};
}

/// Muliplier for framerate that will be used when playing an online match.
Expand All @@ -66,12 +71,8 @@ pub const NETWORK_MAX_PREDICTION_WINDOW_DEFAULT: usize = 7;
/// Amount of frames GGRS will delay local input.
pub const NETWORK_LOCAL_INPUT_DELAY_DEFAULT: usize = 2;

// TODO: Remove this limitation on max players, a variety of types use this for static arrays,
// should either figure out how to make this a compile-time const value specified by game, or
// use dynamic arrays.
//
/// Max players in networked game
pub const MAX_PLAYERS: usize = 4;
#[doc(inline)]
pub use bones_matchmaker_proto::MAX_PLAYERS;

/// Possible errors returned by network loop.
pub enum NetworkError {
Expand All @@ -92,40 +93,32 @@ impl<T: DenseInput + Debug> ggrs::Config for GgrsConfig<T> {
type Address = usize;
}

/// The network endpoint used for all QUIC network communications.
pub static NETWORK_ENDPOINT: Lazy<quinn::Endpoint> = Lazy::new(|| {
// Generate certificate
let (cert, key) = certs::generate_self_signed_cert().unwrap();

let mut transport_config = quinn::TransportConfig::default();
transport_config.keep_alive_interval(Some(std::time::Duration::from_secs(5)));

let mut server_config = quinn::ServerConfig::with_single_cert([cert].to_vec(), key).unwrap();
server_config.transport = Arc::new(transport_config);

// Open Socket and create endpoint
let port = THREAD_RNG.with(|rng| rng.u16(10000..=11000));
info!(port, "Started network endpoint");
let socket = std::net::UdpSocket::bind(("0.0.0.0", port)).unwrap();

let client_config = rustls::ClientConfig::builder()
.with_safe_defaults()
.with_custom_certificate_verifier(certs::SkipServerVerification::new())
.with_no_client_auth();
let client_config = quinn::ClientConfig::new(Arc::new(client_config));

let mut endpoint = quinn::Endpoint::new(
quinn::EndpointConfig::default(),
Some(server_config),
socket,
Arc::new(quinn_runtime_bevy::BevyIoTaskPoolExecutor),
)
.unwrap();

endpoint.set_default_client_config(client_config);

endpoint
});
/// The network endpoint used for all network communications.
static NETWORK_ENDPOINT: tokio::sync::OnceCell<iroh_net::MagicEndpoint> =
tokio::sync::OnceCell::const_new();

/// Get the network endpoint used for all communications.
pub async fn get_network_endpoint() -> &'static iroh_net::MagicEndpoint {
NETWORK_ENDPOINT
.get_or_init(|| async move {
let secret_key = iroh_net::key::SecretKey::generate();
iroh_net::MagicEndpoint::builder()
.alpns(vec![MATCH_ALPN.to_vec(), PLAY_ALPN.to_vec()])
.discovery(Box::new(
iroh_net::discovery::ConcurrentDiscovery::from_services(vec![
Box::new(iroh_net::discovery::dns::DnsDiscovery::n0_dns()),
Box::new(iroh_net::discovery::pkarr_publish::PkarrPublisher::n0_dns(
secret_key.clone(),
)),
]),
))
.secret_key(secret_key)
.bind(0)
.await
.unwrap()
})
.await
}

/// Resource containing the [`NetworkSocket`] implementation while there is a connection to a
/// network game.
Expand Down
40 changes: 0 additions & 40 deletions framework_crates/bones_framework/src/networking/certs.rs

This file was deleted.

Loading
Loading