Merge branch 'feature/vs2017' into 'develop'

[Merge] feature/vs2017 -> develop
This commit is contained in:
momo5502 2017-06-22 10:45:29 +02:00
commit e75c662687
106 changed files with 796 additions and 814 deletions

2
.gitmodules vendored
View File

@ -21,7 +21,7 @@
[submodule "deps/mongoose"] [submodule "deps/mongoose"]
path = deps/mongoose path = deps/mongoose
url = https://github.com/cesanta/mongoose.git url = https://github.com/cesanta/mongoose.git
branch = master branch = dev
[submodule "deps/protobuf"] [submodule "deps/protobuf"]
path = deps/protobuf path = deps/protobuf
url = https://github.com/google/protobuf.git url = https://github.com/google/protobuf.git

View File

@ -8,6 +8,8 @@ The format is based on [Keep a Changelog v0.3.0](http://keepachangelog.com/en/0.
### Added ### Added
- Show friend avatars when they play IW4x (request)
- Cod4 style fast download for usermaps
- Display a toast when an update is available. - Display a toast when an update is available.
- Use the hourglass cursor while loading assets (with the native cursor feature). - Use the hourglass cursor while loading assets (with the native cursor feature).
- Show bots in parenthesis after the number of players in the serverlist (request). - Show bots in parenthesis after the number of players in the serverlist (request).
@ -18,6 +20,9 @@ The format is based on [Keep a Changelog v0.3.0](http://keepachangelog.com/en/0.
### Fixed ### Fixed
- Fix lags and frame drops caused by server sorting
- Fix demos on custom maps
- Can no longer join a lobby with an incorrect password
- Fix lags and frame drops caused by server sorting. - Fix lags and frame drops caused by server sorting.
- Fix demos on custom maps. - Fix demos on custom maps.

4
Jenkinsfile vendored
View File

@ -104,8 +104,8 @@ def doBuild(cfg) {
useShippedPremake { useShippedPremake {
def outputDir = pwd() def outputDir = pwd()
def msbuild = tool "Microsoft.NET MSBuild 14.0" def msbuild = tool "Microsoft.NET MSBuild 15.0"
bat "premake5 vs2015 ${cfg.PremakeArgs}" bat "premake5 vs2017 ${cfg.PremakeArgs}"
bat "\"${msbuild}\" build\\iw4x.sln \"/p:OutDir=$outputDir\\\\\" \"/p:Configuration=${cfg.MSBuildConfiguration}\"" bat "\"${msbuild}\" build\\iw4x.sln \"/p:OutDir=$outputDir\\\\\" \"/p:Configuration=${cfg.MSBuildConfiguration}\""
} }

View File

@ -15,7 +15,7 @@
## How to compile ## How to compile
- Run `premake5 vs2015` or use the delivered `generate.bat`. - Run `premake5 vs2017` or use the delivered `generate.bat`.
- Build via solution file in `build\iw4x.sln`. (You can use the `build.bat` script to do it quick and easy.) - Build via solution file in `build\iw4x.sln`. (You can use the `build.bat` script to do it quick and easy.)
## Premake arguments ## Premake arguments

View File

@ -2,16 +2,16 @@
cd %~dp0 cd %~dp0
if exist "%VS140COMNTOOLS%\vsvars32.bat" call "%VS140COMNTOOLS%\vsvars32.bat" if exist "%PROGRAMFILES(x86)%\Microsoft Visual Studio\2017\Enterprise\Common7\Tools\VsMSBuildCmd.bat" call "%PROGRAMFILES(x86)%\Microsoft Visual Studio\2017\Enterprise\Common7\Tools\VsMSBuildCmd.bat"
msbuild /version >NUL 2>NUL msbuild /version >NUL 2>NUL
if errorlevel 0 goto:build if errorlevel 0 goto:build
if exist "%PROGRAMFILES(x86)%\msbuild\14.0\Bin\msbuild.exe" path %PROGRAMFILES(x86)%\msbuild\14.0\Bin;%PATH% if exist "%PROGRAMFILES(x86)%\Microsoft Visual Studio\2017\Enterprise\MSBuild\15.0\Bin\msbuild.exe" path %PROGRAMFILES(x86)%\Microsoft Visual Studio\2017\Enterprise\MSBuild\15.0\Bin;%PATH%
msbuild /version >NUL 2>NUL msbuild /version >NUL 2>NUL
if errorlevel 0 goto:build if errorlevel 0 goto:build
echo Couldn't find any MSBuild to build this project. echo Couldn't find any MSBuild to build this project.
echo Make sure you have Visual C++ Build Tools 2015 or Visual Studio 2015 installed. echo Make sure you have Visual C++ Build Tools 2017 or Visual Studio 2017 installed.
endlocal endlocal
exit /B 1 exit /B 1

2
deps/json11 vendored

@ -1 +1 @@
Subproject commit ed35a09c043c376969dde9a3293824e1c11aa1f1 Subproject commit ec4e45219af1d7cde3d58b49ed762376fccf1ace

2
deps/libtomcrypt vendored

@ -1 +1 @@
Subproject commit bda493d770259300f48a79a5a8686c83c62b60e0 Subproject commit 6f852936723daa03157efdebfcf0bea711fa17e8

2
deps/mongoose vendored

@ -1 +1 @@
Subproject commit 7c0493071f182b890f4e01ece84ab2523858cc76 Subproject commit fb3a5a7d905978b5b1ce26ad3100294ee669dda1

2
deps/protobuf vendored

@ -1 +1 @@
Subproject commit c722c3d29440de4b33bed3e4d908cabe38a1196f Subproject commit 703cd8e11c8d34283d4c8bf869c61866e8211c9d

View File

@ -1,4 +1,4 @@
@echo off @echo off
echo Updating submodules... echo Updating submodules...
git submodule update --init --recursive git submodule update --init --recursive
tools\premake5 %* vs2015 tools\premake5 %* vs2017

View File

@ -1,83 +0,0 @@
boost = {
settings = nil,
}
function boost.setup(settings)
if not settings.source then error("Missing source.") end
boost.settings = settings
end
function boost.import()
if not boost.settings then error("Run boost.setup first") end
--links { "boost" }
boost.includes()
end
function boost.includes()
if not boost.settings then error("Run boost.setup first") end
submodules = {
"mpl",
"core",
"move",
"tuple",
"assert",
"predef",
"config",
"detail",
"winapi",
"integer",
"utility",
"iterator",
"container",
"unordered",
"date_time",
"smart_ptr",
"intrusive",
"functional",
"type_traits",
"interprocess",
"preprocessor",
"static_assert",
"throw_exception",
}
for i, submodule in ipairs(submodules) do
includedirs { path.join(boost.settings.source, string.format("%s/include", submodule)) }
end
includedirs { boost.settings.source }
end
function boost.project()
if not boost.settings then error("Run boost.setup first") end
--[[
project "boost"
language "C++"
includedirs
{
boost.settings.source,
}
files
{
path.join(boost.settings.source, "*.cpp"),
path.join(boost.settings.source, "*.hpp"),
}
removefiles
{
path.join(boost.settings.source, "test*"),
}
-- not our code, ignore POSIX usage warnings for now
warnings "Off"
defines { "_LIB" }
removedefines { "_USRDLL", "_DLL" }
kind "StaticLib"
]]
end

View File

@ -36,9 +36,6 @@ function libtommath.project()
path.join(libtommath.settings.source, "*.c"), path.join(libtommath.settings.source, "*.c"),
} }
-- dependencies
libtommath.import()
-- not our code, ignore POSIX usage warnings for now -- not our code, ignore POSIX usage warnings for now
warnings "Off" warnings "Off"

View File

@ -40,6 +40,5 @@ function udis86.project()
-- not our code, ignore POSIX usage warnings for now -- not our code, ignore POSIX usage warnings for now
warnings "Off" warnings "Off"
kind "SharedLib"
kind "StaticLib" kind "StaticLib"
end end

View File

@ -235,14 +235,12 @@ workspace "iw4x"
location "./build" location "./build"
objdir "%{wks.location}/obj" objdir "%{wks.location}/obj"
targetdir "%{wks.location}/bin/%{cfg.buildcfg}" targetdir "%{wks.location}/bin/%{cfg.buildcfg}"
buildlog "%{wks.location}/obj/%{cfg.architecture}/%{cfg.buildcfg}/%{prj.name}/%{prj.name}.log"
configurations { "Debug", "Release" } configurations { "Debug", "Release" }
architecture "x32" architecture "x32"
platforms "x86" platforms "x86"
exceptionhandling ("SEH") exceptionhandling ("SEH")
-- VS 2015 toolset only
toolset "msc-140"
flags { "StaticRuntime" } flags { "StaticRuntime" }
configuration "windows" configuration "windows"
@ -266,7 +264,6 @@ workspace "iw4x"
project "iw4x" project "iw4x"
kind "SharedLib" kind "SharedLib"
language "C++" language "C++"
flags { "C++14" }
files { files {
"./src/**.rc", "./src/**.rc",
"./src/**.hpp", "./src/**.hpp",
@ -376,7 +373,8 @@ workspace "iw4x"
end end
-- Specific configurations -- Specific configurations
flags { "UndefinedIdentifiers", "ExtraWarnings" } flags { "UndefinedIdentifiers" }
warnings "Extra"
if symbols ~= nil then if symbols ~= nil then
symbols "On" symbols "On"

View File

@ -61,7 +61,7 @@ namespace Components
Loader::Register(new Monitor()); Loader::Register(new Monitor());
Loader::Register(new Network()); Loader::Register(new Network());
Loader::Register(new Theatre()); Loader::Register(new Theatre());
//Loader::Register(new Clantags()); //Loader::Register(new ClanTags());
Loader::Register(new Download()); Loader::Register(new Download());
Loader::Register(new Playlist()); Loader::Register(new Playlist());
Loader::Register(new RawFiles()); Loader::Register(new RawFiles());
@ -93,7 +93,7 @@ namespace Components
Loader::Register(new ZoneBuilder()); Loader::Register(new ZoneBuilder());
Loader::Register(new AssetHandler()); Loader::Register(new AssetHandler());
Loader::Register(new Localization()); Loader::Register(new Localization());
Loader::Register(new MusicalTalent()); //Loader::Register(new MusicalTalent());
Loader::Register(new ServerCommands()); Loader::Register(new ServerCommands());
Loader::Register(new StructuredData()); Loader::Register(new StructuredData());
Loader::Register(new ConnectProtocol()); Loader::Register(new ConnectProtocol());

View File

@ -92,7 +92,7 @@ namespace Components
#include "Modules/Logger.hpp" #include "Modules/Logger.hpp"
#include "Modules/Friends.hpp" #include "Modules/Friends.hpp"
#include "Modules/IPCPipe.hpp" #include "Modules/IPCPipe.hpp"
#include "Modules/Clantags.hpp" #include "Modules/ClanTags.hpp"
#include "Modules/Download.hpp" #include "Modules/Download.hpp"
#include "Modules/Playlist.hpp" #include "Modules/Playlist.hpp"
#include "Modules/RawFiles.hpp" #include "Modules/RawFiles.hpp"

View File

@ -102,8 +102,8 @@ namespace Components
#ifdef DEBUG_LOAD_LIBRARY #ifdef DEBUG_LOAD_LIBRARY
AntiCheat::LoadLibHook[0].initialize(loadLibA, LoadLibaryAStub, HOOK_JUMP); AntiCheat::LoadLibHook[0].initialize(loadLibA, LoadLibaryAStub, HOOK_JUMP);
AntiCheat::LoadLibHook[1].initialize(loadLibW, LoadLibaryWStub, HOOK_JUMP); AntiCheat::LoadLibHook[1].initialize(loadLibW, LoadLibaryWStub, HOOK_JUMP);
AntiCheat::LoadLibHook[2].initialize(loadLibExA, LoadLibaryAStub, HOOK_JUMP); AntiCheat::LoadLibHook[2].initialize(loadLibExA, LoadLibaryExAStub, HOOK_JUMP);
AntiCheat::LoadLibHook[3].initialize(loadLibExW, LoadLibaryWStub, HOOK_JUMP); AntiCheat::LoadLibHook[3].initialize(loadLibExW, LoadLibaryExWStub, HOOK_JUMP);
#else #else
static uint8_t loadLibStub[] = { 0x33, 0xC0, 0xC2, 0x04, 0x00 }; // xor eax, eax; retn 04h static uint8_t loadLibStub[] = { 0x33, 0xC0, 0xC2, 0x04, 0x00 }; // xor eax, eax; retn 04h
static uint8_t loadLibExStub[] = { 0x33, 0xC0, 0xC2, 0x0C, 0x00 }; // xor eax, eax; retn 0Ch static uint8_t loadLibExStub[] = { 0x33, 0xC0, 0xC2, 0x0C, 0x00 }; // xor eax, eax; retn 0Ch
@ -119,7 +119,7 @@ namespace Components
static uint8_t ldrLoadDll[] = { 0xB3, 0x9B, 0x8D, 0xB3, 0x90, 0x9E, 0x9B, 0xBB, 0x93, 0x93 }; // LdrLoadDll static uint8_t ldrLoadDll[] = { 0xB3, 0x9B, 0x8D, 0xB3, 0x90, 0x9E, 0x9B, 0xBB, 0x93, 0x93 }; // LdrLoadDll
HMODULE ntdll = Utils::GetNTDLL(); HMODULE ntdll = Utils::GetNTDLL();
AntiCheat::LoadLibHook[4].initialize(GetProcAddress(ntdll, Utils::String::XOR(std::string(reinterpret_cast<char*>(ldrLoadDll), sizeof ldrLoadDll), -1).data()), ldrLoadDllStub, HOOK_JUMP); //AntiCheat::LoadLibHook[4].initialize(GetProcAddress(ntdll, Utils::String::XOR(std::string(reinterpret_cast<char*>(ldrLoadDll), sizeof ldrLoadDll), -1).data()), ldrLoadDllStub, HOOK_JUMP);
// Patch LdrpLoadDll // Patch LdrpLoadDll
Utils::Hook::Signature::Container container; Utils::Hook::Signature::Container container;
@ -133,7 +133,7 @@ namespace Components
Utils::Hook::Signature signature(ntdll, Utils::GetModuleSize(ntdll)); Utils::Hook::Signature signature(ntdll, Utils::GetModuleSize(ntdll));
signature.add(container); signature.add(container);
signature.process(); //signature.process();
} }
void AntiCheat::ReadIntegrityCheck() void AntiCheat::ReadIntegrityCheck()
@ -229,10 +229,10 @@ namespace Components
AntiCheat::Flags |= AntiCheat::IntergrityFlag::MEMORY_SCAN; AntiCheat::Flags |= AntiCheat::IntergrityFlag::MEMORY_SCAN;
} }
void AntiCheat::QuickCodeScanner_1() void AntiCheat::QuickCodeScanner1()
{ {
static Utils::Time::Interval interval; static Utils::Time::Interval interval;
static Utils::Value<std::string> hashVal; static std::optional<std::string> hashVal;
if (!interval.elapsed(11s)) return; if (!interval.elapsed(11s)) return;
interval.update(); interval.update();
@ -243,30 +243,30 @@ namespace Components
uint8_t* textBase = reinterpret_cast<uint8_t*>(0x400FFF); uint8_t* textBase = reinterpret_cast<uint8_t*>(0x400FFF);
std::string hash = Utils::Cryptography::SHA256::Compute(textBase + 1, textSize + 1, false); std::string hash = Utils::Cryptography::SHA256::Compute(textBase + 1, textSize + 1, false);
if (hashVal.isValid() && hash != hashVal.get()) if (hashVal.has_value() && hash != hashVal.value())
{ {
Utils::Hook::Set<BYTE>(0x42A667, 0x90); // Crash Utils::Hook::Set<BYTE>(0x42A667, 0x90); // Crash
} }
hashVal.set(hash); hashVal.emplace(hash);
} }
void AntiCheat::QuickCodeScanner_2() void AntiCheat::QuickCodeScanner2()
{ {
static Utils::Time::Interval interval; static Utils::Time::Interval interval;
static Utils::Value<std::string> hashVal; static std::optional<std::string> hashVal;
if (!interval.elapsed(12s)) return; if (!interval.elapsed(12s)) return;
interval.update(); interval.update();
// Hash .text segment // Hash .text segment
std::string hash = Utils::Cryptography::SHA1::Compute(reinterpret_cast<uint8_t*>(0x401000), 0x2D6000, false); std::string hash = Utils::Cryptography::SHA1::Compute(reinterpret_cast<uint8_t*>(0x401000), 0x2D6000, false);
if (hashVal.isValid() && hash != hashVal.get()) if (hashVal.has_value() && hash != hashVal.value())
{ {
Utils::Hook::Set<BYTE>(0x40797C, 0x90); // Crash Utils::Hook::Set<BYTE>(0x40797C, 0x90); // Crash
} }
hashVal.set(hash); hashVal.emplace(hash);
} }
#ifdef DEBUG_LOAD_LIBRARY #ifdef DEBUG_LOAD_LIBRARY

