Skip to content

Commit

Permalink
[PR 11034] Savestate database
Browse files Browse the repository at this point in the history
This adds a savestate database based on the DenormalizedDatabase custom
ORM wrapper.
  • Loading branch information
garbear committed Jun 17, 2017
1 parent 488d51e commit 48262f1
Show file tree
Hide file tree
Showing 6 changed files with 143 additions and 25 deletions.
1 change: 1 addition & 0 deletions xbmc/DatabaseManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ void CDatabaseManager::Initialize(bool addonsOnly)
{ CPVRDatabase db; UpdateDatabase(db, &g_advancedSettings.m_databaseTV); }
{ CPVREpgDatabase db; UpdateDatabase(db, &g_advancedSettings.m_databaseEpg); }
{ CActiveAEDSPDatabase db; UpdateDatabase(db, &g_advancedSettings.m_databaseADSP); }
{ KODI::GAME::CSavestateDatabase db; UpdateDatabase(db, &g_advancedSettings.m_databaseSavestates); }
CLog::Log(LOGDEBUG, "%s, updating databases... DONE", __FUNCTION__);
m_bIsUpgrading = false;
}
Expand Down
10 changes: 5 additions & 5 deletions xbmc/games/addons/savestates/Savestate.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,13 @@
*/
#pragma once

#include "utils/IDeserializable.h"
#include "utils/ISerializable.h"
#include "XBDateTime.h"

#include <stdint.h>
#include <string>

class CVariant;

namespace KODI
{
namespace GAME
Expand All @@ -38,7 +38,7 @@ namespace GAME
MANUAL = 3,
};

