diff --git a/Cargo.lock b/Cargo.lock index 038450a..a22e0dc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3336,6 +3336,7 @@ dependencies = [ "async-trait", "bytes", "byteserde", + "chrono", "clap", "env_logger", "literustlib", diff --git a/rc_multiplayer/Cargo.toml b/rc_multiplayer/Cargo.toml index 33633ba..95719ce 100644 --- a/rc_multiplayer/Cargo.toml +++ b/rc_multiplayer/Cargo.toml @@ -16,6 +16,7 @@ oj_rc_core = { version = "*", path = "../rc_core" } async-trait.workspace = true bytes = "1.10" byteserde = "0.6.2" +chrono.workspace = true literustlib_server = { version = "0.1", path = "../../LiteRustLib/server" } literustlib = { version = "0.1", path = "../../LiteRustLib" } diff --git a/rc_multiplayer/src/events/activate_sync.rs b/rc_multiplayer/src/events/activate_sync.rs index 68e4694..b7f848d 100644 --- a/rc_multiplayer/src/events/activate_sync.rs +++ b/rc_multiplayer/src/events/activate_sync.rs @@ -2,8 +2,8 @@ pub struct RequestLoadingSync { msg_router: tokio::sync::mpsc::Sender, } -pub(super) fn handler(init_ctx: &crate::InitConfig) -> crate::handlers::dataless::Dataless { - crate::handlers::dataless::Dataless::new(RequestLoadingSync::new(init_ctx)) +pub(super) fn handler(init_ctx: &crate::InitConfig) -> crate::handlers::Dataless { + crate::handlers::Dataless::new(RequestLoadingSync::new(init_ctx)) } impl RequestLoadingSync { @@ -15,7 +15,7 @@ impl RequestLoadingSync { } #[async_trait::async_trait] -impl crate::handlers::dataless::DatalessEventCodeHandler for RequestLoadingSync { +impl crate::handlers::DatalessEventCodeHandler for RequestLoadingSync { const CODE: rlnl::event_code::NetworkEvent = rlnl::event_code::NetworkEvent::RequestSync; async fn handle(&self, _peer: &std::sync::Arc>, user: &crate::UserData, _sender: &std::sync::Arc>) { diff --git a/rc_multiplayer/src/events/all_loading_progress.rs b/rc_multiplayer/src/events/all_loading_progress.rs index ce2e91c..cb565fd 100644 --- a/rc_multiplayer/src/events/all_loading_progress.rs +++ b/rc_multiplayer/src/events/all_loading_progress.rs @@ -2,8 +2,8 @@ pub struct RequestAllLoadingProgress { msg_router: tokio::sync::mpsc::Sender, } -pub(super) fn handler(init_ctx: &crate::InitConfig) -> crate::handlers::dataless::Dataless { - crate::handlers::dataless::Dataless::new(RequestAllLoadingProgress::new(init_ctx)) +pub(super) fn handler(init_ctx: &crate::InitConfig) -> crate::handlers::Dataless { + crate::handlers::Dataless::new(RequestAllLoadingProgress::new(init_ctx)) } impl RequestAllLoadingProgress { @@ -15,7 +15,7 @@ impl RequestAllLoadingProgress { } #[async_trait::async_trait] -impl crate::handlers::dataless::DatalessEventCodeHandler for RequestAllLoadingProgress { +impl crate::handlers::DatalessEventCodeHandler for RequestAllLoadingProgress { const CODE: rlnl::event_code::NetworkEvent = rlnl::event_code::NetworkEvent::RequestLoadingProgressAllUsers; async fn handle(&self, _peer: &std::sync::Arc>, user: &crate::UserData, _sender: &std::sync::Arc>) { diff --git a/rc_multiplayer/src/events/loading_done.rs b/rc_multiplayer/src/events/loading_done.rs new file mode 100644 index 0000000..292e5e3 --- /dev/null +++ b/rc_multiplayer/src/events/loading_done.rs @@ -0,0 +1,30 @@ +pub struct LoadComplete { + msg_router: tokio::sync::mpsc::Sender, +} + +pub(super) fn handler(init_ctx: &crate::InitConfig) -> crate::handlers::Dataless { + crate::handlers::Dataless::new(LoadComplete::new(init_ctx)) +} + +impl LoadComplete { + fn new(init_ctx: &crate::InitConfig) -> Self { + Self { + msg_router: init_ctx.matches_chann.clone(), + } + } +} + +#[async_trait::async_trait] +impl crate::handlers::DatalessEventCodeHandler for LoadComplete { + const CODE: rlnl::event_code::NetworkEvent = rlnl::event_code::NetworkEvent::LoadingComplete; + + async fn handle(&self, _peer: &std::sync::Arc>, user: &crate::UserData, _sender: &std::sync::Arc>) { + if let Some(user_info) = user.user().await { + super::log_channel_send_failure(self.msg_router.send(crate::matches::GameMessage::LoadComplete { + user_id: user_info.user_id(), + }).await); + } else { + log::error!("Failed to handle sync loading request for unknown user"); + } + } +} diff --git a/rc_multiplayer/src/events/loading_progress.rs b/rc_multiplayer/src/events/loading_progress.rs index df0d670..3505022 100644 --- a/rc_multiplayer/src/events/loading_progress.rs +++ b/rc_multiplayer/src/events/loading_progress.rs @@ -2,8 +2,8 @@ pub struct GameLoadingProgress { msg_router: tokio::sync::mpsc::Sender, } -pub(super) fn handler(init_ctx: &crate::InitConfig) -> crate::handlers::simple_typed::SimpleRlnl { - crate::handlers::simple_typed::SimpleRlnl::new(GameLoadingProgress::new(init_ctx)) +pub(super) fn handler(init_ctx: &crate::InitConfig) -> crate::handlers::SimpleRlnl { + crate::handlers::SimpleRlnl::new(GameLoadingProgress::new(init_ctx)) } impl GameLoadingProgress { @@ -15,7 +15,7 @@ impl GameLoadingProgress { } #[async_trait::async_trait] -impl crate::handlers::simple_typed::RlnlEventCodeHandler for GameLoadingProgress { +impl crate::handlers::RlnlEventCodeHandler for GameLoadingProgress { type In = rlnl::events::loading::LoadingProgress; const CODE: rlnl::event_code::NetworkEvent = rlnl::event_code::NetworkEvent::BroadcastLoadingProgress; diff --git a/rc_multiplayer/src/events/mod.rs b/rc_multiplayer/src/events/mod.rs index 9b79751..6968d53 100644 --- a/rc_multiplayer/src/events/mod.rs +++ b/rc_multiplayer/src/events/mod.rs @@ -3,6 +3,8 @@ mod loading_progress; mod all_loading_progress; mod weapon_select; mod activate_sync; +mod loading_done; +//mod player_input; pub async fn handler(init_ctx: &crate::InitConfig) -> crate::handler::LnlEventHandler { crate::handler::LnlEventHandler::new(init_ctx.users.clone(), crate::vehicle_motion::handler(init_ctx)) @@ -11,6 +13,35 @@ pub async fn handler(init_ctx: &crate::InitConfig) -> crate::handler::LnlEventHa .add(all_loading_progress::handler(init_ctx)) .add(weapon_select::handler(init_ctx)) .add(activate_sync::handler(init_ctx)) + .add(loading_done::handler(init_ctx)) + //.add(player_input::handler(init_ctx)) + .add(crate::handlers::Broadcaster::< + true, + {rlnl::event_code::NetworkEvent::OnPlayerInputChanged as i16}, + {rlnl::event_code::NetworkEvent::OnServerReceivedInputChange as i16}, + {literustlib::packet::Property::Unreliable as u8}, + rlnl::events::ingame::MultiPlayerInputChanged, + >::handler(init_ctx)) + .add(crate::handlers::DatalessBroadcaster::< + true, + {rlnl::event_code::NetworkEvent::AlignmentRectifierStarted as i16}, + {rlnl::event_code::NetworkEvent::AlignmentRectifierStarted as i16}, + {literustlib::packet::Property::Unreliable as u8}, + >::handler(init_ctx)) + .add(crate::handlers::Broadcaster::< + true, + {rlnl::event_code::NetworkEvent::FireWeaponEffect as i16}, + {rlnl::event_code::NetworkEvent::FireWeaponEffect as i16}, + {literustlib::packet::Property::Unreliable as u8}, + rlnl::events::ingame::WeaponFireEffect, + >::handler(init_ctx)) + .add(crate::handlers::Broadcaster::< + true, + {rlnl::event_code::NetworkEvent::FireMiss as i16}, + {rlnl::event_code::NetworkEvent::FireMiss as i16}, + {literustlib::packet::Property::Unreliable as u8}, + rlnl::events::ingame::FireMiss, + >::handler(init_ctx)) } #[inline] diff --git a/rc_multiplayer/src/events/player_input.rs b/rc_multiplayer/src/events/player_input.rs new file mode 100644 index 0000000..db87f07 --- /dev/null +++ b/rc_multiplayer/src/events/player_input.rs @@ -0,0 +1,34 @@ +pub struct PlayerInput { + msg_router: tokio::sync::mpsc::Sender, +} + +pub(super) fn handler(init_ctx: &crate::InitConfig) -> crate::handlers::simple_typed::SimpleRlnl { + crate::handlers::simple_typed::SimpleRlnl::new(PlayerInput::new(init_ctx)) +} + +impl PlayerInput { + fn new(init_ctx: &crate::InitConfig) -> Self { + Self { + msg_router: init_ctx.matches_chann.clone(), + } + } +} + +#[async_trait::async_trait] +impl crate::handlers::simple_typed::RlnlEventCodeHandler for PlayerInput { + type In = rlnl::events::ingame::MultiPlayerInputChanged; + const CODE: rlnl::event_code::NetworkEvent = rlnl::event_code::NetworkEvent::OnPlayerInputChanged; + + async fn handle(&self, data: Self::In, _peer: &std::sync::Arc>, user: &crate::UserData, _sender: &std::sync::Arc>) { + if let Some(user_info) = user.user().await { + super::log_channel_send_failure(self.msg_router.send(crate::matches::GameMessage::BroadcastRlnl { + user_id: user_info.user_id(), + event: rlnl::event_code::NetworkEvent::OnServerReceivedInputChange, + property: literustlib::packet::Property::Unreliable, + data: Some(Box::new(data)), + }).await); + } else { + log::error!("Failed to rebroadcast OnPlayerInputChanged for user (no auth!)"); + } + } +} diff --git a/rc_multiplayer/src/events/validate_game_guid.rs b/rc_multiplayer/src/events/validate_game_guid.rs index 41f934f..c3e46ee 100644 --- a/rc_multiplayer/src/events/validate_game_guid.rs +++ b/rc_multiplayer/src/events/validate_game_guid.rs @@ -2,8 +2,8 @@ pub struct AuthUserGame { matches: tokio::sync::mpsc::Sender, } -pub(super) fn handler(init_ctx: &crate::InitConfig) -> crate::handlers::simple_typed::SimpleRlnl { - crate::handlers::simple_typed::SimpleRlnl::new(AuthUserGame::new(init_ctx)) +pub(super) fn handler(init_ctx: &crate::InitConfig) -> crate::handlers::SimpleRlnl { + crate::handlers::SimpleRlnl::new(AuthUserGame::new(init_ctx)) } impl AuthUserGame { @@ -15,7 +15,7 @@ impl AuthUserGame { } #[async_trait::async_trait] -impl crate::handlers::simple_typed::RlnlEventCodeHandler for AuthUserGame { +impl crate::handlers::RlnlEventCodeHandler for AuthUserGame { type In = rlnl::events::loading::GameGuidInfo; const CODE: rlnl::event_code::NetworkEvent = rlnl::event_code::NetworkEvent::ValidateGameGuid; diff --git a/rc_multiplayer/src/events/weapon_select.rs b/rc_multiplayer/src/events/weapon_select.rs index a4fb510..266bae4 100644 --- a/rc_multiplayer/src/events/weapon_select.rs +++ b/rc_multiplayer/src/events/weapon_select.rs @@ -2,8 +2,8 @@ pub struct WeaponSelect { msg_router: tokio::sync::mpsc::Sender, } -pub(super) fn handler(init_ctx: &crate::InitConfig) -> crate::handlers::simple_typed::SimpleRlnl { - crate::handlers::simple_typed::SimpleRlnl::new(WeaponSelect::new(init_ctx)) +pub(super) fn handler(init_ctx: &crate::InitConfig) -> crate::handlers::SimpleRlnl { + crate::handlers::SimpleRlnl::new(WeaponSelect::new(init_ctx)) } impl WeaponSelect { @@ -15,7 +15,7 @@ impl WeaponSelect { } #[async_trait::async_trait] -impl crate::handlers::simple_typed::RlnlEventCodeHandler for WeaponSelect { +impl crate::handlers::RlnlEventCodeHandler for WeaponSelect { type In = rlnl::events::ingame::SelectWeapon; const CODE: rlnl::event_code::NetworkEvent = rlnl::event_code::NetworkEvent::WeaponSelect; diff --git a/rc_multiplayer/src/handler.rs b/rc_multiplayer/src/handler.rs index 4d579ba..3bde74a 100644 --- a/rc_multiplayer/src/handler.rs +++ b/rc_multiplayer/src/handler.rs @@ -26,7 +26,7 @@ impl literustlib_server::EventHandler for LnlEventHandler { type PacketData = super::PacketData; type UserData = super::UserData; - async fn on_receive(&self, data: Self::PacketData, _header: &literustlib::packet::Header, peer: &std::sync::Arc< literustlib_server::Connection>, user: &Self::UserData, sender: &std::sync::Arc>) { + async fn on_receive(&self, data: Self::PacketData, header: &literustlib::packet::Header, peer: &std::sync::Arc< literustlib_server::Connection>, user: &Self::UserData, sender: &std::sync::Arc>) { log::debug!("Got message {:?} (len: {}) from connection id {}", data.message_ty, data.data.len(), peer.id()); match data.message_ty { crate::data::MessageType::ClientMsg => { @@ -36,11 +36,11 @@ impl literustlib_server::EventHandler for LnlEventHandler { let variant_pretty = i16_to_event(data.variant).map(|x| format!("{:?}", x)).unwrap_or_else(|| "???".to_owned()); #[cfg(debug_assertions)] { - panic!("Unsupported event variant {} ({}), pls fix!!!\n {:?}", variant_pretty, data.variant, &data.data[..]); + panic!("Unsupported {:?} event variant {} ({}), pls fix!!!\n {:?}", header.property, variant_pretty, data.variant, &data.data[..]); } #[cfg(not(debug_assertions))] { - log::warn!("Unsupported event variant {} ({}), pls fix!!!", variant_pretty, data.variant); + log::warn!("Unsupported {:?} event variant {} ({}); {:?}, pls fix!!!", header.property, variant_pretty, data.variant); } } }, @@ -136,7 +136,7 @@ impl literustlib::packet::PacketData for EventData { } } -fn i16_to_event(num: i16) -> Option { +const fn i16_to_event(num: i16) -> Option { match num { 0 => Some(rlnl::event_code::NetworkEvent::OnFailedToConnectToMasterServer), 1 => Some(rlnl::event_code::NetworkEvent::OnConnectingToLobbyServer), @@ -295,3 +295,164 @@ fn i16_to_event(num: i16) -> Option { _ => None, } } + +#[inline] +pub const fn i16_to_event_or_panic(num: i16) -> rlnl::event_code::NetworkEvent { + match num { + 0 => rlnl::event_code::NetworkEvent::OnFailedToConnectToMasterServer, + 1 => rlnl::event_code::NetworkEvent::OnConnectingToLobbyServer, + 2 => rlnl::event_code::NetworkEvent::OnConnectedToLobbyServer, + 3 => rlnl::event_code::NetworkEvent::OnDisconnectingFromLobbyServer, + 4 => rlnl::event_code::NetworkEvent::OnDisconnectedFromLobbyServer, + 5 => rlnl::event_code::NetworkEvent::OnConnectedToServer, + 6 => rlnl::event_code::NetworkEvent::OnFailedToConnectToServer, + 7 => rlnl::event_code::NetworkEvent::OnConnectionLost, + 8 => rlnl::event_code::NetworkEvent::OnDisconnectedFromServer, + 9 => rlnl::event_code::NetworkEvent::OnConnectedToGameServer, + 10 => rlnl::event_code::NetworkEvent::OnServerStarted, + 11 => rlnl::event_code::NetworkEvent::OnServerStopped, + 12 => rlnl::event_code::NetworkEvent::OnPlayerConnectedToServer, + 13 => rlnl::event_code::NetworkEvent::OnPlayerDisconnectedFromServer, + 14 => rlnl::event_code::NetworkEvent::RequestRespawnPoint, + 15 => rlnl::event_code::NetworkEvent::FreeSpawnPoint, + 16 => rlnl::event_code::NetworkEvent::RequestTeamBaseModel, + 17 => rlnl::event_code::NetworkEvent::RequestCapturePoints, + 18 => rlnl::event_code::NetworkEvent::RequestEqualizerModel, + 19 => rlnl::event_code::NetworkEvent::TeamBase, + 20 => rlnl::event_code::NetworkEvent::RegisterCapturePoints, + 21 => rlnl::event_code::NetworkEvent::RegisterEqualizer, + 22 => rlnl::event_code::NetworkEvent::FreeRespawnPoint, + 23 => rlnl::event_code::NetworkEvent::PlayerIDs, + 24 => rlnl::event_code::NetworkEvent::SyncMachineCubes, + 25 => rlnl::event_code::NetworkEvent::MachineDestroyed, + 26 => rlnl::event_code::NetworkEvent::GameStarted, + 27 => rlnl::event_code::NetworkEvent::OnPlayerInputChanged, + 28 => rlnl::event_code::NetworkEvent::OnServerReceivedInputChange, + 29 => rlnl::event_code::NetworkEvent::ClientUnregistered, + 30 => rlnl::event_code::NetworkEvent::OnAnotherClientDisconnected, + 31 => rlnl::event_code::NetworkEvent::OnClientReconnected, + 32 => rlnl::event_code::NetworkEvent::DamageCube, + 33 => rlnl::event_code::NetworkEvent::FireWeaponEffect, + 35 => rlnl::event_code::NetworkEvent::FireMiss, + 36 => rlnl::event_code::NetworkEvent::MultipleFireMisses, + 37 => rlnl::event_code::NetworkEvent::CurrentGameTime, + 38 => rlnl::event_code::NetworkEvent::EndGame, + 39 => rlnl::event_code::NetworkEvent::GameWon, + 40 => rlnl::event_code::NetworkEvent::GameLost, + 41 => rlnl::event_code::NetworkEvent::GameWonBaseDestroyed, + 42 => rlnl::event_code::NetworkEvent::GameLostBaseDestroyed, + 43 => rlnl::event_code::NetworkEvent::BuffTeamPlayers, + 44 => rlnl::event_code::NetworkEvent::PlayerThreateningBase, + 45 => rlnl::event_code::NetworkEvent::TimeToGameStart, + 46 => rlnl::event_code::NetworkEvent::SetRespawnWaitingTime, + 47 => rlnl::event_code::NetworkEvent::TeamBaseState, + 48 => rlnl::event_code::NetworkEvent::TeamBaseCaptureStart, + 49 => rlnl::event_code::NetworkEvent::TeamBaseCaptureReset, + 50 => rlnl::event_code::NetworkEvent::TeamBaseCaptureStop, + 51 => rlnl::event_code::NetworkEvent::TeamBaseSectionComplete, + 52 => rlnl::event_code::NetworkEvent::TeamBaseFinalSectionComplete, + 53 => rlnl::event_code::NetworkEvent::TeamBaseInitialise, + 54 => rlnl::event_code::NetworkEvent::GetClientPings, + 55 => rlnl::event_code::NetworkEvent::SetClientPing, + 56 => rlnl::event_code::NetworkEvent::WarnPlayer, + 57 => rlnl::event_code::NetworkEvent::EnemySpotted, + 58 => rlnl::event_code::NetworkEvent::RemoteEnemySpotted, + 59 => rlnl::event_code::NetworkEvent::AssistBonusRequest, + 60 => rlnl::event_code::NetworkEvent::TeamBaseContested, + 61 => rlnl::event_code::NetworkEvent::AcquireRemoteAI, + 63 => rlnl::event_code::NetworkEvent::KillBonusRequest, + 64 => rlnl::event_code::NetworkEvent::EACRegisterToken, + 65 => rlnl::event_code::NetworkEvent::HeallingAssistBonusRequest, + 66 => rlnl::event_code::NetworkEvent::ProtectTeamMateBonusRequest, + 67 => rlnl::event_code::NetworkEvent::DefendTheBaseBonusRequest, + 68 => rlnl::event_code::NetworkEvent::DestroyCubesBonusRequest, + 69 => rlnl::event_code::NetworkEvent::DestroyHealCubesPointsAwarded, + 70 => rlnl::event_code::NetworkEvent::ConfirmedKill, + 71 => rlnl::event_code::NetworkEvent::BonusesFlushDone, + 72 => rlnl::event_code::NetworkEvent::AlignmentRectifierStarted, + 73 => rlnl::event_code::NetworkEvent::HealCubesBonusRequest, + 74 => rlnl::event_code::NetworkEvent::SetShieldState, + 75 => rlnl::event_code::NetworkEvent::TeamBaseLowHealth, + 76 => rlnl::event_code::NetworkEvent::AwardTeamBaseProtoniumDestroyedRequest, + 77 => rlnl::event_code::NetworkEvent::InitialiseGameStats, + 78 => rlnl::event_code::NetworkEvent::UpdateGameStats, + 79 => rlnl::event_code::NetworkEvent::MapPingEvent, + 80 => rlnl::event_code::NetworkEvent::SurrenderRequest, + 81 => rlnl::event_code::NetworkEvent::HealSelf, + 82 => rlnl::event_code::NetworkEvent::HealSelfResponse, + 83 => rlnl::event_code::NetworkEvent::SurrenderVoteStarted, + 84 => rlnl::event_code::NetworkEvent::SurrenderVoteCast, + 85 => rlnl::event_code::NetworkEvent::CurrentSurrenderVotes, + 86 => rlnl::event_code::NetworkEvent::SurrenderAccepted, + 87 => rlnl::event_code::NetworkEvent::SurrenderDeclined, + 88 => rlnl::event_code::NetworkEvent::SetSurrenderTimes, + 89 => rlnl::event_code::NetworkEvent::SetFinalGameScore, + 90 => rlnl::event_code::NetworkEvent::PitLeaderBoardUpdate, + 91 => rlnl::event_code::NetworkEvent::PitModeState, + 93 => rlnl::event_code::NetworkEvent::ValidateGameGuid, + 94 => rlnl::event_code::NetworkEvent::GameGuidValidated, + 95 => rlnl::event_code::NetworkEvent::PlayerInsideBase, + 97 => rlnl::event_code::NetworkEvent::ConfirmedAssist, + 98 => rlnl::event_code::NetworkEvent::LockOnNotification, + 99 => rlnl::event_code::NetworkEvent::LockOnNotificationBroadcast, + 100 => rlnl::event_code::NetworkEvent::ShieldSpawned, + 101 => rlnl::event_code::NetworkEvent::SpawnShield, + 102 => rlnl::event_code::NetworkEvent::BroadcastOpenShield, + 103 => rlnl::event_code::NetworkEvent::OpenShield, + 104 => rlnl::event_code::NetworkEvent::BroadcastInvisible, + 105 => rlnl::event_code::NetworkEvent::MakeInvisible, + 106 => rlnl::event_code::NetworkEvent::BroadcastVisible, + 107 => rlnl::event_code::NetworkEvent::MakeVisible, + 108 => rlnl::event_code::NetworkEvent::BroadcastActivateTeleportEffect, + 109 => rlnl::event_code::NetworkEvent::ActivateTeleportEffect, + 110 => rlnl::event_code::NetworkEvent::BroadcastActivateReadyEffect, + 111 => rlnl::event_code::NetworkEvent::ActivateReadyEffect, + 112 => rlnl::event_code::NetworkEvent::BroadcastSpawnEmpLocator, + 113 => rlnl::event_code::NetworkEvent::SpawnEmpLocator, + 114 => rlnl::event_code::NetworkEvent::BroadcastSpawnEmpMachineEffect, + 115 => rlnl::event_code::NetworkEvent::SpawnEmpMachineEffect, + 116 => rlnl::event_code::NetworkEvent::WeaponSelect, + 117 => rlnl::event_code::NetworkEvent::BroadcastWeaponSelect, + 118 => rlnl::event_code::NetworkEvent::HostAIs, + 119 => rlnl::event_code::NetworkEvent::HealAlly, + 120 => rlnl::event_code::NetworkEvent::HealAllyResponse, + 121 => rlnl::event_code::NetworkEvent::SelfDestructClassicMode, + 122 => rlnl::event_code::NetworkEvent::GameModeSettings, + 123 => rlnl::event_code::NetworkEvent::TeamDeathMatchState, + 124 => rlnl::event_code::NetworkEvent::ClientDisconnecting, + 125 => rlnl::event_code::NetworkEvent::SendBonus, + 126 => rlnl::event_code::NetworkEvent::TestConnection, + 127 => rlnl::event_code::NetworkEvent::MachineDestroyedConfirmed, + 128 => rlnl::event_code::NetworkEvent::EnergyModuleActivated, + 129 => rlnl::event_code::NetworkEvent::BroadcastLoadingProgress, + 130 => rlnl::event_code::NetworkEvent::RequestLoadingProgressAllUsers, + 131 => rlnl::event_code::NetworkEvent::LoadingComplete, + 132 => rlnl::event_code::NetworkEvent::GameAborted, + 134 => rlnl::event_code::NetworkEvent::SendDamagedByEnemyShield, + 135 => rlnl::event_code::NetworkEvent::DamagedByEnemyShield, + 136 => rlnl::event_code::NetworkEvent::EqualizerNotification, + 137 => rlnl::event_code::NetworkEvent::CapturePointProgress, + 138 => rlnl::event_code::NetworkEvent::CapturePointNotification, + 140 => rlnl::event_code::NetworkEvent::RadarModuleActivated, + 141 => rlnl::event_code::NetworkEvent::RemoteRadarModuleActivated, + 142 => rlnl::event_code::NetworkEvent::EACMessage, + 143 => rlnl::event_code::NetworkEvent::Taunt, + 144 => rlnl::event_code::NetworkEvent::MachineFullHealth, + 145 => rlnl::event_code::NetworkEvent::RequestSync, + 146 => rlnl::event_code::NetworkEvent::BeginSync, + 147 => rlnl::event_code::NetworkEvent::EndOfSync, + 148 => rlnl::event_code::NetworkEvent::SyncTeamBaseCubes, + 150 => rlnl::event_code::NetworkEvent::SyncEqualizerNotification, + 151 => rlnl::event_code::NetworkEvent::PlayerQuitRequest, + 152 => rlnl::event_code::NetworkEvent::PlayerQuitRequestComplete, + 153 => rlnl::event_code::NetworkEvent::DamageCubeEffectOnly, + 154 => rlnl::event_code::NetworkEvent::DamageCubeNoEffect, + 155 => rlnl::event_code::NetworkEvent::DestroyCubeEffectOnly, + 156 => rlnl::event_code::NetworkEvent::DestroyCubeNoEffect, + 157 => rlnl::event_code::NetworkEvent::DestroyCubesFull, + 170 => rlnl::event_code::NetworkEvent::LongPlayValue, + 171 => rlnl::event_code::NetworkEvent::UpdateVotingAfterBattle, + 172 => rlnl::event_code::NetworkEvent::CosmeticAction, + _ => panic!("Invalid rlnl event code"), + } +} diff --git a/rc_multiplayer/src/handlers/ingame_broadcast.rs b/rc_multiplayer/src/handlers/ingame_broadcast.rs new file mode 100644 index 0000000..c04187e --- /dev/null +++ b/rc_multiplayer/src/handlers/ingame_broadcast.rs @@ -0,0 +1,51 @@ +pub struct Broadcaster + byteserde::ser_heap::ByteSerializeHeap + Send + Sync + 'static> { + msg_router: tokio::sync::mpsc::Sender, + code_out: rlnl::event_code::NetworkEvent, + property: literustlib::packet::Property, + _in: std::marker::PhantomData, +} + +impl + byteserde::ser_heap::ByteSerializeHeap + Send + Sync + 'static> Broadcaster { + pub fn handler(init_ctx: &crate::InitConfig) -> crate::handlers::simple_typed::SimpleRlnl { + crate::handlers::simple_typed::SimpleRlnl::new(Broadcaster::new(init_ctx)) + } + + fn new(init_ctx: &crate::InitConfig) -> Self { + Self { + msg_router: init_ctx.matches_chann.clone(), + code_out: crate::handler::i16_to_event_or_panic(CODE_OUT), + property: literustlib::packet::Property::try_from(PROPERTY).expect("Invalid literustlib packet property"), + _in: std::marker::PhantomData::default(), + } + } +} + +#[async_trait::async_trait] +impl + byteserde::ser_heap::ByteSerializeHeap + Send + Sync + 'static> crate::handlers::simple_typed::RlnlEventCodeHandler for Broadcaster { + type In = InOut; + const CODE: rlnl::event_code::NetworkEvent = crate::handler::i16_to_event_or_panic(CODE_IN); + + async fn handle(&self, data: Self::In, _peer: &std::sync::Arc>, user: &crate::UserData, _sender: &std::sync::Arc>) { + if let Some(user_info) = user.user().await { + + if EXCLUDE_SENDER { + crate::events::log_channel_send_failure(self.msg_router.send(crate::matches::GameMessage::RebroadcastRlnl { + skip_user_id: user_info.user_id(), + event: self.code_out, + property: self.property, + data: Some(Box::new(data)), + }).await); + } else { + crate::events::log_channel_send_failure(self.msg_router.send(crate::matches::GameMessage::BroadcastRlnl { + user_id: user_info.user_id(), + event: self.code_out, + property: self.property, + data: Some(Box::new(data)), + }).await); + } + + } else { + log::error!("Failed to rebroadcast OnPlayerInputChanged for user (no auth!)"); + } + } +} diff --git a/rc_multiplayer/src/handlers/ingame_broadcast_dataless.rs b/rc_multiplayer/src/handlers/ingame_broadcast_dataless.rs new file mode 100644 index 0000000..2dcce58 --- /dev/null +++ b/rc_multiplayer/src/handlers/ingame_broadcast_dataless.rs @@ -0,0 +1,47 @@ +pub struct DatalessBroadcaster { + msg_router: tokio::sync::mpsc::Sender, + code_out: rlnl::event_code::NetworkEvent, + property: literustlib::packet::Property, +} + +impl DatalessBroadcaster { + pub fn handler(init_ctx: &crate::InitConfig) -> crate::handlers::dataless::Dataless { + crate::handlers::dataless::Dataless::new(Self::new(init_ctx)) + } + + fn new(init_ctx: &crate::InitConfig) -> Self { + Self { + msg_router: init_ctx.matches_chann.clone(), + code_out: crate::handler::i16_to_event_or_panic(CODE_OUT), + property: literustlib::packet::Property::try_from(PROPERTY).expect("Invalid literustlib packet property"), + } + } +} + +#[async_trait::async_trait] +impl crate::handlers::dataless::DatalessEventCodeHandler for DatalessBroadcaster { + const CODE: rlnl::event_code::NetworkEvent = crate::handler::i16_to_event_or_panic(CODE_IN); + + async fn handle(&self, _peer: &std::sync::Arc>, user: &crate::UserData, _sender: &std::sync::Arc>) { + if let Some(user_info) = user.user().await { + if EXCLUDE_SENDER { + crate::events::log_channel_send_failure(self.msg_router.send(crate::matches::GameMessage::RebroadcastRlnl { + skip_user_id: user_info.user_id(), + event: self.code_out, + property: self.property, + data: None, + }).await); + } else { + crate::events::log_channel_send_failure(self.msg_router.send(crate::matches::GameMessage::BroadcastRlnl { + user_id: user_info.user_id(), + event: self.code_out, + property: self.property, + data: None, + }).await); + } + + } else { + log::error!("Failed to rebroadcast OnPlayerInputChanged for user (no auth!)"); + } + } +} diff --git a/rc_multiplayer/src/handlers/mod.rs b/rc_multiplayer/src/handlers/mod.rs index 4779f2d..6d8a75e 100644 --- a/rc_multiplayer/src/handlers/mod.rs +++ b/rc_multiplayer/src/handlers/mod.rs @@ -1,2 +1,11 @@ -pub mod simple_typed; -pub mod dataless; +mod simple_typed; +pub use simple_typed::{RlnlEventCodeHandler, SimpleRlnl, RlnlSender}; + +mod dataless; +pub use dataless::{Dataless, DatalessEventCodeHandler}; + +mod ingame_broadcast; +pub use ingame_broadcast::Broadcaster; + +mod ingame_broadcast_dataless; +pub use ingame_broadcast_dataless::DatalessBroadcaster; diff --git a/rc_multiplayer/src/handlers/simple_typed.rs b/rc_multiplayer/src/handlers/simple_typed.rs index a445d00..49a258e 100644 --- a/rc_multiplayer/src/handlers/simple_typed.rs +++ b/rc_multiplayer/src/handlers/simple_typed.rs @@ -46,7 +46,7 @@ impl <'a> RlnlSender<'a> { } } - pub async fn send_data(&self, data: &D, event: rlnl::event_code::NetworkEvent, property: literustlib::packet::Property, conn: &literustlib_server::Connection) -> std::io::Result { + pub async fn send_data(&self, data: &D, event: rlnl::event_code::NetworkEvent, property: literustlib::packet::Property, conn: &literustlib_server::Connection) -> std::io::Result { let mut ser = byteserde::ser_heap::ByteSerializerHeap::default(); data.byte_serialize_heap(&mut ser).map_err(|e| std::io::Error::new(std::io::ErrorKind::Unsupported, e.message))?; let event_data = crate::handler::EventData::with_data( diff --git a/rc_multiplayer/src/matches/countdown.rs b/rc_multiplayer/src/matches/countdown.rs new file mode 100644 index 0000000..d0ae60b --- /dev/null +++ b/rc_multiplayer/src/matches/countdown.rs @@ -0,0 +1,45 @@ +pub fn match_countdown(players: Vec, game_start: chrono::DateTime) { + tokio::spawn(do_match_countdown_async(players, game_start)); +} + +pub fn time_to_game_start_payload(game_start: chrono::DateTime) -> rlnl::events::GameTime { + let now = chrono::Utc::now(); + let time_until_start = game_start.signed_duration_since(now); + let time_until_start_f32 = (time_until_start.abs().num_milliseconds() as f32) / 1000.0; + rlnl::events::GameTime(time_until_start_f32) +} + +async fn do_match_countdown_async(players: Vec, game_start: chrono::DateTime) { + let now = chrono::Utc::now(); + let time_until_start = game_start.signed_duration_since(now); + + let payload = time_to_game_start_payload(game_start); + for player in players.iter() { + let sender = player.rlnl(); + if let Err(e) = sender.send_data( + &payload, + rlnl::event_code::NetworkEvent::TimeToGameStart, + literustlib::packet::Property::ReliableOrdered, + &player.connection) + .await { + log::error!("Failed to send TimeToGameStart to a user: {}", e); + } + } + + tokio::time::sleep(time_until_start.to_std().unwrap_or_default()).await; + log::debug!("Sending starting game event"); + let payload = rlnl::events::ingame::GameStart { + is_reconnecting: 0, + }; + for player in players { + let sender = player.rlnl(); + if let Err(e) = sender.send_data( + &payload, + rlnl::event_code::NetworkEvent::GameStarted, + literustlib::packet::Property::ReliableOrdered, + &player.connection) + .await { + log::error!("Failed to send GameStarted event to a user: {}", e); + } + } +} diff --git a/rc_multiplayer/src/matches/engine.rs b/rc_multiplayer/src/matches/engine.rs index ae2f7f7..036ceca 100644 --- a/rc_multiplayer/src/matches/engine.rs +++ b/rc_multiplayer/src/matches/engine.rs @@ -1,3 +1,2 @@ pub trait GamemodeEngine: Send + Sync { - fn is_complete(&self) -> bool; } diff --git a/rc_multiplayer/src/matches/generic.rs b/rc_multiplayer/src/matches/generic.rs index 5427d56..af579a2 100644 --- a/rc_multiplayer/src/matches/generic.rs +++ b/rc_multiplayer/src/matches/generic.rs @@ -1,11 +1,22 @@ pub(super) struct UserConnection { pub(super) user: std::sync::Arc>, - pub(super) connection: std::sync::Arc>, - pub(super) sender: std::sync::Arc>, + pub(super) connection: UserSender, pub(super) state: UserState, pub(super) machine: MachineState, } +#[derive(Clone)] +pub(super) struct UserSender { + pub(super) connection: std::sync::Arc>, + pub(super) sender: std::sync::Arc>, +} + +impl UserSender { + pub fn rlnl(&self) -> crate::handlers::RlnlSender<'_> { + crate::handlers::RlnlSender::new(&self.sender) + } +} + pub(super) struct UserState { pub(super) mode: std::sync::atomic::AtomicU8, pub(super) progress: std::sync::atomic::AtomicU8, // percent @@ -82,9 +93,13 @@ pub(super) struct GenericGamemodeEngine { //pub send: tokio::sync::mpsc::Sender, pub game_guid: String, pub is_complete: std::sync::atomic::AtomicBool, + pub game_start: std::sync::atomic::AtomicI64, } impl GenericGamemodeEngine { + const END_OF_SYNC_DELAY: std::time::Duration = std::time::Duration::from_millis(100); + const COUNTDOWN_DURATION: std::time::Duration = std::time::Duration::from_secs(5); + pub fn new(guid: String) -> Self { Self { @@ -92,6 +107,7 @@ impl GenericGamemodeEngine { user_id_map: tokio::sync::RwLock::new(std::collections::HashMap::new()), game_guid: guid, is_complete: std::sync::atomic::AtomicBool::new(false), + game_start: std::sync::atomic::AtomicI64::new(-1), } } @@ -99,15 +115,50 @@ impl GenericGamemodeEngine { self.user_id_map.read().await.get(&user_id).map(|x| *x) } - pub(super) async fn broadcast(&self, user_id: i32, code: rlnl::event_code::NetworkEvent, property: literustlib::packet::Property, data: T) { + pub(super) async fn rebroadcast(&self, user_id: i32, code: rlnl::event_code::NetworkEvent, property: literustlib::packet::Property, data: &T) { for conn in self.users.read().await.values() { if user_id == conn.user.user_id() { continue; } - let sender = crate::handlers::simple_typed::RlnlSender::new(&conn.sender); + let sender = crate::handlers::RlnlSender::new(&conn.connection.sender); crate::events::log_lnl_send_failure(sender.send_data( - &data, + data, code, property, - &conn.connection, + &conn.connection.connection, + ).await); + } + } + + pub(super) async fn rebroadcast_dataless(&self, user_id: i32, code: rlnl::event_code::NetworkEvent, property: literustlib::packet::Property) { + for conn in self.users.read().await.values() { + if user_id == conn.user.user_id() { continue; } + let sender = crate::handlers::RlnlSender::new(&conn.connection.sender); + crate::events::log_lnl_send_failure(sender.send_empty( + code, + property, + &conn.connection.connection, + ).await); + } + } + + pub(super) async fn broadcast(&self, code: rlnl::event_code::NetworkEvent, property: literustlib::packet::Property, data: &T) { + for conn in self.users.read().await.values() { + let sender = conn.connection.rlnl(); + crate::events::log_lnl_send_failure(sender.send_data( + data, + code, + property, + &conn.connection.connection, + ).await); + } + } + + pub(super) async fn broadcast_dataless(&self, code: rlnl::event_code::NetworkEvent, property: literustlib::packet::Property) { + for conn in self.users.read().await.values() { + let sender = conn.connection.rlnl(); + crate::events::log_lnl_send_failure(sender.send_empty( + code, + property, + &conn.connection.connection, ).await); } } @@ -133,14 +184,16 @@ impl GenericGamemodeEngine { let mut users = self.users.write().await; let new_user = UserConnection { user, - connection, - sender, + connection: UserSender { + connection, + sender, + }, state: UserState::new(), machine: MachineState::new(), }; //tokio::time::sleep(std::time::Duration::from_secs(1)).await; let id = users.len() as u8; - if let Err(e) = self.send_loading_events(&new_user, id).await { + if let Err(e) = self.send_loading_events(&new_user.connection, id).await { response.send(Some(super::messages::ErrorMessage { message: "Failed to send GameGuidValidated response".to_owned(), inner: Some(Box::new(e)), @@ -158,19 +211,23 @@ impl GenericGamemodeEngine { user_name: rlnl::types::BinaryWriterString(user_name), progress, }; + let mut all_users_loading_complete = true; for conn in self.users.read().await.values() { if user_id == conn.user.user_id() { let progress_percent = (progress * 100.0).ceil() as u8; log::debug!("User {} is loaded {}% into game {}", user_id, progress_percent, self.game_guid); conn.state.progress.store(progress_percent, std::sync::atomic::Ordering::Relaxed); + all_users_loading_complete &= progress_percent == 100; + } else { + all_users_loading_complete &= conn.state.progress.load(std::sync::atomic::Ordering::Relaxed) == 100; } let mode = ConnectionMode::from_u8(conn.state.mode.load(std::sync::atomic::Ordering::Relaxed)); match mode { ConnectionMode::Loading | ConnectionMode::Sync => { if user_id != conn.user.user_id() { - crate::events::log_lnl_send_failure(crate::handlers::simple_typed::RlnlSender::new(&conn.sender) - .send_data(&progress_data, rlnl::event_code::NetworkEvent::BroadcastLoadingProgress, literustlib::packet::Property::ReliableOrdered, &conn.connection).await); + crate::events::log_lnl_send_failure(conn.connection.rlnl() + .send_data(&progress_data, rlnl::event_code::NetworkEvent::BroadcastLoadingProgress, literustlib::packet::Property::ReliableOrdered, &conn.connection.connection).await); } /*if progress > 0.95 { log::info!("User {} is ready, ending sync", user_id); @@ -188,6 +245,24 @@ impl GenericGamemodeEngine { log::warn!("Got loading progress for user {} who is supposed to be already in-game", user_id); }, } + if !matches!(mode, ConnectionMode::Sync) { + all_users_loading_complete = false; + } + } + // trigger game start + if all_users_loading_complete { + log::info!("All players are ready for game {}", self.game_guid); + tokio::time::sleep(Self::END_OF_SYNC_DELAY).await; + let mut senders = Vec::new(); + for conn in self.users.read().await.values() { + crate::events::log_lnl_send_failure(conn.connection.rlnl() + .send_empty(rlnl::event_code::NetworkEvent::EndOfSync, literustlib::packet::Property::ReliableOrdered, &conn.connection.connection).await); + + senders.push(conn.connection.clone()); + } + let game_start = chrono::Utc::now() + Self::COUNTDOWN_DURATION; + self.game_start.store(game_start.timestamp(), std::sync::atomic::Ordering::Relaxed); + super::countdown::match_countdown(senders, game_start); } } super::GameMessage::RequestLoadingProgress { user_id } => { @@ -195,7 +270,6 @@ impl GenericGamemodeEngine { for conn in self.users.read().await.values() { if user_id == conn.user.user_id() { user_info = Some(( - conn.sender.to_owned(), conn.connection.to_owned(), rlnl::events::loading::LoadingProgress { user_name: rlnl::types::BinaryWriterString(conn.user.user_name().to_owned()), @@ -205,14 +279,14 @@ impl GenericGamemodeEngine { } } if let Some(user_info) = user_info { - let sender = crate::handlers::simple_typed::RlnlSender::new(&user_info.0); + let sender = crate::handlers::RlnlSender::new(&user_info.0.sender); for conn in self.users.read().await.values() { if user_id == conn.user.user_id() { continue; } crate::events::log_lnl_send_failure(sender.send_data( - &user_info.2, + &user_info.1, rlnl::event_code::NetworkEvent::BroadcastLoadingProgress, literustlib::packet::Property::ReliableOrdered, - &user_info.1, + &user_info.0.connection, ).await); } } else { @@ -231,11 +305,11 @@ impl GenericGamemodeEngine { item_category: category_u32, item_size: size_u32, }; - self.broadcast( + self.rebroadcast( user_id, rlnl::event_code::NetworkEvent::BroadcastWeaponSelect, literustlib::packet::Property::ReliableOrdered, - data, + &data, ).await; } }, @@ -246,15 +320,50 @@ impl GenericGamemodeEngine { } } }, + super::GameMessage::LoadComplete { user_id } => { + if let Some(user_key) = self.user_key_by_user_id(user_id).await { + if let Some(conn) = self.users.read().await.get(&user_key) { + log::debug!("Loading complete for game {}, user {} ({})", self.game_guid, user_id, user_key); + let game_start = chrono::DateTime::from_timestamp(self.game_start.load(std::sync::atomic::Ordering::Relaxed), 0).unwrap(); + let payload = super::countdown::time_to_game_start_payload(game_start); + let sender = conn.connection.rlnl(); + if let Err(e) = sender.send_data( + &payload, + rlnl::event_code::NetworkEvent::TimeToGameStart, + literustlib::packet::Property::ReliableOrdered, + &conn.connection.connection) + .await { + log::error!("Failed to send updated TimeToGameStart to a user: {}", e); + } + self.spawn_initial_ingame_events(conn, user_id); + } + } + } + super::GameMessage::BroadcastRlnl { user_id: _, event, property, data } => { + if let Some(data) = data { + self.broadcast(event, property, &*data).await; + } else { + self.broadcast_dataless(event, property).await; + } + + } + super::GameMessage::RebroadcastRlnl { skip_user_id, event, property, data } => { + if let Some(data) = data { + self.rebroadcast(skip_user_id, event, property, &*data).await; + } else { + self.rebroadcast_dataless(skip_user_id, event, property).await; + } + + } super::GameMessage::Motion { user_id, data } => { for conn in self.users.read().await.values() { if conn.user.user_id() == user_id { continue; } // fun fact: the game hard crashes if you omit this - crate::events::log_lnl_send_failure(conn.sender.send_data(crate::handler::EventData { + crate::events::log_lnl_send_failure(conn.connection.sender.send_data(crate::handler::EventData { message_ty: crate::data::MessageType::RobotMotion, variant: 0, data_size: data.len() as _, data: data.clone(), - }, literustlib::packet::Property::Unreliable, &conn.connection).await); + }, literustlib::packet::Property::Unreliable, &conn.connection.connection).await); } } super::GameMessage::NoOp => {}, @@ -264,8 +373,8 @@ impl GenericGamemodeEngine { self.is_complete.store(true, std::sync::atomic::Ordering::Relaxed); } - async fn send_loading_events(&self, user: &UserConnection, player_id: u8) -> std::io::Result<()> { - let sender = crate::handlers::simple_typed::RlnlSender::new(&user.sender); + async fn send_loading_events(&self, user: &UserSender, player_id: u8) -> std::io::Result<()> { + let sender = user.rlnl(); sender.send_data( &rlnl::events::loading::PlayerID { owner: player_id }, rlnl::event_code::NetworkEvent::GameGuidValidated, @@ -305,24 +414,23 @@ impl GenericGamemodeEngine { } fn spawn_send_sync_events(&self, user: &UserConnection, user_id: i32) { - let sender = user.sender.clone(); let connection = user.connection.clone(); - tokio::spawn(Self::send_sync_events_wrapper(connection, sender, user_id)); + tokio::spawn(Self::send_sync_events_wrapper(connection, user_id)); user.state.mode.store(ConnectionMode::Sync.to_u8(), std::sync::atomic::Ordering::Relaxed); } - async fn send_sync_events_wrapper(connection: std::sync::Arc>, sender: std::sync::Arc>, user_id: i32) { - if let Err(e) = Self::send_sync_events(connection, sender).await { + async fn send_sync_events_wrapper(connection: UserSender, user_id: i32) { + if let Err(e) = Self::send_sync_events(connection).await { log::error!("Failed to send Sync events for user {}: {}", user_id, e); } } - async fn send_sync_events(connection: std::sync::Arc>, sender: std::sync::Arc>) -> std::io::Result<()> { - let sender = crate::handlers::simple_typed::RlnlSender::new(&sender); + async fn send_sync_events(connection: UserSender) -> std::io::Result<()> { + let sender = connection.rlnl(); sender.send_empty( rlnl::event_code::NetworkEvent::BeginSync, literustlib::packet::Property::ReliableOrdered, - &connection) + &connection.connection) .await?; // sudden death sender.send_data( @@ -332,13 +440,13 @@ impl GenericGamemodeEngine { }, rlnl::event_code::NetworkEvent::GameModeSettings, literustlib::packet::Property::ReliableOrdered, - &connection) + &connection.connection) .await?; sender.send_data( &rlnl::events::GameTime(300.0), // FIXME use value from config rlnl::event_code::NetworkEvent::CurrentGameTime, literustlib::packet::Property::ReliableOrdered, - &connection) + &connection.connection) .await?; // generic sender.send_data( @@ -359,20 +467,21 @@ impl GenericGamemodeEngine { }, rlnl::event_code::NetworkEvent::InitialiseGameStats, literustlib::packet::Property::ReliableOrdered, - &connection) + &connection.connection) .await?; sender.send_data( &rlnl::events::sync::SpawnPoint { pos: rlnl::types::PosQuatPair { - pos: rlnl::types::CompressedVec3 { x: 0, y: 0, z: 0 }, + pos: rlnl::types::CompressedVec3 { x: 0, y: 42, z: 0 }, rot: rlnl::types::CompressedQuat { x: 0, y: 0, z: 0 }, }, owner: 0, }, rlnl::event_code::NetworkEvent::FreeSpawnPoint, literustlib::packet::Property::ReliableOrdered, - &connection) + &connection.connection) .await?; + // seems to be for reconnecting /*sender.send_data( &rlnl::events::sync::SyncMachineCubes { machine_id: 0, @@ -393,10 +502,31 @@ impl GenericGamemodeEngine { .await?;*/ Ok(()) } -} -impl super::GamemodeEngine for GenericGamemodeEngine { - fn is_complete(&self) -> bool { - self.is_complete.load(std::sync::atomic::Ordering::Relaxed) // for now, this is never closed + fn spawn_initial_ingame_events(&self, user: &UserConnection, user_id: i32) { + let connection = user.connection.clone(); + tokio::spawn(Self::send_initial_ingame_events_wrapper(connection, user_id)); + user.state.mode.store(ConnectionMode::InGame.to_u8(), std::sync::atomic::Ordering::Relaxed); + } + + async fn send_initial_ingame_events_wrapper(connection: UserSender, user_id: i32) { + if let Err(e) = Self::send_initial_ingame_events(connection).await { + log::error!("Failed to send Sync events for user {}: {}", user_id, e); + } + } + + async fn send_initial_ingame_events(_connection: UserSender) -> std::io::Result<()> { + //let sender = connection.rlnl(); + /*sender.send_data( + &rlnl::events::GameTime(3.0), + rlnl::event_code::NetworkEvent::TimeToGameStart, + literustlib::packet::Property::ReliableOrdered, + &connection.connection) + .await?;*/ + + // TODO + Ok(()) } } + +impl super::GamemodeEngine for GenericGamemodeEngine {} diff --git a/rc_multiplayer/src/matches/messages.rs b/rc_multiplayer/src/matches/messages.rs index 2dc30b9..ef416b9 100644 --- a/rc_multiplayer/src/matches/messages.rs +++ b/rc_multiplayer/src/matches/messages.rs @@ -23,6 +23,21 @@ pub enum GameMessage { RequestLoadingSync { user_id: i32, }, + LoadComplete { + user_id: i32, + }, + BroadcastRlnl { + user_id: i32, + event: rlnl::event_code::NetworkEvent, + property: literustlib::packet::Property, + data: Option>, + }, + RebroadcastRlnl { + skip_user_id: i32, + event: rlnl::event_code::NetworkEvent, + property: literustlib::packet::Property, + data: Option>, + }, Motion { user_id: i32, data: bytes::Bytes, @@ -40,6 +55,9 @@ impl GameMessage { Self::RequestLoadingProgress { user_id, .. } => *user_id, Self::WeaponSelect { user_id, .. } => *user_id, Self::RequestLoadingSync { user_id, .. } => *user_id, + Self::LoadComplete { user_id, .. } => *user_id, + Self::BroadcastRlnl { user_id, .. } => *user_id, + Self::RebroadcastRlnl { skip_user_id, .. } => *skip_user_id, Self::Motion { user_id, .. } => *user_id, Self::NoOp => unreachable!("NoOp is irrelevant for user ID"), } diff --git a/rc_multiplayer/src/matches/mod.rs b/rc_multiplayer/src/matches/mod.rs index 7e8f590..78da3ff 100644 --- a/rc_multiplayer/src/matches/mod.rs +++ b/rc_multiplayer/src/matches/mod.rs @@ -10,4 +10,6 @@ pub(self) use generic::GenericGamemodeEngine; mod aggregate; pub use aggregate::GameMatches; +mod countdown; + pub const CHANNEL_BOUND: usize = 16; diff --git a/rc_services_room/src/operations/mod.rs b/rc_services_room/src/operations/mod.rs index 2187669..2e7560f 100644 --- a/rc_services_room/src/operations/mod.rs +++ b/rc_services_room/src/operations/mod.rs @@ -218,4 +218,5 @@ pub fn handler(init_ctx: &crate::InitConfig) -> OperationsHandler .add(garage_slot_name::garage_slot_rename_provider()) .add(garage_slot_copy::garage_slot_copy_provider()) .add(polariton_server::operations::Ack::<12, _>::default()) // TODO handle UpdatePlayerDailyQuestProgressRequest instead of ignoring it + .add(polariton_server::operations::Ack::<90, _>::default()) // TODO handle SubmitCRFRatingRequest instead of ignoring it }