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