Added emulator save state JS interface.
This commit is contained in:
parent
2f2482e950
commit
8ebb560d1c
|
@ -44,6 +44,7 @@
|
|||
#include "../../video.h"
|
||||
#include "../../x6502.h"
|
||||
#include "../../debug.h"
|
||||
#include "../../state.h"
|
||||
#include "../../ppu.h"
|
||||
|
||||
#include "common/os_utils.h"
|
||||
|
@ -83,6 +84,8 @@ ColorScriptObject::ColorScriptObject(int r, int g, int b)
|
|||
{
|
||||
numInstances++;
|
||||
//printf("ColorScriptObject(r,g,b) %p Constructor: %i\n", this, numInstances);
|
||||
|
||||
moveToThread(QApplication::instance()->thread());
|
||||
}
|
||||
//----------------------------------------------------
|
||||
ColorScriptObject::~ColorScriptObject()
|
||||
|
@ -91,6 +94,177 @@ ColorScriptObject::~ColorScriptObject()
|
|||
//printf("ColorScriptObject %p Destructor: %i\n", this, numInstances);
|
||||
}
|
||||
//----------------------------------------------------
|
||||
//---- EMU State Object
|
||||
//----------------------------------------------------
|
||||
int EmuStateScriptObject::numInstances = 0;
|
||||
|
||||
//----------------------------------------------------
|
||||
EmuStateScriptObject::EmuStateScriptObject(const QJSValue& jsArg1, const QJSValue& jsArg2)
|
||||
{
|
||||
numInstances++;
|
||||
//printf("EmuStateScriptObject %p JS Constructor: %i\n", this, numInstances);
|
||||
|
||||
moveToThread(QApplication::instance()->thread());
|
||||
QJSValueList args = { jsArg1, jsArg2 };
|
||||
|
||||
for (auto& jsVal : args)
|
||||
{
|
||||
if (jsVal.isObject())
|
||||
{
|
||||
//printf("EmuStateScriptObject %p JS Constructor(Obj): %i\n", this, numInstances);
|
||||
auto obj = qobject_cast<EmuStateScriptObject*>(jsVal.toQObject());
|
||||
|
||||
if (obj != nullptr)
|
||||
{
|
||||
*this = *obj;
|
||||
}
|
||||
}
|
||||
else if (jsVal.isNumber())
|
||||
{
|
||||
//printf("EmuStateScriptObject %p JS Constructor(int): %i\n", this, numInstances);
|
||||
setSlot(jsVal.toInt());
|
||||
|
||||
if (slot >= 0)
|
||||
{
|
||||
loadFromFile(filename);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------
|
||||
EmuStateScriptObject::~EmuStateScriptObject()
|
||||
{
|
||||
if (data != nullptr)
|
||||
{
|
||||
if (persist)
|
||||
{
|
||||
saveToFile(filename);
|
||||
}
|
||||
delete data;
|
||||
data = nullptr;
|
||||
}
|
||||
numInstances--;
|
||||
//printf("EmuStateScriptObject %p Destructor: %i\n", this, numInstances);
|
||||
}
|
||||
//----------------------------------------------------
|
||||
EmuStateScriptObject& EmuStateScriptObject::operator= (const EmuStateScriptObject& obj)
|
||||
{
|
||||
setSlot( obj.slot );
|
||||
persist = obj.persist;
|
||||
compression = obj.compression;
|
||||
filename = obj.filename;
|
||||
|
||||
//printf("EmuStateScriptObject Copy Assignment: %p\n", this);
|
||||
|
||||
if (obj.data != nullptr)
|
||||
{
|
||||
data = new EMUFILE_MEMORY(obj.data->size());
|
||||
memcpy( data->buf(), obj.data->buf(), obj.data->size());
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
//----------------------------------------------------
|
||||
void EmuStateScriptObject::setSlot(int value)
|
||||
{
|
||||
slot = value;
|
||||
|
||||
if (slot >= 0)
|
||||
{
|
||||
slot = slot % 10;
|
||||
|
||||
std::string fileString = FCEU_MakeFName(FCEUMKF_STATE, slot, 0);
|
||||
|
||||
filename = QString::fromStdString(fileString);
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------
|
||||
bool EmuStateScriptObject::save()
|
||||
{
|
||||
if (data != nullptr)
|
||||
{
|
||||
delete data;
|
||||
data = nullptr;
|
||||
}
|
||||
data = new EMUFILE_MEMORY();
|
||||
|
||||
FCEU_WRAPPER_LOCK();
|
||||
FCEUSS_SaveMS( data, compression);
|
||||
data->fseek(0,SEEK_SET);
|
||||
FCEU_WRAPPER_UNLOCK();
|
||||
|
||||
if (persist)
|
||||
{
|
||||
saveToFile(filename);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//----------------------------------------------------
|
||||
bool EmuStateScriptObject::load()
|
||||
{
|
||||
bool loaded = false;
|
||||
if (data != nullptr)
|
||||
{
|
||||
FCEU_WRAPPER_LOCK();
|
||||
if (FCEUSS_LoadFP( data, SSLOADPARAM_NOBACKUP))
|
||||
{
|
||||
data->fseek(0,SEEK_SET);
|
||||
loaded = true;
|
||||
}
|
||||
FCEU_WRAPPER_UNLOCK();
|
||||
}
|
||||
return loaded;
|
||||
}
|
||||
//----------------------------------------------------
|
||||
bool EmuStateScriptObject::saveToFile(const QString& filepath)
|
||||
{
|
||||
if (filepath.isEmpty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (data == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
FILE* outf = fopen(filepath.toLocal8Bit().data(),"wb");
|
||||
if (outf == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
fwrite( data->buf(), 1, data->size(), outf);
|
||||
fclose(outf);
|
||||
return true;
|
||||
}
|
||||
//----------------------------------------------------
|
||||
bool EmuStateScriptObject::loadFromFile(const QString& filepath)
|
||||
{
|
||||
if (filepath.isEmpty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (data != nullptr)
|
||||
{
|
||||
delete data;
|
||||
data = nullptr;
|
||||
}
|
||||
FILE* inf = fopen(filepath.toLocal8Bit().data(),"rb");
|
||||
if (inf == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
fseek(inf,0,SEEK_END);
|
||||
long int len = ftell(inf);
|
||||
fseek(inf,0,SEEK_SET);
|
||||
data = new EMUFILE_MEMORY(len);
|
||||
if ( fread(data->buf(),1,len,inf) != static_cast<size_t>(len) )
|
||||
{
|
||||
FCEU_printf("Warning: JS EmuState::loadFromFile failed to load full buffer.\n");
|
||||
delete data;
|
||||
data = nullptr;
|
||||
}
|
||||
fclose(inf);
|
||||
return true;
|
||||
}
|
||||
//----------------------------------------------------
|
||||
//---- EMU Script Object
|
||||
//----------------------------------------------------
|
||||
EmuScriptObject::EmuScriptObject(QObject* parent)
|
||||
|
@ -361,8 +535,6 @@ QJSValue EmuScriptObject::getScreenPixel(int x, int y, bool useBackup)
|
|||
|
||||
pixelObj->setPalette(p);
|
||||
|
||||
pixelObj->moveToThread(QApplication::instance()->thread());
|
||||
|
||||
QJSValue jsVal = engine->newQObject(pixelObj);
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
|
||||
|
@ -372,6 +544,22 @@ QJSValue EmuScriptObject::getScreenPixel(int x, int y, bool useBackup)
|
|||
return jsVal;
|
||||
}
|
||||
//----------------------------------------------------
|
||||
QJSValue EmuScriptObject::createState(int slot)
|
||||
{
|
||||
QJSValue jsVal;
|
||||
EmuStateScriptObject* emuStateObj = new EmuStateScriptObject(slot);
|
||||
|
||||
if (emuStateObj != nullptr)
|
||||
{
|
||||
jsVal = engine->newQObject(emuStateObj);
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
|
||||
QJSEngine::setObjectOwnership( emuStateObj, QJSEngine::JavaScriptOwnership);
|
||||
#endif
|
||||
}
|
||||
return jsVal;
|
||||
}
|
||||
//----------------------------------------------------
|
||||
//---- ROM Script Object
|
||||
//----------------------------------------------------
|
||||
//----------------------------------------------------
|
||||
|
@ -1077,8 +1265,11 @@ int QtScriptInstance::initEngine()
|
|||
engine->globalObject().setProperty("gui", guiObject);
|
||||
|
||||
// Class Type Definitions for Script Use
|
||||
QJSValue jsMetaObject = engine->newQMetaObject(&JS::ColorScriptObject::staticMetaObject);
|
||||
engine->globalObject().setProperty("Color", jsMetaObject);
|
||||
QJSValue jsColorMetaObject = engine->newQMetaObject(&JS::ColorScriptObject::staticMetaObject);
|
||||
engine->globalObject().setProperty("Color", jsColorMetaObject);
|
||||
|
||||
QJSValue jsEmuStateMetaObject = engine->newQMetaObject(&JS::EmuStateScriptObject::staticMetaObject);
|
||||
engine->globalObject().setProperty("EmuState", jsEmuStateMetaObject);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -65,6 +65,43 @@ public slots:
|
|||
Q_INVOKABLE void setPalette(int p){ _palette = p; }
|
||||
};
|
||||
|
||||
class EmuStateScriptObject: public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
Q_INVOKABLE EmuStateScriptObject(const QJSValue& jsArg1 = QJSValue(), const QJSValue& jsArg2 = QJSValue());
|
||||
~EmuStateScriptObject();
|
||||
|
||||
Q_PROPERTY(bool persist READ isPersistent WRITE setPersistent)
|
||||
Q_PROPERTY(int slot READ getSlot WRITE setSlot)
|
||||
Q_PROPERTY(int compressionLevel READ getCompressionLevel WRITE setCompressionLevel)
|
||||
|
||||
EmuStateScriptObject& operator= (const EmuStateScriptObject& obj);
|
||||
|
||||
private:
|
||||
QString filename;
|
||||
EMUFILE_MEMORY *data = nullptr;
|
||||
int compression = 0;
|
||||
int slot = -1;
|
||||
bool persist = false;
|
||||
|
||||
static int numInstances;
|
||||
|
||||
public slots:
|
||||
Q_INVOKABLE bool save();
|
||||
Q_INVOKABLE bool load();
|
||||
Q_INVOKABLE bool isValid(){ return (data != nullptr); }
|
||||
Q_INVOKABLE bool isPersistent(){ return persist; }
|
||||
Q_INVOKABLE void setPersistent(bool value){ persist = value; }
|
||||
Q_INVOKABLE int getSlot(){ return slot; }
|
||||
Q_INVOKABLE void setSlot(int value);
|
||||
Q_INVOKABLE int getCompressionLevel(){ return compression; }
|
||||
Q_INVOKABLE void setCompressionLevel(int value){ compression = value; }
|
||||
Q_INVOKABLE void setFilename(const QString& name){ filename = name; }
|
||||
Q_INVOKABLE bool saveToFile(const QString& filepath);
|
||||
Q_INVOKABLE bool loadFromFile(const QString& filepath);
|
||||
};
|
||||
|
||||
class EmuScriptObject: public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
@ -108,6 +145,7 @@ public slots:
|
|||
Q_INVOKABLE void exit();
|
||||
Q_INVOKABLE QString getDir();
|
||||
Q_INVOKABLE QJSValue getScreenPixel(int x, int y, bool useBackup = false);
|
||||
Q_INVOKABLE QJSValue createState(int slot = -1);
|
||||
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue