Skip to content

Commit

Permalink
For Qt Netplay, added code to sync cheats between server and clients.
Browse files Browse the repository at this point in the history
  • Loading branch information
thor2016 committed Apr 11, 2024
1 parent 6e69843 commit c97e2c9
Show file tree
Hide file tree
Showing 9 changed files with 252 additions and 53 deletions.
2 changes: 1 addition & 1 deletion src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ if ( ${QT} EQUAL 6 )
message( STATUS "GUI Frontend: Qt6")
set( Qt Qt6 )
find_package( Qt6 REQUIRED COMPONENTS Widgets OpenGL OpenGLWidgets)
find_package( Qt6 REQUIRED COMPONENTS Network)
find_package( Qt6 COMPONENTS Help QUIET)
find_package( Qt6 COMPONENTS Network)
find_package( Qt6 COMPONENTS Qml)
find_package( Qt6 COMPONENTS UiTools)
add_definitions( ${Qt6Widgets_DEFINITIONS} ${Qt6Qml_DEFINITIONS} ${Qt6Network_DEFINITIONS} ${Qt6Help_DEFINITIONS} ${Qt6OpenGLWidgets_DEFINITIONS} )
Expand Down
23 changes: 20 additions & 3 deletions src/cheat.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,15 @@ void FCEU_CheatAddRAM(int s, uint32 A, uint8 *p)
CheatRPtrs[AB+x]=p-A;
}

// Cheat change event callback. Called whenever cheat map is changed or recalculated.
static void (*cheatsChangeEventCB)(void*) = nullptr;
static void* cheatsChangeEventUserData = nullptr;

void FCEU_SetCheatChangeEventCallback( void (*func)(void*), void* userData )
{
cheatsChangeEventCB = func;
cheatsChangeEventUserData = userData;
}

CHEATF_SUBFAST SubCheats[256];
uint32 numsubcheats = 0;
Expand Down Expand Up @@ -132,6 +141,11 @@ void RebuildSubCheats(void)
}
FrozenAddressCount = numsubcheats; //Update the frozen address list

// Notify the system of a change
if (cheatsChangeEventCB != nullptr)
{
cheatsChangeEventCB( cheatsChangeEventUserData );
}
}

void FCEU_PowerCheats()
Expand Down Expand Up @@ -368,12 +382,15 @@ void FCEU_FlushGameCheats(FILE *override, int nosave)
}


int FCEUI_AddCheat(const char *name, uint32 addr, uint8 val, int compare, int type)
int FCEUI_AddCheat(const char *name, uint32 addr, uint8 val, int compare, int type, int status, bool rebuild)
{
AddCheatEntry(name, addr, val, compare, 1, type);
AddCheatEntry(name, addr, val, compare, status, type);
savecheats = 1;
RebuildSubCheats();

if (rebuild)
{
RebuildSubCheats();
}
return 1;
}

Expand Down
2 changes: 2 additions & 0 deletions src/cheat.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ extern int disableAutoLSCheats;
int FCEU_DisableAllCheats(void);
int FCEU_DeleteAllCheats(void);

void FCEU_SetCheatChangeEventCallback( void (*func)(void*) = nullptr, void* userData = nullptr );

struct CHEATF_SUBFAST
{
uint16 addr;
Expand Down
2 changes: 1 addition & 1 deletion src/driver.h
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ void FCEU_DispMessage( __FCEU_PRINTF_FORMAT const char *format, int disppos, ...

int FCEUI_DecodePAR(const char *code, int *a, int *v, int *c, int *type);
int FCEUI_DecodeGG(const char *str, int *a, int *v, int *c);
int FCEUI_AddCheat(const char *name, uint32 addr, uint8 val, int compare, int type);
int FCEUI_AddCheat(const char *name, uint32 addr, uint8 val, int compare, int type, int status = 1, bool rebuild = true);
int FCEUI_DelCheat(uint32 which);
int FCEUI_ToggleCheat(uint32 which);
int FCEUI_GlobalToggleCheat(int global_enable);
Expand Down
14 changes: 14 additions & 0 deletions src/drivers/Qt/ConsoleWindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
#include "../../movie.h"
#include "../../wave.h"
#include "../../state.h"
#include "../../cheat.h"
#include "../../profiler.h"
#include "../../version.h"
#include "common/os_utils.h"
Expand Down Expand Up @@ -285,6 +286,19 @@ consoleWin_t::consoleWin_t(QWidget *parent)
}
};
FCEUSS_SetLoadCallback( stateLoadCallback );

// Register Cheat Change Callback
auto cheatChangeCallback = []( void* userData )
{
FCEU_UNUSED(userData);

//printf("Cheats Changed Event!\n");
if (consoleWindow != nullptr)
{
emit consoleWindow->cheatsChanged();
}
};
FCEU_SetCheatChangeEventCallback( cheatChangeCallback, this );
}

consoleWin_t::~consoleWin_t(void)
Expand Down
1 change: 1 addition & 0 deletions src/drivers/Qt/ConsoleWindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,7 @@ class consoleWin_t : public QMainWindow
void stateLoaded(void);
void nesResetOccurred(void);
void pauseToggled(bool state);
void cheatsChanged(void);

public slots:
void openDebugWindow(void);
Expand Down
173 changes: 142 additions & 31 deletions src/drivers/Qt/NetPlay.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@

#include "../../fceu.h"
#include "../../cart.h"
#include "../../cheat.h"
#include "../../state.h"
#include "../../movie.h"
#include "../../debug.h"
Expand Down Expand Up @@ -182,6 +183,7 @@ NetPlayServer::NetPlayServer(QObject *parent)
connect(consoleWindow, SIGNAL(romUnload(void)), this, SLOT(onRomUnload(void)));
connect(consoleWindow, SIGNAL(stateLoaded(void)), this, SLOT(onStateLoad(void)));
connect(consoleWindow, SIGNAL(nesResetOccurred(void)), this, SLOT(onNesReset(void)));
connect(consoleWindow, SIGNAL(cheatsChanged(void)), this, SLOT(onCheatsChanged(void)));
connect(consoleWindow, SIGNAL(pauseToggled(bool)), this, SLOT(onPauseToggled(bool)));

FCEU_WRAPPER_LOCK();
Expand Down Expand Up @@ -396,22 +398,53 @@ int NetPlayServer::sendRomLoadReq( NetPlayClient *client )
return 0;
}
//-----------------------------------------------------------------------------
struct NetPlayServerCheatQuery
{
int numLoaded = 0;

netPlayLoadStateResp::CheatData data[netPlayLoadStateResp::MaxCheats];
};

static int serverActiveCheatListCB(const char *name, uint32 a, uint8 v, int c, int s, int type, void *data)
{
NetPlayServerCheatQuery* query = static_cast<NetPlayServerCheatQuery*>(data);

const int i = query->numLoaded;

if (i < netPlayLoadStateResp::MaxCheats)
{
auto& cheat = query->data[i];
cheat.addr = a;
cheat.val = v;
cheat.cmp = c;
cheat.type = type;
cheat.stat = s;
Strlcpy( cheat.name, name, sizeof(cheat.name));

query->numLoaded++;
}

return 1;
}
//-----------------------------------------------------------------------------
int NetPlayServer::sendStateSyncReq( NetPlayClient *client )
{
EMUFILE_MEMORY em;
int compressionLevel = 1;
int numCtrlFrames = 0, numCheats = 0, compressionLevel = 1;
static constexpr size_t maxBytesPerWrite = 32 * 1024;
netPlayLoadStateResp resp;
netPlayLoadStateResp::CtrlData ctrlData[netPlayLoadStateResp::MaxCtrlFrames];
NetPlayServerCheatQuery cheatQuery;

if ( GameInfo == nullptr )
{
return -1;
}
FCEUSS_SaveMS( &em, compressionLevel );

resp.hdr.msgSize += em.size();
resp.stateSize = em.size();
resp.opsCrc32 = opsCrc32;
resp.romCrc32 = romCrc32;

NetPlayFrameData lastFrameData;
netPlayFrameData.getLast( lastFrameData );
Expand All @@ -428,20 +461,34 @@ int NetPlayServer::sendStateSyncReq( NetPlayClient *client )
{
if (i < netPlayLoadStateResp::MaxCtrlFrames)
{
resp.ctrlData[i].frameNum = inputFrame.frameCounter;
resp.ctrlData[i].ctrlState[0] = inputFrame.ctrl[0];
resp.ctrlData[i].ctrlState[1] = inputFrame.ctrl[1];
resp.ctrlData[i].ctrlState[2] = inputFrame.ctrl[2];
resp.ctrlData[i].ctrlState[3] = inputFrame.ctrl[3];
ctrlData[i].frameNum = netPlayByteSwap(inputFrame.frameCounter);
ctrlData[i].ctrlState[0] = inputFrame.ctrl[0];
ctrlData[i].ctrlState[1] = inputFrame.ctrl[1];
ctrlData[i].ctrlState[2] = inputFrame.ctrl[2];
ctrlData[i].ctrlState[3] = inputFrame.ctrl[3];
i++;
}
}
resp.numCtrlFrames = i;
resp.numCtrlFrames = numCtrlFrames = i;
}

