XSteam/src/xsteam_ex.cpp
2024-10-11 19:40:20 +08:00

612 lines
21 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "xsteam_ex.h"
#include <iostream>
#include <filesystem>
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_save_data_read();
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<char> _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::basic_string<char>, std::shared_ptr<vdf::basic_object<char>>> _childs;
std::unordered_map<std::basic_string<char>, std::basic_string<char>> _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<std::string, std::string> keys;
for (auto &k : vdf_data.childs)
{
std::string u_id = k.first;
std::string u_key = k.second->attribs.find("DecryptionKey")->second;
if (std::to_string((std::stoi(u_data.uid) + 1)) == u_id)
{
qDebug() << QString::fromStdString(u_id) << ":" << QString::fromStdString(u_key);
u_data.uid_key.insert(std::pair<std::string, std::string>(u_id, u_key));
}
else
{
// 考虑是否需要仅仅针对dlc自行保存key的值.是否全部读入data.json内
for (auto x : u_data.n_dlc)
{
if (std::to_string((std::stoi(x) + 1)) == u_id)
{
qDebug() << QString::fromStdString(u_id) << ":" << QString::fromStdString(u_key);
u_data.uid_key.insert(std::pair<std::string, std::string>(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);
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<std::string, std::string> 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(std::string uid, 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, 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;
}
u_data.uid = uid;
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")
{
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_save_data_read()
{
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");
if (x.value().contains("Manifest"))
{
_temp_data.manifest = x.value().at("Manifest").get<std::vector<std::string>>();
}
if (x.value().contains("UidKey"))
{
_temp_data.uid_key = x.value().at("UidKey").get<std::map<std::string, std::string>>();
}
if (x.value().contains("ALL_DLC"))
{
_temp_data.r_dlc = x.value().at("ALL_DLC").get<std::vector<std::string>>();
}
if (x.value().contains("IN_DLC"))
{
_temp_data.n_dlc = x.value().at("IN_DLC").get<std::vector<std::string>>();
}
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.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出错.
// 默认测试数据源
SrcData _src_data;
_src_data.src_name = "FastGitHud";
_src_data.src_url = "https://githubfast.com/ManifestHub/ManifestHub.git";
_src_data.src_type = GIT_MODE::TAG;
_data.s_data.push_back(_src_data);
// 默认配置
_data.x_config.font = 0;
_data.x_config.style = 0;
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;
// 游戏清单列表
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(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系统的文件包
*/
lua_str = "addappid(" + QString::fromStdString(u_data.uid) + ",1,\"None\")";
dp << lua_str.toStdString() << "\n";
for (auto &x : u_data.n_dlc)
{
for (auto [u, w] : u_data.uid_key)
{
if (std::to_string((std::stoi(x) + 1)) == u)
{
// 增加DLC的uid同时必须和uid_key列表的u比对只增加远程服务器有的DLC
lua_str = "addappid(" + QString::fromStdString(x) + ",1,\"None\")";
dp << lua_str.toStdString() << "\n";
}
}
}
for (auto &[u, w] : u_data.uid_key)
{
qDebug() << "u:" << QString::fromStdString(u) << "w:" << QString::fromStdString(w);
if (std::to_string((std::stoi(u_data.uid) + 1)) == u)
{
// 增加游戏本体的uid和key
lua_str = "addappid(" + QString::fromStdString(u) + ",1," + "\"" + QString::fromStdString(w) + "\"" + ")";
}
else
{
// 增加DLC的uid和key
lua_str = "addappid(" + QString::fromStdString(u) + ",1," + "\"" + QString::fromStdString(w) + "\"" + ")";
}
dp << lua_str.toStdString() << "\n";
}
dp.close();
// 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())
{
_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<void> 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();)
{
if (it->uid == uid)
{
it = _data.u_data.erase(it);
QFile st(QString::fromStdString(_data.x_config.steamtools_st_dir+uid+".st"));
if(st.exists()){
st.remove();
}
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;
}