WIP steam networking

This commit is contained in:
IQuant 2024-05-17 17:55:50 +03:00
parent 7a0efd4a9c
commit 07c98b4f57
7 changed files with 614 additions and 33 deletions

View file

@ -37,9 +37,14 @@ function net.init()
}
end
elseif string.byte(msg, 1, 1) == 1 then
local peer_id_l, peer_id_h = string.byte(msg, 2, 3)
local peer_id = peer_id_l + peer_id_h * 256
local msg_l = string.sub(msg, 4)
local peer_id_b = {string.byte(msg, 2, 2+8-1)}
local mult = 1
local peer_id = 0
for _, b in ipairs(peer_id_b) do
peer_id = peer_id + b * mult
mult = mult * 256
end
local msg_l = string.sub(msg, 2+8)
local success, item = pcall(bitser.loads, msg_l)
if success then
msg_decoded = {

View file

@ -30,7 +30,7 @@ local function send_pending()
table.insert(will_send, packet)
end
if #will_send > 0 then
-- GamePrint(#will_send.." "..total_len)
-- GamePrint(#pending_send_wd.." "..#will_send.." "..total_len)
ctx.lib.net.send_world_data(will_send)
end
end

84
noita-proxy/Cargo.lock generated
View file

@ -90,7 +90,7 @@ version = "3.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9fb4009533e8ff8f1450a5bcbc30f4242a1d34442221f72314bea1f5dc9c7f89"
dependencies = [
"clipboard-win",
"clipboard-win 5.3.1",
"log",
"objc2 0.5.1",
"objc2-app-kit",
@ -313,6 +313,28 @@ dependencies = [
"libc",
]
[[package]]
name = "clipboard"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "25a904646c0340239dcf7c51677b33928bf24fdf424b79a57909c0109075b2e7"
dependencies = [
"clipboard-win 2.2.0",
"objc",
"objc-foundation",
"objc_id",
"x11-clipboard",
]
[[package]]
name = "clipboard-win"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3a093d6fed558e5fe24c3dfc85a68bb68f1c824f440d3ba5aca189e2998786b"
dependencies = [
"winapi",
]
[[package]]
name = "clipboard-win"
version = "5.3.1"
@ -1225,10 +1247,13 @@ name = "noita-proxy"
version = "0.1.0"
dependencies = [
"bitcode",
"clipboard",
"crossbeam",
"eframe",
"lz4_flex",
"rand",
"serde",
"steamworks",
"tangled",
"tracing",
"tracing-subscriber",
@ -1284,6 +1309,17 @@ dependencies = [
"malloc_buf",
]
[[package]]
name = "objc-foundation"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1add1b659e36c9607c7aab864a76c7a4c2760cd0cd2e120f3fb8b952c7e22bf9"
dependencies = [
"block",
"objc",
"objc_id",
]
[[package]]
name = "objc-sys"
version = "0.3.3"
@ -1355,6 +1391,15 @@ dependencies = [
"objc2 0.5.1",
]
[[package]]
name = "objc_id"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c92d4ddb4bd7b50d730c215ff871754d0da6b2178849f8a2a2ab69712d0c073b"
dependencies = [
"objc",
]
[[package]]
name = "once_cell"
version = "1.19.0"
@ -1787,6 +1832,24 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
[[package]]
name = "steamworks"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a79d6f059322f73a4586cc2d0ca595ce1583104b2b1574ae1bb87f2c05bf4c67"
dependencies = [
"bitflags 1.3.2",
"lazy_static",
"steamworks-sys",
"thiserror",
]
[[package]]
name = "steamworks-sys"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ef6b00f8fe8eaaaff22cb9b70822a48c1a5d772bc682c202a57c0b438175845"
[[package]]
name = "syn"
version = "2.0.60"
@ -2563,6 +2626,15 @@ dependencies = [
"memchr",
]
[[package]]
name = "x11-clipboard"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89bd49c06c9eb5d98e6ba6536cf64ac9f7ee3a009b2f53996d405b3944f6bcea"
dependencies = [
"xcb",
]
[[package]]
name = "x11-dl"
version = "2.21.0"
@ -2595,6 +2667,16 @@ version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e63e71c4b8bd9ffec2c963173a4dc4cbde9ee96961d4fcb4429db9929b606c34"
[[package]]
name = "xcb"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e917a3f24142e9ff8be2414e36c649d47d6cc2ba81f16201cdef96e533e02de"
dependencies = [
"libc",
"log",
]
[[package]]
name = "xcursor"
version = "0.3.5"

View file

@ -18,6 +18,9 @@ serde = { version = "1.0.199", features = ["serde_derive"] }
bitcode = "0.6.0"
lz4_flex = { version = "0.11.3", default_features = false, features = ["std"]}
rand = "0.8.5"
steamworks = "0.11.0"
crossbeam = { version = "0.8.4", features = ["crossbeam-channel"] }
clipboard = "0.5.0"
[profile.dev]
opt-level = 1

View file

@ -1,8 +1,12 @@
use std::{net::SocketAddr, sync::Arc, time::Duration};
use std::{fmt::Display, net::SocketAddr, sync::Arc, thread, time::Duration};
use bitcode::{Decode, Encode};
use clipboard::{ClipboardContext, ClipboardProvider};
use eframe::egui::{self, Color32};
use serde::de::Error;
use steamworks::{LobbyId, SteamAPIInitError};
use tangled::Peer;
use tracing::info;
pub mod messages;
@ -17,10 +21,30 @@ pub mod net;
enum AppState {
Init,
Netman { netman: Arc<net::NetManager> },
Error { message: String },
}
struct SteamState {
pub client: steamworks::Client,
}
impl SteamState {
fn new() -> Result<Self, SteamAPIInitError> {
let (client, single) = steamworks::Client::init_app(480)?;
thread::spawn(move || {
info!("Spawned steam callback thread");
loop {
single.run_callbacks();
thread::sleep(Duration::from_millis(3));
}
});
Ok(SteamState { client })
}
}
pub struct App {
state: AppState,
steam_state: Result<SteamState, SteamAPIInitError>,
addr: String,
debug_mode: bool,
use_constant_seed: bool,
@ -30,23 +54,52 @@ impl App {
fn start_server(&mut self) {
let bind_addr = "0.0.0.0:5123".parse().unwrap();
let peer = Peer::host(bind_addr, None).unwrap();
let netman = net::NetManager::new(peer);
{
let netman = net::NetManager::new(net::PeerVariant::Tangled(peer));
self.set_netman_settings(&netman);
netman.clone().start();
self.state = AppState::Netman { netman };
}
fn set_netman_settings(&mut self, netman: &Arc<net::NetManager>) {
let mut settings = netman.settings.lock().unwrap();
settings.debug_mode = self.debug_mode;
if !self.use_constant_seed {
settings.seed = rand::random();
}
}
netman
.accept_local
.store(true, std::sync::atomic::Ordering::SeqCst);
netman.clone().start();
self.state = AppState::Netman { netman };
}
fn start_connect(&mut self, addr: SocketAddr) {
let peer = Peer::connect(addr, None).unwrap();
let netman = net::NetManager::new(peer);
let netman = net::NetManager::new(net::PeerVariant::Tangled(peer));
netman.clone().start();
self.state = AppState::Netman { netman };
}
fn start_steam_host(&mut self) {
let peer = net::steam_networking::SteamPeer::new_host(
steamworks::LobbyType::Private,
self.steam_state.as_ref().unwrap().client.clone(),
);
let netman = net::NetManager::new(net::PeerVariant::Steam(peer));
self.set_netman_settings(&netman);
netman.clone().start();
self.state = AppState::Netman { netman };
}
fn notify_error(&mut self, error: impl Display) {
self.state = AppState::Error {
message: error.to_string(),
}
}
fn start_steam_connect(&mut self, id: LobbyId) {
let peer = net::steam_networking::SteamPeer::new_connect(
id,
self.steam_state.as_ref().unwrap().client.clone(),
);
let netman = net::NetManager::new(net::PeerVariant::Steam(peer));
netman.clone().start();
self.state = AppState::Netman { netman };
}
@ -54,11 +107,13 @@ impl App {
impl Default for App {
fn default() -> Self {
info!("Creating the app...");
Self {
state: AppState::Init,
addr: "192.168.1.168:5123".to_string(),
debug_mode: false,
use_constant_seed: false,
steam_state: SteamState::new(),
}
}
}
@ -85,6 +140,32 @@ impl eframe::App for App {
}
}
});
ui.separator();
ui.heading("Steam networking");
match &self.steam_state {
Ok(_) => {
if ui.button("Create lobby").clicked() {
self.start_steam_host();
}
if ui.button("Connect to lobby in clipboard").clicked() {
let id = ClipboardProvider::new()
.and_then(|mut ctx: ClipboardContext| ctx.get_contents());
match id {
Ok(id) => {
let id = id.parse().map(LobbyId::from_raw);
match id {
Ok(id) => self.start_steam_connect(id),
Err(error) => self.notify_error(error),
}
}
Err(error) => self.notify_error(error),
}
}
}
Err(err) => {
ui.label(format!("Could not init steam networking: {}", err));
}
}
});
}
AppState::Netman { netman } => {
@ -105,13 +186,33 @@ impl eframe::App for App {
ui.label("Not yet ready");
}
ui.separator();
if let Some(id) = netman.peer.lobby_id() {
if ui.button("Save lobby id to clipboard").clicked() {
let mut ctx: ClipboardContext = ClipboardProvider::new().unwrap();
let _ = ctx.set_contents(id.raw().to_string());
}
} else {
ui.label("Lobby id not available");
}
ui.heading("Current users");
for peer in netman.peer.iter_peer_ids() {
ui.label(peer.0.to_string());
ui.label(peer.to_string());
}
ui.label(format!("Peer state: {}", netman.peer.state()));
});
}
AppState::Error { message } => {
if egui::CentralPanel::default()
.show(ctx, |ui| {
ui.heading("An error occured:");
ui.label(message);
ui.button("Back").clicked()
})
.inner
{
self.state = AppState::Init;
}
}
};
}
}

