integrate LAN into the UI better

also fix the MPInterface destructor
This commit is contained in:
Arisotura
2024-08-10 16:57:29 +02:00
parent e0f40cd2d1
commit 4f252cb713
11 changed files with 138 additions and 55 deletions

View File

@ -49,7 +49,7 @@ LANStartHostDialog::LANStartHostDialog(QWidget* parent) : QDialog(parent), ui(ne
ui->setupUi(this); ui->setupUi(this);
setAttribute(Qt::WA_DeleteOnClose); setAttribute(Qt::WA_DeleteOnClose);
MPInterface::Set(MPInterface_LAN); setMPInterface(MPInterface_LAN);
// TODO: remember the last setting? so this doesn't suck massively // TODO: remember the last setting? so this doesn't suck massively
// we could also remember the player name (and auto-init it from the firmware name or whatever) // we could also remember the player name (and auto-init it from the firmware name or whatever)
@ -85,7 +85,7 @@ void LANStartHostDialog::done(int r)
} }
else else
{ {
MPInterface::Set(MPInterface_Local); setMPInterface(MPInterface_Local);
} }
QDialog::done(r); QDialog::done(r);
@ -97,7 +97,7 @@ LANStartClientDialog::LANStartClientDialog(QWidget* parent) : QDialog(parent), u
ui->setupUi(this); ui->setupUi(this);
setAttribute(Qt::WA_DeleteOnClose); setAttribute(Qt::WA_DeleteOnClose);
MPInterface::Set(MPInterface_LAN); setMPInterface(MPInterface_LAN);
QStandardItemModel* model = new QStandardItemModel(); QStandardItemModel* model = new QStandardItemModel();
ui->tvAvailableGames->setModel(model); ui->tvAvailableGames->setModel(model);
@ -213,7 +213,7 @@ void LANStartClientDialog::done(int r)
else else
{ {
lan().EndDiscovery(); lan().EndDiscovery();
MPInterface::Set(MPInterface_Local); setMPInterface(MPInterface_Local);
} }
QDialog::done(r); QDialog::done(r);
@ -293,10 +293,26 @@ LANDialog::~LANDialog()
delete ui; delete ui;
} }
void LANDialog::on_btnLeaveGame_clicked()
{
done(QDialog::Accepted);
}
void LANDialog::done(int r) void LANDialog::done(int r)
{ {
// ??? bool showwarning = true;
// TODO handle this situation, and provide the user a way to reopen this dialog if (lan().GetNumPlayers() < 2)
showwarning = false;
if (showwarning)
{
if (QMessageBox::warning(this, "melonDS", "Really leave this LAN game?",
QMessageBox::Yes | QMessageBox::No, QMessageBox::No) == QMessageBox::No)
return;
}
lan().EndSession();
setMPInterface(MPInterface_Local);
QDialog::done(r); QDialog::done(r);
} }

View File

@ -104,6 +104,7 @@ protected:
void timerEvent(QTimerEvent* event) override; void timerEvent(QTimerEvent* event) override;
private slots: private slots:
void on_btnLeaveGame_clicked();
void done(int r); void done(int r);
void doUpdatePlayerList(); void doUpdatePlayerList();

View File

@ -11,15 +11,35 @@
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
<string>LAN SHITO</string> <string>LAN game - melonDS</string>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout_2"> <layout class="QVBoxLayout" name="verticalLayout">
<item> <item>
<widget class="QLabel" name="lblStatus"> <layout class="QHBoxLayout" name="horizontalLayout">
<property name="text"> <property name="leftMargin">
<string>STATUS PLACEHOLDER</string> <number>0</number>
</property> </property>
</widget> <item>
<widget class="QPushButton" name="btnLeaveGame">
<property name="text">
<string>Leave game</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item> </item>
<item> <item>
<widget class="QTreeView" name="tvPlayerList"/> <widget class="QTreeView" name="tvPlayerList"/>

View File