View File

@ -31,8 +31,8 @@ namespace Components
static void VerifyThreadIntegrity(); static void VerifyThreadIntegrity();
static void QuickCodeScanner_1(); static void QuickCodeScanner1();
static void QuickCodeScanner_2(); static void QuickCodeScanner2();
private: private:
enum IntergrityFlag enum IntergrityFlag

View File

@ -407,8 +407,57 @@ namespace Components
Utils::Hook::Call<void(int, const char*, const char*, const char*)>(0x4F8C70)(severity, format, type, name); // Print error Utils::Hook::Call<void(int, const char*, const char*, const char*)>(0x4F8C70)(severity, format, type, name); // Print error
} }
void AssetHandler::reallocateEntryPool()
{
AssertSize(Game::XAssetEntry, 16);
size_t size = (ZoneBuilder::IsEnabled() ? 1183968 : 789312);
Game::XAssetEntry* entryPool = Utils::Memory::GetAllocator()->allocateArray<Game::XAssetEntry>(size);
// Apply new size
Utils::Hook::Set<DWORD>(0x5BAEB0, size);
// Apply new pool
DWORD patches[] =
{
0x48E6F4,
0x4C67E4,
0x4C8584,
0x5BAEA8,
0x5BB0C4,
0x5BB0F5,
0x5BB1D4,
0x5BB235,
0x5BB278,
0x5BB34C,
0x5BB484,
0x5BB570,
0x5BB6B7,
0x5BB844,
0x5BB98D,
0x5BBA66,
0x5BBB8D,
0x5BBCB1,
0x5BBD9B,
0x5BBE4C,
0x5BBF14,
0x5BBF54,
0x5BBFB8
};
for (int i = 0; i < ARRAYSIZE(patches); ++i)
{
Utils::Hook::Set<Game::XAssetEntry*>(patches[i], entryPool);
}
Utils::Hook::Set<Game::XAssetEntry*>(0x5BAE91, entryPool + 1);
Utils::Hook::Set<Game::XAssetEntry*>(0x5BAEA2, entryPool + 1);
}
AssetHandler::AssetHandler() AssetHandler::AssetHandler()
{ {
this->reallocateEntryPool();
Dvar::Register<bool>("r_noVoid", false, Game::DVAR_FLAG_SAVED, "Disable void model (red fx)"); Dvar::Register<bool>("r_noVoid", false, Game::DVAR_FLAG_SAVED, "Disable void model (red fx)");
AssetHandler::ClearTemporaryAssets(); AssetHandler::ClearTemporaryAssets();
@ -450,9 +499,31 @@ namespace Components
} }
}); });
Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_GAMEWORLD_SP, 1);
Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_IMAGE, ZoneBuilder::IsEnabled() ? 14336 : 7168);
Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_LOADED_SOUND, 2700);
Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_FX, 1200);
Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_LOCALIZE_ENTRY, 14000);
Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_XANIMPARTS, 8192);
Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_XMODEL, 5125);
Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_PHYSPRESET, 128);
Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_PIXELSHADER, ZoneBuilder::IsEnabled() ? 0x4000 : 10000);
Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_VERTEXSHADER, ZoneBuilder::IsEnabled() ? 0x2000 : 3072);
Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_MATERIAL, 8192);
Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_VERTEXDECL, ZoneBuilder::IsEnabled() ? 0x400 : 196);
Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_WEAPON, WEAPON_LIMIT);
Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_STRINGTABLE, 800);
Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_IMPACT_FX, 8);
// Register asset interfaces // Register asset interfaces
if (ZoneBuilder::IsEnabled()) if (ZoneBuilder::IsEnabled())
{ {
Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_MAP_ENTS, 10);
Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_XMODELSURFS, 8192);
Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_TECHNIQUE_SET, 0x2000);
Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_FONT, 32);
Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_RAWFILE, 2048);
AssetHandler::RegisterInterface(new Assets::IFont_s()); AssetHandler::RegisterInterface(new Assets::IFont_s());
AssetHandler::RegisterInterface(new Assets::IXModel()); AssetHandler::RegisterInterface(new Assets::IXModel());
AssetHandler::RegisterInterface(new Assets::IFxWorld()); AssetHandler::RegisterInterface(new Assets::IFxWorld());

