Added initial framework for netplay on Qt GUI. Still much TODO here.
This commit is contained in:
parent
2f2279f5ff
commit
84c2591d3f
|
@ -40,11 +40,12 @@ if ( ${QT} EQUAL 6 )
|
||||||
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 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} ${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
|
# 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})
|
if (${Qt6Help_FOUND})
|
||||||
message( STATUS "Qt6 Help Module Found")
|
message( STATUS "Qt6 Help Module Found")
|
||||||
|
@ -55,6 +56,13 @@ if ( ${QT} EQUAL 6 )
|
||||||
message( STATUS "Qt6 Help Module Not Found")
|
message( STATUS "Qt6 Help Module Not Found")
|
||||||
endif()
|
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})
|
if (${Qt6Qml_FOUND})
|
||||||
message( STATUS "Qt6 Qml Module Found")
|
message( STATUS "Qt6 Qml Module Found")
|
||||||
add_definitions( -D__FCEU_QSCRIPT_ENABLE__ )
|
add_definitions( -D__FCEU_QSCRIPT_ENABLE__ )
|
||||||
|
@ -73,10 +81,11 @@ else()
|
||||||
set( Qt Qt5 )
|
set( Qt Qt5 )
|
||||||
find_package( Qt5 REQUIRED COMPONENTS Widgets OpenGL)
|
find_package( Qt5 REQUIRED COMPONENTS Widgets OpenGL)
|
||||||
find_package( Qt5 COMPONENTS Help QUIET)
|
find_package( Qt5 COMPONENTS Help QUIET)
|
||||||
|
find_package( Qt5 COMPONENTS Network)
|
||||||
find_package( Qt5 COMPONENTS Qml)
|
find_package( Qt5 COMPONENTS Qml)
|
||||||
find_package( Qt5 COMPONENTS UiTools)
|
find_package( Qt5 COMPONENTS UiTools)
|
||||||
add_definitions( ${Qt5Widgets_DEFINITIONS} ${Qt5Qml_DEFINITIONS} ${Qt5UiTools_DEFINITIONS} ${Qt5Help_DEFINITIONS} )
|
add_definitions( ${Qt5Widgets_DEFINITIONS} ${Qt5Qml_DEFINITIONS} ${Qt5UiTools_DEFINITIONS} ${Qt5Network_DEFINITIONS} ${Qt5Help_DEFINITIONS} )
|
||||||
include_directories( ${Qt5Widgets_INCLUDE_DIRS} ${Qt5Qml_INCLUDE_DIRS} ${Qt5UiTools_INCLUDE_DIRS} ${Qt5Help_INCLUDE_DIRS} )
|
include_directories( ${Qt5Widgets_INCLUDE_DIRS} ${Qt5Qml_INCLUDE_DIRS} ${Qt5UiTools_INCLUDE_DIRS} ${Qt5Network_INCLUDE_DIRS} ${Qt5Help_INCLUDE_DIRS} )
|
||||||
|
|
||||||
if (${Qt5Help_FOUND})
|
if (${Qt5Help_FOUND})
|
||||||
message( STATUS "Qt5 Help Module Found")
|
message( STATUS "Qt5 Help Module Found")
|
||||||
|
@ -87,6 +96,13 @@ else()
|
||||||
message( STATUS "Qt5 Help Module Not Found")
|
message( STATUS "Qt5 Help Module Not Found")
|
||||||
endif()
|
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})
|
if (${Qt5Qml_FOUND})
|
||||||
message( STATUS "Qt5 Qml Module Found")
|
message( STATUS "Qt5 Qml Module Found")
|
||||||
add_definitions( -D__FCEU_QSCRIPT_ENABLE__ )
|
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-joystick.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/sdl-throttle.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/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/AviRecord.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/AviRiffViewer.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/AviRiffViewer.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/avi/avi-utils.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/avi/avi-utils.cpp
|
||||||
|
@ -733,6 +750,7 @@ target_link_libraries( ${APP_NAME}
|
||||||
${${Qt}Help_LIBRARIES}
|
${${Qt}Help_LIBRARIES}
|
||||||
${${Qt}Qml_LIBRARIES}
|
${${Qt}Qml_LIBRARIES}
|
||||||
${${Qt}UiTools_LIBRARIES}
|
${${Qt}UiTools_LIBRARIES}
|
||||||
|
${${Qt}Network_LIBRARIES}
|
||||||
${${Qt}OpenGL_LIBRARIES}
|
${${Qt}OpenGL_LIBRARIES}
|
||||||
${${Qt}OpenGLWidgets_LIBRARIES}
|
${${Qt}OpenGLWidgets_LIBRARIES}
|
||||||
${OPENGL_LDFLAGS}
|
${OPENGL_LDFLAGS}
|
||||||
|
|
|
@ -275,6 +275,8 @@ void FCEUI_SetEmulationPaused(int val);
|
||||||
void FCEUI_ToggleEmulationPause();
|
void FCEUI_ToggleEmulationPause();
|
||||||
void FCEUI_PauseForDuration(int secs);
|
void FCEUI_PauseForDuration(int secs);
|
||||||
int FCEUI_PauseFramesRemaining();
|
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)
|
//indicates whether input aids should be drawn (such as crosshairs, etc; usually in fullscreen mode)
|
||||||
bool FCEUD_ShouldDrawInputAids();
|
bool FCEUD_ShouldDrawInputAids();
|
||||||
|
|
|
@ -107,6 +107,7 @@
|
||||||
#include "Qt/RamSearch.h"
|
#include "Qt/RamSearch.h"
|
||||||
#include "Qt/keyscan.h"
|
#include "Qt/keyscan.h"
|
||||||
#include "Qt/nes_shm.h"
|
#include "Qt/nes_shm.h"
|
||||||
|
#include "Qt/NetPlay.h"
|
||||||
#include "Qt/TasEditor/TasEditorWindow.h"
|
#include "Qt/TasEditor/TasEditorWindow.h"
|
||||||
|
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
|
@ -926,13 +927,14 @@ void consoleWin_t::createMainMenu(void)
|
||||||
menubar->setNativeMenuBar( useNativeMenuBar ? true : false );
|
menubar->setNativeMenuBar( useNativeMenuBar ? true : false );
|
||||||
|
|
||||||
// Top Level Menu Iterms
|
// Top Level Menu Iterms
|
||||||
fileMenu = menubar->addMenu(tr("&File"));
|
fileMenu = menubar->addMenu(tr("&File"));
|
||||||
movieMenu = menubar->addMenu(tr("&Movie"));
|
movieMenu = menubar->addMenu(tr("&Movie"));
|
||||||
optMenu = menubar->addMenu(tr("&Options"));
|
optMenu = menubar->addMenu(tr("&Options"));
|
||||||
emuMenu = menubar->addMenu(tr("&Emulation"));
|
emuMenu = menubar->addMenu(tr("&Emulation"));
|
||||||
toolsMenu = menubar->addMenu(tr("&Tools"));
|
netPlayMenu = menubar->addMenu(tr("&NetPlay"));
|
||||||
debugMenu = menubar->addMenu(tr("&Debug"));
|
toolsMenu = menubar->addMenu(tr("&Tools"));
|
||||||
helpMenu = menubar->addMenu(tr("&Help"));
|
debugMenu = menubar->addMenu(tr("&Debug"));
|
||||||
|
helpMenu = menubar->addMenu(tr("&Help"));
|
||||||
|
|
||||||
//-----------------------------------------------------------------------
|
//-----------------------------------------------------------------------
|
||||||
// File
|
// File
|
||||||
|
@ -1657,6 +1659,29 @@ void consoleWin_t::createMainMenu(void)
|
||||||
|
|
||||||
subMenu->addAction(act);
|
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
|
// Tools
|
||||||
|
|
||||||
|
@ -3112,6 +3137,28 @@ void consoleWin_t::openPaletteEditorWin(void)
|
||||||
win->show();
|
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)
|
void consoleWin_t::openAviRiffViewer(void)
|
||||||
{
|
{
|
||||||
AviRiffViewerDialog *win;
|
AviRiffViewerDialog *win;
|
||||||
|
@ -4692,6 +4739,8 @@ void consoleWin_t::updatePeriodic(void)
|
||||||
closeRequested = false;
|
closeRequested = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NetPlayPeriodicUpdate();
|
||||||
|
|
||||||
updateCounter++;
|
updateCounter++;
|
||||||
|
|
||||||
#ifdef __FCEU_PROFILER_ENABLE__
|
#ifdef __FCEU_PROFILER_ENABLE__
|
||||||
|
|
|
@ -193,6 +193,7 @@ class consoleWin_t : public QMainWindow
|
||||||
QMenu *toolsMenu;
|
QMenu *toolsMenu;
|
||||||
QMenu *debugMenu;
|
QMenu *debugMenu;
|
||||||
QMenu *movieMenu;
|
QMenu *movieMenu;
|
||||||
|
QMenu *netPlayMenu;
|
||||||
QMenu *helpMenu;
|
QMenu *helpMenu;
|
||||||
QMenu *recentRomMenu;
|
QMenu *recentRomMenu;
|
||||||
|
|
||||||
|
@ -351,6 +352,8 @@ class consoleWin_t : public QMainWindow
|
||||||
void openTimingConfWin(void);
|
void openTimingConfWin(void);
|
||||||
void openStateRecorderConfWin(void);
|
void openStateRecorderConfWin(void);
|
||||||
void openPaletteEditorWin(void);
|
void openPaletteEditorWin(void);
|
||||||
|
void openNetPlayHostWindow(void);
|
||||||
|
void openNetPlayJoinWindow(void);
|
||||||
void openAviRiffViewer(void);
|
void openAviRiffViewer(void);
|
||||||
void openTimingStatWin(void);
|
void openTimingStatWin(void);
|
||||||
void openMovieOptWin(void);
|
void openMovieOptWin(void);
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -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);
|
|
@ -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)
|
|
@ -77,7 +77,6 @@
|
||||||
// File Base Name from Core
|
// File Base Name from Core
|
||||||
extern char FileBase[];
|
extern char FileBase[];
|
||||||
extern uint8 joy[4];
|
extern uint8 joy[4];
|
||||||
extern uint32 GetGamepadPressedImmediate();
|
|
||||||
|
|
||||||
static thread_local FCEU::JSEngine* currentEngine = nullptr;
|
static thread_local FCEU::JSEngine* currentEngine = nullptr;
|
||||||
|
|
||||||
|
|
|
@ -37,6 +37,7 @@
|
||||||
#include "Qt/sdl-video.h"
|
#include "Qt/sdl-video.h"
|
||||||
#include "Qt/nes_shm.h"
|
#include "Qt/nes_shm.h"
|
||||||
#include "Qt/unix-netplay.h"
|
#include "Qt/unix-netplay.h"
|
||||||
|
#include "Qt/NetPlay.h"
|
||||||
#include "Qt/AviRecord.h"
|
#include "Qt/AviRecord.h"
|
||||||
#include "Qt/HexEditor.h"
|
#include "Qt/HexEditor.h"
|
||||||
#include "Qt/CheatsConf.h"
|
#include "Qt/CheatsConf.h"
|
||||||
|
@ -1476,6 +1477,23 @@ int fceuWrapperUpdate( void )
|
||||||
mutexLockFail = false;
|
mutexLockFail = false;
|
||||||
emulatorHasMutex = 1;
|
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 )
|
if ( GameInfo )
|
||||||
{
|
{
|
||||||
#ifdef __FCEU_QSCRIPT_ENABLE__
|
#ifdef __FCEU_QSCRIPT_ENABLE__
|
||||||
|
|
|
@ -144,6 +144,7 @@ void UpdateInput(Config *config);
|
||||||
const char* ButtonName(const ButtConfig* bc);
|
const char* ButtonName(const ButtConfig* bc);
|
||||||
|
|
||||||
void pollEventsSDL();
|
void pollEventsSDL();
|
||||||
|
uint32 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 );
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
/// \brief Handles emulation speed throttling using the SDL timing functions.
|
/// \brief Handles emulation speed throttling using the SDL timing functions.
|
||||||
|
|
||||||
#include "Qt/sdl.h"
|
#include "Qt/sdl.h"
|
||||||
|
#include "Qt/NetPlay.h"
|
||||||
#include "Qt/throttle.h"
|
#include "Qt/throttle.h"
|
||||||
#include "utils/timeStamp.h"
|
#include "utils/timeStamp.h"
|
||||||
|
|
||||||
|
@ -367,7 +368,7 @@ SpeedThrottle(void)
|
||||||
{
|
{
|
||||||
bool isEmuPaused = FCEUI_EmulationPaused() ? true : false;
|
bool isEmuPaused = FCEUI_EmulationPaused() ? true : false;
|
||||||
bool noWaitActive = (NoWaiting & 0x01) ? 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 Emulator is paused, don't waste CPU cycles spinning on nothing.
|
||||||
if ( !isEmuPaused && ((g_fpsScale >= 32) || turboActive) )
|
if ( !isEmuPaused && ((g_fpsScale >= 32) || turboActive) )
|
||||||
|
|
19
src/fceu.cpp
19
src/fceu.cpp
|
@ -806,7 +806,7 @@ void FCEUI_Emulate(uint8 **pXBuf, int32 **SoundBuf, int32 *SoundBufSize, int ski
|
||||||
RefreshThrottleFPS();
|
RefreshThrottleFPS();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (EmulationPaused & (EMULATIONPAUSED_PAUSED | EMULATIONPAUSED_TIMER) )
|
if (EmulationPaused & (EMULATIONPAUSED_PAUSED | EMULATIONPAUSED_TIMER | EMULATIONPAUSED_NETPLAY) )
|
||||||
{
|
{
|
||||||
// emulator is paused
|
// emulator is paused
|
||||||
memcpy(XBuf, XBackBuf, 256*256);
|
memcpy(XBuf, XBackBuf, 256*256);
|
||||||
|
@ -1309,6 +1309,23 @@ int FCEUI_PauseFramesRemaining(void)
|
||||||
return (EmulationPaused & EMULATIONPAUSED_TIMER) ? pauseTimer : 0;
|
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;
|
static int AutosaveCounter = 0;
|
||||||
|
|
||||||
void UpdateAutosave(void) {
|
void UpdateAutosave(void) {
|
||||||
|
|
|
@ -184,6 +184,7 @@ extern uint8 vsdip;
|
||||||
#define EMULATIONPAUSED_PAUSED 0x01
|
#define EMULATIONPAUSED_PAUSED 0x01
|
||||||
#define EMULATIONPAUSED_TIMER 0x02
|
#define EMULATIONPAUSED_TIMER 0x02
|
||||||
#define EMULATIONPAUSED_FA 0x04
|
#define EMULATIONPAUSED_FA 0x04
|
||||||
|
#define EMULATIONPAUSED_NETPLAY 0x08
|
||||||
|
|
||||||
#define FRAMEADVANCE_DELAY_DEFAULT 10
|
#define FRAMEADVANCE_DELAY_DEFAULT 10
|
||||||
#define NES_HEADER_SIZE 16
|
#define NES_HEADER_SIZE 16
|
||||||
|
|
|
@ -274,7 +274,6 @@ static void UpdateGP(int w, void *data, int arg)
|
||||||
joy[3]= FCEU_JSReadJoypad(3,joy[3]);
|
joy[3]= FCEU_JSReadJoypad(3,joy[3]);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void LogGP(int w, MovieRecord* mr)
|
static void LogGP(int w, MovieRecord* mr)
|
||||||
|
@ -435,6 +434,10 @@ void FCEU_DrawInput(uint8 *buf)
|
||||||
portFC.driver->Draw(buf,portFC.attrib);
|
portFC.driver->Draw(buf,portFC.attrib);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef __FCEU_QNETWORK_ENABLE__
|
||||||
|
extern bool NetPlayActive(void);
|
||||||
|
void NetPlayReadInputFrame(uint8_t* joy);
|
||||||
|
#endif
|
||||||
|
|
||||||
void FCEU_UpdateInput(void)
|
void FCEU_UpdateInput(void)
|
||||||
{
|
{
|
||||||
|
@ -452,6 +455,12 @@ void FCEU_UpdateInput(void)
|
||||||
if (coinon2) coinon2--;
|
if (coinon2) coinon2--;
|
||||||
if (service) service--;
|
if (service) service--;
|
||||||
}
|
}
|
||||||
|
#ifdef __FCEU_QNETWORK_ENABLE__
|
||||||
|
if (NetPlayActive())
|
||||||
|
{
|
||||||
|
NetPlayReadInputFrame(joy);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if(FCEUnetplay)
|
if(FCEUnetplay)
|
||||||
NetplayUpdate(joy);
|
NetplayUpdate(joy);
|
||||||
|
|
|
@ -61,15 +61,15 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define FCEU_VERSION_MAJOR 2
|
#define FCEU_VERSION_MAJOR 2
|
||||||
#define FCEU_VERSION_MINOR 6
|
#define FCEU_VERSION_MINOR 7
|
||||||
#define FCEU_VERSION_PATCH 6
|
#define FCEU_VERSION_PATCH 0
|
||||||
|
|
||||||
#define FCEU_VERSION_NUMERIC ( (FCEU_VERSION_MAJOR*10000) + (FCEU_VERSION_MINOR*100) + (FCEU_VERSION_PATCH) )
|
#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_MAJOR_DECODE(x) ( (x / 10000) )
|
||||||
#define FCEU_VERSION_MINOR_DECODE(x) ( (x / 100) % 100 )
|
#define FCEU_VERSION_MINOR_DECODE(x) ( (x / 100) % 100 )
|
||||||
#define FCEU_VERSION_PATCH_DECODE(x) (x % 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
|
#define FCEU_NAME_AND_VERSION FCEU_NAME " " FCEU_VERSION_STRING
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue