Added sync checking and network byte ordering code for Qt net play.
This commit is contained in:
parent
8d93015a56
commit
0123e1fbf8
|
@ -24,6 +24,8 @@
|
||||||
#include "../../fceu.h"
|
#include "../../fceu.h"
|
||||||
#include "../../state.h"
|
#include "../../state.h"
|
||||||
#include "../../movie.h"
|
#include "../../movie.h"
|
||||||
|
#include "../../debug.h"
|
||||||
|
#include "utils/crc32.h"
|
||||||
#include "Qt/main.h"
|
#include "Qt/main.h"
|
||||||
#include "Qt/dface.h"
|
#include "Qt/dface.h"
|
||||||
#include "Qt/input.h"
|
#include "Qt/input.h"
|
||||||
|
@ -33,6 +35,102 @@
|
||||||
#include "Qt/ConsoleUtilities.h"
|
#include "Qt/ConsoleUtilities.h"
|
||||||
#include "Qt/NetPlayMsgDef.h"
|
#include "Qt/NetPlayMsgDef.h"
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//--- NetPlay State Monitoring Metrics
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
static uint32_t opsCrc32 = 0;
|
||||||
|
|
||||||
|
struct NetPlayFrameData
|
||||||
|
{
|
||||||
|
uint32_t frameNum = 0;
|
||||||
|
uint32_t opsCrc32 = 0;
|
||||||
|
uint32_t ramCrc32 = 0;
|
||||||
|
|
||||||
|
void reset()
|
||||||
|
{
|
||||||
|
frameNum = 0;
|
||||||
|
opsCrc32 = 0;
|
||||||
|
ramCrc32 = 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct NetPlayFrameDataHist_t
|
||||||
|
{
|
||||||
|
static constexpr int numFrames = 10;
|
||||||
|
|
||||||
|
void push( NetPlayFrameData& newData )
|
||||||
|
{
|
||||||
|
|
||||||
|
data[bufHead] = newData;
|
||||||
|
|
||||||
|
bufHead = (bufHead + 1) % numFrames;
|
||||||
|
}
|
||||||
|
|
||||||
|
int getLast( NetPlayFrameData& out )
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
if (bufHead == 0)
|
||||||
|
{
|
||||||
|
i = numFrames - 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
i = bufHead - 1;
|
||||||
|
}
|
||||||
|
out = data[i];
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int find( uint32_t frame, NetPlayFrameData& out )
|
||||||
|
{
|
||||||
|
int i, retval = -1;
|
||||||
|
|
||||||
|
if (bufHead == 0)
|
||||||
|
{
|
||||||
|
i = numFrames - 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
i = bufHead - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (i != bufHead)
|
||||||
|
{
|
||||||
|
if (data[i].frameNum == frame)
|
||||||
|
{
|
||||||
|
out = data[i];
|
||||||
|
retval = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i == 0)
|
||||||
|
{
|
||||||
|
i = numFrames - 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
i = i - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void reset(void)
|
||||||
|
{
|
||||||
|
bufHead = 0;
|
||||||
|
|
||||||
|
for (int i=0; i<numFrames; i++)
|
||||||
|
{
|
||||||
|
data[i].reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NetPlayFrameData data[numFrames];
|
||||||
|
int bufHead = 0;
|
||||||
|
};
|
||||||
|
static NetPlayFrameDataHist_t netPlayFrameData;
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
//--- NetPlayServer
|
//--- NetPlayServer
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
@ -108,6 +206,7 @@ void NetPlayServer::processPendingConnections(void)
|
||||||
|
|
||||||
netPlayAuthReq msg;
|
netPlayAuthReq msg;
|
||||||
|
|
||||||
|
msg.toNetworkByteOrder();
|
||||||
sendMsg( client, &msg, sizeof(msg) );
|
sendMsg( client, &msg, sizeof(msg) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -193,6 +292,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) );
|
sendMsg( client, &msg, sizeof(netPlayLoadRomReq) );
|
||||||
|
|
||||||
while ( (bytesRead = fread( buf, 1, sizeof(buf), fp )) > 0 )
|
while ( (bytesRead = fread( buf, 1, sizeof(buf), fp )) > 0 )
|
||||||
|
@ -209,7 +309,7 @@ int NetPlayServer::sendStateSyncReq( NetPlayClient *client )
|
||||||
{
|
{
|
||||||
EMUFILE_MEMORY em;
|
EMUFILE_MEMORY em;
|
||||||
int compressionLevel = 1;
|
int compressionLevel = 1;
|
||||||
netPlayMsgHdr hdr(NETPLAY_SYNC_STATE);
|
netPlayMsgHdr hdr(NETPLAY_SYNC_STATE_RESP);
|
||||||
|
|
||||||
if ( GameInfo == nullptr )
|
if ( GameInfo == nullptr )
|
||||||
{
|
{
|
||||||
|
@ -222,9 +322,12 @@ 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) );
|
sendMsg( client, &hdr, sizeof(netPlayMsgHdr) );
|
||||||
sendMsg( client, em.buf(), em.size() );
|
sendMsg( client, em.buf(), em.size() );
|
||||||
|
|
||||||
|
opsCrc32 = 0;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
@ -272,14 +375,17 @@ void NetPlayServer::serverProcessMessage( NetPlayClient *client, void *msgBuf, s
|
||||||
{
|
{
|
||||||
netPlayMsgHdr *hdr = (netPlayMsgHdr*)msgBuf;
|
netPlayMsgHdr *hdr = (netPlayMsgHdr*)msgBuf;
|
||||||
|
|
||||||
//printf("Server Received Message: ID: %i Bytes:%zu\n", hdr->msgId, msgSize );
|
const uint32_t msgId = netPlayByteSwap(hdr->msgId);
|
||||||
|
|
||||||
switch (hdr->msgId)
|
//printf("Server Received Message: ID: %i Bytes:%zu\n", msgId, msgSize );
|
||||||
|
|
||||||
|
switch (msgId)
|
||||||
{
|
{
|
||||||
case NETPLAY_AUTH_RESP:
|
case NETPLAY_AUTH_RESP:
|
||||||
{
|
{
|
||||||
bool authentication_passed = false;
|
bool authentication_passed = false;
|
||||||
netPlayAuthResp *msg = static_cast<netPlayAuthResp*>(msgBuf);
|
netPlayAuthResp *msg = static_cast<netPlayAuthResp*>(msgBuf);
|
||||||
|
msg->toHostByteOrder();
|
||||||
printf("Authorize: Player: %i Passwd: %s\n", msg->playerId, msg->pswd);
|
printf("Authorize: Player: %i Passwd: %s\n", msg->playerId, msg->pswd);
|
||||||
|
|
||||||
if (sessionPasswd.isEmpty())
|
if (sessionPasswd.isEmpty())
|
||||||
|
@ -295,6 +401,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 );
|
sendMsg( client, &errorMsg, errorMsg.hdr.msgSize );
|
||||||
client->flushData();
|
client->flushData();
|
||||||
}
|
}
|
||||||
|
@ -315,6 +422,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 );
|
sendMsg( client, &errorMsg, errorMsg.hdr.msgSize );
|
||||||
client->flushData();
|
client->flushData();
|
||||||
}
|
}
|
||||||
|
@ -324,16 +432,55 @@ void NetPlayServer::serverProcessMessage( NetPlayClient *client, void *msgBuf, s
|
||||||
case NETPLAY_CLIENT_STATE:
|
case NETPLAY_CLIENT_STATE:
|
||||||
{
|
{
|
||||||
netPlayClientState *msg = static_cast<netPlayClientState*>(msgBuf);
|
netPlayClientState *msg = static_cast<netPlayClientState*>(msgBuf);
|
||||||
|
msg->toHostByteOrder();
|
||||||
|
|
||||||
client->currentFrame = msg->frameRun;
|
client->currentFrame = msg->frameRun;
|
||||||
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];
|
||||||
client->gpData[3] = msg->ctrlState[3];
|
client->gpData[3] = msg->ctrlState[3];
|
||||||
|
|
||||||
|
NetPlayFrameData data;
|
||||||
|
if ( (msg->opsFrame == 0) || netPlayFrameData.find( msg->opsFrame, data ) )
|
||||||
|
{
|
||||||
|
//printf("Error: Server Could not find data for frame: %u\n", msg->opsFrame );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bool opsSync = (data.opsCrc32 == msg->opsChkSum);
|
||||||
|
bool ramSync = (data.ramCrc32 == msg->ramChkSum);
|
||||||
|
|
||||||
|
client->syncOk = opsSync && ramSync;
|
||||||
|
|
||||||
|
if (!client->syncOk)
|
||||||
|
{
|
||||||
|
printf("Frame:%u is NOT in Sync: OPS:%i RAM:%i\n", msg->frameRun, opsSync, ramSync);
|
||||||
|
client->desyncCount++;
|
||||||
|
|
||||||
|
if (client->desyncCount > forceResyncCount)
|
||||||
|
{
|
||||||
|
sendStateSyncReq( client );
|
||||||
|
|
||||||
|
client->desyncCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (client->desyncCount > 0)
|
||||||
|
{
|
||||||
|
client->desyncCount--;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
client->desyncCount = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
printf("Unknown Msg: %08X\n", msgId);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -438,6 +585,8 @@ void NetPlayServer::update(void)
|
||||||
|
|
||||||
pushBackInput( inputFrame );
|
pushBackInput( inputFrame );
|
||||||
|
|
||||||
|
runFrameReq.toNetworkByteOrder();
|
||||||
|
|
||||||
for (auto it = clientList.begin(); it != clientList.end(); it++)
|
for (auto it = clientList.begin(); it != clientList.end(); it++)
|
||||||
{
|
{
|
||||||
NetPlayClient *client = *it;
|
NetPlayClient *client = *it;
|
||||||
|
@ -642,15 +791,26 @@ void NetPlayClient::update(void)
|
||||||
uint32_t ctlrData = GetGamepadPressedImmediate();
|
uint32_t ctlrData = GetGamepadPressedImmediate();
|
||||||
uint32_t currFrame = static_cast<uint32_t>(currFrameCounter);
|
uint32_t currFrame = static_cast<uint32_t>(currFrameCounter);
|
||||||
|
|
||||||
|
NetPlayFrameData lastFrameData;
|
||||||
|
netPlayFrameData.getLast( lastFrameData );
|
||||||
|
|
||||||
netPlayClientState statusMsg;
|
netPlayClientState statusMsg;
|
||||||
statusMsg.flags = 0;
|
statusMsg.flags = 0;
|
||||||
statusMsg.frameRdy = inputFrameBack();
|
if (FCEUI_EmulationPaused())
|
||||||
statusMsg.frameRun = currFrame;
|
{
|
||||||
|
statusMsg.flags |= 0x0001;
|
||||||
|
}
|
||||||
|
statusMsg.frameRdy = inputFrameBack();
|
||||||
|
statusMsg.frameRun = currFrame;
|
||||||
|
statusMsg.opsFrame = lastFrameData.frameNum;
|
||||||
|
statusMsg.opsChkSum = lastFrameData.opsCrc32;
|
||||||
|
statusMsg.ramChkSum = lastFrameData.ramCrc32;
|
||||||
statusMsg.ctrlState[0] = (ctlrData ) & 0x000000ff;
|
statusMsg.ctrlState[0] = (ctlrData ) & 0x000000ff;
|
||||||
statusMsg.ctrlState[1] = (ctlrData >> 8) & 0x000000ff;
|
statusMsg.ctrlState[1] = (ctlrData >> 8) & 0x000000ff;
|
||||||
statusMsg.ctrlState[2] = (ctlrData >> 16) & 0x000000ff;
|
statusMsg.ctrlState[2] = (ctlrData >> 16) & 0x000000ff;
|
||||||
statusMsg.ctrlState[3] = (ctlrData >> 24) & 0x000000ff;
|
statusMsg.ctrlState[3] = (ctlrData >> 24) & 0x000000ff;
|
||||||
|
|
||||||
|
statusMsg.toNetworkByteOrder();
|
||||||
sock->write( reinterpret_cast<const char*>(&statusMsg), sizeof(statusMsg) );
|
sock->write( reinterpret_cast<const char*>(&statusMsg), sizeof(statusMsg) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -702,18 +862,22 @@ int NetPlayClient::readMessages( void (*msgCallback)( void *userData, void *msgB
|
||||||
|
|
||||||
hdr = (netPlayMsgHdr*)recvMsgBuf;
|
hdr = (netPlayMsgHdr*)recvMsgBuf;
|
||||||
|
|
||||||
recvMsgId = hdr->msgId;
|
recvMsgId = netPlayByteSwap(hdr->msgId);
|
||||||
recvMsgSize = hdr->msgSize - sizeof(netPlayMsgHdr);
|
recvMsgSize = netPlayByteSwap(hdr->msgSize) - sizeof(netPlayMsgHdr);
|
||||||
recvMsgBytesLeft = recvMsgSize;
|
recvMsgBytesLeft = recvMsgSize;
|
||||||
|
|
||||||
if (hdr->msgSize > recvMsgBufSize)
|
if (netPlayByteSwap(hdr->msgSize) > recvMsgBufSize)
|
||||||
{
|
{
|
||||||
printf("Error: Message size too large\n");
|
printf("Error: Message size too large: %08X\n", recvMsgId);
|
||||||
}
|
}
|
||||||
//printf("HDR: Id: %u Size: %u\n", hdr->msgId, hdr->msgSize );
|
//printf("HDR: Id: %u Size: %u\n", netPlayByteSwap(hdr->msgId), netPlayByteSwap(hdr->msgSize) );
|
||||||
|
|
||||||
recvMsgByteIndex = sizeof(netPlayMsgHdr);
|
recvMsgByteIndex = sizeof(netPlayMsgHdr);
|
||||||
|
|
||||||
|
if (recvMsgBytesLeft == 0)
|
||||||
|
{
|
||||||
|
msgCallback( userData, recvMsgBuf, recvMsgSize );
|
||||||
|
}
|
||||||
readReq = (sock->bytesAvailable() >= recvMsgSize);
|
readReq = (sock->bytesAvailable() >= recvMsgSize);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -730,11 +894,14 @@ void NetPlayClient::clientProcessMessage( void *msgBuf, size_t msgSize )
|
||||||
{
|
{
|
||||||
netPlayMsgHdr *hdr = (netPlayMsgHdr*)msgBuf;
|
netPlayMsgHdr *hdr = (netPlayMsgHdr*)msgBuf;
|
||||||
|
|
||||||
switch (hdr->msgId)
|
const uint32_t msgId = netPlayByteSwap(hdr->msgId);
|
||||||
|
|
||||||
|
switch (msgId)
|
||||||
{
|
{
|
||||||
case NETPLAY_ERROR_MSG:
|
case NETPLAY_ERROR_MSG:
|
||||||
{
|
{
|
||||||
auto *msg = static_cast<netPlayErrorMsg<256>*>(msgBuf);
|
auto *msg = static_cast<netPlayErrorMsg<256>*>(msgBuf);
|
||||||
|
msg->toHostByteOrder();
|
||||||
printf("Error: 0x%X %s\n", msg->code, msg->getBuffer());
|
printf("Error: 0x%X %s\n", msg->code, msg->getBuffer());
|
||||||
|
|
||||||
if (msg->isDisconnectFlagSet())
|
if (msg->isDisconnectFlagSet())
|
||||||
|
@ -751,6 +918,8 @@ void NetPlayClient::clientProcessMessage( void *msgBuf, size_t msgSize )
|
||||||
strncpy( msg.userName, userName.toLocal8Bit().constData(), sizeof(msg.userName));
|
strncpy( msg.userName, userName.toLocal8Bit().constData(), sizeof(msg.userName));
|
||||||
strncpy( msg.pswd, password.toLocal8Bit().constData(), sizeof(msg.pswd) );
|
strncpy( msg.pswd, password.toLocal8Bit().constData(), sizeof(msg.pswd) );
|
||||||
|
|
||||||
|
printf("Authentication Request Received\n");
|
||||||
|
msg.toNetworkByteOrder();
|
||||||
sock->write( (const char*)&msg, sizeof(netPlayAuthResp) );
|
sock->write( (const char*)&msg, sizeof(netPlayAuthResp) );
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -759,11 +928,14 @@ void NetPlayClient::clientProcessMessage( void *msgBuf, size_t msgSize )
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
std::string filepath = QDir::tempPath().toStdString();
|
std::string filepath = QDir::tempPath().toStdString();
|
||||||
netPlayLoadRomReq *msg = static_cast<netPlayLoadRomReq*>(msgBuf);
|
netPlayLoadRomReq *msg = static_cast<netPlayLoadRomReq*>(msgBuf);
|
||||||
|
msg->toHostByteOrder();
|
||||||
const char *romData = &static_cast<const char*>(msgBuf)[ sizeof(netPlayLoadRomReq) ];
|
const char *romData = &static_cast<const char*>(msgBuf)[ sizeof(netPlayLoadRomReq) ];
|
||||||
|
|
||||||
filepath.append( "/" );
|
filepath.append( "/" );
|
||||||
filepath.append( msg->fileName );
|
filepath.append( msg->fileName );
|
||||||
|
|
||||||
|
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");
|
||||||
|
|
||||||
|
@ -780,19 +952,27 @@ void NetPlayClient::clientProcessMessage( void *msgBuf, size_t msgSize )
|
||||||
FCEU_WRAPPER_UNLOCK();
|
FCEU_WRAPPER_UNLOCK();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case NETPLAY_SYNC_STATE:
|
case NETPLAY_SYNC_STATE_RESP:
|
||||||
{
|
{
|
||||||
char *stateData = &static_cast<char*>(msgBuf)[ sizeof(netPlayMsgHdr) ];
|
char *stateData = &static_cast<char*>(msgBuf)[ sizeof(netPlayMsgHdr) ];
|
||||||
|
|
||||||
|
printf("Sync state Request Received\n");
|
||||||
|
|
||||||
EMUFILE_MEMORY em( stateData, msgSize );
|
EMUFILE_MEMORY em( stateData, msgSize );
|
||||||
|
|
||||||
|
FCEU_WRAPPER_LOCK();
|
||||||
FCEUSS_LoadFP( &em, SSLOADPARAM_NOBACKUP );
|
FCEUSS_LoadFP( &em, SSLOADPARAM_NOBACKUP );
|
||||||
|
FCEU_WRAPPER_UNLOCK();
|
||||||
|
|
||||||
|
opsCrc32 = 0;
|
||||||
|
netPlayFrameData.reset();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case NETPLAY_RUN_FRAME_REQ:
|
case NETPLAY_RUN_FRAME_REQ:
|
||||||
{
|
{
|
||||||
NetPlayFrameInput inputFrame;
|
NetPlayFrameInput inputFrame;
|
||||||
netPlayRunFrameReq *msg = static_cast<netPlayRunFrameReq*>(msgBuf);
|
netPlayRunFrameReq *msg = static_cast<netPlayRunFrameReq*>(msgBuf);
|
||||||
|
msg->toHostByteOrder();
|
||||||
|
|
||||||
inputFrame.frameCounter = msg->frameNum;
|
inputFrame.frameCounter = msg->frameNum;
|
||||||
inputFrame.ctrl[0] = msg->ctrlState[0];
|
inputFrame.ctrl[0] = msg->ctrlState[0];
|
||||||
|
@ -807,7 +987,7 @@ void NetPlayClient::clientProcessMessage( void *msgBuf, size_t msgSize )
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
printf("Unknown Msg: %08X\n", msgId);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -977,6 +1157,10 @@ NetPlayJoinDialog::NetPlayJoinDialog(QWidget *parent)
|
||||||
|
|
||||||
QString hostAddress = "localhost";
|
QString hostAddress = "localhost";
|
||||||
g_config->getOption("SDL.NetworkIP", &hostAddress);
|
g_config->getOption("SDL.NetworkIP", &hostAddress);
|
||||||
|
if (hostAddress.isEmpty())
|
||||||
|
{
|
||||||
|
hostAddress = "localhost";
|
||||||
|
}
|
||||||
hostEntry = new QLineEdit();
|
hostEntry = new QLineEdit();
|
||||||
hostEntry->setText(hostAddress);
|
hostEntry->setText(hostAddress);
|
||||||
grid->addWidget( hostEntry, 0, 1 );
|
grid->addWidget( hostEntry, 0, 1 );
|
||||||
|
@ -1202,6 +1386,8 @@ void NetPlayReadInputFrame(uint8_t* joy)
|
||||||
joy[1] = netPlayInputFrame.ctrl[1];
|
joy[1] = netPlayInputFrame.ctrl[1];
|
||||||
joy[2] = netPlayInputFrame.ctrl[2];
|
joy[2] = netPlayInputFrame.ctrl[2];
|
||||||
joy[3] = netPlayInputFrame.ctrl[3];
|
joy[3] = netPlayInputFrame.ctrl[3];
|
||||||
|
|
||||||
|
NetPlayOnFrameBegin();
|
||||||
}
|
}
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
void NetPlayCloseSession(void)
|
void NetPlayCloseSession(void)
|
||||||
|
@ -1244,3 +1430,97 @@ void openNetPlayJoinDialog(QWidget* parent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
|
//---- Network Byte Swap Utilities
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
#ifdef __BIG_ENDIAN__
|
||||||
|
|
||||||
|
#define NETPLAY_HOST_BE 1
|
||||||
|
#define NETPLAY_HOST_LE 0
|
||||||
|
|
||||||
|
#elif defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
|
||||||
|
|
||||||
|
#define NETPLAY_HOST_BE 1
|
||||||
|
#define NETPLAY_HOST_LE 0
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#define NETPLAY_HOST_BE 0
|
||||||
|
#define NETPLAY_HOST_LE 1
|
||||||
|
#endif
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
uint16_t netPlayByteSwap(uint16_t in)
|
||||||
|
{
|
||||||
|
uint16_t out = in;
|
||||||
|
#if NETPLAY_HOST_LE
|
||||||
|
unsigned char *in8 = (unsigned char*)∈
|
||||||
|
unsigned char *out8 = (unsigned char*)&out;
|
||||||
|
out8[0] = in8[1];
|
||||||
|
out8[1] = in8[0];
|
||||||
|
#endif
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
uint32_t netPlayByteSwap(uint32_t in)
|
||||||
|
{
|
||||||
|
uint32_t out = in;
|
||||||
|
#if NETPLAY_HOST_LE
|
||||||
|
unsigned char *in8 = (unsigned char*)∈
|
||||||
|
unsigned char *out8 = (unsigned char*)&out;
|
||||||
|
out8[0] = in8[3];
|
||||||
|
out8[1] = in8[2];
|
||||||
|
out8[2] = in8[1];
|
||||||
|
out8[3] = in8[0];
|
||||||
|
#endif
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
uint64_t netPlayByteSwap(uint64_t in)
|
||||||
|
{
|
||||||
|
uint64_t out = in;
|
||||||
|
#if NETPLAY_HOST_LE
|
||||||
|
unsigned char *in8 = (unsigned char*)∈
|
||||||
|
unsigned char *out8 = (unsigned char*)&out;
|
||||||
|
out8[0] = in8[7];
|
||||||
|
out8[1] = in8[6];
|
||||||
|
out8[2] = in8[5];
|
||||||
|
out8[3] = in8[4];
|
||||||
|
out8[4] = in8[3];
|
||||||
|
out8[5] = in8[2];
|
||||||
|
out8[6] = in8[1];
|
||||||
|
out8[7] = in8[0];
|
||||||
|
#endif
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
uint32_t netPlayCalcRamChkSum()
|
||||||
|
{
|
||||||
|
uint32_t crc = 0;
|
||||||
|
uint8_t ram[256];
|
||||||
|
|
||||||
|
for (int i=0; i<256; i++)
|
||||||
|
{
|
||||||
|
ram[i] = GetMem(i);
|
||||||
|
}
|
||||||
|
crc = CalcCRC32( crc, ram, sizeof(ram));
|
||||||
|
|
||||||
|
return crc;
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void NetPlayTraceInstruction(uint8_t *opcode, int size)
|
||||||
|
{
|
||||||
|
opsCrc32 = CalcCRC32( opsCrc32, opcode, size);
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void NetPlayOnFrameBegin()
|
||||||
|
{
|
||||||
|
NetPlayFrameData data;
|
||||||
|
|
||||||
|
data.frameNum = static_cast<uint32_t>(currFrameCounter);
|
||||||
|
data.opsCrc32 = opsCrc32;
|
||||||
|
data.ramCrc32 = netPlayCalcRamChkSum();
|
||||||
|
|
||||||
|
netPlayFrameData.push( data );
|
||||||
|
|
||||||
|
//printf("Frame: %u Ops:%08X \n", data.frameNum, data.opsCrc32 );
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
|
|
@ -134,6 +134,7 @@ class NetPlayServer : public QTcpServer
|
||||||
int role = -1;
|
int role = -1;
|
||||||
int roleMask = 0;
|
int roleMask = 0;
|
||||||
NetPlayClient* clientPlayer[4] = { nullptr };
|
NetPlayClient* clientPlayer[4] = { nullptr };
|
||||||
|
int forceResyncCount = 10;
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void newConnectionRdy(void);
|
void newConnectionRdy(void);
|
||||||
|
@ -211,6 +212,8 @@ class NetPlayClient : public QObject
|
||||||
QString password;
|
QString password;
|
||||||
int role = -1;
|
int role = -1;
|
||||||
int state = 0;
|
int state = 0;
|
||||||
|
int desyncCount = 0;
|
||||||
|
bool syncOk = false;
|
||||||
unsigned int currentFrame = 0;
|
unsigned int currentFrame = 0;
|
||||||
uint8_t gpData[4];
|
uint8_t gpData[4];
|
||||||
|
|
||||||
|
@ -303,7 +306,9 @@ bool isNetPlayHost(void);
|
||||||
void NetPlayPeriodicUpdate(void);
|
void NetPlayPeriodicUpdate(void);
|
||||||
bool NetPlaySkipWait(void);
|
bool NetPlaySkipWait(void);
|
||||||
int NetPlayFrameWait(void);
|
int NetPlayFrameWait(void);
|
||||||
|
void NetPlayOnFrameBegin(void);
|
||||||
void NetPlayReadInputFrame(uint8_t* joy);
|
void NetPlayReadInputFrame(uint8_t* joy);
|
||||||
void NetPlayCloseSession(void);
|
void NetPlayCloseSession(void);
|
||||||
|
void NetPlayTraceInstruction(uint8_t *opcode, int size);
|
||||||
void openNetPlayHostDialog(QWidget* parent = nullptr);
|
void openNetPlayHostDialog(QWidget* parent = nullptr);
|
||||||
void openNetPlayJoinDialog(QWidget* parent = nullptr);
|
void openNetPlayJoinDialog(QWidget* parent = nullptr);
|
||||||
|
|
|
@ -5,6 +5,11 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
// Network Byte Swap Functions
|
||||||
|
uint16_t netPlayByteSwap(uint16_t);
|
||||||
|
uint32_t netPlayByteSwap(uint32_t);
|
||||||
|
uint64_t netPlayByteSwap(uint64_t);
|
||||||
|
|
||||||
#pragma pack(push,4)
|
#pragma pack(push,4)
|
||||||
|
|
||||||
enum netPlayMsgType
|
enum netPlayMsgType
|
||||||
|
@ -12,7 +17,8 @@ enum netPlayMsgType
|
||||||
NETPLAY_AUTH_REQ,
|
NETPLAY_AUTH_REQ,
|
||||||
NETPLAY_AUTH_RESP,
|
NETPLAY_AUTH_RESP,
|
||||||
NETPLAY_LOAD_ROM_REQ,
|
NETPLAY_LOAD_ROM_REQ,
|
||||||
NETPLAY_SYNC_STATE,
|
NETPLAY_SYNC_STATE_REQ,
|
||||||
|
NETPLAY_SYNC_STATE_RESP,
|
||||||
NETPLAY_RUN_FRAME_REQ,
|
NETPLAY_RUN_FRAME_REQ,
|
||||||
NETPLAY_CLIENT_STATE,
|
NETPLAY_CLIENT_STATE,
|
||||||
NETPLAY_ERROR_MSG,
|
NETPLAY_ERROR_MSG,
|
||||||
|
@ -41,18 +47,41 @@ struct netPlayMsgHdr
|
||||||
magic[1] = NETPLAY_MAGIC_NUMBER;
|
magic[1] = NETPLAY_MAGIC_NUMBER;
|
||||||
msgId = id; msgSize = size;
|
msgId = id; msgSize = size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void toHostByteOrder()
|
||||||
|
{
|
||||||
|
magic[0] = netPlayByteSwap(magic[0]);
|
||||||
|
magic[1] = netPlayByteSwap(magic[1]);
|
||||||
|
msgId = netPlayByteSwap(msgId);
|
||||||
|
msgSize = netPlayByteSwap(msgSize);
|
||||||
|
};
|
||||||
|
void toNetworkByteOrder()
|
||||||
|
{
|
||||||
|
magic[0] = netPlayByteSwap(magic[0]);
|
||||||
|
magic[1] = netPlayByteSwap(magic[1]);
|
||||||
|
msgId = netPlayByteSwap(msgId);
|
||||||
|
msgSize = netPlayByteSwap(msgSize);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct netPlayAuthReq
|
struct netPlayAuthReq
|
||||||
{
|
{
|
||||||
netPlayMsgHdr hdr;
|
netPlayMsgHdr hdr;
|
||||||
|
|
||||||
uint8_t ctrlMask;
|
|
||||||
|
|
||||||
netPlayAuthReq(void)
|
netPlayAuthReq(void)
|
||||||
: hdr(NETPLAY_AUTH_REQ, sizeof(netPlayAuthReq)), ctrlMask(0)
|
: hdr(NETPLAY_AUTH_REQ, sizeof(netPlayAuthReq))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void toHostByteOrder()
|
||||||
|
{
|
||||||
|
hdr.toHostByteOrder();
|
||||||
|
}
|
||||||
|
|
||||||
|
void toNetworkByteOrder()
|
||||||
|
{
|
||||||
|
hdr.toNetworkByteOrder();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct netPlayAuthResp
|
struct netPlayAuthResp
|
||||||
|
@ -68,6 +97,16 @@ struct netPlayAuthResp
|
||||||
{
|
{
|
||||||
memset(pswd, 0, sizeof(pswd));
|
memset(pswd, 0, sizeof(pswd));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void toHostByteOrder()
|
||||||
|
{
|
||||||
|
hdr.toHostByteOrder();
|
||||||
|
}
|
||||||
|
|
||||||
|
void toNetworkByteOrder()
|
||||||
|
{
|
||||||
|
hdr.toNetworkByteOrder();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <size_t N=8>
|
template <size_t N=8>
|
||||||
|
@ -114,6 +153,20 @@ struct netPlayErrorMsg
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void toHostByteOrder()
|
||||||
|
{
|
||||||
|
hdr.toHostByteOrder();
|
||||||
|
code = netPlayByteSwap(code);
|
||||||
|
flags = netPlayByteSwap(flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
void toNetworkByteOrder()
|
||||||
|
{
|
||||||
|
hdr.toNetworkByteOrder();
|
||||||
|
code = netPlayByteSwap(code);
|
||||||
|
flags = netPlayByteSwap(flags);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct netPlayLoadRomReq
|
struct netPlayLoadRomReq
|
||||||
|
@ -128,6 +181,18 @@ struct netPlayLoadRomReq
|
||||||
{
|
{
|
||||||
memset(fileName, 0, sizeof(fileName));
|
memset(fileName, 0, sizeof(fileName));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void toHostByteOrder()
|
||||||
|
{
|
||||||
|
hdr.toHostByteOrder();
|
||||||
|
fileSize = netPlayByteSwap(fileSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
void toNetworkByteOrder()
|
||||||
|
{
|
||||||
|
hdr.toNetworkByteOrder();
|
||||||
|
fileSize = netPlayByteSwap(fileSize);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -144,6 +209,20 @@ struct netPlayRunFrameReq
|
||||||
{
|
{
|
||||||
memset( ctrlState, 0, sizeof(ctrlState) );
|
memset( ctrlState, 0, sizeof(ctrlState) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void toHostByteOrder()
|
||||||
|
{
|
||||||
|
hdr.toHostByteOrder();
|
||||||
|
flags = netPlayByteSwap(flags);
|
||||||
|
frameNum = netPlayByteSwap(frameNum);
|
||||||
|
}
|
||||||
|
|
||||||
|
void toNetworkByteOrder()
|
||||||
|
{
|
||||||
|
hdr.toNetworkByteOrder();
|
||||||
|
flags = netPlayByteSwap(flags);
|
||||||
|
frameNum = netPlayByteSwap(frameNum);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct netPlayClientState
|
struct netPlayClientState
|
||||||
|
@ -151,15 +230,41 @@ struct netPlayClientState
|
||||||
netPlayMsgHdr hdr;
|
netPlayMsgHdr hdr;
|
||||||
|
|
||||||
uint32_t flags;
|
uint32_t flags;
|
||||||
uint32_t frameRdy;
|
uint32_t frameRdy; // What frame we have input ready for
|
||||||
uint32_t frameRun;
|
uint32_t frameRun;
|
||||||
|
uint32_t opsFrame; // Last frame for ops data
|
||||||
|
uint32_t opsChkSum;
|
||||||
|
uint32_t ramChkSum;
|
||||||
uint8_t ctrlState[4];
|
uint8_t ctrlState[4];
|
||||||
|
|
||||||
netPlayClientState(void)
|
netPlayClientState(void)
|
||||||
: hdr(NETPLAY_CLIENT_STATE, sizeof(netPlayClientState)), flags(0), frameRdy(0), frameRun(0)
|
: hdr(NETPLAY_CLIENT_STATE, sizeof(netPlayClientState)), flags(0),
|
||||||
|
frameRdy(0), frameRun(0), opsChkSum(0), ramChkSum(0)
|
||||||
{
|
{
|
||||||
memset( ctrlState, 0, sizeof(ctrlState) );
|
memset( ctrlState, 0, sizeof(ctrlState) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void toHostByteOrder()
|
||||||
|
{
|
||||||
|
hdr.toHostByteOrder();
|
||||||
|
flags = netPlayByteSwap(flags);
|
||||||
|
frameRdy = netPlayByteSwap(frameRdy);
|
||||||
|
frameRun = netPlayByteSwap(frameRun);
|
||||||
|
opsFrame = netPlayByteSwap(opsFrame);
|
||||||
|
opsChkSum = netPlayByteSwap(opsChkSum);
|
||||||
|
ramChkSum = netPlayByteSwap(ramChkSum);
|
||||||
|
}
|
||||||
|
|
||||||
|
void toNetworkByteOrder()
|
||||||
|
{
|
||||||
|
hdr.toNetworkByteOrder();
|
||||||
|
flags = netPlayByteSwap(flags);
|
||||||
|
frameRdy = netPlayByteSwap(frameRdy);
|
||||||
|
frameRun = netPlayByteSwap(frameRun);
|
||||||
|
opsFrame = netPlayByteSwap(opsFrame);
|
||||||
|
opsChkSum = netPlayByteSwap(opsChkSum);
|
||||||
|
ramChkSum = netPlayByteSwap(ramChkSum);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -59,6 +59,7 @@
|
||||||
#include "common/os_utils.h"
|
#include "common/os_utils.h"
|
||||||
#include "utils/StringBuilder.h"
|
#include "utils/StringBuilder.h"
|
||||||
|
|
||||||
|
#include "Qt/NetPlay.h"
|
||||||
#include "Qt/ConsoleDebugger.h"
|
#include "Qt/ConsoleDebugger.h"
|
||||||
#include "Qt/ConsoleWindow.h"
|
#include "Qt/ConsoleWindow.h"
|
||||||
#include "Qt/ConsoleUtilities.h"
|
#include "Qt/ConsoleUtilities.h"
|
||||||
|
@ -1188,9 +1189,13 @@ void FCEUD_FlushTrace()
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------
|
//----------------------------------------------------
|
||||||
//todo: really speed this up
|
|
||||||
void FCEUD_TraceInstruction(uint8 *opcode, int size)
|
void FCEUD_TraceInstruction(uint8 *opcode, int size)
|
||||||
{
|
{
|
||||||
|
if (NetPlayActive())
|
||||||
|
{
|
||||||
|
NetPlayTraceInstruction(opcode, size);
|
||||||
|
}
|
||||||
|
|
||||||
if (!logging)
|
if (!logging)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue