From 7a72fdd49bc79a86f865432227ec620a6d2ec945 Mon Sep 17 00:00:00 2001 From: dank_meme01 <42031238+dankmeme01@users.noreply.github.com> Date: Fri, 1 Dec 2023 01:33:44 +0100 Subject: [PATCH] cleanups and improvements --- server/game/src/data/bytebufferext.rs | 4 + server/game/src/server.rs | 12 +- server/game/src/server_thread/error.rs | 4 + server/game/src/server_thread/handlers/mod.rs | 14 ++ server/game/src/server_thread/mod.rs | 17 ++- server/game/src/util/rate_limiter.rs | 17 +-- src/audio/all.hpp | 2 + src/audio/audio_frame.hpp | 1 - src/audio/audio_manager.cpp | 10 +- src/audio/audio_manager.hpp | 1 + src/audio/audio_sample_queue.cpp | 6 +- src/audio/audio_stream.cpp | 3 - src/audio/voice_playback_manager.hpp | 1 - src/crypto/base_box.hpp | 3 +- src/crypto/box.hpp | 1 - src/crypto/secret_box.hpp | 1 - src/data/bytebuffer.hpp | 18 +-- src/data/packets/client/misc.hpp | 2 +- src/defs.hpp | 1 - src/defs/platform.hpp | 4 +- src/managers/server_manager.cpp | 8 +- src/managers/server_manager.hpp | 6 +- src/net/network_manager.cpp | 25 ++-- src/net/network_manager.hpp | 10 +- src/net/socket.hpp | 1 + src/ui/error_check_node.cpp | 17 ++- src/ui/hooks/play_layer.hpp | 128 ++++++++++-------- src/util/sync.hpp | 4 +- src/util/time.hpp | 22 ++- 29 files changed, 195 insertions(+), 148 deletions(-) diff --git a/server/game/src/data/bytebufferext.rs b/server/game/src/data/bytebufferext.rs index a7969c3f..912d7611 100644 --- a/server/game/src/data/bytebufferext.rs +++ b/server/game/src/data/bytebufferext.rs @@ -268,6 +268,10 @@ impl<'a> FastByteBuffer<'a> { } } + pub fn new_with_length(src: &'a mut [u8], len: usize) -> Self { + Self { pos: 0, len, data: src } + } + pub fn write_u8(&mut self, val: u8) { self.internal_write(&val.to_be_bytes()); } diff --git a/server/game/src/server.rs b/server/game/src/server.rs index d63ba6ff..a0d811c9 100644 --- a/server/game/src/server.rs +++ b/server/game/src/server.rs @@ -23,7 +23,7 @@ use crate::{ state::ServerState, }; -const MAX_PACKET_SIZE: usize = 16384; +const MAX_PACKET_SIZE: usize = 8192; pub struct GameServerConfiguration { pub http_client: reqwest::Client, @@ -78,11 +78,8 @@ impl GameServer { }); } - // we preallocate a buffer to avoid zeroing out MAX_PACKET_SIZE bytes on each packet - let mut buf = [0u8; MAX_PACKET_SIZE]; - loop { - match self.recv_and_handle(&mut buf).await { + match self.recv_and_handle().await { Ok(()) => {} Err(err) => { warn!("Failed to handle a packet: {err}"); @@ -182,8 +179,9 @@ impl GameServer { Ok(()) } - async fn recv_and_handle(&'static self, buf: &mut [u8]) -> anyhow::Result<()> { - let (len, peer) = self.socket.recv_from(buf).await?; + async fn recv_and_handle(&'static self) -> anyhow::Result<()> { + let mut buf = [0u8; MAX_PACKET_SIZE]; + let (len, peer) = self.socket.recv_from(&mut buf).await?; let peer = match peer { SocketAddr::V6(_) => bail!("rejecting request from ipv6 host"), diff --git a/server/game/src/server_thread/error.rs b/server/game/src/server_thread/error.rs index 8bf6e93d..6deaf928 100644 --- a/server/game/src/server_thread/error.rs +++ b/server/game/src/server_thread/error.rs @@ -20,6 +20,7 @@ pub enum PacketHandlingError { UnexpectedCentralResponse, // malformed response from the central server ColorParseFailed(ColorParseError), // failed to parse a hex color into a Color3B struct Ratelimited, // too many packets per second + DangerousAllocation(usize), // attempted to allocate a huge chunk of memory with alloca } pub type Result = core::result::Result; @@ -76,6 +77,9 @@ impl Display for PacketHandlingError { Self::UnexpectedCentralResponse => f.write_str("got unexpected response from the central server"), Self::ColorParseFailed(err) => f.write_fmt(format_args!("failed to parse a color: {err}")), Self::Ratelimited => f.write_str("client is sending way too many packets per second"), + Self::DangerousAllocation(size) => f.write_fmt(format_args!( + "attempted to allocate {size} bytes on the stack - that has a potential for a stack overflow!" + )), } } } diff --git a/server/game/src/server_thread/handlers/mod.rs b/server/game/src/server_thread/handlers/mod.rs index 1d556270..4f5d9e6b 100644 --- a/server/game/src/server_thread/handlers/mod.rs +++ b/server/game/src/server_thread/handlers/mod.rs @@ -62,6 +62,17 @@ macro_rules! gs_needauth { }; } +pub const MAX_ALLOCA_SIZE: usize = 100_000; + +macro_rules! gs_alloca_check_size { + ($size:expr) => { + if $size > crate::server_thread::handlers::MAX_ALLOCA_SIZE { + let err = crate::server_thread::error::PacketHandlingError::DangerousAllocation($size); + return Err(err); + } + }; +} + /// hype af (variable size stack allocation) macro_rules! gs_with_alloca { ($size:expr, $data:ident, $code:expr) => { @@ -88,6 +99,8 @@ macro_rules! gs_inline_encode { }; ($self:ident, $size:expr, $data:ident, $rawdata:ident, $code:expr) => { + gs_alloca_check_size!($size); + let retval: Result>> = { gs_with_alloca!($size, $rawdata, { let mut $data = FastByteBuffer::new($rawdata); @@ -112,6 +125,7 @@ macro_rules! gs_inline_encode { } } +pub(crate) use gs_alloca_check_size; pub(crate) use gs_disconnect; pub(crate) use gs_handler; pub(crate) use gs_handler_sync; diff --git a/server/game/src/server_thread/mod.rs b/server/game/src/server_thread/mod.rs index e0ff2e62..e7903417 100644 --- a/server/game/src/server_thread/mod.rs +++ b/server/game/src/server_thread/mod.rs @@ -118,7 +118,8 @@ impl GameServerThread { | PacketHandlingError::ColorParseFailed(_) | PacketHandlingError::UnexpectedCentralResponse | PacketHandlingError::SystemTimeError(_) - | PacketHandlingError::WebRequestError(_) => { + | PacketHandlingError::WebRequestError(_) + | PacketHandlingError::DangerousAllocation(_) => { log::error!("[{} @ {}] err: {}", self.account_id.load(Ordering::Relaxed), self.peer, error); } // these can likely never happen unless network corruption or someone is pentesting, so ignore in release @@ -168,12 +169,11 @@ impl GameServerThread { } /// fast packet sending with best-case zero heap allocation. - /// on average, this is 2-3x faster than `send_packet`, even worst case should be faster by a bit. /// if the packet size isn't known at compile time, calculate it and use `send_packet_fast_rough` async fn send_packet_fast(&self, packet: &P) -> Result<()> { - // in theory, the size is known at compile time, however we still have to resort to using alloca - // because rust does not allow constant expressions with generic parameters. - // i.e. this would fail to compile: `let buffer = [0u8; PacketHeader::SIZE + P::ENCODED_SIZE];` + // in theory, the size is known at compile time, however for some reason, + // alloca manages to be significantly faster than a `[MaybeUninit; N]`. + // i have no idea why or how, but yeah. self.send_packet_fast_rough(packet, P::ENCODED_SIZE).await } @@ -196,6 +196,8 @@ impl GameServerThread { let mac_start = nonce_start + NONCE_SIZE; let raw_data_start = mac_start + MAC_SIZE; + gs_alloca_check_size!(total_size); + let to_send: Result>> = gs_with_alloca!(total_size, data, { // write the header let mut buf = FastByteBuffer::new(data); @@ -295,7 +297,6 @@ impl GameServerThread { .encrypt(&nonce, cltxtbuf.as_bytes()) .map_err(|_| PacketHandlingError::EncryptionError)?; - #[cfg(not(rust_analyzer))] // i am so sorry buf.write_bytes(&nonce); buf.write_bytes(&encrypted); @@ -325,7 +326,7 @@ impl GameServerThread { } // check if we are sending too many packets - if !self.rate_limiter.lock().tick() { + if !self.rate_limiter.lock().try_tick() { return Err(PacketHandlingError::Ratelimited); } @@ -359,6 +360,7 @@ impl GameServerThread { return Err(PacketHandlingError::MalformedLoginAttempt); } + // decrypt the packet in-place if encrypted if header.encrypted { if message.len() < PacketHeader::SIZE + NONCE_SIZE + MAC_SIZE { return Err(PacketHandlingError::MalformedCiphertext); @@ -366,6 +368,7 @@ impl GameServerThread { let cbox = self.crypto_box.get(); if cbox.is_none() { + self.terminate(); return Err(PacketHandlingError::WrongCryptoBoxState); } diff --git a/server/game/src/util/rate_limiter.rs b/server/game/src/util/rate_limiter.rs index d0f50aa6..dd2e02df 100644 --- a/server/game/src/util/rate_limiter.rs +++ b/server/game/src/util/rate_limiter.rs @@ -18,18 +18,19 @@ impl SimpleRateLimiter { } /// Returns `true` if we are not ratelimited, `false` if we are. - pub fn tick(&mut self) -> bool { - let now = Instant::now(); - if (now - self.last_refill) > self.period { - self.count = self.limit; - self.last_refill = now; - } - + pub fn try_tick(&mut self) -> bool { if self.count > 0 { self.count -= 1; true } else { - false + let now = Instant::now(); + if (now - self.last_refill) > self.period { + self.count = self.limit; + self.last_refill = now; + true + } else { + false + } } } } diff --git a/src/audio/all.hpp b/src/audio/all.hpp index c32d2fa1..9976d6e6 100644 --- a/src/audio/all.hpp +++ b/src/audio/all.hpp @@ -2,5 +2,7 @@ #include "audio_frame.hpp" #include "audio_manager.hpp" +#include "audio_sample_queue.hpp" +#include "audio_stream.hpp" #include "opus_codec.hpp" #include "voice_playback_manager.hpp" \ No newline at end of file diff --git a/src/audio/audio_frame.hpp b/src/audio/audio_frame.hpp index e9983036..2baa30a9 100644 --- a/src/audio/audio_frame.hpp +++ b/src/audio/audio_frame.hpp @@ -1,5 +1,4 @@ #pragma once - #include #if GLOBED_VOICE_SUPPORT diff --git a/src/audio/audio_manager.cpp b/src/audio/audio_manager.cpp index da77fbc9..37ec8ae4 100644 --- a/src/audio/audio_manager.cpp +++ b/src/audio/audio_manager.cpp @@ -2,8 +2,6 @@ #if GLOBED_VOICE_SUPPORT -#include -#include #include // this is horrible i know yes @@ -302,7 +300,7 @@ void GlobedAudioManager::audioThreadFunc() { // if we are not recording right now, sleep if (!recordActive) { audioThreadSleeping = true; - std::this_thread::sleep_for(std::chrono::milliseconds(25)); + std::this_thread::sleep_for(std::chrono::milliseconds(10)); continue; } @@ -328,7 +326,7 @@ void GlobedAudioManager::audioThreadFunc() { // if we are at the same position, do nothing if (pos == recordLastPosition) { this->getSystem()->update(); - std::this_thread::sleep_for(std::chrono::milliseconds(5)); + std::this_thread::sleep_for(std::chrono::milliseconds(3)); continue; } @@ -372,7 +370,7 @@ void GlobedAudioManager::audioThreadFunc() { this->getSystem()->update(); // TODO maybe do something with this i dunno - std::this_thread::sleep_for(std::chrono::milliseconds(5)); + std::this_thread::sleep_for(std::chrono::milliseconds(3)); // std::this_thread::yield(); } } @@ -474,7 +472,7 @@ const char* GlobedAudioManager::fmodErrorString(FMOD_RESULT result) { int idx = static_cast(result); if (idx < 0 || idx > 81) { - return "Invalid FMOD result was passed; there is no corresponding error message to return"; + return "Invalid FMOD error code was passed; there is no corresponding error message to return"; } return values[idx]; diff --git a/src/audio/audio_manager.hpp b/src/audio/audio_manager.hpp index 54c88229..14ac85bb 100644 --- a/src/audio/audio_manager.hpp +++ b/src/audio/audio_manager.hpp @@ -67,6 +67,7 @@ class GlobedAudioManager { // start recording the voice and call the callback once a full frame is ready. // if `stopRecording()` is called at any point, the callback will be called with the remaining data. // in that case it may have less than the full 10 frames. + // WARNING: the callback is called from the audio thread, not the GD/cocos thread. void startRecording(std::function callback); // tell the audio thread to stop recording void stopRecording(); diff --git a/src/audio/audio_sample_queue.cpp b/src/audio/audio_sample_queue.cpp index d05eab42..efd7a884 100644 --- a/src/audio/audio_sample_queue.cpp +++ b/src/audio/audio_sample_queue.cpp @@ -1,5 +1,7 @@ #include "audio_sample_queue.hpp" +#if GLOBED_VOICE_SUPPORT + void AudioSampleQueue::writeData(DecodedOpusData data) { this->writeData(data.ptr, data.length); } @@ -31,4 +33,6 @@ size_t AudioSampleQueue::size() const { void AudioSampleQueue::clear() { buf.clear(); -} \ No newline at end of file +} + +#endif // GLOBED_VOICE_SUPPORT \ No newline at end of file diff --git a/src/audio/audio_stream.cpp b/src/audio/audio_stream.cpp index b031f0d8..c5015d0e 100644 --- a/src/audio/audio_stream.cpp +++ b/src/audio/audio_stream.cpp @@ -5,9 +5,6 @@ #include "audio_frame.hpp" #include "audio_manager.hpp" -#include -#include - AudioStream::AudioStream() { FMOD_CREATESOUNDEXINFO exinfo = {}; diff --git a/src/audio/voice_playback_manager.hpp b/src/audio/voice_playback_manager.hpp index 25fbc2ee..9d6f9558 100644 --- a/src/audio/voice_playback_manager.hpp +++ b/src/audio/voice_playback_manager.hpp @@ -5,7 +5,6 @@ #include "audio_frame.hpp" #include "audio_stream.hpp" -#include /* * VoicePlaybackManager is responsible for playing voices of multiple people diff --git a/src/crypto/base_box.hpp b/src/crypto/base_box.hpp index 0c6744e3..564478dd 100644 --- a/src/crypto/base_box.hpp +++ b/src/crypto/base_box.hpp @@ -1,6 +1,7 @@ #pragma once #include #include +#include /* * This class contains no crypto implementation and is here just for boilerplate code. @@ -48,7 +49,7 @@ class BaseCryptoBox { util::data::bytevector encrypt(const std::string& src); /* Decryption */ - + // Decrypt `size` bytes from `data` into itself. Returns the length of the plaintext data. size_t decryptInPlace(util::data::byte* data, size_t size); diff --git a/src/crypto/box.hpp b/src/crypto/box.hpp index df5341fe..5e664abf 100644 --- a/src/crypto/box.hpp +++ b/src/crypto/box.hpp @@ -4,7 +4,6 @@ #include #include -#include class CryptoBox : public BaseCryptoBox { diff --git a/src/crypto/secret_box.hpp b/src/crypto/secret_box.hpp index 05282d6b..2efb5b7d 100644 --- a/src/crypto/secret_box.hpp +++ b/src/crypto/secret_box.hpp @@ -4,7 +4,6 @@ #include #include -#include /* * SecretBox - a class similar to CryptoBox, but instead of using public key cryptography, diff --git a/src/data/bytebuffer.hpp b/src/data/bytebuffer.hpp index 18748db3..2e4221e5 100644 --- a/src/data/bytebuffer.hpp +++ b/src/data/bytebuffer.hpp @@ -132,14 +132,9 @@ class ByteBuffer { template BitBuffer readBits() { constexpr size_t byteCount = util::data::bitsToBytes(BitCount); - boundsCheck(byteCount); + this->boundsCheck(byteCount); - auto value = read>(); - // I am not 100% sure about it, but it appears that byteswapping is unnecessary for BitBuffer. - - // if constexpr (GLOBED_LITTLE_ENDIAN) { - // value = util::data::byteswap(value); - // } + auto value = this->read>(); return BitBuffer(value); } @@ -147,12 +142,7 @@ class ByteBuffer { // Write all bits from the given `BitBuffer` into the current `ByteBuffer` template void writeBits(BitBuffer bitbuf) { - auto value = bitbuf.contents(); - // if constexpr (GLOBED_LITTLE_ENDIAN) { - // value = util::data::byteswap(value); - // } - - write(value); + this->write(bitbuf.contents()); } /* @@ -180,7 +170,7 @@ class ByteBuffer { if (this->readBool()) { value = this->readValue(); } - + return std::move(value); } diff --git a/src/data/packets/client/misc.hpp b/src/data/packets/client/misc.hpp index 3d3a0393..f80be63a 100644 --- a/src/data/packets/client/misc.hpp +++ b/src/data/packets/client/misc.hpp @@ -5,7 +5,7 @@ /* * RawPacket is a special packet. It is not an actual specific packet and has no consistent representation. -* Example usage and explanation can be found in `ui/hooks/play_layer.hpp` in the audio callback function. +* Example usage and explanation can be found in `ui/hooks/play_layer.hpp` in the audio callback. */ class RawPacket : public Packet { public: diff --git a/src/defs.hpp b/src/defs.hpp index 86f0c2b3..55d5c2b7 100644 --- a/src/defs.hpp +++ b/src/defs.hpp @@ -5,6 +5,5 @@ #include #include -#include #include #include \ No newline at end of file diff --git a/src/defs/platform.hpp b/src/defs/platform.hpp index 2df8b6e8..451e2cb3 100644 --- a/src/defs/platform.hpp +++ b/src/defs/platform.hpp @@ -7,8 +7,8 @@ * platform macros * GLOBED_WIN32, GLOBED_MAC, GLOBED_ANDROID - self descriptive * GLOBED_UNIX - mac or android -* GLOBED_X86_32, GLOBED_X86_64, GLOBED_ARM32, GLOBED_ARM64 - only 1 of those 4 is defined, indicating if we are 32-bit or 64-bit -* GLOBED_X86, GLOBED_ARM - any x86 or arm +* GLOBED_X86_32, GLOBED_X86_64, GLOBED_ARM32, GLOBED_ARM64 - only 1 of those 4 is defined, indicating the specific architecture +* GLOBED_X86, GLOBED_ARM - both x86 and x86_64 or both arm and arm64 * * GLOBED_PLATFORM_STRING_PLATFORM - string in format like "Mac", "Android", "Windows" * GLOBED_PLATFORM_STRING_ARCH - string in format like "x86", "x64", "armv7", "arm64" diff --git a/src/managers/server_manager.cpp b/src/managers/server_manager.cpp index 130a40e2..beaf7ca3 100644 --- a/src/managers/server_manager.cpp +++ b/src/managers/server_manager.cpp @@ -73,7 +73,7 @@ uint32_t GlobedServerManager::pingStart(const std::string& serverId) { gsi.pendingPings.clear(); } - auto now = util::time::nowMillis(); + auto now = util::time::sinceEpoch(); gsi.pendingPings[pingId] = now; return pingId; @@ -89,14 +89,14 @@ void GlobedServerManager::pingStartActive() { } void GlobedServerManager::pingFinish(uint32_t pingId, uint32_t playerCount) { - auto now = util::time::nowMillis(); + auto now = util::time::sinceEpoch(); auto data = _data.lock(); for (auto* server : util::collections::mapValuesBorrowed(data->servers)) { if (server->pendingPings.contains(pingId)) { auto start = server->pendingPings.at(pingId); auto timeTook = now - start; - server->ping = chrono::duration_cast(timeTook).count(); + server->ping = chrono::duration_cast(timeTook).count(); server->playerCount = playerCount; server->pingHistory.push(timeTook); server->pendingPings.erase(pingId); @@ -126,7 +126,7 @@ GameServerView GlobedServerManager::getGameServer(const std::string& serverId) { }; } -std::vector GlobedServerManager::getPingHistory(const std::string& serverId) { +std::vector GlobedServerManager::getPingHistory(const std::string& serverId) { auto data = _data.lock(); auto& gsi = data->servers.at(serverId); return gsi.pingHistory.extract(); diff --git a/src/managers/server_manager.hpp b/src/managers/server_manager.hpp index f0fde1cc..31e351d9 100644 --- a/src/managers/server_manager.hpp +++ b/src/managers/server_manager.hpp @@ -18,8 +18,8 @@ struct GameServerInfo { GameServerAddress address; int ping; - std::unordered_map pendingPings; - util::collections::CappedQueue pingHistory; + std::unordered_map pendingPings; + util::collections::CappedQueue pingHistory; uint32_t playerCount; }; @@ -63,7 +63,7 @@ class GlobedServerManager { void pingFinishActive(uint32_t playerCount); GameServerView getGameServer(const std::string& serverId); - std::vector getPingHistory(const std::string& serverId); + std::vector getPingHistory(const std::string& serverId); std::unordered_map extractGameServers(); diff --git a/src/net/network_manager.cpp b/src/net/network_manager.cpp index 7e2e5fb4..54289f59 100644 --- a/src/net/network_manager.cpp +++ b/src/net/network_manager.cpp @@ -63,12 +63,16 @@ NetworkManager::~NetworkManager() { this->removeAllListeners(); builtinListeners.lock()->clear(); - // wait for threads + // stop threads and wait for them to return _running = false; if (this->connected()) { log::debug("disconnecting from the server.."); - this->disconnect(); + try { + this->disconnect(false); + } catch (const std::exception& e) { + log::warn("error trying to disconnect: {}", e.what()); + } } log::debug("waiting for threads to halt.."); @@ -87,7 +91,7 @@ void NetworkManager::connect(const std::string& addr, unsigned short port) { this->disconnect(false); } - lastReceivedPacket = chrono::system_clock::now(); + lastReceivedPacket = util::time::now(); GLOBED_REQUIRE(!GlobedAccountManager::get().authToken.lock()->empty(), "attempting to connect with no authtoken set in account manager") @@ -156,7 +160,7 @@ void NetworkManager::threadMainFunc() { while (_running) { this->maybeSendKeepalive(); - if (!packetQueue.waitForMessages(chrono::milliseconds(250))) { + if (!packetQueue.waitForMessages(util::time::millis(250))) { // check for tasks if (taskQueue.empty()) continue; @@ -216,7 +220,7 @@ void NetworkManager::threadRecvFunc() { continue; } - lastReceivedPacket = chrono::system_clock::now(); + lastReceivedPacket = util::time::now(); auto builtin = builtinListeners.lock(); if (builtin->contains(packetId)) { @@ -245,7 +249,7 @@ void NetworkManager::handlePingResponse(std::shared_ptr packet) { void NetworkManager::maybeSendKeepalive() { if (_loggedin) { - auto now = chrono::system_clock::now(); + auto now = util::time::now(); if ((now - lastKeepalive) > KEEPALIVE_INTERVAL) { lastKeepalive = now; this->send(KeepalivePacket::create()); @@ -256,10 +260,13 @@ void NetworkManager::maybeSendKeepalive() { // Disconnects from the server if there has been no response for a while void NetworkManager::maybeDisconnectIfDead() { - auto now = chrono::system_clock::now(); - if (this->connected() && (now - lastReceivedPacket) > DISCONNECT_AFTER) { + if (this->connected() && (util::time::now() - lastReceivedPacket) > DISCONNECT_AFTER) { ErrorQueues::get().error("The server you were connected to is not responding to any requests. You have been disconnected."); - this->disconnect(); + try { + this->disconnect(); + } catch (const std::exception& e) { + log::warn("failed to disconnect from a dead server: {}", e.what()); + } } } diff --git a/src/net/network_manager.hpp b/src/net/network_manager.hpp index a2f933bd..37fa53c5 100644 --- a/src/net/network_manager.hpp +++ b/src/net/network_manager.hpp @@ -57,7 +57,7 @@ class NetworkManager { // Same as addListener(packetid_t, PacketCallback) but hacky syntax xd template void addListener(PacketCallbackSpecific callback) { - addListener(Pty::PACKET_ID, [callback](std::shared_ptr pkt){ + this->addListener(Pty::PACKET_ID, [callback](std::shared_ptr pkt) { callback(static_cast(pkt.get())); }); } @@ -68,7 +68,7 @@ class NetworkManager { // Same as removeListener(packetid_t) but hacky syntax once again template void removeListener() { - removeListener(T::PACKET_ID); + this->removeListener(T::PACKET_ID); } // Removes all listeners. @@ -112,8 +112,8 @@ class NetworkManager { AtomicBool _established = false; AtomicBool _loggedin = false; - chrono::system_clock::time_point lastKeepalive; - chrono::system_clock::time_point lastReceivedPacket; + util::time::time_point lastKeepalive; + util::time::time_point lastReceivedPacket; void handlePingResponse(std::shared_ptr packet); void maybeSendKeepalive(); @@ -126,7 +126,7 @@ class NetworkManager { template void addBuiltinListener(PacketCallbackSpecific callback) { - addBuiltinListener(Pty::PACKET_ID, [callback](std::shared_ptr pkt){ + this->addBuiltinListener(Pty::PACKET_ID, [callback](std::shared_ptr pkt) { callback(static_cast(pkt.get())); }); } diff --git a/src/net/socket.hpp b/src/net/socket.hpp index d367cec1..97f21ecb 100644 --- a/src/net/socket.hpp +++ b/src/net/socket.hpp @@ -1,5 +1,6 @@ #pragma once #include +#include class Socket { public: diff --git a/src/ui/error_check_node.cpp b/src/ui/error_check_node.cpp index 759a5eff..7c1a1a0e 100644 --- a/src/ui/error_check_node.cpp +++ b/src/ui/error_check_node.cpp @@ -1,5 +1,6 @@ #include "error_check_node.hpp" +#include #include using namespace geode::prelude; @@ -16,22 +17,28 @@ void ErrorCheckNode::updateErrors(float _unused) { if (!currentScene || !currentScene->getChildren() || currentScene->getChildrenCount() == 0) return; auto* currentLayer = currentScene->getChildren()->objectAtIndex(0); - + // do nothing during transitions or loading if (typeinfo_cast(currentScene) || typeinfo_cast(currentLayer)) { return; } - // TODO maybe dont show errors in playlayer if we aren't paused? - - auto errors = ErrorQueues::get().getErrors(); auto warnings = ErrorQueues::get().getWarnings(); - auto notices = ErrorQueues::get().getNotices(); for (auto& warn : warnings) { Notification::create(warn, NotificationIcon::Warning, 2.5f)->show(); } + // if we are in PlayLayer, don't show errors unless paused + + auto playlayer = static_cast(PlayLayer::get()); + if (playlayer != nullptr && !playlayer->isPaused()) { + return; + } + + auto errors = ErrorQueues::get().getErrors(); + auto notices = ErrorQueues::get().getNotices(); + if (errors.size() > 2) { errors.resize(2); } diff --git a/src/ui/hooks/play_layer.hpp b/src/ui/hooks/play_layer.hpp index efd4c01b..118fbac3 100644 --- a/src/ui/hooks/play_layer.hpp +++ b/src/ui/hooks/play_layer.hpp @@ -8,8 +8,7 @@ #include #endif // GLOBED_CUSTOM_KEYBINDS -#include