View File

@ -70,6 +70,8 @@ namespace Components
static void SetBypassState(bool value); static void SetBypassState(bool value);
static void MissingAssetError(int severity, const char* format, const char* type, const char* name); static void MissingAssetError(int severity, const char* format, const char* type, const char* name);
void reallocateEntryPool();
}; };
} }

View File

@ -255,7 +255,7 @@ namespace Assets
{ {
// TODO: Allow loading assets from raw! // TODO: Allow loading assets from raw!
if (Game::s_elemFields[i].handler(&session, element)) break; if (Game::s_elemFields[i].handler(&session, element)) break;
Components::Logger::Error("Failed to parse element %s!\n", newValue); Components::Logger::Error("Failed to parse element %s!\n", newValue.data());
} }
} }

View File

@ -57,7 +57,7 @@ namespace Components
UIFeeder::Add(62.0f, Changelog::GetChangelogCount, Changelog::GetChangelogText, Changelog::SelectChangelog); UIFeeder::Add(62.0f, Changelog::GetChangelogCount, Changelog::GetChangelogText, Changelog::SelectChangelog);
#if !defined(DEBUG) && !defined(DISABLE_ANTICHEAT) #if !defined(DEBUG) && !defined(DISABLE_ANTICHEAT)
Scheduler::OnFrame(AntiCheat::QuickCodeScanner_1); Scheduler::OnFrame(AntiCheat::QuickCodeScanner1);
#endif #endif
} }

View File

@ -2,20 +2,20 @@
namespace Components namespace Components
{ {
std::string Clantags::Tags[18]; std::string ClanTags::Tags[18];
void Clantags::ParseClantags(const char* infoString) void ClanTags::ParseClantags(const char* infoString)
{ {
for (int i = 0; i < 18; i++) for (int i = 0; i < 18; i++)
{ {
const char* clantag = Game::Info_ValueForKey(infoString, std::to_string(i).data()); const char* clantag = Game::Info_ValueForKey(infoString, std::to_string(i).data());
if (clantag) Clantags::Tags[i] = clantag; if (clantag) ClanTags::Tags[i] = clantag;
else Clantags::Tags[i].clear(); else ClanTags::Tags[i].clear();
} }
} }
void Clantags::SendClantagsToClients() void ClanTags::SendClantagsToClients()
{ {
std::string list; std::string list;
@ -35,18 +35,18 @@ namespace Components
Game::SV_GameSendServerCommand(-1, 0, command.data()); Game::SV_GameSendServerCommand(-1, 0, command.data());
} }
const char* Clantags::GetUserClantag(std::uint32_t /*clientnum*/, const char* playername) const char* ClanTags::GetUserClantag(std::uint32_t /*clientnum*/, const char* playername)
{ {
#if 0 #if 0
if (Clantags::Tags[clientnum].empty()) return playername; if (ClanTags::Tags[clientnum].empty()) return playername;
return Utils::String::VA("[%s] %s", Clantags::Tags[clientnum].data(), playername); return Utils::String::VA("[%s] %s", ClanTags::Tags[clientnum].data(), playername);
#else #else
return playername; return playername;
#endif #endif
} }
__declspec(naked) void Clantags::DrawPlayerNameOnScoreboard() __declspec(naked) void ClanTags::DrawPlayerNameOnScoreboard()
{ {
__asm __asm
{ {
@ -56,7 +56,7 @@ namespace Components
push edi push edi
push [ebp] push [ebp]
call Clantags::GetUserClantag call ClanTags::GetUserClantag
add esp, 8 add esp, 8
mov [esp + 20h], eax mov [esp + 20h], eax
@ -70,7 +70,7 @@ namespace Components
} }
} }
Clantags::Clantags() ClanTags::ClanTags()
{ {
// Create clantag dvar // Create clantag dvar
Dvar::OnInit([]() Dvar::OnInit([]()
@ -85,7 +85,7 @@ namespace Components
{ {
if (params->length() == 3) if (params->length() == 3)
{ {
Clantags::ParseClantags(params->get(2)); ClanTags::ParseClantags(params->get(2));
return true; return true;
} }
} }
@ -93,20 +93,20 @@ namespace Components
return false; return false;
}); });
for (int i = 0; i < ARRAYSIZE(Clantags::Tags); ++i) for (int i = 0; i < ARRAYSIZE(ClanTags::Tags); ++i)
{ {
Clantags::Tags[i].clear(); ClanTags::Tags[i].clear();
} }
// Draw clantag before playername // Draw clantag before playername
Utils::Hook(0x591242, Clantags::DrawPlayerNameOnScoreboard).install()->quick(); Utils::Hook(0x591242, ClanTags::DrawPlayerNameOnScoreboard).install()->quick();
} }
Clantags::~Clantags() ClanTags::~ClanTags()
{ {
for (int i = 0; i < ARRAYSIZE(Clantags::Tags); ++i) for (int i = 0; i < ARRAYSIZE(ClanTags::Tags); ++i)
{ {
Clantags::Tags[i].clear(); ClanTags::Tags[i].clear();
} }
} }
} }

View File

@ -2,18 +2,18 @@
namespace Components namespace Components
{ {
class Clantags : public Component class ClanTags : public Component
{ {
public: public:
static void ParseClantags(const char * infoString); static void ParseClantags(const char * infoString);
static void SendClantagsToClients(); static void SendClantagsToClients();
static const char* GetUserClantag(std::uint32_t clientnum, const char * playername); static const char* GetUserClantag(std::uint32_t clientnum, const char * playername);
Clantags(); ClanTags();
~Clantags(); ~ClanTags();
private: private:
static std::string Clantags::Tags[18]; static std::string ClanTags::Tags[18];
static void DrawPlayerNameOnScoreboard(); static void DrawPlayerNameOnScoreboard();

View File

@ -86,6 +86,20 @@ namespace Components
return std::string(buffer); return std::string(buffer);
} }
void Colors::UserInfoCopy(char* buffer, const char* name, size_t size)
{
Utils::Memory::Allocator allocator;
if (!Dvar::Var("sv_allowColoredNames").get<bool>())
{
Colors::Strip(name, buffer, size);
}
else
{
strncpy_s(buffer, size, name, size);
}
}
__declspec(naked) void Colors::ClientUserinfoChanged() __declspec(naked) void Colors::ClientUserinfoChanged()
{ {
__asm __asm
@ -97,7 +111,7 @@ namespace Components
push ecx // name push ecx // name
push edx // buffer push edx // buffer
call strncpy call Colors::UserInfoCopy
add esp, 0Ch add esp, 0Ch
retn retn
@ -109,7 +123,7 @@ namespace Components
Game::CL_GetClientName(localClientNum, index, buf, size); Game::CL_GetClientName(localClientNum, index, buf, size);
// Append clantag to username & remove the colors // Append clantag to username & remove the colors
strncpy_s(buf, size, Colors::Strip(Clantags::GetUserClantag(index, buf)).data(), size); strncpy_s(buf, size, Colors::Strip(ClanTags::GetUserClantag(index, buf)).data(), size);
return buf; return buf;
} }
@ -227,6 +241,7 @@ namespace Components
// Register dvar // Register dvar
Colors::NewColors = Dvar::Register<bool>("cg_newColors", true, Game::dvar_flag::DVAR_FLAG_SAVED, "Use Warfare² color code style."); Colors::NewColors = Dvar::Register<bool>("cg_newColors", true, Game::dvar_flag::DVAR_FLAG_SAVED, "Use Warfare² color code style.");
Game::Dvar_RegisterColor("sv_customTextColor", 1, 0.7f, 0, 1, Game::dvar_flag::DVAR_FLAG_REPLICATED, "Color for the extended color code."); Game::Dvar_RegisterColor("sv_customTextColor", 1, 0.7f, 0, 1, Game::dvar_flag::DVAR_FLAG_REPLICATED, "Color for the extended color code.");
Dvar::Register<bool>("sv_allowColoredNames", true, Game::dvar_flag::DVAR_FLAG_NONE, "Allow colored names on the server");
// Add our colors // Add our colors
Colors::Add(0, 0, 0); // 0 - Black Colors::Add(0, 0, 0); // 0 - Black

View File

@ -25,6 +25,8 @@ namespace Components
static DWORD HsvToRgb(HsvColor hsv); static DWORD HsvToRgb(HsvColor hsv);
static void UserInfoCopy(char* buffer, const char* name, size_t size);
static void ClientUserinfoChanged(); static void ClientUserinfoChanged();
static char* GetClientName(int localClientNum, int index, char *buf, size_t size); static char* GetClientName(int localClientNum, int index, char *buf, size_t size);
static void PatchColorLimit(char limit); static void PatchColorLimit(char limit);

View File

@ -491,7 +491,7 @@ namespace Components
void Console::FreeNativeConsole() void Console::FreeNativeConsole()
{ {
if (!Monitor::IsEnabled() && !Flags::HasFlag("stdout") && (!Dedicated::IsEnabled() || Flags::HasFlag("console"))) if (!Monitor::IsEnabled() && !Flags::HasFlag("stdout") && (!Dedicated::IsEnabled() || Flags::HasFlag("console")) && !Loader::PerformingUnitTests())
{ {
FreeConsole(); FreeConsole();
} }
@ -643,7 +643,7 @@ namespace Components
Utils::Hook(0x43D570, Console::Error, HOOK_JUMP).install()->quick(); Utils::Hook(0x43D570, Console::Error, HOOK_JUMP).install()->quick();
Utils::Hook(0x4859A5, Console::Input, HOOK_CALL).install()->quick(); Utils::Hook(0x4859A5, Console::Input, HOOK_CALL).install()->quick();
} }
else else if(!Loader::PerformingUnitTests())
{ {
FreeConsole(); FreeConsole();
} }

View File

@ -8,14 +8,14 @@ namespace Components
bool Dedicated::IsEnabled() bool Dedicated::IsEnabled()
{ {
static Utils::Value<bool> flag; static std::optional<bool> flag;
if (!flag.isValid()) if (!flag.has_value())
{ {
flag.set(Flags::HasFlag("dedicated")); flag.emplace(Flags::HasFlag("dedicated"));
} }
return flag.get(); return flag.value();
} }
void Dedicated::InitDedicatedServer() void Dedicated::InitDedicatedServer()

View File

@ -11,12 +11,12 @@ namespace Components
#pragma region Client #pragma region Client
void Download::InitiateMapDownload(std::string map) void Download::InitiateMapDownload(std::string map, bool needPassword)
{ {
Download::InitiateClientDownload(map, true); Download::InitiateClientDownload(map, needPassword, true);
} }
void Download::InitiateClientDownload(std::string mod, bool map) void Download::InitiateClientDownload(std::string mod, bool needPassword, bool map)
{ {
if (Download::CLDownload.running) return; if (Download::CLDownload.running) return;
@ -29,6 +29,18 @@ namespace Components
Command::Execute("openmenu mod_download_popmenu", false); Command::Execute("openmenu mod_download_popmenu", false);
if (needPassword)
{
std::string pass = Dvar::Var("password").get<std::string>();
if (!pass.length())
{
// shouldn't ever happen but this is safe
Party::ConnectError("A password is required to connect to this server!");
return;
}
Download::CLDownload.hashedPassword = Utils::Cryptography::SHA256::Compute(pass);
}
Download::CLDownload.running = true; Download::CLDownload.running = true;
Download::CLDownload.isMap = map; Download::CLDownload.isMap = map;
Download::CLDownload.mod = mod; Download::CLDownload.mod = mod;
@ -37,6 +49,7 @@ namespace Components
Download::CLDownload.lastTimeStamp = 0; Download::CLDownload.lastTimeStamp = 0;
Download::CLDownload.downBytes = 0; Download::CLDownload.downBytes = 0;
Download::CLDownload.timeStampBytes = 0; Download::CLDownload.timeStampBytes = 0;
Download::CLDownload.isPrivate = needPassword;
Download::CLDownload.target = Party::Target(); Download::CLDownload.target = Party::Target();
Download::CLDownload.thread = std::thread(Download::ModDownloader, &Download::CLDownload); Download::CLDownload.thread = std::thread(Download::ModDownloader, &Download::CLDownload);
} }
@ -216,7 +229,8 @@ namespace Components
} }
else else
{ {
url = host + "/file/" + (download->isMap ? "map/" : "") + file.name; url = host + "/file/" + (download->isMap ? "map/" : "") + file.name
+ (download->isPrivate ? ("?password=" + download->hashedPassword) : "");
} }
Download::FileDownload fDownload; Download::FileDownload fDownload;
@ -258,7 +272,9 @@ namespace Components
std::string host = "http://" + download->target.getString(); std::string host = "http://" + download->target.getString();
std::string list = Utils::WebIO("IW4x", host + (download->isMap ? "/map" : "/list")).setTimeout(5000)->get(); std::string listUrl = host + (download->isMap ? "/map" : "/list") + (download->isPrivate ? ("?password=" + download->hashedPassword) : "");
std::string list = Utils::WebIO("IW4x", listUrl).setTimeout(5000)->get();
if (list.empty()) if (list.empty())
{ {
if (download->terminateThread) return; if (download->terminateThread) return;
@ -386,6 +402,31 @@ namespace Components
return nullptr; return nullptr;
} }
bool Download::VerifyPassword(mg_connection *nc, http_message* message)
{
std::string g_password = Dvar::Var("g_password").get<std::string>();
if (!g_password.size()) return true;
// sha256 hashes are 64 chars long but we're gonna be safe here
char buffer[128] = { 0 };
int passLen = mg_get_http_var(&message->query_string, "password", buffer, sizeof buffer);
if (passLen <= 0 || std::string(buffer, passLen) != g_password)//Utils::Cryptography::SHA256::Compute(g_password))
{
mg_printf(nc, ("HTTP/1.1 403 Forbidden\r\n"s +
"Content-Type: text/html\r\n"s +
"Connection: close\r\n"s +
"\r\n"s +
((passLen == 0) ? "Password Required"s : "Invalid Password"s)).c_str());
nc->flags |= MG_F_SEND_AND_CLOSE;
return false;
}
return true;
}
void Download::Forbid(mg_connection *nc) void Download::Forbid(mg_connection *nc)
{ {
mg_printf(nc, "HTTP/1.1 403 Forbidden\r\n" mg_printf(nc, "HTTP/1.1 403 Forbidden\r\n"
@ -397,11 +438,13 @@ namespace Components
nc->flags |= MG_F_SEND_AND_CLOSE; nc->flags |= MG_F_SEND_AND_CLOSE;
} }
void Download::MapHandler(mg_connection *nc, int ev, void* /*ev_data*/) void Download::MapHandler(mg_connection *nc, int ev, void* ev_data)
{ {
// Only handle http requests // Only handle http requests
if (ev != MG_EV_HTTP_REQUEST) return; if (ev != MG_EV_HTTP_REQUEST) return;
if (!Download::VerifyPassword(nc, reinterpret_cast<http_message*>(ev_data))) return;
static std::string mapnamePre; static std::string mapnamePre;
static json11::Json jsonList; static json11::Json jsonList;
@ -448,11 +491,13 @@ namespace Components
nc->flags |= MG_F_SEND_AND_CLOSE; nc->flags |= MG_F_SEND_AND_CLOSE;
} }
void Download::ListHandler(mg_connection* nc, int ev, void* /*ev_data*/) void Download::ListHandler(mg_connection* nc, int ev, void* ev_data)
{ {
// Only handle http requests // Only handle http requests
if (ev != MG_EV_HTTP_REQUEST) return; if (ev != MG_EV_HTTP_REQUEST) return;
if (!Download::VerifyPassword(nc, reinterpret_cast<http_message*>(ev_data))) return;
// if (!Download::IsClient(nc)) // if (!Download::IsClient(nc))
// { // {
// Download::Forbid(nc); // Download::Forbid(nc);
@ -512,6 +557,8 @@ namespace Components
http_message* message = reinterpret_cast<http_message*>(ev_data); http_message* message = reinterpret_cast<http_message*>(ev_data);
//if (!Download::VerifyPassword(nc, message)) return;
// if (!Download::IsClient(nc)) // if (!Download::IsClient(nc))
// { // {
// Download::Forbid(nc); // Download::Forbid(nc);
@ -597,7 +644,7 @@ namespace Components
// Only handle http requests // Only handle http requests
if (ev != MG_EV_HTTP_REQUEST) return; if (ev != MG_EV_HTTP_REQUEST) return;
//http_message* message = reinterpret_cast<http_message*>(ev_data); //if (!Download::VerifyPassword(nc, reinterpret_cast<http_message*>(ev_data))) return;
Utils::InfoString status = ServerInfo::GetInfo(); Utils::InfoString status = ServerInfo::GetInfo();

View File

@ -11,8 +11,8 @@ namespace Components
void preDestroy() override; void preDestroy() override;
static void InitiateClientDownload(std::string mod, bool map = false); static void InitiateClientDownload(std::string mod, bool needPassword, bool map = false);
static void InitiateMapDownload(std::string map); static void InitiateMapDownload(std::string map, bool needPassword);
private: private:
class ClientDownload class ClientDownload
@ -25,8 +25,10 @@ namespace Components
bool valid; bool valid;
bool terminateThread; bool terminateThread;
bool isMap; bool isMap;
bool isPrivate;
mg_mgr mgr; mg_mgr mgr;
Network::Address target; Network::Address target;
std::string hashedPassword;
std::string mod; std::string mod;
std::thread thread; std::thread thread;
@ -209,6 +211,8 @@ namespace Components
static std::thread ServerThread; static std::thread ServerThread;
static bool Terminate; static bool Terminate;
static bool VerifyPassword(mg_connection *nc, http_message* message);
static void EventHandler(mg_connection *nc, int ev, void *ev_data); static void EventHandler(mg_connection *nc, int ev, void *ev_data);
static void ListHandler(mg_connection *nc, int ev, void *ev_data); static void ListHandler(mg_connection *nc, int ev, void *ev_data);
static void MapHandler(mg_connection *nc, int ev, void *ev_data); static void MapHandler(mg_connection *nc, int ev, void *ev_data);

View File

@ -345,12 +345,10 @@ namespace Components
{ {
Logger::Error("The fastfile you are trying to load is outdated (%d, expected %d)", header[1], XFILE_VERSION_IW4X); Logger::Error("The fastfile you are trying to load is outdated (%d, expected %d)", header[1], XFILE_VERSION_IW4X);
} }
#ifdef DEBUG
else if (header[1] > XFILE_VERSION_IW4X) else if (header[1] > XFILE_VERSION_IW4X)
{ {
Logger::Error("You are loading a fastfile that is too new (%d, expected %d), how's that possible?", header[1], XFILE_VERSION_IW4X); Logger::Error("You are loading a fastfile that is too new (%d, expected %d), update your game", header[1], XFILE_VERSION_IW4X);
} }
#endif
*reinterpret_cast<unsigned __int64*>(header) = XFILE_MAGIC_UNSIGNED; *reinterpret_cast<unsigned __int64*>(header) = XFILE_MAGIC_UNSIGNED;
} }

View File

@ -164,7 +164,7 @@ namespace Components
{ {
std::vector<int> ids; std::vector<int> ids;
auto addId = [&](int id) const auto addId = [&](int id)
{ {
if (std::find(ids.begin(), ids.end(), id) == ids.end()) if (std::find(ids.begin(), ids.end(), id) == ids.end())
{ {
@ -186,8 +186,7 @@ namespace Components
{ {
std::lock_guard<std::recursive_mutex> _(Friends::Mutex); std::lock_guard<std::recursive_mutex> _(Friends::Mutex);
char* mod = "IW4x"; const unsigned int modId = *reinterpret_cast<unsigned int*>("IW4x") | 0x80000000;
unsigned int modId = *reinterpret_cast<unsigned int*>(mod) | 0x80000000;
// Split up the list // Split up the list
for (auto entry : Friends::FriendsList) for (auto entry : Friends::FriendsList)
@ -283,15 +282,15 @@ namespace Components
void Friends::UpdateRank() void Friends::UpdateRank()
{ {
static Utils::Value<int> levelVal; static std::optional<int> levelVal;
int experience = Game::Live_GetXp(0); int experience = Game::Live_GetXp(0);
int prestige = Game::Live_GetPrestige(0); int prestige = Game::Live_GetPrestige(0);
int level = (experience & 0xFFFFFF) | ((prestige & 0xFF) << 24); int level = (experience & 0xFFFFFF) | ((prestige & 0xFF) << 24);
if(!levelVal.isValid() || levelVal.get() != level) if (!levelVal.has_value() || levelVal.value() != level)
{ {
levelVal.set(level); levelVal.emplace(level);
Friends::SetPresence("iw4x_experience", Utils::String::VA("%d", experience)); Friends::SetPresence("iw4x_experience", Utils::String::VA("%d", experience));
Friends::SetPresence("iw4x_prestige", Utils::String::VA("%d", prestige)); Friends::SetPresence("iw4x_prestige", Utils::String::VA("%d", prestige));

View File

@ -9,7 +9,6 @@ namespace Components
bool Maps::SPMap; bool Maps::SPMap;
std::vector<Maps::DLC> Maps::DlcPacks; std::vector<Maps::DLC> Maps::DlcPacks;
std::vector<Game::XAssetEntry> Maps::EntryPool;
const char* Maps::UserMapFiles[4] = const char* Maps::UserMapFiles[4] =
{ {
@ -713,59 +712,7 @@ namespace Components
Game::XAssetEntry* Maps::GetAssetEntryPool() Game::XAssetEntry* Maps::GetAssetEntryPool()
{ {
if(Maps::EntryPool.empty()) return *reinterpret_cast<Game::XAssetEntry**>(0x48E6F4);
{
return reinterpret_cast<Game::XAssetEntry*>(0x134CAD8);
}
return Maps::EntryPool.data();
}
void Maps::reallocateEntryPool()
{
AssertSize(Game::XAssetEntry, 16);
Maps::EntryPool.clear();
if (ZoneBuilder::IsEnabled())
{
Maps::EntryPool.resize(1183968);
}
else
{
Maps::EntryPool.resize(789312);
}
// Apply new size
Utils::Hook::Set<DWORD>(0x5BAEB0, Maps::EntryPool.size());
// Apply new pool
Utils::Hook::Set<Game::XAssetEntry*>(0x48E6F4, Maps::EntryPool.data());
Utils::Hook::Set<Game::XAssetEntry*>(0x4C67E4, Maps::EntryPool.data());
Utils::Hook::Set<Game::XAssetEntry*>(0x4C8584, Maps::EntryPool.data());
Utils::Hook::Set<Game::XAssetEntry*>(0x5BAEA8, Maps::EntryPool.data());
Utils::Hook::Set<Game::XAssetEntry*>(0x5BB0C4, Maps::EntryPool.data());
Utils::Hook::Set<Game::XAssetEntry*>(0x5BB0F5, Maps::EntryPool.data());
Utils::Hook::Set<Game::XAssetEntry*>(0x5BB1D4, Maps::EntryPool.data());
Utils::Hook::Set<Game::XAssetEntry*>(0x5BB235, Maps::EntryPool.data());
Utils::Hook::Set<Game::XAssetEntry*>(0x5BB278, Maps::EntryPool.data());
Utils::Hook::Set<Game::XAssetEntry*>(0x5BB34C, Maps::EntryPool.data());
Utils::Hook::Set<Game::XAssetEntry*>(0x5BB484, Maps::EntryPool.data());
Utils::Hook::Set<Game::XAssetEntry*>(0x5BB570, Maps::EntryPool.data());
Utils::Hook::Set<Game::XAssetEntry*>(0x5BB6B7, Maps::EntryPool.data());
Utils::Hook::Set<Game::XAssetEntry*>(0x5BB844, Maps::EntryPool.data());
Utils::Hook::Set<Game::XAssetEntry*>(0x5BB98D, Maps::EntryPool.data());
Utils::Hook::Set<Game::XAssetEntry*>(0x5BBA66, Maps::EntryPool.data());
Utils::Hook::Set<Game::XAssetEntry*>(0x5BBB8D, Maps::EntryPool.data());
Utils::Hook::Set<Game::XAssetEntry*>(0x5BBCB1, Maps::EntryPool.data());
Utils::Hook::Set<Game::XAssetEntry*>(0x5BBD9B, Maps::EntryPool.data());
Utils::Hook::Set<Game::XAssetEntry*>(0x5BBE4C, Maps::EntryPool.data());
Utils::Hook::Set<Game::XAssetEntry*>(0x5BBF14, Maps::EntryPool.data());
Utils::Hook::Set<Game::XAssetEntry*>(0x5BBF54, Maps::EntryPool.data());
Utils::Hook::Set<Game::XAssetEntry*>(0x5BBFB8, Maps::EntryPool.data());
Utils::Hook::Set<Game::XAssetEntry*>(0x5BAE91, Maps::EntryPool.data() + 1);
Utils::Hook::Set<Game::XAssetEntry*>(0x5BAEA2, Maps::EntryPool.data() + 1);
} }
// dlcIsTrue serves as a check if the map is a custom map and if it's missing // dlcIsTrue serves as a check if the map is a custom map and if it's missing
@ -1022,24 +969,6 @@ namespace Components
// Load usermap arena file // Load usermap arena file
Utils::Hook(0x630A88, Maps::LoadArenaFileStub, HOOK_CALL).install()->quick(); Utils::Hook(0x630A88, Maps::LoadArenaFileStub, HOOK_CALL).install()->quick();
Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_GAMEWORLD_SP, 1);
Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_IMAGE, 7168);
Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_LOADED_SOUND, 2700);
Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_FX, 1200);
Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_LOCALIZE_ENTRY, 14000);
Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_XANIMPARTS, 8192);
Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_XMODEL, 5125);
Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_PHYSPRESET, 128);
Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_PIXELSHADER, 10000);
Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_VERTEXSHADER, 3072);
Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_MATERIAL, 8192);
Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_VERTEXDECL, 196);
Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_WEAPON, WEAPON_LIMIT);
Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_STRINGTABLE, 800);
Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_IMPACT_FX, 8);
this->reallocateEntryPool();
// Dependencies // Dependencies
//Maps::AddDependency("oilrig", "mp_subbase"); //Maps::AddDependency("oilrig", "mp_subbase");
//Maps::AddDependency("gulag", "mp_subbase"); //Maps::AddDependency("gulag", "mp_subbase");
@ -1113,7 +1042,5 @@ namespace Components
Maps::DependencyList.clear(); Maps::DependencyList.clear();
Maps::CurrentMainZone.clear(); Maps::CurrentMainZone.clear();
Maps::CurrentDependencies.clear(); Maps::CurrentDependencies.clear();
Maps::EntryPool.clear();
} }
} }