class CSavestate
class CSavestate : public ISerializable, public IDeserializable
{
public:
CSavestate() { Reset(); }
Expand Down Expand Up @@ -76,8 +76,8 @@ namespace GAME
void SetTimestamp(const CDateTime& timestamp) { m_timestamp = timestamp; }
void SetThumbnail(const std::string& thumbnail) { m_thumbnail = thumbnail; }

void Serialize(CVariant& value) const;
void Deserialize(const CVariant& value);
virtual void Serialize(CVariant& value) const override;
virtual void Deserialize(const CVariant& value) override;

bool Serialize(const std::string& path) const;
bool Deserialize(const std::string& path);
Expand Down
104 changes: 94 additions & 10 deletions xbmc/games/addons/savestates/SavestateDatabase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,46 +39,130 @@ using namespace GAME;

#define SAVESTATE_OBJECT "savestate"

CSavestateDatabase::CSavestateDatabase()
CSavestateDatabase::CSavestateDatabase() :
CDenormalizedDatabase(SAVESTATE_OBJECT)
{
BeginDeclarations();
DeclareIndex(SAVESTATE_FIELD_PATH, "VARCHAR(512)");
DeclareOneToMany(SAVESTATE_FIELD_GAMECLIENT, "VARCHAR(64)");
DeclareOneToMany(SAVESTATE_FIELD_GAME_PATH, "VARCHAR(1024)");
DeclareOneToMany(SAVESTATE_FIELD_GAME_CRC, "CHAR(8)");
}

bool CSavestateDatabase::Open()
{
return CDatabase::Open(g_advancedSettings.m_databaseSavestates);
}

void CSavestateDatabase::UpdateTables(int version)
{
if (version < 1)
{
BeginDeclarations();
DeclareIndex(SAVESTATE_FIELD_PATH, "VARCHAR(512)");
DeclareOneToMany(SAVESTATE_FIELD_GAMECLIENT, "VARCHAR(64)");
DeclareOneToMany(SAVESTATE_FIELD_GAME_PATH, "VARCHAR(1024)");
DeclareOneToMany(SAVESTATE_FIELD_GAME_CRC, "CHAR(8)");
}
}

bool CSavestateDatabase::AddSavestate(const CSavestate& save)
{
//! @todo
return false;
if (!AddObject(&save))
{
CLog::Log(LOGERROR, "Failed to update the database with savestate information");
return false;
}
return true;
}

bool CSavestateDatabase::GetSavestate(const std::string& path, CSavestate& save)
{
//! @todo
return false;
return GetObjectByIndex(SAVESTATE_FIELD_PATH, path, &save);
}

bool CSavestateDatabase::GetSavestatesNav(CFileItemList& items, const std::string& gamePath, const std::string& gameClient /* = "" */)
{
//! @todo
std::map<std::string, int> predicates;
if (GetItemID(SAVESTATE_FIELD_GAME_PATH, gamePath, predicates[SAVESTATE_FIELD_GAME_PATH]))
{
if (!gameClient.empty())
GetItemID(SAVESTATE_FIELD_GAMECLIENT, gameClient, predicates[SAVESTATE_FIELD_GAMECLIENT]);

return GetObjectsNav(items, predicates);
}
return false;
}

bool CSavestateDatabase::RenameSavestate(const std::string& path, const std::string& label)
{
//! @todo
CSavestate save;
if (GetObjectByIndex(SAVESTATE_FIELD_PATH, path, &save))
{
if (save.Label() != label)
{
save.SetLabel(label);
return AddObject(&save) != -1;
}
}
return false;
}

bool CSavestateDatabase::DeleteSavestate(const std::string& path)
{
//! @todo
return false;
using namespace XFILE;

bool bSuccess = false;

if (DeleteObjectByIndex(SAVESTATE_FIELD_PATH, path))
{
if (!CFile::Delete(path))
CLog::Log(LOGERROR, "Failed to delete savestate %s", path.c_str());
else
{
std::string thumbPath = CSavestateUtils::MakeThumbPath(path);
if (CFile::Exists(thumbPath))
{
if (!CFile::Delete(thumbPath))
CLog::Log(LOGERROR, "Failed to delete thumbnail %s", thumbPath.c_str());
}

bSuccess = true;
}
}

return bSuccess;
}

bool CSavestateDatabase::ClearSavestatesOfGame(const std::string& gamePath, const std::string& gameClient /* = "" */)
{
//! @todo
CFileItemList items;
if (GetSavestatesNav(items, gamePath, gameClient))
{
bool bSuccess = true;

for (int i = 0; i < items.Size(); i++)
bSuccess &= DeleteSavestate(items[i]->GetPath());

return bSuccess;
}
return false;
}

bool CSavestateDatabase::Exists(const CVariant& object, int& idObject)
{
if (!IsValid(object))
return false;

CSavestate dummy;
return GetObjectByIndex(SAVESTATE_FIELD_PATH, object[SAVESTATE_FIELD_PATH], &dummy);
}

bool CSavestateDatabase::IsValid(const CVariant& object) const
{
return !object[SAVESTATE_FIELD_PATH].asString().empty();
}

CFileItem* CSavestateDatabase::CreateFileItem(const CVariant& object) const
{
using namespace ADDON;
Expand Down
26 changes: 22 additions & 4 deletions xbmc/games/addons/savestates/SavestateDatabase.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,13 @@
*/
#pragma once

#include "dbwrappers/DenormalizedDatabase.h"
#include "dbwrappers/DatabaseQuery.h"

#include <string>

#define SAVESTATES_DATABASE_NAME "Savestates"

class CFileItem;
class CFileItemList;
class CVariant;

Expand All @@ -33,12 +35,16 @@ namespace GAME
{
class CSavestate;

class CSavestateDatabase
class CSavestateDatabase : public CDenormalizedDatabase,
public IDatabaseQueryRuleFactory
{
public:
CSavestateDatabase();
virtual ~CSavestateDatabase() = default;

// implementation of CDatabase
virtual bool Open() override;

bool AddSavestate(const CSavestate& save);

bool GetSavestate(const std::string& path, CSavestate& save);
Expand All @@ -51,8 +57,20 @@ namespace GAME

bool ClearSavestatesOfGame(const std::string& gamePath, const std::string& gameClient = "");

private:
CFileItem* CreateFileItem(const CVariant& object) const;
// implementation of IDatabaseQueryRuleFactory
virtual CDatabaseQueryRule *CreateRule() const override { return nullptr; } // TODO
virtual CDatabaseQueryRuleCombination *CreateCombination() const override { return nullptr; } // TODO

protected:
// implementation of CDatabase
virtual void UpdateTables(int version) override;
virtual int GetSchemaVersion() const override { return 1; }
virtual const char *GetBaseDBName() const override { return SAVESTATES_DATABASE_NAME; }

// implementation of CDenormalizedDatabase
virtual bool Exists(const CVariant& object, int& idObject) override;
virtual bool IsValid(const CVariant& object) const override;
virtual CFileItem* CreateFileItem(const CVariant& object) const override;
};
}
}
19 changes: 13 additions & 6 deletions xbmc/games/addons/savestates/SavestateReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,12 @@ using namespace GAME;
CSavestateReader::CSavestateReader() :
m_frameCount(0)
{
m_db.Open();
}

CSavestateReader::~CSavestateReader()
{
m_db.Close();
}

bool CSavestateReader::Initialize(const std::string& path, const CGameClient* gameClient)
Expand All @@ -42,16 +44,21 @@ bool CSavestateReader::Initialize(const std::string& path, const CGameClient* ga

CLog::Log(LOGDEBUG, "Loading savestate from %s", path.c_str());

if (m_db.GetSavestate(path, m_savestate))
if (m_db.IsOpen())
{
// Sanity checks
if (m_savestate.GameClient() == gameClient->ID())
bSuccess = true;
if (m_db.GetSavestate(path, m_savestate))
{
// Sanity checks
if (m_savestate.GameClient() == gameClient->ID())
bSuccess = true;
else
CLog::Log(LOGDEBUG, "Savestate game client %s doesn't match active %s", m_savestate.GameClient().c_str(), gameClient->ID().c_str());
}
else
CLog::Log(LOGDEBUG, "Savestate game client %s doesn't match active %s", m_savestate.GameClient().c_str(), gameClient->ID().c_str());
CLog::Log(LOGERROR, "Failed to query savestate %s", path.c_str());
}
else
CLog::Log(LOGERROR, "Failed to query savestate %s", path.c_str());
CLog::Log(LOGERROR, "Failed to open savestate database");

return bSuccess;
}
Expand Down
8 changes: 8 additions & 0 deletions xbmc/games/addons/savestates/SavestateWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,17 +37,25 @@ using namespace GAME;
CSavestateWriter::CSavestateWriter() :
m_fps(0.0)
{
m_db.Open();
}

CSavestateWriter::~CSavestateWriter()
{
m_db.Close();
}

bool CSavestateWriter::Initialize(const CGameClient* gameClient, uint64_t frameHistoryCount)
{
m_savestate.Reset();
m_fps = 0.0;

if (!m_db.IsOpen())
{
CLog::Log(LOGDEBUG, "Failed to open savestates database");
return false;
}

m_fps = gameClient->Timing().GetFrameRate();

CDateTime now = CDateTime::GetCurrentDateTime();
Expand Down

0 comments on commit 48262f1

Please sign in to comment.