Merge branch 'develop' of https://github.com/IW4x/iw4x-client into develop

This commit is contained in:
RektInator 2019-01-21 00:45:08 +01:00
commit a714924d20
25 changed files with 146 additions and 71 deletions

View File

@ -4,17 +4,38 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog v0.3.0](http://keepachangelog.com/en/0.3.0/) and this project adheres to [Semantic Versioning](http://semver.org/). The format is based on [Keep a Changelog v0.3.0](http://keepachangelog.com/en/0.3.0/) and this project adheres to [Semantic Versioning](http://semver.org/).
## [Unreleased] ## [unreleased] - xxxx-xx-xx
### Added ### Added
- Implement DHT into node network code. - Add host information to /info endpoint (request)
## [0.6.0] - 2018-12-30
### Added
- Implement unbanclient command.
- Implement /serverlist api endpoint on dedicated servers
- Add dvar to control the server query rate (net_serverQueryLimit & net_serverFrames)
### Changed ### Changed
- Update dependencies
### Fixed ### Fixed
- Fix mods not working in private matches. - Fix mods not working in private matches.
- Fix multiple game structures (map tools)
- Fix multiple vulnerability's
- Fix lag spikes on lower end PCs
- Fix invalid name check
- Fix openLink command crash issue
- Fix lobby server map downloading
- Fix steam integration
### Known issues
- HTTPS is not supported for fast downloads at the moment.
## [0.5.4] - 2017-07-09 ## [0.5.4] - 2017-07-09

2
deps/json11 vendored

@ -1 +1 @@
Subproject commit ec4e45219af1d7cde3d58b49ed762376fccf1ace Subproject commit 8d33613ebde0e7756a026e3770330da11e741823

2
deps/libtomcrypt vendored

@ -1 +1 @@
Subproject commit d432b13139ced07e309552f2a4893116883d434a Subproject commit 01c455c3d5f781312de84594a11e102a20d5b959

2
deps/libtommath vendored

@ -1 +1 @@
Subproject commit 9ff526fa2218f8697dcd0c9821330fa04682eb75 Subproject commit 2d80a97a2b48aa1ac6d8f0df29cc4dd6297b1fba

2
deps/mongoose vendored

@ -1 +1 @@
Subproject commit e2dfac946dd4e4fa2312fde0aae90b18e738ad12 Subproject commit c2a10601b9486f28b75307f003f5d9078acdce10

2
deps/pdcurses vendored

@ -1 +1 @@
Subproject commit 03212c5e1783cd41370860903149245bbe36b1fa Subproject commit 3f2336ad818b394110494ccb6d0dafed54a13950

2
deps/zlib vendored

@ -1 +1 @@
Subproject commit 41d86c73b21191a3fa9ea5f476fc9f1fc5e4f8b3 Subproject commit 0d36ec47f310478549c0864f215ab5c0114c49ba

View File

@ -38,7 +38,6 @@ function zlib.project()
} }
defines defines
{ {
"ZLIB_DLL",
"_CRT_SECURE_NO_DEPRECATE", "_CRT_SECURE_NO_DEPRECATE",
} }

View File

@ -219,8 +219,7 @@ protobuf.setup
zlib.setup zlib.setup
{ {
defines = { defines = {
"ZLIB_CONST", "ZLIB_CONST"
"ssize_t=int"
}, },
source = path.join(depsBasePath, "zlib"), source = path.join(depsBasePath, "zlib"),
} }

View File

@ -72,9 +72,7 @@ namespace Components
Loader::Register(new Renderer()); Loader::Register(new Renderer());
Loader::Register(new UIFeeder()); Loader::Register(new UIFeeder());
Loader::Register(new UIScript()); Loader::Register(new UIScript());
#ifndef DISABLE_ANTICHEAT
Loader::Register(new AntiCheat()); Loader::Register(new AntiCheat());
#endif
Loader::Register(new Changelog()); Loader::Register(new Changelog());
Loader::Register(new Dedicated()); Loader::Register(new Dedicated());
Loader::Register(new Discovery()); Loader::Register(new Discovery());

View File