View File

@ -78,7 +78,6 @@ namespace Components
static bool SPMap; static bool SPMap;
static UserMapContainer UserMap; static UserMapContainer UserMap;
static std::vector<DLC> DlcPacks; static std::vector<DLC> DlcPacks;
static std::vector<Game::XAssetEntry> EntryPool;
static std::vector<std::pair<std::string, std::string>> DependencyList; static std::vector<std::pair<std::string, std::string>> DependencyList;
static std::vector<std::string> CurrentDependencies; static std::vector<std::string> CurrentDependencies;
@ -123,7 +122,5 @@ namespace Components
static Game::dvar_t* GetSpecularDvar(); static Game::dvar_t* GetSpecularDvar();
static void SetSpecularStub1(); static void SetSpecularStub1();
static void SetSpecularStub2(); static void SetSpecularStub2();
void reallocateEntryPool();
}; };
} }

View File

@ -767,7 +767,7 @@ namespace Components
}); });
#if !defined(DEBUG) && !defined(DISABLE_ANTICHEAT) #if !defined(DEBUG) && !defined(DISABLE_ANTICHEAT)
Scheduler::OnFrame(AntiCheat::QuickCodeScanner_2); Scheduler::OnFrame(AntiCheat::QuickCodeScanner2);
#endif #endif
Command::Add("mp_QuickMessage", [](Command::Params*) Command::Add("mp_QuickMessage", [](Command::Params*)

View File

@ -7,14 +7,14 @@ namespace Components
{ {
bool Monitor::IsEnabled() bool Monitor::IsEnabled()
{ {
static Utils::Value<bool> flag; static std::optional<bool> flag;
if (!flag.isValid()) if (!flag.has_value())
{ {
flag.set(Flags::HasFlag("monitor")); flag.emplace(Flags::HasFlag("monitor"));
} }
return flag.get(); return flag.value();
} }
int __stdcall Monitor::EntryPoint(HINSTANCE /*hInstance*/, HINSTANCE /*hPrevInstance*/, LPSTR /*lpCmdLine*/, int /*nShowCmd*/) int __stdcall Monitor::EntryPoint(HINSTANCE /*hInstance*/, HINSTANCE /*hPrevInstance*/, LPSTR /*lpCmdLine*/, int /*nShowCmd*/)

View File

@ -17,9 +17,9 @@ namespace Components
{ {
Game::snd_alias_list_t* aliases = Game::DB_FindXAssetHeader(type, filename.data()).sound; Game::snd_alias_list_t* aliases = Game::DB_FindXAssetHeader(type, filename.data()).sound;
if (aliases) if (aliases && aliases->count > 0 && aliases->head && aliases->head->soundFile)
{ {
if (aliases->head->soundFile->type == 2) if (aliases->head->soundFile->type == Game::snd_alias_type_t::SAT_STREAMED)
{ {
aliases->head->soundFile->data.stream.name = MusicalTalent::SoundAliasList[Utils::String::ToLower(filename)]; aliases->head->soundFile->data.stream.name = MusicalTalent::SoundAliasList[Utils::String::ToLower(filename)];
} }

View File

@ -430,15 +430,19 @@ namespace Components
{ {
Party::ConnectError("Invalid map or gametype."); Party::ConnectError("Invalid map or gametype.");
} }
else if (Party::Container.info.get("isPrivate") == "1"s && !Dvar::Var("password").get<std::string>().length())
{
Party::ConnectError("A password is required to join this server! Set it at the bottom of the serverlist.");
}
else if (isUsermap && usermapHash != Maps::GetUsermapHash(info.get("mapname"))) else if (isUsermap && usermapHash != Maps::GetUsermapHash(info.get("mapname")))
{ {
Command::Execute("closemenu popup_reconnectingtoparty"); Command::Execute("closemenu popup_reconnectingtoparty");
Download::InitiateMapDownload(info.get("mapname")); Download::InitiateMapDownload(info.get("mapname"), info.get("isPrivate") == "1");
} }
else if (!info.get("fs_game").empty() && Utils::String::ToLower(mod) != Utils::String::ToLower(info.get("fs_game"))) else if (!info.get("fs_game").empty() && Utils::String::ToLower(mod) != Utils::String::ToLower(info.get("fs_game")))
{ {
Command::Execute("closemenu popup_reconnectingtoparty"); Command::Execute("closemenu popup_reconnectingtoparty");
Download::InitiateClientDownload(info.get("fs_game")); Download::InitiateClientDownload(info.get("fs_game"), info.get("isPrivate") == "1"s);
} }
else if (!Dvar::Var("fs_game").get<std::string>().empty() && info.get("fs_game").empty()) else if (!Dvar::Var("fs_game").get<std::string>().empty() && info.get("fs_game").empty())
{ {
@ -462,7 +466,7 @@ namespace Components
// Send playlist request // Send playlist request
Party::Container.requestTime = Game::Sys_Milliseconds(); Party::Container.requestTime = Game::Sys_Milliseconds();
Party::Container.awaitingPlaylist = true; Party::Container.awaitingPlaylist = true;
Network::SendCommand(Party::Container.target, "getplaylist"); Network::SendCommand(Party::Container.target, "getplaylist", Dvar::Var("password").get<std::string>());
// This is not a safe method // This is not a safe method
// TODO: Fix actual error! // TODO: Fix actual error!

View File

@ -45,6 +45,16 @@ namespace Components
void Playlist::PlaylistRequest(Network::Address address, std::string data) void Playlist::PlaylistRequest(Network::Address address, std::string data)
{ {
std::string password = Dvar::Var("g_password").get<std::string>();
if (password.length())
{
if (password != data)
{
Network::SendCommand(address, "playlistInvalidPassword");
return;
}
}
Logger::Print("Received playlist request, sending currently stored buffer.\n"); Logger::Print("Received playlist request, sending currently stored buffer.\n");
std::string compressedList = Utils::Compression::ZLib::Compress(Playlist::CurrentPlaylistBuffer); std::string compressedList = Utils::Compression::ZLib::Compress(Playlist::CurrentPlaylistBuffer);
@ -104,6 +114,11 @@ namespace Components
} }
} }
void Playlist::PlaylistInvalidPassword(Network::Address /*address*/, std::string /*data*/)
{
Party::PlaylistError("Error: Invalid Password for Party.");
}
void Playlist::MapNameCopy(char *dest, const char *src, int destsize) void Playlist::MapNameCopy(char *dest, const char *src, int destsize)
{ {
Utils::Hook::Call<void(char*, const char*, int)>(0x4D6F80)(dest, src, destsize); Utils::Hook::Call<void(char*, const char*, int)>(0x4D6F80)(dest, src, destsize);
@ -173,6 +188,7 @@ namespace Components
Network::Handle("getPlaylist", PlaylistRequest); Network::Handle("getPlaylist", PlaylistRequest);
Network::Handle("playlistResponse", PlaylistReponse); Network::Handle("playlistResponse", PlaylistReponse);
Network::Handle("playlistInvalidPassword", PlaylistInvalidPassword);
} }
Playlist::~Playlist() Playlist::~Playlist()

View File

@ -22,6 +22,7 @@ namespace Components
static void PlaylistRequest(Network::Address address, std::string data); static void PlaylistRequest(Network::Address address, std::string data);
static void PlaylistReponse(Network::Address address, std::string data); static void PlaylistReponse(Network::Address address, std::string data);
static void PlaylistInvalidPassword(Network::Address address, std::string data);
static void MapNameCopy(char *dest, const char *src, int destsize); static void MapNameCopy(char *dest, const char *src, int destsize);
static void SetMapName(const char* cvar, const char* value); static void SetMapName(const char* cvar, const char* value);

View File

@ -735,6 +735,21 @@ namespace Components
} }
} }
printf("Success\n");
printf("Testing trimming...");
std::string trim1 = " 1 ";
std::string trim2 = " 1";
std::string trim3 = "1 ";
Utils::String::Trim(trim1);
Utils::String::LTrim(trim2);
Utils::String::RTrim(trim3);
if (trim1 != "1") return false;
if (trim2 != "1") return false;
if (trim3 != "1") return false;
printf("Success\n"); printf("Success\n");
return true; return true;
} }

View File

@ -746,8 +746,7 @@ namespace Components
do do
{ {
entry = reinterpret_cast<ServerList::MasterEntry*>(const_cast<char*>(data.data()) + offset++); entry = reinterpret_cast<ServerList::MasterEntry*>(const_cast<char*>(data.data()) + offset++);
} } while (!entry->HasSeparator() && !entry->IsEndToken());
while (!entry->HasSeparator() && !entry->IsEndToken());
for (int i = 0; !entry[i].IsEndToken() && entry[i].HasSeparator(); ++i) for (int i = 0; !entry[i].IsEndToken() && entry[i].HasSeparator(); ++i)
{ {

View File

@ -37,5 +37,4 @@ namespace Components
{ {
StartupMessages::MessageList.push_back(message); StartupMessages::MessageList.push_back(message);
} }
} }

View File

@ -70,6 +70,7 @@ namespace Components
// ToDo: Allow playerdata changes in setPlayerData UI script. // ToDo: Allow playerdata changes in setPlayerData UI script.
} }
Stats::~Stats() Stats::~Stats()
{ {

View File

@ -55,7 +55,7 @@ namespace Components
Game::Font* font = Game::DB_FindXAssetHeader(Game::XAssetType::ASSET_TYPE_FONT, "fonts/objectiveFont").font; if (!font) return; Game::Font* font = Game::DB_FindXAssetHeader(Game::XAssetType::ASSET_TYPE_FONT, "fonts/objectiveFont").font; if (!font) return;
Game::Font* descfont = Game::DB_FindXAssetHeader(Game::XAssetType::ASSET_TYPE_FONT, "fonts/normalFont").font; if (!descfont) return; Game::Font* descfont = Game::DB_FindXAssetHeader(Game::XAssetType::ASSET_TYPE_FONT, "fonts/normalFont").font; if (!descfont) return;
Game::vec4_t wColor = { 1.0f, 1.0f, 1.0f, 1.0f }; Game::vec4_t wColor = { 1.0f, 1.0f, 1.0f, 1.0f };
Game::vec4_t bgColor = { 0.0f, 0.0f, 0.0f, 0.5f }; Game::vec4_t bgColor = { 0.0f, 0.0f, 0.0f, 0.8f };
Game::vec4_t borderColor = { 1.0f, 1.0f, 1.0f, 0.2f }; Game::vec4_t borderColor = { 1.0f, 1.0f, 1.0f, 0.2f };
height /= 5; height /= 5;

View File

@ -506,7 +506,7 @@ namespace Components
// Add branding asset // Add branding asset
void ZoneBuilder::Zone::addBranding() void ZoneBuilder::Zone::addBranding()
{ {
char* data = "FastFile built using IW4x ZoneTool!"; char* data = "FastFile built using the IW4x ZoneBuilder!";
this->branding = { this->zoneName.data(), static_cast<int>(strlen(data)), 0, data }; this->branding = { this->zoneName.data(), static_cast<int>(strlen(data)), 0, data };
if (this->findAsset(Game::XAssetType::ASSET_TYPE_RAWFILE, this->branding.name) != -1) if (this->findAsset(Game::XAssetType::ASSET_TYPE_RAWFILE, this->branding.name) != -1)
@ -664,14 +664,14 @@ namespace Components
bool ZoneBuilder::IsEnabled() bool ZoneBuilder::IsEnabled()
{ {
static Utils::Value<bool> flag; static std::optional<bool> flag;
if (!flag.isValid()) if (!flag.has_value())
{ {
flag.set(Flags::HasFlag("zonebuilder")); flag.emplace(Flags::HasFlag("zonebuilder"));
} }
return (flag.get() && !Dedicated::IsEnabled()); return (flag.value() && !Dedicated::IsEnabled());
} }
void ZoneBuilder::BeginAssetTrace(std::string zone) void ZoneBuilder::BeginAssetTrace(std::string zone)
@ -1034,17 +1034,6 @@ namespace Components
// Don't read stats // Don't read stats
Utils::Hook(0x4875E1, 0x487717, HOOK_JUMP).install()->quick(); Utils::Hook(0x4875E1, 0x487717, HOOK_JUMP).install()->quick();
// Increase asset pools
Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_MAP_ENTS, 10);
Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_XMODELSURFS, 8192);
Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_IMAGE, 14336);
Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_TECHNIQUE_SET, 0x2000);
Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_PIXELSHADER, 0x4000);
Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_VERTEXSHADER, 0x2000);
Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_VERTEXDECL, 0x400);
Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_FONT, 32);
Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_RAWFILE, 2048);
// patch g_copyInfo because we're using so many more assets than originally intended // patch g_copyInfo because we're using so many more assets than originally intended
int newLimit = 0x2000; int newLimit = 0x2000;
int* g_copyInfo_new = Utils::Memory::GetAllocator()->allocateArray<int>(newLimit); int* g_copyInfo_new = Utils::Memory::GetAllocator()->allocateArray<int>(newLimit);

