[Dvar]: Don't lookup dvar every time we need it (#677)
* [Dvar]: Don't lookup dvar every time we need it * [Console]: Cleanup the code * [Party]: Improve source code quality * [Party]: Update
This commit is contained in:
parent
676854167b
commit
86b402a5a0
@ -1,6 +1,8 @@
|
||||
#include <STDInclude.hpp>
|
||||
#include "Console.hpp"
|
||||
|
||||
#include "Terminus_4.49.1.ttf.hpp"
|
||||
|
||||
#include <version.hpp>
|
||||
|
||||
#ifdef MOUSE_MOVED
|
||||
@ -32,14 +34,14 @@ namespace Components
|
||||
bool Console::SkipShutdown = false;
|
||||
|
||||
COLORREF Console::TextColor =
|
||||
#if DEBUG
|
||||
#if _DEBUG
|
||||
RGB(255, 200, 117);
|
||||
#else
|
||||
RGB(120, 237, 122);
|
||||
#endif
|
||||
|
||||
COLORREF Console::BackgroundColor =
|
||||
#if DEBUG
|
||||
#if _DEBUG
|
||||
RGB(35, 21, 0);
|
||||
#else
|
||||
RGB(25, 32, 25);
|
||||
@ -64,16 +66,16 @@ namespace Components
|
||||
const std::string mapname = (*Game::sv_mapname)->current.string;
|
||||
const auto hostname = TextRenderer::StripColors((*Game::sv_hostname)->current.string);
|
||||
|
||||
if (Console::HasConsole)
|
||||
if (HasConsole)
|
||||
{
|
||||
SetConsoleTitleA(hostname.data());
|
||||
|
||||
auto clientCount = 0;
|
||||
auto maxclientCount = *Game::svs_clientCount;
|
||||
auto maxClientCount = *Game::svs_clientCount;
|
||||
|
||||
if (maxclientCount)
|
||||
if (maxClientCount)
|
||||
{
|
||||
for (int i = 0; i < maxclientCount; ++i)
|
||||
for (auto i = 0; i < maxClientCount; ++i)
|
||||
{
|
||||
if (Game::svs_clients[i].header.state >= Game::CS_CONNECTED)
|
||||
{
|
||||
@ -83,18 +85,17 @@ namespace Components
|
||||
}
|
||||
else
|
||||
{
|
||||
maxclientCount = Dvar::Var("party_maxplayers").get<int>();
|
||||
//maxclientCount = Game::Party_GetMaxPlayers(*Game::partyIngame);
|
||||
clientCount = Game::PartyHost_CountMembers(reinterpret_cast<Game::PartyData*>(0x1081C00));
|
||||
maxClientCount = *Game::party_maxplayers ? (*Game::party_maxplayers)->current.integer : 18;
|
||||
clientCount = Game::PartyHost_CountMembers(Game::g_lobbyData);
|
||||
}
|
||||
|
||||
wclear(InfoWindow);
|
||||
wprintw(InfoWindow, "%s : %d/%d players : map %s", hostname.data(), clientCount, maxclientCount, (!mapname.empty()) ? mapname.data() : "none");
|
||||
wprintw(InfoWindow, "%s : %d/%d players : map %s", hostname.data(), clientCount, maxClientCount, (!mapname.empty()) ? mapname.data() : "none");
|
||||
wnoutrefresh(InfoWindow);
|
||||
}
|
||||
else if (IsWindow(Console::GetWindow()) != FALSE)
|
||||
else if (IsWindow(GetWindow()) != FALSE)
|
||||
{
|
||||
SetWindowTextA(Console::GetWindow(), Utils::String::VA("IW4x(" VERSION ") : %s", hostname.data()));
|
||||
SetWindowTextA(GetWindow(), Utils::String::VA("IW4x(" VERSION ") : %s", hostname.data()));
|
||||
}
|
||||
}
|
||||
|
||||
@ -106,35 +107,35 @@ namespace Components
|
||||
|
||||
void Console::RefreshOutput()
|
||||
{
|
||||
prefresh(OutputWindow, ((Console::OutputTop > 0) ? (Console::OutputTop - 1) : 0), 0, 1, 0, Console::Height - 2, Console::Width - 1);
|
||||
prefresh(OutputWindow, ((OutputTop > 0) ? (OutputTop - 1) : 0), 0, 1, 0, Height - 2, Width - 1);
|
||||
}
|
||||
|
||||
void Console::ScrollOutput(int amount)
|
||||
{
|
||||
Console::OutputTop += amount;
|
||||
OutputTop += amount;
|
||||
|
||||
if (Console::OutputTop > OUTPUT_MAX_TOP)
|
||||
if (OutputTop > OUTPUT_MAX_TOP)
|
||||
{
|
||||
Console::OutputTop = OUTPUT_MAX_TOP;
|
||||
OutputTop = OUTPUT_MAX_TOP;
|
||||
}
|
||||
else if (Console::OutputTop < 0)
|
||||
else if (OutputTop < 0)
|
||||
{
|
||||
Console::OutputTop = 0;
|
||||
OutputTop = 0;
|
||||
}
|
||||
|
||||
// make it only scroll the top if there's more than HEIGHT lines
|
||||
if (Console::OutBuffer >= 0)
|
||||
if (OutBuffer >= 0)
|
||||
{
|
||||
Console::OutBuffer += amount;
|
||||
OutBuffer += amount;
|
||||
|
||||
if (Console::OutBuffer >= Console::Height)
|
||||
if (OutBuffer >= Height)
|
||||
{
|
||||
Console::OutBuffer = -1;
|
||||
OutBuffer = -1;
|
||||
}
|
||||
|
||||
if (Console::OutputTop < Console::Height)
|
||||
if (OutputTop < Height)
|
||||
{
|
||||
Console::OutputTop = 0;
|
||||
OutputTop = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -149,17 +150,13 @@ namespace Components
|
||||
|
||||
if (getDpiForWindow)
|
||||
{
|
||||
dpi = getDpiForWindow(hWnd);
|
||||
dpi = static_cast<int>(getDpiForWindow(hWnd));
|
||||
}
|
||||
else if (getDpiForMonitor)
|
||||
{
|
||||
HMONITOR hMonitor = MonitorFromWindow(hWnd, MONITOR_DEFAULTTONEAREST);
|
||||
UINT xdpi, ydpi;
|
||||
LRESULT success = getDpiForMonitor(hMonitor, 0, &xdpi, &ydpi);
|
||||
if (success == S_OK)
|
||||
{
|
||||
dpi = static_cast<int>(ydpi);
|
||||
}
|
||||
getDpiForMonitor(hMonitor, 0, &xdpi, &ydpi);
|
||||
|
||||
dpi = 96;
|
||||
}
|
||||
@ -167,33 +164,33 @@ namespace Components
|
||||
{
|
||||
HDC hDC = GetDC(hWnd);
|
||||
INT ydpi = GetDeviceCaps(hDC, LOGPIXELSY);
|
||||
ReleaseDC(NULL, hDC);
|
||||
ReleaseDC(nullptr, hDC);
|
||||
|
||||
dpi = ydpi;
|
||||
}
|
||||
|
||||
constexpr auto unawareDpi = 96.0f;
|
||||
return dpi / unawareDpi;
|
||||
return static_cast<float>(dpi) / unawareDpi;
|
||||
}
|
||||
|
||||
|
||||
const char* Console::Input()
|
||||
{
|
||||
if (!Console::HasConsole)
|
||||
if (!HasConsole)
|
||||
{
|
||||
Console::ShowPrompt();
|
||||
ShowPrompt();
|
||||
wrefresh(InputWindow);
|
||||
Console::HasConsole = true;
|
||||
HasConsole = true;
|
||||
}
|
||||
|
||||
int currentTime = static_cast<int>(GetTickCount64()); // Make our compiler happy
|
||||
if ((currentTime - Console::LastRefresh) > 250)
|
||||
auto currentTime = static_cast<int>(GetTickCount64()); // Make our compiler happy
|
||||
if ((currentTime - LastRefresh) > 250)
|
||||
{
|
||||
Console::RefreshOutput();
|
||||
Console::LastRefresh = currentTime;
|
||||
RefreshOutput();
|
||||
LastRefresh = currentTime;
|
||||
}
|
||||
|
||||
int c = wgetch(InputWindow);
|
||||
auto c = wgetch(InputWindow);
|
||||
|
||||
if (c == ERR)
|
||||
{
|
||||
@ -208,28 +205,28 @@ namespace Components
|
||||
wattron(OutputWindow, COLOR_PAIR(10) | A_BOLD);
|
||||
wprintw(OutputWindow, "%s", "]");
|
||||
|
||||
if (Console::LineBufferIndex)
|
||||
if (LineBufferIndex)
|
||||
{
|
||||
wprintw(OutputWindow, "%s", Console::LineBuffer);
|
||||
wprintw(OutputWindow, "%s", LineBuffer);
|
||||
}
|
||||
|
||||
wprintw(OutputWindow, "%s", "\n");
|
||||
wattroff(OutputWindow, A_BOLD);
|
||||
wclear(InputWindow);
|
||||
|
||||
Console::ShowPrompt();
|
||||
ShowPrompt();
|
||||
|
||||
wrefresh(InputWindow);
|
||||
|
||||
Console::ScrollOutput(1);
|
||||
Console::RefreshOutput();
|
||||
ScrollOutput(1);
|
||||
RefreshOutput();
|
||||
|
||||
if (Console::LineBufferIndex)
|
||||
if (LineBufferIndex)
|
||||
{
|
||||
strcpy_s(Console::LineBuffer2, Console::LineBuffer);
|
||||
strcat_s(Console::LineBuffer, "\n");
|
||||
Console::LineBufferIndex = 0;
|
||||
return Console::LineBuffer;
|
||||
strcpy_s(LineBuffer2, LineBuffer);
|
||||
strcat_s(LineBuffer, "\n");
|
||||
LineBufferIndex = 0;
|
||||
return LineBuffer;
|
||||
}
|
||||
|
||||
break;
|
||||
@ -237,22 +234,22 @@ namespace Components
|
||||
case 'c' - 'a' + 1: // ctrl-c
|
||||
case 27:
|
||||
{
|
||||
Console::LineBuffer[0] = '\0';
|
||||
Console::LineBufferIndex = 0;
|
||||
LineBuffer[0] = '\0';
|
||||
LineBufferIndex = 0;
|
||||
|
||||
wclear(InputWindow);
|
||||
|
||||
Console::ShowPrompt();
|
||||
ShowPrompt();
|
||||
|
||||
wrefresh(InputWindow);
|
||||
break;
|
||||
}
|
||||
case 8: // backspace
|
||||
{
|
||||
if (Console::LineBufferIndex > 0)
|
||||
if (LineBufferIndex > 0)
|
||||
{
|
||||
Console::LineBufferIndex--;
|
||||
Console::LineBuffer[Console::LineBufferIndex] = '\0';
|
||||
LineBufferIndex--;
|
||||
LineBuffer[LineBufferIndex] = '\0';
|
||||
|
||||
wprintw(InputWindow, "%c %c", static_cast<char>(c), static_cast<char>(c));
|
||||
wrefresh(InputWindow);
|
||||
@ -261,35 +258,35 @@ namespace Components
|
||||
}
|
||||
case KEY_PPAGE:
|
||||
{
|
||||
Console::ScrollOutput(-1);
|
||||
Console::RefreshOutput();
|
||||
ScrollOutput(-1);
|
||||
RefreshOutput();
|
||||
break;
|
||||
}
|
||||
case KEY_NPAGE:
|
||||
{
|
||||
Console::ScrollOutput(1);
|
||||
Console::RefreshOutput();
|
||||
ScrollOutput(1);
|
||||
RefreshOutput();
|
||||
break;
|
||||
}
|
||||
case KEY_UP:
|
||||
{
|
||||
wclear(InputWindow);
|
||||
Console::ShowPrompt();
|
||||
wprintw(InputWindow, "%s", Console::LineBuffer2);
|
||||
ShowPrompt();
|
||||
wprintw(InputWindow, "%s", LineBuffer2);
|
||||
wrefresh(InputWindow);
|
||||
|
||||
strcpy_s(Console::LineBuffer, Console::LineBuffer2);
|
||||
Console::LineBufferIndex = strlen(Console::LineBuffer);
|
||||
strcpy_s(LineBuffer, LineBuffer2);
|
||||
LineBufferIndex = static_cast<int>(std::strlen(LineBuffer));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
if (c <= 127 && Console::LineBufferIndex < 1022)
|
||||
if (c <= 127 && LineBufferIndex < 1022)
|
||||
{
|
||||
// temporary workaround , find out what overwrites our index later on
|
||||
// temporary workaround, find out what overwrites our index later on
|
||||
//consoleLineBufferIndex = strlen(consoleLineBuffer);
|
||||
|
||||
Console::LineBuffer[Console::LineBufferIndex++] = static_cast<char>(c);
|
||||
Console::LineBuffer[Console::LineBufferIndex] = '\0';
|
||||
LineBuffer[LineBufferIndex++] = static_cast<char>(c);
|
||||
LineBuffer[LineBufferIndex] = '\0';
|
||||
wprintw(InputWindow, "%c", static_cast<char>(c));
|
||||
wrefresh(InputWindow);
|
||||
}
|
||||
@ -318,31 +315,31 @@ namespace Components
|
||||
|
||||
void Console::Create()
|
||||
{
|
||||
Console::OutputTop = 0;
|
||||
Console::OutBuffer = 0;
|
||||
Console::LastRefresh = 0;
|
||||
Console::LineBufferIndex = 0;
|
||||
Console::HasConsole = false;
|
||||
OutputTop = 0;
|
||||
OutBuffer = 0;
|
||||
LastRefresh = 0;
|
||||
LineBufferIndex = 0;
|
||||
HasConsole = false;
|
||||
|
||||
CONSOLE_SCREEN_BUFFER_INFO info;
|
||||
if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &info))
|
||||
{
|
||||
Console::Width = info.dwSize.X;
|
||||
Console::Height = info.srWindow.Bottom - info.srWindow.Top + 1;
|
||||
Width = info.dwSize.X;
|
||||
Height = info.srWindow.Bottom - info.srWindow.Top + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
Console::Height = 25;
|
||||
Console::Width = 80;
|
||||
Height = 25;
|
||||
Width = 80;
|
||||
}
|
||||
|
||||
initscr();
|
||||
raw();
|
||||
noecho();
|
||||
|
||||
OutputWindow = newpad(Console::Height - 1, Console::Width);
|
||||
InputWindow = newwin(1, Console::Width, Console::Height - 1, 0);
|
||||
InfoWindow = newwin(1, Console::Width, 0, 0);
|
||||
OutputWindow = newpad(Height - 1, Width);
|
||||
InputWindow = newwin(1, Width, Height - 1, 0);
|
||||
InfoWindow = newwin(1, Width, 0, 0);
|
||||
|
||||
scrollok(OutputWindow, true);
|
||||
idlok(OutputWindow, true);
|
||||
@ -370,7 +367,7 @@ namespace Components
|
||||
wrefresh(InfoWindow);
|
||||
wrefresh(InputWindow);
|
||||
|
||||
Console::RefreshOutput();
|
||||
RefreshOutput();
|
||||
}
|
||||
|
||||
void Console::Error(const char* fmt, ...)
|
||||
@ -384,7 +381,7 @@ namespace Components
|
||||
|
||||
Logger::PrintError(Game::CON_CHANNEL_ERROR, "{}\n", buf);
|
||||
|
||||
Console::RefreshOutput();
|
||||
RefreshOutput();
|
||||
|
||||
if (IsDebuggerPresent())
|
||||
{
|
||||
@ -394,7 +391,7 @@ namespace Components
|
||||
}
|
||||
}
|
||||
|
||||
TerminateProcess(GetCurrentProcess(), 0xDEADDEAD);
|
||||
TerminateProcess(GetCurrentProcess(), EXIT_FAILURE);
|
||||
}
|
||||
|
||||
void Console::Print(const char* message)
|
||||
@ -406,11 +403,9 @@ namespace Components
|
||||
{
|
||||
if (*p == '^')
|
||||
{
|
||||
char color;
|
||||
++p;
|
||||
|
||||
color = (*p - '0');
|
||||
|
||||
const char color = (*p - '0');
|
||||
if (color < 9 && color > 0)
|
||||
{
|
||||
wattron(OutputWindow, COLOR_PAIR(color + 2));
|
||||
@ -426,26 +421,26 @@ namespace Components
|
||||
|
||||
wattron(OutputWindow, COLOR_PAIR(9));
|
||||
|
||||
Console::RefreshOutput();
|
||||
RefreshOutput();
|
||||
}
|
||||
|
||||
HFONT __stdcall Console::ReplaceFont(
|
||||
[[maybe_unused]] int cHeight,
|
||||
int cWidth,
|
||||
int cEscapement,
|
||||
int cOrientation,
|
||||
[[maybe_unused]] int cWeight,
|
||||
DWORD bItalic,
|
||||
DWORD bUnderline,
|
||||
DWORD bStrikeOut,
|
||||
DWORD iCharSet,
|
||||
[[maybe_unused]] DWORD iOutPrecision,
|
||||
DWORD iClipPrecision,
|
||||
[[maybe_unused]] DWORD iQuality,
|
||||
[[maybe_unused]] DWORD iPitchAndFamily,
|
||||
HFONT CALLBACK Console::ReplaceFont(
|
||||
[[maybe_unused]] int cHeight,
|
||||
int cWidth,
|
||||
int cEscapement,
|
||||
int cOrientation,
|
||||
[[maybe_unused]] int cWeight,
|
||||
DWORD bItalic,
|
||||
DWORD bUnderline,
|
||||
DWORD bStrikeOut,
|
||||
DWORD iCharSet,
|
||||
[[maybe_unused]] DWORD iOutPrecision,
|
||||
DWORD iClipPrecision,
|
||||
[[maybe_unused]] DWORD iQuality,
|
||||
[[maybe_unused]] DWORD iPitchAndFamily,
|
||||
[[maybe_unused]] LPCSTR pszFaceName)
|
||||
{
|
||||
auto font = CreateFontA(
|
||||
HFONT font = CreateFontA(
|
||||
12,
|
||||
cWidth,
|
||||
cEscapement,
|
||||
@ -459,7 +454,8 @@ namespace Components
|
||||
iClipPrecision,
|
||||
NONANTIALIASED_QUALITY,
|
||||
0x31,
|
||||
"Terminus (TTF)"); // Terminus (TTF)
|
||||
"Terminus (TTF)"
|
||||
); // Terminus (TTF)
|
||||
|
||||
return font;
|
||||
}
|
||||
@ -467,7 +463,7 @@ namespace Components
|
||||
void Console::GetWindowPos(HWND hWnd, int* x, int* y)
|
||||
{
|
||||
HWND hWndParent = GetParent(hWnd);
|
||||
POINT p = { 0 };
|
||||
POINT p{};
|
||||
|
||||
MapWindowPoints(hWnd, hWndParent, &p, 1);
|
||||
|
||||
@ -478,8 +474,8 @@ namespace Components
|
||||
BOOL CALLBACK Console::ResizeChildWindow(HWND hwndChild, LPARAM lParam)
|
||||
{
|
||||
auto id = GetWindowLong(hwndChild, GWL_ID);
|
||||
bool isInputBox = id == INPUT_BOX;
|
||||
bool isOutputBox = id == OUTPUT_BOX;
|
||||
auto isInputBox = id == INPUT_BOX;
|
||||
auto isOutputBox = id == OUTPUT_BOX;
|
||||
|
||||
if (isInputBox || isOutputBox)
|
||||
{
|
||||
@ -496,31 +492,31 @@ namespace Components
|
||||
|
||||
HWND parent = Utils::Hook::Get<HWND>(0x64A3288);
|
||||
|
||||
float scale = GetDpiScale(parent);
|
||||
auto scale = GetDpiScale(parent);
|
||||
|
||||
if (isInputBox)
|
||||
{
|
||||
|
||||
int newX = childX; // No change!
|
||||
int newY = static_cast<int>((newParentRect.bottom - newParentRect.top) - 65 * scale);
|
||||
int newWidth = static_cast<int>((newParentRect.right - newParentRect.left) - 29 * scale);
|
||||
int newHeight = static_cast<int>((childRect.bottom - childRect.top) * scale); // No change!
|
||||
auto newX = childX; // No change!
|
||||
auto newY = static_cast<int>((newParentRect.bottom - newParentRect.top) - 65 * scale);
|
||||
auto newWidth = static_cast<int>((newParentRect.right - newParentRect.left) - 29 * scale);
|
||||
auto newHeight = static_cast<int>((childRect.bottom - childRect.top) * scale); // No change!
|
||||
|
||||
MoveWindow(hwndChild, newX, newY, newWidth, newHeight, TRUE);
|
||||
}
|
||||
|
||||
if (isOutputBox)
|
||||
{
|
||||
int newX = childX; // No change!
|
||||
int newY = childY; // No change!
|
||||
int newWidth = static_cast<int>((newParentRect.right - newParentRect.left) - 29);
|
||||
|
||||
int margin = 70;
|
||||
auto newX = childX; // No change!
|
||||
auto newY = childY; // No change!
|
||||
auto newWidth = static_cast<int>((newParentRect.right - newParentRect.left) - 29);
|
||||
|
||||
#ifdef REMOVE_HEADERBAR
|
||||
margin = 10;
|
||||
constexpr auto margin = 10;
|
||||
#else
|
||||
constexpr auto margin = 70;
|
||||
#endif
|
||||
int newHeight = static_cast<int>((newParentRect.bottom - newParentRect.top) - 74 * scale - margin);
|
||||
auto newHeight = static_cast<int>((newParentRect.bottom - newParentRect.top) - 74 * scale - margin);
|
||||
|
||||
MoveWindow(hwndChild, newX, newY, newWidth, newHeight, TRUE);
|
||||
}
|
||||
@ -536,23 +532,21 @@ namespace Components
|
||||
// around whenever clearing occurs.
|
||||
void Console::MakeRoomForText([[maybe_unused]] int addedCharacters)
|
||||
{
|
||||
constexpr unsigned int maxChars = 0x4000;
|
||||
constexpr unsigned int maxAffectedChars = 0x100;
|
||||
constexpr auto maxChars = 0x4000;
|
||||
constexpr auto maxAffectedChars = 0x100;
|
||||
HWND outputBox = Utils::Hook::Get<HWND>(0x64A328C);
|
||||
|
||||
unsigned int totalChars;
|
||||
unsigned int totalClearLength = 0;
|
||||
auto totalClearLength = 0;
|
||||
|
||||
char str[maxAffectedChars];
|
||||
unsigned int fetchedCharacters = static_cast<unsigned int>(GetWindowText(outputBox, str, maxAffectedChars));
|
||||
|
||||
totalChars = GetWindowTextLengthA(outputBox);
|
||||
const auto fetchedCharacters = GetWindowTextA(outputBox, str, maxAffectedChars);
|
||||
|
||||
auto totalChars = GetWindowTextLengthA(outputBox);
|
||||
while (totalChars - totalClearLength > maxChars)
|
||||
{
|
||||
unsigned int clearLength = maxAffectedChars; // Default to full clear
|
||||
auto clearLength = maxAffectedChars; // Default to full clear
|
||||
|
||||
for (size_t i = 0; i < fetchedCharacters; i++)
|
||||
for (auto i = 0; i < fetchedCharacters; i++)
|
||||
{
|
||||
if (str[i] == '\n')
|
||||
{
|
||||
@ -567,10 +561,10 @@ namespace Components
|
||||
|
||||
if (totalClearLength > 0)
|
||||
{
|
||||
SendMessage(outputBox, WM_SETREDRAW, FALSE, 0);
|
||||
SendMessage(outputBox, EM_SETSEL, 0, totalClearLength);
|
||||
SendMessage(outputBox, EM_REPLACESEL, FALSE, 0);
|
||||
SendMessage(outputBox, WM_SETREDRAW, TRUE, 0);
|
||||
SendMessageA(outputBox, WM_SETREDRAW, FALSE, 0);
|
||||
SendMessageA(outputBox, EM_SETSEL, 0, totalClearLength);
|
||||
SendMessageA(outputBox, EM_REPLACESEL, FALSE, 0);
|
||||
SendMessageA(outputBox, WM_SETREDRAW, TRUE, 0);
|
||||
}
|
||||
|
||||
Utils::Hook::Set(0x64A38B8, totalChars - totalClearLength);
|
||||
@ -596,18 +590,11 @@ namespace Components
|
||||
{
|
||||
switch (Msg)
|
||||
{
|
||||
|
||||
|
||||
case WM_CREATE:
|
||||
{
|
||||
BOOL darkMode = true;
|
||||
|
||||
#define DWMWA_USE_IMMERSIVE_DARK_MODE 20
|
||||
if (SUCCEEDED(DwmSetWindowAttribute(hWnd, DWMWA_USE_IMMERSIVE_DARK_MODE, reinterpret_cast<LPCVOID>(&darkMode), sizeof(darkMode))))
|
||||
{
|
||||
// cool !
|
||||
}
|
||||
|
||||
BOOL darkMode = TRUE;
|
||||
constexpr auto DWMWA_USE_IMMERSIVE_DARK_MODE = 20;
|
||||
DwmSetWindowAttribute(hWnd, DWMWA_USE_IMMERSIVE_DARK_MODE, &darkMode, sizeof(darkMode));
|
||||
break;
|
||||
}
|
||||
|
||||
@ -630,7 +617,6 @@ namespace Components
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Fall through to basegame
|
||||
return Utils::Hook::Call<LRESULT CALLBACK(HWND, UINT, WPARAM, unsigned int)>(0x64DC50)(hWnd, Msg, wParam, lParam);
|
||||
}
|
||||
|
||||
@ -645,14 +631,14 @@ namespace Components
|
||||
|
||||
void Console::ApplyConsoleStyle()
|
||||
{
|
||||
Utils::Hook::Set<BYTE>(0x428A8E, 0); // Adjust logo Y pos
|
||||
Utils::Hook::Set<BYTE>(0x428A90, 0); // Adjust logo X pos
|
||||
Utils::Hook::Set<BYTE>(0x428AF2, 67); // Adjust output Y pos
|
||||
Utils::Hook::Set<DWORD>(0x428AC5, 397); // Adjust input Y pos
|
||||
Utils::Hook::Set<DWORD>(0x428951, 609); // Reduce window width
|
||||
Utils::Hook::Set<DWORD>(0x42895D, 423); // Reduce window height
|
||||
Utils::Hook::Set<DWORD>(0x428AC0, 597); // Reduce input width
|
||||
Utils::Hook::Set<DWORD>(0x428AED, 596); // Reduce output width
|
||||
Utils::Hook::Set<std::uint8_t>(0x428A8E, 0); // Adjust logo Y pos
|
||||
Utils::Hook::Set<std::uint8_t>(0x428A90, 0); // Adjust logo X pos
|
||||
Utils::Hook::Set<std::uint8_t>(0x428AF2, 67); // Adjust output Y pos
|
||||
Utils::Hook::Set<std::uint32_t>(0x428AC5, 397); // Adjust input Y pos
|
||||
Utils::Hook::Set<std::uint32_t>(0x428951, 609); // Reduce window width
|
||||
Utils::Hook::Set<std::uint32_t>(0x42895D, 423); // Reduce window height
|
||||
Utils::Hook::Set<std::uint32_t>(0x428AC0, 597); // Reduce input width
|
||||
Utils::Hook::Set<std::uint32_t>(0x428AED, 596); // Reduce output width
|
||||
|
||||
DWORD fontsInstalled;
|
||||
CustomConsoleFont = AddFontMemResourceEx(const_cast<void*>(reinterpret_cast<const void*>(Font::Terminus::DATA)), Font::Terminus::LENGTH, 0, &fontsInstalled);
|
||||
@ -680,35 +666,37 @@ namespace Components
|
||||
|
||||
// Never reset text
|
||||
Utils::Hook::Nop(0x4F57DF, 0x4F57F6 - 0x4F57DF);
|
||||
Utils::Hook(0x4F57DF, Console::Sys_PrintStub, HOOK_JUMP).install()->quick();
|
||||
Utils::Hook(0x4F57DF, Sys_PrintStub, HOOK_JUMP).install()->quick();
|
||||
|
||||
}
|
||||
|
||||
void Console::ConsoleRunner()
|
||||
{
|
||||
Console::SkipShutdown = false;
|
||||
SkipShutdown = false;
|
||||
Game::Sys_ShowConsole();
|
||||
|
||||
MSG message;
|
||||
while (IsWindow(Console::GetWindow()) != FALSE && GetMessageA(&message, nullptr, 0, 0))
|
||||
while (IsWindow(GetWindow()) != FALSE && GetMessageA(&message, nullptr, 0, 0))
|
||||
{
|
||||
TranslateMessage(&message);
|
||||
DispatchMessageA(&message);
|
||||
}
|
||||
|
||||
if (Console::SkipShutdown) return;
|
||||
if (SkipShutdown) return;
|
||||
|
||||
if (Game::Sys_Milliseconds() - Console::LastRefresh > 100 &&
|
||||
if (Game::Sys_Milliseconds() -LastRefresh > 100 &&
|
||||
MessageBoxA(nullptr, "The application is not responding anymore, do you want to force its termination?", "Application is not responding", MB_ICONEXCLAMATION | MB_YESNO) == IDYES)
|
||||
{
|
||||
// Force process termination
|
||||
// if the main thread is not responding
|
||||
OutputDebugStringA("Process termination forced, as the main thread is not responding!");
|
||||
#ifdef _DEBUG
|
||||
OutputDebugStringA("Process termination was forced as the main thread is not responding!");
|
||||
#endif
|
||||
|
||||
// We can not force the termination in this thread
|
||||
// The destructor would be called in this thread
|
||||
// and would try to join this thread, which is impossible
|
||||
TerminateProcess(GetCurrentProcess(), 0xFFFFFFFF);
|
||||
TerminateProcess(GetCurrentProcess(), EXIT_FAILURE);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -729,7 +717,7 @@ namespace Components
|
||||
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
_vsnprintf_s(buffer, _TRUNCATE, fmt, ap);
|
||||
vsnprintf_s(buffer, _TRUNCATE, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
perror(buffer);
|
||||
@ -759,7 +747,7 @@ namespace Components
|
||||
void Console::StoreSafeArea()
|
||||
{
|
||||
// Backup the original safe area
|
||||
Console::OriginalSafeArea = *Game::safeArea;
|
||||
OriginalSafeArea = *Game::safeArea;
|
||||
|
||||
// Apply new safe area and border
|
||||
float border = 6.0f;
|
||||
@ -775,12 +763,12 @@ namespace Components
|
||||
void Console::RestoreSafeArea()
|
||||
{
|
||||
// Restore the initial safe area
|
||||
*Game::safeArea = Console::OriginalSafeArea;
|
||||
*Game::safeArea = OriginalSafeArea;
|
||||
}
|
||||
|
||||
void Console::SetSkipShutdown()
|
||||
{
|
||||
Console::SkipShutdown = true;
|
||||
SkipShutdown = true;
|
||||
}
|
||||
|
||||
void Console::FreeNativeConsole()
|
||||
@ -798,11 +786,10 @@ namespace Components
|
||||
|
||||
void Console::ShowAsyncConsole()
|
||||
{
|
||||
Console::ConsoleThread = std::thread(Console::ConsoleRunner);
|
||||
ConsoleThread = std::thread(ConsoleRunner);
|
||||
}
|
||||
|
||||
Game::dvar_t* Console::RegisterConColor(const char* dvarName, float r, float g, float b, float a, float min,
|
||||
float max, unsigned __int16 flags, const char* description)
|
||||
Game::dvar_t* Console::RegisterConColor(const char* dvarName, float r, float g, float b, float a, float min, float max, unsigned __int16 flags, const char* description)
|
||||
{
|
||||
static struct
|
||||
{
|
||||
@ -857,7 +844,7 @@ namespace Components
|
||||
{
|
||||
Command::Add("con_echo", []
|
||||
{
|
||||
Console::Con_ToggleConsole();
|
||||
Con_ToggleConsole();
|
||||
Game::I_strncpyz(Game::g_consoleField->buffer, "\\echo ", sizeof(Game::field_t::buffer));
|
||||
Game::g_consoleField->cursor = static_cast<int>(std::strlen(Game::g_consoleField->buffer));
|
||||
Game::Field_AdjustScroll(Game::ScrPlace_GetFullPlacement(), Game::g_consoleField);
|
||||
@ -878,24 +865,24 @@ namespace Components
|
||||
Utils::Hook::Set<float*>(0x5A4400, consoleColor);
|
||||
|
||||
// Remove the need to type '\' or '/' to send a console command
|
||||
Utils::Hook::Set<BYTE>(0x431565, 0xEB);
|
||||
Utils::Hook::Set<std::uint8_t>(0x431565, 0xEB);
|
||||
|
||||
// Internal console
|
||||
Utils::Hook(0x4F690C, Console::Con_ToggleConsole, HOOK_CALL).install()->quick();
|
||||
Utils::Hook(0x4F65A5, Console::Con_ToggleConsole, HOOK_JUMP).install()->quick();
|
||||
Utils::Hook(0x4F690C, Con_ToggleConsole, HOOK_CALL).install()->quick();
|
||||
Utils::Hook(0x4F65A5, Con_ToggleConsole, HOOK_JUMP).install()->quick();
|
||||
|
||||
// Patch safearea for ingame-console
|
||||
Utils::Hook(0x5A50EF, Console::DrawSolidConsoleStub, HOOK_CALL).install()->quick();
|
||||
Utils::Hook(0x5A50EF, DrawSolidConsoleStub, HOOK_CALL).install()->quick();
|
||||
|
||||
// Check for bad food ;)
|
||||
Utils::Hook(0x4CB9F4, Console::GetAutoCompleteFileList, HOOK_CALL).install()->quick();
|
||||
Utils::Hook(0x4CB9F4, GetAutoCompleteFileList, HOOK_CALL).install()->quick();
|
||||
|
||||
// Patch console dvars
|
||||
Utils::Hook(0x4829AB, Console::RegisterConColor, HOOK_CALL).install()->quick();
|
||||
Utils::Hook(0x4829EE, Console::RegisterConColor, HOOK_CALL).install()->quick();
|
||||
Utils::Hook(0x482A31, Console::RegisterConColor, HOOK_CALL).install()->quick();
|
||||
Utils::Hook(0x482A7A, Console::RegisterConColor, HOOK_CALL).install()->quick();
|
||||
Utils::Hook(0x482AC3, Console::RegisterConColor, HOOK_CALL).install()->quick();
|
||||
Utils::Hook(0x4829AB, RegisterConColor, HOOK_CALL).install()->quick();
|
||||
Utils::Hook(0x4829EE, RegisterConColor, HOOK_CALL).install()->quick();
|
||||
Utils::Hook(0x482A31, RegisterConColor, HOOK_CALL).install()->quick();
|
||||
Utils::Hook(0x482A7A, RegisterConColor, HOOK_CALL).install()->quick();
|
||||
Utils::Hook(0x482AC3, RegisterConColor, HOOK_CALL).install()->quick();
|
||||
|
||||
// Modify console style
|
||||
ApplyConsoleStyle();
|
||||
@ -909,7 +896,7 @@ namespace Components
|
||||
|
||||
if (Dedicated::IsEnabled() && !ZoneBuilder::IsEnabled())
|
||||
{
|
||||
Scheduler::Loop(Console::RefreshStatus, Scheduler::Pipeline::MAIN);
|
||||
Scheduler::Loop(RefreshStatus, Scheduler::Pipeline::MAIN);
|
||||
}
|
||||
|
||||
// Code below is not necessary when performing unit tests!
|
||||
@ -918,8 +905,8 @@ namespace Components
|
||||
// External console
|
||||
if (Flags::HasFlag("stdout"))
|
||||
{
|
||||
Utils::Hook(0x4B2080, Console::StdOutPrint, HOOK_JUMP).install()->quick();
|
||||
Utils::Hook(0x43D570, Console::StdOutError, HOOK_JUMP).install()->quick();
|
||||
Utils::Hook(0x4B2080, StdOutPrint, HOOK_JUMP).install()->quick();
|
||||
Utils::Hook(0x43D570, StdOutError, HOOK_JUMP).install()->quick();
|
||||
}
|
||||
else if (Flags::HasFlag("console") || ZoneBuilder::IsEnabled()) // ZoneBuilder uses the game's console, until the native one is adapted.
|
||||
{
|
||||
@ -930,28 +917,28 @@ namespace Components
|
||||
|
||||
Utils::Hook(0x60BB68, []
|
||||
{
|
||||
Console::ShowAsyncConsole();
|
||||
ShowAsyncConsole();
|
||||
}, HOOK_CALL).install()->quick();
|
||||
|
||||
Utils::Hook(0x4D69A2, []()
|
||||
Utils::Hook(0x4D69A2, []
|
||||
{
|
||||
Console::SetSkipShutdown();
|
||||
SetSkipShutdown();
|
||||
|
||||
// Sys_DestroyConsole
|
||||
Utils::Hook::Call<void()>(0x4528A0)();
|
||||
|
||||
if (Console::ConsoleThread.joinable())
|
||||
if (ConsoleThread.joinable())
|
||||
{
|
||||
Console::ConsoleThread.join();
|
||||
ConsoleThread.join();
|
||||
}
|
||||
}, HOOK_CALL).install()->quick();
|
||||
|
||||
Scheduler::Loop([]
|
||||
{
|
||||
Console::LastRefresh = Game::Sys_Milliseconds();
|
||||
LastRefresh = Game::Sys_Milliseconds();
|
||||
}, Scheduler::Pipeline::MAIN);
|
||||
}
|
||||
else if (Dedicated::IsEnabled()/* || ZoneBuilder::IsEnabled()*/)
|
||||
else if (Dedicated::IsEnabled())
|
||||
{
|
||||
DWORD type = GetFileType(GetStdHandle(STD_INPUT_HANDLE));
|
||||
if (type != FILE_TYPE_CHAR)
|
||||
@ -962,11 +949,11 @@ namespace Components
|
||||
|
||||
Utils::Hook::Nop(0x60BB58, 11);
|
||||
|
||||
Utils::Hook(0x4305E0, Console::Create, HOOK_JUMP).install()->quick();
|
||||
Utils::Hook(0x4528A0, Console::Destroy, HOOK_JUMP).install()->quick();
|
||||
Utils::Hook(0x4B2080, Console::Print, HOOK_JUMP).install()->quick();
|
||||
Utils::Hook(0x43D570, Console::Error, HOOK_JUMP).install()->quick();
|
||||
Utils::Hook(0x4859A5, Console::Input, HOOK_CALL).install()->quick();
|
||||
Utils::Hook(0x4305E0, Create, HOOK_JUMP).install()->quick();
|
||||
Utils::Hook(0x4528A0, Destroy, HOOK_JUMP).install()->quick();
|
||||
Utils::Hook(0x4B2080, Print, HOOK_JUMP).install()->quick();
|
||||
Utils::Hook(0x43D570, Error, HOOK_JUMP).install()->quick();
|
||||
Utils::Hook(0x4859A5, Input, HOOK_CALL).install()->quick();
|
||||
}
|
||||
else if(!Loader::IsPerformingUnitTests())
|
||||
{
|
||||
@ -976,10 +963,10 @@ namespace Components
|
||||
|
||||
Console::~Console()
|
||||
{
|
||||
Console::SetSkipShutdown();
|
||||
if (Console::ConsoleThread.joinable())
|
||||
SetSkipShutdown();
|
||||
if (ConsoleThread.joinable())
|
||||
{
|
||||
Console::ConsoleThread.join();
|
||||
ConsoleThread.join();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include "Terminus_4.49.1.ttf.hpp"
|
||||
|
||||
#define OUTPUT_HEIGHT 250
|
||||
#define OUTPUT_MAX_TOP (OUTPUT_HEIGHT - (Console::Height - 2))
|
||||
|
||||
@ -81,21 +79,7 @@ namespace Components
|
||||
static LRESULT CALLBACK ConWndProc(HWND hWnd, UINT Msg, WPARAM wParam, unsigned int lParam);
|
||||
static ATOM CALLBACK RegisterClassHook(WNDCLASSA* lpWndClass);
|
||||
static BOOL CALLBACK ResizeChildWindow(HWND hwndChild, LPARAM lParam);
|
||||
static HFONT CALLBACK ReplaceFont(
|
||||
int cHeight,
|
||||
int cWidth,
|
||||
int cEscapement,
|
||||
int cOrientation,
|
||||
int cWeight,
|
||||
DWORD bItalic,
|
||||
DWORD bUnderline,
|
||||
DWORD bStrikeOut,
|
||||
DWORD iCharSet,
|
||||
DWORD iOutPrecision,
|
||||
DWORD iClipPrecision,
|
||||
DWORD iQuality,
|
||||
DWORD iPitchAndFamily,
|
||||
LPCSTR pszFaceName);
|
||||
static HFONT CALLBACK ReplaceFont(int cHeight, int cWidth, int cEscapement, int cOrientation, int cWeight, DWORD bItalic, DWORD bUnderline, DWORD bStrikeOut, DWORD iCharSet, DWORD iOutPrecision, DWORD iClipPrecision, DWORD iQuality, DWORD iPitchAndFamily, LPCSTR pszFaceName);
|
||||
static void ApplyConsoleStyle();
|
||||
static void GetWindowPos(HWND hWnd, int* x, int* y);
|
||||
static void Sys_PrintStub();
|
||||
|
@ -8,6 +8,7 @@ namespace Components
|
||||
SteamID Dedicated::PlayerGuids[18][2];
|
||||
|
||||
Dvar::Var Dedicated::SVLanOnly;
|
||||
Dvar::Var Dedicated::SVMOTD;
|
||||
Dvar::Var Dedicated::COMLogFilter;
|
||||
|
||||
bool Dedicated::IsEnabled()
|
||||
@ -76,7 +77,7 @@ namespace Components
|
||||
__asm
|
||||
{
|
||||
pushad
|
||||
call Dedicated::PostInitialization
|
||||
call PostInitialization
|
||||
popad
|
||||
|
||||
// Start Com_EvenLoop
|
||||
@ -96,7 +97,7 @@ namespace Components
|
||||
list.append(Utils::String::VA(" %llX", Game::svs_clients[i].steamID));
|
||||
|
||||
Utils::InfoString info(Game::svs_clients[i].userinfo);
|
||||
list.append(Utils::String::VA(" %llX", strtoull(info.get("realsteamId").data(), nullptr, 16)));
|
||||
list.append(Utils::String::VA(" %llX", std::strtoull(info.get("realsteamId").data(), nullptr, 16)));
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -127,7 +128,7 @@ namespace Components
|
||||
void Dedicated::Heartbeat()
|
||||
{
|
||||
// Do not send a heartbeat if sv_lanOnly is set to true
|
||||
if (Dedicated::SVLanOnly.get<bool>())
|
||||
if (SVLanOnly.get<bool>())
|
||||
{
|
||||
return;
|
||||
}
|
||||
@ -148,18 +149,17 @@ namespace Components
|
||||
|
||||
Dedicated::Dedicated()
|
||||
{
|
||||
Dedicated::COMLogFilter = Dvar::Register<bool>("com_logFilter", true,
|
||||
COMLogFilter = Dvar::Register<bool>("com_logFilter", true,
|
||||
Game::DVAR_LATCH, "Removes ~95% of unneeded lines from the log");
|
||||
|
||||
if (Dedicated::IsEnabled() || ZoneBuilder::IsEnabled())
|
||||
if (IsEnabled() || ZoneBuilder::IsEnabled())
|
||||
{
|
||||
// Make sure all callbacks are handled
|
||||
Scheduler::Loop(Steam::SteamAPI_RunCallbacks, Scheduler::Pipeline::SERVER);
|
||||
|
||||
Dedicated::SVLanOnly = Dvar::Register<bool>("sv_lanOnly", false,
|
||||
Game::DVAR_NONE, "Don't act as node");
|
||||
SVLanOnly = Dvar::Register<bool>("sv_lanOnly", false, Game::DVAR_NONE, "Don't act as node");
|
||||
|
||||
Utils::Hook(0x60BE98, Dedicated::InitDedicatedServer, HOOK_CALL).install()->quick();
|
||||
Utils::Hook(0x60BE98, InitDedicatedServer, HOOK_CALL).install()->quick();
|
||||
|
||||
Utils::Hook::Set<BYTE>(0x683370, 0xC3); // steam sometimes doesn't like the server
|
||||
|
||||
@ -199,7 +199,7 @@ namespace Components
|
||||
Utils::Hook::Set<DWORD>(0x5DEC04, 0);
|
||||
|
||||
// Manually register sv_network_fps
|
||||
Utils::Hook(0x4D3C7B, Dedicated::Dvar_RegisterSVNetworkFps, HOOK_CALL).install()->quick();
|
||||
Utils::Hook(0x4D3C7B, Dvar_RegisterSVNetworkFps, HOOK_CALL).install()->quick();
|
||||
|
||||
// r_loadForRenderer default to 0
|
||||
Utils::Hook::Set<BYTE>(0x519DDF, 0);
|
||||
@ -217,18 +217,18 @@ namespace Components
|
||||
Utils::Hook::Set<BYTE>(0x4B4D19, 0xEB);
|
||||
|
||||
// Intercept time wrapping
|
||||
Utils::Hook(0x62737D, Dedicated::TimeWrapStub, HOOK_CALL).install()->quick();
|
||||
Utils::Hook(0x62737D, TimeWrapStub, HOOK_CALL).install()->quick();
|
||||
//Utils::Hook::Set<DWORD>(0x62735C, 50'000); // Time wrap after 50 seconds (for testing - i don't want to wait 3 weeks)
|
||||
|
||||
if (!ZoneBuilder::IsEnabled())
|
||||
{
|
||||
Scheduler::Once([]
|
||||
{
|
||||
Dvar::Register<const char*>("sv_motd", "", Game::DVAR_NONE, "A custom message of the day for servers");
|
||||
SVMOTD = Dvar::Register<const char*>("sv_motd", "", Game::DVAR_NONE, "A custom message of the day for servers");
|
||||
}, Scheduler::Pipeline::MAIN);
|
||||
|
||||
// Post initialization point
|
||||
Utils::Hook(0x60BFBF, Dedicated::PostInitializationStub, HOOK_JUMP).install()->quick();
|
||||
Utils::Hook(0x60BFBF, PostInitializationStub, HOOK_JUMP).install()->quick();
|
||||
|
||||
// Transmit custom data
|
||||
Scheduler::Loop([]
|
||||
@ -238,16 +238,16 @@ namespace Components
|
||||
}, Scheduler::Pipeline::SERVER, 10s);
|
||||
|
||||
// Heartbeats
|
||||
Scheduler::Once(Dedicated::Heartbeat, Scheduler::Pipeline::SERVER);
|
||||
Scheduler::Loop(Dedicated::Heartbeat, Scheduler::Pipeline::SERVER, 2min);
|
||||
Scheduler::Once(Heartbeat, Scheduler::Pipeline::SERVER);
|
||||
Scheduler::Loop(Heartbeat, Scheduler::Pipeline::SERVER, 2min);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < ARRAYSIZE(Dedicated::PlayerGuids); ++i)
|
||||
for (int i = 0; i < ARRAYSIZE(PlayerGuids); ++i)
|
||||
{
|
||||
Dedicated::PlayerGuids[i][0].bits = 0;
|
||||
Dedicated::PlayerGuids[i][1].bits = 0;
|
||||
PlayerGuids[i][0].bits = 0;
|
||||
PlayerGuids[i][1].bits = 0;
|
||||
}
|
||||
|
||||
// Intercept server commands
|
||||
@ -255,12 +255,12 @@ namespace Components
|
||||
{
|
||||
for (int client = 0; client < 18; client++)
|
||||
{
|
||||
Dedicated::PlayerGuids[client][0].bits = strtoull(params->get(2 * client + 1), nullptr, 16);
|
||||
Dedicated::PlayerGuids[client][1].bits = strtoull(params->get(2 * client + 2), nullptr, 16);
|
||||
PlayerGuids[client][0].bits = std::strtoull(params->get(2 * client + 1), nullptr, 16);
|
||||
PlayerGuids[client][1].bits = std::strtoull(params->get(2 * client + 2), nullptr, 16);
|
||||
|
||||
if (Steam::Proxy::SteamFriends && Dedicated::PlayerGuids[client][1].bits != 0)
|
||||
if (Steam::Proxy::SteamFriends && PlayerGuids[client][1].bits != 0)
|
||||
{
|
||||
Steam::Proxy::SteamFriends->SetPlayedWith(Dedicated::PlayerGuids[client][1]);
|
||||
Steam::Proxy::SteamFriends->SetPlayedWith(PlayerGuids[client][1]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -270,9 +270,9 @@ namespace Components
|
||||
|
||||
Scheduler::Loop([]
|
||||
{
|
||||
if (Dedicated::IsRunning())
|
||||
if (IsRunning())
|
||||
{
|
||||
Dedicated::TransmitGuids();
|
||||
TransmitGuids();
|
||||
}
|
||||
}, Scheduler::Pipeline::SERVER, 15s);
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ namespace Components
|
||||
|
||||
static SteamID PlayerGuids[18][2];
|
||||
static Dvar::Var SVLanOnly;
|
||||
static Dvar::Var SVMOTD;
|
||||
static Dvar::Var COMLogFilter;
|
||||
|
||||
static bool IsEnabled();
|
||||
|
@ -8,6 +8,9 @@ namespace Components
|
||||
{
|
||||
static mg_mgr Mgr;
|
||||
|
||||
Dvar::Var Download::SV_wwwDownload;
|
||||
Dvar::Var Download::SV_wwwBaseUrl;
|
||||
|
||||
Download::ClientDownload Download::CLDownload;
|
||||
|
||||
std::thread Download::ServerThread;
|
||||
@ -138,7 +141,7 @@ namespace Components
|
||||
}
|
||||
|
||||
auto host = "http://" + download->target.getString();
|
||||
auto fastHost = Dvar::Var("sv_wwwBaseUrl").get<std::string>();
|
||||
auto fastHost = SV_wwwBaseUrl.get<std::string>();
|
||||
if (Utils::String::StartsWith(fastHost, "https://"))
|
||||
{
|
||||
download->thread.detach();
|
||||
@ -173,7 +176,7 @@ namespace Components
|
||||
// -mod.ff
|
||||
// /-mod2
|
||||
// ...
|
||||
if (Dvar::Var("sv_wwwDownload").get<bool>())
|
||||
if (SV_wwwDownload.get<bool>())
|
||||
{
|
||||
if (!Utils::String::EndsWith(fastHost, "/")) fastHost.append("/");
|
||||
url = fastHost + path;
|
||||
@ -720,8 +723,8 @@ namespace Components
|
||||
|
||||
Scheduler::Once([]
|
||||
{
|
||||
Dvar::Register<bool>("sv_wwwDownload", false, Game::DVAR_NONE, "Set to true to enable downloading maps/mods from an external server.");
|
||||
Dvar::Register<const char*>("sv_wwwBaseUrl", "", Game::DVAR_NONE, "Set to the base url for the external map download.");
|
||||
SV_wwwDownload = Dvar::Register<bool>("sv_wwwDownload", false, Game::DVAR_NONE, "Set to true to enable downloading maps/mods from an external server.");
|
||||
SV_wwwBaseUrl = Dvar::Register<const char*>("sv_wwwBaseUrl", "", Game::DVAR_NONE, "Set to the base url for the external map download.");
|
||||
}, Scheduler::Pipeline::MAIN);
|
||||
}
|
||||
|
||||
|
@ -13,6 +13,9 @@ namespace Components
|
||||
static void InitiateClientDownload(const std::string& mod, bool needPassword, bool map = false);
|
||||
static void InitiateMapDownload(const std::string& map, bool needPassword);
|
||||
|
||||
static Dvar::Var SV_wwwDownload;
|
||||
static Dvar::Var SV_wwwBaseUrl;
|
||||
|
||||
private:
|
||||
class ClientDownload
|
||||
{
|
||||
|
@ -583,7 +583,7 @@ namespace Components
|
||||
}
|
||||
|
||||
// dlcIsTrue serves as a check if the map is a custom map and if it's missing
|
||||
bool Maps::CheckMapInstalled(const char* mapname, bool error, bool dlcIsTrue)
|
||||
bool Maps::CheckMapInstalled(const std::string& mapname, bool error, bool dlcIsTrue)
|
||||
{
|
||||
if (FastFiles::Exists(mapname)) return true;
|
||||
|
||||
@ -591,12 +591,12 @@ namespace Components
|
||||
{
|
||||
for (auto map : pack.maps)
|
||||
{
|
||||
if (map == std::string(mapname))
|
||||
if (map == mapname)
|
||||
{
|
||||
if (error)
|
||||
{
|
||||
Logger::Error(Game::ERR_DISCONNECT, "Missing DLC pack {} ({}) containing map {} ({}).\nPlease download it to play this map.",
|
||||
pack.name, pack.index, Game::UI_LocalizeMapName(mapname), mapname);
|
||||
pack.name, pack.index, Game::UI_LocalizeMapName(mapname.data()), mapname);
|
||||
}
|
||||
|
||||
return dlcIsTrue;
|
||||
|
@ -54,7 +54,7 @@ namespace Components
|
||||
static std::string CurrentMainZone;
|
||||
static const char* UserMapFiles[4];
|
||||
|
||||
static bool CheckMapInstalled(const char* mapname, bool error = false, bool dlcIsTrue = false);
|
||||
static bool CheckMapInstalled(const std::string& mapname, bool error = false, bool dlcIsTrue = false);
|
||||
|
||||
static UserMapContainer* GetUserMap();
|
||||
static unsigned int GetUsermapHash(const std::string& map);
|
||||
|
@ -28,35 +28,36 @@ namespace Components
|
||||
|
||||
Network::Address Party::Target()
|
||||
{
|
||||
return Party::Container.target;
|
||||
return Container.target;
|
||||
}
|
||||
|
||||
void Party::Connect(Network::Address target)
|
||||
{
|
||||
Node::Add(target);
|
||||
|
||||
Party::Container.valid = true;
|
||||
Party::Container.awaitingPlaylist = false;
|
||||
Party::Container.joinTime = Game::Sys_Milliseconds();
|
||||
Party::Container.target = target;
|
||||
Party::Container.challenge = Utils::Cryptography::Rand::GenerateChallenge();
|
||||
Container.valid = true;
|
||||
Container.awaitingPlaylist = false;
|
||||
Container.joinTime = Game::Sys_Milliseconds();
|
||||
Container.target = target;
|
||||
Container.challenge = Utils::Cryptography::Rand::GenerateChallenge();
|
||||
|
||||
Network::SendCommand(Party::Container.target, "getinfo", Party::Container.challenge);
|
||||
Network::SendCommand(Container.target, "getinfo", Container.challenge);
|
||||
|
||||
Command::Execute("openmenu popup_reconnectingtoparty");
|
||||
}
|
||||
|
||||
const char* Party::GetLobbyInfo(SteamID lobby, const std::string& key)
|
||||
{
|
||||
if (Party::LobbyMap.contains(lobby.bits))
|
||||
if (LobbyMap.contains(lobby.bits))
|
||||
{
|
||||
Network::Address address = Party::LobbyMap[lobby.bits];
|
||||
Network::Address address = LobbyMap[lobby.bits];
|
||||
|
||||
if (key == "addr")
|
||||
if (key == "addr"s)
|
||||
{
|
||||
return Utils::String::VA("%d", address.getIP().full);
|
||||
}
|
||||
else if (key == "port")
|
||||
|
||||
if (key == "port"s)
|
||||
{
|
||||
return Utils::String::VA("%d", address.getPort());
|
||||
}
|
||||
@ -67,7 +68,7 @@ namespace Components
|
||||
|
||||
void Party::RemoveLobby(SteamID lobby)
|
||||
{
|
||||
Party::LobbyMap.erase(lobby.bits);
|
||||
LobbyMap.erase(lobby.bits);
|
||||
}
|
||||
|
||||
void Party::ConnectError(const std::string& message)
|
||||
@ -79,17 +80,12 @@ namespace Components
|
||||
|
||||
std::string Party::GetMotd()
|
||||
{
|
||||
return Party::Container.motd;
|
||||
}
|
||||
|
||||
Game::dvar_t* Party::RegisterMinPlayers(const char* name, int /*value*/, int /*min*/, int max, unsigned __int16 flag, const char* description)
|
||||
{
|
||||
return Dvar::Register<int>(name, 1, 1, max, Game::DVAR_INIT | flag, description).get<Game::dvar_t*>();
|
||||
return Container.motd;
|
||||
}
|
||||
|
||||
bool Party::PlaylistAwaiting()
|
||||
{
|
||||
return Party::Container.awaitingPlaylist;
|
||||
return Container.awaitingPlaylist;
|
||||
}
|
||||
|
||||
void Party::PlaylistContinue()
|
||||
@ -99,20 +95,20 @@ namespace Components
|
||||
// Ensure we can join
|
||||
*Game::g_lobbyCreateInProgress = false;
|
||||
|
||||
Party::Container.awaitingPlaylist = false;
|
||||
Container.awaitingPlaylist = false;
|
||||
|
||||
SteamID id = Party::GenerateLobbyId();
|
||||
SteamID id = GenerateLobbyId();
|
||||
|
||||
// Temporary workaround
|
||||
// TODO: Patch the 127.0.0.1 -> loopback mapping in the party code
|
||||
if (Party::Container.target.isLoopback())
|
||||
if (Container.target.isLoopback())
|
||||
{
|
||||
if (*Game::numIP)
|
||||
{
|
||||
Party::Container.target.setIP(*Game::localIP);
|
||||
Party::Container.target.setType(Game::netadrtype_t::NA_IP);
|
||||
Container.target.setIP(*Game::localIP);
|
||||
Container.target.setType(Game::netadrtype_t::NA_IP);
|
||||
|
||||
Logger::Print("Trying to connect to party with loopback address, using a local ip instead: {}\n", Party::Container.target.getString());
|
||||
Logger::Print("Trying to connect to party with loopback address, using a local ip instead: {}\n", Container.target.getString());
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -120,17 +116,17 @@ namespace Components
|
||||
}
|
||||
}
|
||||
|
||||
Party::LobbyMap[id.bits] = Party::Container.target;
|
||||
LobbyMap[id.bits] = Container.target;
|
||||
|
||||
Game::Steam_JoinLobby(id, 0);
|
||||
}
|
||||
|
||||
void Party::PlaylistError(const std::string& error)
|
||||
{
|
||||
Party::Container.valid = false;
|
||||
Party::Container.awaitingPlaylist = false;
|
||||
Container.valid = false;
|
||||
Container.awaitingPlaylist = false;
|
||||
|
||||
Party::ConnectError(error);
|
||||
ConnectError(error);
|
||||
}
|
||||
|
||||
DWORD Party::UIDvarIntStub(char* dvar)
|
||||
@ -150,7 +146,7 @@ namespace Components
|
||||
|
||||
bool Party::IsInUserMapLobby()
|
||||
{
|
||||
return (Party::IsInLobby() && Maps::IsUserMap(Dvar::Var("ui_mapname").get<const char*>()));
|
||||
return (IsInLobby() && Maps::IsUserMap(Dvar::Var("ui_mapname").get<const char*>()));
|
||||
}
|
||||
|
||||
bool Party::IsEnabled()
|
||||
@ -160,7 +156,7 @@ namespace Components
|
||||
|
||||
Party::Party()
|
||||
{
|
||||
Party::PartyEnable = Dvar::Register<bool>("party_enable", Dedicated::IsEnabled(), Game::DVAR_NONE, "Enable party system");
|
||||
PartyEnable = Dvar::Register<bool>("party_enable", Dedicated::IsEnabled(), Game::DVAR_NONE, "Enable party system");
|
||||
Dvar::Register<bool>("xblive_privatematch", true, Game::DVAR_INIT, "");
|
||||
|
||||
// various changes to SV_DirectConnect-y stuff to allow non-party joinees
|
||||
@ -227,7 +223,7 @@ namespace Components
|
||||
Utils::Hook::Nop(0x5A8E33, 11);
|
||||
|
||||
// Enable XP Bar
|
||||
Utils::Hook(0x62A2A7, Party::UIDvarIntStub, HOOK_CALL).install()->quick();
|
||||
Utils::Hook(0x62A2A7, UIDvarIntStub, HOOK_CALL).install()->quick();
|
||||
|
||||
// Set NAT to open
|
||||
Utils::Hook::Set<int>(0x79D898, 1);
|
||||
@ -238,7 +234,7 @@ namespace Components
|
||||
Utils::Hook::Nop(0x4077A1, 5); // PartyMigrate_Frame
|
||||
|
||||
// Patch playlist stuff for non-party behavior
|
||||
static Game::dvar_t* partyEnable = Party::PartyEnable.get<Game::dvar_t*>();
|
||||
static Game::dvar_t* partyEnable = PartyEnable.get<Game::dvar_t*>();
|
||||
Utils::Hook::Set<Game::dvar_t**>(0x4A4093, &partyEnable);
|
||||
Utils::Hook::Set<Game::dvar_t**>(0x4573F1, &partyEnable);
|
||||
Utils::Hook::Set<Game::dvar_t**>(0x5B1A0C, &partyEnable);
|
||||
@ -248,12 +244,6 @@ namespace Components
|
||||
Utils::Hook::Xor<BYTE>(0x4573FA, 1);
|
||||
Utils::Hook::Xor<BYTE>(0x5B1A17, 1);
|
||||
|
||||
// Fix xstartlobby
|
||||
//Utils::Hook::Set<BYTE>(0x5B71CD, 0xEB);
|
||||
|
||||
// Patch party_minplayers to 1 and protect it
|
||||
//Utils::Hook(0x4D5D51, Party::RegisterMinPlayers, HOOK_CALL).install()->quick();
|
||||
|
||||
// Set ui_maxclients to sv_maxclients
|
||||
Utils::Hook::Set<const char*>(0x42618F, "sv_maxclients");
|
||||
Utils::Hook::Set<const char*>(0x4D3756, "sv_maxclients");
|
||||
@ -267,9 +257,6 @@ namespace Components
|
||||
Utils::Hook::Xor<DWORD>(0x4D376D, Game::DVAR_LATCH);
|
||||
Utils::Hook::Xor<DWORD>(0x5E3789, Game::DVAR_LATCH);
|
||||
|
||||
// Patch Live_PlayerHasLoopbackAddr
|
||||
//Utils::Hook::Set<DWORD>(0x418F30, 0x90C3C033);
|
||||
|
||||
Command::Add("connect", [](Command::Params* params)
|
||||
{
|
||||
if (params->size() < 2)
|
||||
@ -284,33 +271,34 @@ namespace Components
|
||||
}
|
||||
else
|
||||
{
|
||||
Party::Connect(Network::Address(params->get(1)));
|
||||
Connect(Network::Address(params->get(1)));
|
||||
}
|
||||
});
|
||||
|
||||
Command::Add("reconnect", [](Command::Params*)
|
||||
{
|
||||
Party::Connect(Party::Container.target);
|
||||
Connect(Container.target);
|
||||
});
|
||||
|
||||
if (!Dedicated::IsEnabled() && !ZoneBuilder::IsEnabled())
|
||||
{
|
||||
Scheduler::Loop([]
|
||||
{
|
||||
if (Party::Container.valid)
|
||||
if (Container.valid)
|
||||
{
|
||||
if ((Game::Sys_Milliseconds() - Party::Container.joinTime) > 10'000)
|
||||
if ((Game::Sys_Milliseconds() - Container.joinTime) > 10'000)
|
||||
{
|
||||
Party::Container.valid = false;
|
||||
Party::ConnectError("Server connection timed out.");
|
||||
Container.valid = false;
|
||||
ConnectError("Server connection timed out.");
|
||||
}
|
||||
}
|
||||
|
||||
if (Party::Container.awaitingPlaylist)
|
||||
if (Container.awaitingPlaylist)
|
||||
{
|
||||
if ((Game::Sys_Milliseconds() - Party::Container.requestTime) > 5'000)
|
||||
if ((Game::Sys_Milliseconds() - Container.requestTime) > 5'000)
|
||||
{
|
||||
Party::Container.awaitingPlaylist = false;
|
||||
Party::ConnectError("Playlist request timed out.");
|
||||
Container.awaitingPlaylist = false;
|
||||
ConnectError("Playlist request timed out.");
|
||||
}
|
||||
}
|
||||
|
||||
@ -339,8 +327,8 @@ namespace Components
|
||||
}
|
||||
else
|
||||
{
|
||||
maxClientCount = Dvar::Var("party_maxplayers").get<int>();
|
||||
clientCount = Game::PartyHost_CountMembers(reinterpret_cast<Game::PartyData*>(0x1081C00));
|
||||
maxClientCount = *Game::party_maxplayers ? (*Game::party_maxplayers)->current.integer : 18;
|
||||
clientCount = Game::PartyHost_CountMembers(Game::g_lobbyData);
|
||||
}
|
||||
|
||||
Utils::InfoString info;
|
||||
@ -365,7 +353,7 @@ namespace Components
|
||||
info.set("voiceChat", (Voice::SV_VoiceEnabled() ? "1" : "0"));
|
||||
|
||||
// Ensure mapname is set
|
||||
if (info.get("mapname").empty() || Party::IsInLobby())
|
||||
if (info.get("mapname").empty() || IsInLobby())
|
||||
{
|
||||
info.set("mapname", Dvar::Var("ui_mapname").get<const char*>());
|
||||
}
|
||||
@ -374,14 +362,14 @@ namespace Components
|
||||
{
|
||||
info.set("usermaphash", Utils::String::VA("%i", Maps::GetUserMap()->getHash()));
|
||||
}
|
||||
else if (Party::IsInUserMapLobby())
|
||||
else if (IsInUserMapLobby())
|
||||
{
|
||||
info.set("usermaphash", Utils::String::VA("%i", Maps::GetUsermapHash(info.get("mapname"))));
|
||||
}
|
||||
|
||||
if (Dedicated::IsEnabled())
|
||||
{
|
||||
info.set("sv_motd", Dvar::Var("sv_motd").get<std::string>());
|
||||
info.set("sv_motd", Dedicated::SVMOTD.get<std::string>());
|
||||
}
|
||||
|
||||
// Set matchtype
|
||||
@ -402,133 +390,172 @@ namespace Components
|
||||
info.set("matchtype", "0");
|
||||
}
|
||||
|
||||
info.set("wwwDownload", (Dvar::Var("sv_wwwDownload").get<bool>() ? "1" : "0"));
|
||||
info.set("wwwUrl", Dvar::Var("sv_wwwBaseUrl").get<std::string>());
|
||||
info.set("wwwDownload", (Download::SV_wwwDownload.get<bool>() ? "1" : "0"));
|
||||
info.set("wwwUrl", Download::SV_wwwBaseUrl.get<std::string>());
|
||||
|
||||
Network::SendCommand(address, "infoResponse", "\\" + info.build());
|
||||
});
|
||||
|
||||
Network::OnClientPacket("infoResponse", [](const Network::Address& address, [[maybe_unused]] const std::string& data)
|
||||
{
|
||||
Utils::InfoString info(data);
|
||||
const Utils::InfoString info(data);
|
||||
|
||||
const auto _0 = gsl::finally([&]
|
||||
{
|
||||
ServerList::Insert(address, info);
|
||||
Friends::UpdateServer(address, info.get("hostname"), info.get("mapname"));
|
||||
});
|
||||
|
||||
// Handle connection
|
||||
if (Party::Container.valid)
|
||||
if (!Container.valid)
|
||||
{
|
||||
if (Party::Container.target == address)
|
||||
{
|
||||
// Invalidate handler for future packets
|
||||
Party::Container.valid = false;
|
||||
Party::Container.info = info;
|
||||
|
||||
Party::Container.matchType = atoi(info.get("matchtype").data());
|
||||
uint32_t securityLevel = static_cast<uint32_t>(atoi(info.get("securityLevel").data()));
|
||||
bool isUsermap = !info.get("usermaphash").empty();
|
||||
unsigned int usermapHash = atoi(info.get("usermaphash").data());
|
||||
|
||||
std::string mod = (*Game::fs_gameDirVar)->current.string;
|
||||
|
||||
// set fast server stuff here so its updated when we go to download stuff
|
||||
if (info.get("wwwDownload") == "1"s)
|
||||
{
|
||||
Dvar::Var("sv_wwwDownload").set(true);
|
||||
Dvar::Var("sv_wwwBaseUrl").set(info.get("wwwUrl"));
|
||||
}
|
||||
else
|
||||
{
|
||||
Dvar::Var("sv_wwwDownload").set(false);
|
||||
Dvar::Var("sv_wwwBaseUrl").set("");
|
||||
}
|
||||
|
||||
if (info.get("challenge") != Party::Container.challenge)
|
||||
{
|
||||
Party::ConnectError("Invalid join response: Challenge mismatch.");
|
||||
}
|
||||
else if (securityLevel > Auth::GetSecurityLevel())
|
||||
{
|
||||
//Party::ConnectError(Utils::VA("Your security level (%d) is lower than the server's (%d)", Auth::GetSecurityLevel(), securityLevel));
|
||||
Command::Execute("closemenu popup_reconnectingtoparty");
|
||||
Auth::IncreaseSecurityLevel(securityLevel, "reconnect");
|
||||
}
|
||||
else if (!Party::Container.matchType)
|
||||
{
|
||||
Party::ConnectError("Server is not hosting a match.");
|
||||
}
|
||||
else if (Party::Container.matchType > 2 || Party::Container.matchType < 0)
|
||||
{
|
||||
Party::ConnectError("Invalid join response: Unknown matchtype");
|
||||
}
|
||||
else if (Party::Container.info.get("mapname").empty() || Party::Container.info.get("gametype").empty())
|
||||
{
|
||||
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")))
|
||||
{
|
||||
Command::Execute("closemenu popup_reconnectingtoparty");
|
||||
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")))
|
||||
{
|
||||
Command::Execute("closemenu popup_reconnectingtoparty");
|
||||
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())
|
||||
{
|
||||
Game::Dvar_SetString(*Game::fs_gameDirVar, "");
|
||||
|
||||
if (Dvar::Var("cl_modVidRestart").get<bool>())
|
||||
{
|
||||
Command::Execute("vid_restart", false);
|
||||
}
|
||||
|
||||
Command::Execute("reconnect", false);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!Maps::CheckMapInstalled(Party::Container.info.get("mapname").data(), true)) return;
|
||||
|
||||
Party::Container.motd = info.get("sv_motd");
|
||||
|
||||
if (Party::Container.matchType == 1) // Party
|
||||
{
|
||||
// Send playlist request
|
||||
Party::Container.requestTime = Game::Sys_Milliseconds();
|
||||
Party::Container.awaitingPlaylist = true;
|
||||
Network::SendCommand(Party::Container.target, "getplaylist", Dvar::Var("password").get<std::string>());
|
||||
|
||||
// This is not a safe method
|
||||
// TODO: Fix actual error!
|
||||
if (Game::CL_IsCgameInitialized())
|
||||
{
|
||||
Command::Execute("disconnect", true);
|
||||
}
|
||||
}
|
||||
else if (Party::Container.matchType == 2) // Match
|
||||
{
|
||||
if (atoi(Party::Container.info.get("clients").data()) >= atoi(Party::Container.info.get("sv_maxclients").data()))
|
||||
{
|
||||
Party::ConnectError("@EXE_SERVERISFULL");
|
||||
}
|
||||
else
|
||||
{
|
||||
Dvar::Var("xblive_privateserver").set(true);
|
||||
|
||||
Game::Menus_CloseAll(Game::uiContext);
|
||||
|
||||
Game::_XSESSION_INFO hostInfo;
|
||||
Game::CL_ConnectFromParty(0, &hostInfo, *Party::Container.target.get(), 0, 0, Party::Container.info.get("mapname").data(), Party::Container.info.get("gametype").data());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
ServerList::Insert(address, info);
|
||||
Friends::UpdateServer(address, info.get("hostname"), info.get("mapname"));
|
||||
if (Container.target == address)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Invalidate handler for future packets
|
||||
Container.valid = false;
|
||||
Container.info = info;
|
||||
|
||||
Container.matchType = atoi(info.get("matchtype").data());
|
||||
const auto securityLevel = static_cast<uint32_t>(std::strtol(info.get("securityLevel").data(), nullptr, 10));
|
||||
bool isUsermap = !info.get("usermaphash").empty();
|
||||
const auto usermapHash = static_cast<uint32_t>(std::strtol(info.get("usermaphash").data(), nullptr, 10));
|
||||
|
||||
std::string mod = (*Game::fs_gameDirVar)->current.string;
|
||||
|
||||
// set fast server stuff here so its updated when we go to download stuff
|
||||
if (info.get("wwwDownload") == "1"s)
|
||||
{
|
||||
Download::SV_wwwDownload.set(true);
|
||||
Download::SV_wwwBaseUrl.set(info.get("wwwUrl"));
|
||||
}
|
||||
else
|
||||
{
|
||||
Download::SV_wwwDownload.set(false);
|
||||
Download::SV_wwwBaseUrl.set("");
|
||||
}
|
||||
|
||||
if (info.get("challenge") != Container.challenge)
|
||||
{
|
||||
ConnectError("Invalid join response: Challenge mismatch.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (securityLevel > Auth::GetSecurityLevel())
|
||||
{
|
||||
|
||||
Command::Execute("closemenu popup_reconnectingtoparty");
|
||||
Auth::IncreaseSecurityLevel(securityLevel, "reconnect");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Container.matchType)
|
||||
{
|
||||
ConnectError("Server is not hosting a match.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (Container.matchType > 2 || Container.matchType < 0)
|
||||
{
|
||||
ConnectError("Invalid join response: Unknown matchtype");
|
||||
return;
|
||||
}
|
||||
|
||||
if (Container.info.get("mapname").empty() || Container.info.get("gametype").empty())
|
||||
{
|
||||
ConnectError("Invalid map or gametype.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (Container.info.get("isPrivate") == "1"s && !Dvar::Var("password").get<std::string>().empty())
|
||||
{
|
||||
ConnectError("A password is required to join this server! Set it at the bottom of the serverlist.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (isUsermap && usermapHash != Maps::GetUsermapHash(info.get("mapname")))
|
||||
{
|
||||
Command::Execute("closemenu popup_reconnectingtoparty");
|
||||
Download::InitiateMapDownload(info.get("mapname"), info.get("isPrivate") == "1"s);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!info.get("fs_game").empty() && Utils::String::ToLower(mod) != Utils::String::ToLower(info.get("fs_game")))
|
||||
{
|
||||
Command::Execute("closemenu popup_reconnectingtoparty");
|
||||
Download::InitiateClientDownload(info.get("fs_game"), info.get("isPrivate") == "1"s);
|
||||
return;
|
||||
}
|
||||
|
||||
if (*(*Game::fs_gameDirVar)->current.string && info.get("fs_game").empty())
|
||||
{
|
||||
Game::Dvar_SetString(*Game::fs_gameDirVar, "");
|
||||
|
||||
if (Dvar::Var("cl_modVidRestart").get<bool>())
|
||||
{
|
||||
Command::Execute("vid_restart", false);
|
||||
}
|
||||
|
||||
Command::Execute("reconnect", false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Maps::CheckMapInstalled(Container.info.get("mapname"), true))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Container.motd = info.get("sv_motd");
|
||||
|
||||
if (Container.matchType == 1) // Party
|
||||
{
|
||||
// Send playlist request
|
||||
Container.requestTime = Game::Sys_Milliseconds();
|
||||
Container.awaitingPlaylist = true;
|
||||
Network::SendCommand(Party::Container.target, "getplaylist", Dvar::Var("password").get<std::string>());
|
||||
|
||||
// This is not a safe method
|
||||
// TODO: Fix actual error!
|
||||
if (Game::CL_IsCgameInitialized())
|
||||
{
|
||||
Command::Execute("disconnect", true);
|
||||
}
|
||||
}
|
||||
else if (Container.matchType == 2) // Match
|
||||
{
|
||||
int clients;
|
||||
int maxClients;
|
||||
|
||||
try
|
||||
{
|
||||
clients = std::stoi(Container.info.get("clients"));
|
||||
maxClients = std::stoi(Container.info.get("sv_maxclients"));
|
||||
}
|
||||
catch ([[maybe_unused]] const std::exception& ex)
|
||||
{
|
||||
ConnectError("Invalid info string");
|
||||
return;
|
||||
}
|
||||
|
||||
if (clients >= maxClients)
|
||||
{
|
||||
ConnectError("@EXE_SERVERISFULL");
|
||||
}
|
||||
else
|
||||
{
|
||||
Dvar::Var("xblive_privateserver").set(true);
|
||||
|
||||
Game::Menus_CloseAll(Game::uiContext);
|
||||
|
||||
Game::_XSESSION_INFO hostInfo;
|
||||
Game::CL_ConnectFromParty(0, &hostInfo, *Container.target.get(), 0, 0, Container.info.get("mapname").data(), Container.info.get("gametype").data());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -50,8 +50,6 @@ namespace Components
|
||||
|
||||
static SteamID GenerateLobbyId();
|
||||
|
||||
static Game::dvar_t* RegisterMinPlayers(const char* name, int value, int min, int max, unsigned __int16 flag, const char* description);
|
||||
|
||||
static DWORD UIDvarIntStub(char* dvar);
|
||||
};
|
||||
}
|
||||
|
@ -140,7 +140,7 @@ namespace Components
|
||||
|
||||
if (!maxClientCount)
|
||||
{
|
||||
maxClientCount = Dvar::Var("party_maxplayers").get<int>();
|
||||
maxClientCount = *Game::party_maxplayers ? (*Game::party_maxplayers)->current.integer : 18;
|
||||
}
|
||||
|
||||
Utils::InfoString info(Game::Dvar_InfoString_Big(Game::DVAR_SERVERINFO));
|
||||
@ -166,7 +166,7 @@ namespace Components
|
||||
// 1 - Party, use Steam_JoinLobby to connect
|
||||
// 2 - Match, use CL_ConnectFromParty to connect
|
||||
|
||||
if (Dvar::Var("party_enable").get<bool>() && Dvar::Var("party_host").get<bool>()) // Party hosting
|
||||
if (Party::IsEnabled() && Dvar::Var("party_host").get<bool>()) // Party hosting
|
||||
{
|
||||
info.set("matchtype", "1");
|
||||
}
|
||||
|
@ -113,7 +113,7 @@ namespace Components
|
||||
{
|
||||
if (server->svRunning)
|
||||
{
|
||||
if (!sorting && !Maps::CheckMapInstalled(server->mapname.data()))
|
||||
if (!sorting && !Maps::CheckMapInstalled(server->mapname))
|
||||
{
|
||||
return Utils::String::VA("^1%s", Game::UI_LocalizeMapName(server->mapname.data()));
|
||||
}
|
||||
|
@ -77,6 +77,9 @@ namespace Game
|
||||
const dvar_t** loc_warnings = reinterpret_cast<const dvar_t**>(0x62C8700);
|
||||
const dvar_t** loc_warningsAsErrors = reinterpret_cast<const dvar_t**>(0x62C86FC);
|
||||
|
||||
const dvar_t** party_minplayers = reinterpret_cast<const dvar_t**>(0x1081BFC);
|
||||
const dvar_t** party_maxplayers = reinterpret_cast<const dvar_t**>(0x1080998);
|
||||
|
||||
__declspec(naked) void Dvar_SetVariant(dvar_t*, DvarValue, DvarSetSource)
|
||||
{
|
||||
static DWORD Dvar_SetVariant_t = 0x647400;
|
||||
|
@ -127,6 +127,9 @@ namespace Game
|
||||
extern const dvar_t** loc_warnings;
|
||||
extern const dvar_t** loc_warningsAsErrors;
|
||||
|
||||
extern const dvar_t** party_minplayers;
|
||||
extern const dvar_t** party_maxplayers;
|
||||
|
||||
extern void Dvar_SetVariant(dvar_t* var, DvarValue value, DvarSetSource source);
|
||||
extern void Dvar_SetFromStringFromSource(const dvar_t* dvar, const char* string, DvarSetSource source);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user