Changeset View
Changeset View
Standalone View
Standalone View
source/ps/SavedGame.cpp
/* Copyright (C) 2021 Wildfire Games. | /* Copyright (C) 2023 Wildfire Games. | ||||||||||||||
* This file is part of 0 A.D. | * This file is part of 0 A.D. | ||||||||||||||
* | * | ||||||||||||||
* 0 A.D. is free software: you can redistribute it and/or modify | * 0 A.D. is free software: you can redistribute it and/or modify | ||||||||||||||
* it under the terms of the GNU General Public License as published by | * it under the terms of the GNU General Public License as published by | ||||||||||||||
* the Free Software Foundation, either version 2 of the License, or | * the Free Software Foundation, either version 2 of the License, or | ||||||||||||||
* (at your option) any later version. | * (at your option) any later version. | ||||||||||||||
* | * | ||||||||||||||
* 0 A.D. is distributed in the hope that it will be useful, | * 0 A.D. is distributed in the hope that it will be useful, | ||||||||||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||||||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||||||||||||
* GNU General Public License for more details. | * GNU General Public License for more details. | ||||||||||||||
* | * | ||||||||||||||
* You should have received a copy of the GNU General Public License | * You should have received a copy of the GNU General Public License | ||||||||||||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>. | * along with 0 A.D. If not, see <http://www.gnu.org/licenses/>. | ||||||||||||||
*/ | */ | ||||||||||||||
#include "precompiled.h" | #include "precompiled.h" | ||||||||||||||
#include "SavedGame.h" | #include "SavedGame.h" | ||||||||||||||
#include "graphics/GameView.h" | #include "graphics/GameView.h" | ||||||||||||||
#include "gui/GUIManager.h" | |||||||||||||||
#include "i18n/L10n.h" | #include "i18n/L10n.h" | ||||||||||||||
#include "lib/allocators/shared_ptr.h" | #include "lib/allocators/shared_ptr.h" | ||||||||||||||
#include "lib/file/archive/archive_zip.h" | #include "lib/file/archive/archive_zip.h" | ||||||||||||||
#include "lib/file/io/io.h" | #include "lib/file/io/io.h" | ||||||||||||||
#include "lib/timer.h" | |||||||||||||||
#include "lib/utf8.h" | #include "lib/utf8.h" | ||||||||||||||
#include "maths/Vector3D.h" | #include "maths/Vector3D.h" | ||||||||||||||
#include "ps/CLogger.h" | #include "ps/CLogger.h" | ||||||||||||||
#include "ps/Filesystem.h" | #include "ps/Filesystem.h" | ||||||||||||||
#include "ps/Game.h" | #include "ps/Game.h" | ||||||||||||||
#include "ps/Mod.h" | #include "ps/Mod.h" | ||||||||||||||
#include "ps/Pyrogenesis.h" | #include "ps/Pyrogenesis.h" | ||||||||||||||
#include "scriptinterface/Object.h" | #include "scriptinterface/Object.h" | ||||||||||||||
#include "scriptinterface/JSON.h" | #include "scriptinterface/JSON.h" | ||||||||||||||
#include "scriptinterface/StructuredClone.h" | #include "scriptinterface/StructuredClone.h" | ||||||||||||||
#include "simulation2/Simulation2.h" | #include "simulation2/Simulation2.h" | ||||||||||||||
#include "simulation2/system/TurnManager.h" | |||||||||||||||
#include <sstream> | |||||||||||||||
#include <string> | |||||||||||||||
// TODO: we ought to check version numbers when loading files | // TODO: we ought to check version numbers when loading files | ||||||||||||||
static Status LoadQuickSaveArchive(const ScriptRequest &rq, std::string& savedState, JS::MutableHandleValue metadata); | |||||||||||||||
static Status IsQuickSaveFromThisGame(const ScriptRequest &rq, JS::HandleValue quickSaveMetadata, JS::HandleValue gameMetaData); | |||||||||||||||
static Status GetQuickSaveMatchID(const ScriptRequest &rq, std::wstring& savedMatchID, JS::HandleValue quickSaveMetadata); | |||||||||||||||
static Status GetCurrentGameMatchID(const ScriptRequest &rq, std::wstring& matchID, JS::HandleValue gameMetadata); | |||||||||||||||
Status SavedGames::SavePrefix(const CStrW& prefix, const CStrW& description, CSimulation2& simulation, const Script::StructuredClone& guiMetadataClone) | Status SavedGames::SavePrefix(const CStrW& prefix, const CStrW& description, CSimulation2& simulation, const Script::StructuredClone& guiMetadataClone) | ||||||||||||||
{ | { | ||||||||||||||
// Determine the filename to save under | // Determine the filename to save under | ||||||||||||||
const VfsPath basenameFormat(L"saves/" + prefix + L"-%04d"); | const VfsPath basenameFormat(L"saves/" + prefix + L"-%04d"); | ||||||||||||||
const VfsPath filenameFormat = basenameFormat.ChangeExtension(L".0adsave"); | const VfsPath filenameFormat = basenameFormat.ChangeExtension(L".0adsave"); | ||||||||||||||
VfsPath filename; | VfsPath filename; | ||||||||||||||
// Don't make this a static global like NextNumberedFilename expects, because | // Don't make this a static global like NextNumberedFilename expects, because | ||||||||||||||
▲ Show 20 Lines • Show All 249 Lines • ▼ Show 20 Lines | bool SavedGames::DeleteSavedGame(const std::wstring& name) | ||||||||||||||
// Delete actual file | // Delete actual file | ||||||||||||||
if (wunlink(realpath) != 0) | if (wunlink(realpath) != 0) | ||||||||||||||
return false; // Error | return false; // Error | ||||||||||||||
// Successfully deleted file | // Successfully deleted file | ||||||||||||||
return true; | return true; | ||||||||||||||
} | } | ||||||||||||||
Status SavedGames::QuickSave(CSimulation2& simulation, const Script::StructuredClone& GUIMetadataClone) | |||||||||||||||
{ | |||||||||||||||
return Save(L"quicksave", L"quicksave", simulation, GUIMetadataClone); | |||||||||||||||
} | |||||||||||||||
Status SavedGames::QuickLoad(CSimulation2& simulation) | |||||||||||||||
{ | |||||||||||||||
TIMER(L"QuickLoad"); | |||||||||||||||
ScriptRequest rq(simulation.GetScriptInterface()); | |||||||||||||||
phosit: I don't like functions doing multiple things. You could extract some parts… | |||||||||||||||
std::string savedState; | |||||||||||||||
JS::RootedValue quickSaveMetadata(rq.cx); | |||||||||||||||
Done Inline Actions#include <string> Stan: #include <string> | |||||||||||||||
RETURN_STATUS_FROM_CALLBACK(LoadQuickSaveArchive(rq, savedState, &quickSaveMetadata)); | |||||||||||||||
JS::RootedValue currentGameMetadata(rq.cx, simulation.GetInitAttributes()); | |||||||||||||||
RETURN_STATUS_FROM_CALLBACK(IsQuickSaveFromThisGame(rq, quickSaveMetadata, currentGameMetadata)); | |||||||||||||||
std::stringstream stream(savedState); | |||||||||||||||
if (!simulation.DeserializeState(stream)) | |||||||||||||||
return ERR::FAIL; | |||||||||||||||
g_Game->GetTurnManager()->RewindTimeWarp(); | |||||||||||||||
// Provide a copy, so that GUI components don't have to clone to get mutable objects | |||||||||||||||
JS::RootedValue quickSaveMetadataClone(rq.cx, Script::DeepCopy(rq, quickSaveMetadata)); | |||||||||||||||
JS::RootedValueArray<1> paramData(rq.cx); | |||||||||||||||
paramData[0].set(quickSaveMetadataClone); | |||||||||||||||
Done Inline ActionsEach GetProperty might fail. vladislavbelov: Each `GetProperty` might fail. | |||||||||||||||
CStr EventNameSavegameLoaded = "SavegameLoaded"; | |||||||||||||||
g_GUI->SendEventToAll(EventNameSavegameLoaded, paramData); | |||||||||||||||
return INFO::OK; | |||||||||||||||
} | |||||||||||||||
static Status LoadQuickSaveArchive(const ScriptRequest &rq, std::string& savedState, JS::MutableHandleValue metadata) | |||||||||||||||
{ | |||||||||||||||
Status status = SavedGames::Load(L"quicksave", rq.GetScriptInterface(), metadata, savedState); | |||||||||||||||
return status == ERR::FILE_NOT_FOUND ? INFO::CANNOT_HANDLE : status; | |||||||||||||||
} | |||||||||||||||
Done Inline Actions#include <sstream> Stan: #include <sstream> | |||||||||||||||
static Status IsQuickSaveFromThisGame(const ScriptRequest &rq, JS::HandleValue quickSaveMetadata, JS::HandleValue gameMetadata) | |||||||||||||||
Done Inline Actions
Stan: | |||||||||||||||
{ | |||||||||||||||
std::wstring savedMatchID; | |||||||||||||||
RETURN_STATUS_IF_ERR(GetQuickSaveMatchID(rq, savedMatchID, quickSaveMetadata)); | |||||||||||||||
std::wstring matchID; | |||||||||||||||
RETURN_STATUS_IF_ERR(GetCurrentGameMatchID(rq, matchID, gameMetadata)); | |||||||||||||||
return matchID.compare(savedMatchID) == 0 ? INFO::OK : INFO::CANNOT_HANDLE; | |||||||||||||||
} | |||||||||||||||
static Status GetQuickSaveMatchID(const ScriptRequest &rq, std::wstring& savedMatchID, JS::HandleValue quickSaveMetadata) | |||||||||||||||
{ | |||||||||||||||
JS::RootedValue gameInitAttributes(rq.cx); | |||||||||||||||
return Script::GetProperty(rq, quickSaveMetadata, "initAttributes", &gameInitAttributes) && | |||||||||||||||
Done Inline Actions
Stan: | |||||||||||||||
Script::GetProperty(rq, gameInitAttributes, "matchID", savedMatchID) ? INFO::OK : ERR::FAIL; | |||||||||||||||
} | |||||||||||||||
static Status GetCurrentGameMatchID(const ScriptRequest &rq, std::wstring& matchID, JS::HandleValue gameMetadata) | |||||||||||||||
{ | |||||||||||||||
return Script::GetProperty(rq, gameMetadata, "matchID", matchID) ? INFO::OK : ERR::FAIL; | |||||||||||||||
} | |||||||||||||||
Done Inline Actions
Stan: |
Wildfire Games · Phabricator
I don't like functions doing multiple things. You could extract some parts: LoadQuickSaveArchive, GetMatchIDOfQuicksave, GetMatchIDOfCurrentGame.
If you make them static thous will be inlined and there is no overhead.