@ -824,6 +824,64 @@ namespace Components
__VMProtectEnd; __VMProtectEnd;
} }
void AntiCheat::SystemTimeDiff(LPSYSTEMTIME stA, LPSYSTEMTIME stB, LPSYSTEMTIME stC) {
FILETIME ftA, ftB, ftC;
ULARGE_INTEGER uiA, uiB, uiC;
SystemTimeToFileTime(stA, &ftA);
SystemTimeToFileTime(stB, &ftB);
uiA.HighPart = ftA.dwHighDateTime;
uiA.LowPart = ftA.dwLowDateTime;
uiB.HighPart = ftB.dwHighDateTime;
uiB.LowPart = ftB.dwLowDateTime;
uiC.QuadPart = uiA.QuadPart - uiB.QuadPart;
ftC.dwHighDateTime = uiC.HighPart;
ftC.dwLowDateTime = uiC.LowPart;
FileTimeToSystemTime(&ftC, stC);
}
void AntiCheat::CheckStartupTime()
{
__VMProtectBeginUltra("");
FILETIME creation, exit, kernel, user;
SYSTEMTIME current, creationSt, diffSt;
GetSystemTime(&current);
GetProcessTimes(GetCurrentProcess(), &creation, &exit, &kernel, &user);
FileTimeToSystemTime(&creation, &creationSt);
AntiCheat::SystemTimeDiff(&current, &creationSt, &diffSt);
#ifdef DEBUG
char buf[512];
snprintf(buf, 512, "creation: %d:%d:%d:%d\n", creationSt.wHour, creationSt.wMinute, creationSt.wSecond, creationSt.wMilliseconds);
OutputDebugStringA(buf);
snprintf(buf, 512, "current: %d:%d:%d:%d\n", current.wHour, current.wMinute, current.wSecond, current.wMilliseconds);
OutputDebugStringA(buf);
snprintf(buf, 512, "diff: %d:%d:%d:%d\n", diffSt.wHour, diffSt.wMinute, diffSt.wSecond, diffSt.wMilliseconds);
OutputDebugStringA(buf);
#endif
// crash client if they are using process suspension to inject dlls during startup (aka before we got to here)
// maybe tweak this value depending on what the above logging reveals during testing,
// but 5 seconds seems about right for now
int time = diffSt.wMilliseconds + (diffSt.wSecond * 1000) + (diffSt.wMinute * 1000 * 60);
if (time > 5000) {
Components::AntiCheat::CrashClient();
}
// use below for logging when using StartSuspended.exe
// FILE* f = fopen("times.txt", "a");
// fwrite(buf, 1, strlen(buf), f);
// fclose(f);
__VMProtectEnd;
}
AntiCheat::AntiCheat() AntiCheat::AntiCheat()
{ {
__VMProtectBeginUltra(""); __VMProtectBeginUltra("");
@ -831,13 +889,12 @@ namespace Components
time(nullptr); time(nullptr);
AntiCheat::Flags = NO_FLAG; AntiCheat::Flags = NO_FLAG;
#ifdef DEBUG #ifdef DISABLE_ANTICHEAT
Command::Add("penis", [](Command::Params*) Command::Add("penis", [](Command::Params*)
{ {
AntiCheat::CrashClient(); AntiCheat::CrashClient();
}); });
#else #else
Utils::Hook(0x507BD5, AntiCheat::PatchWinAPI, HOOK_CALL).install()->quick(); Utils::Hook(0x507BD5, AntiCheat::PatchWinAPI, HOOK_CALL).install()->quick();
Utils::Hook(0x5082FD, AntiCheat::LostD3DStub, HOOK_CALL).install()->quick(); Utils::Hook(0x5082FD, AntiCheat::LostD3DStub, HOOK_CALL).install()->quick();
Utils::Hook(0x51C76C, AntiCheat::CinematicStub, HOOK_CALL).install()->quick(); Utils::Hook(0x51C76C, AntiCheat::CinematicStub, HOOK_CALL).install()->quick();
@ -866,6 +923,7 @@ namespace Components
// Set the integrity flag // Set the integrity flag
AntiCheat::Flags |= AntiCheat::IntergrityFlag::INITIALIZATION; AntiCheat::Flags |= AntiCheat::IntergrityFlag::INITIALIZATION;
#endif #endif
__VMProtectEnd; __VMProtectEnd;

View File

@ -54,6 +54,9 @@ namespace Components
static void UninstallLibHook(); static void UninstallLibHook();
static void InstallLibHook(); static void InstallLibHook();
static void CheckStartupTime();
static void SystemTimeDiff(LPSYSTEMTIME stA, LPSYSTEMTIME stB, LPSYSTEMTIME stC);
private: private:
enum IntergrityFlag enum IntergrityFlag
{ {
@ -114,3 +117,4 @@ namespace Components
static Utils::Hook VirtualProtectHook[2]; static Utils::Hook VirtualProtectHook[2];
}; };
} }

View File

@ -86,7 +86,7 @@ namespace Components
return; return;
} }
if (Steam::Enabled() && !Dvar::Var("cl_anonymous").get<bool>() && Steam::Proxy::SteamUser_) if (Steam::Enabled() && !Friends::IsInvisible() && !Dvar::Var("cl_anonymous").get<bool>() && Steam::Proxy::SteamUser_)
{ {
infostr.set("realsteamId", Utils::String::VA("%llX", Steam::Proxy::SteamUser_->GetSteamID().bits)); infostr.set("realsteamId", Utils::String::VA("%llX", Steam::Proxy::SteamUser_->GetSteamID().bits));
} }

View File

@ -220,6 +220,12 @@ namespace Components
// Table lookup stuff // Table lookup stuff
Utils::Hook(0x62DCC1, CardTitles::TableLookupByRowHookStub).install()->quick(); Utils::Hook(0x62DCC1, CardTitles::TableLookupByRowHookStub).install()->quick();
Utils::Hook::Nop(0x62DCC6, 1); Utils::Hook::Nop(0x62DCC6, 1);
// This is placed here in case the anticheat has been disabled!
// This checks specifically for launching the process suspended to inject a dll
#if !defined(DISABLE_ANTICHEAT)
AntiCheat::CheckStartupTime();
#endif
} }
CardTitles::~CardTitles() CardTitles::~CardTitles()

View File

@ -701,9 +701,11 @@ namespace Components
//if (!Download::VerifyPassword(nc, reinterpret_cast<http_message*>(ev_data))) return; //if (!Download::VerifyPassword(nc, reinterpret_cast<http_message*>(ev_data))) return;
Utils::InfoString status = ServerInfo::GetInfo(); Utils::InfoString status = ServerInfo::GetInfo();
Utils::InfoString host = ServerInfo::GetHostInfo();
std::map<std::string, json11::Json> info; std::map<std::string, json11::Json> info;
info["status"] = status.to_json(); info["status"] = status.to_json();
info["host"] = host.to_json();
std::vector<json11::Json> players; std::vector<json11::Json> players;

View File

@ -232,53 +232,6 @@ namespace Components
Logger::Print("Old exception handler was 0x%010X.\n", oldHandler); Logger::Print("Old exception handler was 0x%010X.\n", oldHandler);
}); });
#pragma warning(push)
#pragma warning(disable:4740) // flow in or out of inline asm code suppresses global optimization
Command::Add("debug_minidump", [](Command::Params*)
{
// The following code was taken from VC++ 8.0 CRT (invarg.c: line 104)
CONTEXT ContextRecord;
EXCEPTION_RECORD ExceptionRecord;
ZeroMemory(&ContextRecord, sizeof(CONTEXT));
__asm
{
mov [ContextRecord.Eax], eax
mov [ContextRecord.Ecx], ecx
mov [ContextRecord.Edx], edx
mov [ContextRecord.Ebx], ebx
mov [ContextRecord.Esi], esi
mov [ContextRecord.Edi], edi
mov word ptr [ContextRecord.SegSs], ss
mov word ptr [ContextRecord.SegCs], cs
mov word ptr [ContextRecord.SegDs], ds
mov word ptr [ContextRecord.SegEs], es
mov word ptr [ContextRecord.SegFs], fs
mov word ptr [ContextRecord.SegGs], gs
pushfd
pop [ContextRecord.EFlags]
}
ContextRecord.ContextFlags = CONTEXT_CONTROL;
ContextRecord.Eip = reinterpret_cast<DWORD>(_ReturnAddress());
ContextRecord.Esp = reinterpret_cast<DWORD>(_AddressOfReturnAddress());
ContextRecord.Ebp = *reinterpret_cast<DWORD*>(_AddressOfReturnAddress()) - 1;
ZeroMemory(&ExceptionRecord, sizeof(EXCEPTION_RECORD));
ExceptionRecord.ExceptionCode = EXCEPTION_BREAKPOINT;
ExceptionRecord.ExceptionAddress = _ReturnAddress();
EXCEPTION_POINTERS eptr;
eptr.ExceptionRecord = &ExceptionRecord;
eptr.ContextRecord = &ContextRecord;
Exception::ExceptionFilter(&eptr);
});
#pragma warning(pop)
// Check if folder exists && crash-helper exists // Check if folder exists && crash-helper exists
if (Utils::IO::DirectoryExists("minidumps\\") && Utils::IO::FileExists("crash-helper.exe")) if (Utils::IO::DirectoryExists("minidumps\\") && Utils::IO::FileExists("crash-helper.exe"))

