dolphin/Source/Core/Core/State.h
2024-03-01 10:52:50 -08:00

121 lines
3.6 KiB
C++

// Copyright 2008 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
// Emulator state saving support.
#pragma once
#include <cstddef>
#include <functional>
#include <string>
#include <type_traits>
#include <vector>
#include "Common/CommonTypes.h"
namespace Core
{
class System;
}
namespace State
{
// number of states
static const u32 NUM_STATES = 10;
struct StateHeaderLegacy
{
char game_id[6];
char reserved1[2];
u32 lzo_size = 0; // Must be zero for new states. Used to support legacy decompression algorithm.
char reserved2[4];
double time;
};
constexpr size_t STATE_HEADER_SIZE = sizeof(StateHeaderLegacy);
static_assert(STATE_HEADER_SIZE == 24);
static_assert(offsetof(StateHeaderLegacy, lzo_size) == 8);
static_assert(offsetof(StateHeaderLegacy, time) == 16);
static_assert(std::is_trivially_copyable_v<StateHeaderLegacy>);
struct StateHeaderVersion
{
u32 version_cookie;
u32 version_string_length;
};
static_assert(std::is_trivially_copyable_v<StateHeaderVersion>);
struct StateHeader
{
StateHeaderLegacy legacy_header;
StateHeaderVersion version_header;
std::string version_string;
};
enum CompressionType : u16
{
Uncompressed = 0,
LZ4 = 1,
// Add new compression types after this, as the compression type
// is numerically stored in the state file.
};
struct StateExtendedBaseHeader
{
u16 header_version;
u16 compression_type;
u32 payload_offset;
u64 uncompressed_size;
};
constexpr size_t EXTENDED_BASE_HEADER_SIZE = sizeof(StateExtendedBaseHeader);
static_assert(EXTENDED_BASE_HEADER_SIZE == 16);
static_assert(offsetof(StateExtendedBaseHeader, payload_offset) == 4);
static_assert(offsetof(StateExtendedBaseHeader, uncompressed_size) == 8);
static_assert(std::is_trivially_copyable_v<StateExtendedBaseHeader>);
struct StateExtendedHeader
{
StateExtendedBaseHeader base_header;
// Feel free to add new fields here, adjusting COMPRESSED_DATA_OFFSET accordingly, as well as
// CreateExtendedHeader(). Add the appropriate IOFile read/write calls within LoadFileStateData()
// and WriteHeadersToFile()
};
void Init(Core::System& system);
void Shutdown();
void EnableCompression(bool compression);
bool ReadHeader(const std::string& filename, StateHeader& header);
// Returns a string containing information of the savestate in the given slot
// which can be presented to the user for identification purposes
std::string GetInfoStringOfSlot(int slot, bool translate = true);
// Returns when the savestate in the given slot was created, or 0 if the slot is empty.
u64 GetUnixTimeOfSlot(int slot);
// These don't happen instantly - they get scheduled as events.
// ...But only if we're not in the main CPU thread.
// If we're in the main CPU thread then they run immediately instead
// because some things (like Lua) need them to run immediately.
// Slots from 0-99.
void Save(Core::System& system, int slot, bool wait = false);
void Load(Core::System& system, int slot);
void SaveAs(Core::System& system, const std::string& filename, bool wait = false);
void LoadAs(Core::System& system, const std::string& filename);
void SaveToBuffer(Core::System& system, std::vector<u8>& buffer);
void LoadFromBuffer(Core::System& system, std::vector<u8>& buffer);
void LoadLastSaved(Core::System& system, int i = 1);
void SaveFirstSaved(Core::System& system);
void UndoSaveState(Core::System& system);
void UndoLoadState(Core::System& system);
// for calling back into UI code without introducing a dependency on it in core
using AfterLoadCallbackFunc = std::function<void()>;
void SetOnAfterLoadCallback(AfterLoadCallbackFunc callback);
} // namespace State