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

Use Trait for sending/receiving packets #36

Closed
wants to merge 11 commits into from
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
[workspace]
members = ["renet", "rechannel", "demo_chat/matcher", "demo_chat/chat", "demo_bevy", "renetcode", "bevy_renet", "renet_visualizer"]
members = ["renet", "rechannel", "demo_chat/matcher", "demo_chat/chat", "demo_bevy", "demo_steam", "renetcode", "bevy_renet", "renet_visualizer", "renet_transport_steam"]
resolver = "2"
2 changes: 2 additions & 0 deletions demo_chat/chat/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ edition = "2018"
matcher = { path = "../matcher" }
renet = { path = "../../renet" }
renet_visualizer = { path = "../../renet_visualizer" }
renet_transport_steam = { path = "../../renet_transport_steam" }
steamworks = { path = "../../../steamworks-rs", version = "0.9.0" }
eframe = "0.19"
egui_extras = "0.19"
serde = { version = "1.0", features = [ "derive" ] }
Expand Down
24 changes: 18 additions & 6 deletions demo_chat/chat/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ use eframe::egui;
use log::error;
use matcher::{LobbyListing, RequestConnection};
use renet::{ClientAuthentication, ConnectToken, DefaultChannel, RenetClient, RenetConnectionConfig};
use renet_transport_steam::SteamTransport;
use renet_visualizer::RenetClientVisualizer;
use steamworks::{Client, SingleClient, ClientManager};

