diff options
Diffstat (limited to 'NorthstarDLL/client')
-rw-r--r-- | NorthstarDLL/client/audio.cpp | 504 | ||||
-rw-r--r-- | NorthstarDLL/client/audio.h | 46 | ||||
-rw-r--r-- | NorthstarDLL/client/chatcommand.cpp | 36 | ||||
-rw-r--r-- | NorthstarDLL/client/clientauthhooks.cpp | 72 | ||||
-rw-r--r-- | NorthstarDLL/client/clientruihooks.cpp | 23 | ||||
-rw-r--r-- | NorthstarDLL/client/clientvideooverrides.cpp | 41 | ||||
-rw-r--r-- | NorthstarDLL/client/debugoverlay.cpp | 348 | ||||
-rw-r--r-- | NorthstarDLL/client/demofixes.cpp | 25 | ||||
-rw-r--r-- | NorthstarDLL/client/diskvmtfixes.cpp | 15 | ||||
-rw-r--r-- | NorthstarDLL/client/languagehooks.cpp | 115 | ||||
-rw-r--r-- | NorthstarDLL/client/latencyflex.cpp | 43 | ||||
-rw-r--r-- | NorthstarDLL/client/localchatwriter.cpp | 449 | ||||
-rw-r--r-- | NorthstarDLL/client/localchatwriter.h | 64 | ||||
-rw-r--r-- | NorthstarDLL/client/modlocalisation.cpp | 55 | ||||
-rw-r--r-- | NorthstarDLL/client/r2client.cpp | 13 | ||||
-rw-r--r-- | NorthstarDLL/client/r2client.h | 7 | ||||
-rw-r--r-- | NorthstarDLL/client/rejectconnectionfixes.cpp | 34 |
17 files changed, 0 insertions, 1890 deletions
diff --git a/NorthstarDLL/client/audio.cpp b/NorthstarDLL/client/audio.cpp deleted file mode 100644 index aa32e390..00000000 --- a/NorthstarDLL/client/audio.cpp +++ /dev/null @@ -1,504 +0,0 @@ -#include "audio.h" -#include "dedicated/dedicated.h" -#include "core/convar/convar.h" - -#include "rapidjson/error/en.h" -#include <fstream> -#include <iostream> -#include <sstream> -#include <random> - -AUTOHOOK_INIT() - -static const char* pszAudioEventName; - -ConVar* Cvar_mileslog_enable; -ConVar* Cvar_ns_print_played_sounds; - -CustomAudioManager g_CustomAudioManager; - -EventOverrideData::EventOverrideData() -{ - spdlog::warn("Initialised struct EventOverrideData without any data!"); - LoadedSuccessfully = false; -} - -// Empty stereo 48000 WAVE file -unsigned char EMPTY_WAVE[45] = {0x52, 0x49, 0x46, 0x46, 0x25, 0x00, 0x00, 0x00, 0x57, 0x41, 0x56, 0x45, 0x66, 0x6D, 0x74, - 0x20, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x44, 0xAC, 0x00, 0x00, 0x88, 0x58, - 0x01, 0x00, 0x02, 0x00, 0x10, 0x00, 0x64, 0x61, 0x74, 0x61, 0x74, 0x00, 0x00, 0x00, 0x00}; - -EventOverrideData::EventOverrideData(const std::string& data, const fs::path& path) -{ - if (data.length() <= 0) - { - spdlog::error("Failed reading audio override file {}: file is empty", path.string()); - return; - } - - fs::path samplesFolder = path; - samplesFolder = samplesFolder.replace_extension(); - - if (!fs::exists(samplesFolder)) - { - spdlog::error( - "Failed reading audio override file {}: samples folder doesn't exist; should be named the same as the definition file without " - "JSON extension.", - path.string()); - return; - } - - rapidjson_document dataJson; - dataJson.Parse<rapidjson::ParseFlag::kParseCommentsFlag | rapidjson::ParseFlag::kParseTrailingCommasFlag>(data); - - // fail if parse error - if (dataJson.HasParseError()) - { - spdlog::error( - "Failed reading audio override file {}: encountered parse error \"{}\" at offset {}", - path.string(), - GetParseError_En(dataJson.GetParseError()), - dataJson.GetErrorOffset()); - return; - } - - // fail if it's not a json obj (could be an array, string, etc) - if (!dataJson.IsObject()) - { - spdlog::error("Failed reading audio override file {}: file is not a JSON object", path.string()); - return; - } - - // fail if no event ids given - if (!dataJson.HasMember("EventId")) - { - spdlog::error("Failed reading audio override file {}: JSON object does not have the EventId property", path.string()); - return; - } - - // array of event ids - if (dataJson["EventId"].IsArray()) - { - for (auto& eventId : dataJson["EventId"].GetArray()) - { - if (!eventId.IsString()) - { - spdlog::error( - "Failed reading audio override file {}: EventId array has a value of invalid type, all must be strings", path.string()); - return; - } - - EventIds.push_back(eventId.GetString()); - } - } - // singular event id - else if (dataJson["EventId"].IsString()) - { - EventIds.push_back(dataJson["EventId"].GetString()); - } - // incorrect type - else - { - spdlog::error( - "Failed reading audio override file {}: EventId property is of invalid type (must be a string or an array of strings)", - path.string()); - return; - } - - if (dataJson.HasMember("EventIdRegex")) - { - // array of event id regex - if (dataJson["EventIdRegex"].IsArray()) - { - for (auto& eventId : dataJson["EventIdRegex"].GetArray()) - { - if (!eventId.IsString()) - { - spdlog::error( - "Failed reading audio override file {}: EventIdRegex array has a value of invalid type, all must be strings", - path.string()); - return; - } - - const std::string& regex = eventId.GetString(); - - try - { - EventIdsRegex.push_back({regex, std::regex(regex)}); - } - catch (...) - { - spdlog::error("Malformed regex \"{}\" in audio override file {}", regex, path.string()); - return; - } - } - } - // singular event id regex - else if (dataJson["EventIdRegex"].IsString()) - { - const std::string& regex = dataJson["EventIdRegex"].GetString(); - try - { - EventIdsRegex.push_back({regex, std::regex(regex)}); - } - catch (...) - { - spdlog::error("Malformed regex \"{}\" in audio override file {}", regex, path.string()); - return; - } - } - // incorrect type - else - { - spdlog::error( - "Failed reading audio override file {}: EventIdRegex property is of invalid type (must be a string or an array of strings)", - path.string()); - return; - } - } - - if (dataJson.HasMember("AudioSelectionStrategy")) - { - if (!dataJson["AudioSelectionStrategy"].IsString()) - { - spdlog::error("Failed reading audio override file {}: AudioSelectionStrategy property must be a string", path.string()); - return; - } - - std::string strategy = dataJson["AudioSelectionStrategy"].GetString(); - - if (strategy == "sequential") - { - Strategy = AudioSelectionStrategy::SEQUENTIAL; - } - else if (strategy == "random") - { - Strategy = AudioSelectionStrategy::RANDOM; - } - else - { - spdlog::error( - "Failed reading audio override file {}: AudioSelectionStrategy string must be either \"sequential\" or \"random\"", - path.string()); - return; - } - } - - // load samples - for (fs::directory_entry file : fs::recursive_directory_iterator(samplesFolder)) - { - if (file.is_regular_file() && file.path().extension().string() == ".wav") - { - std::string pathString = file.path().string(); - - // Open the file. - std::ifstream wavStream(pathString, std::ios::binary); - - if (wavStream.fail()) - { - spdlog::error("Failed reading audio sample {}", file.path().string()); - continue; - } - - // Get file size. - wavStream.seekg(0, std::ios::end); - size_t fileSize = wavStream.tellg(); - wavStream.close(); - - // Allocate enough memory for the file. - // blank out the memory for now, then read it later - uint8_t* data = new uint8_t[fileSize]; - memcpy(data, EMPTY_WAVE, sizeof(EMPTY_WAVE)); - Samples.push_back({fileSize, std::unique_ptr<uint8_t[]>(data)}); - - // thread off the file read - // should we spawn one thread per read? or should there be a cap to the number of reads at once? - std::thread readThread( - [pathString, fileSize, data] - { - std::shared_lock lock(g_CustomAudioManager.m_loadingMutex); - std::ifstream wavStream(pathString, std::ios::binary); - - // would be weird if this got hit, since it would've worked previously - if (wavStream.fail()) - { - spdlog::error("Failed async read of audio sample {}", pathString); - return; - } - - // read from after the header first to preserve the empty header, then read the header last - wavStream.seekg(0, std::ios::beg); - wavStream.read(reinterpret_cast<char*>(data), fileSize); - wavStream.close(); - - spdlog::info("Finished async read of audio sample {}", pathString); - }); - - readThread.detach(); - } - } - - /* - if (dataJson.HasMember("EnableOnLoopedSounds")) - { - if (!dataJson["EnableOnLoopedSounds"].IsBool()) - { - spdlog::error("Failed reading audio override file {}: EnableOnLoopedSounds property is of invalid type (must be a bool)", - path.string()); return; - } - - EnableOnLoopedSounds = dataJson["EnableOnLoopedSounds"].GetBool(); - } - */ - - if (Samples.size() == 0) - spdlog::warn("Audio override {} has no valid samples! Sounds will not play for this event.", path.string()); - - spdlog::info("Loaded audio override file {}", path.string()); - - LoadedSuccessfully = true; -} - -bool CustomAudioManager::TryLoadAudioOverride(const fs::path& defPath) -{ - if (IsDedicatedServer()) - return true; // silently fail - - std::ifstream jsonStream(defPath); - std::stringstream jsonStringStream; - - // fail if no audio json - if (jsonStream.fail()) - { - spdlog::warn("Unable to read audio override from file {}", defPath.string()); - return false; - } - - while (jsonStream.peek() != EOF) - jsonStringStream << (char)jsonStream.get(); - - jsonStream.close(); - - std::shared_ptr<EventOverrideData> data = std::make_shared<EventOverrideData>(jsonStringStream.str(), defPath); - - if (!data->LoadedSuccessfully) - return false; // no logging, the constructor has probably already logged - - for (const std::string& eventId : data->EventIds) - { - spdlog::info("Registering sound event {}", eventId); - m_loadedAudioOverrides.insert({eventId, data}); - } - - for (const auto& eventIdRegexData : data->EventIdsRegex) - { - spdlog::info("Registering sound event regex {}", eventIdRegexData.first); - m_loadedAudioOverridesRegex.insert({eventIdRegexData.first, data}); - } - - return true; -} - -typedef void (*MilesStopAll_Type)(); -MilesStopAll_Type MilesStopAll; - -void CustomAudioManager::ClearAudioOverrides() -{ - if (IsDedicatedServer()) - return; - - if (m_loadedAudioOverrides.size() > 0 || m_loadedAudioOverridesRegex.size() > 0) - { - // stop all miles sounds beforehand - // miles_stop_all - - MilesStopAll(); - - // this is cancer but it works - Sleep(50); - } - - // slightly (very) bad - // wait for all audio reads to complete so we don't kill preexisting audio buffers as we're writing to them - std::unique_lock lock(m_loadingMutex); - - m_loadedAudioOverrides.clear(); - m_loadedAudioOverridesRegex.clear(); -} - -template <typename Iter, typename RandomGenerator> Iter select_randomly(Iter start, Iter end, RandomGenerator& g) -{ - std::uniform_int_distribution<> dis(0, std::distance(start, end) - 1); - std::advance(start, dis(g)); - return start; -} - -template <typename Iter> Iter select_randomly(Iter start, Iter end) -{ - static std::random_device rd; - static std::mt19937 gen(rd()); - return select_randomly(start, end, gen); -} - -bool ShouldPlayAudioEvent(const char* eventName, const std::shared_ptr<EventOverrideData>& data) -{ - std::string eventNameString = eventName; - std::string eventNameStringBlacklistEntry = ("!" + eventNameString); - - for (const std::string& name : data->EventIds) - { - if (name == eventNameStringBlacklistEntry) - return false; // event blacklisted - - if (name == "*") - { - // check for bad sounds I guess? - // really feel like this should be an option but whatever - if (!!strstr(eventName, "_amb_") || !!strstr(eventName, "_emit_") || !!strstr(eventName, "amb_")) - return false; // would play static noise, I hate this - } - } - - return true; // good to go -} - -// clang-format off -AUTOHOOK(LoadSampleMetadata, mileswin64.dll + 0xF110, -bool, __fastcall, (void* sample, void* audioBuffer, unsigned int audioBufferLength, int audioType)) -// clang-format on -{ - // Raw source, used for voice data only - if (audioType == 0) - return LoadSampleMetadata(sample, audioBuffer, audioBufferLength, audioType); - - const char* eventName = pszAudioEventName; - - if (Cvar_ns_print_played_sounds->GetInt() > 0) - spdlog::info("[AUDIO] Playing event {}", eventName); - - auto iter = g_CustomAudioManager.m_loadedAudioOverrides.find(eventName); - std::shared_ptr<EventOverrideData> overrideData; - - if (iter == g_CustomAudioManager.m_loadedAudioOverrides.end()) - { - // override for that specific event not found, try wildcard - iter = g_CustomAudioManager.m_loadedAudioOverrides.find("*"); - - if (iter == g_CustomAudioManager.m_loadedAudioOverrides.end()) - { - // not found - - // try regex - for (const auto& item : g_CustomAudioManager.m_loadedAudioOverridesRegex) - for (const auto& regexData : item.second->EventIdsRegex) - if (std::regex_search(eventName, regexData.second)) - overrideData = item.second; - - if (!overrideData) - // not found either - return LoadSampleMetadata(sample, audioBuffer, audioBufferLength, audioType); - else - { - // cache found pattern to improve performance - g_CustomAudioManager.m_loadedAudioOverrides[eventName] = overrideData; - } - } - else - overrideData = iter->second; - } - else - overrideData = iter->second; - - if (!ShouldPlayAudioEvent(eventName, overrideData)) - return LoadSampleMetadata(sample, audioBuffer, audioBufferLength, audioType); - - void* data = 0; - unsigned int dataLength = 0; - - if (overrideData->Samples.size() == 0) - { - // 0 samples, turn off this particular event. - - // using a dummy empty wave file - data = EMPTY_WAVE; - dataLength = sizeof(EMPTY_WAVE); - } - else - { - std::pair<size_t, std::unique_ptr<uint8_t[]>>* dat = NULL; - - switch (overrideData->Strategy) - { - case AudioSelectionStrategy::RANDOM: - dat = &*select_randomly(overrideData->Samples.begin(), overrideData->Samples.end()); - break; - case AudioSelectionStrategy::SEQUENTIAL: - default: - dat = &overrideData->Samples[overrideData->CurrentIndex++]; - if (overrideData->CurrentIndex >= overrideData->Samples.size()) - overrideData->CurrentIndex = 0; // reset back to the first sample entry - break; - } - - if (!dat) - spdlog::warn("Could not get sample data from override struct for event {}! Shouldn't happen", eventName); - else - { - data = dat->second.get(); - dataLength = dat->first; - } - } - - if (!data) - { - spdlog::warn("Could not fetch override sample data for event {}! Using original data instead.", eventName); - return LoadSampleMetadata(sample, audioBuffer, audioBufferLength, audioType); - } - - audioBuffer = data; - audioBufferLength = dataLength; - - // most important change: set the sample class buffer so that the correct audio plays - *(void**)((uintptr_t)sample + 0xE8) = audioBuffer; - *(unsigned int*)((uintptr_t)sample + 0xF0) = audioBufferLength; - - // 64 - Auto-detect sample type - bool res = LoadSampleMetadata(sample, audioBuffer, audioBufferLength, 64); - if (!res) - spdlog::error("LoadSampleMetadata failed! The game will crash :("); - - return res; -} - -// clang-format off -AUTOHOOK(sub_1800294C0, mileswin64.dll + 0x294C0, -void*, __fastcall, (void* a1, void* a2)) -// clang-format on -{ - pszAudioEventName = reinterpret_cast<const char*>((*((__int64*)a2 + 6))); - return sub_1800294C0(a1, a2); -} - -// clang-format off -AUTOHOOK(MilesLog, client.dll + 0x57DAD0, -void, __fastcall, (int level, const char* string)) -// clang-format on -{ - if (!Cvar_mileslog_enable->GetBool()) - return; - - spdlog::info("[MSS] {} - {}", level, string); -} - -ON_DLL_LOAD_RELIESON("engine.dll", MilesLogFuncHooks, ConVar, (CModule module)) -{ - Cvar_mileslog_enable = new ConVar("mileslog_enable", "0", FCVAR_NONE, "Enables/disables whether the mileslog func should be logged"); -} - -ON_DLL_LOAD_CLIENT_RELIESON("client.dll", AudioHooks, ConVar, (CModule module)) -{ - AUTOHOOK_DISPATCH() - - Cvar_ns_print_played_sounds = new ConVar("ns_print_played_sounds", "0", FCVAR_NONE, ""); - MilesStopAll = module.Offset(0x580850).RCast<MilesStopAll_Type>(); -} diff --git a/NorthstarDLL/client/audio.h b/NorthstarDLL/client/audio.h deleted file mode 100644 index 15fd1a35..00000000 --- a/NorthstarDLL/client/audio.h +++ /dev/null @@ -1,46 +0,0 @@ -#pragma once - -#include <vector> -#include <filesystem> -#include <regex> -#include <shared_mutex> - -enum class AudioSelectionStrategy -{ - INVALID = -1, - SEQUENTIAL, - RANDOM -}; - -class EventOverrideData -{ -public: - EventOverrideData(const std::string&, const fs::path&); - EventOverrideData(); - -public: - bool LoadedSuccessfully = false; - - std::vector<std::string> EventIds = {}; - std::vector<std::pair<std::string, std::regex>> EventIdsRegex = {}; - - std::vector<std::pair<size_t, std::unique_ptr<uint8_t[]>>> Samples = {}; - - AudioSelectionStrategy Strategy = AudioSelectionStrategy::SEQUENTIAL; - size_t CurrentIndex = 0; - - bool EnableOnLoopedSounds = false; -}; - -class CustomAudioManager -{ -public: - bool TryLoadAudioOverride(const fs::path&); - void ClearAudioOverrides(); - - std::shared_mutex m_loadingMutex; - std::unordered_map<std::string, std::shared_ptr<EventOverrideData>> m_loadedAudioOverrides = {}; - std::unordered_map<std::string, std::shared_ptr<EventOverrideData>> m_loadedAudioOverridesRegex = {}; -}; - -extern CustomAudioManager g_CustomAudioManager; diff --git a/NorthstarDLL/client/chatcommand.cpp b/NorthstarDLL/client/chatcommand.cpp deleted file mode 100644 index 9cf34e43..00000000 --- a/NorthstarDLL/client/chatcommand.cpp +++ /dev/null @@ -1,36 +0,0 @@ -#include "core/convar/convar.h" -#include "core/convar/concommand.h" -#include "localchatwriter.h" - -// note: isIngameChat is an int64 because the whole register the arg is stored in needs to be 0'd out to work -// if isIngameChat is false, we use network chat instead -void(__fastcall* ClientSayText)(void* a1, const char* message, uint64_t isIngameChat, bool isTeamChat); - -void ConCommand_say(const CCommand& args) -{ - if (args.ArgC() >= 2) - ClientSayText(nullptr, args.ArgS(), true, false); -} - -void ConCommand_say_team(const CCommand& args) -{ - if (args.ArgC() >= 2) - ClientSayText(nullptr, args.ArgS(), true, true); -} - -void ConCommand_log(const CCommand& args) -{ - if (args.ArgC() >= 2) - { - LocalChatWriter(LocalChatWriter::GameContext).WriteLine(args.ArgS()); - } -} - -ON_DLL_LOAD_CLIENT_RELIESON("engine.dll", ClientChatCommand, ConCommand, (CModule module)) -{ - ClientSayText = - module.Offset(0x54780).RCast<void(__fastcall*)(void* a1, const char* message, uint64_t isIngameChat, bool isTeamChat)>(); - RegisterConCommand("say", ConCommand_say, "Enters a message in public chat", FCVAR_CLIENTDLL); - RegisterConCommand("say_team", ConCommand_say_team, "Enters a message in team chat", FCVAR_CLIENTDLL); - RegisterConCommand("log", ConCommand_log, "Log a message to the local chat window", FCVAR_CLIENTDLL); -} diff --git a/NorthstarDLL/client/clientauthhooks.cpp b/NorthstarDLL/client/clientauthhooks.cpp deleted file mode 100644 index 35ae3aa7..00000000 --- a/NorthstarDLL/client/clientauthhooks.cpp +++ /dev/null @@ -1,72 +0,0 @@ -#include "masterserver/masterserver.h" -#include "core/convar/convar.h" -#include "client/r2client.h" -#include "core/vanilla.h" - -AUTOHOOK_INIT() - -ConVar* Cvar_ns_has_agreed_to_send_token; - -// mirrored in script -const int NOT_DECIDED_TO_SEND_TOKEN = 0; -const int AGREED_TO_SEND_TOKEN = 1; -const int DISAGREED_TO_SEND_TOKEN = 2; - -// clang-format off -AUTOHOOK(AuthWithStryder, engine.dll + 0x1843A0, -void, __fastcall, (void* a1)) -// clang-format on -{ - // don't attempt to do Atlas auth if we are in vanilla compatibility mode - // this prevents users from joining untrustworthy servers (unless they use a concommand or something) - if (g_pVanillaCompatibility->GetVanillaCompatibility()) - { - AuthWithStryder(a1); - return; - } - - // game will call this forever, until it gets a valid auth key - // so, we need to manually invalidate our key until we're authed with northstar, then we'll allow game to auth with stryder - if (!g_pMasterServerManager->m_bOriginAuthWithMasterServerDone && Cvar_ns_has_agreed_to_send_token->GetInt() != DISAGREED_TO_SEND_TOKEN) - { - // if player has agreed to send token and we aren't already authing, try to auth - if (Cvar_ns_has_agreed_to_send_token->GetInt() == AGREED_TO_SEND_TOKEN && - !g_pMasterServerManager->m_bOriginAuthWithMasterServerInProgress) - g_pMasterServerManager->AuthenticateOriginWithMasterServer(g_pLocalPlayerUserID, g_pLocalPlayerOriginToken); - - // invalidate key so auth will fail - *g_pLocalPlayerOriginToken = 0; - } - - AuthWithStryder(a1); -} - -char* p3PToken; - -// clang-format off -AUTOHOOK(Auth3PToken, engine.dll + 0x183760, -char*, __fastcall, ()) -// clang-format on -{ - if (!g_pVanillaCompatibility->GetVanillaCompatibility() && g_pMasterServerManager->m_sOwnClientAuthToken[0]) - { - memset(p3PToken, 0x0, 1024); - strcpy(p3PToken, "Protocol 3: Protect the Pilot"); - } - - return Auth3PToken(); -} - -ON_DLL_LOAD_CLIENT_RELIESON("engine.dll", ClientAuthHooks, ConVar, (CModule module)) -{ - AUTOHOOK_DISPATCH() - - p3PToken = module.Offset(0x13979D80).RCast<char*>(); - - // this cvar will save to cfg once initially agreed with - Cvar_ns_has_agreed_to_send_token = new ConVar( - "ns_has_agreed_to_send_token", - "0", - FCVAR_ARCHIVE_PLAYERPROFILE, - "whether the user has agreed to send their origin token to the northstar masterserver"); -} diff --git a/NorthstarDLL/client/clientruihooks.cpp b/NorthstarDLL/client/clientruihooks.cpp deleted file mode 100644 index ad50d11a..00000000 --- a/NorthstarDLL/client/clientruihooks.cpp +++ /dev/null @@ -1,23 +0,0 @@ -#include "core/convar/convar.h" - -AUTOHOOK_INIT() - -ConVar* Cvar_rui_drawEnable; - -// clang-format off -AUTOHOOK(DrawRUIFunc, engine.dll + 0xFC500, -bool, __fastcall, (void* a1, float* a2)) -// clang-format on -{ - if (!Cvar_rui_drawEnable->GetBool()) - return 0; - - return DrawRUIFunc(a1, a2); -} - -ON_DLL_LOAD_CLIENT_RELIESON("engine.dll", RUI, ConVar, (CModule module)) -{ - AUTOHOOK_DISPATCH() - - Cvar_rui_drawEnable = new ConVar("rui_drawEnable", "1", FCVAR_CLIENTDLL, "Controls whether RUI should be drawn"); -} diff --git a/NorthstarDLL/client/clientvideooverrides.cpp b/NorthstarDLL/client/clientvideooverrides.cpp deleted file mode 100644 index d8aa2754..00000000 --- a/NorthstarDLL/client/clientvideooverrides.cpp +++ /dev/null @@ -1,41 +0,0 @@ -#include "mods/modmanager.h" - -AUTOHOOK_INIT() - -// clang-format off -AUTOHOOK_PROCADDRESS(BinkOpen, bink2w64.dll, BinkOpen, -void*, __fastcall, (const char* path, uint32_t flags)) -// clang-format on -{ - std::string filename(fs::path(path).filename().string()); - spdlog::info("BinkOpen {}", filename); - - // figure out which mod is handling the bink - Mod* fileOwner = nullptr; - for (Mod& mod : g_pModManager->m_LoadedMods) - { - if (!mod.m_bEnabled) - continue; - - if (std::find(mod.BinkVideos.begin(), mod.BinkVideos.end(), filename) != mod.BinkVideos.end()) - fileOwner = &mod; - } - - if (fileOwner) - { - // create new path - fs::path binkPath(fileOwner->m_ModDirectory / "media" / filename); - return BinkOpen(binkPath.string().c_str(), flags); - } - else - return BinkOpen(path, flags); -} - -ON_DLL_LOAD_CLIENT("engine.dll", BinkVideo, (CModule module)) -{ - AUTOHOOK_DISPATCH() - - // remove engine check for whether the bik we're trying to load exists in r2/media, as this will fail for biks in mods - // note: the check in engine is actually unnecessary, so it's just useless in practice and we lose nothing by removing it - module.Offset(0x459AD).NOP(6); -} diff --git a/NorthstarDLL/client/debugoverlay.cpp b/NorthstarDLL/client/debugoverlay.cpp deleted file mode 100644 index e231054d..00000000 --- a/NorthstarDLL/client/debugoverlay.cpp +++ /dev/null @@ -1,348 +0,0 @@ -#include "dedicated/dedicated.h" -#include "core/convar/cvar.h" -#include "core/math/vector.h" - -AUTOHOOK_INIT() - -enum OverlayType_t -{ - OVERLAY_BOX = 0, - OVERLAY_SPHERE, - OVERLAY_LINE, - OVERLAY_SMARTAMMO, - OVERLAY_TRIANGLE, - OVERLAY_SWEPT_BOX, - // [Fifty]: the 2 bellow i did not confirm, rest are good - OVERLAY_BOX2, - OVERLAY_CAPSULE -}; - -struct OverlayBase_t -{ - OverlayBase_t() - { - m_Type = OVERLAY_BOX; - m_nServerCount = -1; - m_nCreationTick = -1; - m_flEndTime = 0.0f; - m_pNextOverlay = NULL; - } - - OverlayType_t m_Type; // What type of overlay is it? - int m_nCreationTick; // Duration -1 means go away after this frame # - int m_nServerCount; // Latch server count, too - float m_flEndTime; // When does this box go away - OverlayBase_t* m_pNextOverlay; - __int64 m_pUnk; -}; - -struct OverlayLine_t : public OverlayBase_t -{ - OverlayLine_t() - { - m_Type = OVERLAY_LINE; - } - - Vector3 origin; - Vector3 dest; - int r; - int g; - int b; - int a; - bool noDepthTest; -}; - -struct OverlayBox_t : public OverlayBase_t -{ - OverlayBox_t() - { - m_Type = OVERLAY_BOX; - } - - Vector3 origin; - Vector3 mins; - Vector3 maxs; - QAngle angles; - int r; - int g; - int b; - int a; -}; - -struct OverlayTriangle_t : public OverlayBase_t -{ - OverlayTriangle_t() - { - m_Type = OVERLAY_TRIANGLE; - } - - Vector3 p1; - Vector3 p2; - Vector3 p3; - int r; - int g; - int b; - int a; - bool noDepthTest; -}; - -struct OverlaySweptBox_t : public OverlayBase_t -{ - OverlaySweptBox_t() - { - m_Type = OVERLAY_SWEPT_BOX; - } - - Vector3 start; - Vector3 end; - Vector3 mins; - Vector3 maxs; - QAngle angles; - int r; - int g; - int b; - int a; -}; - -struct OverlaySphere_t : public OverlayBase_t -{ - OverlaySphere_t() - { - m_Type = OVERLAY_SPHERE; - } - - Vector3 vOrigin; - float flRadius; - int nTheta; - int nPhi; - int r; - int g; - int b; - int a; - bool m_bWireframe; -}; - -typedef bool (*OverlayBase_t__IsDeadType)(OverlayBase_t* a1); -static OverlayBase_t__IsDeadType OverlayBase_t__IsDead; -typedef void (*OverlayBase_t__DestroyOverlayType)(OverlayBase_t* a1); -static OverlayBase_t__DestroyOverlayType OverlayBase_t__DestroyOverlay; - -static ConVar* Cvar_enable_debug_overlays; - -LPCRITICAL_SECTION s_OverlayMutex; - -// Render Line -typedef void (*RenderLineType)(const Vector3& v1, const Vector3& v2, Color c, bool bZBuffer); -static RenderLineType RenderLine; - -// Render box -typedef void (*RenderBoxType)( - const Vector3& vOrigin, const QAngle& angles, const Vector3& vMins, const Vector3& vMaxs, Color c, bool bZBuffer, bool bInsideOut); -static RenderBoxType RenderBox; - -// Render wireframe box -static RenderBoxType RenderWireframeBox; - -// Render swept box -typedef void (*RenderWireframeSweptBoxType)( - const Vector3& vStart, const Vector3& vEnd, const QAngle& angles, const Vector3& vMins, const Vector3& vMaxs, Color c, bool bZBuffer); -RenderWireframeSweptBoxType RenderWireframeSweptBox; - -// Render Triangle -typedef void (*RenderTriangleType)(const Vector3& p1, const Vector3& p2, const Vector3& p3, Color c, bool bZBuffer); -static RenderTriangleType RenderTriangle; - -// Render Axis -typedef void (*RenderAxisType)(const Vector3& vOrigin, float flScale, bool bZBuffer); -static RenderAxisType RenderAxis; - -// I dont know -typedef void (*RenderUnknownType)(const Vector3& vUnk, float flUnk, bool bUnk); -static RenderUnknownType RenderUnknown; - -// Render Sphere -typedef void (*RenderSphereType)(const Vector3& vCenter, float flRadius, int nTheta, int nPhi, Color c, bool bZBuffer); -static RenderSphereType RenderSphere; - -OverlayBase_t** s_pOverlays; - -int* g_nRenderTickCount; -int* g_nOverlayTickCount; - -// clang-format off -AUTOHOOK(DrawOverlay, engine.dll + 0xABCB0, -void, __fastcall, (OverlayBase_t * pOverlay)) -// clang-format on -{ - EnterCriticalSection(s_OverlayMutex); - - switch (pOverlay->m_Type) - { - case OVERLAY_SMARTAMMO: - case OVERLAY_LINE: - { - OverlayLine_t* pLine = static_cast<OverlayLine_t*>(pOverlay); - RenderLine(pLine->origin, pLine->dest, Color(pLine->r, pLine->g, pLine->b, pLine->a), pLine->noDepthTest); - } - break; - case OVERLAY_BOX: - { - OverlayBox_t* pCurrBox = static_cast<OverlayBox_t*>(pOverlay); - if (pCurrBox->a > 0) - { - RenderBox( - pCurrBox->origin, - pCurrBox->angles, - pCurrBox->mins, - pCurrBox->maxs, - Color(pCurrBox->r, pCurrBox->g, pCurrBox->b, pCurrBox->a), - false, - false); - } - if (pCurrBox->a < 255) - { - RenderWireframeBox( - pCurrBox->origin, - pCurrBox->angles, - pCurrBox->mins, - pCurrBox->maxs, - Color(pCurrBox->r, pCurrBox->g, pCurrBox->b, 255), - false, - false); - } - } - break; - case OVERLAY_TRIANGLE: - { - OverlayTriangle_t* pTriangle = static_cast<OverlayTriangle_t*>(pOverlay); - RenderTriangle( - pTriangle->p1, - pTriangle->p2, - pTriangle->p3, - Color(pTriangle->r, pTriangle->g, pTriangle->b, pTriangle->a), - pTriangle->noDepthTest); - } - break; - case OVERLAY_SWEPT_BOX: - { - OverlaySweptBox_t* pBox = static_cast<OverlaySweptBox_t*>(pOverlay); - RenderWireframeSweptBox( - pBox->start, pBox->end, pBox->angles, pBox->mins, pBox->maxs, Color(pBox->r, pBox->g, pBox->b, pBox->a), false); - } - break; - case OVERLAY_SPHERE: - { - OverlaySphere_t* pSphere = static_cast<OverlaySphere_t*>(pOverlay); - RenderSphere( - pSphere->vOrigin, - pSphere->flRadius, - pSphere->nTheta, - pSphere->nPhi, - Color(pSphere->r, pSphere->g, pSphere->b, pSphere->a), - false); - } - break; - default: - { - spdlog::warn("Unimplemented overlay type {}", pOverlay->m_Type); - } - break; - } - - LeaveCriticalSection(s_OverlayMutex); -} - -// clang-format off -AUTOHOOK(DrawAllOverlays, engine.dll + 0xAB780, -void, __fastcall, (bool bRender)) -// clang-format on -{ - EnterCriticalSection(s_OverlayMutex); - - OverlayBase_t* pCurrOverlay = *s_pOverlays; // rbx - OverlayBase_t* pPrevOverlay = nullptr; // rsi - OverlayBase_t* pNextOverlay = nullptr; // rdi - - int m_nCreationTick; // eax - bool bShouldDraw; // zf - int m_pUnk; // eax - - while (pCurrOverlay) - { - if (OverlayBase_t__IsDead(pCurrOverlay)) - { - if (pPrevOverlay) - { - pPrevOverlay->m_pNextOverlay = pCurrOverlay->m_pNextOverlay; - } - else - { - *s_pOverlays = pCurrOverlay->m_pNextOverlay; - } - - pNextOverlay = pCurrOverlay->m_pNextOverlay; - OverlayBase_t__DestroyOverlay(pCurrOverlay); - pCurrOverlay = pNextOverlay; - } - else - { - if (pCurrOverlay->m_nCreationTick == -1) - { - m_pUnk = pCurrOverlay->m_pUnk; - - if (m_pUnk == -1) - { - bShouldDraw = true; - } - else - { - bShouldDraw = m_pUnk == *g_nOverlayTickCount; - } - } - else - { - bShouldDraw = pCurrOverlay->m_nCreationTick == *g_nRenderTickCount; - } - - if (bShouldDraw && bRender && (Cvar_enable_debug_overlays->GetBool() || pCurrOverlay->m_Type == OVERLAY_SMARTAMMO)) - { - DrawOverlay(pCurrOverlay); - } - - pPrevOverlay = pCurrOverlay; - pCurrOverlay = pCurrOverlay->m_pNextOverlay; - } - } - - LeaveCriticalSection(s_OverlayMutex); -} - -ON_DLL_LOAD_CLIENT_RELIESON("engine.dll", DebugOverlay, ConVar, (CModule module)) -{ - AUTOHOOK_DISPATCH() - - OverlayBase_t__IsDead = module.Offset(0xACAC0).RCast<OverlayBase_t__IsDeadType>(); - OverlayBase_t__DestroyOverlay = module.Offset(0xAB680).RCast<OverlayBase_t__DestroyOverlayType>(); - - RenderLine = module.Offset(0x192A70).RCast<RenderLineType>(); - RenderBox = module.Offset(0x192520).RCast<RenderBoxType>(); - RenderWireframeBox = module.Offset(0x193DA0).RCast<RenderBoxType>(); - RenderWireframeSweptBox = module.Offset(0x1945A0).RCast<RenderWireframeSweptBoxType>(); - RenderTriangle = module.Offset(0x193940).RCast<RenderTriangleType>(); - RenderAxis = module.Offset(0x1924D0).RCast<RenderAxisType>(); - RenderSphere = module.Offset(0x194170).RCast<RenderSphereType>(); - RenderUnknown = module.Offset(0x1924E0).RCast<RenderUnknownType>(); - - s_OverlayMutex = module.Offset(0x10DB0A38).RCast<LPCRITICAL_SECTION>(); - - s_pOverlays = module.Offset(0x10DB0968).RCast<OverlayBase_t**>(); - - g_nRenderTickCount = module.Offset(0x10DB0984).RCast<int*>(); - g_nOverlayTickCount = module.Offset(0x10DB0980).RCast<int*>(); - - // not in g_pCVar->FindVar by this point for whatever reason, so have to get from memory - Cvar_enable_debug_overlays = module.Offset(0x10DB0990).RCast<ConVar*>(); - Cvar_enable_debug_overlays->SetValue(false); - Cvar_enable_debug_overlays->m_pszDefaultValue = (char*)"0"; - Cvar_enable_debug_overlays->AddFlags(FCVAR_CHEAT); -} diff --git a/NorthstarDLL/client/demofixes.cpp b/NorthstarDLL/client/demofixes.cpp deleted file mode 100644 index 344764ba..00000000 --- a/NorthstarDLL/client/demofixes.cpp +++ /dev/null @@ -1,25 +0,0 @@ -#include "core/convar/convar.h" - -ON_DLL_LOAD_CLIENT("engine.dll", EngineDemoFixes, (CModule module)) -{ - // allow demo recording on loopback - module.Offset(0x8E1B1).NOP(2); - module.Offset(0x56CC3).NOP(2); -} - -ON_DLL_LOAD_CLIENT_RELIESON("client.dll", ClientDemoFixes, ConVar, (CModule module)) -{ - // change default values of demo cvars to enable them by default, but not autorecord - // this is before Host_Init, the setvalue calls here will get overwritten by custom cfgs/launch options - ConVar* Cvar_demo_enableDemos = g_pCVar->FindVar("demo_enabledemos"); - Cvar_demo_enableDemos->m_pszDefaultValue = "1"; - Cvar_demo_enableDemos->SetValue(true); - - ConVar* Cvar_demo_writeLocalFile = g_pCVar->FindVar("demo_writeLocalFile"); - Cvar_demo_writeLocalFile->m_pszDefaultValue = "1"; - Cvar_demo_writeLocalFile->SetValue(true); - - ConVar* Cvar_demo_autoRecord = g_pCVar->FindVar("demo_autoRecord"); - Cvar_demo_autoRecord->m_pszDefaultValue = "0"; - Cvar_demo_autoRecord->SetValue(false); -} diff --git a/NorthstarDLL/client/diskvmtfixes.cpp b/NorthstarDLL/client/diskvmtfixes.cpp deleted file mode 100644 index 4ab951c0..00000000 --- a/NorthstarDLL/client/diskvmtfixes.cpp +++ /dev/null @@ -1,15 +0,0 @@ - -ON_DLL_LOAD_CLIENT("materialsystem_dx11.dll", DiskVMTFixes, (CModule module)) -{ - // in retail VMTs will never load if cache read is invalid due to a special case for them in KeyValues::LoadFromFile - // this effectively makes it impossible to load them from mods because we invalidate cache for doing this - // so uhh, stop that from happening - - // tbh idk why they even changed any of this what's the point it looks like it works fine who cares my god - - // matsystem KeyValues::LoadFromFile: patch special case on cache read failure for vmts - module.Offset(0x1281B9).Patch("EB"); - - // CMaterialSystem::FindMaterial: don't call function that crashes if previous patch is applied - module.Offset(0x5F55A).NOP(5); -} diff --git a/NorthstarDLL/client/languagehooks.cpp b/NorthstarDLL/client/languagehooks.cpp deleted file mode 100644 index 35ca5659..00000000 --- a/NorthstarDLL/client/languagehooks.cpp +++ /dev/null @@ -1,115 +0,0 @@ -#include "core/tier0.h" - -#include <filesystem> -#include <regex> - -AUTOHOOK_INIT() - -typedef LANGID (*Tier0_DetectDefaultLanguageType)(); - -bool CheckLangAudioExists(char* lang) -{ - std::string path {"r2\\sound\\general_"}; - path += lang; - path += ".mstr"; - return fs::exists(path); -} - -std::vector<std::string> file_list(fs::path dir, std::regex ext_pattern) -{ - std::vector<std::string> result; - - if (!fs::exists(dir) || !fs::is_directory(dir)) - return result; - - using iterator = fs::directory_iterator; - - const iterator end; - for (iterator iter {dir}; iter != end; ++iter) - { - const std::string filename = iter->path().filename().string(); - std::smatch matches; - if (fs::is_regular_file(*iter) && std::regex_match(filename, matches, ext_pattern)) - { - result.push_back(std::move(matches.str(1))); - } - } - - return result; -} - -std::string GetAnyInstalledAudioLanguage() -{ - for (const auto& lang : file_list("r2\\sound\\", std::regex(".*?general_([a-z]+)_patch_1\\.mstr"))) - if (lang != "general" || lang != "") - return lang; - return "NO LANGUAGE DETECTED"; -} - -// clang-format off -AUTOHOOK(GetGameLanguage, tier0.dll + 0xF560, -char*, __fastcall, ()) -// clang-format on -{ - auto tier0Handle = GetModuleHandleA("tier0.dll"); - auto Tier0_DetectDefaultLanguageType = GetProcAddress(tier0Handle, "Tier0_DetectDefaultLanguage"); - char* ingameLang1 = (char*)tier0Handle + 0xA9B60; // one of the globals we need to override if overriding lang (size: 256) - bool& canOriginDictateLang = *(bool*)((char*)tier0Handle + 0xA9A90); - - const char* forcedLanguage; - if (CommandLine()->CheckParm("-language", &forcedLanguage)) - { - if (!CheckLangAudioExists((char*)forcedLanguage)) - { - spdlog::info( - "User tried to force the language (-language) to \"{}\", but audio for this language doesn't exist and the game is bound " - "to error, falling back to next option...", - forcedLanguage); - } - else - { - spdlog::info("User forcing the language (-language) to: {}", forcedLanguage); - strncpy(ingameLang1, forcedLanguage, 256); - return ingameLang1; - } - } - - canOriginDictateLang = true; // let it try - { - auto lang = GetGameLanguage(); - if (!CheckLangAudioExists(lang)) - { - if (strcmp(lang, "russian") != - 0) // don't log for "russian" since it's the default and that means Origin detection just didn't change it most likely - spdlog::info( - "Origin detected language \"{}\", but we do not have audio for it installed, falling back to the next option", lang); - } - else - { - spdlog::info("Origin detected language: {}", lang); - return lang; - } - } - - Tier0_DetectDefaultLanguageType(); // force the global in tier0 to be populated with language inferred from user's system rather than - // defaulting to Russian - canOriginDictateLang = false; // Origin has no say anymore, we will fallback to user's system setup language - auto lang = GetGameLanguage(); - spdlog::info("Detected system language: {}", lang); - if (!CheckLangAudioExists(lang)) - { - spdlog::warn("Caution, audio for this language does NOT exist. You might want to override your game language with -language " - "command line option."); - auto lang = GetAnyInstalledAudioLanguage(); - spdlog::warn("Falling back to the first installed audio language: {}", lang.c_str()); - strncpy(ingameLang1, lang.c_str(), 256); - return ingameLang1; - } - - return lang; -} - -ON_DLL_LOAD_CLIENT("tier0.dll", LanguageHooks, (CModule module)) -{ - AUTOHOOK_DISPATCH() -} diff --git a/NorthstarDLL/client/latencyflex.cpp b/NorthstarDLL/client/latencyflex.cpp deleted file mode 100644 index 25e38c7a..00000000 --- a/NorthstarDLL/client/latencyflex.cpp +++ /dev/null @@ -1,43 +0,0 @@ -#include "core/convar/convar.h" - -AUTOHOOK_INIT() - -ConVar* Cvar_r_latencyflex; - -void (*m_winelfx_WaitAndBeginFrame)(); - -// clang-format off -AUTOHOOK(OnRenderStart, client.dll + 0x1952C0, -void, __fastcall, ()) -// clang-format on -{ - if (Cvar_r_latencyflex->GetBool() && m_winelfx_WaitAndBeginFrame) - m_winelfx_WaitAndBeginFrame(); - - OnRenderStart(); -} - -ON_DLL_LOAD_CLIENT_RELIESON("client.dll", LatencyFlex, ConVar, (CModule module)) -{ - // Connect to the LatencyFleX service - // LatencyFleX is an open source vendor agnostic replacement for Nvidia Reflex input latency reduction technology. - // https://ishitatsuyuki.github.io/post/latencyflex/ - HMODULE pLfxModule; - - if (pLfxModule = LoadLibraryA("latencyflex_layer.dll")) - m_winelfx_WaitAndBeginFrame = - reinterpret_cast<void (*)()>(reinterpret_cast<void*>(GetProcAddress(pLfxModule, "lfx_WaitAndBeginFrame"))); - else if (pLfxModule = LoadLibraryA("latencyflex_wine.dll")) - m_winelfx_WaitAndBeginFrame = - reinterpret_cast<void (*)()>(reinterpret_cast<void*>(GetProcAddress(pLfxModule, "winelfx_WaitAndBeginFrame"))); - else - { - spdlog::info("Unable to load LatencyFleX library, LatencyFleX disabled."); - return; - } - - AUTOHOOK_DISPATCH() - - spdlog::info("LatencyFleX initialized."); - Cvar_r_latencyflex = new ConVar("r_latencyflex", "1", FCVAR_ARCHIVE, "Whether or not to use LatencyFleX input latency reduction."); -} diff --git a/NorthstarDLL/client/localchatwriter.cpp b/NorthstarDLL/client/localchatwriter.cpp deleted file mode 100644 index 35cc065f..00000000 --- a/NorthstarDLL/client/localchatwriter.cpp +++ /dev/null @@ -1,449 +0,0 @@ -#include "localchatwriter.h" - -class vgui_BaseRichText_vtable; - -class vgui_BaseRichText -{ -public: - vgui_BaseRichText_vtable* vtable; -}; - -class vgui_BaseRichText_vtable -{ -public: - char unknown1[1880]; - - void(__fastcall* InsertChar)(vgui_BaseRichText* self, wchar_t ch); - - // yes these are swapped from the Source 2013 code, who knows why - void(__fastcall* InsertStringWide)(vgui_BaseRichText* self, const wchar_t* wszText); - void(__fastcall* InsertStringAnsi)(vgui_BaseRichText* self, const char* text); - - void(__fastcall* SelectNone)(vgui_BaseRichText* self); - void(__fastcall* SelectAllText)(vgui_BaseRichText* self); - void(__fastcall* SelectNoText)(vgui_BaseRichText* self); - void(__fastcall* CutSelected)(vgui_BaseRichText* self); - void(__fastcall* CopySelected)(vgui_BaseRichText* self); - void(__fastcall* SetPanelInteractive)(vgui_BaseRichText* self, bool bInteractive); - void(__fastcall* SetUnusedScrollbarInvisible)(vgui_BaseRichText* self, bool bInvis); - - void* unknown2; - - void(__fastcall* GotoTextStart)(vgui_BaseRichText* self); - void(__fastcall* GotoTextEnd)(vgui_BaseRichText* self); - - void* unknown3[3]; - - void(__fastcall* SetVerticalScrollbar)(vgui_BaseRichText* self, bool state); - void(__fastcall* SetMaximumCharCount)(vgui_BaseRichText* self, int maxChars); - void(__fastcall* InsertColorChange)(vgui_BaseRichText* self, Color col); - void(__fastcall* InsertIndentChange)(vgui_BaseRichText* self, int pixelsIndent); - void(__fastcall* InsertClickableTextStart)(vgui_BaseRichText* self, const char* pchClickAction); - void(__fastcall* InsertClickableTextEnd)(vgui_BaseRichText* self); - void(__fastcall* InsertPossibleURLString)(vgui_BaseRichText* self, const char* text, Color URLTextColor, Color normalTextColor); - void(__fastcall* InsertFade)(vgui_BaseRichText* self, float flSustain, float flLength); - void(__fastcall* ResetAllFades)(vgui_BaseRichText* self, bool bHold, bool bOnlyExpired, float flNewSustain); - void(__fastcall* SetToFullHeight)(vgui_BaseRichText* self); - int(__fastcall* GetNumLines)(vgui_BaseRichText* self); -}; - -class CGameSettings -{ -public: - char unknown1[92]; - int isChatEnabled; -}; - -// Not sure what this actually refers to but chatFadeLength and chatFadeSustain -// have their value at the same offset -class CGameFloatVar -{ -public: - char unknown1[88]; - float value; -}; - -CGameSettings** gGameSettings; -CGameFloatVar** gChatFadeLength; -CGameFloatVar** gChatFadeSustain; - -CHudChat** CHudChat::allHuds; - -typedef void(__fastcall* ConvertANSIToUnicodeType)(LPCSTR ansi, int ansiCharLength, LPWSTR unicode, int unicodeCharLength); -ConvertANSIToUnicodeType ConvertANSIToUnicode; - -LocalChatWriter::SwatchColor swatchColors[4] = { - LocalChatWriter::MainTextColor, - LocalChatWriter::SameTeamNameColor, - LocalChatWriter::EnemyTeamNameColor, - LocalChatWriter::NetworkNameColor, -}; - -Color darkColors[8] = { - Color {0, 0, 0, 255}, - Color {205, 49, 49, 255}, - Color {13, 188, 121, 255}, - Color {229, 229, 16, 255}, - Color {36, 114, 200, 255}, - Color {188, 63, 188, 255}, - Color {17, 168, 205, 255}, - Color {229, 229, 229, 255}}; - -Color lightColors[8] = { - Color {102, 102, 102, 255}, - Color {241, 76, 76, 255}, - Color {35, 209, 139, 255}, - Color {245, 245, 67, 255}, - Color {59, 142, 234, 255}, - Color {214, 112, 214, 255}, - Color {41, 184, 219, 255}, - Color {255, 255, 255, 255}}; - -class AnsiEscapeParser -{ -public: - explicit AnsiEscapeParser(LocalChatWriter* writer) : m_writer(writer) {} - - void HandleVal(unsigned long val) - { - switch (m_next) - { - case Next::ControlType: - m_next = HandleControlType(val); - break; - case Next::ForegroundType: - m_next = HandleForegroundType(val); - break; - case Next::Foreground8Bit: - m_next = HandleForeground8Bit(val); - break; - case Next::ForegroundR: - m_next = HandleForegroundR(val); - break; - case Next::ForegroundG: - m_next = HandleForegroundG(val); - break; - case Next::ForegroundB: - m_next = HandleForegroundB(val); - break; - } - } - -private: - enum class Next - { - ControlType, - ForegroundType, - Foreground8Bit, - ForegroundR, - ForegroundG, - ForegroundB - }; - - LocalChatWriter* m_writer; - Next m_next = Next::ControlType; - Color m_expandedColor {0, 0, 0, 0}; - - Next HandleControlType(unsigned long val) - { - // Reset - if (val == 0 || val == 39) - { - m_writer->InsertSwatchColorChange(LocalChatWriter::MainTextColor); - return Next::ControlType; - } - - // Dark foreground color - if (val >= 30 && val < 38) - { - m_writer->InsertColorChange(darkColors[val - 30]); - return Next::ControlType; - } - - // Light foreground color - if (val >= 90 && val < 98) - { - m_writer->InsertColorChange(lightColors[val - 90]); - return Next::ControlType; - } - - // Game swatch color - if (val >= 110 && val < 114) - { - m_writer->InsertSwatchColorChange(swatchColors[val - 110]); - return Next::ControlType; - } - - // Expanded foreground color - if (val == 38) - { - return Next::ForegroundType; - } - - return Next::ControlType; - } - - Next HandleForegroundType(unsigned long val) - { - // Next values are r,g,b - if (val == 2) - { - m_expandedColor.SetColor(0, 0, 0, 255); - return Next::ForegroundR; - } - // Next value is 8-bit swatch color - if (val == 5) - { - return Next::Foreground8Bit; - } - - // Invalid - return Next::ControlType; - } - - Next HandleForeground8Bit(unsigned long val) - { - if (val < 8) - { - m_writer->InsertColorChange(darkColors[val]); - } - else if (val < 16) - { - m_writer->InsertColorChange(lightColors[val - 8]); - } - else if (val < 232) - { - unsigned char code = val - 16; - unsigned char blue = code % 6; - unsigned char green = ((code - blue) / 6) % 6; - unsigned char red = (code - blue - (green * 6)) / 36; - m_writer->InsertColorChange(Color {(unsigned char)(red * 51), (unsigned char)(green * 51), (unsigned char)(blue * 51), 255}); - } - else if (val < UCHAR_MAX) - { - unsigned char brightness = (val - 232) * 10 + 8; - m_writer->InsertColorChange(Color {brightness, brightness, brightness, 255}); - } - - return Next::ControlType; - } - - Next HandleForegroundR(unsigned long val) - { - if (val >= UCHAR_MAX) - return Next::ControlType; - - m_expandedColor[0] = (unsigned char)val; - return Next::ForegroundG; - } - - Next HandleForegroundG(unsigned long val) - { - if (val >= UCHAR_MAX) - return Next::ControlType; - - m_expandedColor[1] = (unsigned char)val; - return Next::ForegroundB; - } - - Next HandleForegroundB(unsigned long val) - { - if (val >= UCHAR_MAX) - return Next::ControlType; - - m_expandedColor[2] = (unsigned char)val; - m_writer->InsertColorChange(m_expandedColor); - return Next::ControlType; - } -}; - -LocalChatWriter::LocalChatWriter(Context context) : m_context(context) {} - -void LocalChatWriter::Write(const char* str) -{ - char writeBuffer[256]; - - while (true) - { - const char* startOfEscape = strstr(str, "\033["); - - if (startOfEscape == NULL) - { - // No more escape sequences, write the remaining text and exit - InsertText(str); - break; - } - - if (startOfEscape != str) - { - // There is some text before the escape sequence, just print that - size_t copyChars = startOfEscape - str; - if (copyChars > 255) - copyChars = 255; - - strncpy_s(writeBuffer, copyChars + 1, str, copyChars); - - InsertText(writeBuffer); - } - - const char* escape = startOfEscape + 2; - str = ApplyAnsiEscape(escape); - } -} - -void LocalChatWriter::WriteLine(const char* str) -{ - InsertChar(L'\n'); - InsertSwatchColorChange(MainTextColor); - Write(str); -} - -void LocalChatWriter::InsertChar(wchar_t ch) -{ - for (CHudChat* hud = *CHudChat::allHuds; hud != NULL; hud = hud->next) - { - if (hud->m_unknownContext != (int)m_context) - continue; - - hud->m_richText->vtable->InsertChar(hud->m_richText, ch); - } - - if (ch != L'\n') - { - InsertDefaultFade(); - } -} - -void LocalChatWriter::InsertText(const char* str) -{ - spdlog::info(str); - - WCHAR messageUnicode[288]; - ConvertANSIToUnicode(str, -1, messageUnicode, 274); - - for (CHudChat* hud = *CHudChat::allHuds; hud != NULL; hud = hud->next) - { - if (hud->m_unknownContext != (int)m_context) - continue; - - hud->m_richText->vtable->InsertStringWide(hud->m_richText, messageUnicode); - } - - InsertDefaultFade(); -} - -void LocalChatWriter::InsertText(const wchar_t* str) -{ - for (CHudChat* hud = *CHudChat::allHuds; hud != NULL; hud = hud->next) - { - if (hud->m_unknownContext != (int)m_context) - continue; - - hud->m_richText->vtable->InsertStringWide(hud->m_richText, str); - } - - InsertDefaultFade(); -} - -void LocalChatWriter::InsertColorChange(Color color) -{ - for (CHudChat* hud = *CHudChat::allHuds; hud != NULL; hud = hud->next) - { - if (hud->m_unknownContext != (int)m_context) - continue; - - hud->m_richText->vtable->InsertColorChange(hud->m_richText, color); - } -} - -static Color GetHudSwatchColor(CHudChat* hud, LocalChatWriter::SwatchColor swatchColor) -{ - switch (swatchColor) - { - case LocalChatWriter::MainTextColor: - return hud->m_mainTextColor; - - case LocalChatWriter::SameTeamNameColor: - return hud->m_sameTeamColor; - - case LocalChatWriter::EnemyTeamNameColor: - return hud->m_enemyTeamColor; - - case LocalChatWriter::NetworkNameColor: - return hud->m_networkNameColor; - } - - return Color(0, 0, 0, 0); -} - -void LocalChatWriter::InsertSwatchColorChange(SwatchColor swatchColor) -{ - for (CHudChat* hud = *CHudChat::allHuds; hud != NULL; hud = hud->next) - { - if (hud->m_unknownContext != (int)m_context) - continue; - hud->m_richText->vtable->InsertColorChange(hud->m_richText, GetHudSwatchColor(hud, swatchColor)); - } -} - -const char* LocalChatWriter::ApplyAnsiEscape(const char* escape) -{ - AnsiEscapeParser decoder(this); - while (true) - { - char* afterControlType = NULL; - unsigned long controlType = strtoul(escape, &afterControlType, 10); - - // Malformed cases: - // afterControlType = NULL: strtoul errored - // controlType = 0 and escape doesn't actually start with 0: wasn't a number - if (afterControlType == NULL || (controlType == 0 && escape[0] != '0')) - { - return escape; - } - - decoder.HandleVal(controlType); - - // m indicates the end of the sequence - if (afterControlType[0] == 'm') - { - return afterControlType + 1; - } - - // : or ; indicates more values remain, anything else is malformed - if (afterControlType[0] != ':' && afterControlType[0] != ';') - { - return afterControlType; - } - - escape = afterControlType + 1; - } -} - -void LocalChatWriter::InsertDefaultFade() -{ - float fadeLength = 0.f; - float fadeSustain = 0.f; - if ((*gGameSettings)->isChatEnabled) - { - fadeLength = (*gChatFadeLength)->value; - fadeSustain = (*gChatFadeSustain)->value; - } - - for (CHudChat* hud = *CHudChat::allHuds; hud != NULL; hud = hud->next) - { - if (hud->m_unknownContext != (int)m_context) - continue; - hud->m_richText->vtable->InsertFade(hud->m_richText, fadeSustain, fadeLength); - } -} - -ON_DLL_LOAD_CLIENT("client.dll", LocalChatWriter, (CModule module)) -{ - gGameSettings = module.Offset(0x11BAA48).RCast<CGameSettings**>(); - gChatFadeLength = module.Offset(0x11BAB78).RCast<CGameFloatVar**>(); - gChatFadeSustain = module.Offset(0x11BAC08).RCast<CGameFloatVar**>(); - CHudChat::allHuds = module.Offset(0x11BA9E8).RCast<CHudChat**>(); - - ConvertANSIToUnicode = module.Offset(0x7339A0).RCast<ConvertANSIToUnicodeType>(); -} diff --git a/NorthstarDLL/client/localchatwriter.h b/NorthstarDLL/client/localchatwriter.h deleted file mode 100644 index acf6f87e..00000000 --- a/NorthstarDLL/client/localchatwriter.h +++ /dev/null @@ -1,64 +0,0 @@ -#pragma once -#include "core/math/color.h" - -class vgui_BaseRichText; - -class CHudChat -{ -public: - static CHudChat** allHuds; - - char unknown1[720]; - - Color m_sameTeamColor; - Color m_enemyTeamColor; - Color m_mainTextColor; - Color m_networkNameColor; - - char unknown2[12]; - - int m_unknownContext; - - char unknown3[8]; - - vgui_BaseRichText* m_richText; - - CHudChat* next; - CHudChat* previous; -}; - -class LocalChatWriter -{ -public: - enum Context - { - NetworkContext = 0, - GameContext = 1 - }; - enum SwatchColor - { - MainTextColor, - SameTeamNameColor, - EnemyTeamNameColor, - NetworkNameColor - }; - - explicit LocalChatWriter(Context context); - - // Custom chat writing with ANSI escape codes - void Write(const char* str); - void WriteLine(const char* str); - - // Low-level RichText access - void InsertChar(wchar_t ch); - void InsertText(const char* str); - void InsertText(const wchar_t* str); - void InsertColorChange(Color color); - void InsertSwatchColorChange(SwatchColor color); - -private: - Context m_context; - - const char* ApplyAnsiEscape(const char* escape); - void InsertDefaultFade(); -}; diff --git a/NorthstarDLL/client/modlocalisation.cpp b/NorthstarDLL/client/modlocalisation.cpp deleted file mode 100644 index 2b73876b..00000000 --- a/NorthstarDLL/client/modlocalisation.cpp +++ /dev/null @@ -1,55 +0,0 @@ -#include "mods/modmanager.h" - -AUTOHOOK_INIT() - -void* g_pVguiLocalize; - -// clang-format off -AUTOHOOK(CLocalize__AddFile, localize.dll + 0x6D80, -bool, __fastcall, (void* pVguiLocalize, const char* path, const char* pathId, bool bIncludeFallbackSearchPaths)) -// clang-format on -{ - // save this for later - g_pVguiLocalize = pVguiLocalize; - - bool ret = CLocalize__AddFile(pVguiLocalize, path, pathId, bIncludeFallbackSearchPaths); - if (ret) - spdlog::info("Loaded localisation file {} successfully", path); - - return true; -} - -// clang-format off -AUTOHOOK(CLocalize__ReloadLocalizationFiles, localize.dll + 0xB830, -void, __fastcall, (void* pVguiLocalize)) -// clang-format on -{ - // load all mod localization manually, so we keep track of all files, not just previously loaded ones - for (Mod mod : g_pModManager->m_LoadedMods) - if (mod.m_bEnabled) - for (std::string& localisationFile : mod.LocalisationFiles) - CLocalize__AddFile(g_pVguiLocalize, localisationFile.c_str(), nullptr, false); - - spdlog::info("reloading localization..."); - CLocalize__ReloadLocalizationFiles(pVguiLocalize); -} - -// clang-format off -AUTOHOOK(CEngineVGui__Init, engine.dll + 0x247E10, -void, __fastcall, (void* self)) -// clang-format on -{ - CEngineVGui__Init(self); // this loads r1_english, valve_english, dev_english - - // previously we did this in CLocalize::AddFile, but for some reason it won't properly overwrite localization from - // files loaded previously if done there, very weird but this works so whatever - for (Mod mod : g_pModManager->m_LoadedMods) - if (mod.m_bEnabled) - for (std::string& localisationFile : mod.LocalisationFiles) - CLocalize__AddFile(g_pVguiLocalize, localisationFile.c_str(), nullptr, false); -} - -ON_DLL_LOAD_CLIENT("localize.dll", Localize, (CModule module)) -{ - AUTOHOOK_DISPATCH() -} diff --git a/NorthstarDLL/client/r2client.cpp b/NorthstarDLL/client/r2client.cpp deleted file mode 100644 index c8e59d74..00000000 --- a/NorthstarDLL/client/r2client.cpp +++ /dev/null @@ -1,13 +0,0 @@ -#include "r2client.h" - -char* g_pLocalPlayerUserID; -char* g_pLocalPlayerOriginToken; -GetBaseLocalClientType GetBaseLocalClient; - -ON_DLL_LOAD("engine.dll", R2EngineClient, (CModule module)) -{ - g_pLocalPlayerUserID = module.Offset(0x13F8E688).RCast<char*>(); - g_pLocalPlayerOriginToken = module.Offset(0x13979C80).RCast<char*>(); - - GetBaseLocalClient = module.Offset(0x78200).RCast<GetBaseLocalClientType>(); -} diff --git a/NorthstarDLL/client/r2client.h b/NorthstarDLL/client/r2client.h deleted file mode 100644 index ea263dbc..00000000 --- a/NorthstarDLL/client/r2client.h +++ /dev/null @@ -1,7 +0,0 @@ -#pragma once - -extern char* g_pLocalPlayerUserID; -extern char* g_pLocalPlayerOriginToken; - -typedef void* (*GetBaseLocalClientType)(); -extern GetBaseLocalClientType GetBaseLocalClient; diff --git a/NorthstarDLL/client/rejectconnectionfixes.cpp b/NorthstarDLL/client/rejectconnectionfixes.cpp deleted file mode 100644 index 1b326a3c..00000000 --- a/NorthstarDLL/client/rejectconnectionfixes.cpp +++ /dev/null @@ -1,34 +0,0 @@ -#include "engine/r2engine.h"
-
-AUTOHOOK_INIT()
-
-// this is called from when our connection is rejected, this is the only case we're hooking this for
-// clang-format off
-AUTOHOOK(COM_ExplainDisconnection, engine.dll + 0x1342F0,
-void,, (bool a1, const char* fmt, ...))
-// clang-format on
-{
- va_list va;
- va_start(va, fmt);
- char buf[4096];
- vsnprintf_s(buf, 4096, fmt, va);
- va_end(va);
-
- // slightly hacky comparison, but patching the function that calls this for reject would be worse
- if (!strncmp(fmt, "Connection rejected: ", 21))
- {
- // when COM_ExplainDisconnection is called from engine.dll + 19ff1c for connection rejected, it doesn't
- // call Host_Disconnect, which properly shuts down listen server
- // not doing this gets our client in a pretty weird state so we need to shut it down manually here
-
- // don't call Cbuf_Execute because we don't need this called immediately
- Cbuf_AddText(Cbuf_GetCurrentPlayer(), "disconnect", cmd_source_t::kCommandSrcCode);
- }
-
- return COM_ExplainDisconnection(a1, "%s", buf);
-}
-
-ON_DLL_LOAD_CLIENT("engine.dll", RejectConnectionFixes, (CModule module))
-{
- AUTOHOOK_DISPATCH()
-}
|