From dbc862291fb9c003a32083e952262456e69528a2 Mon Sep 17 00:00:00 2001 From: dank_meme01 <42031238+dankmeme01@users.noreply.github.com> Date: Thu, 7 Dec 2023 14:26:11 +0100 Subject: [PATCH] stuff and some tidying --- .gitignore | 7 +- CMakeLists.txt | 15 +- server/central/src/config.rs | 10 +- server/game-derive/src/lib.rs | 2 +- server/game/Cargo.toml | 14 ++ server/game/benchmarks/bench.rs | 133 +++++++++++++++++ server/game/src/data/bytebufferext.rs | 72 +++------ server/game/src/data/types/common.rs | 56 +++++-- server/game/src/lib.rs | 17 +++ server/game/src/main.rs | 4 +- server/game/src/managers/player.rs | 27 ++-- .../game/src/server_thread/handlers/game.rs | 37 +---- server/game/src/server_thread/handlers/mod.rs | 2 +- server/game/src/server_thread/mod.rs | 66 ++++++--- server/game/tests/test.rs | 138 ++++++++++++++++++ server/shared/src/lib.rs | 4 +- src/audio/all.hpp | 2 +- src/audio/audio_frame.hpp | 2 +- src/audio/audio_manager.cpp | 36 ++--- src/audio/audio_manager.hpp | 4 +- src/audio/audio_sample_queue.hpp | 2 +- src/audio/audio_stream.cpp | 5 +- src/audio/audio_stream.hpp | 2 +- src/audio/opus_codec.cpp | 2 +- src/audio/opus_codec.hpp | 2 +- src/audio/voice_playback_manager.cpp | 2 +- src/audio/voice_playback_manager.hpp | 4 +- src/config.hpp | 2 +- src/crypto/base_box.hpp | 2 +- src/crypto/box.cpp | 12 +- src/crypto/box.hpp | 12 +- src/crypto/secret_box.cpp | 12 +- src/crypto/secret_box.hpp | 12 +- src/defs.hpp | 2 +- src/defs/net.hpp | 2 +- src/main.cpp | 2 +- src/managers/account_manager.cpp | 1 - src/managers/central_server_manager.cpp | 4 +- src/managers/central_server_manager.hpp | 2 +- src/managers/error_queues.hpp | 2 +- src/managers/game_server_manager.hpp | 2 +- src/managers/settings.hpp | 2 +- src/net/network_manager.cpp | 4 +- src/net/udp_socket.cpp | 2 +- src/ui/error_check_node.cpp | 2 +- src/ui/error_check_node.hpp | 4 +- src/ui/hooks/menu_layer.hpp | 2 +- src/ui/hooks/play_layer.hpp | 11 +- src/ui/menu/main/globed_menu_layer.cpp | 15 +- src/ui/menu/main/signup_layer.cpp | 2 +- src/ui/menu/main/signup_popup.cpp | 6 +- .../menu/server_switcher/add_server_popup.cpp | 2 +- src/util/crypto.cpp | 10 +- src/util/data.hpp | 2 +- src/util/debugging.cpp | 8 +- src/util/math.cpp | 16 +- src/util/math.hpp | 12 ++ src/util/net.cpp | 4 +- src/util/rng.cpp | 5 + src/util/rng.hpp | 3 + src/util/sync.hpp | 2 +- src/util/time.cpp | 2 +- src/util/time.hpp | 2 +- src/util/ui.cpp | 2 +- src/util/ui.hpp | 4 +- 65 files changed, 602 insertions(+), 258 deletions(-) create mode 100644 server/game/benchmarks/bench.rs create mode 100644 server/game/src/lib.rs create mode 100644 server/game/tests/test.rs diff --git a/.gitignore b/.gitignore index 377c6dd8..b1ecf72d 100644 --- a/.gitignore +++ b/.gitignore @@ -62,4 +62,9 @@ mod-a.json server/bench-client server/target server/central-conf.json -server/Cargo.lock \ No newline at end of file +server/Cargo.lock +server/game/flamegraph.svg +server/game/perf.data +server/game/perf.data.old +server/game/test-flamegraph.sh +server/game/test-bench.sh \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 2d0444e1..5742026c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,7 +21,7 @@ file(GLOB_RECURSE SOURCES # Include winsock if (CMAKE_SYSTEM_NAME STREQUAL "Windows") add_compile_definitions(WIN32_LEAN_AND_MEAN=1) # geode moment - add_definitions(/FI"winsock2.h") + add_definitions(/FI"WinSock2.h") endif() # i am crying so hard right now @@ -29,13 +29,20 @@ if (CMAKE_HOST_SYSTEM MATCHES "Linux" AND CMAKE_SYSTEM_NAME STREQUAL "Windows") add_compile_options("-march=skylake") endif() -# disable iterator debugging if building in debug -if (CMAKE_BUILD_TYPE STREQUAL "Debug") - add_compile_definitions(_HAS_ITERATOR_DEBUGGING=0) +# enable exceptions on android +if (ANDROID) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fexceptions") endif() add_library(${PROJECT_NAME} SHARED ${SOURCES}) +# enable extra warnings +if (CMAKE_HOST_SYSTEM STREQUAL "Windows") +else() + # i hate this language okay? + target_compile_options(${PROJECT_NAME} PRIVATE -Wall -Wextra -Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-c++11-compat -Wno-c++14-compat -Wno-c++17-compat -Wno-old-style-cast -Wno-implicit-int-float-conversion -Wno-global-constructors -Wno-pre-c++20-compat-pedantic -Wno-exit-time-destructors -Wno-reserved-identifier -Wno-reserved-macro-identifier -Wno-dollar-in-identifier-extension -Wno-ctad-maybe-unsupported -Wno-unsafe-buffer-usage -Wno-newline-eof -Wno-shadow -Wno-inconsistent-missing-destructor-override -Wno-float-conversion -Wno-shorten-64-to-32 -Wno-sign-conversion -Wno-suggest-destructor-override -Wno-suggest-override -Wno-overloaded-virtual -Wno-unused-parameter -Wno-undefined-func-template -Wno-non-virtual-dtor -Wno-sign-compare -Wno-header-hygiene) +endif() + if (NOT DEFINED ENV{GEODE_SDK}) message(FATAL_ERROR "Unable to find Geode SDK! Please define GEODE_SDK environment variable to point to Geode") else() diff --git a/server/central/src/config.rs b/server/central/src/config.rs index b71c935e..961d7534 100644 --- a/server/central/src/config.rs +++ b/server/central/src/config.rs @@ -1,5 +1,5 @@ use std::{ - collections::{HashMap, HashSet}, + collections::HashMap, fs::{File, OpenOptions}, path::Path, }; @@ -47,8 +47,8 @@ fn default_userlist_mode() -> UserlistMode { UserlistMode::None } -fn default_userlist() -> HashSet<i32> { - HashSet::new() +fn default_userlist() -> Vec<i32> { + Vec::new() } fn default_tps() -> u32 { @@ -121,9 +121,9 @@ pub struct ServerConfig { #[serde(default = "default_userlist_mode")] pub userlist_mode: UserlistMode, #[serde(default = "default_userlist")] - pub userlist: HashSet<i32>, + pub userlist: Vec<i32>, #[serde(default = "default_userlist")] - pub no_chat_list: HashSet<i32>, + pub no_chat_list: Vec<i32>, // game stuff #[serde(default = "default_tps")] diff --git a/server/game-derive/src/lib.rs b/server/game-derive/src/lib.rs index 18e56bd2..3014e50c 100644 --- a/server/game-derive/src/lib.rs +++ b/server/game-derive/src/lib.rs @@ -270,7 +270,7 @@ struct PacketAttributes { encrypted: bool, } -/// Implements `Packet`, `PacketMetadata` and the function `header() -> PacketHeader` for the given struct. +/// Implements `Packet`, `PacketMetadata` and the function `const fn header() -> PacketHeader` for the given struct. /// You must also pass additional attributes with `#[packet]`, specifically packet ID and whether the packet should be encrypted. /// Example: /// ```rust diff --git a/server/game/Cargo.toml b/server/game/Cargo.toml index b4857133..ed3ac8cf 100644 --- a/server/game/Cargo.toml +++ b/server/game/Cargo.toml @@ -14,9 +14,23 @@ anyhow = "1.0.75" array-init = "2.1.0" bytebuffer = "2.2.0" crypto_box = { version = "0.9.1", features = ["std", "chacha20"] } +nohash-hasher = "0.2.0" parking_lot = "0.12.1" reqwest = "0.11.22" rustc-hash = "1.1.0" serde = { version = "1.0.193", features = ["serde_derive"] } serde_json = "1.0.108" tokio = { version = "1.34.0", features = ["full"] } + +[dev-dependencies] +criterion = "0.5.1" +rand = "0.8.5" + +[[bench]] +name = "globed-bench" +path = "benchmarks/bench.rs" +harness = false + +[[test]] +name = "globed-tests" +path = "tests/test.rs" diff --git a/server/game/benchmarks/bench.rs b/server/game/benchmarks/bench.rs new file mode 100644 index 00000000..b9504308 --- /dev/null +++ b/server/game/benchmarks/bench.rs @@ -0,0 +1,133 @@ +#![allow(clippy::wildcard_imports)] +use bytebuffer::{ByteBuffer, ByteReader}; +use criterion::{black_box, criterion_group, criterion_main, Criterion}; +use globed_game_server::{data::*, managers::PlayerManager}; +use rand::RngCore; + +fn buffers(c: &mut Criterion) { + let data = PlayerAccountData { + account_id: 234_234_234, + name: FastString::from_str("hit his is my name"), + icons: PlayerIconData::default(), + special_user_data: Some(SpecialUserData { + name_color: Color3B { r: 10, g: 100, b: 200 }, + }), + }; + + c.bench_function("alloca-byte-buffer", |b| { + b.iter(black_box(|| { + alloca::with_alloca(PlayerAccountData::ENCODED_SIZE * 64, |data_| { + let stackarray = unsafe { + let ptr = data_.as_mut_ptr().cast::<u8>(); + std::slice::from_raw_parts_mut(ptr, std::mem::size_of_val(data_)) + }; + + let mut buf = FastByteBuffer::new(stackarray); + for _ in 0..64 { + buf.write_value(&data); + } + + // let mut buf = ByteReader::from_bytes(stackarray); + // for _ in 0..64 { + // assert_eq!(buf.read_value::<PlayerAccountData>().unwrap().account_id, data.account_id); + // } + }); + })); + }); + + c.bench_function("fast-byte-buffer", |b| { + b.iter(black_box(|| { + let mut stackarray = [0u8; PlayerAccountData::ENCODED_SIZE * 64]; + let mut buf = FastByteBuffer::new(&mut stackarray); + for _ in 0..64 { + buf.write_value(&data); + } + + // let mut buf = ByteReader::from_bytes(&stackarray); + // for _ in 0..64 { + // assert_eq!(buf.read_value::<PlayerAccountData>().unwrap().account_id, data.account_id); + // } + })); + }); + + c.bench_function("slow-byte-buffer", |b| { + b.iter(black_box(|| { + let mut buffer = ByteBuffer::new(); + for _ in 0..64 { + buffer.write_value(&data); + } + })); + }); +} + +fn structs(c: &mut Criterion) { + let mut data = [0u8; 2048]; + rand::thread_rng().fill_bytes(&mut data); + + c.bench_function("encode-audio-frame", |b| { + b.iter(black_box(|| { + let data = FastEncodedAudioFrame { + data: data.to_vec().into(), + }; + let mut stack_array = [0u8; 3000 * 8]; + let mut buf = FastByteBuffer::new(&mut stack_array); + for _ in 0..8 { + buf.write_value(&data); + } + + let written_data = buf.as_bytes(); + + for _ in 0..128 { + let mut reader = ByteReader::from_bytes(written_data); + + let abc = reader.read_value::<FastEncodedAudioFrame>().unwrap(); + assert_eq!(abc.data.len(), written_data.len()); + } + })); + }); +} + +fn managers(c: &mut Criterion) { + c.bench_function("player-manager", |b| { + b.iter(black_box(|| { + let mut manager = PlayerManager::new(); + + 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 {}); + } + } + + let mut total_players = 0; + for i in 0..100 { + let count = manager.get_player_count_on_level(i).unwrap_or(0); + assert_eq!(count, 10); + + let total = manager.for_each_player_on_level( + i, + |_, _, p| { + *p += 1; + true + }, + &mut total_players, + ); + + assert_eq!(total, count); + } + + assert_eq!(total_players, 1000); + + for level_id in 0..100 { + for account_id in 0..10 { + manager.remove_from_level(level_id, level_id * 10 + account_id); + manager.remove_player(level_id * 10 + account_id); + } + } + })); + }); +} + +criterion_group!(benches, buffers, structs, managers); +// criterion_group!(benches, structs); +criterion_main!(benches); diff --git a/server/game/src/data/bytebufferext.rs b/server/game/src/data/bytebufferext.rs index ec4ab06f..63d3e0bd 100644 --- a/server/game/src/data/bytebufferext.rs +++ b/server/game/src/data/bytebufferext.rs @@ -1,9 +1,6 @@ use std::fmt::Display; -use crate::data::{ - packets::{PacketHeader, PacketMetadata}, - types::cocos, -}; +use crate::data::packets::{PacketHeader, PacketMetadata}; use bytebuffer::{ByteBuffer, ByteReader}; #[derive(Debug)] @@ -132,18 +129,6 @@ macro_rules! size_calc_impl { }; } -/// Simple way of getting total encoded size of given primitives. -/// -/// Example usage: -/// ```rust -/// assert_eq!(16, size_of_primitives!(u64, i32, i16, i8, bool)); -/// ``` -macro_rules! size_of_primitives { - ($($t:ty),+ $(,)?) => {{ - 0 $(+ std::mem::size_of::<$t>())* - }}; -} - /// Simple way of getting total (maximum) encoded size of given types that implement `Encodable` and `KnownSize` /// /// Example usage: @@ -159,7 +144,6 @@ macro_rules! size_of_types { pub(crate) use decode_impl; pub(crate) use encode_impl; pub(crate) use size_calc_impl; -pub(crate) use size_of_primitives; pub(crate) use size_of_types; /* ByteBuffer extensions */ @@ -187,10 +171,6 @@ pub trait ByteBufferExtWrite { fn write_value_vec<T: Encodable>(&mut self, val: &[T]); fn write_packet_header<T: PacketMetadata>(&mut self); - - fn write_color3(&mut self, val: cocos::Color3B); - fn write_color4(&mut self, val: cocos::Color4B); - fn write_point(&mut self, val: cocos::Point); } pub trait ByteBufferExtRead { @@ -214,20 +194,18 @@ pub trait ByteBufferExtRead { fn read_value_vec<T: Decodable>(&mut self) -> DecodeResult<Vec<T>>; fn read_packet_header(&mut self) -> DecodeResult<PacketHeader>; - - fn read_color3(&mut self) -> DecodeResult<cocos::Color3B>; - fn read_color4(&mut self) -> DecodeResult<cocos::Color4B>; - fn read_point(&mut self) -> DecodeResult<cocos::Point>; } /// Buffer for encoding that does zero heap allocation but also has limited functionality. /// It will panic on writes if there isn't enough space. +/// On average, is at least 5x faster than a regular `ByteBuffer`. pub struct FastByteBuffer<'a> { pos: usize, len: usize, data: &'a mut [u8], } +#[allow(clippy::inline_always)] impl<'a> FastByteBuffer<'a> { /// Create a new `FastByteBuffer` given this mutable slice pub fn new(src: &'a mut [u8]) -> Self { @@ -242,71 +220,88 @@ impl<'a> FastByteBuffer<'a> { Self { pos: 0, len, data: src } } + #[inline(always)] pub fn write_u8(&mut self, val: u8) { self.internal_write(&val.to_be_bytes()); } + #[inline(always)] pub fn write_u16(&mut self, val: u16) { self.internal_write(&val.to_be_bytes()); } + #[inline(always)] pub fn write_u32(&mut self, val: u32) { self.internal_write(&val.to_be_bytes()); } + #[inline(always)] pub fn write_u64(&mut self, val: u64) { self.internal_write(&val.to_be_bytes()); } + #[inline(always)] pub fn write_i8(&mut self, val: i8) { self.internal_write(&val.to_be_bytes()); } + #[inline(always)] pub fn write_i16(&mut self, val: i16) { self.internal_write(&val.to_be_bytes()); } + #[inline(always)] pub fn write_i32(&mut self, val: i32) { self.internal_write(&val.to_be_bytes()); } + #[inline(always)] pub fn write_i64(&mut self, val: i64) { self.internal_write(&val.to_be_bytes()); } + #[inline(always)] pub fn write_f32(&mut self, val: f32) { self.internal_write(&val.to_be_bytes()); } + #[inline(always)] pub fn write_f64(&mut self, val: f64) { self.internal_write(&val.to_be_bytes()); } + #[inline(always)] pub fn write_bytes(&mut self, data: &[u8]) { self.internal_write(data); } + #[inline(always)] pub fn write_string(&mut self, val: &str) { self.write_u32(val.len() as u32); self.write_bytes(val.as_bytes()); } + #[inline(always)] pub fn as_bytes(&'a mut self) -> &'a [u8] { &self.data[..self.len] } + #[inline(always)] pub fn len(&self) -> usize { self.len } + #[inline(always)] pub fn set_pos(&mut self, pos: usize) { self.pos = pos; } + #[inline(always)] pub fn is_empty(&self) -> bool { self.len == 0 } + #[inline(always)] pub fn capacity(&self) -> usize { self.data.len() } @@ -373,18 +368,6 @@ macro_rules! impl_extwrite { fn write_packet_header<T: PacketMetadata>(&mut self) { self.write_value(&PacketHeader::from_packet::<T>()); } - - fn write_color3(&mut self, val: cocos::Color3B) { - self.write_value(&val); - } - - fn write_color4(&mut self, val: cocos::Color4B) { - self.write_value(&val); - } - - fn write_point(&mut self, val: cocos::Point) { - self.write_value(&val); - } }; } @@ -403,7 +386,8 @@ macro_rules! impl_extread { let remainder = self.len() - self.get_rpos(); let mut data = Vec::with_capacity(remainder); - // safety: we don't allow to read any unitialized memory, as we trust the return value of `Read::read` + // safety: we use `Vec::set_len` appropriately so the caller won't be able to read uninitialized data. + // we could avoid unsafe and use io::Read::read_to_end here, but that is significantly slower. unsafe { let ptr = data.as_mut_ptr(); let mut slice = std::slice::from_raw_parts_mut(ptr, remainder); @@ -442,18 +426,6 @@ macro_rules! impl_extread { fn read_packet_header(&mut self) -> DecodeResult<PacketHeader> { self.read_value() } - - fn read_color3(&mut self) -> DecodeResult<cocos::Color3B> { - self.read_value() - } - - fn read_color4(&mut self) -> DecodeResult<cocos::Color4B> { - self.read_value() - } - - fn read_point(&mut self) -> DecodeResult<cocos::Point> { - self.read_value() - } }; } diff --git a/server/game/src/data/types/common.rs b/server/game/src/data/types/common.rs index b1bb8e08..95976834 100644 --- a/server/game/src/data/types/common.rs +++ b/server/game/src/data/types/common.rs @@ -9,13 +9,33 @@ use crate::data::bytebufferext::*; macro_rules! impl_primitive { ($typ:ty,$read:ident,$write:ident) => { - encode_impl!($typ, buf, self, { - buf.$write(*self); - }); - - decode_impl!($typ, buf, { buf.$read().map_err(|e| e.into()) }); - - size_calc_impl!($typ, size_of_primitives!(Self)); + impl crate::data::Encodable for $typ { + #[inline(always)] + fn encode(&self, buf: &mut bytebuffer::ByteBuffer) { + buf.$write(*self); + } + + #[inline(always)] + fn encode_fast(&self, buf: &mut crate::data::FastByteBuffer) { + buf.$write(*self); + } + } + + impl crate::data::Decodable for $typ { + #[inline(always)] + fn decode(buf: &mut bytebuffer::ByteBuffer) -> crate::data::DecodeResult<Self> { + buf.$read().map_err(|e| e.into()) + } + + #[inline(always)] + fn decode_from_reader(buf: &mut bytebuffer::ByteReader) -> crate::data::DecodeResult<Self> { + buf.$read().map_err(|e| e.into()) + } + } + + impl crate::data::KnownSize for $typ { + const ENCODED_SIZE: usize = std::mem::size_of::<$typ>(); + } }; } @@ -167,12 +187,12 @@ decode_impl!(PublicKey, buf, { Ok(Self::from_bytes(key)) }); -/* RemainderBytes - wrapper around Vec<u8> that decodes with `buf.read_remaining_bytes()` and encodes with `buf.write_bytes()` */ +/* RemainderBytes - wrapper around Box<[u8]> that decodes with `buf.read_remaining_bytes()` and encodes with `buf.write_bytes()` */ #[derive(Clone)] #[repr(transparent)] pub struct RemainderBytes { - data: Vec<u8>, + data: Box<[u8]>, } encode_impl!(RemainderBytes, buf, self, { @@ -181,13 +201,27 @@ encode_impl!(RemainderBytes, buf, self, { decode_impl!(RemainderBytes, buf, { Ok(Self { - data: buf.read_remaining_bytes()?, + data: buf.read_remaining_bytes()?.into(), }) }); impl Deref for RemainderBytes { - type Target = Vec<u8>; + type Target = [u8]; fn deref(&self) -> &Self::Target { &self.data } } + +impl From<Vec<u8>> for RemainderBytes { + fn from(value: Vec<u8>) -> Self { + Self { + data: value.into_boxed_slice(), + } + } +} + +impl From<Box<[u8]>> for RemainderBytes { + fn from(value: Box<[u8]>) -> Self { + Self { data: value } + } +} diff --git a/server/game/src/lib.rs b/server/game/src/lib.rs new file mode 100644 index 00000000..3d165be7 --- /dev/null +++ b/server/game/src/lib.rs @@ -0,0 +1,17 @@ +#![feature(sync_unsafe_cell)] +#![allow( + clippy::must_use_candidate, + clippy::module_name_repetitions, + clippy::cast_possible_truncation, + clippy::missing_errors_doc, + clippy::missing_panics_doc, + clippy::wildcard_imports, + clippy::missing_safety_doc +)] + +pub mod data; +pub mod managers; +pub mod server; +pub mod server_thread; +pub mod state; +pub mod util; diff --git a/server/game/src/main.rs b/server/game/src/main.rs index 18482c87..68c9f20b 100644 --- a/server/game/src/main.rs +++ b/server/game/src/main.rs @@ -17,7 +17,7 @@ )] use std::{ - collections::{HashMap, HashSet}, + collections::HashMap, error::Error, net::{IpAddr, Ipv4Addr, SocketAddr}, }; @@ -161,7 +161,7 @@ async fn main() -> Result<(), Box<dyn Error>> { warn!("Starting in standalone mode, authentication is disabled"); GameServerBootData { protocol: PROTOCOL_VERSION, - no_chat: HashSet::new(), + no_chat: Vec::new(), special_users: HashMap::new(), tps: 30, } diff --git a/server/game/src/managers/player.rs b/server/game/src/managers/player.rs index cfc4aef3..d1d0ddee 100644 --- a/server/game/src/managers/player.rs +++ b/server/game/src/managers/player.rs @@ -1,4 +1,4 @@ -use rustc_hash::{FxHashMap, FxHashSet}; +use nohash_hasher::IntMap; use crate::data::{ types::{AssociatedPlayerData, PlayerData}, @@ -12,15 +12,15 @@ pub struct PlayerEntry { } pub struct PlayerManager { - players: FxHashMap<i32, PlayerEntry>, // player id : associated data - levels: FxHashMap<i32, FxHashSet<i32>>, // level id : [player id] + players: IntMap<i32, PlayerEntry>, // player id : associated data + levels: IntMap<i32, Vec<i32>>, // level id : [player id] } impl PlayerManager { pub fn new() -> Self { Self { - players: FxHashMap::default(), - levels: FxHashMap::default(), + players: IntMap::default(), + levels: IntMap::default(), } } @@ -57,16 +57,16 @@ impl PlayerManager { } /// get a reference to a list of account IDs of players on a level given its ID - pub fn get_level(&self, level_id: i32) -> Option<&FxHashSet<i32>> { + pub fn get_level(&self, level_id: i32) -> Option<&Vec<i32>> { self.levels.get(&level_id) } /// get the amount of players on a level given its ID pub fn get_player_count_on_level(&self, level_id: i32) -> Option<usize> { - self.levels.get(&level_id).map(FxHashSet::len) + self.levels.get(&level_id).map(Vec::len) } - /// run a function `f` on each player on a level given its ID, with additional data (wink wink it's always gonna be `&mut FastByteBuffer`) + /// 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<F, A>(&self, level_id: i32, f: F, additional: &mut A) -> usize where F: Fn(&PlayerEntry, usize, &mut A) -> bool, @@ -82,14 +82,19 @@ impl PlayerManager { /// add a player to a level given a level ID and an account ID pub fn add_to_level(&mut self, level_id: i32, account_id: i32) { - let players = self.levels.entry(level_id).or_default(); - players.insert(account_id); + let players = self.levels.entry(level_id).or_insert_with(|| Vec::with_capacity(128)); + if !players.contains(&account_id) { + players.push(account_id); + } } /// remove a player from a level given a level ID and an account ID pub fn remove_from_level(&mut self, level_id: i32, account_id: i32) { let should_remove_level = self.levels.get_mut(&level_id).is_some_and(|level| { - level.remove(&account_id); + if let Some(index) = level.iter().position(|&x| x == account_id) { + level.remove(index); + } + level.is_empty() }); diff --git a/server/game/src/server_thread/handlers/game.rs b/server/game/src/server_thread/handlers/game.rs index 7a35a06c..da8e43a4 100644 --- a/server/game/src/server_thread/handlers/game.rs +++ b/server/game/src/server_thread/handlers/game.rs @@ -1,20 +1,15 @@ -use std::{ - sync::{atomic::Ordering, Arc}, - time::{SystemTime, UNIX_EPOCH}, -}; +use std::sync::{atomic::Ordering, Arc}; use crate::{ data::packets::PacketHeader, server_thread::{GameServerThread, PacketHandlingError, Result}, }; -use globed_shared::logger::*; - use super::*; use crate::data::*; /// max voice throughput in kb/s -const MAX_VOICE_THROUGHPUT: usize = 8; +pub const MAX_VOICE_THROUGHPUT: usize = 8; /// max voice packet size in bytes pub const MAX_VOICE_PACKET_SIZE: usize = 4096; @@ -239,34 +234,6 @@ impl GameServerThread { let accid = self.account_id.load(Ordering::Relaxed); - // check the throughput - { - let now = SystemTime::now().duration_since(UNIX_EPOCH)?.as_millis() as u64; - let last_voice_packet = self.last_voice_packet.swap(now, Ordering::Relaxed); - let mut passed_time = now - last_voice_packet; - - if passed_time == 0 { - passed_time = 1; - } - - let total_size = packet.data.data.len(); - - // let total_size = packet - // .data - // .opus_frames - // .iter() - // .filter_map(|opt| opt.as_ref()) - // .map(Vec::len) - // .sum::<usize>(); - - let throughput = total_size / passed_time as usize; // in kb per second - - if throughput > MAX_VOICE_THROUGHPUT { - warn!("rejecting a voice packet, throughput above the limit: {}kb/s", throughput); - return Ok(()); - } - } - let vpkt = Arc::new(VoiceBroadcastPacket { player_id: accid, data: packet.data, diff --git a/server/game/src/server_thread/handlers/mod.rs b/server/game/src/server_thread/handlers/mod.rs index e78bd6dd..7ce01e34 100644 --- a/server/game/src/server_thread/handlers/mod.rs +++ b/server/game/src/server_thread/handlers/mod.rs @@ -1,7 +1,7 @@ mod connection; mod game; -pub use game::MAX_VOICE_PACKET_SIZE; +pub use game::{MAX_VOICE_PACKET_SIZE, MAX_VOICE_THROUGHPUT}; /// packet handler for a specific packet type macro_rules! gs_handler { diff --git a/server/game/src/server_thread/mod.rs b/server/game/src/server_thread/mod.rs index 9d2a5b41..ed291dd8 100644 --- a/server/game/src/server_thread/mod.rs +++ b/server/game/src/server_thread/mod.rs @@ -4,7 +4,7 @@ use std::{ atomic::{AtomicBool, AtomicI32, AtomicU64, Ordering}, Arc, OnceLock, }, - time::Duration, + time::{Duration, SystemTime, UNIX_EPOCH}, }; use parking_lot::Mutex as SyncMutex; @@ -166,9 +166,9 @@ impl GameServerThread { /// fast packet sending with best-case zero heap allocation. /// if the packet size isn't known at compile time, calculate it and use `send_packet_fast_rough` async fn send_packet_fast<P: Packet + Encodable + KnownSize>(&self, packet: &P) -> Result<()> { - // in theory, the size is known at compile time, however for some reason, - // alloca manages to be significantly faster than a `[MaybeUninit<u8>; N]`. - // i have no idea why or how, but yeah. + // in theory, the size is known at compile time, so we could use a stack array here, + // instead of calling `send_packet_fast_rough` which uses alloca. + // however in practice, the performance difference is negligible, so we avoid code unnecessary code repetition. self.send_packet_fast_rough(packet, P::ENCODED_SIZE).await } @@ -298,6 +298,44 @@ impl GameServerThread { Ok(buf) } + fn is_chat_packet_allowed(&self, voice: bool, len: usize) -> bool { + if !self.authenticated.load(Ordering::Relaxed) { + return false; + } + + let accid = self.account_id.load(Ordering::Relaxed); + if self.game_server.chat_blocked(accid) { + return false; + } + + if !voice { + return true; + } + + if len > MAX_VOICE_PACKET_SIZE { + return false; + } + + // check the throughput + let now = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_millis() as u64; + let last_voice_packet = self.last_voice_packet.swap(now, Ordering::Relaxed); + let mut passed_time = now - last_voice_packet; + + if passed_time == 0 { + passed_time = 1; + } + + let throughput = len / passed_time as usize; // in kb per second + + if throughput > MAX_VOICE_THROUGHPUT { + #[cfg(debug_assertions)] + warn!("rejecting a voice packet, throughput above the limit: {}kb/s", throughput); + return false; + } + + true + } + /// handle a message sent from the `GameServer` async fn handle_message(&self, message: ServerThreadMessage) -> Result<()> { match message { @@ -329,20 +367,12 @@ impl GameServerThread { } // also for optimization, reject the voice packet immediately on certain conditions - if header.packet_id == VoicePacket::PACKET_ID || header.packet_id == ChatMessagePacket::PACKET_ID { - let accid = self.account_id.load(Ordering::Relaxed); - if self.game_server.chat_blocked(accid) { - debug!("blocking voice packet from {accid}"); - return Ok(()); - } - - if header.packet_id == VoicePacket::PACKET_ID && message.len() > MAX_VOICE_PACKET_SIZE { - debug!( - "blocking voice packet from {accid} because it's too big ({} bytes)", - message.len() - ); - return Ok(()); - } + if (header.packet_id == VoicePacket::PACKET_ID || header.packet_id == ChatMessagePacket::PACKET_ID) + && !self.is_chat_packet_allowed(header.packet_id == VoicePacket::PACKET_ID, message.len()) + { + #[cfg(debug_assertions)] + log::warn!("blocking text/voice packet from {}", self.account_id.load(Ordering::Relaxed)); + return Ok(()); } // reject cleartext credentials diff --git a/server/game/tests/test.rs b/server/game/tests/test.rs new file mode 100644 index 00000000..8b947787 --- /dev/null +++ b/server/game/tests/test.rs @@ -0,0 +1,138 @@ +// this doc is mostly for flamegraphs +#![allow(clippy::wildcard_imports)] +use bytebuffer::{ByteBuffer, ByteReader}; +use globed_game_server::{data::*, managers::PlayerManager}; +use std::hint::black_box; + +const ITERS: usize = 500_000; + +#[test] +fn test_alloca_buffer() { + let data = PlayerAccountData { + account_id: 234_234_234, + name: FastString::from_str("hit his is my name"), + icons: PlayerIconData::default(), + special_user_data: Some(SpecialUserData { + name_color: Color3B { r: 10, g: 100, b: 200 }, + }), + }; + + for _ in 0..ITERS { + let func1 = black_box(|| { + alloca::with_alloca(PlayerAccountData::ENCODED_SIZE * 64, |data_| { + let stackarray = unsafe { + let ptr = data_.as_mut_ptr().cast::<u8>(); + std::slice::from_raw_parts_mut(ptr, std::mem::size_of_val(data_)) + }; + + let mut buf = FastByteBuffer::new(stackarray); + for _ in 0..64 { + buf.write_value(&data); + } + + let mut buf = ByteReader::from_bytes(stackarray); + for _ in 0..64 { + assert_eq!(buf.read_value::<PlayerAccountData>().unwrap().account_id, data.account_id); + } + }); + }); + + func1(); + } +} + +#[test] +fn test_fast_buffer() { + let data = PlayerAccountData { + account_id: 234_234_234, + name: FastString::from_str("hit his is my name"), + icons: PlayerIconData::default(), + special_user_data: Some(SpecialUserData { + name_color: Color3B { r: 10, g: 100, b: 200 }, + }), + }; + + for _ in 0..ITERS { + let func1 = black_box(|| { + let mut stackarray = [0u8; PlayerAccountData::ENCODED_SIZE * 64]; + let mut buf = FastByteBuffer::new(&mut stackarray); + for _ in 0..64 { + buf.write_value(&data); + } + + let mut buf = ByteReader::from_bytes(&stackarray); + for _ in 0..64 { + assert_eq!(buf.read_value::<PlayerAccountData>().unwrap().account_id, data.account_id); + } + }); + + func1(); + } +} + +#[test] +fn test_slow_buffer() { + let data = PlayerAccountData { + account_id: 234_234_234, + name: FastString::from_str("hit his is my name"), + icons: PlayerIconData::default(), + special_user_data: Some(SpecialUserData { + name_color: Color3B { r: 10, g: 100, b: 200 }, + }), + }; + + for _ in 0..ITERS { + let func2 = black_box(|| { + let mut buffer = ByteBuffer::new(); + for _ in 0..64 { + buffer.write_value(&data); + } + + let mut reader = ByteReader::from_bytes(buffer.as_bytes()); + + for _ in 0..64 { + assert_eq!(reader.read_value::<PlayerAccountData>().unwrap().account_id, data.account_id); + } + }); + + func2(); + } +} + +#[test] +fn test_player_manager() { + let mut manager = PlayerManager::new(); + + 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 {}); + } + } + + let mut total_players = 0; + for i in 0..100 { + let count = manager.get_player_count_on_level(i).unwrap_or(0); + assert_eq!(count, 100); + + let total = manager.for_each_player_on_level( + i, + |_, _, p| { + *p += 1; + true + }, + &mut total_players, + ); + + assert_eq!(total, count); + } + + assert_eq!(total_players, 10000); + + for level_id in 0..100 { + for account_id in 0..100 { + manager.remove_from_level(level_id, level_id * 100 + account_id); + manager.remove_player(level_id * 100 + account_id); + } + } +} diff --git a/server/shared/src/lib.rs b/server/shared/src/lib.rs index 299c1376..b2d859e5 100644 --- a/server/shared/src/lib.rs +++ b/server/shared/src/lib.rs @@ -1,5 +1,5 @@ use serde::{Deserialize, Serialize}; -use std::collections::{HashMap, HashSet}; +use std::collections::HashMap; // module reexports pub use colored; @@ -24,7 +24,7 @@ pub struct SpecialUser { #[derive(Serialize, Deserialize)] pub struct GameServerBootData { pub protocol: u16, - pub no_chat: HashSet<i32>, + pub no_chat: Vec<i32>, pub special_users: HashMap<i32, SpecialUser>, pub tps: u32, } diff --git a/src/audio/all.hpp b/src/audio/all.hpp index 9976d6e6..18436420 100644 --- a/src/audio/all.hpp +++ b/src/audio/all.hpp @@ -5,4 +5,4 @@ #include "audio_sample_queue.hpp" #include "audio_stream.hpp" #include "opus_codec.hpp" -#include "voice_playback_manager.hpp" \ No newline at end of file +#include "voice_playback_manager.hpp" diff --git a/src/audio/audio_frame.hpp b/src/audio/audio_frame.hpp index 2baa30a9..0e06dc4a 100644 --- a/src/audio/audio_frame.hpp +++ b/src/audio/audio_frame.hpp @@ -44,4 +44,4 @@ class EncodedAudioFrame { }; -#endif // GLOBED_VOICE_SUPPORT \ No newline at end of file +#endif // GLOBED_VOICE_SUPPORT diff --git a/src/audio/audio_manager.cpp b/src/audio/audio_manager.cpp index 37ec8ae4..7e73f858 100644 --- a/src/audio/audio_manager.cpp +++ b/src/audio/audio_manager.cpp @@ -36,7 +36,7 @@ std::vector<AudioRecordingDevice> GlobedAudioManager::getRecordingDevices() { FMOD_ERR_CHECK( this->getSystem()->getRecordNumDrivers(&numDrivers, &numConnected), "System::getRecordNumDrivers" - ); + ) for (int i = 0; i < numDrivers; i++) { out.push_back(this->getRecordingDevice(i)); @@ -52,7 +52,7 @@ std::vector<AudioPlaybackDevice> GlobedAudioManager::getPlaybackDevices() { FMOD_ERR_CHECK( this->getSystem()->getNumDrivers(&numDrivers), "System::getNumDrivers" - ); + ) for (int i = 0; i < numDrivers; i++) { out.push_back(this->getPlaybackDevice(i)); @@ -71,7 +71,7 @@ AudioRecordingDevice GlobedAudioManager::getRecordingDevice(int deviceId) { &device.speakerMode, &device.speakerModeChannels, &device.driverState - ), "System::getRecordDriverInfo"); + ), "System::getRecordDriverInfo") device.id = deviceId; device.name = std::string(name); @@ -88,7 +88,7 @@ AudioPlaybackDevice GlobedAudioManager::getPlaybackDevice(int deviceId) { &device.sampleRate, &device.speakerMode, &device.speakerModeChannels - ), "System::getDriverInfo"); + ), "System::getDriverInfo") device.id = deviceId; device.name = std::string(name); @@ -120,7 +120,7 @@ void GlobedAudioManager::validateDevices() { void GlobedAudioManager::startRecording(std::function<void(const EncodedAudioFrame&)> callback) { GLOBED_REQUIRE(this->recordDevice.id >= 0, "no recording device is set") - GLOBED_REQUIRE(!this->isRecording() && !recordActive, "attempting to record when already recording"); + GLOBED_REQUIRE(!this->isRecording() && !recordActive, "attempting to record when already recording") FMOD_CREATESOUNDEXINFO exinfo = {}; @@ -141,12 +141,12 @@ void GlobedAudioManager::startRecording(std::function<void(const EncodedAudioFra FMOD_ERR_CHECK( this->getSystem()->createSound(nullptr, FMOD_2D | FMOD_OPENUSER | FMOD_LOOP_NORMAL, &exinfo, &recordSound), "System::createSound" - ); + ) FMOD_ERR_CHECK( this->getSystem()->recordStart(recordDevice.id, recordSound, true), "System::recordStart" - ); + ) recordQueuedStop = false; recordQueuedHalt = false; @@ -159,7 +159,7 @@ void GlobedAudioManager::internalStopRecording() { FMOD_ERR_CHECK( this->getSystem()->recordStop(recordDevice.id), "System::recordStop" - ); + ) // if halting instead of stopping, don't call the callback if (recordQueuedHalt) { @@ -171,7 +171,7 @@ void GlobedAudioManager::internalStopRecording() { } // cleanup - recordCallback = [](const auto& _){}; + recordCallback = [](const auto&){}; recordLastPosition = 0; recordChunkSize = 0; recordQueue.clear(); @@ -203,7 +203,7 @@ bool GlobedAudioManager::isRecording() { FMOD_ERR_CHECK( this->getSystem()->isRecording(this->recordDevice.id, &recording), "System::isRecording" - ); + ) return recording; } @@ -213,7 +213,7 @@ FMOD::Channel* GlobedAudioManager::playSound(FMOD::Sound* sound) { FMOD_ERR_CHECK( this->getSystem()->playSound(sound, nullptr, false, &ch), "System::playSound" - ); + ) return ch; } @@ -237,20 +237,20 @@ FMOD::Sound* GlobedAudioManager::createSound(const float* pcm, size_t samples, i FMOD_ERR_CHECK(this->getSystem()->createSound( nullptr, FMOD_2D | FMOD_OPENUSER | FMOD_CREATESAMPLE, &exinfo, &sound), "System::createSound" - ); + ) float* data; FMOD_ERR_CHECK( sound->lock(0, exinfo.length, (void**)&data, nullptr, nullptr, nullptr), "Sound::lock" - ); + ) std::memcpy(data, pcm, exinfo.length); FMOD_ERR_CHECK( sound->unlock(data, nullptr, exinfo.length, 0), "Sound::unlock" - ); + ) return sound; } @@ -321,7 +321,7 @@ void GlobedAudioManager::audioThreadFunc() { FMOD_ERR_CHECK( this->getSystem()->getRecordPosition(recordDevice.id, &pos), "System::getRecordPosition" - ); + ) // if we are at the same position, do nothing if (pos == recordLastPosition) { @@ -333,7 +333,7 @@ void GlobedAudioManager::audioThreadFunc() { FMOD_ERR_CHECK( recordSound->lock(0, recordChunkSize, (void**)&pcmData, nullptr, &pcmLen, nullptr), "Sound::lock" - ); + ) if (pos > recordLastPosition) { recordQueue.writeData(pcmData + recordLastPosition, pos - recordLastPosition); @@ -349,7 +349,7 @@ void GlobedAudioManager::audioThreadFunc() { FMOD_ERR_CHECK( recordSound->unlock(pcmData, nullptr, pcmLen, 0), "Sound::unlock" - ); + ) if (recordQueue.size() >= VOICE_TARGET_FRAMESIZE) { float pcmbuf[VOICE_TARGET_FRAMESIZE]; @@ -482,4 +482,4 @@ std::string GlobedAudioManager::formatFmodError(FMOD_RESULT result, const char* return fmt::format("{} failed: [FMOD error {}] {}", whatFailed, (int)result, fmodErrorString(result)); } -#endif // GLOBED_VOICE_SUPPORT \ No newline at end of file +#endif // GLOBED_VOICE_SUPPORT diff --git a/src/audio/audio_manager.hpp b/src/audio/audio_manager.hpp index 60e747dc..2f14e7a4 100644 --- a/src/audio/audio_manager.hpp +++ b/src/audio/audio_manager.hpp @@ -40,7 +40,7 @@ constexpr size_t VOICE_TARGET_FRAMESIZE = VOICE_TARGET_SAMPLERATE * VOICE_CHUNK_ // This class is not thread safe. At all. class GlobedAudioManager { public: - GLOBED_SINGLETON(GlobedAudioManager); + GLOBED_SINGLETON(GlobedAudioManager) GlobedAudioManager(); ~GlobedAudioManager(); @@ -127,4 +127,4 @@ class GlobedAudioManager { std::thread audioThreadHandle; }; -#endif // GLOBED_VOICE_SUPPORT \ No newline at end of file +#endif // GLOBED_VOICE_SUPPORT diff --git a/src/audio/audio_sample_queue.hpp b/src/audio/audio_sample_queue.hpp index 098f2bb7..ce92d3c7 100644 --- a/src/audio/audio_sample_queue.hpp +++ b/src/audio/audio_sample_queue.hpp @@ -18,4 +18,4 @@ class AudioSampleQueue { std::vector<float> buf; }; -#endif // GLOBED_VOICE_SUPPORT \ No newline at end of file +#endif // GLOBED_VOICE_SUPPORT diff --git a/src/audio/audio_stream.cpp b/src/audio/audio_stream.cpp index b330a169..61b18434 100644 --- a/src/audio/audio_stream.cpp +++ b/src/audio/audio_stream.cpp @@ -55,7 +55,7 @@ AudioStream::AudioStream() { auto system = vm.getSystem(); res = system->createStream(nullptr, FMOD_OPENUSER | FMOD_2D | FMOD_LOOP_NORMAL, &exinfo, &sound); - GLOBED_REQUIRE(res == FMOD_OK, GlobedAudioManager::formatFmodError(res, "System::createStream")); + GLOBED_REQUIRE(res == FMOD_OK, GlobedAudioManager::formatFmodError(res, "System::createStream")) } AudioStream::~AudioStream() { @@ -76,7 +76,6 @@ void AudioStream::start() { void AudioStream::writeData(const EncodedAudioFrame& frame) { auto& vm = GlobedAudioManager::get(); - FMOD_RESULT res; const auto& frames = frame.getFrames(); for (const auto& opusFrame : frames) { @@ -87,4 +86,4 @@ void AudioStream::writeData(const EncodedAudioFrame& frame) { } } -#endif // GLOBED_VOICE_SUPPORT \ No newline at end of file +#endif // GLOBED_VOICE_SUPPORT diff --git a/src/audio/audio_stream.hpp b/src/audio/audio_stream.hpp index 9eba9dd0..79666abe 100644 --- a/src/audio/audio_stream.hpp +++ b/src/audio/audio_stream.hpp @@ -33,4 +33,4 @@ class AudioStream { }; -#endif // GLOBED_VOICE_SUPPORT \ No newline at end of file +#endif // GLOBED_VOICE_SUPPORT diff --git a/src/audio/opus_codec.cpp b/src/audio/opus_codec.cpp index efe83308..39b0b6cb 100644 --- a/src/audio/opus_codec.cpp +++ b/src/audio/opus_codec.cpp @@ -80,7 +80,7 @@ void OpusCodec::freeData(EncodedOpusData data) { void OpusCodec::errcheck(const char* where) { if (_res != OPUS_OK) { const char* msg = opus_strerror(_res); - GLOBED_REQUIRE(false, std::string("opus error in ") + where + ": " + msg); + GLOBED_REQUIRE(false, std::string("opus error in ") + where + ": " + msg) } } diff --git a/src/audio/opus_codec.hpp b/src/audio/opus_codec.hpp index db342e65..e3e5ee41 100644 --- a/src/audio/opus_codec.hpp +++ b/src/audio/opus_codec.hpp @@ -72,4 +72,4 @@ class OpusCodec { void cleanup(); }; -#endif // GLOBED_VOICE_SUPPORT \ No newline at end of file +#endif // GLOBED_VOICE_SUPPORT diff --git a/src/audio/voice_playback_manager.cpp b/src/audio/voice_playback_manager.cpp index a3cb63b7..3f1044de 100644 --- a/src/audio/voice_playback_manager.cpp +++ b/src/audio/voice_playback_manager.cpp @@ -42,4 +42,4 @@ bool VoicePlaybackManager::isSpeaking(int playerId) { return !streams.at(playerId)->starving; } -#endif // GLOBED_VOICE_SUPPORT \ No newline at end of file +#endif // GLOBED_VOICE_SUPPORT diff --git a/src/audio/voice_playback_manager.hpp b/src/audio/voice_playback_manager.hpp index 4a7ea8f8..f11f9aea 100644 --- a/src/audio/voice_playback_manager.hpp +++ b/src/audio/voice_playback_manager.hpp @@ -12,7 +12,7 @@ */ class VoicePlaybackManager { public: - GLOBED_SINGLETON(VoicePlaybackManager); + GLOBED_SINGLETON(VoicePlaybackManager) VoicePlaybackManager(); ~VoicePlaybackManager(); @@ -27,4 +27,4 @@ class VoicePlaybackManager { std::unordered_map<int, std::unique_ptr<AudioStream>> streams; }; -#endif // GLOBED_VOICE_SUPPORT \ No newline at end of file +#endif // GLOBED_VOICE_SUPPORT diff --git a/src/config.hpp b/src/config.hpp index d918d5b9..c7e66b97 100644 --- a/src/config.hpp +++ b/src/config.hpp @@ -36,4 +36,4 @@ -#endif // GLOBED_IGNORE_CONFIG_HPP \ No newline at end of file +#endif // GLOBED_IGNORE_CONFIG_HPP diff --git a/src/crypto/base_box.hpp b/src/crypto/base_box.hpp index 8e8456de..71d95e14 100644 --- a/src/crypto/base_box.hpp +++ b/src/crypto/base_box.hpp @@ -64,4 +64,4 @@ class BaseCryptoBox { std::string decryptToString(const util::data::bytevector& src); // Decrypt `size` bytes from byte buffer `src` and return a string with the plaintext data. std::string decryptToString(const util::data::byte* src, size_t size); -}; \ No newline at end of file +}; diff --git a/src/crypto/box.cpp b/src/crypto/box.cpp index f5d322d3..7666b15c 100644 --- a/src/crypto/box.cpp +++ b/src/crypto/box.cpp @@ -13,14 +13,14 @@ CryptoBox::CryptoBox(byte* key) { SHARED_KEY_LEN // sharedKey )); - CRYPTO_REQUIRE(memBasePtr != nullptr, "sodium_malloc returned nullptr"); + CRYPTO_REQUIRE(memBasePtr != nullptr, "sodium_malloc returned nullptr") secretKey = memBasePtr; // base + 0 publicKey = secretKey + SECRET_KEY_LEN; // base + 32 peerPublicKey = publicKey + KEY_LEN; // base + 64 sharedKey = peerPublicKey + KEY_LEN; // base + 96 - CRYPTO_ERR_CHECK(func_box_keypair(publicKey, secretKey), "func_box_keypair failed"); + CRYPTO_ERR_CHECK(func_box_keypair(publicKey, secretKey), "func_box_keypair failed") if (key != nullptr) { this->setPeerKey(key); @@ -46,7 +46,7 @@ bytearray<CryptoBox::KEY_LEN> CryptoBox::extractPublicKey() noexcept { void CryptoBox::setPeerKey(byte* key) { std::memcpy(peerPublicKey, key, KEY_LEN); - CRYPTO_ERR_CHECK(func_box_beforenm(sharedKey, peerPublicKey, secretKey), "func_box_beforenm failed"); + CRYPTO_ERR_CHECK(func_box_beforenm(sharedKey, peerPublicKey, secretKey), "func_box_beforenm failed") } constexpr size_t CryptoBox::nonceLength() { @@ -62,7 +62,7 @@ size_t CryptoBox::encryptInto(const byte* src, byte* dest, size_t size) { util::crypto::secureRandom(nonce, NONCE_LEN); byte* ciphertext = dest + NONCE_LEN; - CRYPTO_ERR_CHECK(func_box_easy(ciphertext, src, size, nonce, sharedKey), "func_box_easy failed"); + CRYPTO_ERR_CHECK(func_box_easy(ciphertext, src, size, nonce, sharedKey), "func_box_easy failed") // prepend the nonce std::memcpy(dest, nonce, NONCE_LEN); @@ -71,7 +71,7 @@ size_t CryptoBox::encryptInto(const byte* src, byte* dest, size_t size) { } size_t CryptoBox::decryptInto(const util::data::byte* src, util::data::byte* dest, size_t size) { - CRYPTO_REQUIRE(size >= PREFIX_LEN, "message is too short"); + CRYPTO_REQUIRE(size >= PREFIX_LEN, "message is too short") const byte* nonce = src; const byte* ciphertext = src + NONCE_LEN; @@ -79,7 +79,7 @@ size_t CryptoBox::decryptInto(const util::data::byte* src, util::data::byte* des size_t plaintextLength = size - PREFIX_LEN; size_t ciphertextLength = size - NONCE_LEN; - CRYPTO_ERR_CHECK(func_box_open_easy(dest, ciphertext, ciphertextLength, nonce, sharedKey), "func_box_open_easy failed"); + CRYPTO_ERR_CHECK(func_box_open_easy(dest, ciphertext, ciphertextLength, nonce, sharedKey), "func_box_open_easy failed") return plaintextLength; } \ No newline at end of file diff --git a/src/crypto/box.hpp b/src/crypto/box.hpp index 74caafd2..185a8d62 100644 --- a/src/crypto/box.hpp +++ b/src/crypto/box.hpp @@ -3,7 +3,7 @@ #include <sodium.h> -class CryptoBox : public BaseCryptoBox { +class CryptoBox final : public BaseCryptoBox { public: // XSalsa20 is theoretically slower and less secure, but still possible to use by defining GLOBED_USE_XSALSA20 @@ -47,11 +47,11 @@ class CryptoBox : public BaseCryptoBox { // This precomputes the shared key and stores it for use in all future operations. void setPeerKey(util::data::byte* src); - constexpr size_t nonceLength(); - constexpr size_t macLength(); + constexpr size_t nonceLength() override; + constexpr size_t macLength() override; - size_t encryptInto(const util::data::byte* src, util::data::byte* dest, size_t size); - size_t decryptInto(const util::data::byte* src, util::data::byte* dest, size_t size); + size_t encryptInto(const util::data::byte* src, util::data::byte* dest, size_t size) override; + size_t decryptInto(const util::data::byte* src, util::data::byte* dest, size_t size) override; private: // nuh uh util::data::byte* memBasePtr = nullptr; @@ -61,4 +61,4 @@ class CryptoBox : public BaseCryptoBox { util::data::byte* peerPublicKey; util::data::byte* sharedKey; -}; \ No newline at end of file +}; diff --git a/src/crypto/secret_box.cpp b/src/crypto/secret_box.cpp index d9536458..9f7e2347 100644 --- a/src/crypto/secret_box.cpp +++ b/src/crypto/secret_box.cpp @@ -7,13 +7,13 @@ using namespace util::data; SecretBox::SecretBox(bytevector key) { - CRYPTO_REQUIRE(key.size() == crypto_secretbox_KEYBYTES, "provided key is too long or too short for SecretBox"); + CRYPTO_REQUIRE(key.size() == crypto_secretbox_KEYBYTES, "provided key is too long or too short for SecretBox") this->key = reinterpret_cast<byte*>(sodium_malloc( crypto_secretbox_KEYBYTES )); - CRYPTO_REQUIRE(this->key != nullptr, "sodium_malloc returned nullptr"); + CRYPTO_REQUIRE(this->key != nullptr, "sodium_malloc returned nullptr") std::memcpy(this->key, key.data(), crypto_secretbox_KEYBYTES); } @@ -42,7 +42,7 @@ size_t SecretBox::encryptInto(const byte* src, byte* dest, size_t size) { util::crypto::secureRandom(nonce, NONCE_LEN); byte* ciphertext = dest + NONCE_LEN; - CRYPTO_ERR_CHECK(crypto_secretbox_easy(ciphertext, src, size, nonce, key), "crypto_secretbox_easy failed"); + CRYPTO_ERR_CHECK(crypto_secretbox_easy(ciphertext, src, size, nonce, key), "crypto_secretbox_easy failed") // prepend the nonce std::memcpy(dest, nonce, NONCE_LEN); @@ -51,7 +51,7 @@ size_t SecretBox::encryptInto(const byte* src, byte* dest, size_t size) { } size_t SecretBox::decryptInto(const byte* src, byte* dest, size_t size) { - CRYPTO_REQUIRE(size >= PREFIX_LEN, "message is too short"); + CRYPTO_REQUIRE(size >= PREFIX_LEN, "message is too short") const byte* nonce = src; const byte* ciphertext = src + NONCE_LEN; @@ -59,13 +59,13 @@ size_t SecretBox::decryptInto(const byte* src, byte* dest, size_t size) { size_t plaintextLength = size - PREFIX_LEN; size_t ciphertextLength = size - NONCE_LEN; - CRYPTO_ERR_CHECK(crypto_secretbox_open_easy(dest, ciphertext, ciphertextLength, nonce, key), "crypto_secretbox_open_easy failed"); + CRYPTO_ERR_CHECK(crypto_secretbox_open_easy(dest, ciphertext, ciphertextLength, nonce, key), "crypto_secretbox_open_easy failed") return plaintextLength; } void SecretBox::setKey(const util::data::bytevector& src) { - GLOBED_REQUIRE(src.size() == crypto_secretbox_KEYBYTES, "key size is too small or too big for SecretBox"); + GLOBED_REQUIRE(src.size() == crypto_secretbox_KEYBYTES, "key size is too small or too big for SecretBox") setKey(src.data()); } diff --git a/src/crypto/secret_box.hpp b/src/crypto/secret_box.hpp index bf80b67b..49bafeab 100644 --- a/src/crypto/secret_box.hpp +++ b/src/crypto/secret_box.hpp @@ -8,7 +8,7 @@ * uses a single secret key (or derives it from a passphrase) for data encryption. */ -class SecretBox : public BaseCryptoBox { +class SecretBox final : public BaseCryptoBox { public: static const size_t NONCE_LEN = crypto_secretbox_NONCEBYTES; static const size_t MAC_LEN = crypto_secretbox_MACBYTES; @@ -21,12 +21,12 @@ class SecretBox : public BaseCryptoBox { static SecretBox withPassword(const std::string& pw); - constexpr size_t nonceLength(); - constexpr size_t macLength(); + constexpr size_t nonceLength() override; + constexpr size_t macLength() override; using BaseCryptoBox::prefixLength; - size_t encryptInto(const util::data::byte* src, util::data::byte* dest, size_t size); - size_t decryptInto(const util::data::byte* src, util::data::byte* dest, size_t size); + size_t encryptInto(const util::data::byte* src, util::data::byte* dest, size_t size) override; + size_t decryptInto(const util::data::byte* src, util::data::byte* dest, size_t size) override; void setKey(const util::data::bytevector& src); void setKey(const util::data::byte* src); @@ -35,4 +35,4 @@ class SecretBox : public BaseCryptoBox { private: util::data::byte* key = nullptr; -}; \ No newline at end of file +}; diff --git a/src/defs.hpp b/src/defs.hpp index 10ca13a8..89f8441b 100644 --- a/src/defs.hpp +++ b/src/defs.hpp @@ -4,4 +4,4 @@ #include <defs/assert.hpp> #include <defs/crash.hpp> #include <defs/platform.hpp> -#include <defs/util.hpp> \ No newline at end of file +#include <defs/util.hpp> diff --git a/src/defs/net.hpp b/src/defs/net.hpp index 9dc8ea3d..5092f741 100644 --- a/src/defs/net.hpp +++ b/src/defs/net.hpp @@ -13,7 +13,7 @@ /* windows includes */ -# include <ws2tcpip.h> +# include <WS2tcpip.h> #elif defined(GLOBED_UNIX) // ^ windows | v unix diff --git a/src/main.cpp b/src/main.cpp index 6d4c9fe4..1ad89535 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -129,4 +129,4 @@ void printDebugInfo() { #if GLOBED_VOICE_SUPPORT geode::log::info("Opus version: {}", opus_get_version_string()); #endif -} \ No newline at end of file +} diff --git a/src/managers/account_manager.cpp b/src/managers/account_manager.cpp index 8379055c..af1d90be 100644 --- a/src/managers/account_manager.cpp +++ b/src/managers/account_manager.cpp @@ -25,7 +25,6 @@ void GlobedAccountManager::initialize(const std::string& name, int accountId, co void GlobedAccountManager::autoInitialize() { auto* gjam = GJAccountManager::get(); auto& csm = CentralServerManager::get(); - auto& gsm = GameServerManager::get(); std::string activeCentralUrl = ""; diff --git a/src/managers/central_server_manager.cpp b/src/managers/central_server_manager.cpp index 619c8c4c..b11ad93e 100644 --- a/src/managers/central_server_manager.cpp +++ b/src/managers/central_server_manager.cpp @@ -14,9 +14,7 @@ CentralServerManager::CentralServerManager() { if (empty) { this->addServer(CentralServer { .name = "Main server", - // .url = "https://globed.dankmeme.dev" - // TODO prod ^ - .url = "http://127.0.0.1:41000" + .url = "https://globed.dankmeme.dev" }); } diff --git a/src/managers/central_server_manager.hpp b/src/managers/central_server_manager.hpp index 93ff825d..6cc4149f 100644 --- a/src/managers/central_server_manager.hpp +++ b/src/managers/central_server_manager.hpp @@ -22,7 +22,7 @@ struct CentralServer { class CentralServerManager { public: - GLOBED_SINGLETON(CentralServerManager); + GLOBED_SINGLETON(CentralServerManager) CentralServerManager(); // set the current active server, thread safe diff --git a/src/managers/error_queues.hpp b/src/managers/error_queues.hpp index b6a408f4..7ac6ddbc 100644 --- a/src/managers/error_queues.hpp +++ b/src/managers/error_queues.hpp @@ -11,7 +11,7 @@ */ class ErrorQueues { - GLOBED_SINGLETON(ErrorQueues); + GLOBED_SINGLETON(ErrorQueues) ErrorQueues(); void warn(const std::string& message, bool print = true); diff --git a/src/managers/game_server_manager.hpp b/src/managers/game_server_manager.hpp index d97ee5ca..d8a72363 100644 --- a/src/managers/game_server_manager.hpp +++ b/src/managers/game_server_manager.hpp @@ -26,7 +26,7 @@ struct GameServer { // This class is fully thread safe to use. class GameServerManager { public: - GLOBED_SINGLETON(GameServerManager); + GLOBED_SINGLETON(GameServerManager) GameServerManager(); constexpr static const char* STANDALONE_ID = "__standalone__server_id__"; diff --git a/src/managers/settings.hpp b/src/managers/settings.hpp index ae62627a..c0a74353 100644 --- a/src/managers/settings.hpp +++ b/src/managers/settings.hpp @@ -6,7 +6,7 @@ // Besides `getCached()`, this class is not thread safe (reason: Mod::getSavedValue/Mod::setSavedValue) class GlobedSettings { - GLOBED_SINGLETON(GlobedSettings); + GLOBED_SINGLETON(GlobedSettings) GlobedSettings(); struct CachedSettings; diff --git a/src/net/network_manager.cpp b/src/net/network_manager.cpp index 8966a8cf..201adfee 100644 --- a/src/net/network_manager.cpp +++ b/src/net/network_manager.cpp @@ -33,7 +33,7 @@ NetworkManager::NetworkManager() { this->send(LoginPacket::create(gddata->accountId, gddata->accountName, authtoken)); }); - addBuiltinListener<KeepaliveResponsePacket>([this](auto packet) { + addBuiltinListener<KeepaliveResponsePacket>([](auto packet) { GameServerManager::get().finishKeepalive(packet->playerCount); }); @@ -54,7 +54,7 @@ NetworkManager::NetworkManager() { this->disconnect(true); }); - addBuiltinListener<ServerNoticePacket>([this](auto packet) { + addBuiltinListener<ServerNoticePacket>([](auto packet) { ErrorQueues::get().notice(packet->message); }); diff --git a/src/net/udp_socket.cpp b/src/net/udp_socket.cpp index cdf8eb14..c2a61123 100644 --- a/src/net/udp_socket.cpp +++ b/src/net/udp_socket.cpp @@ -26,7 +26,7 @@ bool UdpSocket::connect(const std::string& serverIp, unsigned short port) { } int UdpSocket::send(const char* data, unsigned int dataSize) { - GLOBED_REQUIRE(connected, "attempting to call UdpSocket::send on a disconnected socket"); + GLOBED_REQUIRE(connected, "attempting to call UdpSocket::send on a disconnected socket") int retval = sendto(socket_, data, dataSize, 0, reinterpret_cast<struct sockaddr*>(&destAddr_), sizeof(destAddr_)); diff --git a/src/ui/error_check_node.cpp b/src/ui/error_check_node.cpp index 516164d3..46a3aa9c 100644 --- a/src/ui/error_check_node.cpp +++ b/src/ui/error_check_node.cpp @@ -12,7 +12,7 @@ bool ErrorCheckNode::init() { return true; } -void ErrorCheckNode::updateErrors(float _unused) { +void ErrorCheckNode::updateErrors(float) { auto* currentScene = CCDirector::get()->getRunningScene(); if (!currentScene || !currentScene->getChildren() || currentScene->getChildrenCount() == 0) return; diff --git a/src/ui/error_check_node.hpp b/src/ui/error_check_node.hpp index 292a0a63..91f6dddf 100644 --- a/src/ui/error_check_node.hpp +++ b/src/ui/error_check_node.hpp @@ -6,6 +6,6 @@ class ErrorCheckNode : public cocos2d::CCNode { static ErrorCheckNode* create(); protected: - bool init(); - void updateErrors(float _unused); + bool init() override; + void updateErrors(float dt); }; \ No newline at end of file diff --git a/src/ui/hooks/menu_layer.hpp b/src/ui/hooks/menu_layer.hpp index 2b109fb7..19ae4d72 100644 --- a/src/ui/hooks/menu_layer.hpp +++ b/src/ui/hooks/menu_layer.hpp @@ -50,7 +50,7 @@ class $modify(HookedMenuLayer, MenuLayer) { menu->updateLayout(); } - void maybeUpdateButton(float _) { + void maybeUpdateButton(float) { bool authenticated = NetworkManager::get().established(); if (authenticated != m_fields->btnActive) { m_fields->btnActive = authenticated; diff --git a/src/ui/hooks/play_layer.hpp b/src/ui/hooks/play_layer.hpp index 3d392134..f680697c 100644 --- a/src/ui/hooks/play_layer.hpp +++ b/src/ui/hooks/play_layer.hpp @@ -60,7 +60,6 @@ class $modify(GlobedPlayLayer, PlayLayer) { // is to only do it when the state actually changed. like we got a new best or // the attempt count increased by quite a bit. - auto scheduler = CCScheduler::get(); this->rescheduleSender(); this->setupCustomKeybinds(); @@ -94,14 +93,14 @@ class $modify(GlobedPlayLayer, PlayLayer) { void setupEventListeners() { auto& nm = NetworkManager::get(); - nm.addListener<PlayerProfilesPacket>([this](PlayerProfilesPacket* packet) { + nm.addListener<PlayerProfilesPacket>([](PlayerProfilesPacket* packet) { auto& pcm = ProfileCacheManager::get(); for (auto& player : packet->data) { pcm.insert(player); } }); - nm.addListener<LevelDataPacket>([this](LevelDataPacket* packet){ + nm.addListener<LevelDataPacket>([](LevelDataPacket* packet){ log::debug("Recv level data, {} players", packet->players.size()); }); @@ -118,7 +117,7 @@ class $modify(GlobedPlayLayer, PlayLayer) { } }); - nm.addListener<PlayerMetadataPacket>([this](PlayerMetadataPacket* packet) { + nm.addListener<PlayerMetadataPacket>([](PlayerMetadataPacket*) { // TODO handle player metadata }); } @@ -176,7 +175,7 @@ class $modify(GlobedPlayLayer, PlayLayer) { /* periodical selectors */ // selSendPlayerData - runs 30 times per second - void selSendPlayerData(float _dt) { + void selSendPlayerData(float) { if (!this->established()) return; if (!this->isCurrentPlayLayer()) return; if (!this->accountForSpeedhack()) return; @@ -218,7 +217,7 @@ class $modify(GlobedPlayLayer, PlayLayer) { bool accountForSpeedhack() { auto* sched = CCScheduler::get(); auto ts = sched->getTimeScale(); - if (ts != m_fields->lastKnownTimeScale) { + if (util::math::equal(ts, m_fields->lastKnownTimeScale)) { sched->unscheduleSelector(schedule_selector(GlobedPlayLayer::selSendPlayerData), this); this->rescheduleSender(); } diff --git a/src/ui/menu/main/globed_menu_layer.cpp b/src/ui/menu/main/globed_menu_layer.cpp index 67839507..9f621e97 100644 --- a/src/ui/menu/main/globed_menu_layer.cpp +++ b/src/ui/menu/main/globed_menu_layer.cpp @@ -62,7 +62,7 @@ bool GlobedMenuLayer::init() { Build<CCSprite>::createSpriteName("miniSkull_001.png") .scale(1.2f) - .intoMenuItem([this](auto) { + .intoMenuItem([](auto) { // this->requestServerList(); if (auto* popup = PlayerListPopup::create()) { popup->m_noElasticity = true; @@ -76,7 +76,7 @@ bool GlobedMenuLayer::init() { Build<CCSprite>::createSpriteName("d_skull01_001.png") .scale(1.2f) - .intoMenuItem([this](auto) { + .intoMenuItem([](auto) { GlobedAccountManager::get().clearAuthKey(); }) .id("btn-clear-authtoken"_spr) @@ -86,7 +86,7 @@ bool GlobedMenuLayer::init() { Build<CCSprite>::createSpriteName("gjHand_05_001.png") .scale(1.2f) - .intoMenuItem([this](auto) { + .intoMenuItem([](auto) { if (auto* popup = ServerSwitcherPopup::create()) { popup->m_noElasticity = true; popup->show(); @@ -105,7 +105,7 @@ bool GlobedMenuLayer::init() { auto menu = CCMenu::create(); this->addChild(menu); - util::ui::addBackButton(this, menu, util::ui::navigateBack); + util::ui::addBackButton(menu, util::ui::navigateBack); this->setKeyboardEnabled(true); this->setKeypadEnabled(true); @@ -141,7 +141,7 @@ CCArray* GlobedMenuLayer::createServerList() { auto activeServer = gsm.active(); - for (const auto [serverId, server] : gsm.getAllServers()) { + for (const auto& [serverId, server] : gsm.getAllServers()) { bool active = authenticated && serverId == activeServer; auto cell = ServerListCell::create(server, active); ret->addObject(cell); @@ -150,9 +150,8 @@ CCArray* GlobedMenuLayer::createServerList() { return ret; } -void GlobedMenuLayer::refreshServerList(float _) { +void GlobedMenuLayer::refreshServerList(float) { auto& am = GlobedAccountManager::get(); - auto& nm = NetworkManager::get(); auto& csm = CentralServerManager::get(); // if we do not have a session token from the central server, and are not in a standalone server, don't show game servers @@ -273,7 +272,7 @@ void GlobedMenuLayer::keyBackClicked() { util::ui::navigateBack(); } -void GlobedMenuLayer::pingServers(float _) { +void GlobedMenuLayer::pingServers(float) { NetworkManager::get().taskPingServers(); } diff --git a/src/ui/menu/main/signup_layer.cpp b/src/ui/menu/main/signup_layer.cpp index c6c3f551..547fd8d5 100644 --- a/src/ui/menu/main/signup_layer.cpp +++ b/src/ui/menu/main/signup_layer.cpp @@ -22,7 +22,7 @@ bool GlobedSignupLayer::init() { this->setContentSize(listLayer->getScaledContentSize()); Build<ButtonSprite>::create("Login", "goldFont.fnt", "GJ_button_01.png", 0.8f) - .intoMenuItem([this](auto) { + .intoMenuItem([](auto) { if (!GlobedSettings::get().getFlag("seen-signup-notice")) { geode::createQuickPopup("Notice", CONSENT_MESSAGE, "Cancel", "Ok", [](auto, bool agreed){ if (agreed) { diff --git a/src/ui/menu/main/signup_popup.cpp b/src/ui/menu/main/signup_popup.cpp index d808d01d..72696969 100644 --- a/src/ui/menu/main/signup_popup.cpp +++ b/src/ui/menu/main/signup_popup.cpp @@ -80,7 +80,7 @@ void GlobedSignupPopup::onChallengeCreated(int levelId, const std::string& chtok } } -void GlobedSignupPopup::commentUploadFinished(int _) { +void GlobedSignupPopup::commentUploadFinished(int) { GameLevelManager::get()->m_commentUploadDelegate = nullptr; this->runAction( @@ -96,7 +96,7 @@ void GlobedSignupPopup::onDelayedChallengeCompleted() { this->onChallengeCompleted(storedAuthcode); } -void GlobedSignupPopup::commentUploadFailed(int cid, CommentError e) { +void GlobedSignupPopup::commentUploadFailed(int, CommentError e) { GameLevelManager::get()->m_commentUploadDelegate = nullptr; this->onFailure(fmt::format("Comment upload failed: <cy>error {}</c>", (int)e)); } @@ -155,7 +155,7 @@ void GlobedSignupPopup::onFailure(const std::string& message) { this->onClose(this); } -void GlobedSignupPopup::keyDown(cocos2d::enumKeyCodes key) { +void GlobedSignupPopup::keyDown(cocos2d::enumKeyCodes) { // do nothing; the popup should be impossible to close manually } diff --git a/src/ui/menu/server_switcher/add_server_popup.cpp b/src/ui/menu/server_switcher/add_server_popup.cpp index aaabb0de..3c21defb 100644 --- a/src/ui/menu/server_switcher/add_server_popup.cpp +++ b/src/ui/menu/server_switcher/add_server_popup.cpp @@ -53,7 +53,7 @@ bool AddServerPopup::setup(int modifyingIndex, ServerSwitcherPopup* parent) { // create button Build<ButtonSprite>::create(modifyingIndex == -1 ? "Create" : "Save", "bigFont.fnt", "GJ_button_01.png", 0.8f) - .intoMenuItem([this, modifyingIndex](auto) { + .intoMenuItem([this](auto) { static std::regex serverPattern("^(https?://[^\\s]+[.][^\\s]+)$"); std::string name = this->nameNode->getString(); diff --git a/src/util/crypto.cpp b/src/util/crypto.cpp index 54de17e3..3ae56a62 100644 --- a/src/util/crypto.cpp +++ b/src/util/crypto.cpp @@ -43,7 +43,7 @@ bytevector pwHash(const byte* input, size_t len) { crypto_pwhash_OPSLIMIT_INTERACTIVE, crypto_pwhash_MEMLIMIT_INTERACTIVE, crypto_pwhash_ALG_DEFAULT - ), "crypto_pwhash failed"); + ), "crypto_pwhash failed") return out; } @@ -63,7 +63,7 @@ bytevector simpleHash(const byte* input, size_t size) { crypto_generichash_BYTES, input, size, nullptr, 0 - ), "crypto_generichash failed"); + ), "crypto_generichash failed") return out; } @@ -78,7 +78,7 @@ std::string simpleTOTP(const bytevector& key) { } std::string simpleTOTPForPeriod(const byte *key, size_t keySize, uint64_t period) { - CRYPTO_REQUIRE(keySize == crypto_auth_hmacsha256_KEYBYTES, "invalid key size passed to simpleTOTPForPeriod"); + CRYPTO_REQUIRE(keySize == crypto_auth_hmacsha256_KEYBYTES, "invalid key size passed to simpleTOTPForPeriod") if constexpr (GLOBED_LITTLE_ENDIAN) { period = byteswap(period); @@ -179,7 +179,7 @@ bytevector base64Decode(const byte* source, size_t size, Base64Variant variant) out.data(), outMaxLen, reinterpret_cast<const char*>(source), size, nullptr, &outRealLen, nullptr, (int)variant - ), "invalid base64 string"); + ), "invalid base64 string") out.resize(outRealLen); // necessary @@ -224,7 +224,7 @@ bytevector hexDecode(const byte* source, size_t size) { out.data(), outLen, reinterpret_cast<const char*>(source), size, nullptr, &realOutLen, nullptr - ), "invalid hex string"); + ), "invalid hex string") out.resize(realOutLen); diff --git a/src/util/data.hpp b/src/util/data.hpp index 38d12dee..cc32cf66 100644 --- a/src/util/data.hpp +++ b/src/util/data.hpp @@ -69,4 +69,4 @@ namespace util::data { constexpr size_t bitsToBytes(size_t bits) { return (bits + 7) / 8; } -}; \ No newline at end of file +} \ No newline at end of file diff --git a/src/util/debugging.cpp b/src/util/debugging.cpp index c20828b3..2a6fd044 100644 --- a/src/util/debugging.cpp +++ b/src/util/debugging.cpp @@ -25,7 +25,7 @@ namespace util::debugging { formatting::formatBytes(totalBytesOut), formatting::formatBytes(totalBytesIn) ); - geode::log::debug("Average bytes per packet: {}", formatting::formatBytes(bytesPerPacket)); + geode::log::debug("Average bytes per packet: {}", formatting::formatBytes((uint64_t)bytesPerPacket)); // sort packets by the counts std::vector<std::pair<packetid_t, size_t>> pc(packetCounts.begin(), packetCounts.end()); @@ -100,7 +100,7 @@ namespace util::debugging { [[noreturn]] void suicide(const std::source_location loc) { geode::log::error("suicide called at " + sourceLocation(loc) + ", terminating."); geode::log::error("If you see this, something very, very bad happened."); - GLOBED_SUICIDE; + GLOBED_SUICIDE } #else std::string sourceLocation() { @@ -110,11 +110,11 @@ namespace util::debugging { [[noreturn]] void suicide() { GLOBED_REQUIRE_LOG("suicide called at <unknown location>, terminating."); GLOBED_REQUIRE_LOG("If you see this, something very, very bad happened."); - GLOBED_SUICIDE; + GLOBED_SUICIDE } #endif void timedLog(const std::string& message) { geode::log::info("\r[{}] [Globed] {}", util::formatting::formatDateTime(util::time::now()), message); } -} \ No newline at end of file +} diff --git a/src/util/math.cpp b/src/util/math.cpp index 626abb72..52d385e5 100644 --- a/src/util/math.cpp +++ b/src/util/math.cpp @@ -1,6 +1,14 @@ #include "math.hpp" namespace util::math { + float snan(float val) { + return std::isnan(val) ? snan() : val; + } + + float snan() { + return std::numeric_limits<float>::signaling_NaN(); + } + bool equal(float val1, float val2, float errorMargin) { return std::fabs(val2 - val1) < errorMargin; } @@ -18,11 +26,11 @@ namespace util::math { } bool greaterOrEqual(float val1, float val2, float errorMargin) { - return val1 > val2 || equal(val1, val2); + return val1 > val2 || equal(val1, val2, errorMargin); } bool greaterOrEqual(double val1, double val2, double errorMargin) { - return val1 > val2 || equal(val1, val2); + return val1 > val2 || equal(val1, val2, errorMargin); } bool smaller(float val1, float val2, float errorMargin) { @@ -34,10 +42,10 @@ namespace util::math { } bool smallerOrEqual(float val1, float val2, float errorMargin) { - return val1 < val2 || equal(val1, val2); + return val1 < val2 || equal(val1, val2, errorMargin); } bool smallerOrEqual(double val1, double val2, double errorMargin) { - return val1 < val2 || equal(val1, val2); + return val1 < val2 || equal(val1, val2, errorMargin); } } \ No newline at end of file diff --git a/src/util/math.hpp b/src/util/math.hpp index 641b16a9..888f8ad8 100644 --- a/src/util/math.hpp +++ b/src/util/math.hpp @@ -5,6 +5,18 @@ namespace util::math { constexpr float FLOAT_ERROR_MARGIN = 0.002f; constexpr double DOUBLE_ERROR_MARGIN = 0.0001; + // if `val` is NaN, return a signaling NaN, otherwise return `val` unchanged + float snan(float val); + // returns a signaling NaN + float snan(); + + // Returns `true` if all passed numbers are valid. Returns `false` if at least one of them is NaN + template <typename... Args> + requires (std::floating_point<Args> && ...) + bool checkNotNaN(Args... args) { + return ((!std::isnan(args)) && ...); + } + // `val1` == `val2` bool equal(float val1, float val2, float errorMargin = FLOAT_ERROR_MARGIN); // `val1` == `val2` diff --git a/src/util/net.cpp b/src/util/net.cpp index 42ad1862..166c0c33 100644 --- a/src/util/net.cpp +++ b/src/util/net.cpp @@ -31,10 +31,10 @@ namespace util::net { std::string lastErrorString(int code) { #ifdef GLOBED_WIN32 - char *s = NULL; + char *s = nullptr; if (FormatMessageA( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&s, 0, NULL) + nullptr, code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&s, 0, nullptr) == 0) { // some errors like WSA 10038 can raise ERROR_MR_MID_NOT_FOUND (0x13D) // which basically means the formatted message txt doesn't exist in the OS. diff --git a/src/util/rng.cpp b/src/util/rng.cpp index bef82fb6..4a47bd3c 100644 --- a/src/util/rng.cpp +++ b/src/util/rng.cpp @@ -64,4 +64,9 @@ namespace util::rng { template<> double Random::generate<double>() { return generate(0.0, 1.0); } + + bool Random::genRatio(uint32_t numerator, uint32_t denominator) { + double probability = static_cast<double>(numerator) / denominator; + return this->generate<double>() < probability; + } } \ No newline at end of file diff --git a/src/util/rng.hpp b/src/util/rng.hpp index b1d320f7..bd24a373 100644 --- a/src/util/rng.hpp +++ b/src/util/rng.hpp @@ -20,6 +20,9 @@ namespace util::rng { template <typename T> T generate(T min, T max); + // Has a `(numerator/denominator)` chance of returning true. + bool genRatio(uint32_t numerator, uint32_t denominator); + private: std::mt19937_64 engine; }; diff --git a/src/util/sync.hpp b/src/util/sync.hpp index 4f5b123c..deeae5e8 100644 --- a/src/util/sync.hpp +++ b/src/util/sync.hpp @@ -104,7 +104,7 @@ class WrappingMutex { class Guard { public: - Guard(std::shared_ptr<T> data, std::mutex& mutex) : mutex_(mutex), data_(data) { + Guard(std::shared_ptr<T> data, std::mutex& mutex) : data_(data), mutex_(mutex) { mutex_.lock(); } ~Guard() { diff --git a/src/util/time.cpp b/src/util/time.cpp index a38f663b..15056f19 100644 --- a/src/util/time.cpp +++ b/src/util/time.cpp @@ -13,4 +13,4 @@ namespace util::time { return ss.str(); } -} \ No newline at end of file +} diff --git a/src/util/time.hpp b/src/util/time.hpp index f51fd1f6..2713c5c1 100644 --- a/src/util/time.hpp +++ b/src/util/time.hpp @@ -48,4 +48,4 @@ namespace util::time { } std::string nowPretty(); -} \ No newline at end of file +} diff --git a/src/util/ui.cpp b/src/util/ui.cpp index 66cfc855..3e4dc115 100644 --- a/src/util/ui.cpp +++ b/src/util/ui.cpp @@ -21,7 +21,7 @@ namespace util::ui { .parent(layer); } - void addBackButton(CCNode* parent, CCMenu* menu, std::function<void()> callback) { + void addBackButton(CCMenu* menu, std::function<void()> callback) { auto windowSize = CCDirector::get()->getWinSize(); Build<CCSprite>::createSpriteName("GJ_arrow_01_001.png") .intoMenuItem([=](CCObject*) { diff --git a/src/util/ui.hpp b/src/util/ui.hpp index a694c309..994ceb76 100644 --- a/src/util/ui.hpp +++ b/src/util/ui.hpp @@ -5,6 +5,6 @@ namespace util::ui { void addBackground(cocos2d::CCNode* layer); - void addBackButton(cocos2d::CCNode* parent, cocos2d::CCMenu* menu, std::function<void()> callback); + void addBackButton(cocos2d::CCMenu* menu, std::function<void()> callback); void navigateBack(); -} \ No newline at end of file +}