#include "pch.h" #include "ServerConsoleApp.h" #include "ServerDialog.h" IMPLEMENT_DYNAMIC(ServerDialog, CDialogEx) ServerDialog::ServerDialog(IGameServiceProvider* serviceProvider, CWnd* parent) : CDialogEx(IDD_SERVER, parent), m_serviceProvider(serviceProvider) { const auto& pGameServer = m_serviceProvider->Get(); using namespace std::placeholders; m_playerConnectedEventHandle = pGameServer->Listen(GameServerEventType::PlayerConnected, std::bind(&ServerDialog::HandlePlayerConnected, this, _1)); m_playerDisconnectedEventHandle = pGameServer->Listen(GameServerEventType::PlayerDisconnected, std::bind(&ServerDialog::HandlePlayerDisconnected, this, _1)); m_playerChatMessageHandle = pGameServer->Listen(GameServerEventType::ChatMessage, std::bind(&ServerDialog::HandleChatMessage, this, _1)); m_worldLoadedHandle = pGameServer->Listen(GameServerEventType::WorldLoaded, std::bind(&ServerDialog::HandleWorldLoaded, this, _1)); } ServerDialog::~ServerDialog() { try { const auto& pGameServer = m_serviceProvider->Get(); pGameServer->Unlisten(GameServerEventType::PlayerConnected, m_playerConnectedEventHandle); pGameServer->Unlisten(GameServerEventType::PlayerDisconnected, m_playerDisconnectedEventHandle); pGameServer->Unlisten(GameServerEventType::ChatMessage, m_playerChatMessageHandle); pGameServer->Unlisten(GameServerEventType::WorldLoaded, m_worldLoadedHandle); } catch (...) { } } void ServerDialog::DoDataExchange(CDataExchange* pDX) { CDialogEx::DoDataExchange(pDX); DDX_Control(pDX, IDC_CONSOLE, ConsoleEditBox); DDX_Control(pDX, IDC_PLAYERS, PlayersListCtrl); DDX_Control(pDX, IDC_BAN, ButtonBan); DDX_Control(pDX, IDC_KICK, ButtonKick); } void __stdcall ServerDialog::TimerCallback(HWND hwnd, UINT uMsg, UINT idEvent, DWORD dwTime) { ((ServerDialog*)idEvent)->RefreshPlayers(); } void ServerDialog::CloseDialog() { OnCancel(); } void ServerDialog::ShowDialog() { AFX_MANAGE_STATE(AfxGetStaticModuleState()); Create(IDD_SERVER); ShowWindow(SW_SHOW); } BOOL ServerDialog::OnInitDialog() { AFX_MANAGE_STATE(AfxGetStaticModuleState()); CDialog::OnInitDialog(); CreateColumns(); using namespace std::placeholders; SetTimer((UINT_PTR)this, 1000, TimerCallback); return TRUE; } void ServerDialog::CreateColumns() { AFX_MANAGE_STATE(AfxGetStaticModuleState()); PlayersListCtrl.InsertColumn(0, _T("Name"), LVCFMT_LEFT, 40); PlayersListCtrl.InsertColumn(1, _T("Status"), LVCFMT_LEFT, 80); PlayersListCtrl.InsertColumn(2, _T("Ping"), LVCFMT_LEFT, 40); PlayersListCtrl.InsertColumn(3, _T("Score"), LVCFMT_LEFT, 80); PlayersListCtrl.InsertColumn(4, _T("Team"), LVCFMT_LEFT, 80); for (int i = 0; i < NumColumns; i++) { PlayersListCtrl.SetColumnWidth(i, LVSCW_AUTOSIZE_USEHEADER); } } void ServerDialog::PostNcDestroy() { AFX_MANAGE_STATE(AfxGetStaticModuleState()); CDialog::PostNcDestroy(); } void ServerDialog::OnOK() { AFX_MANAGE_STATE(AfxGetStaticModuleState()); if (!UpdateData(TRUE)) return; DestroyWindow(); } void ServerDialog::OnCancel() { AFX_MANAGE_STATE(AfxGetStaticModuleState()); ShowWindow(SW_HIDE); DestroyWindow(); KillTimer((UINT_PTR)this); m_pParentWnd->SendMessage(WM_CLOSE, 0, 0); } void ServerDialog::RefreshPlayers() { if (!m_hWnd) { return; } AFX_MANAGE_STATE(AfxGetStaticModuleState()); const int savedSelection = PlayersListCtrl.GetSelectionMark(); PlayersListCtrl.DeleteAllItems(); const auto& pTextLookupService = m_serviceProvider->Get(); const auto& pGameServer = m_serviceProvider->Get(); for (const auto& player : pGameServer->GetPlayers()) { if (player->host) { continue; // Skip host player } LVITEM item{}; item.cColumns = NumColumns; item.mask = LVIF_COLUMNS | LVIF_PARAM; item.lParam = player->index; const int index = PlayersListCtrl.InsertItem(&item); PlayersListCtrl.SetItemText(index, 0, player->name.c_str()); PlayersListCtrl.SetItemText(index, 1, pTextLookupService->GetNetPlayerStateName(player->state).c_str()); PlayersListCtrl.SetItemText(index, 2, fmt::format(_T("{0}"), player->ping).c_str()); PlayersListCtrl.SetItemText(index, 3, fmt::format(_T("{0}"), player->score).c_str()); PlayersListCtrl.SetItemText(index, 4, pTextLookupService->GetPlayerTeamName(player->team).c_str()); } PlayersListCtrl.SetSelectionMark(savedSelection); } EventListenerResult ServerDialog::HandlePlayerConnected(const GameServerEvent& event) { RefreshPlayers(); return EventListenerResult::Continue; } EventListenerResult ServerDialog::HandlePlayerDisconnected(const GameServerEvent& event) { RefreshPlayers(); return EventListenerResult::Continue; } EventListenerResult ServerDialog::HandleChatMessage(const GameServerEvent& event) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); const auto& chatMessageEvent = (const ChatMessageEvent&)event; ConsoleEditBox.SetSel(-1, 0); ConsoleEditBox.ReplaceSel(chatMessageEvent.message.data()); ConsoleEditBox.SetSel(-1, 0); ConsoleEditBox.ReplaceSel("\n"); return EventListenerResult::Continue; } EventListenerResult ServerDialog::HandleWorldLoaded(const GameServerEvent& event) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); const auto& pGameServer = m_serviceProvider->Get(); auto details = pGameServer->GetGameDetails(); return EventListenerResult::Continue; // TODO: Connect to world state controls } BEGIN_MESSAGE_MAP(ServerDialog, CDialogEx) ON_BN_CLICKED(IDC_BAN, &ServerDialog::OnBnClickedBan) ON_NOTIFY(LVN_ITEMCHANGED, IDC_PLAYERS, &ServerDialog::OnItemChanged) ON_BN_CLICKED(IDC_KICK, &ServerDialog::OnBnClickedKick) END_MESSAGE_MAP() // ServerDialog message handlers void ServerDialog::OnBnClickedBan() { const int selection = PlayersListCtrl.GetSelectionMark(); if (selection == -1) { return; } const PlayerIndex playerIndex = (PlayerIndex)PlayersListCtrl.GetItemData(selection); if (playerIndex > 0) { const auto& pGameServer = m_serviceProvider->Get(); pGameServer->BanPlayer(playerIndex); } } void ServerDialog::OnBnClickedKick() { const int selection = PlayersListCtrl.GetSelectionMark(); if (selection == -1) { return; } const PlayerIndex playerIndex = (PlayerIndex)PlayersListCtrl.GetItemData(selection); if (playerIndex > 0) { const auto& pGameServer = m_serviceProvider->Get(); pGameServer->KickPlayer(playerIndex, KickReason::Removed); } } void ServerDialog::OnItemChanged(NMHDR* pNMHDR, LRESULT* pResult) { const LPNMLISTVIEW pNMListView = (const LPNMLISTVIEW)(pNMHDR); if (!(pNMListView->uChanged & LVIF_STATE)) { return; } if ((pNMListView->uOldState & LVIS_SELECTED) == (pNMListView->uNewState & LVIS_SELECTED)) { return; } ButtonKick.EnableWindow(TRUE); ButtonBan.EnableWindow(TRUE); *pResult = 0; }