FCEUI_ListCheats(::serverActiveCheatListCB, (void *)&cheatQuery);
resp.numCheats = numCheats = cheatQuery.numLoaded;

resp.calcTotalSize();

printf("Sending ROM Sync Request: %zu\n", em.size());

sendMsg( client, &resp, sizeof(netPlayLoadStateResp), [&resp]{ resp.toNetworkByteOrder(); } );

if (numCtrlFrames > 0)
{
sendMsg( client, ctrlData, numCtrlFrames * sizeof(netPlayLoadStateResp::CtrlData) );
}
if (numCheats > 0)
{
sendMsg( client, &cheatQuery.data, numCheats * sizeof(netPlayLoadStateResp::CheatData) );
}
//sendMsg( client, em.buf(), em.size() );

const unsigned char* bufPtr = em.buf();
Expand Down Expand Up @@ -583,6 +630,7 @@ void NetPlayServer::onRomLoad()
//-----------------------------------------------------------------------------
void NetPlayServer::onRomUnload()
{
//printf("ROM UnLoaded!\n");
netPlayMsgHdr unloadMsg(NETPLAY_UNLOAD_ROM_REQ);

romCrc32 = 0;
Expand Down Expand Up @@ -642,6 +690,32 @@ void NetPlayServer::onNesReset()
FCEU_WRAPPER_UNLOCK();
}
//-----------------------------------------------------------------------------
void NetPlayServer::onCheatsChanged()
{
//printf("NES Cheats Event!\n");
if (romCrc32 == 0)
{
return;
}
FCEU_WRAPPER_LOCK();

opsCrc32 = 0;
netPlayFrameData.reset();

inputClear();
inputFrameCount = static_cast<uint32_t>(currFrameCounter);

sendPauseAll();

// NES Reset has occurred on server, signal clients sync
for (auto& client : clientList )
{
//sendRomLoadReq( client );
sendStateSyncReq( client );
}
FCEU_WRAPPER_UNLOCK();
}
//-----------------------------------------------------------------------------
void NetPlayServer::onPauseToggled( bool isPaused )
{
if (isPaused)
Expand Down Expand Up @@ -1568,6 +1642,11 @@ int NetPlayClient::requestStateLoad(EMUFILE *is)
{
printf("Read Error\n");
}

if (currCartInfo != nullptr)
{
resp.romCrc32 = romCrc32;
}
printf("Sending Client ROM Sync Request: %u\n", resp.stateSize);

resp.toNetworkByteOrder();
Expand Down Expand Up @@ -1893,6 +1972,7 @@ void NetPlayClient::clientProcessMessage( void *msgBuf, size_t msgSize )
netPlayLoadStateResp* msg = static_cast<netPlayLoadStateResp*>(msgBuf);
msg->toHostByteOrder();

const bool romMatch = (msg->romCrc32 = romCrc32);
char *stateData = msg->stateDataBuf();
const uint32_t stateDataSize = msg->stateDataSize();

Expand All @@ -1901,34 +1981,64 @@ void NetPlayClient::clientProcessMessage( void *msgBuf, size_t msgSize )
EMUFILE_MEMORY em( stateData, stateDataSize );

FCEU_WRAPPER_LOCK();
serverRequestedStateLoad = true;
FCEUSS_LoadFP( &em, SSLOADPARAM_NOBACKUP );
serverRequestedStateLoad = false;

opsCrc32 = msg->opsCrc32;
netPlayFrameData.reset();
bool dataValid = romMatch;

NetPlayFrameData data;
data.frameNum = msg->lastFrame.num;
data.opsCrc32 = msg->lastFrame.opsCrc32;
data.ramCrc32 = msg->lastFrame.ramCrc32;
if (dataValid)
{
serverRequestedStateLoad = true;
FCEUSS_LoadFP( &em, SSLOADPARAM_NOBACKUP );
serverRequestedStateLoad = false;

netPlayFrameData.push( data );
opsCrc32 = msg->opsCrc32;
netPlayFrameData.reset();

inputClear();
NetPlayFrameData data;
data.frameNum = msg->lastFrame.num;
data.opsCrc32 = msg->lastFrame.opsCrc32;
data.ramCrc32 = msg->lastFrame.ramCrc32;

const int numInputFrames = msg->numCtrlFrames;
for (int i=0; i<numInputFrames; i++)
{
NetPlayFrameInput inputFrame;
netPlayFrameData.push( data );

inputFrame.frameCounter = msg->ctrlData[i].frameNum;
inputFrame.ctrl[0] = msg->ctrlData[i].ctrlState[0];
inputFrame.ctrl[1] = msg->ctrlData[i].ctrlState[1];
inputFrame.ctrl[2] = msg->ctrlData[i].ctrlState[2];
inputFrame.ctrl[3] = msg->ctrlData[i].ctrlState[3];
inputClear();

pushBackInput( inputFrame );
const int numInputFrames = msg->numCtrlFrames;
for (int i=0; i<numInputFrames; i++)
{
NetPlayFrameInput inputFrame;
auto ctrlData = msg->ctrlDataBuf();

ctrlData[i].toHostByteOrder();
inputFrame.frameCounter = ctrlData[i].frameNum;
inputFrame.ctrl[0] = ctrlData[i].ctrlState[0];
inputFrame.ctrl[1] = ctrlData[i].ctrlState[1];
inputFrame.ctrl[2] = ctrlData[i].ctrlState[2];
inputFrame.ctrl[3] = ctrlData[i].ctrlState[3];

pushBackInput( inputFrame );
}

const int numCheats = msg->numCheats;

if (numCheats > 0)
{
const int lastCheatIdx = numCheats - 1;

FCEU_FlushGameCheats(0, 1);
for (int i=0; i<numCheats; i++)
{
auto cheatBuf = msg->cheatDataBuf();
auto& cheatData = cheatBuf[i];
// Set cheat rebuild flag on last item.
bool lastItem = (i == lastCheatIdx);

FCEUI_AddCheat( cheatData.name, cheatData.addr, cheatData.val, cheatData.cmp, cheatData.type, cheatData.stat, lastItem );
}
}
else
{
FCEU_DeleteAllCheats();
}
}
FCEU_WRAPPER_UNLOCK();

Expand Down Expand Up @@ -3009,10 +3119,11 @@ uint64_t netPlayByteSwap(uint64_t in)
//----------------------------------------------------------------------------
uint32_t netPlayCalcRamChkSum()
{
constexpr int ramSize = 0x800;
uint32_t crc = 0;
uint8_t ram[256];
uint8_t ram[ramSize];

for (int i=0; i<256; i++)
for (int i=0; i<ramSize; i++)
{
ram[i] = GetMem(i);
}
Expand Down
1 change: 1 addition & 0 deletions src/drivers/Qt/NetPlay.h
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,7 @@ class NetPlayServer : public QTcpServer
void onStateLoad(void);
void onNesReset(void);
void onPauseToggled(bool);
void onCheatsChanged(void);
void processClientRomLoadRequests(void);
void processClientStateLoadRequests(void);
};
Expand Down
Loading

0 comments on commit c97e2c9

Please sign in to comment.