Added NetPlay server force resync and drop player UI functionality.
This commit is contained in:
parent
75e9627aa8
commit
ee814f99e5
|
@ -237,8 +237,9 @@ void NetPlayServer::processPendingConnections(void)
|
||||||
|
|
||||||
netPlayAuthReq msg;
|
netPlayAuthReq msg;
|
||||||
|
|
||||||
msg.toNetworkByteOrder();
|
sendMsg( client, &msg, sizeof(msg), [&msg]{ msg.toNetworkByteOrder(); } );
|
||||||
sendMsg( client, &msg, sizeof(msg) );
|
|
||||||
|
emit clientConnected();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -258,17 +259,22 @@ int NetPlayServer::closeAllConnections(void)
|
||||||
delete client;
|
delete client;
|
||||||
}
|
}
|
||||||
clientList.clear();
|
clientList.clear();
|
||||||
|
emit clientDisconnected();
|
||||||
|
|
||||||
|
roleMask = 0;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
int NetPlayServer::sendMsg( NetPlayClient *client, void *msg, size_t msgSize)
|
int NetPlayServer::sendMsg( NetPlayClient *client, void *msg, size_t msgSize, std::function<void(void)> netByteOrderConvertFunc)
|
||||||
{
|
{
|
||||||
QTcpSocket* sock;
|
QTcpSocket* sock;
|
||||||
|
|
||||||
sock = client->getSocket();
|
sock = client->getSocket();
|
||||||
|
|
||||||
|
netByteOrderConvertFunc();
|
||||||
|
|
||||||
sock->write( static_cast<const char *>(msg), msgSize );
|
sock->write( static_cast<const char *>(msg), msgSize );
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -323,8 +329,7 @@ int NetPlayServer::sendRomLoadReq( NetPlayClient *client )
|
||||||
printf("Sending ROM Load Request: %s %lu\n", filepath, fileSize );
|
printf("Sending ROM Load Request: %s %lu\n", filepath, fileSize );
|
||||||
FCEUI_SetEmulationPaused(EMULATIONPAUSED_PAUSED);
|
FCEUI_SetEmulationPaused(EMULATIONPAUSED_PAUSED);
|
||||||
|
|
||||||
msg.toNetworkByteOrder();
|
sendMsg( client, &msg, sizeof(netPlayLoadRomReq), [&msg]{ msg.toNetworkByteOrder(); } );
|
||||||
sendMsg( client, &msg, sizeof(netPlayLoadRomReq) );
|
|
||||||
|
|
||||||
while ( (bytesRead = fread( buf, 1, sizeof(buf), fp )) > 0 )
|
while ( (bytesRead = fread( buf, 1, sizeof(buf), fp )) > 0 )
|
||||||
{
|
{
|
||||||
|
@ -353,8 +358,7 @@ int NetPlayServer::sendStateSyncReq( NetPlayClient *client )
|
||||||
printf("Sending ROM Sync Request\n");
|
printf("Sending ROM Sync Request\n");
|
||||||
FCEUI_SetEmulationPaused(EMULATIONPAUSED_PAUSED);
|
FCEUI_SetEmulationPaused(EMULATIONPAUSED_PAUSED);
|
||||||
|
|
||||||
hdr.toNetworkByteOrder();
|
sendMsg( client, &hdr, sizeof(netPlayMsgHdr), [&hdr]{ hdr.toNetworkByteOrder(); } );
|
||||||
sendMsg( client, &hdr, sizeof(netPlayMsgHdr) );
|
|
||||||
sendMsg( client, em.buf(), em.size() );
|
sendMsg( client, em.buf(), em.size() );
|
||||||
|
|
||||||
opsCrc32 = 0;
|
opsCrc32 = 0;
|
||||||
|
@ -397,6 +401,18 @@ bool NetPlayServer::claimRole(NetPlayClient* client, int _role)
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
void NetPlayServer::releaseRole(NetPlayClient* client)
|
||||||
|
{
|
||||||
|
int role = client->role;
|
||||||
|
|
||||||
|
if ( (role >= NETPLAY_PLAYER1) && (role <= NETPLAY_PLAYER4) )
|
||||||
|
{
|
||||||
|
int mask = (0x01 << role);
|
||||||
|
|
||||||
|
roleMask = roleMask & ~mask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
void NetPlayServer::onRomLoad()
|
void NetPlayServer::onRomLoad()
|
||||||
{
|
{
|
||||||
//printf("New ROM Loaded!\n");
|
//printf("New ROM Loaded!\n");
|
||||||
|
@ -420,6 +436,20 @@ void NetPlayServer::onNesReset()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
void NetPlayServer::resyncClient( NetPlayClient *client )
|
||||||
|
{
|
||||||
|
sendRomLoadReq( client );
|
||||||
|
sendStateSyncReq( client );
|
||||||
|
}
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
void NetPlayServer::resyncAllClients()
|
||||||
|
{
|
||||||
|
for (auto& client : clientList )
|
||||||
|
{
|
||||||
|
resyncClient( client );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
static void serverMessageCallback( void *userData, void *msgBuf, size_t msgSize )
|
static void serverMessageCallback( void *userData, void *msgBuf, size_t msgSize )
|
||||||
{
|
{
|
||||||
NetPlayServer *server = NetPlayServer::GetInstance();
|
NetPlayServer *server = NetPlayServer::GetInstance();
|
||||||
|
@ -457,8 +487,7 @@ void NetPlayServer::serverProcessMessage( NetPlayClient *client, void *msgBuf, s
|
||||||
netPlayErrorMsg<128> errorMsg;
|
netPlayErrorMsg<128> errorMsg;
|
||||||
errorMsg.setDisconnectFlag();
|
errorMsg.setDisconnectFlag();
|
||||||
errorMsg.printf("Invalid Password");
|
errorMsg.printf("Invalid Password");
|
||||||
errorMsg.toNetworkByteOrder();
|
sendMsg( client, &errorMsg, errorMsg.hdr.msgSize, [&errorMsg]{ errorMsg.toNetworkByteOrder(); } );
|
||||||
sendMsg( client, &errorMsg, errorMsg.hdr.msgSize );
|
|
||||||
client->flushData();
|
client->flushData();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -478,8 +507,7 @@ void NetPlayServer::serverProcessMessage( NetPlayClient *client, void *msgBuf, s
|
||||||
netPlayErrorMsg<128> errorMsg;
|
netPlayErrorMsg<128> errorMsg;
|
||||||
errorMsg.setDisconnectFlag();
|
errorMsg.setDisconnectFlag();
|
||||||
errorMsg.printf("Player %i role is not available", msg->playerId+1);
|
errorMsg.printf("Player %i role is not available", msg->playerId+1);
|
||||||
errorMsg.toNetworkByteOrder();
|
sendMsg( client, &errorMsg, errorMsg.hdr.msgSize, [&errorMsg]{ errorMsg.toNetworkByteOrder(); } );
|
||||||
sendMsg( client, &errorMsg, errorMsg.hdr.msgSize );
|
|
||||||
client->flushData();
|
client->flushData();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -496,7 +524,8 @@ void NetPlayServer::serverProcessMessage( NetPlayClient *client, void *msgBuf, s
|
||||||
client->gpData[2] = msg->ctrlState[2];
|
client->gpData[2] = msg->ctrlState[2];
|
||||||
client->gpData[3] = msg->ctrlState[3];
|
client->gpData[3] = msg->ctrlState[3];
|
||||||
|
|
||||||
client->setPaused( (msg->flags & netPlayClientState::PAUSE_FLAG) ? true : false );
|
client->setPaused( (msg->flags & netPlayClientState::PAUSE_FLAG ) ? true : false );
|
||||||
|
client->setDesync( (msg->flags & netPlayClientState::DESYNC_FLAG) ? true : false );
|
||||||
|
|
||||||
NetPlayFrameData data;
|
NetPlayFrameData data;
|
||||||
if ( (msg->opsFrame == 0) || netPlayFrameData.find( msg->opsFrame, data ) )
|
if ( (msg->opsFrame == 0) || netPlayFrameData.find( msg->opsFrame, data ) )
|
||||||
|
@ -619,7 +648,6 @@ void NetPlayServer::update(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (client->shouldDestroy())
|
if (client->shouldDestroy())
|
||||||
{
|
{
|
||||||
it = clientList.erase(it);
|
it = clientList.erase(it);
|
||||||
|
@ -630,7 +658,10 @@ void NetPlayServer::update(void)
|
||||||
clientPlayer[i] = nullptr;
|
clientPlayer[i] = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
releaseRole(client);
|
||||||
delete client;
|
delete client;
|
||||||
|
//printf("Emit clientDisconnected!\n");
|
||||||
|
emit clientDisconnected();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -873,12 +904,12 @@ void NetPlayClient::onDisconnect(void)
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
void NetPlayClient::onSocketError(QAbstractSocket::SocketError error)
|
void NetPlayClient::onSocketError(QAbstractSocket::SocketError error)
|
||||||
{
|
{
|
||||||
FCEU_DispMessage("Socket Error",0);
|
//FCEU_DispMessage("Socket Error",0);
|
||||||
|
|
||||||
QString errorMsg = sock->errorString();
|
QString errorMsg = sock->errorString();
|
||||||
printf("Error: %s\n", errorMsg.toLocal8Bit().constData());
|
printf("Error: %s\n", errorMsg.toLocal8Bit().constData());
|
||||||
|
|
||||||
FCEU_DispMessage("%s", 0, errorMsg.toLocal8Bit().constData());
|
FCEU_DispMessage("Socket Error: %s", 0, errorMsg.toLocal8Bit().constData());
|
||||||
|
|
||||||
emit errorOccurred(errorMsg);
|
emit errorOccurred(errorMsg);
|
||||||
}
|
}
|
||||||
|
@ -932,6 +963,10 @@ void NetPlayClient::update(void)
|
||||||
{
|
{
|
||||||
statusMsg.flags |= netPlayClientState::PAUSE_FLAG;
|
statusMsg.flags |= netPlayClientState::PAUSE_FLAG;
|
||||||
}
|
}
|
||||||
|
if (desyncCount > 0)
|
||||||
|
{
|
||||||
|
statusMsg.flags |= netPlayClientState::DESYNC_FLAG;
|
||||||
|
}
|
||||||
statusMsg.frameRdy = inputFrameBack();
|
statusMsg.frameRdy = inputFrameBack();
|
||||||
statusMsg.frameRun = currFrame;
|
statusMsg.frameRun = currFrame;
|
||||||
statusMsg.opsFrame = lastFrameData.frameNum;
|
statusMsg.opsFrame = lastFrameData.frameNum;
|
||||||
|
@ -1452,35 +1487,58 @@ NetPlayHostStatusDialog* NetPlayHostStatusDialog::instance = nullptr;
|
||||||
NetPlayHostStatusDialog::NetPlayHostStatusDialog(QWidget *parent)
|
NetPlayHostStatusDialog::NetPlayHostStatusDialog(QWidget *parent)
|
||||||
: QDialog(parent)
|
: QDialog(parent)
|
||||||
{
|
{
|
||||||
QVBoxLayout *mainLayout;
|
QVBoxLayout *mainLayout, *vbox1;
|
||||||
QHBoxLayout *hbox;
|
QHBoxLayout *hbox;
|
||||||
//QGridLayout *grid;
|
//QGridLayout *grid;
|
||||||
|
QGroupBox *gbox;
|
||||||
QPushButton *closeButton;
|
QPushButton *closeButton;
|
||||||
//QLabel *lbl;
|
//QLabel *lbl;
|
||||||
|
|
||||||
instance = this;
|
instance = this;
|
||||||
|
|
||||||
setWindowTitle("NetPlay Status");
|
setWindowTitle("NetPlay Status");
|
||||||
|
resize( 512, 256 );
|
||||||
|
|
||||||
mainLayout = new QVBoxLayout();
|
mainLayout = new QVBoxLayout();
|
||||||
|
vbox1 = new QVBoxLayout();
|
||||||
|
|
||||||
|
gbox = new QGroupBox(tr("Connected Players / Spectators"));
|
||||||
clientTree = new QTreeWidget();
|
clientTree = new QTreeWidget();
|
||||||
mainLayout->addWidget( clientTree );
|
dropPlayerButton = new QPushButton( tr("Drop Player") );
|
||||||
|
resyncPlayerButton = new QPushButton( tr("Resync Player") );
|
||||||
|
resyncAllButton = new QPushButton( tr("Resync All") );
|
||||||
|
|
||||||
|
dropPlayerButton->setEnabled(false);
|
||||||
|
resyncPlayerButton->setEnabled(false);
|
||||||
|
|
||||||
|
gbox->setLayout(vbox1);
|
||||||
|
vbox1->addWidget( clientTree );
|
||||||
|
|
||||||
|
hbox = new QHBoxLayout();
|
||||||
|
hbox->addWidget( dropPlayerButton, 1 );
|
||||||
|
hbox->addStretch(3);
|
||||||
|
hbox->addWidget( resyncPlayerButton, 1 );
|
||||||
|
hbox->addWidget( resyncAllButton, 1 );
|
||||||
|
vbox1->addLayout(hbox);
|
||||||
|
|
||||||
|
mainLayout->addWidget( gbox );
|
||||||
|
|
||||||
clientTree->setColumnCount(3);
|
clientTree->setColumnCount(3);
|
||||||
|
|
||||||
auto* item = new QTreeWidgetItem();
|
auto* item = new QTreeWidgetItem();
|
||||||
item->setText( 0, QString::fromStdString( "Player" ) );
|
item->setText( 0, QString::fromStdString( "Player" ) );
|
||||||
item->setText( 1, QString::fromStdString( "Role" ) );
|
item->setText( 1, QString::fromStdString( "Role" ) );
|
||||||
item->setText( 2, QString::fromStdString( "State" ) );
|
item->setText( 2, QString::fromStdString( "Frame" ) );
|
||||||
|
item->setText( 3, QString::fromStdString( "State" ) );
|
||||||
item->setTextAlignment( 0, Qt::AlignLeft);
|
item->setTextAlignment( 0, Qt::AlignLeft);
|
||||||
item->setTextAlignment( 1, Qt::AlignLeft);
|
item->setTextAlignment( 1, Qt::AlignLeft);
|
||||||
item->setTextAlignment( 2, Qt::AlignLeft);
|
item->setTextAlignment( 2, Qt::AlignLeft);
|
||||||
|
item->setTextAlignment( 3, Qt::AlignLeft);
|
||||||
|
|
||||||
//connect( clientTree, SIGNAL(itemClicked(QTreeWidgetItem*, int)),
|
connect( clientTree, SIGNAL(itemClicked(QTreeWidgetItem*, int)), this, SLOT(clientItemClicked( QTreeWidgetItem*, int)) );
|
||||||
//this, SLOT(watchClicked( QTreeWidgetItem*, int)) );
|
|
||||||
|
|
||||||
clientTree->setHeaderItem( item );
|
clientTree->setHeaderItem( item );
|
||||||
|
clientTree->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||||
|
|
||||||
closeButton = new QPushButton( tr("Close") );
|
closeButton = new QPushButton( tr("Close") );
|
||||||
closeButton->setIcon(style()->standardIcon(QStyle::SP_DialogCloseButton));
|
closeButton->setIcon(style()->standardIcon(QStyle::SP_DialogCloseButton));
|
||||||
|
@ -1493,12 +1551,26 @@ NetPlayHostStatusDialog::NetPlayHostStatusDialog(QWidget *parent)
|
||||||
|
|
||||||
setLayout(mainLayout);
|
setLayout(mainLayout);
|
||||||
|
|
||||||
|
connect( NetPlayServer::GetInstance(), SIGNAL(clientConnected(void)), this, SLOT(loadClientTree(void)) );
|
||||||
|
connect( NetPlayServer::GetInstance(), SIGNAL(clientDisconnected(void)), this, SLOT(loadClientTree(void)) );
|
||||||
|
connect( clientTree, &QTreeWidget::customContextMenuRequested, this, &NetPlayHostStatusDialog::onClientTreeContextMenu);
|
||||||
|
|
||||||
|
connect( dropPlayerButton , SIGNAL(clicked(void)), this, SLOT(dropPlayer(void)) );
|
||||||
|
connect( resyncPlayerButton, SIGNAL(clicked(void)), this, SLOT(resyncPlayer(void)) );
|
||||||
|
connect( resyncAllButton , SIGNAL(clicked(void)), this, SLOT(resyncAllPlayers(void)) );
|
||||||
|
|
||||||
loadClientTree();
|
loadClientTree();
|
||||||
|
|
||||||
|
periodicTimer = new QTimer(this);
|
||||||
|
periodicTimer->start(200); // 5hz
|
||||||
|
connect(periodicTimer, &QTimer::timeout, this, &NetPlayHostStatusDialog::updatePeriodic);
|
||||||
}
|
}
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
NetPlayHostStatusDialog::~NetPlayHostStatusDialog(void)
|
NetPlayHostStatusDialog::~NetPlayHostStatusDialog(void)
|
||||||
{
|
{
|
||||||
instance = nullptr;
|
instance = nullptr;
|
||||||
|
periodicTimer->stop();
|
||||||
|
delete periodicTimer;
|
||||||
//printf("Destroy NetPlay Status Window\n");
|
//printf("Destroy NetPlay Status Window\n");
|
||||||
}
|
}
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
|
@ -1517,20 +1589,142 @@ void NetPlayHostStatusDialog::closeWindow(void)
|
||||||
deleteLater();
|
deleteLater();
|
||||||
}
|
}
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
|
void NetPlayHostStatusDialog::dropPlayer(void)
|
||||||
|
{
|
||||||
|
auto* clientItem = static_cast<NetPlayClientTreeItem*>(clientTree->currentItem());
|
||||||
|
|
||||||
|
if (clientItem != nullptr)
|
||||||
|
{
|
||||||
|
clientItem->client->forceDisconnect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void NetPlayHostStatusDialog::resyncPlayer(void)
|
||||||
|
{
|
||||||
|
auto* clientItem = static_cast<NetPlayClientTreeItem*>(clientTree->currentItem());
|
||||||
|
|
||||||
|
if (clientItem != nullptr)
|
||||||
|
{
|
||||||
|
auto* server = NetPlayServer::GetInstance();
|
||||||
|
|
||||||
|
if ( (server != nullptr) && (clientItem->client != nullptr) )
|
||||||
|
{
|
||||||
|
server->resyncClient( clientItem->client );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void NetPlayHostStatusDialog::resyncAllPlayers(void)
|
||||||
|
{
|
||||||
|
auto* server = NetPlayServer::GetInstance();
|
||||||
|
|
||||||
|
if (server != nullptr)
|
||||||
|
{
|
||||||
|
server->resyncAllClients();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void NetPlayHostStatusDialog::clientItemClicked( QTreeWidgetItem* item, int column)
|
||||||
|
{
|
||||||
|
auto* clientItem = static_cast<NetPlayClientTreeItem*>(item);
|
||||||
|
|
||||||
|
bool hasClient = clientItem->client != nullptr;
|
||||||
|
|
||||||
|
dropPlayerButton->setEnabled( hasClient );
|
||||||
|
resyncPlayerButton->setEnabled( hasClient );
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void NetPlayHostStatusDialog::onClientTreeContextMenu(const QPoint &pos)
|
||||||
|
{
|
||||||
|
QAction *act;
|
||||||
|
QMenu menu(this);
|
||||||
|
|
||||||
|
printf("Custom Menu (%i,%i)\n", pos.x(), pos.y());
|
||||||
|
|
||||||
|
act = new QAction(tr("Resync Client"), &menu);
|
||||||
|
//act->setShortcut( QKeySequence(tr("R")));
|
||||||
|
//connect( act, SIGNAL(triggered(void)), this, SLOT(openTileEditor(void)) );
|
||||||
|
menu.addAction( act );
|
||||||
|
|
||||||
|
act = new QAction(tr("Drop Client"), &menu);
|
||||||
|
//act->setShortcut( QKeySequence(tr("D")));
|
||||||
|
//connect( act, SIGNAL(triggered(void)), this, SLOT(openTileEditor(void)) );
|
||||||
|
menu.addAction( act );
|
||||||
|
|
||||||
|
menu.exec( clientTree->mapToGlobal(pos) );
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void NetPlayClientTreeItem::updateData()
|
||||||
|
{
|
||||||
|
const char *roleString = nullptr;
|
||||||
|
|
||||||
|
if (server != nullptr)
|
||||||
|
{
|
||||||
|
QString state;
|
||||||
|
roleString = NetPlayPlayerRoleToString( server->getRole() );
|
||||||
|
|
||||||
|
if (FCEUI_EmulationPaused())
|
||||||
|
{
|
||||||
|
state += QObject::tr("Paused");
|
||||||
|
}
|
||||||
|
|
||||||
|
setText( 0, QObject::tr("Host") );
|
||||||
|
setText( 1, QObject::tr(roleString) );
|
||||||
|
setText( 2, QString::number(static_cast<uint32_t>(currFrameCounter)));
|
||||||
|
setText( 3, state);
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (client != nullptr)
|
||||||
|
{
|
||||||
|
QString state;
|
||||||
|
roleString = NetPlayPlayerRoleToString( client->role );
|
||||||
|
|
||||||
|
if (client->isPaused())
|
||||||
|
{
|
||||||
|
state += QObject::tr("Paused");
|
||||||
|
}
|
||||||
|
if (client->hasDesync())
|
||||||
|
{
|
||||||
|
if (!state.isEmpty())
|
||||||
|
{
|
||||||
|
state += QObject::tr(",");
|
||||||
|
}
|
||||||
|
state += QObject::tr("Desync");
|
||||||
|
}
|
||||||
|
|
||||||
|
setText( 0, client->userName );
|
||||||
|
setText( 1, QObject::tr(roleString) );
|
||||||
|
setText( 2, QString::number(client->currentFrame) );
|
||||||
|
setText( 3, state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void NetPlayHostStatusDialog::updatePeriodic()
|
||||||
|
{
|
||||||
|
for (int i=0; i<clientTree->topLevelItemCount(); i++)
|
||||||
|
{
|
||||||
|
NetPlayClientTreeItem *item = static_cast<NetPlayClientTreeItem*>( clientTree->topLevelItem(i) );
|
||||||
|
|
||||||
|
item->updateData();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
void NetPlayHostStatusDialog::loadClientTree()
|
void NetPlayHostStatusDialog::loadClientTree()
|
||||||
{
|
{
|
||||||
auto* server = NetPlayServer::GetInstance();
|
auto* server = NetPlayServer::GetInstance();
|
||||||
|
|
||||||
|
//printf("Load Client Connection Tree\n");
|
||||||
|
|
||||||
|
clientTree->clear();
|
||||||
|
|
||||||
if (server == nullptr)
|
if (server == nullptr)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const char *roleString = NetPlayPlayerRoleToString( server->getRole() );
|
|
||||||
auto* serverTopLvlItem = new NetPlayClientTreeItem();
|
auto* serverTopLvlItem = new NetPlayClientTreeItem();
|
||||||
|
|
||||||
serverTopLvlItem->server = server;
|
serverTopLvlItem->server = server;
|
||||||
serverTopLvlItem->setText( 0, tr("Host") );
|
serverTopLvlItem->updateData();
|
||||||
serverTopLvlItem->setText( 1, tr(roleString) );
|
|
||||||
|
|
||||||
clientTree->addTopLevelItem( serverTopLvlItem );
|
clientTree->addTopLevelItem( serverTopLvlItem );
|
||||||
|
|
||||||
|
@ -1538,14 +1732,10 @@ void NetPlayHostStatusDialog::loadClientTree()
|
||||||
|
|
||||||
for (auto& client : clientList)
|
for (auto& client : clientList)
|
||||||
{
|
{
|
||||||
roleString = NetPlayPlayerRoleToString( client->role );
|
|
||||||
|
|
||||||
auto* clientTopLvlItem = new NetPlayClientTreeItem();
|
auto* clientTopLvlItem = new NetPlayClientTreeItem();
|
||||||
|
|
||||||
clientTopLvlItem->client = client;
|
clientTopLvlItem->client = client;
|
||||||
|
clientTopLvlItem->updateData();
|
||||||
clientTopLvlItem->setText( 0, client->userName );
|
|
||||||
clientTopLvlItem->setText( 1, tr(roleString) );
|
|
||||||
|
|
||||||
clientTree->addTopLevelItem( clientTopLvlItem );
|
clientTree->addTopLevelItem( clientTopLvlItem );
|
||||||
}
|
}
|
||||||
|
@ -1571,6 +1761,12 @@ void NetPlayPeriodicUpdate(void)
|
||||||
if (client)
|
if (client)
|
||||||
{
|
{
|
||||||
client->update();
|
client->update();
|
||||||
|
|
||||||
|
if ( client->shouldDestroy() )
|
||||||
|
{
|
||||||
|
NetPlayClient::Destroy();
|
||||||
|
client = nullptr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
NetPlayServer *server = NetPlayServer::GetInstance();
|
NetPlayServer *server = NetPlayServer::GetInstance();
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <list>
|
#include <list>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
#include <QDialog>
|
#include <QDialog>
|
||||||
|
@ -124,12 +125,16 @@ class NetPlayServer : public QTcpServer
|
||||||
input.clear();
|
input.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
int sendMsg( NetPlayClient *client, void *msg, size_t msgSize);
|
void resyncClient( NetPlayClient *client );
|
||||||
|
void resyncAllClients();
|
||||||
|
|
||||||
|
int sendMsg( NetPlayClient *client, void *msg, size_t msgSize, std::function<void(void)> netByteOrderConvertFunc = []{});
|
||||||
int sendRomLoadReq( NetPlayClient *client );
|
int sendRomLoadReq( NetPlayClient *client );
|
||||||
int sendStateSyncReq( NetPlayClient *client );
|
int sendStateSyncReq( NetPlayClient *client );
|
||||||
void setRole(int _role);
|
void setRole(int _role);
|
||||||
int getRole(void){ return role; }
|
int getRole(void){ return role; }
|
||||||
bool claimRole(NetPlayClient* client, int _role);
|
bool claimRole(NetPlayClient* client, int _role);
|
||||||
|
void releaseRole(NetPlayClient* client);
|
||||||
|
|
||||||
uint32_t getMaxLeadFrames(){ return maxLeadFrames; }
|
uint32_t getMaxLeadFrames(){ return maxLeadFrames; }
|
||||||
void setMaxLeadFrames(uint32_t value){ maxLeadFrames = value; }
|
void setMaxLeadFrames(uint32_t value){ maxLeadFrames = value; }
|
||||||
|
@ -155,6 +160,11 @@ class NetPlayServer : public QTcpServer
|
||||||
uint32_t cycleCounter = 0;
|
uint32_t cycleCounter = 0;
|
||||||
uint32_t maxLeadFrames = 10u;
|
uint32_t maxLeadFrames = 10u;
|
||||||
|
|
||||||
|
public:
|
||||||
|
signals:
|
||||||
|
void clientConnected(void);
|
||||||
|
void clientDisconnected(void);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void newConnectionRdy(void);
|
void newConnectionRdy(void);
|
||||||
void onRomLoad(void);
|
void onRomLoad(void);
|
||||||
|
@ -236,6 +246,8 @@ class NetPlayClient : public QObject
|
||||||
bool shouldDestroy(){ return needsDestroy; }
|
bool shouldDestroy(){ return needsDestroy; }
|
||||||
bool isPaused(){ return paused; }
|
bool isPaused(){ return paused; }
|
||||||
void setPaused(bool value){ paused = value; }
|
void setPaused(bool value){ paused = value; }
|
||||||
|
bool hasDesync(){ return desync; }
|
||||||
|
void setDesync(bool value){ desync = value; }
|
||||||
void recordPingResult( uint64_t delay_ms );
|
void recordPingResult( uint64_t delay_ms );
|
||||||
void resetPingData(void);
|
void resetPingData(void);
|
||||||
double getAvgPingDelay();
|
double getAvgPingDelay();
|
||||||
|
@ -263,6 +275,7 @@ class NetPlayClient : public QObject
|
||||||
bool needsDestroy = false;
|
bool needsDestroy = false;
|
||||||
bool _connected = false;
|
bool _connected = false;
|
||||||
bool paused = false;
|
bool paused = false;
|
||||||
|
bool desync = false;
|
||||||
|
|
||||||
uint64_t pingDelaySum = 0;
|
uint64_t pingDelaySum = 0;
|
||||||
uint64_t pingDelayLast = 0;
|
uint64_t pingDelayLast = 0;
|
||||||
|
@ -349,6 +362,8 @@ class NetPlayClientTreeItem : public QTreeWidgetItem
|
||||||
|
|
||||||
NetPlayClient* client = nullptr;
|
NetPlayClient* client = nullptr;
|
||||||
NetPlayServer* server = nullptr;
|
NetPlayServer* server = nullptr;
|
||||||
|
|
||||||
|
void updateData();
|
||||||
private:
|
private:
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -364,14 +379,23 @@ public:
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void closeEvent(QCloseEvent *event);
|
void closeEvent(QCloseEvent *event);
|
||||||
void loadClientTree(void);
|
|
||||||
|
|
||||||
QTreeWidget *clientTree;
|
QTreeWidget *clientTree;
|
||||||
|
QPushButton *dropPlayerButton;
|
||||||
|
QPushButton *resyncPlayerButton;
|
||||||
|
QPushButton *resyncAllButton;
|
||||||
|
QTimer *periodicTimer;
|
||||||
static NetPlayHostStatusDialog* instance;
|
static NetPlayHostStatusDialog* instance;
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void closeWindow(void);
|
void closeWindow(void);
|
||||||
|
void updatePeriodic(void);
|
||||||
|
void loadClientTree(void);
|
||||||
|
void onClientTreeContextMenu(const QPoint &pos);
|
||||||
|
void clientItemClicked(QTreeWidgetItem* item, int);
|
||||||
|
void dropPlayer(void);
|
||||||
|
void resyncPlayer(void);
|
||||||
|
void resyncAllPlayers(void);
|
||||||
};
|
};
|
||||||
|
|
||||||
bool NetPlayActive(void);
|
bool NetPlayActive(void);
|
||||||
|
|
|
@ -125,6 +125,7 @@ struct netPlayErrorMsg
|
||||||
netPlayErrorMsg(void)
|
netPlayErrorMsg(void)
|
||||||
: hdr(NETPLAY_ERROR_MSG, sizeof(netPlayErrorMsg)), code(0), flags(0)
|
: hdr(NETPLAY_ERROR_MSG, sizeof(netPlayErrorMsg)), code(0), flags(0)
|
||||||
{
|
{
|
||||||
|
hdr.msgSize = sizeof(*this) - N + 1;
|
||||||
memset(data, 0, N);
|
memset(data, 0, N);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -151,7 +152,7 @@ struct netPlayErrorMsg
|
||||||
retval = ::vsnprintf(data, sizeof(data), format, args);
|
retval = ::vsnprintf(data, sizeof(data), format, args);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
|
|
||||||
hdr.msgSize = sizeof(netPlayErrorMsg) - N + strlen(data) + 1;
|
hdr.msgSize = sizeof(*this) - N + strlen(data) + 1;
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
@ -239,7 +240,8 @@ struct netPlayClientState
|
||||||
uint32_t ramChkSum;
|
uint32_t ramChkSum;
|
||||||
uint8_t ctrlState[4];
|
uint8_t ctrlState[4];
|
||||||
|
|
||||||
static constexpr uint32_t PAUSE_FLAG = 0x0001;
|
static constexpr uint32_t PAUSE_FLAG = 0x0001;
|
||||||
|
static constexpr uint32_t DESYNC_FLAG = 0x0002;
|
||||||
|
|
||||||
netPlayClientState(void)
|
netPlayClientState(void)
|
||||||
: hdr(NETPLAY_CLIENT_STATE, sizeof(netPlayClientState)), flags(0),
|
: hdr(NETPLAY_CLIENT_STATE, sizeof(netPlayClientState)), flags(0),
|
||||||
|
|
Loading…
Reference in New Issue