2021-02-06 17:24:47 +00:00
|
|
|
#include "download_cheats_page.hpp"
|
|
|
|
#include "constants.hpp"
|
2021-02-10 16:28:47 +00:00
|
|
|
#include "download.hpp"
|
|
|
|
#include "utils.hpp"
|
|
|
|
#include "current_cfw.hpp"
|
|
|
|
#include <fstream>
|
|
|
|
#include <filesystem>
|
2021-02-06 17:24:47 +00:00
|
|
|
|
|
|
|
namespace i18n = brls::i18n;
|
|
|
|
using namespace i18n::literals;
|
|
|
|
using json = nlohmann::json;
|
|
|
|
|
|
|
|
DownloadCheatsPage::DownloadCheatsPage(uint64_t tid) : AppletFrame(true, true)
|
|
|
|
{
|
|
|
|
this->setTitle("menus/cheat_menu"_i18n );
|
|
|
|
|
2021-02-10 17:41:13 +00:00
|
|
|
std::string bid = "";
|
|
|
|
if(running_cfw == ams)
|
|
|
|
bid = GetBuilID(tid);
|
|
|
|
if(bid == "")
|
|
|
|
bid = GetBuilIDFromFile(tid);
|
|
|
|
|
2021-02-06 17:24:47 +00:00
|
|
|
list = new brls::List();
|
|
|
|
label = new brls::Label(
|
|
|
|
brls::LabelStyle::DESCRIPTION,
|
|
|
|
"menus/download_cheatslips"_i18n + "\n\uE016 Build ID: " + bid,
|
|
|
|
true
|
|
|
|
);
|
|
|
|
list->addView(label);
|
|
|
|
|
|
|
|
if(bid != "") {
|
|
|
|
std::vector<std::string> headers = {"accept: application/json"};
|
2021-02-06 21:00:25 +00:00
|
|
|
json cheatsInfo = getRequest((CHEATSLIPS_CHEATS_URL + formatApplicationId(tid) + "/" + bid).c_str(), headers);
|
2021-02-06 17:24:47 +00:00
|
|
|
if(cheatsInfo.find("cheats") != cheatsInfo.end()) {
|
|
|
|
for (const auto& p : cheatsInfo["cheats"].items()) {
|
|
|
|
json cheat = p.value();
|
2021-02-16 17:03:14 +00:00
|
|
|
listItem = new::brls::ToggleListItem(GetCheatsTitle(cheat), 0, "", "\uE016", "o");
|
2021-02-06 17:24:47 +00:00
|
|
|
listItem->registerAction("menus/see_more"_i18n , brls::Key::Y, [this, cheat] {
|
|
|
|
if(cheat.find("titles") != cheat.end()) {
|
2021-02-09 15:27:18 +00:00
|
|
|
ShowCheatsContent(cheat["titles"]);
|
2021-02-06 17:24:47 +00:00
|
|
|
}
|
|
|
|
return true;
|
|
|
|
});
|
|
|
|
toggles.push_back(std::make_pair(listItem, cheat["id"]));
|
|
|
|
list->addView(listItem);
|
|
|
|
}
|
2021-02-10 17:50:52 +00:00
|
|
|
list->addView(new brls::ListItemGroupSpacing(true));
|
2021-02-06 17:24:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-10 17:41:13 +00:00
|
|
|
else {
|
|
|
|
label = new brls::Label(
|
|
|
|
brls::LabelStyle::REGULAR,
|
|
|
|
"menus/bid_not_found"_i18n,
|
|
|
|
true
|
|
|
|
);
|
|
|
|
list->addView(label);
|
|
|
|
}
|
|
|
|
|
|
|
|
list->registerAction((bid != "") ? "menus/download_cheats"_i18n : "brls/hints/back"_i18n, brls::Key::B, [this, bid, tid] {
|
2021-02-06 17:24:47 +00:00
|
|
|
std::vector<int> ids;
|
|
|
|
for(auto& e : toggles){
|
|
|
|
if(e.first->getToggleState()){
|
|
|
|
ids.push_back(e.second);
|
|
|
|
}
|
|
|
|
}
|
2021-02-06 18:42:14 +00:00
|
|
|
int error = 0;
|
2021-02-06 17:24:47 +00:00
|
|
|
if(!ids.empty()) {
|
|
|
|
json token;
|
|
|
|
std::ifstream tokenFile(TOKEN_PATH);
|
|
|
|
tokenFile >> token;
|
|
|
|
tokenFile.close();
|
|
|
|
std::vector<std::string> headers = {"accept: application/json"};
|
|
|
|
if(token.find("token") != token.end()) {
|
|
|
|
headers.push_back("X-API-TOKEN: " + token["token"].get<std::string>());
|
|
|
|
}
|
|
|
|
json cheatsInfo = getRequest(("https://www.cheatslips.com/api/v1/cheats/" + formatApplicationId(tid) + "/" + bid).c_str(), headers);
|
|
|
|
if(cheatsInfo.find("cheats") != cheatsInfo.end()) {
|
|
|
|
for (const auto& p : cheatsInfo["cheats"].items()) {
|
|
|
|
if(std::find(ids.begin(), ids.end(), p.value()["id"]) != ids.end()) {
|
2021-02-06 18:42:14 +00:00
|
|
|
if(p.value()["content"].get<std::string>() == "Quota exceeded for today !"){
|
|
|
|
error = 1;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
WriteCheats(tid, bid, p.value()["content"]);
|
|
|
|
}
|
2021-02-06 17:24:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
2021-02-06 18:42:14 +00:00
|
|
|
error = 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(error != 0){
|
|
|
|
brls::Dialog* dialog;
|
|
|
|
switch(error){
|
|
|
|
case 1:
|
|
|
|
dialog = new brls::Dialog("menus/quota_cheatslips"_i18n);
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
dialog = new brls::Dialog("menus/couldnt_dl_cheats"_i18n);
|
|
|
|
break;
|
|
|
|
}
|
2021-02-06 17:24:47 +00:00
|
|
|
brls::GenericEvent::Callback callback = [dialog](brls::View* view) {
|
|
|
|
dialog->close();
|
|
|
|
};
|
|
|
|
dialog->addButton("menus/Ok_button"_i18n , callback);
|
|
|
|
dialog->setCancelable(true);
|
|
|
|
dialog->open();
|
|
|
|
}
|
|
|
|
}
|
2021-02-15 14:19:49 +00:00
|
|
|
if(error == 0) {
|
|
|
|
/* brls::Dialog* dialog = new brls::Dialog("menus/cheatslips_success"_i18n);
|
|
|
|
bool dialogResult = false;
|
|
|
|
bool result = false;
|
|
|
|
brls::GenericEvent::Callback callback = [dialog, &dialogResult](brls::View* view) {
|
|
|
|
dialogResult = true;
|
|
|
|
dialog->close();
|
|
|
|
};
|
|
|
|
dialog->addButton("menus/Ok_button"_i18n , callback);
|
|
|
|
dialog->setCancelable(true);
|
|
|
|
dialog->open();
|
|
|
|
while(result == false){
|
|
|
|
usleep(1);
|
|
|
|
result = dialogResult;
|
|
|
|
}
|
|
|
|
dialogResult = false; */
|
|
|
|
brls::Application::popView();
|
|
|
|
}
|
2021-02-06 17:24:47 +00:00
|
|
|
return true;
|
|
|
|
});
|
|
|
|
|
|
|
|
del = new brls::ListItem("menus/delete_cheat"_i18n);
|
|
|
|
del->getClickEvent()->subscribe([this, tid, bid](brls::View* view) {
|
|
|
|
DeleteCheats(tid, bid);
|
|
|
|
brls::Dialog* dialog = new brls::Dialog("menus/All_done"_i18n);
|
|
|
|
brls::GenericEvent::Callback callback = [dialog](brls::View* view) {
|
|
|
|
dialog->close();
|
|
|
|
};
|
|
|
|
dialog->addButton("menus/Ok_button"_i18n , callback);
|
|
|
|
dialog->setCancelable(true);
|
|
|
|
dialog->open();
|
|
|
|
});
|
|
|
|
list->addView(del);
|
|
|
|
this->setContentView(list);
|
|
|
|
}
|
|
|
|
std::string DownloadCheatsPage::GetBuilID(uint64_t tid) {
|
2021-02-10 17:41:13 +00:00
|
|
|
static Service g_dmntchtSrv;
|
|
|
|
DmntCheatProcessMetadata metadata;
|
|
|
|
smGetService(&g_dmntchtSrv, "dmnt:cht");
|
|
|
|
serviceDispatch(&g_dmntchtSrv, 65003);
|
|
|
|
serviceDispatchOut(&g_dmntchtSrv, 65002, metadata);
|
|
|
|
serviceClose(&g_dmntchtSrv);
|
|
|
|
if(metadata.title_id == tid){
|
|
|
|
u8 buildID[0x20];
|
|
|
|
memcpy(buildID, metadata.main_nso_build_id, 0x20);
|
|
|
|
std::stringstream ss;
|
|
|
|
for (u8 i = 0; i < 8; i++)
|
|
|
|
ss << std::uppercase << std::hex << std::setfill('0') << std::setw(2) << (u16)buildID[i];
|
|
|
|
return ss.str();
|
|
|
|
}
|
|
|
|
else{
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string DownloadCheatsPage::GetBuilIDFromFile(uint64_t tid) {
|
2021-02-06 17:24:47 +00:00
|
|
|
NsApplicationContentMetaStatus *MetaSatus = new NsApplicationContentMetaStatus[100U];
|
|
|
|
s32 out;
|
|
|
|
nsListApplicationContentMetaStatus(tid, 0, MetaSatus, 100, &out);
|
|
|
|
u32 version = 0;
|
|
|
|
for(int i = 0; i < out ; i++){
|
|
|
|
if(version < MetaSatus[i].version) version = MetaSatus[i].version;
|
|
|
|
}
|
|
|
|
|
|
|
|
this->setFooterText("Game version: v" + std::to_string(version / 0x10000));
|
|
|
|
|
|
|
|
json lookupTable = getRequest(LOOKUP_TABLE_URL);
|
|
|
|
|
|
|
|
std::string tidstr = formatApplicationId(tid);
|
|
|
|
std::string versionstr = std::to_string(version);
|
|
|
|
if(lookupTable.find(tidstr) != lookupTable.end()) {
|
|
|
|
json buildIDs = lookupTable[tidstr];
|
|
|
|
if(buildIDs.find(versionstr) != buildIDs.end()) {
|
|
|
|
return buildIDs[versionstr];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string DownloadCheatsPage::GetCheatsTitle(json cheat) {
|
|
|
|
std::string res = "";
|
|
|
|
if(cheat.find("titles") != cheat.end()) {
|
|
|
|
for(auto& p : cheat["titles"]){
|
|
|
|
res += "[" + p.get<std::string>() + "]" + " - ";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
res.erase(res.length() - 3);
|
|
|
|
if(res.size() > 80){
|
2021-02-15 14:19:49 +00:00
|
|
|
res = res.substr(0, 79) + "\u2026";
|
2021-02-06 17:24:47 +00:00
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
void DownloadCheatsPage::WriteCheats(uint64_t tid, std::string bid, std::string cheatContent) {
|
|
|
|
std::string path;
|
|
|
|
std::string tidstr = formatApplicationId(tid);
|
2021-02-10 16:28:47 +00:00
|
|
|
switch(running_cfw){
|
2021-02-06 17:24:47 +00:00
|
|
|
case ams:
|
|
|
|
path = std::string(AMS_PATH) + std::string(CONTENTS_PATH);
|
|
|
|
break;
|
|
|
|
case rnx:
|
|
|
|
path = std::string(REINX_PATH) + std::string(CONTENTS_PATH);
|
|
|
|
break;
|
|
|
|
case sxos:
|
|
|
|
path = std::string(SXOS_PATH) + std::string(TITLES_PATH);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
path += tidstr + "/cheats/";
|
|
|
|
createTree(path);
|
|
|
|
path += bid + ".txt";
|
|
|
|
std::ofstream cheatFile;
|
|
|
|
cheatFile.open(path, std::ios::app);
|
2021-02-24 19:44:15 +00:00
|
|
|
cheatFile << "\n\n" << cheatContent;
|
2021-02-06 17:24:47 +00:00
|
|
|
std::ofstream updated;
|
|
|
|
updated.open(UPDATED_TITLES_PATH, std::ios::app);
|
|
|
|
updated << "\n" << tidstr;
|
|
|
|
}
|
|
|
|
|
|
|
|
void DownloadCheatsPage::DeleteCheats(uint64_t tid, std::string bid) {
|
|
|
|
std::string path;
|
2021-02-10 16:28:47 +00:00
|
|
|
switch(running_cfw){
|
2021-02-06 17:24:47 +00:00
|
|
|
case ams:
|
|
|
|
path = std::string(AMS_PATH) + std::string(CONTENTS_PATH);
|
|
|
|
break;
|
|
|
|
case rnx:
|
|
|
|
path = std::string(REINX_PATH) + std::string(CONTENTS_PATH);
|
|
|
|
break;
|
|
|
|
case sxos:
|
|
|
|
path = std::string(SXOS_PATH) + std::string(TITLES_PATH);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
std::filesystem::remove(path + formatApplicationId(tid) + "/cheats/" + bid + ".txt");
|
2021-02-09 15:27:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void DownloadCheatsPage::ShowCheatsContent(nlohmann::ordered_json titles) {
|
|
|
|
brls::AppletFrame* appView = new brls::AppletFrame(true, true);
|
|
|
|
brls::List* list = new brls::List();
|
|
|
|
brls::ListItem* listItem;
|
|
|
|
for(auto& p : titles){
|
|
|
|
listItem = new brls::ListItem(p.get<std::string>());
|
2021-02-09 15:43:03 +00:00
|
|
|
listItem->registerAction("", brls::Key::A, [this] {
|
|
|
|
return true;
|
|
|
|
});
|
2021-02-09 15:27:18 +00:00
|
|
|
list->addView(listItem);
|
|
|
|
}
|
|
|
|
appView->setContentView(list);
|
|
|
|
brls::PopupFrame::open("menus/cheat_cheat_content"_i18n, appView, "", "");
|
2021-02-06 17:24:47 +00:00
|
|
|
}
|