View File

@ -124,7 +124,7 @@ namespace Components
void Friends::UpdateState(bool force) void Friends::UpdateState(bool force)
{ {
if (Dvar::Var("cl_anonymous").get<bool>() || !Steam::Enabled()) return; if (Dvar::Var("cl_anonymous").get<bool>() || Friends::IsInvisible() || !Steam::Enabled()) return;
if (force) if (force)
{ {
@ -228,7 +228,7 @@ namespace Components
void Friends::SetPresence(const std::string& key, const std::string& value) void Friends::SetPresence(const std::string& key, const std::string& value)
{ {
if (Steam::Proxy::ClientFriends && Steam::Proxy::SteamUtils && !Dvar::Var("cl_anonymous").get<bool>() && Steam::Enabled()) if (Steam::Proxy::ClientFriends && Steam::Proxy::SteamUtils && !Dvar::Var("cl_anonymous").get<bool>() && !Friends::IsInvisible() && Steam::Enabled())
{ {
Friends::SetRawPresence(key.data(), value.data()); Friends::SetRawPresence(key.data(), value.data());
} }
@ -494,6 +494,11 @@ namespace Components
return appId; return appId;
} }
bool Friends::IsInvisible()
{
return Friends::InitialState == 7;
}
void Friends::UpdateTimeStamp() void Friends::UpdateTimeStamp()
{ {
Friends::SetPresence("iw4x_playing", Utils::String::VA("%d", Steam::SteamUtils()->GetServerRealTime())); Friends::SetPresence("iw4x_playing", Utils::String::VA("%d", Steam::SteamUtils()->GetServerRealTime()));
@ -696,10 +701,10 @@ namespace Components
{ {
if (Steam::Proxy::SteamFriends) if (Steam::Proxy::SteamFriends)
{ {
Friends::InitialState = Steam::Proxy::SteamFriends->GetPersonaState(); Friends::InitialState = Steam::Proxy::SteamFriends->GetFriendPersonaState(Steam::Proxy::SteamUser_->GetSteamID());
} }
if (Dvar::Var("cl_anonymous").get<bool>() || !Steam::Enabled()) if (Dvar::Var("cl_anonymous").get<bool>() || Friends::IsInvisible() || !Steam::Enabled())
{ {
if (Steam::Proxy::ClientFriends) if (Steam::Proxy::ClientFriends)
{ {

View File

@ -23,6 +23,8 @@ namespace Components
static int GetGame(SteamID user); static int GetGame(SteamID user);
static bool IsInvisible();
private: private:
#pragma pack(push, 4) #pragma pack(push, 4)
struct FriendRichPresenceUpdate struct FriendRichPresenceUpdate

View File

@ -212,6 +212,11 @@ namespace Components
Utils::OpenUrl(Utils::Cache::GetStaticUrl("/wiki/")); Utils::OpenUrl(Utils::Cache::GetStaticUrl("/wiki/"));
}); });
UIScript::Add("visitDiscord", [](UIScript::Token)
{
Utils::OpenUrl("https://discord.gg/sKeVmR3");
});
Localization::Set("MPUI_CHANGELOG_TEXT", "Loading..."); Localization::Set("MPUI_CHANGELOG_TEXT", "Loading...");
Localization::Set("MPUI_MOTD_TEXT", NEWS_MOTD_DEFAULT); Localization::Set("MPUI_MOTD_TEXT", NEWS_MOTD_DEFAULT);

View File

@ -5,7 +5,7 @@ namespace Components
std::recursive_mutex Node::Mutex; std::recursive_mutex Node::Mutex;
std::vector<Node::Entry> Node::Nodes; std::vector<Node::Entry> Node::Nodes;
bool Node::wasIngame; bool Node::wasIngame = false;
bool Node::Entry::isValid() bool Node::Entry::isValid()
{ {
@ -169,7 +169,7 @@ namespace Components
{ {
if (Dedicated::IsEnabled() && Dvar::Var("sv_lanOnly").get<bool>()) return; if (Dedicated::IsEnabled() && Dvar::Var("sv_lanOnly").get<bool>()) return;
if (Game::CL_IsCgameInitialized()) if (!Dedicated::IsEnabled() && Game::CL_IsCgameInitialized())
{ {
wasIngame = true; wasIngame = true;
return; // don't run while ingame because it can still cause lag spikes on lower end PCs return; // don't run while ingame because it can still cause lag spikes on lower end PCs

View File

@ -110,6 +110,19 @@ namespace Components
} }
} }
Utils::InfoString ServerInfo::GetHostInfo()
{
Utils::InfoString info;
// TODO: Possibly add all Dvar starting with _
info.set("admin", Dvar::Var("_Admin").get<const char*>());
info.set("website", Dvar::Var("_Website").get<const char*>());
info.set("email", Dvar::Var("_Email").get<const char*>());
info.set("location", Dvar::Var("_Location").get<const char*>());
return info;
}
Utils::InfoString ServerInfo::GetInfo() Utils::InfoString ServerInfo::GetInfo()
{ {
int maxclientCount = *Game::svs_numclients; int maxclientCount = *Game::svs_numclients;

View File

@ -8,6 +8,7 @@ namespace Components
ServerInfo(); ServerInfo();
~ServerInfo(); ~ServerInfo();
static Utils::InfoString GetHostInfo();
static Utils::InfoString GetInfo(); static Utils::InfoString GetInfo();
private: private:

View File

@ -207,6 +207,9 @@ namespace Components
{ {
Game::XAssetType type = Game::DB_GetXAssetNameType(typeName.data()); Game::XAssetType type = Game::DB_GetXAssetNameType(typeName.data());
if (name.find(" ", 0) != std::string::npos)
Logger::Print("Warning: asset with name '%s' contains spaces. Check your zone source file to ensure this is correct!\n", name.data());
// Sanitize name for empty assets // Sanitize name for empty assets
if (name[0] == ',') name.erase(name.begin()); if (name[0] == ',') name.erase(name.begin());

View File

@ -1,6 +1,6 @@
#pragma once #pragma once
#define PROTOCOL 0x95 #define PROTOCOL 0x96
#define NUM_CUSTOM_CLASSES 15 #define NUM_CUSTOM_CLASSES 15
#define SEMANTIC_WATER_MAP 11 #define SEMANTIC_WATER_MAP 11
#define FX_ELEM_FIELD_COUNT 90 #define FX_ELEM_FIELD_COUNT 90

View File

@ -86,7 +86,11 @@ namespace Steam
if (ud_insn_mnemonic(&ud) == UD_Iret) if (ud_insn_mnemonic(&ud) == UD_Iret)
{ {
const ud_operand* operand = ud_insn_opr(&ud, 0); const ud_operand* operand = ud_insn_opr(&ud, 0);
if (!operand) break; if (!operand)
{
*params = 0;
return true;
}
if (operand->type == UD_OP_IMM && operand->size == 16) if (operand->type == UD_OP_IMM && operand->size == 16)
{ {
@ -110,6 +114,8 @@ namespace Steam
} }
} }
} }
if (*reinterpret_cast<unsigned char*>(ud.pc) == 0xCC) break;
} }
return false; return false;