mirror of https://github.com/zeldaret/botw.git
ksys/res: Add GameSaveData
This commit is contained in:
parent
92cd68c374
commit
911625ac23
|
@ -92284,20 +92284,20 @@
|
|||
0x000000710127a9b4,LowPrioThreadMgr::submitRequest,412,
|
||||
0x000000710127ac44,sub_710127AC44,112,
|
||||
0x000000710127acb4,sub_710127ACB4,92,
|
||||
0x000000710127ad10,sub_710127AD10,140,
|
||||
0x000000710127ad9c,sub_710127AD9C,164,
|
||||
0x000000710127ae40,Bgsvdata::File::forEachFlag,140,
|
||||
0x000000710127aecc,sub_710127AECC,204,
|
||||
0x000000710127af98,Bgsvdata::doCreate,1572,
|
||||
0x000000710127b5bc,Bgsvdata::cleanUp,156,
|
||||
0x000000710127b658,Bgsvdata::allocFileList,12,
|
||||
0x000000710127b664,Bgsvdata::addFile,112,
|
||||
0x000000710127b6d4,Bgsvdata::allocFileFlags,228,
|
||||
0x000000710127b7b8,Bgsvdata::copyFilesFrom,932,
|
||||
0x000000710127bb5c,Bgsvdata::FlagArray::sort,936,
|
||||
0x000000710127bf04,Bgsvdata::sort,64,
|
||||
0x000000710127bf44,Bgsvdata::dtor,160,
|
||||
0x000000710127bfe4,Bgsvdata::dtorDelete,168,
|
||||
0x000000710127ad10,sub_710127AD10,140,_ZN4ksys3res12GameSaveData4File11forEachFlagERKN4sead9Delegate1INS_7SaveMgrERKNS1_4FlagEEE
|
||||
0x000000710127ad9c,sub_710127AD9C,164,_ZN4ksys3res12GameSaveData4File11forEachFlagERKN4sead9Delegate1INS_7SaveMgrERKNS1_4FlagEEEii
|
||||
0x000000710127ae40,Bgsvdata::File::forEachFlag,140,_ZN4ksys3res12GameSaveData4File11forEachFlagERKN4sead9Delegate1INS_7SaveMgrERNS1_4FlagEEE
|
||||
0x000000710127aecc,sub_710127AECC,204,_ZNK4ksys3res12GameSaveData4File13findFlagIndexEj
|
||||
0x000000710127af98,Bgsvdata::doCreate,1572,_ZN4ksys3res12GameSaveData9doCreate_EPhjPN4sead4HeapE?
|
||||
0x000000710127b5bc,Bgsvdata::cleanUp,156,_ZN4ksys3res12GameSaveData8finalizeEv
|
||||
0x000000710127b658,Bgsvdata::allocFileList,12,_ZN4ksys3res12GameSaveData10allocFilesEiPN4sead4HeapE
|
||||
0x000000710127b664,Bgsvdata::addFile,112,_ZN4ksys3res12GameSaveData7addFileEjPN4sead4HeapE
|
||||
0x000000710127b6d4,Bgsvdata::allocFileFlags,228,_ZN4ksys3res12GameSaveData10allocFlagsEjiPN4sead4HeapE
|
||||
0x000000710127b7b8,Bgsvdata::copyFilesFrom,932,_ZN4ksys3res12GameSaveData8copyFromERKS1_PN4sead4HeapE
|
||||
0x000000710127bb5c,Bgsvdata::FlagArray::sort,936,_ZN4ksys3resL21sortGameSaveDataFlagsERN4sead10RingBufferINS0_12GameSaveData4FlagEEE?
|
||||
0x000000710127bf04,Bgsvdata::sort,64,_ZN4ksys3res12GameSaveData9sortFlagsEv
|
||||
0x000000710127bf44,Bgsvdata::dtor,160,_ZN4ksys3res12GameSaveDataD2Ev
|
||||
0x000000710127bfe4,Bgsvdata::dtorDelete,168,_ZN4ksys3res12GameSaveDataD0Ev
|
||||
0x000000710127c08c,sub_710127C08C,56,
|
||||
0x000000710127c0c4,sub_710127C0C4,92,
|
||||
0x000000710127c120,AutoGenFramework::a,144,
|
||||
|
|
Can't render this file because it is too large.
|
Binary file not shown.
Binary file not shown.
2
lib/sead
2
lib/sead
|
@ -1 +1 @@
|
|||
Subproject commit 13296d91839701e43afaf36b6f2c333295cc4170
|
||||
Subproject commit b11dae5d32def13f83425033bb5e80493c23f741
|
|
@ -138,6 +138,8 @@ target_sources(uking PRIVATE
|
|||
resResourceDrop.h
|
||||
resResourceGameData.cpp
|
||||
resResourceGameData.h
|
||||
resResourceGameSaveData.cpp
|
||||
resResourceGameSaveData.h
|
||||
resResourceGParamList.cpp
|
||||
resResourceGParamList.h
|
||||
resResourceLifeCondition.cpp
|
||||
|
|
|
@ -0,0 +1,207 @@
|
|||
#include "KingSystem/Resource/resResourceGameSaveData.h"
|
||||
#include <codec/seadHashCRC32.h>
|
||||
#include <prim/seadContainerIterator.h>
|
||||
#include "KingSystem/GameData/gdtManager.h"
|
||||
#include "KingSystem/Utils/Byaml.h"
|
||||
|
||||
namespace ksys::res {
|
||||
|
||||
void GameSaveData::File::forEachFlag(const sead::Delegate1<SaveMgr, const Flag&>& delegate) {
|
||||
for (const auto& flag : flags)
|
||||
delegate(flag);
|
||||
}
|
||||
|
||||
void GameSaveData::File::forEachFlag(const sead::Delegate1<SaveMgr, const Flag&>& delegate,
|
||||
s32 start, s32 end) {
|
||||
if (start == end)
|
||||
return;
|
||||
|
||||
for (auto it = flags.begin(start), it_end = flags.begin(end); it != it_end; ++it)
|
||||
delegate(*it);
|
||||
}
|
||||
|
||||
void GameSaveData::File::forEachFlag(const sead::Delegate1<SaveMgr, Flag&>& delegate) {
|
||||
for (auto& flag : flags)
|
||||
delegate(flag);
|
||||
}
|
||||
|
||||
s32 GameSaveData::File::findFlagIndex(u32 flag_name_hash) const {
|
||||
s32 a = 0;
|
||||
s32 b = flags.size() - 1;
|
||||
while (a < b) {
|
||||
const s32 m = (a + b) / 2;
|
||||
if (u32(flags[m].kv.name_hash) == flag_name_hash)
|
||||
return m;
|
||||
if (u32(flags[m].kv.name_hash) < flag_name_hash)
|
||||
a = m + 1;
|
||||
else
|
||||
b = m;
|
||||
}
|
||||
|
||||
if (u32(flags[a].kv.name_hash) == flag_name_hash)
|
||||
return a;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// NON_MATCHING: cNullChar is loaded too late (which throws off a lot of things) and Clang is
|
||||
// using a different register to access file->info
|
||||
void GameSaveData::doCreate_(u8* buffer, u32, sead::Heap*) {
|
||||
auto* heap = gdt::Manager::instance()->getSaveAreaHeap();
|
||||
al::ByamlIter root_iter{buffer};
|
||||
al::ByamlIter file_info_iter;
|
||||
al::ByamlIter save_info_iter;
|
||||
al::ByamlIter flags_iter;
|
||||
|
||||
{
|
||||
al::ByamlIter iter;
|
||||
if (root_iter.tryGetIterByKey(&iter, "file_list")) {
|
||||
iter.tryGetIterByIndex(&file_info_iter, 0);
|
||||
iter.tryGetIterByIndex(&flags_iter, 1);
|
||||
}
|
||||
al::ByamlIter iter2;
|
||||
if (root_iter.tryGetIterByKey(&iter2, "save_info"))
|
||||
iter2.tryGetIterByIndex(&save_info_iter, 0);
|
||||
}
|
||||
|
||||
mFiles.allocBuffer(1, heap);
|
||||
|
||||
mSaveInfo = new (heap) SaveInfo;
|
||||
save_info_iter.tryGetIntByKey(&mSaveInfo->revision, "revision");
|
||||
save_info_iter.tryGetIntByKey(&mSaveInfo->directory_num, "directory_num");
|
||||
save_info_iter.tryGetBoolByKey(&mSaveInfo->is_build_machine, "is_build_machine");
|
||||
|
||||
#ifdef MATCHING_HACK_NX_CLANG
|
||||
// This isn't required but makes the diff cleaner... cNullChar is loaded here in the original.
|
||||
*static_cast<volatile const char*>(&sead::SafeString::cNullChar);
|
||||
#endif
|
||||
|
||||
const auto num_flags = flags_iter.getSize();
|
||||
|
||||
auto* file = new (heap) File;
|
||||
file->name_hash = std::numeric_limits<int>::min();
|
||||
file->info = new (heap) FileInfo;
|
||||
|
||||
const char* file_name = "";
|
||||
file_info_iter.tryGetStringByKey(&file_name, "file_name");
|
||||
auto* file_name_str = new (heap) sead::FixedSafeString<64>;
|
||||
file_name_str->copy(file_name);
|
||||
file->info->name = file_name_str->cstr();
|
||||
|
||||
file_info_iter.tryGetBoolByKey(&file->info->is_common, "IsCommon");
|
||||
file_info_iter.tryGetBoolByKey(&file->info->is_common_at_same_account, "IsCommonAtSameAccount");
|
||||
file_info_iter.tryGetBoolByKey(&file->info->is_save_secure_code, "IsSaveSecureCode");
|
||||
|
||||
if (num_flags > 0) {
|
||||
file->flags.allocBuffer(num_flags, heap);
|
||||
for (s32 i = 0; i < num_flags; ++i) {
|
||||
al::ByamlIter iter;
|
||||
if (!flags_iter.tryGetIterByIndex(&iter, i))
|
||||
continue;
|
||||
|
||||
Flag flag;
|
||||
iter.tryGetIntByKey(&flag.kv.name_hash, "HashValue");
|
||||
const char* data_name = "";
|
||||
iter.tryGetStringByKey(&data_name, "DataName");
|
||||
const s32 data_name_hash = sead::HashCRC32::calcStringHash(data_name);
|
||||
if (flag.kv.name_hash != data_name_hash)
|
||||
flag.kv.name_hash = data_name_hash;
|
||||
|
||||
file->flags.pushBack(flag);
|
||||
}
|
||||
}
|
||||
|
||||
mFiles.pushBack(file);
|
||||
}
|
||||
|
||||
void GameSaveData::finalize() {
|
||||
if (mSaveInfo)
|
||||
delete mSaveInfo;
|
||||
|
||||
if (mFiles.isBufferReady()) {
|
||||
for (auto it = mFiles.begin(), end = mFiles.end(); it != end; ++it) {
|
||||
it->flags.freeBuffer();
|
||||
delete &*it;
|
||||
[[maybe_unused]] auto next = it;
|
||||
++next;
|
||||
}
|
||||
mFiles.freeBuffer();
|
||||
}
|
||||
}
|
||||
|
||||
void GameSaveData::allocFiles(s32 count, sead::Heap* heap) {
|
||||
mFiles.allocBuffer(count, heap);
|
||||
}
|
||||
|
||||
void GameSaveData::addFile(u32 hash, sead::Heap* heap) {
|
||||
if (!mFiles.isBufferReady())
|
||||
return;
|
||||
|
||||
auto* file = new (heap) File;
|
||||
file->info = nullptr;
|
||||
file->name_hash = hash;
|
||||
mFiles.pushBack(file);
|
||||
}
|
||||
|
||||
std::optional<GameSaveData::File*> GameSaveData::getFile(u32 hash) const {
|
||||
for (auto& file : mFiles)
|
||||
if (file.name_hash == hash)
|
||||
return &file;
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
void GameSaveData::allocFlags(u32 file_name_hash, s32 count, sead::Heap* heap) {
|
||||
if (!mFiles.isBufferReady())
|
||||
return;
|
||||
|
||||
auto file = getFile(file_name_hash);
|
||||
if (!file)
|
||||
return;
|
||||
|
||||
(*file)->flags.allocBuffer(count, heap);
|
||||
}
|
||||
|
||||
void GameSaveData::copyFrom(const GameSaveData& src, sead::Heap* heap) {
|
||||
if (!mSaveInfo && src.mSaveInfo) {
|
||||
mSaveInfo = new (heap) SaveInfo;
|
||||
*mSaveInfo = *src.mSaveInfo;
|
||||
}
|
||||
|
||||
if (!mFiles.isBufferReady())
|
||||
return;
|
||||
|
||||
auto it = mFiles.begin(), end = mFiles.end();
|
||||
const File& src_file = *src.mFiles[0];
|
||||
for (; it != end; ++it) {
|
||||
const u32 other_hash = sead::HashCRC32::calcStringHash(src_file.info->name);
|
||||
if (it->name_hash != other_hash)
|
||||
continue;
|
||||
|
||||
if (it->info == nullptr) {
|
||||
it->info = new (heap) FileInfo;
|
||||
auto* target = it->info;
|
||||
*target = *src_file.info;
|
||||
}
|
||||
|
||||
for (auto flag = src_file.flags.begin(), e = src_file.flags.end(); flag != e; ++flag)
|
||||
it->flags.pushBack(*flag);
|
||||
}
|
||||
}
|
||||
|
||||
[[gnu::noinline]] static void sortGameSaveDataFlags(sead::RingBuffer<GameSaveData::Flag>& flags) {
|
||||
const auto wrapper = sead::stdIterator(flags);
|
||||
std::sort(wrapper.begin(), wrapper.end(),
|
||||
[](const GameSaveData::Flag& lhs, const GameSaveData::Flag& rhs) {
|
||||
return lhs.kv.name_hash < rhs.kv.name_hash;
|
||||
});
|
||||
}
|
||||
|
||||
void GameSaveData::sortFlags() {
|
||||
if (!mFiles.isBufferReady())
|
||||
return;
|
||||
|
||||
for (auto& file : mFiles)
|
||||
sortGameSaveDataFlags(file.flags);
|
||||
}
|
||||
|
||||
} // namespace ksys::res
|
|
@ -0,0 +1,109 @@
|
|||
#pragma once
|
||||
|
||||
#include <container/seadPtrArray.h>
|
||||
#include <container/seadRingBuffer.h>
|
||||
#include <limits>
|
||||
#include <optional>
|
||||
#include <prim/seadDelegate.h>
|
||||
#include <prim/seadSafeString.h>
|
||||
#include <resource/seadResource.h>
|
||||
#include "KingSystem/GameData/gdtFlag.h"
|
||||
#include "KingSystem/Utils/Types.h"
|
||||
|
||||
namespace ksys {
|
||||
class SaveMgr;
|
||||
}
|
||||
|
||||
namespace ksys::res {
|
||||
|
||||
class GameSaveData : public sead::DirectResource {
|
||||
public:
|
||||
struct SaveInfo {
|
||||
SaveInfo() = default;
|
||||
SaveInfo(const SaveInfo& other) { *this = other; }
|
||||
SaveInfo& operator=(const SaveInfo& other) {
|
||||
revision = other.revision;
|
||||
directory_num = other.directory_num;
|
||||
is_build_machine = other.is_build_machine;
|
||||
return *this;
|
||||
}
|
||||
|
||||
s32 revision = 0;
|
||||
s32 directory_num = 0;
|
||||
bool is_build_machine = false;
|
||||
};
|
||||
KSYS_CHECK_SIZE_NX150(SaveInfo, 0xc);
|
||||
|
||||
struct FileInfo {
|
||||
FileInfo() = default;
|
||||
FileInfo(const FileInfo& other) { *this = other; }
|
||||
FileInfo& operator=(const FileInfo& other) {
|
||||
name = other.name;
|
||||
is_common = other.is_common;
|
||||
is_common_at_same_account = other.is_common_at_same_account;
|
||||
is_save_secure_code = other.is_save_secure_code;
|
||||
return *this;
|
||||
}
|
||||
|
||||
sead::FixedSafeString<32> name = sead::SafeString::cEmptyString;
|
||||
bool is_common = false;
|
||||
bool is_common_at_same_account = false;
|
||||
bool is_save_secure_code = false;
|
||||
};
|
||||
KSYS_CHECK_SIZE_NX150(FileInfo, 0x40);
|
||||
|
||||
struct Flag {
|
||||
Flag() = default;
|
||||
Flag(const Flag& other) { *this = other; }
|
||||
Flag& operator=(const Flag& other) {
|
||||
_8 = other._8;
|
||||
kv = other.kv;
|
||||
type = other.type;
|
||||
return *this;
|
||||
}
|
||||
|
||||
struct KeyValue {
|
||||
s32 name_hash = std::numeric_limits<int>::min();
|
||||
s32 value = std::numeric_limits<int>::min();
|
||||
};
|
||||
KeyValue kv;
|
||||
u32 _8 = 0;
|
||||
gdt::FlagType type = gdt::FlagType::Invalid;
|
||||
};
|
||||
KSYS_CHECK_SIZE_NX150(Flag, 0x10);
|
||||
|
||||
struct File {
|
||||
void forEachFlag(const sead::Delegate1<SaveMgr, const Flag&>& delegate);
|
||||
void forEachFlag(const sead::Delegate1<SaveMgr, const Flag&>& delegate, s32 start, s32 end);
|
||||
void forEachFlag(const sead::Delegate1<SaveMgr, Flag&>& delegate);
|
||||
s32 findFlagIndex(u32 flag_name_hash) const;
|
||||
|
||||
u32 name_hash = std::numeric_limits<int>::min();
|
||||
FileInfo* info = nullptr;
|
||||
sead::RingBuffer<Flag> flags;
|
||||
};
|
||||
KSYS_CHECK_SIZE_NX150(File, 0x28);
|
||||
|
||||
GameSaveData() = default;
|
||||
~GameSaveData() override { finalize(); }
|
||||
|
||||
void finalize();
|
||||
|
||||
void allocFiles(s32 count, sead::Heap* heap);
|
||||
void addFile(u32 hash, sead::Heap* heap);
|
||||
std::optional<File*> getFile(u32 hash) const;
|
||||
void allocFlags(u32 file_name_hash, s32 count, sead::Heap* heap);
|
||||
void copyFrom(const GameSaveData& src, sead::Heap* heap);
|
||||
void sortFlags();
|
||||
|
||||
const sead::PtrArray<File>& getFiles() const { return mFiles; }
|
||||
|
||||
private:
|
||||
void doCreate_(u8* buffer, u32 size, sead::Heap* heap) override;
|
||||
|
||||
SaveInfo* mSaveInfo = nullptr;
|
||||
sead::PtrArray<File> mFiles;
|
||||
};
|
||||
KSYS_CHECK_SIZE_NX150(GameSaveData, 0x38);
|
||||
|
||||
} // namespace ksys::res
|
Loading…
Reference in New Issue