use std::{
collections::HashMap,
Expand All @@ -30,6 +32,7 @@ pub struct UiState {
pub lobby_name: String,
pub error: Option<String>,
pub text_input: String,
pub server_addr: String,
pub show_network_info: bool,
}

Expand All @@ -54,6 +57,8 @@ pub enum AppState {

pub struct ChatApp {
state: AppState,
client: Client<ClientManager>,
single_client: SingleClient<ClientManager>,
ui_state: UiState,
last_updated: Instant,
}
Expand Down Expand Up @@ -122,10 +127,14 @@ pub fn connect_token_request(

impl Default for ChatApp {
fn default() -> Self {
let (client, single_client) = Client::init().unwrap();

Self {
state: AppState::main_screen(),
ui_state: UiState::default(),
last_updated: Instant::now(),
client,
single_client
}
}
}
Expand All @@ -135,7 +144,7 @@ impl ChatApp {
match &mut self.state {
AppState::MainScreen { lobby_list, .. } => {
let lobby_list = lobby_list.clone();
draw_main_screen(&mut self.ui_state, &mut self.state, lobby_list, ctx);
draw_main_screen(&self.client, &mut self.ui_state, &mut self.state, lobby_list, ctx);
}
AppState::RequestingToken { .. } => draw_loader(ctx),
AppState::ClientChat { client, .. } if !client.is_connected() => draw_loader(ctx),
Expand All @@ -155,6 +164,8 @@ impl ChatApp {
let duration = now - self.last_updated;
self.last_updated = now;

self.single_client.run_callbacks();

match &mut self.state {
AppState::ClientChat {
client,
Expand Down Expand Up @@ -216,7 +227,7 @@ impl ChatApp {
},
AppState::RequestingToken { token } => match token.try_recv() {
Ok(Ok(token)) => {
let client = create_renet_client_from_token(token);
let client = create_renet_client_from_token(&self.client, token);

self.state = AppState::ClientChat {
visualizer: Box::new(RenetClientVisualizer::default()),
Expand All @@ -239,13 +250,14 @@ impl ChatApp {
}
}

fn create_renet_client_from_token(connect_token: ConnectToken) -> RenetClient {
let client_addr = SocketAddr::from(([127, 0, 0, 1], 0));
let socket = UdpSocket::bind(client_addr).unwrap();
fn create_renet_client_from_token(client: &Client<ClientManager>, connect_token: ConnectToken) -> RenetClient {
// let client_addr = SocketAddr::from(([127, 0, 0, 1], 0));
// let socket = UdpSocket::bind(client_addr).unwrap();
let transport = SteamTransport::new(client);
let connection_config = RenetConnectionConfig::default();

let current_time = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap();
let authentication = ClientAuthentication::Secure { connect_token };

RenetClient::new(current_time, socket, connection_config, authentication).unwrap()
RenetClient::new(current_time, connection_config, authentication, Box::new(transport)).unwrap()
}
14 changes: 9 additions & 5 deletions demo_chat/chat/src/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ use renet_visualizer::RenetServerVisualizer;
use crate::{lobby_status::update_lobby_status, ClientMessages, Message, ServerMessages};
use bincode::Options;
use log::info;
use steamworks::{Client, SingleClient, ClientManager};
use renet_transport_steam::{address_from_steam_id, SteamTransport};

pub struct ChatServer {
pub server: RenetServer,
Expand All @@ -23,12 +25,14 @@ pub struct ChatServer {
}

impl ChatServer {
pub fn new(lobby_name: String, host_username: String, password: String) -> Self {
let socket = UdpSocket::bind("127.0.0.1:0").unwrap();
let server_addr = socket.local_addr().unwrap();
pub fn new(client: &Client<ClientManager>, lobby_name: String, host_username: String, password: String) -> Self {
// let socket = UdpSocket::bind("127.0.0.1:0").unwrap();
let transport = SteamTransport::new(client);

let server_addr = address_from_steam_id(client.user().steam_id());
let connection_config = RenetConnectionConfig::default();
let private_key = generate_random_bytes();
let server_config = ServerConfig::new(64, PROTOCOL_ID, server_addr, ServerAuthentication::Secure { private_key });
let server_config = ServerConfig::new(64, PROTOCOL_ID, server_addr, ServerAuthentication::Unsecure);

let password = if password.is_empty() { None } else { Some(password) };

Expand All @@ -41,7 +45,7 @@ impl ChatServer {
current_clients: 0,
};
let current_time = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap();
let server = RenetServer::new(current_time, server_config, connection_config, socket).unwrap();
let server = RenetServer::new(current_time, server_config, connection_config, Box::new(transport));
let mut usernames = HashMap::new();
usernames.insert(1, host_username);

Expand Down
68 changes: 62 additions & 6 deletions demo_chat/chat/src/ui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,20 @@ use eframe::{
epaint::PathShape,
};
use egui_extras::{Size, TableBuilder};
use matcher::{LobbyListing, RequestConnection};
use renet::DefaultChannel;
use matcher::{LobbyListing, RequestConnection, Username};
use renet::{ClientAuthentication, DefaultChannel, RenetClient, RenetConnectionConfig};
use renet_visualizer::RenetClientVisualizer;

use std::{collections::HashMap, sync::mpsc};
use std::{collections::HashMap, net::SocketAddr, sync::mpsc, time::SystemTime};
use steamworks::{Client, ClientManager};

use crate::{client::connect_token_request, ClientMessages};
use crate::{
client::{AppState, UiState},
server::ChatServer,
};
use matcher::PROTOCOL_ID;
use renet_transport_steam::SteamTransport;

pub fn draw_lobby_list(ui: &mut Ui, lobby_list: Vec<LobbyListing>) -> Option<(u64, bool)> {
ui.separator();
Expand Down Expand Up @@ -119,7 +123,13 @@ pub fn draw_host_commands(ui: &mut Ui, chat_server: &mut ChatServer) {
});
}

pub fn draw_main_screen(ui_state: &mut UiState, state: &mut AppState, lobby_list: Vec<LobbyListing>, ctx: &egui::Context) {
pub fn draw_main_screen(
client: &Client<ClientManager>,
ui_state: &mut UiState,
state: &mut AppState,
lobby_list: Vec<LobbyListing>,
ctx: &egui::Context,
) {
egui::CentralPanel::default().show(ctx, |ui| {
egui::Area::new("buttons")
.anchor(egui::Align2::CENTER_CENTER, egui::vec2(0.0, 0.0))
Expand Down Expand Up @@ -147,15 +157,61 @@ pub fn draw_main_screen(ui_state: &mut UiState, state: &mut AppState, lobby_list
if ui_state.username.is_empty() || ui_state.lobby_name.is_empty() {
ui_state.error = Some("Nick or Lobby name can't be empty".to_owned());
} else {
let server =
ChatServer::new(ui_state.lobby_name.clone(), ui_state.username.clone(), ui_state.password.clone());
let server = ChatServer::new(
client,
ui_state.lobby_name.clone(),
ui_state.username.clone(),
ui_state.password.clone(),
);
*state = AppState::HostChat {
chat_server: Box::new(server),
};
}
}
});

ui.separator();

ui.horizontal(|ui| {
ui.label("Server addr:");
ui.text_edit_singleline(&mut ui_state.server_addr)
});

ui.vertical_centered_justified(|ui| {
if ui.button("Connect").clicked() {
if ui_state.username.is_empty() {
ui_state.error = Some("Nick can't be empty".to_owned());
} else {
match ui_state.server_addr.parse::<SocketAddr>() {
Err(e) => ui_state.error = Some(e.to_string()),
Ok(addr) => {
let transport = SteamTransport::new(client);
let connection_config = RenetConnectionConfig::default();
let username = Username(ui_state.username.clone());

let current_time = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap();
let authentication = ClientAuthentication::Unsecure {
protocol_id: PROTOCOL_ID,
client_id: client.user().steam_id().raw(),
server_addr: addr,
user_data: Some(username.to_netcode_user_data()),
};

let client =
RenetClient::new(current_time, connection_config, authentication, Box::new(transport)).unwrap();

*state = AppState::ClientChat {
client: Box::new(client),
usernames: HashMap::new(),
messages: vec![],
visualizer: Box::new(RenetClientVisualizer::default()),
};
}
}
}
}
});

if let Some(error) = &ui_state.error {
ui.separator();
ui.colored_label(Color32::RED, format!("Error: {}", error));
Expand Down
1 change: 1 addition & 0 deletions demo_chat/chat/steam_appid.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
480
11 changes: 11 additions & 0 deletions demo_steam/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[package]
name = "demo_steam"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
renet = { path = "../renet", version = "0.0.9" }
steamworks = { path = "../../steamworks-rs", version = "0.9.0" }
renet_transport_steam = { path = "../renet_transport_steam" }
117 changes: 117 additions & 0 deletions demo_steam/src/bin/client.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
use std::{
sync::mpsc::{self, Receiver, TryRecvError},
time::{Duration, Instant, SystemTime},
};

use renet::{ClientAuthentication, ConnectToken, DefaultChannel, RenetClient, RenetConnectionConfig};
use renet_transport_steam::SteamTransport;
use steamworks::{Client, LobbyId};
use demo_steam::CONNECT_TOKEN_CHANNEL;

fn main() {
println!("Usage: cargo run --bin client -- [LOBBY_ID]");
let args: Vec<String> = std::env::args().collect();

let lobby_id = args[1].parse::<u64>().unwrap();
client(LobbyId::from_raw(lobby_id));
}

enum ClientState {
WaitingLobby,
WaitingConnectToken { lobby_id: LobbyId },
Client { client: RenetClient },
}

fn client(lobby_id: LobbyId) {
let (client, single_client) = Client::init().unwrap();

let mut state = ClientState::WaitingLobby;

let matchmaking = client.matchmaking();
let networking_messages = client.networking_messages();

let (sender_join_lobby, receiver_join_lobby) = mpsc::channel();

matchmaking.join_lobby(lobby_id, move |result| match result {
Ok(lobby) => sender_join_lobby.send(lobby).unwrap(),
Err(_) => panic!("Failed to connect lobby"),
});

let stdin_channel = spawn_stdin_channel();

let mut last_updated = Instant::now();
loop {
single_client.run_callbacks();
let now = Instant::now();
let delta = now - last_updated;
last_updated = now;
match state {
ClientState::WaitingLobby => {
if let Ok(lobby_id) = receiver_join_lobby.recv() {
state = ClientState::WaitingConnectToken { lobby_id };
}
}
ClientState::WaitingConnectToken { lobby_id } => {
for message in networking_messages.receive_messages_on_channel(CONNECT_TOKEN_CHANNEL, 1).iter() {
let data = message.data().to_vec();
if let Ok(connect_token) = ConnectToken::read(&mut data.as_slice()) {
let connection_config = RenetConnectionConfig::default();

let current_time = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap();
let authentication = ClientAuthentication::Secure { connect_token };

let mut transport = SteamTransport::new(&client);

let client_clone = client.clone();
let lobby_id_clone = lobby_id.clone();
// Only accepts request from the lobby owner.
transport.session_request_callback(move |request| {
let matchmaking = client_clone.matchmaking();
let lobby_owner = matchmaking.lobby_owner(lobby_id_clone);
if let Some(remote_user) = request.remote().steam_id() {
if remote_user == lobby_owner {
request.accept();
return;
}
}

request.reject();
});

let client = RenetClient::new(current_time, connection_config, authentication, Box::new(transport)).unwrap();
state = ClientState::Client { client };
}
}
}
ClientState::Client { ref mut client } => {
client.update(delta).unwrap();
if client.is_connected() {
match stdin_channel.try_recv() {
Ok(text) => client.send_message(DefaultChannel::Reliable, text.as_bytes().to_vec()),
Err(TryRecvError::Empty) => {}
Err(TryRecvError::Disconnected) => panic!("Channel disconnected"),
}

while let Some(text) = client.receive_message(DefaultChannel::Reliable) {
let text = String::from_utf8(text).unwrap();
println!("{}", text);
}
}

client.send_packets().unwrap();
}
}

std::thread::sleep(Duration::from_millis(50));
}
}

fn spawn_stdin_channel() -> Receiver<String> {
let (tx, rx) = mpsc::channel::<String>();
std::thread::spawn(move || loop {
let mut buffer = String::new();
std::io::stdin().read_line(&mut buffer).unwrap();
tx.send(buffer.trim_end().to_string()).unwrap();
});
rx
}
Loading