Skip to content

Commit

Permalink
libretro: implement save/load state.
Browse files Browse the repository at this point in the history
Signed-off-by: Andrea Odetti <mariofutire@gmail.com>
  • Loading branch information
audetto committed Nov 27, 2021
1 parent 741849a commit 7037e20
Show file tree
Hide file tree
Showing 4 changed files with 160 additions and 4 deletions.
4 changes: 3 additions & 1 deletion source/frontends/libretro/CMakeLists.txt
Expand Up @@ -11,9 +11,11 @@ set(SOURCE_FILES
retroregistry.cpp
retroframe.cpp
diskcontrol.cpp
serialisation.cpp
)

set(HEADER_FILES
libretro-common/include/libretro.h
environment.h
rdirectsound.h
game.h
Expand All @@ -25,7 +27,7 @@ set(HEADER_FILES
retroregistry.h
retroframe.h
diskcontrol.h
libretro-common/include/libretro.h
serialisation.h
)

add_library(applewin_libretro SHARED
Expand Down
10 changes: 7 additions & 3 deletions source/frontends/libretro/libretro.cpp
Expand Up @@ -19,6 +19,7 @@
#include "frontends/libretro/joypad.h"
#include "frontends/libretro/analog.h"
#include "frontends/libretro/mouse.h"
#include "frontends/libretro/serialisation.h"

namespace
{
Expand Down Expand Up @@ -362,19 +363,22 @@ bool retro_load_game_special(unsigned type, const struct retro_game_info *info,
size_t retro_serialize_size(void)
{
ra2::log_cb(RETRO_LOG_INFO, "RA2: %s\n", __FUNCTION__);
return 0;
const size_t size = ra2::RetroSerialisation::getSize();
// we cannot guarantee exact file size, so we allow for a small grace buffer
const size_t buffer = 4096;
return size + buffer;
}

bool retro_serialize(void *data, size_t size)
{
ra2::log_cb(RETRO_LOG_INFO, "RA2: %s\n", __FUNCTION__);
return false;
return ra2::RetroSerialisation::serialise(static_cast<char *>(data), size);
}

bool retro_unserialize(const void *data, size_t size)
{
ra2::log_cb(RETRO_LOG_INFO, "RA2: %s\n", __FUNCTION__);
return false;
return ra2::RetroSerialisation::deserialise(static_cast<const char *>(data), size);
}

void retro_cheat_reset(void)
Expand Down
136 changes: 136 additions & 0 deletions source/frontends/libretro/serialisation.cpp
@@ -0,0 +1,136 @@
#include "StdAfx.h"
#include "SaveState.h"

#include "frontends/libretro/serialisation.h"
#include "frontends/libretro/environment.h"

#include <cstdio>
#include <fstream>

namespace
{
class AutoFile
{
public:
AutoFile();
~AutoFile();

std::string getFilename() const; // only if true

operator bool() const;
protected:
const char * myFilename;
};

AutoFile::AutoFile()
{
// massive race condition, but without changes to AW, little can we do here
myFilename = std::tmpnam(nullptr);
}

AutoFile::~AutoFile()
{
std::remove(myFilename);
}

AutoFile::operator bool() const
{
return myFilename;
}

std::string AutoFile::getFilename() const
{
return myFilename;
}

void saveToFile(const std::string & filename) // cannot be null!
{
Snapshot_SetFilename(filename);
Snapshot_SaveState();
}

}

namespace ra2
{

size_t RetroSerialisation::getSize()
{
AutoFile autoFile;
if (!autoFile)
{
return 0;
}

const std::string filename = autoFile.getFilename();
saveToFile(filename);
std::ifstream ifs(filename, std::ios::binary | std::ios::ate);

const std::ifstream::pos_type fileSize = ifs.tellg();
return sizeof(uint32_t) + fileSize;
}

bool RetroSerialisation::serialise(char * data, size_t size)
{
AutoFile autoFile;
if (!autoFile)
{
return 0;
}

const std::string filename = autoFile.getFilename();
saveToFile(filename);
std::ifstream ifs(filename, std::ios::binary | std::ios::ate);

const std::ifstream::pos_type fileSize = ifs.tellg();
if (sizeof(uint32_t) + fileSize > size)
{
return false;
}
else
{
uint32_t * sizePtr = reinterpret_cast<uint32_t *>(data);
*sizePtr = fileSize;

char * dataPtr = data + sizeof(uint32_t);

ifs.seekg(0, std::ios::beg);
ifs.read(dataPtr, fileSize);

return true;
}
}

bool RetroSerialisation::deserialise(const char * data, size_t size)
{
AutoFile autoFile;
if (!autoFile)
{
return false;
}

const uint32_t * sizePtr = reinterpret_cast<const uint32_t *>(data);
const size_t fileSize = *sizePtr;

if (sizeof(uint32_t) + fileSize > size)
{
return false;
}
else
{
const char * dataPtr = data + sizeof(uint32_t);

const std::string filename = autoFile.getFilename();
// do not remove the {} scope below!
{
std::ofstream ofs(filename, std::ios::binary);
ofs.write(dataPtr, fileSize);
}

Snapshot_SetFilename(filename);
Snapshot_LoadState();
return true;
}
}

}
14 changes: 14 additions & 0 deletions source/frontends/libretro/serialisation.h
@@ -0,0 +1,14 @@
#include <cstddef>

namespace ra2
{

class RetroSerialisation
{
public:
static size_t getSize();
static bool serialise(char * data, size_t size);
static bool deserialise(const char * data, size_t size);
};

}

0 comments on commit 7037e20

Please sign in to comment.