View file

@ -6,15 +6,16 @@ use std::{
thread,
time::Duration,
};
use steamworks::{LobbyId, SteamId};
use tracing::debug;
use tangled::{PeerId, Reliability};
use tangled::{PeerId, PeerState, Reliability};
use tracing::{error, info, warn};
use tungstenite::{accept, WebSocket};
use crate::{messages::NetMsg, GameSettings};
static HOST: PeerId = PeerId(0);
pub mod steam_networking;
pub(crate) fn ws_encode_proxy(key: &'static str, value: impl Display) -> tungstenite::Message {
let mut buf = Vec::new();
@ -23,7 +24,7 @@ pub(crate) fn ws_encode_proxy(key: &'static str, value: impl Display) -> tungste
tungstenite::Message::Binary(buf)
}
pub(crate) fn ws_encode_mod(peer: PeerId, data: &[u8]) -> tungstenite::Message {
pub(crate) fn ws_encode_mod(peer: OmniPeerId, data: &[u8]) -> tungstenite::Message {
let mut buf = Vec::new();
buf.push(1u8);
buf.extend_from_slice(&peer.0.to_le_bytes());
@ -46,8 +47,136 @@ impl NetInnerState {
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct OmniPeerId(u64);
impl From<PeerId> for OmniPeerId {
fn from(value: PeerId) -> Self {
Self(value.0.into())
}
}
impl From<SteamId> for OmniPeerId {
fn from(value: SteamId) -> Self {
Self(value.raw())
}
}
impl From<OmniPeerId> for PeerId {
fn from(value: OmniPeerId) -> Self {
Self(
value
.0
.try_into()
.expect("Assuming PeerId was stored here, so conversion should succeed"),
)
}
}
impl From<OmniPeerId> for SteamId {
fn from(value: OmniPeerId) -> Self {
Self::from_raw(value.0)
}
}
impl Display for OmniPeerId {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
pub enum OmniNetworkEvent {
PeerConnected(OmniPeerId),
PeerDisconnected(OmniPeerId),
Message { src: OmniPeerId, data: Vec<u8> },
}
impl From<tangled::NetworkEvent> for OmniNetworkEvent {
fn from(value: tangled::NetworkEvent) -> Self {
match value {
tangled::NetworkEvent::PeerConnected(id) => Self::PeerConnected(id.into()),
tangled::NetworkEvent::PeerDisconnected(id) => Self::PeerDisconnected(id.into()),
tangled::NetworkEvent::Message(msg) => Self::Message {
src: msg.src.into(),
data: msg.data,
},
}
}
}
pub enum PeerVariant {
Tangled(tangled::Peer),
Steam(steam_networking::SteamPeer),
}
impl PeerVariant {
fn send(
&self,
peer: OmniPeerId,
msg: Vec<u8>,
reliability: Reliability,
) -> Result<(), tangled::NetError> {
match self {
PeerVariant::Tangled(p) => p.send(peer.into(), msg, reliability),
PeerVariant::Steam(p) => {
p.send_message(peer.into(), &msg, reliability);
Ok(())
}
}
}
fn broadcast(&self, msg: Vec<u8>, reliability: Reliability) -> Result<(), tangled::NetError> {
match self {
PeerVariant::Tangled(p) => p.broadcast(msg, reliability),
PeerVariant::Steam(p) => Ok(p.broadcast_message(&msg, reliability)),
}
}
fn my_id(&self) -> Option<OmniPeerId> {
match self {
PeerVariant::Tangled(p) => p.my_id().map(OmniPeerId::from),
PeerVariant::Steam(p) => Some(p.my_id().into()),
}
}
pub fn iter_peer_ids(&self) -> Vec<OmniPeerId> {
match self {
PeerVariant::Tangled(p) => p.iter_peer_ids().map(OmniPeerId::from).collect(),
PeerVariant::Steam(p) => p.get_peer_ids().into_iter().map(OmniPeerId::from).collect(),
}
}
fn recv(&self) -> Vec<OmniNetworkEvent> {
match self {
PeerVariant::Tangled(p) => p.recv().map(OmniNetworkEvent::from).collect(),
PeerVariant::Steam(p) => p.recv(),
}
}
pub fn state(&self) -> PeerState {
match self {
PeerVariant::Tangled(p) => p.state(),
PeerVariant::Steam(p) => p.state(),
}
}
pub fn host_id(&self) -> OmniPeerId {
match self {
PeerVariant::Tangled(_) => PeerId::HOST.into(),
PeerVariant::Steam(p) => p.host_id().into(),
}
}
pub fn lobby_id(&self) -> Option<LobbyId> {
match self {
PeerVariant::Tangled(_) => None,
PeerVariant::Steam(p) => p.lobby_id(),
}
}
}
pub struct NetManager {
pub(crate) peer: tangled::Peer,
pub(crate) peer: PeerVariant,
pub(crate) settings: Mutex<GameSettings>,
pub(crate) continue_running: AtomicBool, // TODO stop on drop
pub(crate) accept_local: AtomicBool,
@ -55,7 +184,7 @@ pub struct NetManager {
}
impl NetManager {
pub fn new(peer: tangled::Peer) -> Arc<Self> {
pub fn new(peer: PeerVariant) -> Arc<Self> {
Self {
peer,
settings: Mutex::new(GameSettings {
@ -70,7 +199,7 @@ impl NetManager {
.into()
}
pub(crate) fn send(&self, peer: tangled::PeerId, msg: &NetMsg, reliability: Reliability) {
pub(crate) fn send(&self, peer: OmniPeerId, msg: &NetMsg, reliability: Reliability) {
let encoded = bitcode::encode(msg);
self.peer.send(peer, encoded.clone(), reliability).ok(); // TODO log
}
@ -135,9 +264,9 @@ impl NetManager {
}
for net_event in self.peer.recv() {
match net_event {
tangled::NetworkEvent::PeerConnected(id) => {
OmniNetworkEvent::PeerConnected(id) => {
info!("Peer connected");
if self.peer.my_id() == Some(HOST) {
if self.peer.my_id() == Some(self.peer.host_id()) {
info!("Sending start game message");
self.send(
id,
@ -149,11 +278,11 @@ impl NetManager {
}
state.try_ws_write(ws_encode_proxy("join", id));
}
tangled::NetworkEvent::PeerDisconnected(id) => {
OmniNetworkEvent::PeerDisconnected(id) => {
state.try_ws_write(ws_encode_proxy("leave", id));
}
tangled::NetworkEvent::Message(msg) => {
let Ok(net_msg) = bitcode::decode::<NetMsg>(&msg.data) else {
OmniNetworkEvent::Message { src, data } => {
let Ok(net_msg) = bitcode::decode::<NetMsg>(&data) else {
continue;
};
match net_msg {
@ -164,12 +293,12 @@ impl NetManager {
.store(true, std::sync::atomic::Ordering::SeqCst);
}
NetMsg::ModRaw { data } => {
state.try_ws_write(ws_encode_mod(msg.src, &data));
state.try_ws_write(ws_encode_mod(src, &data));
}
NetMsg::ModCompressed { data } => {
if let Ok(decompressed) = lz4_flex::decompress_size_prepended(&data)
{
state.try_ws_write(ws_encode_mod(msg.src, &decompressed));
state.try_ws_write(ws_encode_mod(src, &decompressed));
}
}
}
@ -251,7 +380,7 @@ impl NetManager {
}
fn is_host(&self) -> bool {
self.peer.my_id() == Some(PeerId::HOST)
self.peer.my_id() == Some(self.peer.host_id())
}
pub(crate) fn handle_message_to_proxy(&self, msg: &[u8]) {

View file

@ -0,0 +1,261 @@
use std::sync::Mutex;
use crossbeam::channel;
use steamworks::{
CallbackHandle, LobbyChatUpdate, LobbyId, LobbyType, P2PSessionRequest, SendType, SteamError,
SteamId,
};
use tangled::{PeerState, Reliability};
use tracing::{info, warn};
use super::OmniNetworkEvent;
enum SteamEvent {
LobbyCreated(LobbyId),
LobbyError(SteamError),
LobbyJoinError,
PeerConnected(SteamId),
PeerDisconnected(SteamId),
PeerStateChanged,
AcceptConnection(SteamId),
}
pub struct InnerState {
lobby_id: Option<LobbyId>,
host_id: SteamId,
remote_peers: Vec<SteamId>,
state: PeerState,
}
pub struct SteamPeer {
client: steamworks::Client,
events: channel::Receiver<SteamEvent>,
sender: channel::Sender<SteamEvent>,
my_id: SteamId,
is_host: bool,
inner: Mutex<InnerState>,
_cbs: Vec<CallbackHandle>,
}
impl SteamPeer {
pub fn new_host(lobby_type: LobbyType, client: steamworks::Client) -> Self {
let (sender, events) = channel::unbounded();
let matchmaking = client.matchmaking();
{
let sender = sender.clone();
matchmaking.create_lobby(lobby_type, 20, move |lobby| {
let event = match lobby {
Ok(id) => SteamEvent::LobbyCreated(id),
Err(err) => SteamEvent::LobbyError(err),
};
sender.send(event).ok();
});
}
let my_id = client.user().steam_id();
let _cbs = make_callbacks(&sender, &client);
Self {
my_id,
client,
events,
sender,
is_host: true,
inner: Mutex::new(InnerState {
lobby_id: None,
host_id: my_id,
remote_peers: Vec::new(),
state: PeerState::PendingConnection,
}),
_cbs,
}
}
pub fn new_connect(lobby: LobbyId, client: steamworks::Client) -> Self {
let (sender, events) = channel::unbounded();
let matchmaking = client.matchmaking();
{
let sender = sender.clone();
matchmaking.join_lobby(lobby, move |lobby| {
let event = match lobby {
Ok(id) => SteamEvent::LobbyCreated(id),
Err(_) => SteamEvent::LobbyJoinError,
};
sender.send(event).ok();
});
}
let my_id = client.user().steam_id();
let _cbs = make_callbacks(&sender, &client);
Self {
my_id,
client,
events,
sender,
is_host: false,
inner: Mutex::new(InnerState {
lobby_id: None,
remote_peers: Vec::new(),
host_id: my_id,
state: PeerState::PendingConnection,
}),
_cbs,
}
}
pub fn send_message(&self, peer: SteamId, msg: &[u8], reliability: Reliability) -> bool {
let send_type = if reliability == Reliability::Reliable || msg.len() > 1200 {
SendType::Reliable
} else {
SendType::Unreliable
};
let networking = self.client.networking();
let res = networking.send_p2p_packet(peer, send_type.clone(), msg);
// info!("Sent a packet to {:?}, st {:?}", peer, send_type);
if !res {
warn!("Couldn't send a packet to {:?}, st {:?}", peer, send_type)
}
res
}
pub fn broadcast_message(&self, msg: &[u8], reliability: Reliability) {
let peers = self.inner.lock().unwrap().remote_peers.clone();
for peer in peers {
self.send_message(peer, msg, reliability);
}
}
pub fn recv(&self) -> Vec<OmniNetworkEvent> {
let mut returned_events = Vec::new();
for event in self.events.try_iter() {
match event {
SteamEvent::LobbyCreated(id) => {
info!("Lobby ready");
self.inner.lock().unwrap().lobby_id = Some(id);
if !self.is_host {
let host_id = self.client.matchmaking().lobby_owner(id);
self.inner.lock().unwrap().host_id = host_id;
info!("Got host id: {:?}", host_id)
}
self.update_remote_peers();
self.inner.lock().unwrap().state = PeerState::Connected;
}
SteamEvent::LobbyError(err) => {
warn!("Could not create lobby: {}", err);
self.inner.lock().unwrap().state = PeerState::Disconnected;
}
SteamEvent::LobbyJoinError => {
warn!("Could not join lobby");
self.inner.lock().unwrap().state = PeerState::Disconnected;
}
SteamEvent::PeerConnected(id) => {
returned_events.push(OmniNetworkEvent::PeerConnected(id.into()))
}
SteamEvent::PeerDisconnected(id) => {
returned_events.push(OmniNetworkEvent::PeerDisconnected(id.into()))
}
SteamEvent::PeerStateChanged => self.update_remote_peers(),
SteamEvent::AcceptConnection(id) => {
info!("p2p accepted");
self.client.networking().accept_p2p_session(id);
}
}
}
let networking = self.client.networking();
while let Some(size) = networking.is_p2p_packet_available() {
info!("Got packet {}", size);
let mut empty_array = vec![0; size];
let mut buffer = empty_array.as_mut_slice();
if let Some((sender, _)) = networking.read_p2p_packet(&mut buffer) {
returned_events.push(OmniNetworkEvent::Message {
src: sender.into(),
data: empty_array,
})
}
}
returned_events
}
fn update_remote_peers(&self) {
let matchmaking = self.client.matchmaking();
let lobby = self.inner.lock().unwrap().lobby_id;
let mut peers = match lobby {
Some(lobby_id) => matchmaking.lobby_members(lobby_id),
None => Vec::new(),
};
peers.retain(|x| *x != self.my_id);
peers.sort();
let current_peers = &mut self.inner.lock().unwrap().remote_peers;
// TODO: could be done more efficiently
for peer in &peers {
if !current_peers.contains(&peer) {
self.sender.send(SteamEvent::PeerConnected(*peer)).ok();
}
}
for peer in &mut *current_peers {
if !peers.contains(&peer) {
self.sender.send(SteamEvent::PeerDisconnected(*peer)).ok();
}
}
*current_peers = peers;
}
pub fn get_peer_ids(&self) -> Vec<SteamId> {
// let matchmaking = self.client.matchmaking();
// let lobby = self.inner.lock().unwrap().lobby_id;
// match lobby {
// Some(lobby_id) => matchmaking.lobby_members(lobby_id),
// None => Vec::new(),
// }
let mut peers = self.inner.lock().unwrap().remote_peers.clone();
peers.push(self.my_id);
peers
}
pub fn my_id(&self) -> SteamId {
self.my_id
}
pub fn host_id(&self) -> SteamId {
if self.is_host {
self.my_id
} else {
self.inner.lock().unwrap().host_id
}
}
pub fn lobby_id(&self) -> Option<LobbyId> {
self.inner.lock().unwrap().lobby_id
}
pub fn state(&self) -> PeerState {
self.inner.lock().unwrap().state
}
}
fn make_callbacks(
sender: &channel::Sender<SteamEvent>,
client: &steamworks::Client,
) -> Vec<CallbackHandle> {
let cb_req = {
let sender = sender.clone();
client.register_callback(move |request: P2PSessionRequest| {
info!("Accepting connection with {:?}", request.remote);
sender
.send(SteamEvent::AcceptConnection(request.remote))
.ok();
})
};
let cb_ch = {
let sender = sender.clone();
client.register_callback(move |update: LobbyChatUpdate| {
info!("User state changed {:?}", update);
sender.send(SteamEvent::PeerStateChanged).ok();
})
};
vec![cb_ch, cb_req]
}