For NetPlay, added ability for client to request a ROM to load.

This commit is contained in:
harry 2024-03-03 20:30:35 -05:00
parent ee814f99e5
commit 798c5a1d9c
8 changed files with 256 additions and 54 deletions

View File

@ -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) );
} }
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------

View File

@ -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:

View File

@ -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

View File

@ -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);

View File

@ -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();
} }

View File

@ -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 );

View File

@ -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 );

View File

@ -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();