View File

@ -222,14 +222,12 @@ namespace Game
const void *initial_ptr; const void *initial_ptr;
}; };
/* 526 */
struct MssSound struct MssSound
{ {
_AILSOUNDINFO info; _AILSOUNDINFO info;
char *data; char *data;
}; };
/* 527 */
struct LoadedSound struct LoadedSound
{ {
const char *name; const char *name;
@ -242,7 +240,7 @@ namespace Game
StreamedSound stream; StreamedSound stream;
}; };
struct SoundFile // 0xC struct SoundFile
{ {
snd_alias_type_t type; snd_alias_type_t type;
bool exists; bool exists;

View File

@ -5,6 +5,7 @@
#ifndef RC_INVOKED #ifndef RC_INVOKED
#define _HAS_CXX17 1
#define VC_EXTRALEAN #define VC_EXTRALEAN
#define WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN
@ -33,12 +34,12 @@
#include <regex> #include <regex>
#include <thread> #include <thread>
#include <future> #include <future>
#include <queue>
#include <unordered_map> #include <unordered_map>
#include <queue> #include <queue>
// Experimental C++17 features // Experimental C++17 features
#include <filesystem> #include <filesystem>
#include <optional>
#pragma warning(pop) #pragma warning(pop)

View File

@ -6,12 +6,12 @@ namespace Steam
{ {
unsigned int Utils::GetSecondsSinceAppActive() unsigned int Utils::GetSecondsSinceAppActive()
{ {
return 0; return Game::Sys_Milliseconds() / 1000;
} }
unsigned int Utils::GetSecondsSinceComputerActive() unsigned int Utils::GetSecondsSinceComputerActive()
{ {
return 0; return timeGetTime();
} }
int Utils::GetConnectedUniverse() int Utils::GetConnectedUniverse()
@ -21,25 +21,28 @@ namespace Steam
unsigned int Utils::GetServerRealTime() unsigned int Utils::GetServerRealTime()
{ {
static ::Utils::Value<unsigned int> timeDelta; static std::optional<unsigned int> timeDelta;
if(!timeDelta.has_value())
if(!timeDelta.isValid())
{ {
unsigned int steamTime = static_cast<unsigned int>(time(nullptr)); unsigned int steamTime = static_cast<unsigned int>(time(nullptr));
if(Steam::Proxy::SteamUtils) if(Steam::Proxy::SteamUtils)
{ {
steamTime = Steam::Proxy::SteamUtils->GetServerRealTime(); steamTime = Steam::Proxy::SteamUtils->GetServerRealTime();
} }
timeDelta.set(steamTime - (Game::Sys_Milliseconds() / 1000)); timeDelta.emplace(steamTime - (Game::Sys_Milliseconds() / 1000));
} }
return timeDelta.get() + (Game::Sys_Milliseconds() / 1000); return timeDelta.value() + (Game::Sys_Milliseconds() / 1000);
} }
const char* Utils::GetIPCountry() const char* Utils::GetIPCountry()
{ {
if (Steam::Proxy::SteamUtils)
{
return Steam::Proxy::SteamUtils->GetIPCountry();
}
return "US"; return "US";
} }
@ -60,6 +63,11 @@ namespace Steam
unsigned char Utils::GetCurrentBatteryPower() unsigned char Utils::GetCurrentBatteryPower()
{ {
if (Steam::Proxy::SteamUtils)
{
return Steam::Proxy::SteamUtils->GetCurrentBatteryPower();
}
return 255; return 255;
} }

View File

@ -48,10 +48,8 @@ namespace Utils
{ {
ECC::Key key; ECC::Key key;
register_prng(&sprng_desc);
ltc_mp = ltm_desc; ltc_mp = ltm_desc;
register_prng(&sprng_desc);
ecc_make_key(nullptr, find_prng("sprng"), bits / 8, key.getKeyPtr()); ecc_make_key(nullptr, find_prng("sprng"), bits / 8, key.getKeyPtr());
return key; return key;
@ -64,10 +62,8 @@ namespace Utils
uint8_t buffer[512]; uint8_t buffer[512];
DWORD length = sizeof(buffer); DWORD length = sizeof(buffer);
register_prng(&sprng_desc);
ltc_mp = ltm_desc; ltc_mp = ltm_desc;
register_prng(&sprng_desc);
ecc_sign_hash(reinterpret_cast<const uint8_t*>(message.data()), message.size(), buffer, &length, nullptr, find_prng("sprng"), key.getKeyPtr()); ecc_sign_hash(reinterpret_cast<const uint8_t*>(message.data()), message.size(), buffer, &length, nullptr, find_prng("sprng"), key.getKeyPtr());
return std::string(reinterpret_cast<char*>(buffer), length); return std::string(reinterpret_cast<char*>(buffer), length);

View File

@ -113,14 +113,20 @@ namespace Utils
// trim from start // trim from start
std::string &LTrim(std::string &s) std::string &LTrim(std::string &s)
{ {
s.erase(s.begin(), std::find_if(s.begin(), s.end(), std::not1(std::ptr_fun<int, int>(IsSpace)))); s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](int val)
{
return !IsSpace(val);
}));
return s; return s;
} }
// trim from end // trim from end
std::string &RTrim(std::string &s) std::string &RTrim(std::string &s)
{ {
s.erase(std::find_if(s.rbegin(), s.rend(), std::not1(std::ptr_fun<int, int>(IsSpace))).base(), s.end()); s.erase(std::find_if(s.rbegin(), s.rend(), [](int val)
{
return !IsSpace(val);
}).base(), s.end());
return s; return s;
} }

View File

@ -112,33 +112,4 @@ namespace Utils
private: private:
std::vector<Slot<T>> slots; std::vector<Slot<T>> slots;
}; };
// TODO: Replace with std::optional, once C++17 is fully available!
template <typename T>
class Value
{
public:
Value() : hasValue(false) {}
Value(T _value) { this->set(_value); }
void set(T _value)
{
this->value = _value;
this->hasValue = true;
}
bool isValid()
{
return this->hasValue;
}
T get()
{
return this->value;
}
private:
bool hasValue;
T value;
};
} }