#include "xsteam_ex.h" #include #include void xsteam_init_opts() { // current dir ex_base_exe_path = QDir::currentPath(); // current dir+/ ex_base_exe_ex = ex_base_exe_path + QStringLiteral("/"); // current dir+/save ex_save_path = ex_base_exe_path + QStringLiteral("/save"); // current dir+/save/ ex_save_path_ex = ex_save_path + QStringLiteral("/"); xsteam_data_unserialize(); if (_data.s_data.size() > 0) { for (auto x : _data.s_data) { xsteam_branch_tag_data_read(x.src_name); } } } void xsteam_vdf_free_dir_file(UidData u_data) { } void xsteam_git2_error_check(int error) { if (error != 0) { const git_error *err = git_error_last(); if (err) { printf("ERROR %d: %s\n", err->klass, err->message); } else { printf("ERROR %d: no detailed info\n", error); } } } void xsteam_msg_tip(QWidget *parent, QString tipInfo) { UNUSED(parent); QMessageBox::information(nullptr, "TIP", tipInfo); } void xsteam_msg_error(QWidget *parent, QString tipInfo) { UNUSED(parent); QMessageBox::information(nullptr, "ERROR", tipInfo); } bool xsteam_msg_select(QWidget *parent, QString tipText) { QMessageBox *msgBox = nullptr; if (msgBox != nullptr) { delete msgBox; msgBox = nullptr; } msgBox = new QMessageBox(parent); msgBox->setWindowModality(Qt::WindowModal); msgBox->setAttribute(Qt::WA_DeleteOnClose); msgBox->setWindowFlags(msgBox->windowFlags() | Qt::WindowStaysOnTopHint); msgBox->setInformativeText(tipText); msgBox->setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel); msgBox->setStyleSheet("QLabel{" "qproperty-alignment:AlignHCenter;" "min-width: 400px;" "min-height: 20px; " "}"); int msgRet = msgBox->exec(); if (msgRet == QMessageBox::Ok) { return true; } return false; } void xsteam_branch_tag_data_read(std::string _src_name) { QString save_file_str = ex_save_path_ex + "tags_" + QString::fromStdString(_src_name) + ".data"; if (!QFile(save_file_str).exists()) { return; } _data.s_ex_data[_src_name].clear(); std::ifstream file(save_file_str.toStdString(), std::ios::binary); if (!file.is_open()) { qDebug() << "Failed to open file: " << save_file_str; } std::string line; while (std::getline(file, line)) { // qDebug() << "Line_Branch_Tag:" << QString::fromStdString(line); _data.s_ex_data[_src_name].push_back(line); } file.close(); } vdf::object xsteam_vdf_read(QString vdf_path) { std::basic_ifstream _T_File(vdf_path.toStdString(), std::ios::in); if (!_T_File.is_open()) { throw std::runtime_error("Failed to open file: " + vdf_path.toStdString()); } std::stringstream buffer; buffer << _T_File.rdbuf(); std::string vdf_str = buffer.str(); vdf::object vdf_data; bool ok = false; vdf_data = vdf::read(vdf_str.begin(), vdf_str.end(), &ok); return vdf_data; } void xsteam_vdf_write(QString vdf_file, vdf::object &vdf_data) { std::ofstream _T_W_File(vdf_file.toStdString().c_str()); std::unordered_map, std::shared_ptr>> _childs; std::unordered_map, std::basic_string> _attribs; for (auto x : vdf_data.childs) { if (x.first == "Software") { _childs.emplace(x.first, x.second); } else if (x.first == "streaming") { _childs.emplace(x.first, x.second); } else if (x.first == "Music") { _childs.emplace(x.first, x.second); } else if (x.first == "AuthorizedDevice") { _childs.emplace(x.first, x.second); } vdf_data.childs.erase(x.first); } for (auto u : vdf_data.attribs) { if (u.first == "SDL_GamepadBind") { vdf_data.attribs.erase(u.first); } } vdf_data.childs.swap(_childs); vdf_data.attribs.swap(_attribs); vdf::write(_T_W_File, vdf_data); } // 从拉取的库中读取key的信息以std::map类型返回 void xsteam_vdf_read_key(vdf::object vdf_data, UidData &u_data) { std::cout << vdf_data.name << std::endl; std::map keys; u_data.uid_key.clear(); for (auto &k : vdf_data.childs) { std::string u_id = k.first; std::string u_key = k.second->attribs.find("DecryptionKey")->second; // 游戏UID depots的key qDebug() << QString::fromStdString(u_id) << ":" << QString::fromStdString(u_key); u_data.uid_key.insert(std::pair(u_id, u_key)); } } // 读取指定uid目录下的文件名 void xsteam_vdf_manifest_name(QString uid_dir, UidData &u_data) { QDir _uid_dir(uid_dir); QStringList manifest_list = _uid_dir.entryList(QStringList() << "*.manifest", QDir::Files); u_data.manifest.clear(); for (auto &x : manifest_list) { u_data.manifest.push_back(x.toStdString()); } } void xsteam_vdf_manifest_move(UidData &u_data) { // vdf manifest dir str QString src_manifest_dir_str = ex_base_exe_ex + QString::fromStdString(u_data.uid); // steam steamtools dir QString steam_tools_dir_depotcache_str = QString::fromStdString(_data.x_config.steam_dir) + "/depotcache"; for (auto f : u_data.manifest) { qDebug() << f.c_str(); // src manifest file path str QString src_manifest_file_str = src_manifest_dir_str + "/" + QString::fromStdString(f); // src QFile object if (QDir(src_manifest_dir_str).exists() && QFile(src_manifest_file_str).exists() && QDir(steam_tools_dir_depotcache_str).exists()) { QString dest_manifest_file_str = steam_tools_dir_depotcache_str + "/" + QString::fromStdString(f); QFile::copy(src_manifest_file_str, dest_manifest_file_str); } else { return; } } } void xsteam_vdf_edit(vdf::object, std::map data, VDF_EDIT_MODE edit_mode) { if (edit_mode == VDF_EDIT_MODE::ADD) { } } // curl get steam id info to _data bool xsteam_curl_steam_id_app_info(UidData &u_data) { xsteam_curl *_x_curl = new xsteam_curl(); auto info_str = _x_curl->get_steam_id_info(_data.x_config.steam_api_url, u_data.uid); delete _x_curl; _x_curl = nullptr; if (info_str == "error" || info_str == "") { return false; } json info_json; try { info_json = json::parse(info_str); } catch (json::parse_error &e) { std::cerr << "解析错误:" << e.what() << std::endl; std::cerr << "位置:字符索引 " << e.byte << std::endl; return false; } qDebug() << QString::fromStdString(info_json.dump(4)); for (auto &root_data : info_json.items()) { auto node_data = root_data.value().at("data").items(); for (auto &data : node_data) { if (data.value().is_string()) { if (data.key() == "name") { u_data.name = data.value(); } } if (data.value().is_array()) { if (data.key() == "dlc") { if (data.value().size() > 0) { u_data.r_dlc.clear(); for (auto x : data.value()) { u_data.r_dlc.push_back(x.dump()); } } } } } } if (u_data.name != "") { //_data.u_data.push_back(u_data); return true; } return false; } // 读取xsteam软件保存在save目录下的data.json并且反序列化读取到全局变量内 void xsteam_data_unserialize() { QString save_file = ex_save_path_ex + "data.json"; if (!QDir(ex_save_path).exists()) { QDir().mkdir(ex_save_path); } if (QFile(save_file).exists()) { QFile _save_file(save_file); _save_file.open(QIODevice::ReadOnly | QIODevice::Text); std::string temp_str = _save_file.readAll().toStdString(); _save_file.close(); json j3 = json::parse(temp_str); if (j3 == nullptr) { return; } for (auto &k : j3.items()) { // 托管数据服务器列表反序列化 if (k.value().is_object() && k.key() == "src_data") { for (auto &u : k.value().items()) { SrcData _src_data = {}; _src_data.src_name = u.value().at("src_name"); if (u.value().at("src_type") == 0) { _src_data.src_type = GIT_MODE::BRANCH; } else { _src_data.src_type = GIT_MODE::TAG; } _src_data.src_url = u.value().at("src_url"); _data.s_data.push_back(_src_data); } } // 入库游戏信息列表反序列化 if (k.value().is_object() && k.key() == "uid_data") { // x的key是uid x的value是内容 for (auto &x : k.value().items()) { UidData _temp_data = {}; _temp_data.name = x.value().at("Name"); _temp_data.uid = x.value().at("Uid"); _temp_data.i_time = x.value().at("In_Time"); _temp_data.m_time = x.value().at("Up_Time"); _temp_data.ico = x.value().at("Ico"); _temp_data.s_name = x.value().at("Src_Name"); if (x.value().contains("Manifest")) { _temp_data.manifest = x.value().at("Manifest").get>(); } if (x.value().contains("UidKey")) { _temp_data.uid_key = x.value().at("UidKey").get>(); } if (x.value().contains("ALL_DLC")) { _temp_data.r_dlc = x.value().at("ALL_DLC").get>(); } if (x.value().contains("IN_DLC")) { _temp_data.n_dlc = x.value().at("IN_DLC").get>(); } std::cout << "manifest size:" << _temp_data.manifest.size() << std::endl; std::cout << "uid_key size:" << _temp_data.uid_key.size() << std::endl; std::cout << "all_dlc size:" << _temp_data.r_dlc.size() << std::endl; std::cout << "in_dlc size:" << _temp_data.n_dlc.size() << std::endl; _data.u_data.push_back(_temp_data); } } } _data.x_config.style = j3.at("xsteam_sets").at("style"); _data.x_config.font = j3.at("xsteam_sets").at("font"); _data.x_config.font_bold = j3.at("xsteam_sets").at("font_bold"); _data.x_config.steam_dir = j3.at("xsteam_sets").at("steam_dir"); _data.x_config.steamtools_dir = j3.at("xsteam_sets").at("steamtools_dir"); _data.x_config.steamtools_st_dir = j3.at("xsteam_sets").at("steamtools_st_dir"); _data.x_config.steam_api_url = j3.at("xsteam_sets").at("steam_api_url"); _data.x_config.steam_logo_url = j3.at("xsteam_sets").at("steam_logo_url"); } else { // 当本地保存数据文件不存在或者读取data.json文件出错或者导致用户修改配置使得读取data.json出错. // 默认测试数据源 for (int i = 0; i <= ex_default_src_name.count() - 1; i++) { SrcData _src_data; _src_data.src_name = ex_default_src_name[i].toStdString(); _src_data.src_url = ex_default_src_url[i].toStdString(); _src_data.src_type = GIT_MODE::TAG; _data.s_data.push_back(_src_data); } // 默认配置 _data.x_config.font = 0; _data.x_config.font_bold = 0; _data.x_config.style = 1; QSettings settings("HKEY_CURRENT_USER\\Software\\Valve\\Steam", QSettings::NativeFormat); _data.x_config.steam_dir = (settings.value("SteamPath", "").toString()).toStdString(); _data.x_config.steam_api_url = "https://store.steampowered.com/api/appdetails/?appids="; _data.x_config.steam_logo_url = "https://shared.cloudflare.steamstatic.com/store_item_assets/steam/apps/"; _data.x_config.steamtools_dir = _data.x_config.steam_dir + "/config/stUI/"; _data.x_config.steamtools_st_dir = _data.x_config.steam_dir + "/config/stplug-in/"; } } // 序列化全局变量中需要保存在data.json目录下的数据 json xsteam_data_serialize(json jsonData) { // 序列化数据托管服务器 if (_data.s_data.size() > 0) { for (auto &k : _data.s_data) { jsonData[toStr(src_data)][k.src_name][toStr(src_name)] = k.src_name; jsonData[toStr(src_data)][k.src_name][toStr(src_type)] = k.src_type; jsonData[toStr(src_data)][k.src_name][toStr(src_url)] = k.src_url; } } // 序列化入库游戏数据 if (_data.u_data.size() > 0) { for (auto &u : _data.u_data) { // 游戏名 jsonData[toStr(uid_data)][u.uid][toStr(Name)] = u.name; // 游戏UID jsonData[toStr(uid_data)][u.uid][toStr(Uid)] = u.uid; // 游戏入库时间 jsonData[toStr(uid_data)][u.uid][toStr(In_Time)] = u.i_time; // 游戏清单最后更新时间 jsonData[toStr(uid_data)][u.uid][toStr(Up_Time)] = u.m_time; // 游戏ico图标参数 jsonData[toStr(uid_data)][u.uid][toStr(Ico)] = u.ico; jsonData[toStr(uid_data)][u.uid][toStr(Src_Name)] = u.s_name; // 游戏清单列表 for (auto &w : u.manifest) { jsonData[toStr(uid_data)][u.uid][toStr(Manifest)].push_back(w); } for (auto &[x, y] : u.uid_key) { jsonData[toStr(uid_data)][u.uid][toStr(UidKey)][x] = y; } // 游戏所有DLC清单 for (auto w : u.r_dlc) { jsonData[toStr(uid_data)][u.uid][toStr(ALL_DLC)].push_back(w); } // 游戏已经入库DLC清单 for (auto w : u.n_dlc) { jsonData[toStr(uid_data)][u.uid][toStr(IN_DLC)].push_back(w); } } } jsonData[toStr(xsteam_sets)][toStr(style)] = _data.x_config.style; jsonData[toStr(xsteam_sets)][toStr(font)] = _data.x_config.font; jsonData[toStr(xsteam_sets)][toStr(font_bold)] = _data.x_config.font_bold; jsonData[toStr(xsteam_sets)][toStr(steam_dir)] = _data.x_config.steam_dir; jsonData[toStr(xsteam_sets)][toStr(steamtools_dir)] = _data.x_config.steamtools_dir; jsonData[toStr(xsteam_sets)][toStr(steamtools_st_dir)] = _data.x_config.steamtools_st_dir; jsonData[toStr(xsteam_sets)][toStr(steam_api_url)] = _data.x_config.steam_api_url; jsonData[toStr(xsteam_sets)][toStr(steam_logo_url)] = _data.x_config.steam_logo_url; return jsonData; } void xsteam_save_data_write() { QString save_file = ex_save_path_ex + "data.json"; json jsonData = nullptr; jsonData = xsteam_data_serialize(jsonData); std::ofstream out(save_file.toStdString(), std::ios::binary); std::cout << jsonData << std::endl; out << std::setw(4) << jsonData; out.close(); } bool xsteam_lua_to_com(UidData u_data) { // 文件路径的设定和检测 QString lua_file = ex_base_exe_ex + QString::fromStdString(u_data.uid) + ".lua"; QString lua_packa_file = ex_base_exe_ex + "luapacka.exe"; QString lua_to_steam_st = QString::fromStdString(_data.x_config.steamtools_st_dir) + QString::fromStdString(u_data.uid) + ".st"; QFile _lua_file(lua_file); QFile _lua_packa_file(lua_packa_file); if (_lua_file.exists()) { QFile::remove(lua_file); } std::ofstream dp(lua_file.toStdString()); if (!dp.is_open()) { xsteam_msg_error(nullptr, "写入lua文件错误"); return false; } // 游戏的uid和DLC的uid拟合输出lua脚本文件 QString lua_str; // 增加游戏uid /* 1-一般游戏的UID和DLC末尾为0是游戏的解锁代码 2-一般UID内末尾为1则是windows系统的文件包 */ // 游戏UID-0 lua_str = "addappid(" + QString::fromStdString(u_data.uid) + ",1,\"None\")"; dp << lua_str.toStdString() << "\n"; qDebug() << "UID_KEY_0" << lua_str.toStdString(); // 增加已经入库的DLC的UID-0 for (auto &x : u_data.n_dlc) { // 增加DLC的uid同时必须和uid_key列表的u比对只增加远程服务器有的DLC lua_str = "addappid(" + QString::fromStdString(x) + ",1,\"None\")"; dp << lua_str.toStdString() << "\n"; qDebug() << "DLC_KEY_0" << lua_str.toStdString(); } for (auto &[uid, key] : u_data.uid_key) { if (std::to_string((std::stoi(u_data.uid) + 1)) == uid) { // 增加游戏本体的uid和key lua_str = "addappid(" + QString::fromStdString(uid) + ",1," + "\"" + QString::fromStdString(key) + "\"" + ")"; dp << lua_str.toStdString() << "\n"; qDebug() << "UID_KEY:" << lua_str.toStdString(); } } for (auto &d_id : u_data.n_dlc) { for (auto &[uid, key] : u_data.uid_key) { if (std::to_string((std::stoi(d_id) + 1)) == uid) { // 增加DLC的uid和key lua_str = "addappid(" + QString::fromStdString(uid) + ",1," + "\"" + QString::fromStdString(key) + "\"" + ")"; dp << lua_str.toStdString() << "\n"; qDebug() << "DLC_KEY:" << lua_str.toStdString(); } } } dp.close(); qDebug() << "n_dlc_size:" << u_data.n_dlc; // luapacka文件不存在则释放luapacka.exe文件 if (!_lua_packa_file.exists()) { QFile f_dp; f_dp.copy(":/res/bin/luapacka.exe", lua_packa_file); f_dp.close(); } // 输入lua脚本文件输出lua二进制文件 QProcess *m_cmd = new QProcess(); std::cout << "lua_packa_file:" << lua_packa_file.toStdString() << std::endl; std::cout << "lua_file:" << lua_file.toStdString() << std::endl; std::cout << "lua_to_steam_st:" << lua_to_steam_st.toStdString() << std::endl; m_cmd->setWorkingDirectory(ex_base_exe_path); m_cmd->start(lua_packa_file, QStringList() << lua_file << lua_to_steam_st); m_cmd->waitForFinished(); m_cmd->kill(); delete m_cmd; m_cmd = nullptr; std::cout << "lua_file exists:" << _lua_file.exists() << std::endl; std::cout << "lua_packa_file exists:" << _lua_packa_file.exists() << std::endl; if (_lua_file.exists()) { _lua_file.remove(); }; if (_lua_packa_file.exists()) { QFile::setPermissions(lua_packa_file,QFile::ReadOther | QFile::WriteOther); _lua_packa_file.remove(); }; return true; } void xsteam_run_steam_steamtools(RUN_MODE _mode) { QString run_steam_steamtools_path; QString _tips; if (_mode == RUN_MODE::STEAM) { run_steam_steamtools_path = QString::fromStdString(_data.x_config.steam_dir) + "/steam.exe"; _tips = "未检测到Steam安装,请先配置Steam路径"; } else if (_mode == RUN_MODE::STEAMTOOLS) { run_steam_steamtools_path = QString::fromStdString(_data.x_config.steamtools_dir) + "Steamtools.exe"; _tips = "未检测到SteamTools安装,请先配置SteamTools路径"; } if (QFile(run_steam_steamtools_path).exists()) { QFuture future = QtConcurrent::run([=]() { QProcess *m_cmd = new QProcess(); m_cmd->startDetached(run_steam_steamtools_path); m_cmd->waitForFinished(); m_cmd->kill(); delete m_cmd; m_cmd = nullptr; }); } else { xsteam_msg_error(nullptr, _tips); } } bool xsteam_uid_exists(std::string uid) { for (auto u : _data.u_data) { if (u.uid == uid) { return true; } } return false; } bool xsteam_steam_steamtools_exists(bool &steam_ok, bool &steamtools_ok) { if (!_data.x_config.steam_dir.empty()) { if (QDir(QString::fromStdString(_data.x_config.steam_dir)).exists()) { steam_ok = true; } } if (!_data.x_config.steamtools_dir.empty()) { if (QDir(QString::fromStdString(_data.x_config.steamtools_dir)).exists()) { steamtools_ok = true; } } return steam_ok && steamtools_ok; } void xsteam_delete_uid_st(std::string uid) { for (auto it = _data.u_data.begin(); it != _data.u_data.end(); ++it) { if (it->uid == uid) { QFile st(QString::fromStdString(_data.x_config.steamtools_st_dir + uid + ".st")); if (st.exists()) { st.remove(); } _data.u_data.erase(it); xsteam_save_data_write(); break; } } } bool xsteam_src_data_exists(std::string src_name) { QString save_file_str = ex_save_path_ex + "tags_" + QString::fromStdString(src_name) + ".data"; if (QFile(save_file_str).exists()) { return true; } return false; }