diff --git a/src/Components/Modules/Debug.cpp b/src/Components/Modules/Debug.cpp index 456320a8..0d968983 100644 --- a/src/Components/Modules/Debug.cpp +++ b/src/Components/Modules/Debug.cpp @@ -1,4 +1,5 @@ #include +#include "Game/Engine/ScopedCriticalSection.hpp" namespace Components { @@ -288,7 +289,7 @@ namespace Components sprintf_s(newFileName, "%s_%s.log", bug, Game::Live_GetLocalClientName(0)); - Game::Sys_EnterCriticalSection(Game::CRITSECT_CONSOLE); + Game::Engine::ScopedCriticalSection _(Game::CRITSECT_CONSOLE, Game::Engine::SCOPED_CRITSECT_NORMAL); if (*Game::logfile) { @@ -301,8 +302,6 @@ namespace Components const auto result = CopyFileA(from_ospath, to_ospath, 0); Game::Com_OpenLogFile(); - Game::Sys_LeaveCriticalSection(Game::CRITSECT_CONSOLE); - if (!result) { Logger::PrintError(1, "CopyFile failed({}) {} {}\n", GetLastError(), "console_mp.log", newFileName); diff --git a/src/Game/Engine/ScopedCriticalSection.cpp b/src/Game/Engine/ScopedCriticalSection.cpp new file mode 100644 index 00000000..9a756c94 --- /dev/null +++ b/src/Game/Engine/ScopedCriticalSection.cpp @@ -0,0 +1,82 @@ +#include +#include "ScopedCriticalSection.hpp" + +namespace Game::Engine +{ + ScopedCriticalSection::ScopedCriticalSection(const CriticalSection s, const ScopedCriticalSectionType type) + : s_(s), isScopedRelease_(false) + { + if (type == SCOPED_CRITSECT_NORMAL) + { + Sys_EnterCriticalSection(this->s_); + this->hasOwnership_ = true; + } + else + { + if (type == SCOPED_CRITSECT_TRY) + { + this->hasOwnership_ = Sys_TryEnterCriticalSection(this->s_); + } + else + { + if (type == SCOPED_CRITSECT_RELEASE) + { + Sys_LeaveCriticalSection(this->s_); + this->isScopedRelease_ = true; + } + + this->hasOwnership_ = false; + } + } + } + + ScopedCriticalSection::~ScopedCriticalSection() + { + if (!this->hasOwnership_ || this->isScopedRelease_) + { + if (!this->hasOwnership_ && this->isScopedRelease_) + { + Sys_EnterCriticalSection(this->s_); + } + } + else + { + Sys_LeaveCriticalSection(this->s_); + } + } + + void ScopedCriticalSection::enterCritSect() + { + assert(!this->hasOwnership_); + + this->hasOwnership_ = true; + Sys_EnterCriticalSection(this->s_); + } + + void ScopedCriticalSection::leaveCritSect() + { + assert(this->hasOwnership_); + + this->hasOwnership_ = false; + Sys_LeaveCriticalSection(this->s_); + } + + bool ScopedCriticalSection::tryEnterCritSect() + { + assert(!this->hasOwnership_); + + const auto result = Sys_TryEnterCriticalSection(this->s_); + this->hasOwnership_ = result; + return result; + } + + bool ScopedCriticalSection::hasOwnership() const + { + return this->hasOwnership_; + } + + bool ScopedCriticalSection::isScopedRelease() const + { + return this->isScopedRelease_; + } +} diff --git a/src/Game/Engine/ScopedCriticalSection.hpp b/src/Game/Engine/ScopedCriticalSection.hpp new file mode 100644 index 00000000..608721dc --- /dev/null +++ b/src/Game/Engine/ScopedCriticalSection.hpp @@ -0,0 +1,31 @@ +#pragma once + +namespace Game::Engine +{ + enum ScopedCriticalSectionType + { + SCOPED_CRITSECT_NORMAL = 0x0, + SCOPED_CRITSECT_DISABLED = 0x1, + SCOPED_CRITSECT_RELEASE = 0x2, + SCOPED_CRITSECT_TRY = 0x3, + }; + + class ScopedCriticalSection + { + public: + ScopedCriticalSection(CriticalSection s, ScopedCriticalSectionType type); + ~ScopedCriticalSection(); + + void enterCritSect(); + void leaveCritSect(); + [[nodiscard]] bool tryEnterCritSect(); + + [[nodiscard]] bool hasOwnership() const; + [[nodiscard]] bool isScopedRelease() const; + + private: + CriticalSection s_; + bool hasOwnership_; + bool isScopedRelease_; + }; +} diff --git a/src/Game/System.cpp b/src/Game/System.cpp index 9a85028b..24cf1687 100644 --- a/src/Game/System.cpp +++ b/src/Game/System.cpp @@ -24,6 +24,8 @@ namespace Game char(*sys_exitCmdLine)[1024] = reinterpret_cast(0x649FB68); + RTL_CRITICAL_SECTION* s_criticalSection = reinterpret_cast(0x6499BC8); + void Sys_LockRead(FastCriticalSection* critSect) { InterlockedIncrement(&critSect->readCount); @@ -35,4 +37,12 @@ namespace Game assert(critSect->readCount > 0); InterlockedDecrement(&critSect->readCount); } + + bool Sys_TryEnterCriticalSection(CriticalSection critSect) + { + assert(static_cast(critSect) < + static_cast(CRITSECT_COUNT)); + + return TryEnterCriticalSection(&s_criticalSection[critSect]) != FALSE; + } } diff --git a/src/Game/System.hpp b/src/Game/System.hpp index 5265f736..1232ba81 100644 --- a/src/Game/System.hpp +++ b/src/Game/System.hpp @@ -62,6 +62,10 @@ namespace Game extern char(*sys_exitCmdLine)[1024]; + extern RTL_CRITICAL_SECTION* s_criticalSection; + extern void Sys_LockRead(FastCriticalSection* critSect); extern void Sys_UnlockRead(FastCriticalSection* critSect); + + extern bool Sys_TryEnterCriticalSection(CriticalSection critSect); } diff --git a/src/Steam/Proxy.cpp b/src/Steam/Proxy.cpp index 4ac7e709..0df90ca1 100644 --- a/src/Steam/Proxy.cpp +++ b/src/Steam/Proxy.cpp @@ -162,31 +162,31 @@ namespace Steam Interface clientUtils(Proxy::ClientEngine->GetIClientUtils(Proxy::SteamPipe)); clientUtils.invoke("SetAppIDForCurrentPipe", Proxy::AppId, false); - char ourPath[MAX_PATH] = {0}; + char ourPath[MAX_PATH]{}; GetModuleFileNameA(GetModuleHandle(nullptr), ourPath, sizeof(ourPath)); - char ourDirectory[MAX_PATH] = { 0 }; + char ourDirectory[MAX_PATH]{}; GetCurrentDirectoryA(sizeof(ourDirectory), ourDirectory); - std::string cmdline = ::Utils::String::VA("\"%s\" -proc %d", ourPath, GetCurrentProcessId()); + const auto* cmdline = ::Utils::String::VA("\"%s\" -proc %d", ourPath, GetCurrentProcessId()); // As of 02/19/2017, the SpawnProcess method doesn't require the app id anymore, // but only for those who participate in the beta. // Therefore we have to check how many bytes the method expects as arguments // and adapt our call accordingly! - size_t expectedParams = Proxy::ClientUser.paramSize("SpawnProcess"); + const auto expectedParams = Proxy::ClientUser.paramSize("SpawnProcess"); if (expectedParams == 40) // Release { - Proxy::ClientUser.invoke("SpawnProcess", ourPath, cmdline.data(), ourDirectory, gameID.bits, mod.data(), Proxy::AppId, 0, 0); + Proxy::ClientUser.invoke("SpawnProcess", ourPath, cmdline, ourDirectory, gameID.bits, mod.data(), Proxy::AppId, 0, 0, 0); } else if (expectedParams == 36) // Beta { - Proxy::ClientUser.invoke("SpawnProcess", ourPath, cmdline.data(), ourDirectory, gameID.bits, mod.data(), Proxy::AppId, 0, 0); + Proxy::ClientUser.invoke("SpawnProcess", ourPath, cmdline, ourDirectory, gameID.bits, mod.data(), Proxy::AppId, 0, 0); } else if (expectedParams == 48) // Legacy, expects VAC blob { char blob[8] = { 0 }; - Proxy::ClientUser.invoke("SpawnProcess", blob, 0, ourPath, cmdline.data(), 0, ourDirectory, gameID.bits, Proxy::AppId, mod.data(), 0, 0); + Proxy::ClientUser.invoke("SpawnProcess", blob, 0, ourPath, cmdline, 0, ourDirectory, gameID.bits, Proxy::AppId, mod.data(), 0, 0); } else { @@ -260,7 +260,7 @@ namespace Steam Proxy::Callbacks.erase(callId); } - void Proxy::RunCallback(int32_t callId, void* data, size_t /*size*/) + void Proxy::RunCallback(int32_t callId, void* data, std::size_t /*size*/) { std::lock_guard _(Proxy::CallMutex); diff --git a/src/Steam/Proxy.hpp b/src/Steam/Proxy.hpp index 3e0c84a3..27c0cf30 100644 --- a/src/Steam/Proxy.hpp +++ b/src/Steam/Proxy.hpp @@ -169,8 +169,8 @@ namespace Steam return T(); } - size_t argc = method.second; - constexpr size_t passedArgc = Interface::AddSizes::value; + std::size_t argc = method.second; + constexpr std::size_t passedArgc = Interface::AddSizes::value; if(passedArgc != argc) { OutputDebugStringA(::Utils::String::VA("Steam interface arguments for method %s do not match (expected %d bytes, but got %d bytes)!\n", methodName.data(), argc, passedArgc)); @@ -185,7 +185,7 @@ namespace Steam return this->interfacePtr != nullptr; } - size_t paramSize(const std::string& methodName) + std::size_t paramSize(const std::string& methodName) { auto method = this->getMethod(methodName); return method.second; @@ -222,9 +222,9 @@ namespace Steam private: std::string buffer; - inline void packBytes(const void* bytes, size_t size) + inline void packBytes(const void* bytes, std::size_t size) { - this->buffer.append(reinterpret_cast(bytes), size); + this->buffer.append(static_cast(bytes), size); } inline void packDataType(uint8_t type) @@ -358,7 +358,7 @@ namespace Steam static std::function SteamFreeLastCallback; static std::function SteamGetAPICallResult; - static void RunCallback(int32_t callId, void* data, size_t size); + static void RunCallback(int32_t callId, void* data, std::size_t size); static void UnregisterCalls(); static void LaunchWatchGuard();