@ -749,6 +749,8 @@ MainWindow::MainWindow(int id, EmuInstance* inst, QWidget* parent) :
QObject::connect(qApp, &QApplication::applicationStateChanged, this, &MainWindow::onAppStateChanged); QObject::connect(qApp, &QApplication::applicationStateChanged, this, &MainWindow::onAppStateChanged);
onUpdateInterfaceSettings(); onUpdateInterfaceSettings();
updateMPInterface(MPInterface::GetType());
} }
MainWindow::~MainWindow() MainWindow::~MainWindow()
@ -1712,6 +1714,19 @@ void MainWindow::onNPTest()
//Netplay::StartGame(); //Netplay::StartGame();
} }
void MainWindow::updateMPInterface(MPInterfaceType type)
{
// MP interface was changed, reflect it in the UI
bool enable = (type == MPInterface_Local);
actMPNewInstance->setEnabled(enable);
actLANStartHost->setEnabled(enable);
actLANStartClient->setEnabled(enable);
actNPStartHost->setEnabled(enable);
actNPStartClient->setEnabled(enable);
actNPTest->setEnabled(enable);
}
bool MainWindow::lanWarning(bool host) bool MainWindow::lanWarning(bool host)
{ {
if (numEmuInstances() < 2) if (numEmuInstances() < 2)

View File

@ -35,6 +35,7 @@
#include "Screen.h" #include "Screen.h"
#include "Config.h" #include "Config.h"
#include "MPInterface.h"
class EmuInstance; class EmuInstance;
@ -125,6 +126,9 @@ public:
void osdAddMessage(unsigned int color, const char* msg); void osdAddMessage(unsigned int color, const char* msg);
// called when the MP interface is changed
void updateMPInterface(melonDS::MPInterfaceType type);
protected: protected:
void keyPressEvent(QKeyEvent* event) override; void keyPressEvent(QKeyEvent* event) override;
void keyReleaseEvent(QKeyEvent* event) override; void keyReleaseEvent(QKeyEvent* event) override;

View File

@ -205,6 +205,28 @@ void pathInit()
} }
void setMPInterface(MPInterfaceType type)
{
// switch to the requested MP interface
MPInterface::Set(type);
// set receive timeout
// TODO: different settings per interface?
MPInterface::Get().SetRecvTimeout(Config::GetGlobalTable().GetInt("MP.RecvTimeout"));
// update UI appropriately
// TODO: decide how to deal with multi-window when it becomes a thing
for (int i = 0; i < kMaxEmuInstances; i++)
{
EmuInstance* inst = emuInstances[i];
if (!inst) continue;
MainWindow* win = inst->getMainWindow();
if (win) win->updateMPInterface(type);
}
}
MelonApplication::MelonApplication(int& argc, char** argv) MelonApplication::MelonApplication(int& argc, char** argv)
: QApplication(argc, argv) : QApplication(argc, argv)
@ -313,8 +335,7 @@ int main(int argc, char** argv)
// default MP interface type is local MP // default MP interface type is local MP
// this will be changed if a LAN or netplay session is initiated // this will be changed if a LAN or netplay session is initiated
MPInterface::Set(MPInterface_Local); setMPInterface(MPInterface_Local);
MPInterface::Get().SetRecvTimeout(Config::GetGlobalTable().GetInt("MP.RecvTimeout"));
NetInit(); NetInit();

View File

@ -29,6 +29,7 @@
#include "Window.h" #include "Window.h"
#include "EmuThread.h" #include "EmuThread.h"
#include "ScreenLayout.h" #include "ScreenLayout.h"
#include "MPInterface.h"
class MelonApplication : public QApplication class MelonApplication : public QApplication
{ {
@ -49,4 +50,6 @@ void deleteEmuInstance(int id);
void deleteAllEmuInstances(int first = 0); void deleteAllEmuInstances(int first = 0);
int numEmuInstances(); int numEmuInstances();
void setMPInterface(melonDS::MPInterfaceType type);
#endif // MAIN_H #endif // MAIN_H

View File

@ -17,10 +17,7 @@
*/ */
#include <stdio.h> #include <stdio.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include <queue>
#include <vector>
#ifdef __WIN32__ #ifdef __WIN32__
#include <winsock2.h> #include <winsock2.h>
@ -107,46 +104,25 @@ LAN::LAN() noexcept : Inited(false)
// TODO make this somewhat nicer // TODO make this somewhat nicer
if (enet_initialize() != 0) if (enet_initialize() != 0)
{ {
printf("enet shat itself :(\n"); Platform::Log(Platform::LogLevel::Error, "LAN: failed to initialize enet\n");
return; return;
} }
printf("enet init OK\n"); Platform::Log(Platform::LogLevel::Info, "LAN: enet initialized\n");
Inited = true; Inited = true;
} }
LAN::~LAN() noexcept LAN::~LAN() noexcept
{ {
if (DiscoverySocket) EndSession();
{
closesocket(DiscoverySocket);
DiscoverySocket = INVALID_SOCKET;
}
while (!RXQueue.empty())
{
ENetPacket* packet = RXQueue.front();
RXQueue.pop();
enet_packet_destroy(packet);
}
for (int i = 0; i < 16; i++)
{
if (i == MyPlayer.ID) continue;
if (RemotePeers[i])
enet_peer_disconnect(RemotePeers[i], 0);
RemotePeers[i] = nullptr;
}
enet_host_destroy(Host);
Host = nullptr;
Inited = false;
enet_deinitialize(); enet_deinitialize();
Platform::Mutex_Free(DiscoveryMutex); Platform::Mutex_Free(DiscoveryMutex);
Platform::Mutex_Free(PlayersMutex); Platform::Mutex_Free(PlayersMutex);
Platform::Log(Platform::LogLevel::Info, "LAN: enet deinitialized\n");
} }
@ -281,9 +257,6 @@ bool LAN::StartHost(const char* playername, int numplayers)
Active = true; Active = true;
IsHost = true; IsHost = true;
//if (lanDlg)
// lanDlg->updatePlayerList();
StartDiscovery(); StartDiscovery();
return true; return true;
} }
@ -398,6 +371,35 @@ bool LAN::StartClient(const char* playername, const char* host)
return true; return true;
} }
void LAN::EndSession()
{
if (!Active) return;
if (IsHost) EndDiscovery();
Active = false;
while (!RXQueue.empty())
{
ENetPacket* packet = RXQueue.front();
RXQueue.pop();
enet_packet_destroy(packet);
}
for (int i = 0; i < 16; i++)
{
if (i == MyPlayer.ID) continue;
if (RemotePeers[i])
enet_peer_disconnect(RemotePeers[i], 0);
RemotePeers[i] = nullptr;
}
enet_host_destroy(Host);
Host = nullptr;
IsHost = false;
}
void LAN::ProcessDiscovery() void LAN::ProcessDiscovery()
{ {
@ -631,7 +633,6 @@ void LAN::ProcessHostEvent(ENetEvent& event)
{ {
if (event.packet->dataLength != 1) break; if (event.packet->dataLength != 1) break;
Player* player = (Player*)event.peer->data; Player* player = (Player*)event.peer->data;
//printf("HOST: PLAYER CONNECT %p\n", player);
if (!player) break; if (!player) break;
ConnectedBitmask |= (1 << player->ID); ConnectedBitmask |= (1 << player->ID);
@ -642,7 +643,6 @@ void LAN::ProcessHostEvent(ENetEvent& event)
{ {
if (event.packet->dataLength != 1) break; if (event.packet->dataLength != 1) break;
Player* player = (Player*)event.peer->data; Player* player = (Player*)event.peer->data;
//printf("HOST: PLAYER DISCONNECT %p\n", player);
if (!player) break; if (!player) break;
ConnectedBitmask &= ~(1 << player->ID); ConnectedBitmask &= ~(1 << player->ID);
@ -757,7 +757,6 @@ void LAN::ProcessClientEvent(ENetEvent& event)
{ {
if (event.packet->dataLength != 1) break; if (event.packet->dataLength != 1) break;
Player* player = (Player*)event.peer->data; Player* player = (Player*)event.peer->data;
//printf("CLIENT: PLAYER CONNECT %p\n", player);
if (!player) break; if (!player) break;
ConnectedBitmask |= (1 << player->ID); ConnectedBitmask |= (1 << player->ID);
@ -768,7 +767,6 @@ void LAN::ProcessClientEvent(ENetEvent& event)
{ {
if (event.packet->dataLength != 1) break; if (event.packet->dataLength != 1) break;
Player* player = (Player*)event.peer->data; Player* player = (Player*)event.peer->data;
//printf("CLIENT: PLAYER DISCONNECT %p\n", player);
if (!player) break; if (!player) break;
ConnectedBitmask &= ~(1 << player->ID); ConnectedBitmask &= ~(1 << player->ID);
@ -796,7 +794,6 @@ void LAN::ProcessEvent(ENetEvent& event)
void LAN::ProcessLAN(int type) void LAN::ProcessLAN(int type)
{ {
if (!Host) return; if (!Host) return;
//printf("Process(%d): %d %d\n", type, RXQueue.empty(), RXQueue.size());
u32 time_last = (u32)Platform::GetMSCount(); u32 time_last = (u32)Platform::GetMSCount();
@ -842,7 +839,7 @@ void LAN::ProcessLAN(int type)
if (event.type == ENET_EVENT_TYPE_RECEIVE && event.channelID == Chan_MP) if (event.type == ENET_EVENT_TYPE_RECEIVE && event.channelID == Chan_MP)
{ {
MPPacketHeader* header = (MPPacketHeader*)&event.packet->data[0]; MPPacketHeader* header = (MPPacketHeader*)&event.packet->data[0];
//printf("- enet_host_service: (%d) got MP frame, len=%d type=%08X fc=%04X\n", type, event.packet->dataLength, header->Type, *(u16*)&event.packet->data[sizeof(MPPacketHeader)+12]);
bool good = true; bool good = true;
if (event.packet->dataLength < sizeof(MPPacketHeader)) if (event.packet->dataLength < sizeof(MPPacketHeader))
good = false; good = false;
@ -870,7 +867,6 @@ void LAN::ProcessLAN(int type)
} }
else else
{ {
//printf("- enet_host_service: got something else, time=%d\n", SDL_GetTicks()-time_last);
ProcessEvent(event); ProcessEvent(event);
} }
@ -1053,7 +1049,6 @@ u16 LAN::RecvReplies(int inst, u8* packets, u64 timestamp, u16 aidmask)
if (RXQueue.empty()) if (RXQueue.empty())
{ {
// no more replies available // no more replies available
//printf("RecvMPReplies timeout, ret=%04X myinstmask=%04X conn=%04X aidmask=%04X\n", ret, myinstmask, ConnectedBitmask, aidmask);
return ret; return ret;
} }

View File

@ -87,6 +87,7 @@ public:
void EndDiscovery(); void EndDiscovery();
bool StartHost(const char* player, int numplayers); bool StartHost(const char* player, int numplayers);
bool StartClient(const char* player, const char* host); bool StartClient(const char* player, const char* host);
void EndSession();
std::map<u32, DiscoveryData> GetDiscoveryList(); std::map<u32, DiscoveryData> GetDiscoveryList();
std::vector<Player> GetPlayerList(); std::vector<Player> GetPlayerList();

View File

@ -42,6 +42,7 @@ public:
std::unique_ptr<MPInterface> MPInterface::Current(std::make_unique<DummyMP>()); std::unique_ptr<MPInterface> MPInterface::Current(std::make_unique<DummyMP>());
MPInterfaceType MPInterface::CurrentType = MPInterface_Dummy;
void MPInterface::Set(MPInterfaceType type) void MPInterface::Set(MPInterfaceType type)
@ -60,6 +61,8 @@ void MPInterface::Set(MPInterfaceType type)
Current = std::make_unique<DummyMP>(); Current = std::make_unique<DummyMP>();
break; break;
} }
CurrentType = type;
} }
} }

View File

@ -46,7 +46,10 @@ struct MPPacketHeader
class MPInterface class MPInterface
{ {
public: public:
virtual ~MPInterface() = default;
static MPInterface& Get() { return *Current; } static MPInterface& Get() { return *Current; }
static MPInterfaceType GetType() { return CurrentType; }
static void Set(MPInterfaceType type); static void Set(MPInterfaceType type);
[[nodiscard]] int GetRecvTimeout() const noexcept { return RecvTimeout; } [[nodiscard]] int GetRecvTimeout() const noexcept { return RecvTimeout; }
@ -70,6 +73,7 @@ protected:
int RecvTimeout = 25; int RecvTimeout = 25;
private: private:
static MPInterfaceType CurrentType;
static std::unique_ptr<MPInterface> Current; static std::unique_ptr<MPInterface> Current;
}; };