feat: private battles
This commit is contained in:
parent
33b0391ef3
commit
384f5abca5
21 changed files with 831 additions and 96 deletions
122
src/nex/matchmake.rs
Normal file
122
src/nex/matchmake.rs
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
use std::collections::HashMap;
|
||||
use std::sync::{Arc, Weak};
|
||||
use std::sync::atomic::AtomicU32;
|
||||
use std::sync::atomic::Ordering::{Relaxed, Release};
|
||||
use rand::random;
|
||||
use tokio::sync::{Mutex, RwLock};
|
||||
use crate::kerberos::KerberosDateTime;
|
||||
use crate::nex::user::User;
|
||||
use crate::rmc::protocols::notifications::{NotificationEvent, RemoteNotification};
|
||||
use crate::rmc::structures::matchmake::{Gathering, MatchmakeParam, MatchmakeSession};
|
||||
use crate::rmc::structures::variant::Variant;
|
||||
|
||||
pub struct MatchmakeManager{
|
||||
pub gid_counter: AtomicU32,
|
||||
pub sessions: RwLock<HashMap<u32, Arc<Mutex<ExtendedMatchmakeSession>>>>,
|
||||
pub rv_cid_counter: AtomicU32,
|
||||
pub users: RwLock<HashMap<u32, Weak<User>>>
|
||||
}
|
||||
|
||||
impl MatchmakeManager{
|
||||
pub fn next_gid(&self) -> u32{
|
||||
self.gid_counter.fetch_add(1, Relaxed)
|
||||
}
|
||||
|
||||
pub fn next_cid(&self) -> u32{
|
||||
self.rv_cid_counter.fetch_add(1, Relaxed)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
pub struct ExtendedMatchmakeSession{
|
||||
pub session: MatchmakeSession,
|
||||
pub connected_players: Vec<Weak<User>>,
|
||||
}
|
||||
|
||||
impl ExtendedMatchmakeSession{
|
||||
pub async fn from_matchmake_session(gid: u32, session: MatchmakeSession, host: &Weak<User>) -> Self{
|
||||
let Some(host) = host.upgrade() else{
|
||||
return Default::default();
|
||||
};
|
||||
|
||||
|
||||
let mm_session = MatchmakeSession{
|
||||
gathering: Gathering{
|
||||
self_gid: 1,
|
||||
owner_pid: host.pid,
|
||||
host_pid: host.pid,
|
||||
..session.gathering.clone()
|
||||
},
|
||||
datetime: KerberosDateTime::now(),
|
||||
session_key: vec![16, 118, 112, 238, 158, 122, 106, 219, 196, 238, 34, 21, 228, 127, 137, 75, 198, 215, 192, 113, 84, 157, 53, 144, 210, 99, 233, 179, 232, 113, 203, 64],//(0..32).map(|_| random()).collect(),
|
||||
matchmake_param: MatchmakeParam{
|
||||
params: vec![
|
||||
("@SR".to_owned(), Variant::Bool(true)),
|
||||
("@GIR".to_owned(), Variant::SInt64(3))
|
||||
]
|
||||
},
|
||||
system_password_enabled: false,
|
||||
..session
|
||||
};
|
||||
|
||||
Self{
|
||||
session: mm_session,
|
||||
connected_players: Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn add_player(&mut self, conn: Weak<User>, join_msg: String) {
|
||||
let Some(arc_conn) = conn.upgrade() else {
|
||||
return
|
||||
};
|
||||
|
||||
let joining_pid = arc_conn.pid;
|
||||
|
||||
let old_particip = self.connected_players.clone();
|
||||
|
||||
self.connected_players.push(conn);
|
||||
self.session.participation_count = self.connected_players.len() as u32;
|
||||
|
||||
|
||||
for other_connection in &self.connected_players{
|
||||
let Some(other_conn) = other_connection.upgrade() else {
|
||||
continue;
|
||||
};
|
||||
|
||||
|
||||
let other_pid = other_conn.pid;
|
||||
/*if other_pid == self.session.gathering.owner_pid &&
|
||||
joining_pid == self.session.gathering.owner_pid{
|
||||
continue;
|
||||
}*/
|
||||
|
||||
other_conn.remote.process_notification_event(NotificationEvent{
|
||||
pid_source: joining_pid,
|
||||
notif_type: 3001,
|
||||
param_1: self.session.gathering.self_gid,
|
||||
param_2: other_pid,
|
||||
str_param: join_msg.clone(),
|
||||
param_3: self.connected_players.len() as _
|
||||
}).await;
|
||||
}
|
||||
|
||||
for old_conns in &old_particip{
|
||||
let Some(old_conns) = old_conns.upgrade() else {
|
||||
continue;
|
||||
};
|
||||
|
||||
|
||||
let older_pid = old_conns.pid;
|
||||
|
||||
arc_conn.remote.process_notification_event(NotificationEvent{
|
||||
pid_source: joining_pid,
|
||||
notif_type: 3001,
|
||||
param_1: self.session.gathering.self_gid,
|
||||
param_2: older_pid,
|
||||
str_param: join_msg.clone(),
|
||||
param_3: self.connected_players.len() as _
|
||||
}).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,3 +1,5 @@
|
|||
pub mod account;
|
||||
pub mod auth_handler;
|
||||
pub mod user;
|
||||
pub mod user;
|
||||
pub mod remote_console;
|
||||
pub mod matchmake;
|
||||
23
src/nex/remote_console.rs
Normal file
23
src/nex/remote_console.rs
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
use macros::rmc_struct;
|
||||
use crate::rmc::protocols::notifications::{Notification, NotificationEvent, RawNotification, RawNotificationInfo, RemoteNotification};
|
||||
use crate::rmc::protocols::nat_traversal::{NatTraversal, RemoteNatTraversal, RawNatTraversalInfo, RawNatTraversal};
|
||||
use crate::define_rmc_proto;
|
||||
use crate::nex::user::RemoteUserProtocol;
|
||||
|
||||
define_rmc_proto!(
|
||||
proto Console{
|
||||
Notification,
|
||||
NatTraversal
|
||||
}
|
||||
);
|
||||
/*
|
||||
#[rmc_struct(Console)]
|
||||
pub struct TestRemoteConsole{
|
||||
pub remote: RemoteUserProtocol,
|
||||
}
|
||||
|
||||
impl Notification for TestRemoteConsole{
|
||||
async fn process_notification_event(&self, event: NotificationEvent) {
|
||||
println!("NOTIF RECIEVED: {:?}", event);
|
||||
}
|
||||
}*/
|
||||
378
src/nex/user.rs
378
src/nex/user.rs
|
|
@ -1,45 +1,379 @@
|
|||
use std::net::{Ipv4Addr, SocketAddrV4};
|
||||
use macros::rmc_struct;
|
||||
use std::io::ErrorKind::HostUnreachable;
|
||||
use crate::define_rmc_proto;
|
||||
use crate::prudp::station_url::{nat_types, StationUrl};
|
||||
use crate::prudp::station_url::Type::PRUDPS;
|
||||
use crate::prudp::station_url::UrlOptions::{Address, NatFiltering, NatMapping, NatType, Port, PrincipalID, RVConnectionID};
|
||||
use crate::rmc::protocols::secure::{RemoteAuth, RawAuthInfo, RawAuth, Auth};
|
||||
use crate::nex::matchmake::{ExtendedMatchmakeSession, MatchmakeManager};
|
||||
use crate::nex::remote_console::RemoteConsole;
|
||||
use crate::prudp::sockaddr::PRUDPSockAddr;
|
||||
use crate::prudp::station_url::Type::{PRUDP, PRUDPS};
|
||||
use crate::prudp::station_url::UrlOptions::{
|
||||
Address, NatFiltering, NatMapping, NatType, Platform, Port, PrincipalID, RVConnectionID,
|
||||
StreamID, PMP, UPNP,
|
||||
};
|
||||
use crate::prudp::station_url::{nat_types, StationUrl, Type};
|
||||
use crate::rmc::protocols::matchmake::{
|
||||
Matchmake, RawMatchmake, RawMatchmakeInfo, RemoteMatchmake,
|
||||
};
|
||||
use crate::rmc::protocols::matchmake_extension::{
|
||||
MatchmakeExtension, RawMatchmakeExtension, RawMatchmakeExtensionInfo, RemoteMatchmakeExtension,
|
||||
};
|
||||
use crate::rmc::protocols::nat_traversal::{
|
||||
NatTraversal, RawNatTraversal, RawNatTraversalInfo, RemoteNatTraversal,
|
||||
};
|
||||
use crate::rmc::protocols::secure::{RawSecure, RawSecureInfo, RemoteSecure, Secure};
|
||||
use crate::rmc::response::ErrorCode;
|
||||
use crate::rmc::structures::matchmake::{AutoMatchmakeParam, CreateMatchmakeSessionParam, JoinMatchmakeSessionParam, MatchmakeSession};
|
||||
use crate::rmc::structures::qresult::QResult;
|
||||
use macros::rmc_struct;
|
||||
use std::net::{Ipv4Addr, SocketAddrV4};
|
||||
use std::sync::{Arc, Weak};
|
||||
use log::{error, info};
|
||||
use rocket::http::ext::IntoCollection;
|
||||
use tokio::sync::{Mutex, RwLock};
|
||||
use crate::prudp::station_url::nat_types::PUBLIC;
|
||||
use crate::rmc::response::ErrorCode::{Core_Exception, Core_InvalidArgument, RendezVous_AccountExpired, RendezVous_SessionVoid};
|
||||
|
||||
define_rmc_proto!(
|
||||
proto UserProtocol{
|
||||
Auth
|
||||
Secure,
|
||||
MatchmakeExtension,
|
||||
Matchmake,
|
||||
NatTraversal
|
||||
}
|
||||
);
|
||||
|
||||
#[rmc_struct(UserProtocol)]
|
||||
pub struct User {
|
||||
pub pid: u32,
|
||||
pub ip: SocketAddrV4,
|
||||
pub ip: PRUDPSockAddr,
|
||||
pub this: Weak<User>,
|
||||
pub remote: RemoteConsole,
|
||||
pub station_url: RwLock<Vec<StationUrl>>,
|
||||
pub matchmake_manager: Arc<MatchmakeManager>,
|
||||
}
|
||||
|
||||
impl Auth for User{
|
||||
async fn register(&self, station_urls: Vec<String>) -> Result<(QResult, u32, String), ErrorCode> {
|
||||
let public_station = StationUrl{
|
||||
url_type: PRUDPS,
|
||||
options: vec![
|
||||
RVConnectionID(0),
|
||||
Address(*self.ip.ip()),
|
||||
Port(self.ip.port()),
|
||||
NatFiltering(0),
|
||||
NatMapping(0),
|
||||
NatType(nat_types::BEHIND_NAT),
|
||||
PrincipalID(self.pid),
|
||||
]
|
||||
impl Secure for User {
|
||||
async fn register(
|
||||
&self,
|
||||
station_urls: Vec<StationUrl>,
|
||||
) -> Result<(QResult, u32, StationUrl), ErrorCode> {
|
||||
let cid = self.matchmake_manager.next_cid();
|
||||
|
||||
println!("{:?}", station_urls);
|
||||
|
||||
let mut users = self.matchmake_manager.users.write().await;
|
||||
users.insert(cid, self.this.clone());
|
||||
drop(users);
|
||||
|
||||
let mut public_station: Option<StationUrl> = None;
|
||||
let mut private_station: Option<StationUrl> = None;
|
||||
|
||||
for station in station_urls{
|
||||
let is_public = station.options.iter().any(|v| {
|
||||
if let NatType(v) = v {
|
||||
if *v & PUBLIC != 0 {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
});
|
||||
|
||||
let Some(nat_filtering) = station.options.iter().find_map(|v| match v {
|
||||
NatFiltering(v) => Some(v),
|
||||
_ => None
|
||||
}) else {
|
||||
return Err(Core_Exception);
|
||||
};
|
||||
|
||||
let Some(nat_mapping) = station.options.iter().find_map(|v| match v {
|
||||
NatMapping(v) => Some(v),
|
||||
_ => None
|
||||
}) else {
|
||||
return Err(Core_Exception);
|
||||
};
|
||||
|
||||
if !is_public || (*nat_filtering == 0 && *nat_mapping == 0){
|
||||
private_station = Some(station.clone());
|
||||
}
|
||||
|
||||
if is_public{
|
||||
public_station = Some(station);
|
||||
}
|
||||
}
|
||||
|
||||
let Some(mut private_station) = private_station else {
|
||||
return Err(Core_Exception);
|
||||
};
|
||||
|
||||
let mut public_station = if let Some(public_station) = public_station{
|
||||
public_station
|
||||
} else {
|
||||
let mut public_station = private_station.clone();
|
||||
|
||||
public_station.options.retain(|v| {
|
||||
match v {
|
||||
Address(_) | Port(_) | NatFiltering(_) | NatMapping(_) | NatType(_) => false,
|
||||
_ => true
|
||||
}
|
||||
});
|
||||
|
||||
public_station.options.push(Address(*self.ip.regular_socket_addr.ip()));
|
||||
public_station.options.push(Port(self.ip.regular_socket_addr.port()));
|
||||
public_station.options.push(NatFiltering(0));
|
||||
public_station.options.push(NatMapping(0));
|
||||
public_station.options.push(NatType(3));
|
||||
|
||||
public_station
|
||||
};
|
||||
|
||||
let mut both = [&mut public_station, &mut private_station];
|
||||
|
||||
for station in both{
|
||||
station.options.retain(|v| {
|
||||
match v {
|
||||
PrincipalID(_) | RVConnectionID(_) => false,
|
||||
_ => true
|
||||
}
|
||||
});
|
||||
|
||||
station.options.push(PrincipalID(self.pid));
|
||||
station.options.push(RVConnectionID(cid));
|
||||
}
|
||||
|
||||
|
||||
let mut lock = self.station_url.write().await;
|
||||
*lock = vec![
|
||||
public_station.clone(),
|
||||
private_station
|
||||
];
|
||||
drop(lock);
|
||||
|
||||
let result = QResult::success(ErrorCode::Core_Unknown);
|
||||
|
||||
Ok((result, 0, public_station.to_string()))
|
||||
let out = public_station.to_string();
|
||||
|
||||
println!("out: {}", out);
|
||||
|
||||
Ok((result, cid, public_station))
|
||||
}
|
||||
|
||||
async fn replace_url(&self, target_url: StationUrl, dest: StationUrl) -> Result<(), ErrorCode> {
|
||||
let mut lock = self.station_url.write().await;
|
||||
|
||||
let Some(target_addr) = target_url.options.iter().find(|v| matches!(v, Address(_))) else{
|
||||
return Err(ErrorCode::Core_InvalidArgument);
|
||||
};
|
||||
|
||||
let Some(target_port) = target_url.options.iter().find(|v| matches!(v, Port(_))) else{
|
||||
return Err(ErrorCode::Core_InvalidArgument);
|
||||
};
|
||||
|
||||
let Some(replacement_target) = lock.iter_mut().find(|url| {
|
||||
url.options.iter().any(|o| o == target_addr) &&
|
||||
url.options.iter().any(|o| o == target_port)
|
||||
}) else {
|
||||
return Err(ErrorCode::Core_InvalidArgument);
|
||||
};
|
||||
*replacement_target = dest;
|
||||
|
||||
drop(lock);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl MatchmakeExtension for User {
|
||||
async fn get_playing_session(&self, pids: Vec<u32>) -> Result<Vec<()>, ErrorCode> {
|
||||
Ok(Vec::new())
|
||||
}
|
||||
|
||||
async fn update_progress_score(&self, gid: u32, progress: u8) -> Result<(), ErrorCode> {
|
||||
let mut sessions = self.matchmake_manager.sessions.read().await;
|
||||
|
||||
let Some(session) = sessions.get(&gid) else {
|
||||
return Err(RendezVous_SessionVoid);
|
||||
};
|
||||
|
||||
let session = session.clone();
|
||||
drop(sessions);
|
||||
|
||||
let mut session = session.lock().await;
|
||||
|
||||
session.session.progress_score = progress;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn create_matchmake_session_with_param(
|
||||
&self,
|
||||
session: CreateMatchmakeSessionParam,
|
||||
) -> Result<MatchmakeSession, ErrorCode> {
|
||||
println!("{:?}", session);
|
||||
|
||||
let gid = self.matchmake_manager.next_gid();
|
||||
|
||||
let mut new_session = ExtendedMatchmakeSession::from_matchmake_session(
|
||||
gid,
|
||||
session.matchmake_session,
|
||||
&self.this.clone(),
|
||||
)
|
||||
.await;
|
||||
|
||||
new_session.session.participation_count = session.participation_count as u32;
|
||||
new_session
|
||||
.add_player(self.this.clone(), session.join_message)
|
||||
.await;
|
||||
|
||||
let session = new_session.session.clone();
|
||||
|
||||
let mut sessions = self.matchmake_manager.sessions.write().await;
|
||||
sessions.insert(gid, Arc::new(Mutex::new(new_session)));
|
||||
drop(sessions);
|
||||
|
||||
Ok(session)
|
||||
}
|
||||
|
||||
async fn join_matchmake_session_with_param(
|
||||
&self,
|
||||
join_session_param: JoinMatchmakeSessionParam,
|
||||
) -> Result<MatchmakeSession, ErrorCode> {
|
||||
let mut sessions = self.matchmake_manager.sessions.read().await;
|
||||
|
||||
let Some(session) = sessions.get(&join_session_param.gid) else {
|
||||
return Err(ErrorCode::RendezVous_SessionVoid);
|
||||
};
|
||||
|
||||
let session = session.clone();
|
||||
drop(sessions);
|
||||
|
||||
let mut session = session.lock().await;
|
||||
|
||||
session.connected_players.retain(|v| v.upgrade().is_some_and(|v| v.pid != self.pid));
|
||||
|
||||
session
|
||||
.add_player(self.this.clone(), join_session_param.join_message)
|
||||
.await;
|
||||
|
||||
let mm_session = session.session.clone();
|
||||
|
||||
Ok(mm_session)
|
||||
}
|
||||
|
||||
async fn auto_matchmake_with_param_postpone(&self, session: AutoMatchmakeParam) -> Result<MatchmakeSession, ErrorCode> {
|
||||
println!("{:?}", session.search_criteria);
|
||||
|
||||
let AutoMatchmakeParam{
|
||||
join_message,
|
||||
participation_count,
|
||||
gid_for_participation_check,
|
||||
matchmake_session,
|
||||
additional_participants,
|
||||
..
|
||||
} = session;
|
||||
|
||||
self.create_matchmake_session_with_param(CreateMatchmakeSessionParam{
|
||||
join_message,
|
||||
participation_count,
|
||||
gid_for_participation_check,
|
||||
create_matchmake_session_option: 0,
|
||||
matchmake_session,
|
||||
additional_participants
|
||||
}).await
|
||||
}
|
||||
}
|
||||
|
||||
impl Matchmake for User {
|
||||
async fn unregister_gathering(&self, gid: u32) -> Result<bool, ErrorCode> {
|
||||
Ok(true)
|
||||
}
|
||||
async fn get_session_urls(&self, gid: u32) -> Result<Vec<StationUrl>, ErrorCode> {
|
||||
let sessions = self.matchmake_manager.sessions.read().await;
|
||||
|
||||
let Some(session) = sessions.get(&gid) else {
|
||||
return Err(ErrorCode::RendezVous_SessionVoid);
|
||||
};
|
||||
|
||||
let session = session.clone();
|
||||
|
||||
drop(sessions);
|
||||
|
||||
let session = session.lock().await;
|
||||
|
||||
let urls: Vec<_> =
|
||||
session
|
||||
.connected_players
|
||||
.iter()
|
||||
.filter_map(|v| v.upgrade())
|
||||
.filter(|u| u.pid == session.session.gathering.host_pid)
|
||||
.map(|u| async move {
|
||||
u.station_url.read().await.clone()
|
||||
})
|
||||
.next()
|
||||
.ok_or(ErrorCode::RendezVous_SessionClosed)?
|
||||
.await;
|
||||
|
||||
|
||||
println!("{:?}", urls);
|
||||
|
||||
Ok(urls)
|
||||
}
|
||||
}
|
||||
|
||||
impl NatTraversal for User {
|
||||
async fn report_nat_properties(
|
||||
&self,
|
||||
nat_mapping: u32,
|
||||
nat_filtering: u32,
|
||||
_rtt: u32,
|
||||
) -> Result<(), ErrorCode> {
|
||||
|
||||
let mut urls = self.station_url.write().await;
|
||||
|
||||
for station_url in urls.iter_mut() {
|
||||
station_url.options.retain(|o| match o {
|
||||
NatMapping(_) | NatFiltering(_) => false,
|
||||
_ => true
|
||||
});
|
||||
|
||||
station_url.options.push(NatMapping(nat_mapping as u8));
|
||||
station_url.options.push(NatFiltering(nat_filtering as u8));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn request_probe_initiation(&self, station_to_probe: String) -> Result<(), ErrorCode> {
|
||||
info!("NO!");
|
||||
Err(RendezVous_AccountExpired)
|
||||
}
|
||||
|
||||
async fn request_probe_initialization_ext(&self, target_list: Vec<String>, station_to_probe: String) -> Result<(), ErrorCode> {
|
||||
let users = self.matchmake_manager.users.read().await;
|
||||
|
||||
println!("requesting station probe for {:?} to {:?}", target_list, station_to_probe);
|
||||
|
||||
for target in target_list{
|
||||
let Ok(url) = StationUrl::try_from(target.as_ref()) else{
|
||||
continue;
|
||||
};
|
||||
|
||||
let Some(RVConnectionID(v)) = url.options.into_iter().find(|o| { matches!(o, &RVConnectionID(_)) }) else{
|
||||
continue;
|
||||
};
|
||||
|
||||
let Some(v) = users.get(&v) else{
|
||||
continue;
|
||||
};
|
||||
|
||||
let Some(user) = v.upgrade() else {
|
||||
continue;
|
||||
};
|
||||
|
||||
if let Err(e) = user.remote.request_probe_initiation(station_to_probe.clone()).await{
|
||||
error!("error whilest probing");
|
||||
}
|
||||
}
|
||||
|
||||
info!("finished probing");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue