mirror of
https://github.com/J-D-K/JKSV.git
synced 2026-03-22 01:34:13 -05:00
209 lines
7.4 KiB
C++
209 lines
7.4 KiB
C++
#include "data/data.hpp"
|
|
#include "config.hpp"
|
|
#include "fs/fs.hpp"
|
|
#include "fslib.hpp"
|
|
#include "logger.hpp"
|
|
#include "strings.hpp"
|
|
#include <algorithm>
|
|
#include <array>
|
|
#include <switch.h>
|
|
#include <unordered_map>
|
|
#include <vector>
|
|
|
|
namespace
|
|
{
|
|
// This is easer to read imo
|
|
using UserIDPair = std::pair<AccountUid, data::User>;
|
|
// User vector to preserve order.
|
|
std::vector<UserIDPair> s_userVector;
|
|
// Map of Title info paired with its title/application
|
|
std::unordered_map<uint64_t, data::TitleInfo> s_titleInfoMap;
|
|
// Array of SaveDataSpaceIDs - SaveDataSpaceAll doesn't seem to work as it should...
|
|
constexpr std::array<FsSaveDataSpaceId, 7> SAVE_DATA_SPACE_ORDER = {FsSaveDataSpaceId_System,
|
|
FsSaveDataSpaceId_User,
|
|
FsSaveDataSpaceId_SdSystem,
|
|
FsSaveDataSpaceId_Temporary,
|
|
FsSaveDataSpaceId_SdUser,
|
|
FsSaveDataSpaceId_ProperSystem,
|
|
FsSaveDataSpaceId_SafeMode};
|
|
|
|
} // namespace
|
|
|
|
bool data::initialize(void)
|
|
{
|
|
// Switch can only have up to 8 accounts.
|
|
int totalAccounts = 0;
|
|
AccountUid accountIDs[8];
|
|
Result accError = accountListAllUsers(accountIDs, 8, &totalAccounts);
|
|
if (R_FAILED(accError))
|
|
{
|
|
logger::log("Error getting user list: 0x%X.", accError);
|
|
return false;
|
|
}
|
|
|
|
// Loop through and load all users found.
|
|
for (int i = 0; i < totalAccounts; i++)
|
|
{
|
|
data::User newUser(accountIDs[i], FsSaveDataType_Account);
|
|
s_userVector.push_back(std::make_pair(accountIDs[i], newUser));
|
|
}
|
|
|
|
// Need this for save data of deleted users. It does happen. This is where they are inserted.
|
|
// size_t userInsertPosition = s_userVector.size() - 1;
|
|
|
|
// "System" users.
|
|
constexpr AccountUid deviceID = {FsSaveDataType_Device};
|
|
constexpr AccountUid bcatID = {FsSaveDataType_Bcat};
|
|
constexpr AccountUid cacheID = {FsSaveDataType_Cache};
|
|
constexpr AccountUid systemID = {FsSaveDataType_System};
|
|
|
|
s_userVector.push_back(std::make_pair(deviceID, data::User(deviceID, "Device", "romfs:/Textures/SystemSaves.png", FsSaveDataType_Device)));
|
|
s_userVector.push_back(std::make_pair(bcatID, data::User(bcatID, "BCAT", "romfs:/Textures/BCAT.png", FsSaveDataType_Bcat)));
|
|
s_userVector.push_back(std::make_pair(cacheID, data::User(cacheID, "Cache", "romfs:/Textures/Cache.png", FsSaveDataType_Cache)));
|
|
s_userVector.push_back(std::make_pair(systemID, data::User(systemID, "System", "romfs:/Textures/SystemSaves.png", FsSaveDataType_System)));
|
|
|
|
NsApplicationRecord currentRecord = {0};
|
|
int entryCount = 0, entryOffset = 0;
|
|
while (R_SUCCEEDED(nsListApplicationRecord(¤tRecord, 1, entryOffset++, &entryCount)) && entryCount > 0)
|
|
{
|
|
s_titleInfoMap.emplace(std::make_pair(currentRecord.application_id, data::TitleInfo(currentRecord.application_id)));
|
|
}
|
|
|
|
for (int i = 0; i < 7; i++)
|
|
{
|
|
fslib::SaveInfoReader saveInfoReader(SAVE_DATA_SPACE_ORDER[i]);
|
|
if (!saveInfoReader.isOpen())
|
|
{
|
|
logger::log(fslib::getErrorString());
|
|
continue;
|
|
}
|
|
|
|
while (saveInfoReader.read())
|
|
{
|
|
FsSaveDataInfo &saveInfo = saveInfoReader.get();
|
|
|
|
// This will filter out the account system saves unless the config is set to show them.
|
|
if (!config::getByKey(config::keys::LIST_ACCOUNT_SYS_SAVES) && saveInfo.save_data_type == FsSaveDataType_System &&
|
|
saveInfo.uid != 0)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// Since JKSV uses fake users to support system type saves.
|
|
AccountUid accountID;
|
|
switch (saveInfo.save_data_type)
|
|
{
|
|
case FsSaveDataType_Bcat:
|
|
{
|
|
accountID = {FsSaveDataType_Bcat};
|
|
}
|
|
break;
|
|
|
|
case FsSaveDataType_Device:
|
|
{
|
|
accountID = {FsSaveDataType_Device};
|
|
}
|
|
break;
|
|
|
|
case FsSaveDataType_Cache:
|
|
{
|
|
accountID = {FsSaveDataType_Cache};
|
|
}
|
|
break;
|
|
|
|
default:
|
|
{
|
|
accountID = saveInfo.uid;
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (config::getByKey(config::keys::ONLY_LIST_MOUNTABLE) &&
|
|
!fslib::openSaveFileSystemWithSaveDataInfo(fs::DEFAULT_SAVE_MOUNT, saveInfo))
|
|
{
|
|
// Continue the loop since mounting failed.
|
|
continue;
|
|
}
|
|
fslib::closeFileSystem(fs::DEFAULT_SAVE_MOUNT);
|
|
|
|
// Find the user with the ID.
|
|
auto findUser = std::find_if(s_userVector.begin(), s_userVector.end(), [accountID](const UserIDPair &userPair) {
|
|
return accountID == userPair.second.getAccountID();
|
|
});
|
|
|
|
if (findUser == s_userVector.end())
|
|
{
|
|
// To do: Handle this like old JKSV did.
|
|
continue;
|
|
}
|
|
|
|
// This is for system save data since it has no application ID.
|
|
uint64_t applicationID = (saveInfo.save_data_type == FsSaveDataType_System || saveInfo.save_data_type == FsSaveDataType_SystemBcat)
|
|
? saveInfo.system_save_data_id
|
|
: saveInfo.application_id;
|
|
|
|
if (s_titleInfoMap.find(applicationID) == s_titleInfoMap.end())
|
|
{
|
|
s_titleInfoMap.emplace(std::make_pair(applicationID, data::TitleInfo(applicationID)));
|
|
}
|
|
|
|
PdmPlayStatistics playStats = {0};
|
|
Result pdmError = pdmqryQueryPlayStatisticsByApplicationIdAndUserAccountId(applicationID, saveInfo.uid, false, &playStats);
|
|
if (R_FAILED(pdmError))
|
|
{
|
|
// Logged, but not fatal.
|
|
logger::log("Error getting play stats for %016llX: 0x%X", applicationID, pdmError);
|
|
}
|
|
// Push it to user.
|
|
findUser->second.addData(saveInfo, playStats);
|
|
}
|
|
}
|
|
|
|
// Sort data for users.
|
|
for (auto &[accountID, user] : s_userVector)
|
|
{
|
|
user.sortData();
|
|
}
|
|
|
|
// Wew
|
|
return true;
|
|
}
|
|
|
|
void data::getUsers(std::vector<data::User *> &vectorOut)
|
|
{
|
|
vectorOut.clear();
|
|
for (auto &[accountID, userData] : s_userVector)
|
|
{
|
|
vectorOut.push_back(&userData);
|
|
}
|
|
}
|
|
|
|
data::TitleInfo *data::getTitleInfoByID(uint64_t applicationID)
|
|
{
|
|
if (s_titleInfoMap.find(applicationID) == s_titleInfoMap.end())
|
|
{
|
|
return nullptr;
|
|
}
|
|
return &s_titleInfoMap.at(applicationID);
|
|
}
|
|
|
|
std::unordered_map<uint64_t, data::TitleInfo> &data::getTitleInfoMap(void)
|
|
{
|
|
return s_titleInfoMap;
|
|
}
|
|
|
|
void data::getTitleInfoByType(FsSaveDataType saveType, std::vector<data::TitleInfo *> &vectorOut)
|
|
{
|
|
// Clear vector JIC
|
|
vectorOut.clear();
|
|
|
|
// Loop and push pointers
|
|
for (auto &[applicationID, titleInfo] : s_titleInfoMap)
|
|
{
|
|
if (titleInfo.hasSaveDataType(saveType))
|
|
{
|
|
vectorOut.push_back(&titleInfo);
|
|
}
|
|
}
|
|
}
|