For Qt Netplay, added code to sync cheats between server and clients.
This commit is contained in:
parent
6e698433aa
commit
c97e2c9ad3
|
@ -39,8 +39,8 @@ if ( ${QT} EQUAL 6 )
|
||||||
message( STATUS "GUI Frontend: Qt6")
|
message( STATUS "GUI Frontend: Qt6")
|
||||||
set( Qt Qt6 )
|
set( Qt Qt6 )
|
||||||
find_package( Qt6 REQUIRED COMPONENTS Widgets OpenGL OpenGLWidgets)
|
find_package( Qt6 REQUIRED COMPONENTS Widgets OpenGL OpenGLWidgets)
|
||||||
|
find_package( Qt6 REQUIRED COMPONENTS Network)
|
||||||
find_package( Qt6 COMPONENTS Help QUIET)
|
find_package( Qt6 COMPONENTS Help QUIET)
|
||||||
find_package( Qt6 COMPONENTS Network)
|
|
||||||
find_package( Qt6 COMPONENTS Qml)
|
find_package( Qt6 COMPONENTS Qml)
|
||||||
find_package( Qt6 COMPONENTS UiTools)
|
find_package( Qt6 COMPONENTS UiTools)
|
||||||
add_definitions( ${Qt6Widgets_DEFINITIONS} ${Qt6Qml_DEFINITIONS} ${Qt6Network_DEFINITIONS} ${Qt6Help_DEFINITIONS} ${Qt6OpenGLWidgets_DEFINITIONS} )
|
add_definitions( ${Qt6Widgets_DEFINITIONS} ${Qt6Qml_DEFINITIONS} ${Qt6Network_DEFINITIONS} ${Qt6Help_DEFINITIONS} ${Qt6OpenGLWidgets_DEFINITIONS} )
|
||||||
|
|
|
@ -58,6 +58,15 @@ void FCEU_CheatAddRAM(int s, uint32 A, uint8 *p)
|
||||||
CheatRPtrs[AB+x]=p-A;
|
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];
|
CHEATF_SUBFAST SubCheats[256];
|
||||||
uint32 numsubcheats = 0;
|
uint32 numsubcheats = 0;
|
||||||
|
@ -132,6 +141,11 @@ void RebuildSubCheats(void)
|
||||||
}
|
}
|
||||||
FrozenAddressCount = numsubcheats; //Update the frozen address list
|
FrozenAddressCount = numsubcheats; //Update the frozen address list
|
||||||
|
|
||||||
|
// Notify the system of a change
|
||||||
|
if (cheatsChangeEventCB != nullptr)
|
||||||
|
{
|
||||||
|
cheatsChangeEventCB( cheatsChangeEventUserData );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FCEU_PowerCheats()
|
void FCEU_PowerCheats()
|
||||||
|
@ -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;
|
savecheats = 1;
|
||||||
RebuildSubCheats();
|
|
||||||
|
|
||||||
|
if (rebuild)
|
||||||
|
{
|
||||||
|
RebuildSubCheats();
|
||||||
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,6 +33,8 @@ extern int disableAutoLSCheats;
|
||||||
int FCEU_DisableAllCheats(void);
|
int FCEU_DisableAllCheats(void);
|
||||||
int FCEU_DeleteAllCheats(void);
|
int FCEU_DeleteAllCheats(void);
|
||||||
|
|
||||||
|
void FCEU_SetCheatChangeEventCallback( void (*func)(void*) = nullptr, void* userData = nullptr );
|
||||||
|
|
||||||
struct CHEATF_SUBFAST
|
struct CHEATF_SUBFAST
|
||||||
{
|
{
|
||||||
uint16 addr;
|
uint16 addr;
|
||||||
|
|
|
@ -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_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_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_DelCheat(uint32 which);
|
||||||
int FCEUI_ToggleCheat(uint32 which);
|
int FCEUI_ToggleCheat(uint32 which);
|
||||||
int FCEUI_GlobalToggleCheat(int global_enable);
|
int FCEUI_GlobalToggleCheat(int global_enable);
|
||||||
|
|
|
@ -55,6 +55,7 @@
|
||||||
#include "../../movie.h"
|
#include "../../movie.h"
|
||||||
#include "../../wave.h"
|
#include "../../wave.h"
|
||||||
#include "../../state.h"
|
#include "../../state.h"
|
||||||
|
#include "../../cheat.h"
|
||||||
#include "../../profiler.h"
|
#include "../../profiler.h"
|
||||||
#include "../../version.h"
|
#include "../../version.h"
|
||||||
#include "common/os_utils.h"
|
#include "common/os_utils.h"
|
||||||
|
@ -285,6 +286,19 @@ consoleWin_t::consoleWin_t(QWidget *parent)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
FCEUSS_SetLoadCallback( stateLoadCallback );
|
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)
|
consoleWin_t::~consoleWin_t(void)
|
||||||
|
|
|
@ -332,6 +332,7 @@ class consoleWin_t : public QMainWindow
|
||||||
void stateLoaded(void);
|
void stateLoaded(void);
|
||||||
void nesResetOccurred(void);
|
void nesResetOccurred(void);
|
||||||
void pauseToggled(bool state);
|
void pauseToggled(bool state);
|
||||||
|
void cheatsChanged(void);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void openDebugWindow(void);
|
void openDebugWindow(void);
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
|
|
||||||
#include "../../fceu.h"
|
#include "../../fceu.h"
|
||||||
#include "../../cart.h"
|
#include "../../cart.h"
|
||||||
|
#include "../../cheat.h"
|
||||||
#include "../../state.h"
|
#include "../../state.h"
|
||||||
#include "../../movie.h"
|
#include "../../movie.h"
|
||||||
#include "../../debug.h"
|
#include "../../debug.h"
|
||||||
|
@ -182,6 +183,7 @@ NetPlayServer::NetPlayServer(QObject *parent)
|
||||||
connect(consoleWindow, SIGNAL(romUnload(void)), this, SLOT(onRomUnload(void)));
|
connect(consoleWindow, SIGNAL(romUnload(void)), this, SLOT(onRomUnload(void)));
|
||||||
connect(consoleWindow, SIGNAL(stateLoaded(void)), this, SLOT(onStateLoad(void)));
|
connect(consoleWindow, SIGNAL(stateLoaded(void)), this, SLOT(onStateLoad(void)));
|
||||||
connect(consoleWindow, SIGNAL(nesResetOccurred(void)), this, SLOT(onNesReset(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)));
|
connect(consoleWindow, SIGNAL(pauseToggled(bool)), this, SLOT(onPauseToggled(bool)));
|
||||||
|
|
||||||
FCEU_WRAPPER_LOCK();
|
FCEU_WRAPPER_LOCK();
|
||||||
|
@ -396,12 +398,43 @@ int NetPlayServer::sendRomLoadReq( NetPlayClient *client )
|
||||||
return 0;
|
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 )
|
int NetPlayServer::sendStateSyncReq( NetPlayClient *client )
|
||||||
{
|
{
|
||||||
EMUFILE_MEMORY em;
|
EMUFILE_MEMORY em;
|
||||||
int compressionLevel = 1;
|
int numCtrlFrames = 0, numCheats = 0, compressionLevel = 1;
|
||||||
static constexpr size_t maxBytesPerWrite = 32 * 1024;
|
static constexpr size_t maxBytesPerWrite = 32 * 1024;
|
||||||
netPlayLoadStateResp resp;
|
netPlayLoadStateResp resp;
|
||||||
|
netPlayLoadStateResp::CtrlData ctrlData[netPlayLoadStateResp::MaxCtrlFrames];
|
||||||
|
NetPlayServerCheatQuery cheatQuery;
|
||||||
|
|
||||||
if ( GameInfo == nullptr )
|
if ( GameInfo == nullptr )
|
||||||
{
|
{
|
||||||
|
@ -409,9 +442,9 @@ int NetPlayServer::sendStateSyncReq( NetPlayClient *client )
|
||||||
}
|
}
|
||||||
FCEUSS_SaveMS( &em, compressionLevel );
|
FCEUSS_SaveMS( &em, compressionLevel );
|
||||||
|
|
||||||
resp.hdr.msgSize += em.size();
|
|
||||||
resp.stateSize = em.size();
|
resp.stateSize = em.size();
|
||||||
resp.opsCrc32 = opsCrc32;
|
resp.opsCrc32 = opsCrc32;
|
||||||
|
resp.romCrc32 = romCrc32;
|
||||||
|
|
||||||
NetPlayFrameData lastFrameData;
|
NetPlayFrameData lastFrameData;
|
||||||
netPlayFrameData.getLast( lastFrameData );
|
netPlayFrameData.getLast( lastFrameData );
|
||||||
|
@ -428,20 +461,34 @@ int NetPlayServer::sendStateSyncReq( NetPlayClient *client )
|
||||||
{
|
{
|
||||||
if (i < netPlayLoadStateResp::MaxCtrlFrames)
|
if (i < netPlayLoadStateResp::MaxCtrlFrames)
|
||||||
{
|
{
|
||||||
resp.ctrlData[i].frameNum = inputFrame.frameCounter;
|
ctrlData[i].frameNum = netPlayByteSwap(inputFrame.frameCounter);
|
||||||
resp.ctrlData[i].ctrlState[0] = inputFrame.ctrl[0];
|
ctrlData[i].ctrlState[0] = inputFrame.ctrl[0];
|
||||||
resp.ctrlData[i].ctrlState[1] = inputFrame.ctrl[1];
|
ctrlData[i].ctrlState[1] = inputFrame.ctrl[1];
|
||||||
resp.ctrlData[i].ctrlState[2] = inputFrame.ctrl[2];
|
ctrlData[i].ctrlState[2] = inputFrame.ctrl[2];
|
||||||
resp.ctrlData[i].ctrlState[3] = inputFrame.ctrl[3];
|
ctrlData[i].ctrlState[3] = inputFrame.ctrl[3];
|
||||||
i++;
|
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());
|
printf("Sending ROM Sync Request: %zu\n", em.size());
|
||||||
|
|
||||||
sendMsg( client, &resp, sizeof(netPlayLoadStateResp), [&resp]{ resp.toNetworkByteOrder(); } );
|
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() );
|
//sendMsg( client, em.buf(), em.size() );
|
||||||
|
|
||||||
const unsigned char* bufPtr = em.buf();
|
const unsigned char* bufPtr = em.buf();
|
||||||
|
@ -583,6 +630,7 @@ void NetPlayServer::onRomLoad()
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
void NetPlayServer::onRomUnload()
|
void NetPlayServer::onRomUnload()
|
||||||
{
|
{
|
||||||
|
//printf("ROM UnLoaded!\n");
|
||||||
netPlayMsgHdr unloadMsg(NETPLAY_UNLOAD_ROM_REQ);
|
netPlayMsgHdr unloadMsg(NETPLAY_UNLOAD_ROM_REQ);
|
||||||
|
|
||||||
romCrc32 = 0;
|
romCrc32 = 0;
|
||||||
|
@ -642,6 +690,32 @@ void NetPlayServer::onNesReset()
|
||||||
FCEU_WRAPPER_UNLOCK();
|
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 )
|
void NetPlayServer::onPauseToggled( bool isPaused )
|
||||||
{
|
{
|
||||||
if (isPaused)
|
if (isPaused)
|
||||||
|
@ -1568,6 +1642,11 @@ int NetPlayClient::requestStateLoad(EMUFILE *is)
|
||||||
{
|
{
|
||||||
printf("Read Error\n");
|
printf("Read Error\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (currCartInfo != nullptr)
|
||||||
|
{
|
||||||
|
resp.romCrc32 = romCrc32;
|
||||||
|
}
|
||||||
printf("Sending Client ROM Sync Request: %u\n", resp.stateSize);
|
printf("Sending Client ROM Sync Request: %u\n", resp.stateSize);
|
||||||
|
|
||||||
resp.toNetworkByteOrder();
|
resp.toNetworkByteOrder();
|
||||||
|
@ -1893,6 +1972,7 @@ void NetPlayClient::clientProcessMessage( void *msgBuf, size_t msgSize )
|
||||||
netPlayLoadStateResp* msg = static_cast<netPlayLoadStateResp*>(msgBuf);
|
netPlayLoadStateResp* msg = static_cast<netPlayLoadStateResp*>(msgBuf);
|
||||||
msg->toHostByteOrder();
|
msg->toHostByteOrder();
|
||||||
|
|
||||||
|
const bool romMatch = (msg->romCrc32 = romCrc32);
|
||||||
char *stateData = msg->stateDataBuf();
|
char *stateData = msg->stateDataBuf();
|
||||||
const uint32_t stateDataSize = msg->stateDataSize();
|
const uint32_t stateDataSize = msg->stateDataSize();
|
||||||
|
|
||||||
|
@ -1901,34 +1981,64 @@ void NetPlayClient::clientProcessMessage( void *msgBuf, size_t msgSize )
|
||||||
EMUFILE_MEMORY em( stateData, stateDataSize );
|
EMUFILE_MEMORY em( stateData, stateDataSize );
|
||||||
|
|
||||||
FCEU_WRAPPER_LOCK();
|
FCEU_WRAPPER_LOCK();
|
||||||
serverRequestedStateLoad = true;
|
|
||||||
FCEUSS_LoadFP( &em, SSLOADPARAM_NOBACKUP );
|
|
||||||
serverRequestedStateLoad = false;
|
|
||||||
|
|
||||||
opsCrc32 = msg->opsCrc32;
|
bool dataValid = romMatch;
|
||||||
netPlayFrameData.reset();
|
|
||||||
|
|
||||||
NetPlayFrameData data;
|
if (dataValid)
|
||||||
data.frameNum = msg->lastFrame.num;
|
|
||||||
data.opsCrc32 = msg->lastFrame.opsCrc32;
|
|
||||||
data.ramCrc32 = msg->lastFrame.ramCrc32;
|
|
||||||
|
|
||||||
netPlayFrameData.push( data );
|
|
||||||
|
|
||||||
inputClear();
|
|
||||||
|
|
||||||
const int numInputFrames = msg->numCtrlFrames;
|
|
||||||
for (int i=0; i<numInputFrames; i++)
|
|
||||||
{
|
{
|
||||||
NetPlayFrameInput inputFrame;
|
serverRequestedStateLoad = true;
|
||||||
|
FCEUSS_LoadFP( &em, SSLOADPARAM_NOBACKUP );
|
||||||
|
serverRequestedStateLoad = false;
|
||||||
|
|
||||||
inputFrame.frameCounter = msg->ctrlData[i].frameNum;
|
opsCrc32 = msg->opsCrc32;
|
||||||
inputFrame.ctrl[0] = msg->ctrlData[i].ctrlState[0];
|
netPlayFrameData.reset();
|
||||||
inputFrame.ctrl[1] = msg->ctrlData[i].ctrlState[1];
|
|
||||||
inputFrame.ctrl[2] = msg->ctrlData[i].ctrlState[2];
|
|
||||||
inputFrame.ctrl[3] = msg->ctrlData[i].ctrlState[3];
|
|
||||||
|
|
||||||
pushBackInput( inputFrame );
|
NetPlayFrameData data;
|
||||||
|
data.frameNum = msg->lastFrame.num;
|
||||||
|
data.opsCrc32 = msg->lastFrame.opsCrc32;
|
||||||
|
data.ramCrc32 = msg->lastFrame.ramCrc32;
|
||||||
|
|
||||||
|
netPlayFrameData.push( data );
|
||||||
|
|
||||||
|
inputClear();
|
||||||
|
|
||||||
|
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();
|
FCEU_WRAPPER_UNLOCK();
|
||||||
|
|
||||||
|
@ -3009,10 +3119,11 @@ uint64_t netPlayByteSwap(uint64_t in)
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
uint32_t netPlayCalcRamChkSum()
|
uint32_t netPlayCalcRamChkSum()
|
||||||
{
|
{
|
||||||
|
constexpr int ramSize = 0x800;
|
||||||
uint32_t crc = 0;
|
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);
|
ram[i] = GetMem(i);
|
||||||
}
|
}
|
||||||
|
|
|
@ -190,6 +190,7 @@ class NetPlayServer : public QTcpServer
|
||||||
void onStateLoad(void);
|
void onStateLoad(void);
|
||||||
void onNesReset(void);
|
void onNesReset(void);
|
||||||
void onPauseToggled(bool);
|
void onPauseToggled(bool);
|
||||||
|
void onCheatsChanged(void);
|
||||||
void processClientRomLoadRequests(void);
|
void processClientRomLoadRequests(void);
|
||||||
void processClientStateLoadRequests(void);
|
void processClientStateLoadRequests(void);
|
||||||
};
|
};
|
||||||
|
|
|
@ -262,7 +262,10 @@ struct netPlayLoadStateResp
|
||||||
netPlayMsgHdr hdr;
|
netPlayMsgHdr hdr;
|
||||||
|
|
||||||
uint32_t stateSize;
|
uint32_t stateSize;
|
||||||
|
uint32_t numCtrlFrames;
|
||||||
|
uint32_t numCheats;
|
||||||
uint32_t opsCrc32;
|
uint32_t opsCrc32;
|
||||||
|
uint32_t romCrc32;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
uint32_t num = 0;
|
uint32_t num = 0;
|
||||||
|
@ -270,57 +273,107 @@ struct netPlayLoadStateResp
|
||||||
uint32_t ramCrc32 = 0;
|
uint32_t ramCrc32 = 0;
|
||||||
} lastFrame;
|
} lastFrame;
|
||||||
|
|
||||||
uint32_t numCtrlFrames;
|
|
||||||
|
|
||||||
static constexpr int MaxCtrlFrames = 10;
|
static constexpr int MaxCtrlFrames = 10;
|
||||||
|
static constexpr int MaxCheats = 64;
|
||||||
|
|
||||||
struct {
|
struct CtrlData
|
||||||
|
{
|
||||||
uint32_t frameNum = 0;
|
uint32_t frameNum = 0;
|
||||||
uint8_t ctrlState[4] = {0};
|
uint8_t ctrlState[4] = {0};
|
||||||
|
|
||||||
} ctrlData[MaxCtrlFrames];
|
void toHostByteOrder()
|
||||||
|
{
|
||||||
|
frameNum = netPlayByteSwap(frameNum);
|
||||||
|
}
|
||||||
|
|
||||||
|
void toNetworkByteOrder()
|
||||||
|
{
|
||||||
|
frameNum = netPlayByteSwap(frameNum);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CheatData
|
||||||
|
{
|
||||||
|
uint16_t addr = 0;
|
||||||
|
uint8_t val = 0;
|
||||||
|
int8_t cmp = -1; /* -1 for no compare. */
|
||||||
|
int8_t type = 0; /* 0 for replace, 1 for substitute(GG). */
|
||||||
|
int8_t stat = 0;
|
||||||
|
char name[64] = {0};
|
||||||
|
|
||||||
|
void toHostByteOrder()
|
||||||
|
{
|
||||||
|
addr = netPlayByteSwap(addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void toNetworkByteOrder()
|
||||||
|
{
|
||||||
|
addr = netPlayByteSwap(addr);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
netPlayLoadStateResp(void)
|
netPlayLoadStateResp(void)
|
||||||
: hdr(NETPLAY_SYNC_STATE_RESP, sizeof(netPlayLoadStateResp)),
|
: hdr(NETPLAY_SYNC_STATE_RESP, sizeof(netPlayLoadStateResp)),
|
||||||
stateSize(0), opsCrc32(0), numCtrlFrames(0)
|
stateSize(0), numCtrlFrames(0), numCheats(0), opsCrc32(0), romCrc32(0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t calcTotalSize()
|
||||||
|
{
|
||||||
|
size_t size = sizeof(netPlayLoadStateResp) +
|
||||||
|
(numCtrlFrames * sizeof(CtrlData) ) +
|
||||||
|
(numCheats * sizeof(CheatData)) +
|
||||||
|
stateSize;
|
||||||
|
|
||||||
|
hdr.msgSize = size;
|
||||||
|
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
void toHostByteOrder()
|
void toHostByteOrder()
|
||||||
{
|
{
|
||||||
hdr.toHostByteOrder();
|
hdr.toHostByteOrder();
|
||||||
stateSize = netPlayByteSwap(stateSize);
|
stateSize = netPlayByteSwap(stateSize);
|
||||||
|
numCtrlFrames = netPlayByteSwap(numCtrlFrames);
|
||||||
|
numCheats = netPlayByteSwap(numCheats);
|
||||||
opsCrc32 = netPlayByteSwap(opsCrc32);
|
opsCrc32 = netPlayByteSwap(opsCrc32);
|
||||||
|
romCrc32 = netPlayByteSwap(romCrc32);
|
||||||
lastFrame.num = netPlayByteSwap(lastFrame.num);
|
lastFrame.num = netPlayByteSwap(lastFrame.num);
|
||||||
lastFrame.opsCrc32 = netPlayByteSwap(lastFrame.opsCrc32);
|
lastFrame.opsCrc32 = netPlayByteSwap(lastFrame.opsCrc32);
|
||||||
lastFrame.ramCrc32 = netPlayByteSwap(lastFrame.ramCrc32);
|
lastFrame.ramCrc32 = netPlayByteSwap(lastFrame.ramCrc32);
|
||||||
numCtrlFrames = netPlayByteSwap(numCtrlFrames);
|
|
||||||
|
|
||||||
for (int i=0; i<MaxCtrlFrames; i++)
|
|
||||||
{
|
|
||||||
ctrlData[i].frameNum = netPlayByteSwap(ctrlData[i].frameNum);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void toNetworkByteOrder()
|
void toNetworkByteOrder()
|
||||||
{
|
{
|
||||||
hdr.toNetworkByteOrder();
|
hdr.toNetworkByteOrder();
|
||||||
stateSize = netPlayByteSwap(stateSize);
|
stateSize = netPlayByteSwap(stateSize);
|
||||||
|
numCtrlFrames = netPlayByteSwap(numCtrlFrames);
|
||||||
|
numCheats = netPlayByteSwap(numCheats);
|
||||||
opsCrc32 = netPlayByteSwap(opsCrc32);
|
opsCrc32 = netPlayByteSwap(opsCrc32);
|
||||||
|
romCrc32 = netPlayByteSwap(romCrc32);
|
||||||
lastFrame.num = netPlayByteSwap(lastFrame.num);
|
lastFrame.num = netPlayByteSwap(lastFrame.num);
|
||||||
lastFrame.opsCrc32 = netPlayByteSwap(lastFrame.opsCrc32);
|
lastFrame.opsCrc32 = netPlayByteSwap(lastFrame.opsCrc32);
|
||||||
lastFrame.ramCrc32 = netPlayByteSwap(lastFrame.ramCrc32);
|
lastFrame.ramCrc32 = netPlayByteSwap(lastFrame.ramCrc32);
|
||||||
numCtrlFrames = netPlayByteSwap(numCtrlFrames);
|
}
|
||||||
|
|
||||||
for (int i=0; i<MaxCtrlFrames; i++)
|
CtrlData* ctrlDataBuf()
|
||||||
{
|
{
|
||||||
ctrlData[i].frameNum = netPlayByteSwap(ctrlData[i].frameNum);
|
uintptr_t buf = ((uintptr_t)this) + sizeof(netPlayLoadStateResp);
|
||||||
}
|
|
||||||
|
return (CtrlData*)buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
CheatData* cheatDataBuf()
|
||||||
|
{
|
||||||
|
uintptr_t buf = ((uintptr_t)this) + sizeof(netPlayLoadStateResp) +
|
||||||
|
(numCtrlFrames * sizeof(CtrlData));
|
||||||
|
return (CheatData*)buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
char* stateDataBuf()
|
char* stateDataBuf()
|
||||||
{
|
{
|
||||||
uintptr_t buf = ((uintptr_t)this) + sizeof(netPlayLoadStateResp);
|
uintptr_t buf = ((uintptr_t)this) + sizeof(netPlayLoadStateResp) +
|
||||||
|
(numCtrlFrames * sizeof(CtrlData)) + (numCheats * sizeof(CheatData));
|
||||||
return (char*)buf;
|
return (char*)buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue