For NetPlay, added ability for client to request a ROM to load.
This commit is contained in:
parent
ee814f99e5
commit
798c5a1d9c
|
@ -416,38 +416,44 @@ void NetPlayServer::releaseRole(NetPlayClient* client)
|
||||||
void NetPlayServer::onRomLoad()
|
void NetPlayServer::onRomLoad()
|
||||||
{
|
{
|
||||||
//printf("New ROM Loaded!\n");
|
//printf("New ROM Loaded!\n");
|
||||||
|
FCEU_WRAPPER_LOCK();
|
||||||
// New ROM has been loaded by server, signal clients to load and sync
|
// New ROM has been loaded by server, signal clients to load and sync
|
||||||
for (auto& client : clientList )
|
for (auto& client : clientList )
|
||||||
{
|
{
|
||||||
sendRomLoadReq( client );
|
sendRomLoadReq( client );
|
||||||
sendStateSyncReq( client );
|
sendStateSyncReq( client );
|
||||||
}
|
}
|
||||||
|
FCEU_WRAPPER_UNLOCK();
|
||||||
}
|
}
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
void NetPlayServer::onNesReset()
|
void NetPlayServer::onNesReset()
|
||||||
{
|
{
|
||||||
//printf("New ROM Loaded!\n");
|
//printf("New ROM Loaded!\n");
|
||||||
|
FCEU_WRAPPER_LOCK();
|
||||||
// NES Reset has occurred on server, signal clients sync
|
// NES Reset has occurred on server, signal clients sync
|
||||||
for (auto& client : clientList )
|
for (auto& client : clientList )
|
||||||
{
|
{
|
||||||
sendStateSyncReq( client );
|
sendStateSyncReq( client );
|
||||||
}
|
}
|
||||||
|
FCEU_WRAPPER_UNLOCK();
|
||||||
}
|
}
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
void NetPlayServer::resyncClient( NetPlayClient *client )
|
void NetPlayServer::resyncClient( NetPlayClient *client )
|
||||||
{
|
{
|
||||||
|
FCEU_WRAPPER_LOCK();
|
||||||
sendRomLoadReq( client );
|
sendRomLoadReq( client );
|
||||||
sendStateSyncReq( client );
|
sendStateSyncReq( client );
|
||||||
|
FCEU_WRAPPER_UNLOCK();
|
||||||
}
|
}
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
void NetPlayServer::resyncAllClients()
|
void NetPlayServer::resyncAllClients()
|
||||||
{
|
{
|
||||||
|
FCEU_WRAPPER_LOCK();
|
||||||
for (auto& client : clientList )
|
for (auto& client : clientList )
|
||||||
{
|
{
|
||||||
resyncClient( client );
|
resyncClient( client );
|
||||||
}
|
}
|
||||||
|
FCEU_WRAPPER_UNLOCK();
|
||||||
}
|
}
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
static void serverMessageCallback( void *userData, void *msgBuf, size_t msgSize )
|
static void serverMessageCallback( void *userData, void *msgBuf, size_t msgSize )
|
||||||
|
@ -484,8 +490,8 @@ void NetPlayServer::serverProcessMessage( NetPlayClient *client, void *msgBuf, s
|
||||||
|
|
||||||
if (!authentication_passed)
|
if (!authentication_passed)
|
||||||
{
|
{
|
||||||
netPlayErrorMsg<128> errorMsg;
|
netPlayTextMsg<128> errorMsg(NETPLAY_ERROR_MSG);
|
||||||
errorMsg.setDisconnectFlag();
|
errorMsg.setFlag(netPlayTextMsgFlags::DISCONNECT);
|
||||||
errorMsg.printf("Invalid Password");
|
errorMsg.printf("Invalid Password");
|
||||||
sendMsg( client, &errorMsg, errorMsg.hdr.msgSize, [&errorMsg]{ errorMsg.toNetworkByteOrder(); } );
|
sendMsg( client, &errorMsg, errorMsg.hdr.msgSize, [&errorMsg]{ errorMsg.toNetworkByteOrder(); } );
|
||||||
client->flushData();
|
client->flushData();
|
||||||
|
@ -497,15 +503,17 @@ void NetPlayServer::serverProcessMessage( NetPlayClient *client, void *msgBuf, s
|
||||||
if ( claimRole(client, msg->playerId) )
|
if ( claimRole(client, msg->playerId) )
|
||||||
{
|
{
|
||||||
client->userName = msg->userName;
|
client->userName = msg->userName;
|
||||||
|
FCEU_WRAPPER_LOCK();
|
||||||
sendRomLoadReq( client );
|
sendRomLoadReq( client );
|
||||||
sendStateSyncReq( client );
|
sendStateSyncReq( client );
|
||||||
|
FCEU_WRAPPER_UNLOCK();
|
||||||
client->state = 1;
|
client->state = 1;
|
||||||
FCEU_DispMessage("%s Joined",0, client->userName.toLocal8Bit().constData());
|
FCEU_DispMessage("%s Joined",0, client->userName.toLocal8Bit().constData());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
netPlayErrorMsg<128> errorMsg;
|
netPlayTextMsg<128> errorMsg(NETPLAY_ERROR_MSG);
|
||||||
errorMsg.setDisconnectFlag();
|
errorMsg.setFlag(netPlayTextMsgFlags::DISCONNECT);
|
||||||
errorMsg.printf("Player %i role is not available", msg->playerId+1);
|
errorMsg.printf("Player %i role is not available", msg->playerId+1);
|
||||||
sendMsg( client, &errorMsg, errorMsg.hdr.msgSize, [&errorMsg]{ errorMsg.toNetworkByteOrder(); } );
|
sendMsg( client, &errorMsg, errorMsg.hdr.msgSize, [&errorMsg]{ errorMsg.toNetworkByteOrder(); } );
|
||||||
client->flushData();
|
client->flushData();
|
||||||
|
@ -519,6 +527,7 @@ void NetPlayServer::serverProcessMessage( NetPlayClient *client, void *msgBuf, s
|
||||||
msg->toHostByteOrder();
|
msg->toHostByteOrder();
|
||||||
|
|
||||||
client->currentFrame = msg->frameRun;
|
client->currentFrame = msg->frameRun;
|
||||||
|
client->readyFrame = msg->frameRdy;
|
||||||
client->gpData[0] = msg->ctrlState[0];
|
client->gpData[0] = msg->ctrlState[0];
|
||||||
client->gpData[1] = msg->ctrlState[1];
|
client->gpData[1] = msg->ctrlState[1];
|
||||||
client->gpData[2] = msg->ctrlState[2];
|
client->gpData[2] = msg->ctrlState[2];
|
||||||
|
@ -546,7 +555,9 @@ void NetPlayServer::serverProcessMessage( NetPlayClient *client, void *msgBuf, s
|
||||||
|
|
||||||
if (client->desyncCount > forceResyncCount)
|
if (client->desyncCount > forceResyncCount)
|
||||||
{
|
{
|
||||||
|
FCEU_WRAPPER_LOCK();
|
||||||
sendStateSyncReq( client );
|
sendStateSyncReq( client );
|
||||||
|
FCEU_WRAPPER_UNLOCK();
|
||||||
|
|
||||||
client->desyncCount = 0;
|
client->desyncCount = 0;
|
||||||
}
|
}
|
||||||
|
@ -582,6 +593,60 @@ void NetPlayServer::serverProcessMessage( NetPlayClient *client, void *msgBuf, s
|
||||||
//printf("Ping Latency ms: %llu Avg:%f\n", static_cast<unsigned long long>(diff), client->getAvgPingDelay());
|
//printf("Ping Latency ms: %llu Avg:%f\n", static_cast<unsigned long long>(diff), client->getAvgPingDelay());
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case NETPLAY_LOAD_ROM_REQ:
|
||||||
|
{
|
||||||
|
netPlayLoadRomReq *msg = static_cast<netPlayLoadRomReq*>(msgBuf);
|
||||||
|
msg->toHostByteOrder();
|
||||||
|
|
||||||
|
bool acceptRomLoadReq = false;
|
||||||
|
|
||||||
|
if (allowClientRomLoadReq)
|
||||||
|
{
|
||||||
|
QString msgBoxTxt = tr("Client '") + client->userName + tr("' has requested to load this ROM:\n\n");
|
||||||
|
msgBoxTxt += tr(msg->fileName) + tr("\n\nDo you want to load it?");
|
||||||
|
int ans = QMessageBox::question( consoleWindow, tr("Client ROM Load Request"), msgBoxTxt, QMessageBox::Yes | QMessageBox::No );
|
||||||
|
|
||||||
|
if (ans == QMessageBox::Yes)
|
||||||
|
{
|
||||||
|
acceptRomLoadReq = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (acceptRomLoadReq)
|
||||||
|
{
|
||||||
|
FILE *fp;
|
||||||
|
std::string filepath = QDir::tempPath().toLocal8Bit().constData();
|
||||||
|
const char *romData = &static_cast<const char*>(msgBuf)[ sizeof(netPlayLoadRomReq) ];
|
||||||
|
|
||||||
|
filepath.append( "/" );
|
||||||
|
filepath.append( msg->fileName );
|
||||||
|
|
||||||
|
printf("Load ROM Request Received: %s\n", filepath.c_str());
|
||||||
|
|
||||||
|
//printf("Dumping Temp Rom to: %s\n", filepath.c_str());
|
||||||
|
fp = ::fopen( filepath.c_str(), "w");
|
||||||
|
|
||||||
|
if (fp == nullptr)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
::fwrite( romData, 1, msgSize, fp );
|
||||||
|
::fclose(fp);
|
||||||
|
|
||||||
|
FCEU_WRAPPER_LOCK();
|
||||||
|
LoadGame( filepath.c_str(), true, true );
|
||||||
|
FCEUI_SetEmulationPaused(EMULATIONPAUSED_PAUSED);
|
||||||
|
FCEU_WRAPPER_UNLOCK();
|
||||||
|
|
||||||
|
resyncAllClients();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
netPlayTextMsg<128> errorMsg(NETPLAY_ERROR_MSG);
|
||||||
|
errorMsg.printf("Host is rejected ROMs load request");
|
||||||
|
sendMsg( client, &errorMsg, errorMsg.hdr.msgSize, [&errorMsg]{ errorMsg.toNetworkByteOrder(); } );
|
||||||
|
}
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
printf("Unknown Msg: %08X\n", msgId);
|
printf("Unknown Msg: %08X\n", msgId);
|
||||||
break;
|
break;
|
||||||
|
@ -591,6 +656,7 @@ void NetPlayServer::serverProcessMessage( NetPlayClient *client, void *msgBuf, s
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
void NetPlayServer::update(void)
|
void NetPlayServer::update(void)
|
||||||
{
|
{
|
||||||
|
bool hostRdyFrame = false;
|
||||||
bool shouldRunFrame = false;
|
bool shouldRunFrame = false;
|
||||||
unsigned int clientMinFrame = 0xFFFFFFFF;
|
unsigned int clientMinFrame = 0xFFFFFFFF;
|
||||||
unsigned int clientMaxFrame = 0;
|
unsigned int clientMaxFrame = 0;
|
||||||
|
@ -669,11 +735,22 @@ void NetPlayServer::update(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hostRdyFrame = ( (currFrame > lastFrame) || (lastFrame == 0) );
|
||||||
|
|
||||||
shouldRunFrame = (clientMinFrame != 0xFFFFFFFF) &&
|
shouldRunFrame = (clientMinFrame != 0xFFFFFFFF) &&
|
||||||
(clientMinFrame >= lagFrame ) &&
|
(clientMinFrame >= lagFrame ) &&
|
||||||
(clientMaxFrame < leadFrame) &&
|
(clientMaxFrame < leadFrame) &&
|
||||||
( (currFrame > lastFrame) || (lastFrame == 0) ) &&
|
(numClientsPaused == 0) &&
|
||||||
(numClientsPaused == 0);
|
hostRdyFrame;
|
||||||
|
|
||||||
|
if (hostRdyFrame && !shouldRunFrame)
|
||||||
|
{
|
||||||
|
clientWaitCounter++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
clientWaitCounter = 0;
|
||||||
|
}
|
||||||
|
|
||||||
//printf("Client Frame: Min:%u Max:%u\n", clientMinFrame, clientMaxFrame);
|
//printf("Client Frame: Min:%u Max:%u\n", clientMinFrame, clientMaxFrame);
|
||||||
|
|
||||||
|
@ -914,6 +991,48 @@ void NetPlayClient::onSocketError(QAbstractSocket::SocketError error)
|
||||||
emit errorOccurred(errorMsg);
|
emit errorOccurred(errorMsg);
|
||||||
}
|
}
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
int NetPlayClient::requestRomLoad( const char *romPath )
|
||||||
|
{
|
||||||
|
constexpr size_t BufferSize = 64 * 1024;
|
||||||
|
char buf[BufferSize];
|
||||||
|
size_t bytesRead;
|
||||||
|
long fileSize = 0;
|
||||||
|
netPlayLoadRomReq msg;
|
||||||
|
QFileInfo fi( romPath );
|
||||||
|
|
||||||
|
printf("Prep ROM Load Request: %s \n", romPath );
|
||||||
|
FILE *fp = ::fopen( romPath, "r");
|
||||||
|
|
||||||
|
if (fp == nullptr)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
fseek( fp, 0, SEEK_END);
|
||||||
|
|
||||||
|
fileSize = ftell(fp);
|
||||||
|
|
||||||
|
rewind(fp);
|
||||||
|
|
||||||
|
msg.hdr.msgSize += fileSize;
|
||||||
|
msg.fileSize = fileSize;
|
||||||
|
Strlcpy( msg.fileName, fi.fileName().toLocal8Bit().constData(), sizeof(msg.fileName) );
|
||||||
|
|
||||||
|
printf("Sending ROM Load Request: %s %lu\n", romPath, fileSize );
|
||||||
|
FCEUI_SetEmulationPaused(EMULATIONPAUSED_PAUSED);
|
||||||
|
|
||||||
|
msg.toNetworkByteOrder();
|
||||||
|
sock->write( reinterpret_cast<const char*>(&msg), sizeof(netPlayLoadRomReq) );
|
||||||
|
|
||||||
|
while ( (bytesRead = fread( buf, 1, sizeof(buf), fp )) > 0 )
|
||||||
|
{
|
||||||
|
sock->write( buf, bytesRead );
|
||||||
|
}
|
||||||
|
|
||||||
|
::fclose(fp);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
void NetPlayClient::recordPingResult( uint64_t delay_ms )
|
void NetPlayClient::recordPingResult( uint64_t delay_ms )
|
||||||
{
|
{
|
||||||
pingNumSamples++;
|
pingNumSamples++;
|
||||||
|
@ -1069,15 +1188,15 @@ void NetPlayClient::clientProcessMessage( void *msgBuf, size_t msgSize )
|
||||||
{
|
{
|
||||||
case NETPLAY_ERROR_MSG:
|
case NETPLAY_ERROR_MSG:
|
||||||
{
|
{
|
||||||
auto *msg = static_cast<netPlayErrorMsg<256>*>(msgBuf);
|
auto *msg = static_cast<netPlayTextMsg<256>*>(msgBuf);
|
||||||
msg->toHostByteOrder();
|
msg->toHostByteOrder();
|
||||||
printf("Error: 0x%X %s\n", msg->code, msg->getBuffer());
|
FCEU_printf("NetPlay Error: 0x%X %s\n", msg->code, msg->getBuffer());
|
||||||
|
|
||||||
if (msg->isDisconnectFlagSet())
|
if (msg->isFlagSet(netPlayTextMsgFlags::DISCONNECT))
|
||||||
{
|
{
|
||||||
sock->disconnectFromHost();
|
sock->disconnectFromHost();
|
||||||
}
|
}
|
||||||
FCEU_DispMessage("Host connect failed",0);
|
FCEU_DispMessage("NetPlay Errors... check message log",0);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case NETPLAY_AUTH_REQ:
|
case NETPLAY_AUTH_REQ:
|
||||||
|
@ -1087,7 +1206,7 @@ void NetPlayClient::clientProcessMessage( void *msgBuf, size_t msgSize )
|
||||||
Strlcpy( msg.userName, userName.toLocal8Bit().constData(), sizeof(msg.userName));
|
Strlcpy( msg.userName, userName.toLocal8Bit().constData(), sizeof(msg.userName));
|
||||||
Strlcpy( msg.pswd, password.toLocal8Bit().constData(), sizeof(msg.pswd) );
|
Strlcpy( msg.pswd, password.toLocal8Bit().constData(), sizeof(msg.pswd) );
|
||||||
|
|
||||||
printf("Authentication Request Received\n");
|
FCEU_printf("Authentication Request Received\n");
|
||||||
msg.toNetworkByteOrder();
|
msg.toNetworkByteOrder();
|
||||||
sock->write( (const char*)&msg, sizeof(netPlayAuthResp) );
|
sock->write( (const char*)&msg, sizeof(netPlayAuthResp) );
|
||||||
}
|
}
|
||||||
|
@ -1095,7 +1214,7 @@ void NetPlayClient::clientProcessMessage( void *msgBuf, size_t msgSize )
|
||||||
case NETPLAY_LOAD_ROM_REQ:
|
case NETPLAY_LOAD_ROM_REQ:
|
||||||
{
|
{
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
std::string filepath = QDir::tempPath().toStdString();
|
std::string filepath = QDir::tempPath().toLocal8Bit().constData();
|
||||||
netPlayLoadRomReq *msg = static_cast<netPlayLoadRomReq*>(msgBuf);
|
netPlayLoadRomReq *msg = static_cast<netPlayLoadRomReq*>(msgBuf);
|
||||||
msg->toHostByteOrder();
|
msg->toHostByteOrder();
|
||||||
const char *romData = &static_cast<const char*>(msgBuf)[ sizeof(netPlayLoadRomReq) ];
|
const char *romData = &static_cast<const char*>(msgBuf)[ sizeof(netPlayLoadRomReq) ];
|
||||||
|
@ -1103,7 +1222,7 @@ void NetPlayClient::clientProcessMessage( void *msgBuf, size_t msgSize )
|
||||||
filepath.append( "/" );
|
filepath.append( "/" );
|
||||||
filepath.append( msg->fileName );
|
filepath.append( msg->fileName );
|
||||||
|
|
||||||
printf("Load ROM Request Received: %s\n", filepath.c_str());
|
FCEU_printf("Load ROM Request Received: %s\n", filepath.c_str());
|
||||||
|
|
||||||
//printf("Dumping Temp Rom to: %s\n", filepath.c_str());
|
//printf("Dumping Temp Rom to: %s\n", filepath.c_str());
|
||||||
fp = ::fopen( filepath.c_str(), "w");
|
fp = ::fopen( filepath.c_str(), "w");
|
||||||
|
@ -1116,7 +1235,7 @@ void NetPlayClient::clientProcessMessage( void *msgBuf, size_t msgSize )
|
||||||
::fclose(fp);
|
::fclose(fp);
|
||||||
|
|
||||||
FCEU_WRAPPER_LOCK();
|
FCEU_WRAPPER_LOCK();
|
||||||
LoadGame( filepath.c_str(), true );
|
LoadGame( filepath.c_str(), true, true );
|
||||||
FCEUI_SetEmulationPaused(EMULATIONPAUSED_PAUSED);
|
FCEUI_SetEmulationPaused(EMULATIONPAUSED_PAUSED);
|
||||||
FCEU_WRAPPER_UNLOCK();
|
FCEU_WRAPPER_UNLOCK();
|
||||||
}
|
}
|
||||||
|
@ -1125,7 +1244,7 @@ void NetPlayClient::clientProcessMessage( void *msgBuf, size_t msgSize )
|
||||||
{
|
{
|
||||||
char *stateData = &static_cast<char*>(msgBuf)[ sizeof(netPlayMsgHdr) ];
|
char *stateData = &static_cast<char*>(msgBuf)[ sizeof(netPlayMsgHdr) ];
|
||||||
|
|
||||||
printf("Sync state Request Received\n");
|
FCEU_printf("Sync state Request Received\n");
|
||||||
|
|
||||||
EMUFILE_MEMORY em( stateData, msgSize );
|
EMUFILE_MEMORY em( stateData, msgSize );
|
||||||
|
|
||||||
|
@ -1528,8 +1647,8 @@ NetPlayHostStatusDialog::NetPlayHostStatusDialog(QWidget *parent)
|
||||||
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( "Frame" ) );
|
item->setText( 2, QString::fromStdString( "State" ) );
|
||||||
item->setText( 3, QString::fromStdString( "State" ) );
|
item->setText( 3, QString::fromStdString( "Frame" ) );
|
||||||
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);
|
||||||
|
@ -1665,37 +1784,54 @@ void NetPlayClientTreeItem::updateData()
|
||||||
|
|
||||||
if (FCEUI_EmulationPaused())
|
if (FCEUI_EmulationPaused())
|
||||||
{
|
{
|
||||||
state += QObject::tr("Paused");
|
state = QObject::tr("Paused");
|
||||||
|
}
|
||||||
|
else if (server->waitingOnClients())
|
||||||
|
{
|
||||||
|
state = QObject::tr("Waiting");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
state = QObject::tr("Running");
|
||||||
}
|
}
|
||||||
|
|
||||||
setText( 0, QObject::tr("Host") );
|
setText( 0, QObject::tr("Host") );
|
||||||
setText( 1, QObject::tr(roleString) );
|
setText( 1, QObject::tr(roleString) );
|
||||||
setText( 2, QString::number(static_cast<uint32_t>(currFrameCounter)));
|
setText( 2, state);
|
||||||
setText( 3, state);
|
setText( 3, QString::number(static_cast<uint32_t>(currFrameCounter)));
|
||||||
|
|
||||||
}
|
}
|
||||||
else if (client != nullptr)
|
else if (client != nullptr)
|
||||||
{
|
{
|
||||||
QString state;
|
QString state;
|
||||||
|
uint32_t currFrame = currFrameCounter;
|
||||||
|
|
||||||
|
bool hasInput = (client->readyFrame > client->currentFrame) &&
|
||||||
|
(client->readyFrame <= currFrame);
|
||||||
|
|
||||||
roleString = NetPlayPlayerRoleToString( client->role );
|
roleString = NetPlayPlayerRoleToString( client->role );
|
||||||
|
|
||||||
if (client->isPaused())
|
if (client->isPaused())
|
||||||
{
|
{
|
||||||
state += QObject::tr("Paused");
|
state = QObject::tr("Paused");
|
||||||
|
}
|
||||||
|
else if (!hasInput)
|
||||||
|
{
|
||||||
|
state = QObject::tr("Waiting");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
state = QObject::tr("Running");
|
||||||
}
|
}
|
||||||
if (client->hasDesync())
|
if (client->hasDesync())
|
||||||
{
|
{
|
||||||
if (!state.isEmpty())
|
state += QObject::tr(",Desync");
|
||||||
{
|
|
||||||
state += QObject::tr(",");
|
|
||||||
}
|
|
||||||
state += QObject::tr("Desync");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setText( 0, client->userName );
|
setText( 0, client->userName );
|
||||||
setText( 1, QObject::tr(roleString) );
|
setText( 1, QObject::tr(roleString) );
|
||||||
setText( 2, QString::number(client->currentFrame) );
|
setText( 2, state);
|
||||||
setText( 3, state);
|
setText( 3, QString::number(client->currentFrame) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
|
|
|
@ -135,6 +135,7 @@ class NetPlayServer : public QTcpServer
|
||||||
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);
|
void releaseRole(NetPlayClient* client);
|
||||||
|
bool waitingOnClients(){ return clientWaitCounter > 3; }
|
||||||
|
|
||||||
uint32_t getMaxLeadFrames(){ return maxLeadFrames; }
|
uint32_t getMaxLeadFrames(){ return maxLeadFrames; }
|
||||||
void setMaxLeadFrames(uint32_t value){ maxLeadFrames = value; }
|
void setMaxLeadFrames(uint32_t value){ maxLeadFrames = value; }
|
||||||
|
@ -159,6 +160,8 @@ class NetPlayServer : public QTcpServer
|
||||||
int forceResyncCount = 10;
|
int forceResyncCount = 10;
|
||||||
uint32_t cycleCounter = 0;
|
uint32_t cycleCounter = 0;
|
||||||
uint32_t maxLeadFrames = 10u;
|
uint32_t maxLeadFrames = 10u;
|
||||||
|
uint32_t clientWaitCounter = 0;
|
||||||
|
bool allowClientRomLoadReq = true;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
signals:
|
signals:
|
||||||
|
@ -190,6 +193,7 @@ class NetPlayClient : public QObject
|
||||||
bool disconnectRequested(){ return disconnectPending; }
|
bool disconnectRequested(){ return disconnectPending; }
|
||||||
void forceDisconnect();
|
void forceDisconnect();
|
||||||
bool flushData();
|
bool flushData();
|
||||||
|
int requestRomLoad( const char *romPath );
|
||||||
|
|
||||||
QTcpSocket* createSocket(void);
|
QTcpSocket* createSocket(void);
|
||||||
void setSocket(QTcpSocket *s);
|
void setSocket(QTcpSocket *s);
|
||||||
|
@ -259,6 +263,7 @@ class NetPlayClient : public QObject
|
||||||
int desyncCount = 0;
|
int desyncCount = 0;
|
||||||
bool syncOk = false;
|
bool syncOk = false;
|
||||||
unsigned int currentFrame = 0;
|
unsigned int currentFrame = 0;
|
||||||
|
unsigned int readyFrame = 0;
|
||||||
uint8_t gpData[4];
|
uint8_t gpData[4];
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -21,7 +21,9 @@ enum netPlayMsgType
|
||||||
NETPLAY_SYNC_STATE_RESP,
|
NETPLAY_SYNC_STATE_RESP,
|
||||||
NETPLAY_RUN_FRAME_REQ,
|
NETPLAY_RUN_FRAME_REQ,
|
||||||
NETPLAY_CLIENT_STATE,
|
NETPLAY_CLIENT_STATE,
|
||||||
|
NETPLAY_INFO_MSG,
|
||||||
NETPLAY_ERROR_MSG,
|
NETPLAY_ERROR_MSG,
|
||||||
|
NETPLAY_CHAT_MSG,
|
||||||
NETPLAY_PING_REQ,
|
NETPLAY_PING_REQ,
|
||||||
NETPLAY_PING_RESP,
|
NETPLAY_PING_RESP,
|
||||||
};
|
};
|
||||||
|
@ -111,32 +113,37 @@ struct netPlayAuthResp
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct netPlayTextMsgFlags
|
||||||
|
{
|
||||||
|
static const uint32_t DISCONNECT = 0x00000001;
|
||||||
|
static const uint32_t WARNING = 0x00000002;
|
||||||
|
static const uint32_t INFO = 0x00000004;
|
||||||
|
};
|
||||||
|
|
||||||
template <size_t N=8>
|
template <size_t N=8>
|
||||||
struct netPlayErrorMsg
|
struct netPlayTextMsg
|
||||||
{
|
{
|
||||||
netPlayMsgHdr hdr;
|
netPlayMsgHdr hdr;
|
||||||
|
|
||||||
unsigned short code;
|
unsigned short code;
|
||||||
unsigned short flags;
|
unsigned short flags;
|
||||||
char data[N];
|
unsigned short dataSize;
|
||||||
|
|
||||||
static const uint32_t DISCONNECT_FLAG = 0x00000001;
|
netPlayTextMsg(int type)
|
||||||
|
: hdr(type, sizeof(netPlayTextMsg)), code(0), flags(0), dataSize(0)
|
||||||
netPlayErrorMsg(void)
|
|
||||||
: hdr(NETPLAY_ERROR_MSG, sizeof(netPlayErrorMsg)), code(0), flags(0)
|
|
||||||
{
|
{
|
||||||
hdr.msgSize = sizeof(*this) - N + 1;
|
hdr.msgSize = sizeof(*this) - N + 1;
|
||||||
memset(data, 0, N);
|
memset(data, 0, N);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setDisconnectFlag()
|
void setFlag(uint32_t flag)
|
||||||
{
|
{
|
||||||
flags |= DISCONNECT_FLAG;
|
flags |= flag;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isDisconnectFlagSet()
|
bool isFlagSet(uint32_t flag)
|
||||||
{
|
{
|
||||||
return (flags & DISCONNECT_FLAG) ? true : false;
|
return (flags & flag) ? true : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *getBuffer()
|
const char *getBuffer()
|
||||||
|
@ -149,19 +156,55 @@ struct netPlayErrorMsg
|
||||||
int retval;
|
int retval;
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start(args, format);
|
va_start(args, format);
|
||||||
retval = ::vsnprintf(data, sizeof(data), format, args);
|
retval = ::vsnprintf(data, N, format, args);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
|
|
||||||
hdr.msgSize = sizeof(*this) - N + strlen(data) + 1;
|
if (retval > static_cast<int>(N-1))
|
||||||
|
{
|
||||||
|
retval = static_cast<int>(N-1);
|
||||||
|
}
|
||||||
|
dataSize = retval;
|
||||||
|
|
||||||
|
hdr.msgSize = sizeof(*this) - N + retval + 1;
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void assign(const char *msg)
|
||||||
|
{
|
||||||
|
int i=0;
|
||||||
|
|
||||||
|
while ( (i < (N-1)) && (msg[i] != 0) )
|
||||||
|
{
|
||||||
|
data[i] = msg[i]; i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
data[i] = 0;
|
||||||
|
dataSize = i;
|
||||||
|
|
||||||
|
hdr.msgSize = sizeof(*this) - N + i + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void append(const char *msg)
|
||||||
|
{
|
||||||
|
int i=dataSize, j=0;
|
||||||
|
|
||||||
|
while ( (i < (N-1)) && (msg[j] != 0) )
|
||||||
|
{
|
||||||
|
data[i] = msg[j]; i++; j++;
|
||||||
|
}
|
||||||
|
data[i] = 0;
|
||||||
|
dataSize = i;
|
||||||
|
|
||||||
|
hdr.msgSize = sizeof(*this) - N + i + 1;
|
||||||
|
}
|
||||||
|
|
||||||
void toHostByteOrder()
|
void toHostByteOrder()
|
||||||
{
|
{
|
||||||
hdr.toHostByteOrder();
|
hdr.toHostByteOrder();
|
||||||
code = netPlayByteSwap(code);
|
code = netPlayByteSwap(code);
|
||||||
flags = netPlayByteSwap(flags);
|
flags = netPlayByteSwap(flags);
|
||||||
|
dataSize = netPlayByteSwap(dataSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
void toNetworkByteOrder()
|
void toNetworkByteOrder()
|
||||||
|
@ -169,7 +212,10 @@ struct netPlayErrorMsg
|
||||||
hdr.toNetworkByteOrder();
|
hdr.toNetworkByteOrder();
|
||||||
code = netPlayByteSwap(code);
|
code = netPlayByteSwap(code);
|
||||||
flags = netPlayByteSwap(flags);
|
flags = netPlayByteSwap(flags);
|
||||||
|
dataSize = netPlayByteSwap(dataSize);
|
||||||
}
|
}
|
||||||
|
private:
|
||||||
|
char data[N];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct netPlayLoadRomReq
|
struct netPlayLoadRomReq
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
#pragma once
|
||||||
|
#include <stdint.h>
|
||||||
#include "common/args.h"
|
#include "common/args.h"
|
||||||
#include "common/config.h"
|
#include "common/config.h"
|
||||||
|
|
||||||
|
@ -9,10 +11,10 @@ extern ARGPSTRUCT DriverArgs[];
|
||||||
void DoDriverArgs(void);
|
void DoDriverArgs(void);
|
||||||
|
|
||||||
int InitSound();
|
int InitSound();
|
||||||
void WriteSound(int32 *Buffer, int Count);
|
void WriteSound(int32_t *Buffer, int Count);
|
||||||
int KillSound(void);
|
int KillSound(void);
|
||||||
uint32 GetMaxSound(void);
|
uint32_t GetMaxSound(void);
|
||||||
uint32 GetWriteSound(void);
|
uint32_t GetWriteSound(void);
|
||||||
bool FCEUD_SoundIsMuted(void);
|
bool FCEUD_SoundIsMuted(void);
|
||||||
void FCEUD_MuteSoundOutput(bool value);
|
void FCEUD_MuteSoundOutput(bool value);
|
||||||
void FCEUD_MuteSoundWindow(bool value);
|
void FCEUD_MuteSoundWindow(bool value);
|
||||||
|
@ -24,18 +26,19 @@ int KillJoysticks(void);
|
||||||
int AddJoystick( int which );
|
int AddJoystick( int which );
|
||||||
int RemoveJoystick( int which );
|
int RemoveJoystick( int which );
|
||||||
int FindJoystickByInstanceID( int which );
|
int FindJoystickByInstanceID( int which );
|
||||||
uint32 *GetJSOr(void);
|
uint32_t *GetJSOr(void);
|
||||||
|
|
||||||
|
struct FCEUGI;
|
||||||
int InitVideo(FCEUGI *gi);
|
int InitVideo(FCEUGI *gi);
|
||||||
int KillVideo(void);
|
int KillVideo(void);
|
||||||
void CalcVideoDimensions(void);
|
void CalcVideoDimensions(void);
|
||||||
void BlitScreen(uint8 *XBuf);
|
void BlitScreen(uint8_t *XBuf);
|
||||||
void LockConsole(void);
|
void LockConsole(void);
|
||||||
void UnlockConsole(void);
|
void UnlockConsole(void);
|
||||||
void ToggleFS(); /* SDL */
|
void ToggleFS(); /* SDL */
|
||||||
|
|
||||||
int LoadGame(const char *path, bool silent);
|
int LoadGame(const char *path, bool silent = false, bool netPlayRequested = false);
|
||||||
//int CloseGame(void);
|
int CloseGame(void);
|
||||||
|
|
||||||
void Giggles(int);
|
void Giggles(int);
|
||||||
void DoFun(void);
|
void DoFun(void);
|
||||||
|
|
|
@ -308,11 +308,22 @@ int reloadLastGame(void)
|
||||||
* provides data necessary for the driver code(number of scanlines to
|
* provides data necessary for the driver code(number of scanlines to
|
||||||
* render, what virtual input devices to use, etc.).
|
* render, what virtual input devices to use, etc.).
|
||||||
*/
|
*/
|
||||||
int LoadGame(const char *path, bool silent)
|
int LoadGame(const char *path, bool silent, bool netPlayRequested)
|
||||||
{
|
{
|
||||||
std::string fullpath;
|
std::string fullpath;
|
||||||
int gg_enabled, autoLoadDebug, autoOpenDebugger, autoInputPreset;
|
int gg_enabled, autoLoadDebug, autoOpenDebugger, autoInputPreset;
|
||||||
|
|
||||||
|
// Check if this application instance has joined a net play session,
|
||||||
|
// NetPlay clients can only load ROMs retrieved from the host server.
|
||||||
|
// However, clients can request that a host load their ROM for all players.
|
||||||
|
auto* netPlayClient = NetPlayClient::GetInstance();
|
||||||
|
|
||||||
|
if (!netPlayRequested && (netPlayClient != nullptr))
|
||||||
|
{
|
||||||
|
netPlayClient->requestRomLoad( path );
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (isloaded){
|
if (isloaded){
|
||||||
CloseGame();
|
CloseGame();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
// fceuWrapper.h
|
// fceuWrapper.h
|
||||||
//
|
//
|
||||||
#include "Qt/config.h"
|
#include "Qt/config.h"
|
||||||
|
#include "Qt/dface.h"
|
||||||
|
|
||||||
//*****************************************************************
|
//*****************************************************************
|
||||||
// Define Global Variables to be shared with FCEU Core
|
// Define Global Variables to be shared with FCEU Core
|
||||||
|
@ -26,7 +27,7 @@ extern unsigned int emulatorCycleCount;
|
||||||
// global configuration object
|
// global configuration object
|
||||||
extern Config *g_config;
|
extern Config *g_config;
|
||||||
|
|
||||||
int LoadGame(const char *path, bool silent = false);
|
//int LoadGame(const char *path, bool silent = false, bool netPlayRequested = false);
|
||||||
int CloseGame(void);
|
int CloseGame(void);
|
||||||
int reloadLastGame(void);
|
int reloadLastGame(void);
|
||||||
int LoadGameFromLua( const char *path );
|
int LoadGameFromLua( const char *path );
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include <QAction>
|
#include <QAction>
|
||||||
|
|
||||||
#include "common/configSys.h"
|
#include "common/configSys.h"
|
||||||
|
#include "Qt/main.h"
|
||||||
|
|
||||||
//#define MAXBUTTCONFIG 4
|
//#define MAXBUTTCONFIG 4
|
||||||
|
|
||||||
|
@ -26,6 +27,7 @@ struct ButtConfig
|
||||||
int state;
|
int state;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct FCEUGI;
|
||||||
extern int NoWaiting;
|
extern int NoWaiting;
|
||||||
extern CFGSTRUCT InputConfig[];
|
extern CFGSTRUCT InputConfig[];
|
||||||
extern ARGPSTRUCT InputArgs[];
|
extern ARGPSTRUCT InputArgs[];
|
||||||
|
@ -144,7 +146,7 @@ void UpdateInput(Config *config);
|
||||||
const char* ButtonName(const ButtConfig* bc);
|
const char* ButtonName(const ButtConfig* bc);
|
||||||
|
|
||||||
void pollEventsSDL();
|
void pollEventsSDL();
|
||||||
uint32 GetGamepadPressedImmediate(void);
|
uint32_t GetGamepadPressedImmediate(void);
|
||||||
int getInputSelection( int port, int *cur, int *usr );
|
int getInputSelection( int port, int *cur, int *usr );
|
||||||
int saveInputSettingsToFile( const char *fileBase = NULL );
|
int saveInputSettingsToFile( const char *fileBase = NULL );
|
||||||
int loadInputSettingsFromFile( const char *filename = NULL );
|
int loadInputSettingsFromFile( const char *filename = NULL );
|
||||||
|
|
|
@ -24,8 +24,6 @@ extern int dendy;
|
||||||
extern int pal_emulation;
|
extern int pal_emulation;
|
||||||
extern bool swapDuty;
|
extern bool swapDuty;
|
||||||
|
|
||||||
int LoadGame(const char *path, bool silent);
|
|
||||||
int CloseGame(void);
|
|
||||||
void FCEUD_Update(uint8 *XBuf, int32 *Buffer, int Count);
|
void FCEUD_Update(uint8 *XBuf, int32 *Buffer, int Count);
|
||||||
uint64 FCEUD_GetTime();
|
uint64 FCEUD_GetTime();
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue