diff --git a/server/game/benchmarks/bench.rs b/server/game/benchmarks/bench.rs index b9504308..197b956b 100644 --- a/server/game/benchmarks/bench.rs +++ b/server/game/benchmarks/bench.rs @@ -95,7 +95,13 @@ fn managers(c: &mut Criterion) { for level_id in 0..100 { for account_id in 0..10 { manager.add_to_level(level_id, level_id * 10 + account_id); - manager.set_player_data(level_id * 10 + account_id, &PlayerData {}); + manager.set_player_data( + level_id * 10 + account_id, + &PlayerData { + percentage: 0, + attempts: 0, + }, + ); } } diff --git a/server/game/src/data/packets/client/game.rs b/server/game/src/data/packets/client/game.rs index 1c087076..b31991c4 100644 --- a/server/game/src/data/packets/client/game.rs +++ b/server/game/src/data/packets/client/game.rs @@ -1,5 +1,11 @@ use crate::data::*; +#[derive(Packet, Decodable)] +#[packet(id = 12000, encrypted = false)] +pub struct RequestPlayerProfilesPacket { + pub requested: i32, // 0 to get all ppl on the level +} + #[derive(Packet, Decodable)] #[packet(id = 12001, encrypted = false)] pub struct LevelJoinPacket { @@ -16,13 +22,6 @@ pub struct PlayerDataPacket { pub data: PlayerData, } -#[derive(Packet, Decodable)] -#[packet(id = 12004, encrypted = false)] -pub struct SyncPlayerMetadataPacket { - pub data: PlayerMetadata, - pub requested: Option, -} - #[derive(Packet, Decodable)] #[packet(id = 12010, encrypted = true)] pub struct VoicePacket { diff --git a/server/game/src/data/packets/server/game.rs b/server/game/src/data/packets/server/game.rs index 675f207b..3a265dd6 100644 --- a/server/game/src/data/packets/server/game.rs +++ b/server/game/src/data/packets/server/game.rs @@ -5,12 +5,12 @@ use crate::data::*; */ #[derive(Packet, Encodable)] -#[packet(id = 22001, encrypted = false)] -pub struct LevelDataPacket; +#[packet(id = 22000, encrypted = false)] +pub struct PlayerProfilesPacket; #[derive(Packet, Encodable)] -#[packet(id = 22002, encrypted = false)] -pub struct PlayerMetadataPacket; +#[packet(id = 22001, encrypted = false)] +pub struct LevelDataPacket; #[derive(Packet, Encodable)] #[packet(id = 22010, encrypted = true)] diff --git a/server/game/src/data/types/gd.rs b/server/game/src/data/types/gd.rs index b1a57d41..f24acff0 100644 --- a/server/game/src/data/types/gd.rs +++ b/server/game/src/data/types/gd.rs @@ -146,7 +146,10 @@ pub enum IconType { /* PlayerData (data in a level) */ #[derive(Clone, Default, Encodable, KnownSize, Decodable)] -pub struct PlayerData {} +pub struct PlayerData { + pub percentage: u16, + pub attempts: i32, +} /* AssociatedPlayerData */ @@ -155,19 +158,3 @@ pub struct AssociatedPlayerData { pub account_id: i32, pub data: PlayerData, } - -/* PlayerMetadata (things like your percentage in a level, attempt count) */ - -#[derive(Copy, Clone, Default, Encodable, KnownSize, Decodable)] -pub struct PlayerMetadata { - percentage: u16, - attempts: i32, -} - -/* FullPlayerMetadata */ - -#[derive(Clone, Default, Encodable, KnownSize)] -pub struct FullPlayerMetadata { - pub account_data: PlayerAccountData, - pub metadata: PlayerMetadata, -} diff --git a/server/game/src/managers/player.rs b/server/game/src/managers/player.rs index 0164c155..c0ac6f4b 100644 --- a/server/game/src/managers/player.rs +++ b/server/game/src/managers/player.rs @@ -1,20 +1,11 @@ use nohash_hasher::IntMap; -use crate::data::{ - types::{AssociatedPlayerData, PlayerData}, - PlayerMetadata, -}; - -#[derive(Default)] -pub struct PlayerEntry { - pub data: AssociatedPlayerData, - pub meta: PlayerMetadata, -} +use crate::data::types::{AssociatedPlayerData, PlayerData}; #[derive(Default)] pub struct PlayerManager { - pub players: IntMap, // player id : associated data - pub levels: IntMap>, // level id : [player id] + pub players: IntMap, // player id : associated data + pub levels: IntMap>, // level id : [player id] } impl PlayerManager { @@ -23,36 +14,29 @@ impl PlayerManager { } pub fn get_player_data(&self, account_id: i32) -> Option<&AssociatedPlayerData> { - self.players.get(&account_id).map(|entry| &entry.data) - } - - pub fn get_player_metadata(&self, account_id: i32) -> Option<&PlayerMetadata> { - self.players.get(&account_id).map(|entry| &entry.meta) + self.players.get(&account_id) } pub fn create_player(&mut self, account_id: i32) { - let mut entry = PlayerEntry::default(); - entry.data.account_id = account_id; - - self.players.insert(account_id, entry); + self.players.insert( + account_id, + AssociatedPlayerData { + account_id, + ..Default::default() + }, + ); } - fn get_or_create_player(&mut self, account_id: i32) -> &mut PlayerEntry { - self.players.entry(account_id).or_insert_with(|| { - let mut entry = PlayerEntry::default(); - entry.data.account_id = account_id; - entry + fn get_or_create_player(&mut self, account_id: i32) -> &mut AssociatedPlayerData { + self.players.entry(account_id).or_insert_with(|| AssociatedPlayerData { + account_id, + ..Default::default() }) } /// set player's data, inserting a new entry if doesn't already exist pub fn set_player_data(&mut self, account_id: i32, data: &PlayerData) { - self.get_or_create_player(account_id).data.data.clone_from(data); - } - - /// set player's metadata, inserting a new entry if it doesn't already exist - pub fn set_player_metadata(&mut self, account_id: i32, data: &PlayerMetadata) { - self.get_or_create_player(account_id).meta.clone_from(data); + self.get_or_create_player(account_id).data.clone_from(data); } /// remove the player from the list of players @@ -78,7 +62,7 @@ impl PlayerManager { /// run a function `f` on each player on a level given its ID, with possibility to pass additional data pub fn for_each_player_on_level(&self, level_id: i32, f: F, additional: &mut A) -> usize where - F: Fn(&PlayerEntry, usize, &mut A) -> bool, + F: Fn(&AssociatedPlayerData, usize, &mut A) -> bool, { if let Some(ids) = self.levels.get(&level_id) { ids.iter() @@ -92,7 +76,7 @@ impl PlayerManager { /// run a function `f` on each player in this `PlayerManager`, with possibility to pass additional data pub fn for_each_player(&self, f: F, additional: &mut A) -> usize where - F: Fn(&PlayerEntry, usize, &mut A) -> bool, + F: Fn(&AssociatedPlayerData, usize, &mut A) -> bool, { self.players .values() diff --git a/server/game/src/server_thread/handlers/game.rs b/server/game/src/server_thread/handlers/game.rs index 7520993c..67590b75 100644 --- a/server/game/src/server_thread/handlers/game.rs +++ b/server/game/src/server_thread/handlers/game.rs @@ -79,8 +79,8 @@ impl GameServerThread { level_id, |player, count, buf| { // we do additional length check because player count may have increased since 1st lock - if count < written_players && player.data.account_id != account_id { - buf.write_value(&player.data); + if count < written_players && player.account_id != account_id { + buf.write_value(player); true } else { false @@ -100,7 +100,7 @@ impl GameServerThread { Ok(()) }); - gs_handler!(self, handle_sync_player_metadata, SyncPlayerMetadataPacket, packet, { + gs_handler!(self, handle_request_profiles, RequestPlayerProfilesPacket, packet, { let account_id = gs_needauth!(self); let level_id = self.level_id.load(Ordering::Relaxed); @@ -111,7 +111,6 @@ impl GameServerThread { let room_id = self.room_id.load(Ordering::Relaxed); let total_players = self.game_server.state.room_manager.with_any(room_id, |pm| { - pm.set_player_metadata(account_id, &packet.data); // this unwrap should be safe and > 0 given that self.level_id != 0, but we leave a default just in case pm.get_player_count_on_level(level_id).unwrap_or(1) - 1 }); @@ -121,54 +120,41 @@ impl GameServerThread { return Ok(()); } - let written_players = if packet.requested.is_some() { 1 } else { total_players }; + let written_players = if packet.requested != 0 { 1 } else { total_players }; - let calc_size = size_of_types!(PacketHeader, u32) + size_of_types!(FullPlayerMetadata) * written_players; + let calc_size = size_of_types!(PacketHeader, u32) + size_of_types!(PlayerAccountData) * written_players; gs_inline_encode!(self, calc_size, buf, { - buf.write_packet_header::(); + buf.write_packet_header::(); buf.write_u32(written_players as u32); - let written = self.game_server.state.room_manager.with_any(room_id, |pm| { - // if they requested one specific player, encode just them (if we find them) - if let Some(player_id) = packet.requested { - if let Some(meta) = pm.get_player_metadata(player_id) { - let account_data = self.game_server.get_player_account_data(player_id); - if account_data.is_some() { - let fpm = FullPlayerMetadata { - metadata: *meta, - account_data: account_data.unwrap(), - }; - - buf.write_value(&fpm); - return 1; - } - } - - return 0; + // if they requested one specific player, encode just them (if we find them) + let written = if packet.requested != 0 { + let account_data = self.game_server.get_player_account_data(packet.requested); + if let Some(data) = account_data { + buf.write_value(&data); + 1 + } else { + 0 } - - // otherwise, encode everyone on the level - pm.for_each_player_on_level( - level_id, - |player, count, buf| { - let account_data = self.game_server.get_player_account_data(player.data.account_id); - // we do additional length check because player count may have changed since 1st lock - if count < written_players && player.data.account_id != account_id && account_data.is_some() { - let fpm = FullPlayerMetadata { - metadata: player.meta, - account_data: account_data.unwrap(), - }; - - buf.write_value(&fpm); - true - } else { - false - } - }, - &mut buf, - ) - }); + } else { + self.game_server.state.room_manager.with_any(room_id, |pm| { + // otherwise, encode everyone on the level + pm.for_each_player_on_level( + level_id, + |player, count, buf| { + // we do additional length check because player count may have changed since 1st lock + if count < written_players && player.account_id != account_id { + let account_data = self.game_server.get_player_account_data(player.account_id); + account_data.map(|data| buf.write_value(&data)).is_some() + } else { + false + } + }, + &mut buf, + ) + }) + }; // if the player count has instead decreased, we now lied and the client will fail decoding. re-encode the actual count. if written != written_players { diff --git a/server/game/src/server_thread/mod.rs b/server/game/src/server_thread/mod.rs index 2aea6abe..57779d77 100644 --- a/server/game/src/server_thread/mod.rs +++ b/server/game/src/server_thread/mod.rs @@ -431,10 +431,10 @@ impl GameServerThread { RequestRoomPlayerListPacket::PACKET_ID => self.handle_request_room_list(&mut data).await, /* game related */ + RequestPlayerProfilesPacket::PACKET_ID => self.handle_request_profiles(&mut data).await, LevelJoinPacket::PACKET_ID => self.handle_level_join(&mut data).await, LevelLeavePacket::PACKET_ID => self.handle_level_leave(&mut data).await, PlayerDataPacket::PACKET_ID => self.handle_player_data(&mut data).await, - SyncPlayerMetadataPacket::PACKET_ID => self.handle_sync_player_metadata(&mut data).await, VoicePacket::PACKET_ID => self.handle_voice(&mut data).await, ChatMessagePacket::PACKET_ID => self.handle_chat_message(&mut data).await, diff --git a/server/game/tests/test.rs b/server/game/tests/test.rs index 8b947787..72f06155 100644 --- a/server/game/tests/test.rs +++ b/server/game/tests/test.rs @@ -106,7 +106,13 @@ fn test_player_manager() { for level_id in 0..100 { for account_id in 0..100 { manager.add_to_level(level_id, level_id * 100 + account_id); - manager.set_player_data(level_id * 100 + account_id, &PlayerData {}); + manager.set_player_data( + level_id * 100 + account_id, + &PlayerData { + percentage: 0, + attempts: 0, + }, + ); } } diff --git a/server/protocol.md b/server/protocol.md index c63c76f2..febf8650 100644 --- a/server/protocol.md +++ b/server/protocol.md @@ -37,10 +37,10 @@ General Game related +* 12000 - RequestPlayerProfilesPacket - request account data of another player (or all people on the level) * 12001 - LevelJoinPacket - join a level * 12002 - LevelLeavePacket - leave a level * 12003 - PlayerDataPacket - player data -* 12004^ - SyncPlayerMetadataPacket - request player account data & metadata and sync own * 12010+ - VoicePacket - voice frame * 12011?^+ - ChatMessagePacket - chat message @@ -67,7 +67,7 @@ General Game related +* 22000 - PlayerProfilesPacket - list of requested profiles * 22001 - LevelDataPacket - level data -* 22002 - PlayerMetadataPacket - list of player metadata * 22010+ - VoiceBroadcastPacket - voice frame from another user * 22011+ - ChatMessageBroadcastPacket - chat message from another user \ No newline at end of file diff --git a/src/audio/manager.cpp b/src/audio/manager.cpp index a3ecd664..986d8c9a 100644 --- a/src/audio/manager.cpp +++ b/src/audio/manager.cpp @@ -36,7 +36,10 @@ std::vector GlobedAudioManager::getRecordingDevices() { ) for (int i = 0; i < numDrivers; i++) { - out.push_back(this->getRecordingDevice(i)); + auto dev = this->getRecordingDevice(i); + if (dev.has_value()) { + out.push_back(dev.value()); + } } return out; @@ -52,23 +55,28 @@ std::vector GlobedAudioManager::getPlaybackDevices() { ) for (int i = 0; i < numDrivers; i++) { - out.push_back(this->getPlaybackDevice(i)); + auto dev = this->getPlaybackDevice(i); + if (dev.has_value()) { + out.push_back(dev.value()); + } } return out; } -AudioRecordingDevice GlobedAudioManager::getRecordingDevice(int deviceId) { +std::optional GlobedAudioManager::getRecordingDevice(int deviceId) { AudioRecordingDevice device; char name[256]; - FMOD_ERR_CHECK(this->getSystem()->getRecordDriverInfo( + if (this->getSystem()->getRecordDriverInfo( deviceId, name, 256, &device.guid, &device.sampleRate, &device.speakerMode, &device.speakerModeChannels, &device.driverState - ), "System::getRecordDriverInfo") + ) != FMOD_OK) { + return std::nullopt; + } device.id = deviceId; device.name = std::string(name); @@ -76,16 +84,18 @@ AudioRecordingDevice GlobedAudioManager::getRecordingDevice(int deviceId) { return device; } -AudioPlaybackDevice GlobedAudioManager::getPlaybackDevice(int deviceId) { +std::optional GlobedAudioManager::getPlaybackDevice(int deviceId) { AudioPlaybackDevice device; char name[256]; - FMOD_ERR_CHECK(this->getSystem()->getDriverInfo( + if (this->getSystem()->getDriverInfo( deviceId, name, 256, &device.guid, &device.sampleRate, &device.speakerMode, &device.speakerModeChannels - ), "System::getDriverInfo") + ) != FMOD_OK) { + return std::nullopt; + } device.id = deviceId; device.name = std::string(name); @@ -99,18 +109,16 @@ bool GlobedAudioManager::isRecordingDeviceSet() { void GlobedAudioManager::validateDevices() { if (recordDevice.id != -1) { - try { - recordDevice = this->getRecordingDevice(recordDevice.id); - } catch (const std::exception& e) { - geode::log::info("Invalidating recording device {}: {}", recordDevice.id, e.what()); + this->setActiveRecordingDevice(recordDevice.id); + if (recordDevice.id == -1) { + geode::log::info("Invalidating recording device {}", recordDevice.id); } } if (playbackDevice.id != -1) { - try { - playbackDevice = this->getPlaybackDevice(playbackDevice.id); - } catch (const std::exception& e) { - geode::log::info("Invalidating playback device {}: {}", playbackDevice.id, e.what()); + this->setActivePlaybackDevice(playbackDevice.id); + if (playbackDevice.id == -1) { + geode::log::info("Invalidating playback device {}", playbackDevice.id); } } } @@ -265,11 +273,21 @@ void GlobedAudioManager::setActiveRecordingDevice(int deviceId) { GLOBED_REQUIRE(!this->isRecording(), "attempting to change the recording device while recording") } - recordDevice = this->getRecordingDevice(deviceId); + auto dev = this->getRecordingDevice(deviceId); + if (dev.has_value()) { + recordDevice = dev.value(); + } else { + recordDevice.id = -1; + } } void GlobedAudioManager::setActivePlaybackDevice(int deviceId) { - playbackDevice = this->getPlaybackDevice(deviceId); + auto dev = this->getPlaybackDevice(deviceId); + if (dev.has_value()) { + playbackDevice = dev.value(); + } else { + playbackDevice.id = -1; + } } void GlobedAudioManager::recordInvokeCallback() { @@ -277,8 +295,8 @@ void GlobedAudioManager::recordInvokeCallback() { try { recordCallback(recordFrame); - } catch (const std::exception& e) { - ErrorQueues::get().error(std::string("Exception in audio callback: ") + e.what()); + } CATCH { + ErrorQueues::get().error(std::string("Exception in audio callback: ") + CATCH_GET_EXC); } recordFrame.clear(); @@ -346,8 +364,8 @@ void GlobedAudioManager::audioThreadFunc() { try { recordFrame.pushOpusFrame(encoder.encode(pcmbuf)); - } catch (const std::exception& e) { - ErrorQueues::get().error(std::string("Exception in audio thread: ") + e.what()); + } CATCH { + ErrorQueues::get().error(std::string("Exception in audio thread: ") + CATCH_GET_EXC); continue; } } diff --git a/src/audio/manager.hpp b/src/audio/manager.hpp index 980948cc..c3da477e 100644 --- a/src/audio/manager.hpp +++ b/src/audio/manager.hpp @@ -48,9 +48,9 @@ class GlobedAudioManager : GLOBED_SINGLETON(GlobedAudioManager) { std::vector getPlaybackDevices(); // get the record device by device ID - AudioRecordingDevice getRecordingDevice(int deviceId); + std::optional getRecordingDevice(int deviceId); // get the playback device by device ID - AudioPlaybackDevice getPlaybackDevice(int deviceId); + std::optional getPlaybackDevice(int deviceId); // get the current active record device AudioRecordingDevice getRecordingDevice(); diff --git a/src/data/bytebuffer.hpp b/src/data/bytebuffer.hpp index 9db30b6e..d6725703 100644 --- a/src/data/bytebuffer.hpp +++ b/src/data/bytebuffer.hpp @@ -362,5 +362,6 @@ class ByteBuffer { inline void boundsCheck(size_t readBytes) { GLOBED_REQUIRE(_position + readBytes <= _data.size(), "ByteBuffer out of bounds read") + // throw 1; } }; \ No newline at end of file diff --git a/src/data/packets/all.cpp b/src/data/packets/all.cpp index a9c4199c..06aec23e 100644 --- a/src/data/packets/all.cpp +++ b/src/data/packets/all.cpp @@ -24,8 +24,8 @@ std::shared_ptr matchPacket(packetid_t packetId) { // game related + PACKET(PlayerProfilesPacket); PACKET(LevelDataPacket); - PACKET(PlayerMetadataPacket); #if GLOBED_VOICE_SUPPORT PACKET(VoiceBroadcastPacket); #endif diff --git a/src/data/packets/client/game.hpp b/src/data/packets/client/game.hpp index da0428fa..446225aa 100644 --- a/src/data/packets/client/game.hpp +++ b/src/data/packets/client/game.hpp @@ -2,6 +2,24 @@ #include #include +class RequestPlayerProfilesPacket : public Packet { + GLOBED_PACKET(12000, false) + + GLOBED_PACKET_ENCODE { + buf.writeI32(requested); + } + + GLOBED_PACKET_DECODE_UNIMPL + + RequestPlayerProfilesPacket(int requested) : requested(requested) {} + + static std::shared_ptr create(int requested) { + return std::make_shared(requested); + } + + int requested; +}; + class LevelJoinPacket : public Packet { GLOBED_PACKET(12001, false) @@ -51,32 +69,6 @@ class PlayerDataPacket : public Packet { PlayerData data; }; -class SyncPlayerMetadataPacket : public Packet { - GLOBED_PACKET(12004, false) - - GLOBED_PACKET_ENCODE { - buf.writeValue(data); - - // what a dogshit fucking language that refuses to work unless i write down a whole essay in my variable declaration - std::function ef = [](auto& buf, const int& val) { - buf.writeI32(val); - }; - - buf.writeOptionalValue(requested, ef); - } - - GLOBED_PACKET_DECODE_UNIMPL - - SyncPlayerMetadataPacket(const PlayerMetadata& data, const std::optional& requested) : data(data), requested(requested) {} - - static std::shared_ptr create(const PlayerMetadata& data, const std::optional& requested) { - return std::make_shared(data, requested); - } - - PlayerMetadata data; - std::optional requested; -}; - #if GLOBED_VOICE_SUPPORT #include