#include "StdAfx.h" #include "Server.h" #include "World.h" CPhatServer *g_pPhatServer = 0; HINSTANCE g_hInstance = 0; HWND g_hWndLauncher = 0; HWND g_hWndStatus = 0; HWND g_hWndMain = 0; DWORD g_dwMagicNumber = 0; // This is used for the admin login. UINT64 framerecord = 0; void UpdateFramesHUD(UINT64 frames) { if (g_hWndStatus) { SetWindowText(GetDlgItem(g_hWndStatus, IDC_FRAMERATE), csprintf("%I64u", frames)); SetWindowText(GetDlgItem(g_hWndStatus, IDC_RP), csprintf("%I64u", g_pGlobals->GetPacketRecvCount())); SetWindowText(GetDlgItem(g_hWndStatus, IDC_SP), csprintf("%I64u", g_pGlobals->GetPacketSendCount())); SetWindowText(GetDlgItem(g_hWndStatus, IDC_BR), csprintf("%I64u", g_pGlobals->GetPacketRecvSize())); SetWindowText(GetDlgItem(g_hWndStatus, IDC_BS), csprintf("%I64u", g_pGlobals->GetPacketSendSize())); } if (frames > framerecord) framerecord = frames; if (g_hWndMain) { HWND hWndCPUText = GetDlgItem(g_hWndMain, IDC_CPULOADTEXT); HWND hWndCPUBar = GetDlgItem(g_hWndMain, IDC_CPULOADBAR); double fraction = framerecord ? ((double)frames / framerecord) : 1.0f; fraction = (1.0 - fraction) * 100.0; SendMessage(hWndCPUBar, PBM_SETRANGE, 0, MAKELPARAM(0, 100)); SendMessage(hWndCPUBar, PBM_SETPOS, (WORD)fraction, 0); SetWindowText(hWndCPUText, csprintf("CPU Lag (%.2f%%):", fraction)); } } //Costly and ineffecient, but saves coding time. void UpdateClientsHUD(CClient **clients, WORD slotrange) { if (slotrange >= 400) { slotrange = 400 - 1; } if (!g_hWndMain) { return; } HWND hWndClients = GetDlgItem(g_hWndMain, IDC_CLIENTS); if (!hWndClients) { return; } SendMessage(hWndClients, LB_RESETCONTENT, 0, 0); WORD wCount = 0; for (CClient **it = &clients[1]; it <= &clients[slotrange]; it++) { CClient *client = *it; if (!client) continue; const char *lbText = client->GetDescription(); DWORD lbIndex = (DWORD)SendMessage(hWndClients, LB_ADDSTRING, 0, (LPARAM)lbText); wCount++; } g_pGlobals->SetClientCount(wCount); HWND hWndLoadText = GetDlgItem(g_hWndMain, IDC_NETWORKLOADTEXT); HWND hWndLoad = GetDlgItem(g_hWndMain, IDC_NETWORKLOADBAR); SetWindowText(hWndLoadText, csprintf("Server Load (%u)", g_pGlobals->GetClientCount())); SendMessage(hWndLoad, PBM_SETRANGE, 0, MAKELPARAM(0, 400)); SendMessage(hWndLoad, PBM_SETPOS, g_pGlobals->GetClientCount(), 0); } LRESULT CALLBACK AboutProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_INITDIALOG: return TRUE; case WM_COMMAND: switch (LOWORD(wParam)) { case IDOK: EndDialog(hDlg, LOWORD(wParam)); return TRUE; case IDC_WEBSITE: ShellExecute(0, "open", "https://discord.gg/ve6uAKt", NULL, NULL, SW_SHOW); break; default: break; } break; case WM_CLOSE: DestroyWindow(hDlg); break; } return FALSE; } LRESULT CALLBACK StatusProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_INITDIALOG: { HWND hWndPriority = GetDlgItem(hDlg, IDC_PRIORITY); SendMessage(hWndPriority, CB_ADDSTRING, 0, (LPARAM)"Lowest"); SendMessage(hWndPriority, CB_ADDSTRING, 0, (LPARAM)"Below Normal"); SendMessage(hWndPriority, CB_ADDSTRING, 0, (LPARAM)"Normal"); SendMessage(hWndPriority, CB_ADDSTRING, 0, (LPARAM)"Above Normal"); SendMessage(hWndPriority, CB_ADDSTRING, 0, (LPARAM)"Highest"); int tp = GetThreadPriority(GetCurrentThread()); int index; switch (tp) { case THREAD_PRIORITY_LOWEST: index = 0; break; case THREAD_PRIORITY_BELOW_NORMAL: index = 1; break; case THREAD_PRIORITY_NORMAL: index = 2; break; case THREAD_PRIORITY_ABOVE_NORMAL: index = 3; break; case THREAD_PRIORITY_HIGHEST: index = 4; break; default: index = 2; break; }; SendMessage(hWndPriority, CB_SETCURSEL, index, 0); return TRUE; } case WM_COMMAND: { WORD wEvent = HIWORD(wParam); WORD wID = LOWORD(wParam); switch (wID) { case IDC_PRIORITY: if (wEvent == CBN_SELCHANGE) { int index = SendMessage(GetDlgItem(hDlg, IDC_PRIORITY), CB_GETCURSEL, 0, 0); int tp; switch (index) { case 0: tp = THREAD_PRIORITY_LOWEST; break; case 1: tp = THREAD_PRIORITY_BELOW_NORMAL; break; case 3: tp = THREAD_PRIORITY_ABOVE_NORMAL; break; case 4: tp = THREAD_PRIORITY_HIGHEST; break; case 2: default: tp = THREAD_PRIORITY_NORMAL; break; } SetThreadPriority(GetCurrentThread(), tp); } case IDOK: if (wEvent == BN_CLICKED) { g_hWndStatus = 0; DestroyWindow(hDlg); } break; } break; } case WM_CLOSE: g_hWndStatus = 0; DestroyWindow(hDlg); break; } return FALSE; } LRESULT CALLBACK LauncherProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_INITDIALOG: { char account[256]; char password[256]; char remoteport[256]; DWORD remoteip; if (ReadConfigKey("account", account, 256)) SetWindowText(GetDlgItem(hDlg, IDC_ACCOUNT), account); if (ReadConfigKey("password", password, 256)) SetWindowText(GetDlgItem(hDlg, IDC_PASSWORD), password); if (ReadConfigKey("remoteport", remoteport, 256)) SetWindowText(GetDlgItem(hDlg, IDC_REMOTEPORT), remoteport); if (ReadConfigKey("remoteip", &remoteip)) SendMessage(GetDlgItem(hDlg, IDC_REMOTEIP), IPM_SETADDRESS, 0, remoteip); return TRUE; } case WM_COMMAND: { WORD wEvent = HIWORD(wParam); WORD wID = LOWORD(wParam); switch (wID) { case IDC_LAUNCHCLIENT: if (wEvent == BN_CLICKED) { char szRemotePort[10]; char szAccount[64]; *szAccount = 0; char szPassword[64]; *szPassword = 0; DWORD dwRemoteIP; DWORD dwFields = (DWORD)SendMessage(GetDlgItem(hDlg, IDC_REMOTEIP), IPM_GETADDRESS, 0, (LPARAM)&dwRemoteIP); SendMessage(GetDlgItem(hDlg, IDC_REMOTEPORT), WM_GETTEXT, 10, (LPARAM)&szRemotePort); SendMessage(GetDlgItem(hDlg, IDC_ACCOUNT), WM_GETTEXT, 64, (LPARAM)&szAccount); SendMessage(GetDlgItem(hDlg, IDC_PASSWORD), WM_GETTEXT, 64, (LPARAM)&szPassword); if (!strlen(szAccount) || !strlen(szPassword)) { MsgBox("Please specify the account name/password to connect with."); break; } if (dwFields == 4) { dwRemoteIP = htonl(dwRemoteIP); char szLaunch[256]; char szLaunchDir[MAX_PATH + 1]; sprintf(szLaunch, "-h %s -p %u -rodat off -a %s:%s", inet_ntoa(*((in_addr *)&dwRemoteIP)), atol(szRemotePort), szAccount, szPassword); DWORD dwLen = MAX_PATH + 1; memset(szLaunchDir, 0, dwLen); dwLen -= 1; /* HKEY hKey; if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Microsoft Games\\Asheron's Call\\1.00", NULL, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS) { RegQueryValueEx(hKey, "Portal Dat", NULL, NULL, (BYTE*)szLaunchDir, &dwLen); RegCloseKey(hKey); } else { MsgBox("Couldn't find installation directory. Is AC installed?\r\n"); break; } */ char dir[MAX_PATH]; GetCurrentDirectory(MAX_PATH, dir); dir[MAX_PATH - 1] = '\0'; sprintf(szLaunchDir, "%s\\Client", dir); if (szLaunchDir[strlen(szLaunchDir) - 1] != '\\') { char *end = &szLaunchDir[strlen(szLaunchDir)]; end[0] = '\\'; end[1] = '\0'; } if (!FileExists(((std::string)szLaunchDir + "\\acclient.exe").c_str())) { MsgBox("Please copy your Asheron's Call client to the Client folder of PhatAC.\r\n"); } else { //LOG(Temp, Normal, "Launching %s %s\n", szLaunch, szLaunchDir); ShellExecute(0, "open", "acclient.exe", szLaunch, szLaunchDir, SW_SHOW); } } else MsgBox("Please specify the remote IP to connect to."); } break; } break; } case WM_CLOSE: char account[256]; *account = 0; char password[256]; *password = 0; char remoteport[256]; *remoteport = 0; DWORD remoteip; if (GetWindowText(GetDlgItem(hDlg, IDC_ACCOUNT), account, 256)) SaveConfigKey("account", account); if (GetWindowText(GetDlgItem(hDlg, IDC_PASSWORD), password, 256)) SaveConfigKey("password", password); if (GetWindowText(GetDlgItem(hDlg, IDC_REMOTEPORT), remoteport, 256)) SaveConfigKey("remoteport", remoteport); if (4 == SendMessage(GetDlgItem(hDlg, IDC_REMOTEIP), IPM_GETADDRESS, 0, (LPARAM)&remoteip)) SaveConfigKey("remoteip", remoteip); g_hWndLauncher = 0; DestroyWindow(hDlg); break; } return FALSE; } void OutputConsole(int category, int level, const char *text) { if (level < LOGLEVEL_Normal) { return; } HWND hWndConsole = g_pGlobals->GetConsoleWindowHandle(); if (!hWndConsole) return; int len = (int)SendMessage(hWndConsole, WM_GETTEXTLENGTH, 0, 0); DWORD start, end; SendMessage(hWndConsole, EM_GETSEL, (WPARAM)&start, (LPARAM)&end); SendMessage(hWndConsole, EM_SETSEL, len, len); SendMessage(hWndConsole, EM_REPLACESEL, FALSE, (LPARAM)text); SendMessage(hWndConsole, EM_SETSEL, start, end); } void SetWindowStringText(HWND hWnd, const char *text) { SendMessage(hWnd, WM_SETTEXT, 0, (LPARAM)text); } std::string GetWindowStringText(HWND hWnd) { char text[300]; text[0] = '\0'; SendMessage(hWnd, WM_GETTEXT, 300, (LPARAM)text); text[299] = '\0'; return text; } int CALLBACK MainProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_INITDIALOG: { g_pGlobals->SetWindowHandle(hDlg); g_pGlobals->SetConsoleWindowHandle(GetDlgItem(hDlg, IDC_CONSOLE)); g_Logger.AddLogCallback(OutputConsole); HWND hVersion = GetDlgItem(hDlg, IDC_VERSION); SetWindowText(hVersion, "PhatAC compiled " __TIMESTAMP__); HICON hIcon = LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_PHATAC)); SendMessage(hDlg, WM_SETICON, ICON_SMALL, (LPARAM)hIcon); SendMessage(hDlg, WM_SETICON, ICON_BIG, (LPARAM)hIcon); DeleteObject(hIcon); SetWindowStringText(GetDlgItem(hDlg, IDC_SERVERHOST), GetLocalIPString().c_str()); SetWindowStringText(GetDlgItem(hDlg, IDC_SERVERPORT), "9050"); return TRUE; } case WM_COMMAND: { WORD wEvent = HIWORD(wParam); WORD wID = LOWORD(wParam); switch (wID) { case IDM_EXIT: PostQuitMessage(0); DestroyWindow(hDlg); break; case IDM_ABOUT: DialogBox(g_hInstance, (LPCTSTR)IDD_ABOUT, hDlg, (DLGPROC)AboutProc); break; case IDM_LAUNCHER: if (!g_hWndLauncher) { g_hWndLauncher = CreateDialog(g_hInstance, (LPCTSTR)IDD_LAUNCHER, hDlg, (DLGPROC)LauncherProc); ShowWindow(g_hWndLauncher, SW_SHOW); } break; case IDM_STATUS: if (!g_hWndStatus) { g_hWndStatus = CreateDialog(g_hInstance, (LPCTSTR)IDD_STATUS, hDlg, (DLGPROC)StatusProc); ShowWindow(g_hWndStatus, SW_SHOW); } break; case IDC_CLEARLOG: { if (wEvent == BN_CLICKED) { HWND hWndConsole = GetDlgItem(hDlg, IDC_CONSOLE); SetWindowText(hWndConsole, ""); LOG(Temp, Normal, "Console cleared.\n"); } } break; case IDC_BROADCAST: if (wEvent == BN_CLICKED) { if (!g_pPhatServer) { LOG(Temp, Normal, "You must be running a server to broadcast a system message.\n"); break; } char text[400]; memset(text, 0, 400); SendMessage(GetDlgItem(hDlg, IDC_BROADCASTTEXT), WM_GETTEXT, 399, (LPARAM)text); g_pPhatServer->SystemBroadcast(text); } break; case IDC_KICK: if (wEvent == BN_CLICKED) { if (!g_pPhatServer) break; g_pWorld->Test(); } break; case IDC_BAN: if (wEvent == BN_CLICKED) { if (!g_pPhatServer) break; HWND hWndClients = GetDlgItem(hDlg, IDC_CLIENTS); LRESULT lResult = SendMessage(hWndClients, LB_GETCURSEL, 0, 0); if (lResult == CB_ERR) break; //This assumes the description begins with 4 numbers indicating the celit index. LRESULT lLen = SendMessage(hWndClients, LB_GETTEXTLEN, lResult, 0); if (lLen >= 4) { char *szText = new char[lLen + 1]; SendMessage(hWndClients, LB_GETTEXT, lResult, (LPARAM)szText); szText[4] = 0; int clientIndex = atoi(szText); g_pPhatServer->BanClient(clientIndex); delete[]szText; } } break; case IDC_LAUNCH: if (wEvent == BN_CLICKED) { if (!g_pPhatServer) { MsgBox("You might want to start the server first. ;)"); break; } std::string serverHost = GetLocalIPString(); SetWindowStringText(GetDlgItem(hDlg, IDC_SERVERHOST), serverHost.c_str()); int serverPort = atoi(GetWindowStringText(GetDlgItem(hDlg, IDC_SERVERPORT)).c_str()); if (serverHost.length() != 0 && serverPort != 0) { char szLaunch[256]; char szLaunchDir[MAX_PATH + 10]; sprintf(szLaunch, "-h %s -p %u -rodat off -a admin:%06lu", serverHost.c_str(), serverPort, g_dwMagicNumber); DWORD dwLen = MAX_PATH + 10; memset(szLaunchDir, 0, dwLen); dwLen -= 1; /* HKEY hKey; if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Microsoft Games\\Asheron's Call\\1.00", NULL, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS) { RegQueryValueEx(hKey, "Portal Dat", NULL, NULL, (BYTE*)szLaunchDir, &dwLen); RegCloseKey(hKey); } else { MsgBox("Couldn't find installation directory. Is AC installed?\r\n"); break; } */ char dir[MAX_PATH]; GetCurrentDirectory(MAX_PATH, dir); dir[MAX_PATH - 1] = '\0'; sprintf(szLaunchDir, "%s\\Client", dir); if (szLaunchDir[strlen(szLaunchDir) - 1] != '\\') { char *end = &szLaunchDir[strlen(szLaunchDir)]; end[0] = '\\'; end[1] = '\0'; } if (!FileExists(((std::string)szLaunchDir + "\\acclient.exe").c_str())) { MsgBox("Please copy your Asheron's Call client to the Client folder of PhatAC.\r\n"); } else { //LOG(Temp, Normal, "Launching %s %s\n", szLaunch, szLaunchDir); ShellExecute(0, "open", "acclient.exe", szLaunch, szLaunchDir, SW_SHOW); } } else { MsgBox("Please specify the server host and port."); } } break; case IDC_TOGGLE: if (wEvent == BN_CLICKED) { if (!g_pPhatServer) { std::string serverHost = GetLocalIPString(); SetWindowStringText(GetDlgItem(hDlg, IDC_SERVERHOST), serverHost.c_str()); unsigned long serverIP = GetLocalIP(); int serverPort = atoi(GetWindowStringText(GetDlgItem(hDlg, IDC_SERVERPORT)).c_str()); if (serverIP != 0 && serverPort != 0) { serverIP = htonl(serverIP); g_pPhatServer = new CPhatServer(*((in_addr *)&serverIP), serverPort); SetWindowText(GetDlgItem(hDlg, IDC_TOGGLE), "Stop"); SetWindowText(GetDlgItem(hDlg, IDC_CONNECTLINK), csprintf("acclient.exe -h %s -p %d -a username:password -rodat off", serverHost.c_str(), serverPort)); } else MsgBox("Please specify the server's external IP."); } else { SafeDelete(g_pPhatServer); SendMessage(GetDlgItem(hDlg, IDC_CLIENTS), LB_RESETCONTENT, 0, 0); SetWindowText(GetDlgItem(hDlg, IDC_TOGGLE), "Start"); SetWindowText(GetDlgItem(hDlg, IDC_NETWORKLOADTEXT), "Server Load (0)"); SetWindowText(GetDlgItem(hDlg, IDC_CPULOADTEXT), "CPU Load (0.00%)"); SendMessage(GetDlgItem(hDlg, IDC_NETWORKLOADBAR), PBM_SETRANGE, 0, MAKELPARAM(0, 400)); SendMessage(GetDlgItem(hDlg, IDC_NETWORKLOADBAR), PBM_SETPOS, 0, 0); SendMessage(GetDlgItem(hDlg, IDC_CPULOADBAR), PBM_SETRANGE, 0, MAKELPARAM(0, 100)); SendMessage(GetDlgItem(hDlg, IDC_CPULOADBAR), PBM_SETPOS, 0, 0); SetWindowText(GetDlgItem(hDlg, IDC_CONNECTLINK), ""); LOG(Temp, Normal, "Server shutdown.\n"); } } break; } } break; case WM_CLOSE: if (g_hWndLauncher) SendMessage(g_hWndLauncher, WM_CLOSE, 0, 0); if (g_hWndStatus) SendMessage(g_hWndStatus, WM_CLOSE, 0, 0); PostQuitMessage(0); DestroyWindow(hDlg); break; } return FALSE; } int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) { SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL); srand((unsigned int)time(NULL)); g_pGlobals = new CGlobals(); g_Logger.Open(); INITCOMMONCONTROLSEX iccex; iccex.dwSize = sizeof(INITCOMMONCONTROLSEX); iccex.dwICC = ICC_INTERNET_CLASSES; InitCommonControlsEx(&iccex); WSADATA wsaData; USHORT wVersionRequested = 0x0202; WSAStartup(wVersionRequested, &wsaData); g_hInstance = hInstance; g_hWndMain = CreateDialog(hInstance, MAKEINTRESOURCE(IDD_MAIN), NULL, MainProc); if (!g_hWndMain) { MsgBoxError(GetLastError(), "creating main dialog box"); return 0; } g_dwMagicNumber = RandomLong(0, 1234567890); LOG(UserInterface, Normal, "Welcome to PhatAC..\n"); ShowWindow(g_hWndMain, nCmdShow); MSG msg; msg.message = WM_NULL; while (msg.message != WM_QUIT) { Sleep(1); if (PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE)) { if (IsDialogMessage(g_hWndMain, &msg)) continue; TranslateMessage(&msg); DispatchMessage(&msg); } else { if (g_pPhatServer) g_pPhatServer->Tick(); } } SafeDelete(g_pPhatServer); SafeDelete(g_pGlobals); WSACleanup(); #ifdef _DEBUG if (_CrtDumpMemoryLeaks()) OutputDebugString("Memory leak found!\n"); else OutputDebugString("No memory leaks found!\n"); #endif return 0; }