Added initial framework for netplay on Qt GUI. Still much TODO here.

This commit is contained in:
harry 2024-02-19 11:57:12 -05:00
parent 2f2279f5ff
commit 84c2591d3f
15 changed files with 1587 additions and 18 deletions

View File

@ -40,11 +40,12 @@ if ( ${QT} EQUAL 6 )
set( Qt Qt6 )
find_package( Qt6 REQUIRED COMPONENTS Widgets OpenGL OpenGLWidgets)
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} ${Qt6Help_DEFINITIONS} ${Qt6OpenGLWidgets_DEFINITIONS} )
add_definitions( ${Qt6Widgets_DEFINITIONS} ${Qt6Qml_DEFINITIONS} ${Qt6Network_DEFINITIONS} ${Qt6Help_DEFINITIONS} ${Qt6OpenGLWidgets_DEFINITIONS} )
# add_definitions(${Qt6UiTools_DEFINITIONS}) # Leave ${Qt6UiTools_DEFINITIONS} out as this is causing a build error
include_directories( ${Qt6Widgets_INCLUDE_DIRS} ${Qt6Qml_INCLUDE_DIRS} ${Qt6UiTools_INCLUDE_DIRS} ${Qt6Help_INCLUDE_DIRS} ${Qt6OpenGLWidgets_INCLUDE_DIRS} )
include_directories( ${Qt6Widgets_INCLUDE_DIRS} ${Qt6Qml_INCLUDE_DIRS} ${Qt6UiTools_INCLUDE_DIRS} ${Qt6Network_INCLUDE_DIRS} ${Qt6Help_INCLUDE_DIRS} ${Qt6OpenGLWidgets_INCLUDE_DIRS} )
if (${Qt6Help_FOUND})
message( STATUS "Qt6 Help Module Found")
@ -55,6 +56,13 @@ if ( ${QT} EQUAL 6 )
message( STATUS "Qt6 Help Module Not Found")
endif()
if (${Qt6Network_FOUND})
message( STATUS "Qt6 Network Module Found")
add_definitions( -D__FCEU_QNETWORK_ENABLE__ )
else()
message( STATUS "Qt6 Network Module Not Found")
endif()
if (${Qt6Qml_FOUND})
message( STATUS "Qt6 Qml Module Found")
add_definitions( -D__FCEU_QSCRIPT_ENABLE__ )
@ -73,10 +81,11 @@ else()
set( Qt Qt5 )
find_package( Qt5 REQUIRED COMPONENTS Widgets OpenGL)
find_package( Qt5 COMPONENTS Help QUIET)
find_package( Qt5 COMPONENTS Network)
find_package( Qt5 COMPONENTS Qml)
find_package( Qt5 COMPONENTS UiTools)
add_definitions( ${Qt5Widgets_DEFINITIONS} ${Qt5Qml_DEFINITIONS} ${Qt5UiTools_DEFINITIONS} ${Qt5Help_DEFINITIONS} )
include_directories( ${Qt5Widgets_INCLUDE_DIRS} ${Qt5Qml_INCLUDE_DIRS} ${Qt5UiTools_INCLUDE_DIRS} ${Qt5Help_INCLUDE_DIRS} )
add_definitions( ${Qt5Widgets_DEFINITIONS} ${Qt5Qml_DEFINITIONS} ${Qt5UiTools_DEFINITIONS} ${Qt5Network_DEFINITIONS} ${Qt5Help_DEFINITIONS} )
include_directories( ${Qt5Widgets_INCLUDE_DIRS} ${Qt5Qml_INCLUDE_DIRS} ${Qt5UiTools_INCLUDE_DIRS} ${Qt5Network_INCLUDE_DIRS} ${Qt5Help_INCLUDE_DIRS} )
if (${Qt5Help_FOUND})
message( STATUS "Qt5 Help Module Found")
@ -87,6 +96,13 @@ else()
message( STATUS "Qt5 Help Module Not Found")
endif()
if (${Qt5Network_FOUND})
message( STATUS "Qt5 Network Module Found")
add_definitions( -D__FCEU_NETWORK_ENABLE__ )
else()
message( STATUS "Qt5 Network Module Not Found")
endif()
if (${Qt5Qml_FOUND})
message( STATUS "Qt5 Qml Module Found")
add_definitions( -D__FCEU_QSCRIPT_ENABLE__ )
@ -661,6 +677,7 @@ set(SRC_DRIVERS_SDL
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/sdl-joystick.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/sdl-throttle.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/unix-netplay.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/NetPlay.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/AviRecord.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/AviRiffViewer.cpp
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/avi/avi-utils.cpp
@ -733,6 +750,7 @@ target_link_libraries( ${APP_NAME}
${${Qt}Help_LIBRARIES}
${${Qt}Qml_LIBRARIES}
${${Qt}UiTools_LIBRARIES}
${${Qt}Network_LIBRARIES}
${${Qt}OpenGL_LIBRARIES}
${${Qt}OpenGLWidgets_LIBRARIES}
${OPENGL_LDFLAGS}

View File

@ -275,6 +275,8 @@ void FCEUI_SetEmulationPaused(int val);
void FCEUI_ToggleEmulationPause();
void FCEUI_PauseForDuration(int secs);
int FCEUI_PauseFramesRemaining();
void FCEUI_SetNetPlayPause(bool value);
bool FCEUI_GetNetPlayPause();
//indicates whether input aids should be drawn (such as crosshairs, etc; usually in fullscreen mode)
bool FCEUD_ShouldDrawInputAids();

View File

@ -107,6 +107,7 @@
#include "Qt/RamSearch.h"
#include "Qt/keyscan.h"
#include "Qt/nes_shm.h"
#include "Qt/NetPlay.h"
#include "Qt/TasEditor/TasEditorWindow.h"
#ifdef __APPLE__
@ -926,13 +927,14 @@ void consoleWin_t::createMainMenu(void)
menubar->setNativeMenuBar( useNativeMenuBar ? true : false );
// Top Level Menu Iterms
fileMenu = menubar->addMenu(tr("&File"));
movieMenu = menubar->addMenu(tr("&Movie"));
optMenu = menubar->addMenu(tr("&Options"));
emuMenu = menubar->addMenu(tr("&Emulation"));
toolsMenu = menubar->addMenu(tr("&Tools"));
debugMenu = menubar->addMenu(tr("&Debug"));
helpMenu = menubar->addMenu(tr("&Help"));
fileMenu = menubar->addMenu(tr("&File"));
movieMenu = menubar->addMenu(tr("&Movie"));
optMenu = menubar->addMenu(tr("&Options"));
emuMenu = menubar->addMenu(tr("&Emulation"));
netPlayMenu = menubar->addMenu(tr("&NetPlay"));
toolsMenu = menubar->addMenu(tr("&Tools"));
debugMenu = menubar->addMenu(tr("&Debug"));
helpMenu = menubar->addMenu(tr("&Help"));
//-----------------------------------------------------------------------
// File
@ -1657,6 +1659,29 @@ void consoleWin_t::createMainMenu(void)
subMenu->addAction(act);
//-----------------------------------------------------------------------
// NetPlay
connect( netPlayMenu, SIGNAL(aboutToShow(void)), this, SLOT(mainMenuOpen(void)) );
connect( netPlayMenu, SIGNAL(aboutToHide(void)), this, SLOT(mainMenuClose(void)) );
// NetPlay -> Host
act = new QAction(tr("&Host"), this);
//act->setShortcut( QKeySequence(tr("Shift+F7")));
act->setStatusTip(tr("Host Game Window"));
connect(act, SIGNAL(triggered()), this, SLOT(openNetPlayHostWindow(void)) );
netPlayMenu->addAction(act);
// NetPlay -> Join
act = new QAction(tr("&Join"), this);
//act->setShortcut( QKeySequence(tr("Shift+F7")));
act->setStatusTip(tr("Join Game Window"));
connect(act, SIGNAL(triggered()), this, SLOT(openNetPlayJoinWindow(void)) );
netPlayMenu->addAction(act);
netPlayMenu->setEnabled(false);
//-----------------------------------------------------------------------
// Tools
@ -3112,6 +3137,28 @@ void consoleWin_t::openPaletteEditorWin(void)
win->show();
}
void consoleWin_t::openNetPlayHostWindow(void)
{
NetPlayHostDialog *win;
//printf("Open NetPlay Host Window\n");
win = new NetPlayHostDialog(this);
win->show();
}
void consoleWin_t::openNetPlayJoinWindow(void)
{
NetPlayJoinDialog *win;
//printf("Open NetPlay Join Window\n");
win = new NetPlayJoinDialog(this);
win->show();
}
void consoleWin_t::openAviRiffViewer(void)
{
AviRiffViewerDialog *win;
@ -4692,6 +4739,8 @@ void consoleWin_t::updatePeriodic(void)
closeRequested = false;
}
NetPlayPeriodicUpdate();
updateCounter++;
#ifdef __FCEU_PROFILER_ENABLE__

View File

@ -193,6 +193,7 @@ class consoleWin_t : public QMainWindow
QMenu *toolsMenu;
QMenu *debugMenu;
QMenu *movieMenu;
QMenu *netPlayMenu;
QMenu *helpMenu;
QMenu *recentRomMenu;
@ -351,6 +352,8 @@ class consoleWin_t : public QMainWindow
void openTimingConfWin(void);
void openStateRecorderConfWin(void);
void openPaletteEditorWin(void);
void openNetPlayHostWindow(void);
void openNetPlayJoinWindow(void);
void openAviRiffViewer(void);
void openTimingStatWin(void);
void openMovieOptWin(void);

1009
src/drivers/Qt/NetPlay.cpp Normal file

File diff suppressed because it is too large Load Diff

275
src/drivers/Qt/NetPlay.h Normal file
View File

@ -0,0 +1,275 @@
// NetPlay.h
//
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <list>
#include <QWidget>
#include <QDialog>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QGridLayout>
#include <QComboBox>
#include <QCheckBox>
#include <QSpinBox>
#include <QPushButton>
#include <QLineEdit>
#include <QLabel>
#include <QFrame>
#include <QGroupBox>
#include <QCloseEvent>
#include <QTcpSocket>
#include <QTcpServer>
#include "utils/mutex.h"
class NetPlayClient;
struct NetPlayFrameInput
{
static constexpr uint32_t ownsData = 0x01;
NetPlayFrameInput(void)
{
flags = 0; frameCounter = 0;
ctrl[0] = ctrl[1] = ctrl[2] = ctrl[3] = 0;
data = nullptr;
}
~NetPlayFrameInput()
{
if (data)
{
if (flags & ownsData)
{
::free(data);
data = nullptr;
}
}
}
uint32_t flags;
uint32_t frameCounter;
uint8_t ctrl[4];
uint8_t *data;
};
class NetPlayServer : public QTcpServer
{
Q_OBJECT
public:
NetPlayServer(QObject *parent = 0);
~NetPlayServer(void);
static NetPlayServer *GetInstance(void){ return instance; };
static int Create(QObject *parent = 0);
bool removeClient(NetPlayClient *client, bool markForDelete = false);
int closeAllConnections(void);
void update(void);
size_t inputAvailable(void)
{
FCEU::autoScopedLock alock(inputMtx);
return input.size();
};
void pushBackInput( NetPlayFrameInput &in )
{
FCEU::autoScopedLock alock(inputMtx);
input.push_back(in);
};
NetPlayFrameInput getNextInput(void)
{
NetPlayFrameInput in;
FCEU::autoScopedLock alock(inputMtx);
if (!input.empty())
{
in = input.front();
input.pop_front();
}
return in;
};
uint32_t inputFrameBack()
{
uint32_t frame = 0;
FCEU::autoScopedLock alock(inputMtx);
if (!input.empty())
{
NetPlayFrameInput &in = input.back();
frame = in.frameCounter;
}
return frame;
}
int sendMsg( NetPlayClient *client, void *msg, size_t msgSize);
int sendRomLoadReq( NetPlayClient *client );
int sendStateSyncReq( NetPlayClient *client );
void setRole(int _role);
bool claimRole(NetPlayClient* client, int _role);
void serverProcessMessage( NetPlayClient *client, void *msgBuf, size_t msgSize );
private:
static NetPlayServer *instance;
void processPendingConnections(void);
std::list <NetPlayClient*> clientList;
std::list <NetPlayFrameInput> input;
FCEU::mutex inputMtx;
int role = -1;
int roleMask = 0;
NetPlayClient* clientPlayer[4] = { nullptr };
public slots:
void newConnectionRdy(void);
};
class NetPlayClient : public QObject
{
Q_OBJECT
public:
NetPlayClient(QObject *parent = 0, bool outGoing = false);
~NetPlayClient(void);
static NetPlayClient *GetInstance(void){ return instance; };
static int Create(QObject *parent = 0);
int connectToHost( const QString host, int port );
bool isConnected(void);
void disconnect();
void setSocket(QTcpSocket *s);
QTcpSocket* getSocket(void){ return sock; };
void update(void);
int readMessages( void (*msgCallback)( void *userData, void *msgBuf, size_t msgSize ), void *userData );
void clientProcessMessage( void *msgBuf, size_t msgSize );
size_t inputAvailable(void)
{
FCEU::autoScopedLock alock(inputMtx);
return !input.empty();
};
void pushBackInput( NetPlayFrameInput &in )
{
FCEU::autoScopedLock alock(inputMtx);
input.push_back(in);
};
NetPlayFrameInput getNextInput(void)
{
NetPlayFrameInput in;
FCEU::autoScopedLock alock(inputMtx);
if (!input.empty())
{
in = input.front();
input.pop_front();
}
return in;
};
uint32_t inputFrameBack()
{
uint32_t frame = 0;
FCEU::autoScopedLock alock(inputMtx);
if (!input.empty())
{
NetPlayFrameInput &in = input.back();
frame = in.frameCounter;
}
return frame;
}
QString userName;
int role;
int state;
unsigned int currentFrame;
private:
int createSocket(void);
static NetPlayClient *instance;
QTcpSocket *sock;
int recvMsgId;
int recvMsgSize;
int recvMsgBytesLeft;
int recvMsgByteIndex;
char *recvMsgBuf;
std::list <NetPlayFrameInput> input;
FCEU::mutex inputMtx;
static constexpr size_t recvMsgBufSize = 2 * 1024 * 1024;
public slots:
void onConnect(void);
void onDisconnect(void);
};
class NetPlayHostDialog : public QDialog
{
Q_OBJECT
public:
NetPlayHostDialog(QWidget *parent = 0);
~NetPlayHostDialog(void);
protected:
void closeEvent(QCloseEvent *event);
QLineEdit *serverNameEntry;
QSpinBox *portEntry;
QComboBox *playerRoleBox;
public slots:
void closeWindow(void);
void onStartClicked(void);
};
class NetPlayJoinDialog : public QDialog
{
Q_OBJECT
public:
NetPlayJoinDialog(QWidget *parent = 0);
~NetPlayJoinDialog(void);
protected:
void closeEvent(QCloseEvent *event);
QLineEdit *hostEntry;
QSpinBox *portEntry;
QComboBox *playerRoleBox;
public slots:
void closeWindow(void);
void onJoinClicked(void);
};
bool NetPlayActive(void);
void NetPlayPeriodicUpdate(void);
bool NetPlaySkipWait(void);
int NetPlayFrameWait(void);
void NetPlayReadInputFrame(uint8_t* joy);

View File

@ -0,0 +1,167 @@
// NetPlayMsgDef.h
#pragma once
#include <string.h>
#include <stdint.h>
#pragma pack(push,4)
enum netPlayMsgType
{
NETPLAY_AUTH_REQ,
NETPLAY_AUTH_RESP,
NETPLAY_LOAD_ROM_REQ,
NETPLAY_SYNC_STATE,
NETPLAY_RUN_FRAME_REQ,
NETPLAY_RUN_FRAME_RESP,
NETPLAY_CLIENT_STATE,
NETPLAY_ERROR_MSG,
};
enum netPlayerId
{
NETPLAY_SPECTATOR = -1,
NETPLAY_PLAYER1,
NETPLAY_PLAYER2,
NETPLAY_PLAYER3,
NETPLAY_PLAYER4
};
static const uint32_t NETPLAY_MAGIC_NUMBER = 0xaa55aa55;
struct netPlayMsgHdr
{
uint32_t magic[2];
uint32_t msgId;
uint32_t msgSize;
netPlayMsgHdr( uint32_t id, uint32_t size = sizeof(netPlayMsgHdr) )
{
magic[0] = NETPLAY_MAGIC_NUMBER;
magic[1] = NETPLAY_MAGIC_NUMBER;
msgId = id; msgSize = size;
}
};
struct netPlayAuthReq
{
netPlayMsgHdr hdr;
uint8_t ctrlMask;
netPlayAuthReq(void)
: hdr(NETPLAY_AUTH_REQ, sizeof(netPlayAuthReq)), ctrlMask(0)
{
}
};
struct netPlayAuthResp
{
netPlayMsgHdr hdr;
char playerId;
char pswd[128];
netPlayAuthResp(void)
: hdr(NETPLAY_AUTH_RESP, sizeof(netPlayAuthResp)), playerId(NETPLAY_SPECTATOR)
{
memset(pswd, 0, sizeof(pswd));
}
};
template <size_t N=8>
struct netPlayErrorMsg
{
netPlayMsgHdr hdr;
char data[N];
netPlayErrorMsg(void)
: hdr(NETPLAY_ERROR_MSG, sizeof(netPlayErrorMsg))
{
}
char *getMsgBuffer()
{
return &data[0];
}
int printf(const char* format, ...)
{
int retval;
va_list args;
va_start(args, format);
retval = ::vsnprintf(data, sizeof(data), format, args);
va_end(args);
hdr.msgSize = sizeof(netPlayMsgHdr) + strlen(data);
return retval;
}
};
struct netPlayLoadRomReq
{
netPlayMsgHdr hdr;
uint32_t fileSize;
char fileName[256];
netPlayLoadRomReq(void)
: hdr(NETPLAY_LOAD_ROM_REQ, sizeof(netPlayLoadRomReq)), fileSize(0)
{
memset(fileName, 0, sizeof(fileName));
}
};
struct netPlayRunFrameReq
{
netPlayMsgHdr hdr;
uint32_t flags;
uint32_t frameNum;
uint8_t ctrlState[4];
netPlayRunFrameReq(void)
: hdr(NETPLAY_RUN_FRAME_REQ, sizeof(netPlayRunFrameReq)), flags(0), frameNum(0)
{
memset( ctrlState, 0, sizeof(ctrlState) );
}
};
struct netPlayRunFrameResp
{
netPlayMsgHdr hdr;
uint32_t flags;
uint32_t frameNum;
uint32_t frameRun;
uint8_t ctrlState[4];
netPlayRunFrameResp(void)
: hdr(NETPLAY_RUN_FRAME_RESP, sizeof(netPlayRunFrameResp)), flags(0), frameNum(0), frameRun(0)
{
memset( ctrlState, 0, sizeof(ctrlState) );
}
};
struct netPlayClientState
{
netPlayMsgHdr hdr;
uint32_t flags;
uint32_t frameRdy;
uint32_t frameRun;
uint8_t ctrlState[4];
netPlayClientState(void)
: hdr(NETPLAY_CLIENT_STATE, sizeof(netPlayClientState)), flags(0), frameRdy(0), frameRun(0)
{
memset( ctrlState, 0, sizeof(ctrlState) );
}
};
#pragma pack(pop)

View File

@ -77,7 +77,6 @@
// File Base Name from Core
extern char FileBase[];
extern uint8 joy[4];
extern uint32 GetGamepadPressedImmediate();
static thread_local FCEU::JSEngine* currentEngine = nullptr;

View File

@ -37,6 +37,7 @@
#include "Qt/sdl-video.h"
#include "Qt/nes_shm.h"
#include "Qt/unix-netplay.h"
#include "Qt/NetPlay.h"
#include "Qt/AviRecord.h"
#include "Qt/HexEditor.h"
#include "Qt/CheatsConf.h"
@ -1475,6 +1476,23 @@ int fceuWrapperUpdate( void )
}
mutexLockFail = false;
emulatorHasMutex = 1;
// For netplay, set pause if we do not have input ready for all players
if (NetPlayActive())
{
if (NetPlayFrameWait())
{
FCEUI_SetNetPlayPause(true);
}
else
{
FCEUI_SetNetPlayPause(false);
}
}
else
{
FCEUI_SetNetPlayPause(false);
}
if ( GameInfo )
{

View File

@ -144,6 +144,7 @@ void UpdateInput(Config *config);
const char* ButtonName(const ButtConfig* bc);
void pollEventsSDL();
uint32 GetGamepadPressedImmediate(void);
int getInputSelection( int port, int *cur, int *usr );
int saveInputSettingsToFile( const char *fileBase = NULL );
int loadInputSettingsFromFile( const char *filename = NULL );

View File

@ -21,6 +21,7 @@
/// \brief Handles emulation speed throttling using the SDL timing functions.
#include "Qt/sdl.h"
#include "Qt/NetPlay.h"
#include "Qt/throttle.h"
#include "utils/timeStamp.h"
@ -367,7 +368,7 @@ SpeedThrottle(void)
{
bool isEmuPaused = FCEUI_EmulationPaused() ? true : false;
bool noWaitActive = (NoWaiting & 0x01) ? true : false;
bool turboActive = (turbo || noWaitActive);
bool turboActive = (turbo || noWaitActive || NetPlaySkipWait());
// If Emulator is paused, don't waste CPU cycles spinning on nothing.
if ( !isEmuPaused && ((g_fpsScale >= 32) || turboActive) )

View File

@ -806,7 +806,7 @@ void FCEUI_Emulate(uint8 **pXBuf, int32 **SoundBuf, int32 *SoundBufSize, int ski
RefreshThrottleFPS();
}
#endif
if (EmulationPaused & (EMULATIONPAUSED_PAUSED | EMULATIONPAUSED_TIMER) )
if (EmulationPaused & (EMULATIONPAUSED_PAUSED | EMULATIONPAUSED_TIMER | EMULATIONPAUSED_NETPLAY) )
{
// emulator is paused
memcpy(XBuf, XBackBuf, 256*256);
@ -1309,6 +1309,23 @@ int FCEUI_PauseFramesRemaining(void)
return (EmulationPaused & EMULATIONPAUSED_TIMER) ? pauseTimer : 0;
}
bool FCEUI_GetNetPlayPause()
{
return (EmulationPaused & EMULATIONPAUSED_NETPLAY) ? true : false;
}
void FCEUI_SetNetPlayPause(bool value)
{
if (value)
{
EmulationPaused |= EMULATIONPAUSED_NETPLAY;
}
else
{
EmulationPaused &= ~EMULATIONPAUSED_NETPLAY;
}
}
static int AutosaveCounter = 0;
void UpdateAutosave(void) {

View File

@ -184,6 +184,7 @@ extern uint8 vsdip;
#define EMULATIONPAUSED_PAUSED 0x01
#define EMULATIONPAUSED_TIMER 0x02
#define EMULATIONPAUSED_FA 0x04
#define EMULATIONPAUSED_NETPLAY 0x08
#define FRAMEADVANCE_DELAY_DEFAULT 10
#define NES_HEADER_SIZE 16

View File

@ -274,7 +274,6 @@ static void UpdateGP(int w, void *data, int arg)
joy[3]= FCEU_JSReadJoypad(3,joy[3]);
#endif
}
}
static void LogGP(int w, MovieRecord* mr)
@ -435,6 +434,10 @@ void FCEU_DrawInput(uint8 *buf)
portFC.driver->Draw(buf,portFC.attrib);
}
#ifdef __FCEU_QNETWORK_ENABLE__
extern bool NetPlayActive(void);
void NetPlayReadInputFrame(uint8_t* joy);
#endif
void FCEU_UpdateInput(void)
{
@ -452,6 +455,12 @@ void FCEU_UpdateInput(void)
if (coinon2) coinon2--;
if (service) service--;
}
#ifdef __FCEU_QNETWORK_ENABLE__
if (NetPlayActive())
{
NetPlayReadInputFrame(joy);
}
#endif
if(FCEUnetplay)
NetplayUpdate(joy);

View File

@ -61,15 +61,15 @@
#endif
#define FCEU_VERSION_MAJOR 2
#define FCEU_VERSION_MINOR 6
#define FCEU_VERSION_PATCH 6
#define FCEU_VERSION_MINOR 7
#define FCEU_VERSION_PATCH 0
#define FCEU_VERSION_NUMERIC ( (FCEU_VERSION_MAJOR*10000) + (FCEU_VERSION_MINOR*100) + (FCEU_VERSION_PATCH) )
#define FCEU_VERSION_MAJOR_DECODE(x) ( (x / 10000) )
#define FCEU_VERSION_MINOR_DECODE(x) ( (x / 100) % 100 )
#define FCEU_VERSION_PATCH_DECODE(x) (x % 100)
#define FCEU_VERSION_STRING "2.6.6" FCEU_SUBVERSION_STRING FCEU_FEATURE_STRING FCEU_COMPILER
#define FCEU_VERSION_STRING "2.7.0" FCEU_SUBVERSION_STRING FCEU_FEATURE_STRING FCEU_COMPILER
#define FCEU_NAME_AND_VERSION FCEU_NAME " " FCEU_VERSION_STRING
#endif