Merge master
This commit is contained in:
+19
-14
@@ -458,19 +458,14 @@ add_library(citra_core STATIC
|
||||
mmio.h
|
||||
movie.cpp
|
||||
movie.h
|
||||
nus_download.cpp
|
||||
nus_download.h
|
||||
perf_stats.cpp
|
||||
perf_stats.h
|
||||
precompiled_headers.h
|
||||
rpc/packet.cpp
|
||||
rpc/packet.h
|
||||
rpc/rpc_server.cpp
|
||||
rpc/rpc_server.h
|
||||
rpc/server.cpp
|
||||
rpc/server.h
|
||||
rpc/udp_server.cpp
|
||||
rpc/udp_server.h
|
||||
savestate.cpp
|
||||
savestate.h
|
||||
savestate_data.h
|
||||
system_titles.cpp
|
||||
system_titles.h
|
||||
telemetry_session.cpp
|
||||
@@ -483,16 +478,26 @@ add_library(citra_core STATIC
|
||||
create_target_directory_groups(citra_core)
|
||||
|
||||
target_link_libraries(citra_core PUBLIC citra_common PRIVATE audio_core network video_core)
|
||||
target_link_libraries(citra_core PRIVATE Boost::boost Boost::serialization Boost::iostreams)
|
||||
target_link_libraries(citra_core PRIVATE Boost::boost Boost::serialization Boost::iostreams httplib)
|
||||
target_link_libraries(citra_core PUBLIC dds-ktx PRIVATE cryptopp fmt::fmt lodepng open_source_archives)
|
||||
set_target_properties(citra_core PROPERTIES INTERPROCEDURAL_OPTIMIZATION ${ENABLE_LTO})
|
||||
|
||||
if (ENABLE_WEB_SERVICE)
|
||||
target_compile_definitions(citra_core PRIVATE -DENABLE_WEB_SERVICE -DCPPHTTPLIB_OPENSSL_SUPPORT)
|
||||
target_link_libraries(citra_core PRIVATE web_service ${OPENSSL_LIBS} httplib)
|
||||
if (ANDROID)
|
||||
target_link_libraries(citra_core PRIVATE ifaddrs)
|
||||
endif()
|
||||
target_link_libraries(citra_core PRIVATE web_service)
|
||||
endif()
|
||||
|
||||
if (ENABLE_SCRIPTING)
|
||||
target_compile_definitions(citra_core PUBLIC -DENABLE_SCRIPTING)
|
||||
target_sources(citra_core PRIVATE
|
||||
rpc/packet.cpp
|
||||
rpc/packet.h
|
||||
rpc/rpc_server.cpp
|
||||
rpc/rpc_server.h
|
||||
rpc/server.cpp
|
||||
rpc/server.h
|
||||
rpc/udp_server.cpp
|
||||
rpc/udp_server.h
|
||||
)
|
||||
endif()
|
||||
|
||||
if ("x86_64" IN_LIST ARCHITECTURE OR "arm64" IN_LIST ARCHITECTURE)
|
||||
|
||||
@@ -45,7 +45,9 @@
|
||||
#include "core/hw/lcd.h"
|
||||
#include "core/loader/loader.h"
|
||||
#include "core/movie.h"
|
||||
#ifdef ENABLE_SCRIPTING
|
||||
#include "core/rpc/server.h"
|
||||
#endif
|
||||
#include "core/telemetry_session.h"
|
||||
#include "network/network.h"
|
||||
#include "video_core/custom_textures/custom_tex_manager.h"
|
||||
@@ -418,7 +420,9 @@ System::ResultStatus System::Init(Frontend::EmuWindow& emu_window,
|
||||
|
||||
telemetry_session = std::make_unique<Core::TelemetrySession>();
|
||||
|
||||
#ifdef ENABLE_SCRIPTING
|
||||
rpc_server = std::make_unique<RPC::Server>(*this);
|
||||
#endif
|
||||
|
||||
service_manager = std::make_unique<Service::SM::ServiceManager>(*this);
|
||||
archive_manager = std::make_unique<Service::FS::ArchiveManager>(*this);
|
||||
@@ -555,7 +559,9 @@ void System::Shutdown(bool is_deserializing) {
|
||||
}
|
||||
custom_tex_manager.reset();
|
||||
telemetry_session.reset();
|
||||
#ifdef ENABLE_SCRIPTING
|
||||
rpc_server.reset();
|
||||
#endif
|
||||
archive_manager.reset();
|
||||
service_manager.reset();
|
||||
dsp_core.reset();
|
||||
|
||||
@@ -405,8 +405,10 @@ private:
|
||||
/// Image interface
|
||||
std::shared_ptr<Frontend::ImageInterface> registered_image_interface;
|
||||
|
||||
#ifdef ENABLE_SCRIPTING
|
||||
/// RPC Server for scripting support
|
||||
std::unique_ptr<RPC::Server> rpc_server;
|
||||
#endif
|
||||
|
||||
std::unique_ptr<Service::FS::ArchiveManager> archive_manager;
|
||||
|
||||
|
||||
@@ -151,6 +151,17 @@ void Module::Interface::RegisterDisconnectEvent(Kernel::HLERequestContext& ctx)
|
||||
LOG_WARNING(Service_AC, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void Module::Interface::GetConnectingProxyEnable(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp(ctx);
|
||||
constexpr bool proxy_enabled = false;
|
||||
|
||||
IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push(proxy_enabled);
|
||||
|
||||
LOG_WARNING(Service_AC, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void Module::Interface::IsConnected(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp(ctx);
|
||||
u32 unk = rp.Pop<u32>();
|
||||
|
||||
@@ -120,6 +120,14 @@ public:
|
||||
*/
|
||||
void RegisterDisconnectEvent(Kernel::HLERequestContext& ctx);
|
||||
|
||||
/**
|
||||
* AC::GetConnectingProxyEnable service function
|
||||
* Outputs:
|
||||
* 1 : Result of function, 0 on success, otherwise error code
|
||||
* 2 : bool, is proxy enabled
|
||||
*/
|
||||
void GetConnectingProxyEnable(Kernel::HLERequestContext& ctx);
|
||||
|
||||
/**
|
||||
* AC::IsConnected service function
|
||||
* Outputs:
|
||||
|
||||
@@ -27,6 +27,7 @@ AC_I::AC_I(std::shared_ptr<Module> ac) : Module::Interface(std::move(ac), "ac:i"
|
||||
{0x0027, &AC_I::GetInfraPriority, "GetInfraPriority"},
|
||||
{0x002D, &AC_I::SetRequestEulaVersion, "SetRequestEulaVersion"},
|
||||
{0x0030, &AC_I::RegisterDisconnectEvent, "RegisterDisconnectEvent"},
|
||||
{0x0036, &AC_I::GetConnectingProxyEnable, "GetConnectingProxyEnable"},
|
||||
{0x003C, nullptr, "GetAPSSIDList"},
|
||||
{0x003E, &AC_I::IsConnected, "IsConnected"},
|
||||
{0x0040, &AC_I::SetClientVersion, "SetClientVersion"},
|
||||
|
||||
@@ -27,6 +27,7 @@ AC_U::AC_U(std::shared_ptr<Module> ac) : Module::Interface(std::move(ac), "ac:u"
|
||||
{0x0027, &AC_U::GetInfraPriority, "GetInfraPriority"},
|
||||
{0x002D, &AC_U::SetRequestEulaVersion, "SetRequestEulaVersion"},
|
||||
{0x0030, &AC_U::RegisterDisconnectEvent, "RegisterDisconnectEvent"},
|
||||
{0x0036, &AC_U::GetConnectingProxyEnable, "GetConnectingProxyEnable"},
|
||||
{0x003C, nullptr, "GetAPSSIDList"},
|
||||
{0x003E, &AC_U::IsConnected, "IsConnected"},
|
||||
{0x0040, &AC_U::SetClientVersion, "SetClientVersion"},
|
||||
|
||||
@@ -31,9 +31,7 @@
|
||||
#include "core/hle/service/fs/fs_user.h"
|
||||
#include "core/loader/loader.h"
|
||||
#include "core/loader/smdh.h"
|
||||
#ifdef ENABLE_WEB_SERVICE
|
||||
#include "web_service/nus_download.h"
|
||||
#endif
|
||||
#include "core/nus_download.h"
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
@@ -463,7 +461,6 @@ InstallStatus InstallCIA(const std::string& path,
|
||||
}
|
||||
|
||||
InstallStatus InstallFromNus(u64 title_id, int version) {
|
||||
#ifdef ENABLE_WEB_SERVICE
|
||||
LOG_DEBUG(Service_AM, "Downloading {:X}", title_id);
|
||||
|
||||
CIAFile install_file{GetTitleMediaType(title_id)};
|
||||
@@ -472,7 +469,7 @@ InstallStatus InstallFromNus(u64 title_id, int version) {
|
||||
if (version != -1) {
|
||||
path += fmt::format(".{}", version);
|
||||
}
|
||||
auto tmd_response = WebService::NUS::Download(path);
|
||||
auto tmd_response = Core::NUS::Download(path);
|
||||
if (!tmd_response) {
|
||||
LOG_ERROR(Service_AM, "Failed to download tmd for {:016X}", title_id);
|
||||
return InstallStatus::ErrorFileNotFound;
|
||||
@@ -481,7 +478,7 @@ InstallStatus InstallFromNus(u64 title_id, int version) {
|
||||
tmd.Load(*tmd_response);
|
||||
|
||||
path = fmt::format("/ccs/download/{:016X}/cetk", title_id);
|
||||
auto cetk_response = WebService::NUS::Download(path);
|
||||
auto cetk_response = Core::NUS::Download(path);
|
||||
if (!cetk_response) {
|
||||
LOG_ERROR(Service_AM, "Failed to download cetk for {:016X}", title_id);
|
||||
return InstallStatus::ErrorFileNotFound;
|
||||
@@ -492,7 +489,7 @@ InstallStatus InstallFromNus(u64 title_id, int version) {
|
||||
for (std::size_t i = 0; i < content_count; ++i) {
|
||||
const std::string filename = fmt::format("{:08x}", tmd.GetContentIDByIndex(i));
|
||||
path = fmt::format("/ccs/download/{:016X}/{}", title_id, filename);
|
||||
const auto temp_response = WebService::NUS::Download(path);
|
||||
const auto temp_response = Core::NUS::Download(path);
|
||||
if (!temp_response) {
|
||||
LOG_ERROR(Service_AM, "Failed to download content for {:016X}", title_id);
|
||||
return InstallStatus::ErrorFileNotFound;
|
||||
@@ -550,9 +547,6 @@ InstallStatus InstallFromNus(u64 title_id, int version) {
|
||||
return result;
|
||||
}
|
||||
return InstallStatus::Success;
|
||||
#else
|
||||
return InstallStatus::ErrorFileNotFound;
|
||||
#endif
|
||||
}
|
||||
|
||||
u64 GetTitleUpdateId(u64 title_id) {
|
||||
|
||||
@@ -620,9 +620,9 @@ void Module::Interface::SetData(Kernel::HLERequestContext& ctx) {
|
||||
|
||||
void Module::Interface::ReadData(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp(ctx);
|
||||
const u32 dest_buffer_size = rp.Pop<u32>();
|
||||
const CecSystemInfoType info_type = rp.PopEnum<CecSystemInfoType>();
|
||||
const u32 param_buffer_size = rp.Pop<u32>();
|
||||
const auto dest_buffer_size = rp.Pop<u32>();
|
||||
const auto info_type = rp.PopEnum<CecSystemInfoType>();
|
||||
const auto param_buffer_size = rp.Pop<u32>();
|
||||
auto& param_buffer = rp.PopMappedBuffer();
|
||||
auto& dest_buffer = rp.PopMappedBuffer();
|
||||
|
||||
@@ -631,22 +631,23 @@ void Module::Interface::ReadData(Kernel::HLERequestContext& ctx) {
|
||||
std::vector<u8> buffer;
|
||||
switch (info_type) {
|
||||
case CecSystemInfoType::EulaVersion: {
|
||||
auto cfg = Service::CFG::GetModule(cecd->system);
|
||||
Service::CFG::EULAVersion version = cfg->GetEULAVersion();
|
||||
dest_buffer.Write(&version, 0, sizeof(version));
|
||||
const auto cfg = Service::CFG::GetModule(cecd->system);
|
||||
const auto version = cfg->GetEULAVersion();
|
||||
buffer = {version.minor, version.major};
|
||||
break;
|
||||
}
|
||||
case CecSystemInfoType::Eula:
|
||||
buffer = {0x01}; // Eula agreed
|
||||
dest_buffer.Write(buffer.data(), 0, buffer.size());
|
||||
buffer = {true}; // Eula agreed
|
||||
break;
|
||||
case CecSystemInfoType::ParentControl:
|
||||
buffer = {0x00}; // No parent control
|
||||
dest_buffer.Write(buffer.data(), 0, buffer.size());
|
||||
buffer = {false}; // No parent control
|
||||
break;
|
||||
default:
|
||||
LOG_ERROR(Service_CECD, "Unknown system info type={:#x}", info_type);
|
||||
buffer = {};
|
||||
}
|
||||
dest_buffer.Write(buffer.data(), 0,
|
||||
std::min(static_cast<size_t>(dest_buffer_size), buffer.size()));
|
||||
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushMappedBuffer(param_buffer);
|
||||
|
||||
@@ -314,6 +314,7 @@ void HTTP_C::ReceiveDataImpl(Kernel::HLERequestContext& ctx, bool timeout) {
|
||||
} else {
|
||||
LOG_WARNING(Service_HTTP, "(STUBBED) called");
|
||||
}
|
||||
[[maybe_unused]] Kernel::MappedBuffer& buffer = rp.PopMappedBuffer();
|
||||
|
||||
Kernel::MappedBuffer& buffer = rp.PopMappedBuffer();
|
||||
|
||||
|
||||
@@ -17,12 +17,10 @@
|
||||
#include <boost/serialization/unordered_map.hpp>
|
||||
#include <boost/serialization/vector.hpp>
|
||||
#include <boost/serialization/weak_ptr.hpp>
|
||||
#ifdef ENABLE_WEB_SERVICE
|
||||
#if defined(__ANDROID__)
|
||||
#include <ifaddrs.h>
|
||||
#endif
|
||||
#include <httplib.h>
|
||||
#endif
|
||||
#include "core/hle/ipc_helpers.h"
|
||||
#include "core/hle/kernel/shared_memory.h"
|
||||
#include "core/hle/service/service.h"
|
||||
@@ -214,7 +212,6 @@ public:
|
||||
bool uses_default_client_cert{};
|
||||
#ifdef ENABLE_WEB_SERVICE
|
||||
httplib::Response response;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct SessionData : public Kernel::SessionRequestHandler::SessionDataBase {
|
||||
|
||||
@@ -316,7 +316,7 @@ void Module::Interface::GetTagInfo2(Kernel::HLERequestContext& ctx) {
|
||||
|
||||
if (nfc->nfc_mode == CommunicationMode::TrainTag) {
|
||||
LOG_ERROR(Service_NFC, "CommunicationMode {} not implemented", nfc->nfc_mode);
|
||||
IPC::RequestBuilder rb = rp.MakeBuilder(26, 0);
|
||||
IPC::RequestBuilder rb = rp.MakeBuilder(25, 0);
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushRaw<TagInfo2>({});
|
||||
return;
|
||||
@@ -324,7 +324,7 @@ void Module::Interface::GetTagInfo2(Kernel::HLERequestContext& ctx) {
|
||||
|
||||
TagInfo2 tag_info{};
|
||||
const auto result = nfc->device->GetTagInfo2(tag_info);
|
||||
IPC::RequestBuilder rb = rp.MakeBuilder(26, 0);
|
||||
IPC::RequestBuilder rb = rp.MakeBuilder(25, 0);
|
||||
rb.Push(result);
|
||||
rb.PushRaw<TagInfo2>(tag_info);
|
||||
}
|
||||
@@ -383,10 +383,14 @@ void Module::Interface::OpenApplicationArea(Kernel::HLERequestContext& ctx) {
|
||||
void Module::Interface::CreateApplicationArea(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp(ctx);
|
||||
u32 access_id = rp.Pop<u32>();
|
||||
[[maybe_unused]] u32 size = rp.Pop<u32>();
|
||||
u32 size = rp.Pop<u32>();
|
||||
std::vector<u8> buffer = rp.PopStaticBuffer();
|
||||
|
||||
LOG_CRITICAL(Service_NFC, "called, size={}", size);
|
||||
LOG_INFO(Service_NFC, "called, size={}", size);
|
||||
|
||||
if (buffer.size() > size) {
|
||||
buffer.resize(size);
|
||||
}
|
||||
|
||||
if (nfc->nfc_mode != CommunicationMode::Amiibo) {
|
||||
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
||||
@@ -402,8 +406,9 @@ void Module::Interface::CreateApplicationArea(Kernel::HLERequestContext& ctx) {
|
||||
|
||||
void Module::Interface::ReadApplicationArea(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp(ctx);
|
||||
u32 size = rp.Pop<u32>();
|
||||
|
||||
LOG_INFO(Service_NFC, "called");
|
||||
LOG_INFO(Service_NFC, "called, size={}", size);
|
||||
|
||||
nfc->device->RescheduleTagRemoveEvent();
|
||||
|
||||
@@ -413,7 +418,7 @@ void Module::Interface::ReadApplicationArea(Kernel::HLERequestContext& ctx) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<u8> buffer(sizeof(ApplicationArea));
|
||||
std::vector<u8> buffer(size);
|
||||
const auto result = nfc->device->GetApplicationArea(buffer);
|
||||
|
||||
IPC::RequestBuilder rb = rp.MakeBuilder(1, 2);
|
||||
@@ -423,11 +428,15 @@ void Module::Interface::ReadApplicationArea(Kernel::HLERequestContext& ctx) {
|
||||
|
||||
void Module::Interface::WriteApplicationArea(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp(ctx);
|
||||
[[maybe_unused]] u32 size = rp.Pop<u32>();
|
||||
u32 size = rp.Pop<u32>();
|
||||
std::vector<u8> tag_uuid_info = rp.PopStaticBuffer();
|
||||
std::vector<u8> buffer = rp.PopStaticBuffer();
|
||||
|
||||
LOG_CRITICAL(Service_NFC, "called, size={}", size);
|
||||
LOG_INFO(Service_NFC, "called, size={}", size);
|
||||
|
||||
if (buffer.size() > size) {
|
||||
buffer.resize(size);
|
||||
}
|
||||
|
||||
if (nfc->nfc_mode != CommunicationMode::Amiibo) {
|
||||
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
||||
@@ -540,7 +549,7 @@ void Module::Interface::GetIdentificationBlock(Kernel::HLERequestContext& ctx) {
|
||||
ModelInfo model_info{};
|
||||
const auto result = nfc->device->GetModelInfo(model_info);
|
||||
|
||||
IPC::RequestBuilder rb = rp.MakeBuilder(0x1F, 0);
|
||||
IPC::RequestBuilder rb = rp.MakeBuilder(14, 0);
|
||||
rb.Push(result);
|
||||
rb.PushRaw<ModelInfo>(model_info);
|
||||
}
|
||||
|
||||
@@ -1101,8 +1101,8 @@ void NfcDevice::BuildAmiiboWithoutKeys() {
|
||||
}
|
||||
|
||||
void NfcDevice::RescheduleTagRemoveEvent() {
|
||||
/// The interval at which the amiibo will be removed automatically 1.5s
|
||||
static constexpr u64 amiibo_removal_interval = nsToCycles(1500 * 1000 * 1000);
|
||||
/// The interval at which the amiibo will be removed automatically 3s
|
||||
static constexpr u64 amiibo_removal_interval = msToCycles(3 * 1000);
|
||||
|
||||
system.CoreTiming().UnscheduleEvent(remove_amiibo_event, 0);
|
||||
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
// Copyright 2020 Citra Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <memory>
|
||||
#include <httplib.h>
|
||||
#include "common/logging/log.h"
|
||||
#include "core/nus_download.h"
|
||||
|
||||
namespace Core::NUS {
|
||||
|
||||
std::optional<std::vector<u8>> Download(const std::string& path) {
|
||||
constexpr auto HOST = "http://nus.cdn.c.shop.nintendowifi.net";
|
||||
|
||||
std::unique_ptr<httplib::Client> client = std::make_unique<httplib::Client>(HOST);
|
||||
if (client == nullptr) {
|
||||
LOG_ERROR(WebService, "Invalid URL {}{}", HOST, path);
|
||||
return {};
|
||||
}
|
||||
|
||||
httplib::Request request{
|
||||
.method = "GET",
|
||||
.path = path,
|
||||
// Needed when httplib is included on android
|
||||
.matches = httplib::Match(),
|
||||
};
|
||||
|
||||
client->set_follow_location(true);
|
||||
const auto result = client->send(request);
|
||||
if (!result) {
|
||||
LOG_ERROR(WebService, "GET to {}{} returned null", HOST, path);
|
||||
return {};
|
||||
}
|
||||
|
||||
const auto& response = result.value();
|
||||
if (response.status >= 400) {
|
||||
LOG_ERROR(WebService, "GET to {}{} returned error status code: {}", HOST, path,
|
||||
response.status);
|
||||
return {};
|
||||
}
|
||||
if (!response.headers.contains("content-type")) {
|
||||
LOG_ERROR(WebService, "GET to {}{} returned no content", HOST, path);
|
||||
return {};
|
||||
}
|
||||
|
||||
return std::vector<u8>(response.body.begin(), response.body.end());
|
||||
}
|
||||
|
||||
} // namespace Core::NUS
|
||||
@@ -0,0 +1,15 @@
|
||||
// Copyright 2020 Citra Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
#include "common/common_types.h"
|
||||
|
||||
namespace Core::NUS {
|
||||
|
||||
std::optional<std::vector<u8>> Download(const std::string& path);
|
||||
|
||||
} // namespace Core::NUS
|
||||
+29
-7
@@ -15,18 +15,21 @@
|
||||
#include "core/core.h"
|
||||
#include "core/movie.h"
|
||||
#include "core/savestate.h"
|
||||
#include "core/savestate_data.h"
|
||||
#include "network/network.h"
|
||||
|
||||
namespace Core {
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct CSTHeader {
|
||||
std::array<u8, 4> filetype; /// Unique Identifier to check the file type (always "CST"0x1B)
|
||||
u64_le program_id; /// ID of the ROM being executed. Also called title_id
|
||||
std::array<u8, 20> revision; /// Git hash of the revision this savestate was created with
|
||||
u64_le time; /// The time when this save state was created
|
||||
std::array<u8, 4> filetype; /// Unique Identifier to check the file type (always "CST"0x1B)
|
||||
u64_le program_id; /// ID of the ROM being executed. Also called title_id
|
||||
std::array<u8, 20> revision; /// Git hash of the revision this savestate was created with
|
||||
u64_le time; /// The time when this save state was created
|
||||
std::array<u8, 20> build_name; /// The build name (Canary/Nightly) with the version number
|
||||
u32_le zero = 0; /// Should be zero, just in case.
|
||||
|
||||
std::array<u8, 216> reserved{}; /// Make heading 256 bytes so it has consistent size
|
||||
std::array<u8, 192> reserved{}; /// Make heading 256 bytes so it has consistent size
|
||||
};
|
||||
static_assert(sizeof(CSTHeader) == 256, "CSTHeader should be 256 bytes");
|
||||
#pragma pack(pop)
|
||||
@@ -58,11 +61,26 @@ static bool ValidateSaveState(const CSTHeader& header, SaveStateInfo& info, u64
|
||||
return false;
|
||||
}
|
||||
const std::string revision = fmt::format("{:02x}", fmt::join(header.revision, ""));
|
||||
const std::string build_name =
|
||||
header.zero == 0 ? reinterpret_cast<const char*>(header.build_name.data()) : "";
|
||||
|
||||
if (revision == Common::g_scm_rev) {
|
||||
info.status = SaveStateInfo::ValidationStatus::OK;
|
||||
} else {
|
||||
LOG_WARNING(Core, "Save state file {} created from a different revision {}", path,
|
||||
revision);
|
||||
if (!build_name.empty()) {
|
||||
info.build_name = build_name;
|
||||
} else if (hash_to_version.find(revision) != hash_to_version.end()) {
|
||||
info.build_name = hash_to_version.at(revision);
|
||||
}
|
||||
if (info.build_name.empty()) {
|
||||
LOG_WARNING(Core, "Save state file {} created from a different revision {}", path,
|
||||
revision);
|
||||
} else {
|
||||
LOG_WARNING(Core,
|
||||
"Save state file {} created from a different build {} with revision {}",
|
||||
path, info.build_name, revision);
|
||||
}
|
||||
|
||||
info.status = SaveStateInfo::ValidationStatus::RevisionDismatch;
|
||||
}
|
||||
return true;
|
||||
@@ -134,6 +152,10 @@ void System::SaveState(u32 slot) const {
|
||||
header.time = std::chrono::duration_cast<std::chrono::seconds>(
|
||||
std::chrono::system_clock::now().time_since_epoch())
|
||||
.count();
|
||||
const std::string build_fullname = Common::g_build_fullname;
|
||||
std::memset(header.build_name.data(), 0, sizeof(header.build_name));
|
||||
std::memcpy(header.build_name.data(), build_fullname.c_str(),
|
||||
std::min(build_fullname.length(), sizeof(header.build_name) - 1));
|
||||
|
||||
if (file.WriteBytes(&header, sizeof(header)) != sizeof(header) ||
|
||||
file.WriteBytes(buffer.data(), buffer.size()) != buffer.size()) {
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "common/common_types.h"
|
||||
|
||||
@@ -16,6 +17,7 @@ struct SaveStateInfo {
|
||||
OK,
|
||||
RevisionDismatch,
|
||||
} status;
|
||||
std::string build_name;
|
||||
};
|
||||
|
||||
constexpr u32 SaveStateSlotCount = 10; // Maximum count of savestate slots
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user