Support UGC on steam deck

This commit is contained in:
momo5502 2023-03-16 21:50:49 +01:00
parent bf9a3336d0
commit 5532980cc6
4 changed files with 127 additions and 44 deletions

View File

@ -7,8 +7,6 @@
#include <utils/finally.hpp> #include <utils/finally.hpp>
#include <utils/concurrency.hpp> #include <utils/concurrency.hpp>
#include "game/utils.hpp"
#include "steam/interface.hpp" #include "steam/interface.hpp"
#include "steam/steam.hpp" #include "steam/steam.hpp"
@ -22,8 +20,8 @@ namespace steam_proxy
utils::nt::library steam_client_module{}; utils::nt::library steam_client_module{};
utils::nt::library steam_overlay_module{}; utils::nt::library steam_overlay_module{};
void* steam_pipe = nullptr; steam::HSteamPipe steam_pipe = 0;
void* global_user = nullptr; steam::HSteamUser global_user = 0;
steam::interface client_engine{}; steam::interface client_engine{};
steam::interface client_user{}; steam::interface client_user{};
@ -31,6 +29,9 @@ namespace steam_proxy
steam::interface client_friends{}; steam::interface client_friends{};
steam::interface client_ugc{}; steam::interface client_ugc{};
steam::client* steam_client{};
steam::ugc* steam_ugc{};
utils::concurrency::container<subscribed_item_map> subscribed_items; utils::concurrency::container<subscribed_item_map> subscribed_items;
enum class ownership_state enum class ownership_state
@ -64,6 +65,8 @@ namespace steam_proxy
void load_client() void load_client()
{ {
SetEnvironmentVariableA("SteamAppId", std::to_string(steam::SteamUtils()->GetAppID()).data());
const std::filesystem::path steam_path = steam::SteamAPI_GetSteamInstallPath(); const std::filesystem::path steam_path = steam::SteamAPI_GetSteamInstallPath();
if (steam_path.empty()) return; if (steam_path.empty()) return;
@ -76,8 +79,8 @@ namespace steam_proxy
client_engine = load_client_engine(); client_engine = load_client_engine();
if (!client_engine) return; if (!client_engine) return;
steam_pipe = steam_client_module.invoke<void*>("Steam_CreateSteamPipe"); steam_pipe = steam_client_module.invoke<steam::HSteamPipe>("Steam_CreateSteamPipe");
global_user = steam_client_module.invoke<void*>( global_user = steam_client_module.invoke<steam::HSteamUser>(
"Steam_ConnectToGlobalUser", steam_pipe); "Steam_ConnectToGlobalUser", steam_pipe);
client_user = client_engine.invoke<void*>(8, global_user, steam_pipe); client_user = client_engine.invoke<void*>(8, global_user, steam_pipe);
@ -94,19 +97,21 @@ namespace steam_proxy
client_friends = nullptr; client_friends = nullptr;
client_ugc = nullptr; client_ugc = nullptr;
steam_pipe = nullptr; steam_pipe = 0;
global_user = nullptr; global_user = 0;
steam_client_module = utils::nt::library{nullptr}; steam_client = nullptr;
steam_ugc = nullptr;
} }
bool perform_cleanup_if_needed() bool perform_cleanup_if_needed()
{ {
if (steam_client) return true;
if (steam_client_module if (steam_client_module
&& steam_pipe && steam_pipe
&& global_user && global_user
&& steam_client_module.invoke<bool>("Steam_BConnected", global_user, && steam_client_module.invoke<bool>("Steam_BConnected", global_user, steam_pipe)
steam_pipe)
&& steam_client_module.invoke<bool>("Steam_BLoggedOn", global_user, steam_pipe) && steam_client_module.invoke<bool>("Steam_BLoggedOn", global_user, steam_pipe)
) )
{ {
@ -224,7 +229,16 @@ namespace steam_proxy
void pre_destroy() override void pre_destroy() override
{ {
if (steam_client_module && steam_pipe) if (steam_client)
{
if (global_user)
{
steam_client->ReleaseUser(steam_pipe, global_user);
}
steam_client->BReleaseSteamPipe(steam_pipe);
}
else if (steam_client_module && steam_pipe)
{ {
if (global_user) if (global_user)
{ {
@ -232,7 +246,7 @@ namespace steam_proxy
global_user); global_user);
} }
steam_client_module.invoke<bool>("Steam_BReleaseSteamPipe", steam_pipe); (void)steam_client_module.invoke<bool>("Steam_BReleaseSteamPipe", steam_pipe);
} }
} }
@ -257,6 +271,87 @@ namespace steam_proxy
return ""; return "";
} }
void initialize()
{
if (client_engine || !steam_client_module) return;
steam_client = steam_client_module.invoke<steam::client*>("CreateInterface", "SteamClient017", nullptr);
if (!steam_client) return;
steam_pipe = steam_client->CreateSteamPipe();
global_user = steam_client->ConnectToGlobalUser(steam_pipe);
}
void create_ugc()
{
if (!steam_client) return;
auto* ugc = steam_client->GetISteamUGC(global_user, steam_pipe, "STEAMUGC_INTERFACE_VERSION008");
steam_ugc = static_cast<steam::ugc*>(ugc);
}
void update_map_client(subscribed_item_map& map)
{
const auto app_id = steam::SteamUtils()->GetAppID();
const auto num_items = client_ugc.invoke<uint32_t>("GetNumSubscribedItems", app_id);
if (!num_items)
{
return;
}
std::vector<uint64_t> ids;
ids.resize(num_items);
auto result = client_ugc.invoke<uint32_t>("GetSubscribedItems", app_id, ids.data(),
num_items);
result = std::min(num_items, result);
for (uint32_t i = 0; i < result; ++i)
{
char buffer[0x1000] = {0};
subscribed_item item{};
item.state = client_ugc.invoke<uint32_t>("GetItemState", app_id, ids[i]);
item.available = client_ugc.invoke<bool>("GetItemInstallInfo", app_id, ids[i],
&item.size_on_disk,
buffer,
sizeof(buffer), &item.time_stamp);
item.path = buffer;
map[ids[i]] = std::move(item);
}
}
void update_map_steam(subscribed_item_map& map)
{
const auto num_items = steam_ugc->GetNumSubscribedItems();
if (!num_items)
{
return;
}
std::vector<uint64_t> ids;
ids.resize(num_items);
auto result = steam_ugc->GetSubscribedItems(ids.data(), num_items);
result = std::min(num_items, result);
for (uint32_t i = 0; i < result; ++i)
{
char buffer[0x1000] = {0};
subscribed_item item{};
item.state = steam_ugc->GetItemState(ids[i]);
item.available = steam_ugc->GetItemInstallInfo(ids[i], &item.size_on_disk, buffer, sizeof(buffer),
&item.time_stamp);
item.path = buffer;
map[ids[i]] = std::move(item);
}
}
void update_subscribed_items() void update_subscribed_items()
{ {
subscribed_item_map map{}; subscribed_item_map map{};
@ -269,41 +364,15 @@ namespace steam_proxy
}); });
}); });
if (!client_ugc)
{
return;
}
try try
{ {
const auto app_id = steam::SteamUtils()->GetAppID(); if (client_ugc)
const auto num_items = client_ugc.invoke<uint32_t>("GetNumSubscribedItems", app_id);
if (!num_items)
{ {
return; update_map_client(map);
} }
else if (steam_ugc)
std::vector<uint64_t> ids;
ids.resize(num_items);
auto result = client_ugc.invoke<uint32_t>("GetSubscribedItems", app_id, ids.data(),
num_items);
result = std::min(num_items, result);
for (uint32_t i = 0; i < result; ++i)
{ {
char buffer[0x1000] = {0}; update_map_steam(map);
subscribed_item item{};
item.state = client_ugc.invoke<uint32_t>("GetItemState", app_id, ids[i]);
item.available = client_ugc.invoke<bool>("GetItemInstallInfo", app_id, ids[i],
&item.size_on_disk,
buffer,
sizeof(buffer), &item.time_stamp);
item.path = buffer;
map[ids[i]] = std::move(item);
} }
} }
catch (...) catch (...)

View File

@ -18,6 +18,9 @@ namespace steam_proxy
using subscribed_item_map = std::unordered_map<uint64_t, subscribed_item>; using subscribed_item_map = std::unordered_map<uint64_t, subscribed_item>;
void initialize();
void create_ugc();
void update_subscribed_items(); void update_subscribed_items();
void access_subscribed_items(const std::function<void(const subscribed_item_map&)>& callback); void access_subscribed_items(const std::function<void(const subscribed_item_map&)>& callback);
} }

View File

@ -1,5 +1,6 @@
#include <std_include.hpp> #include <std_include.hpp>
#include "../steam.hpp" #include "../steam.hpp"
#include "../../component/steam_proxy.hpp"
namespace steam namespace steam
{ {
@ -225,6 +226,13 @@ namespace steam
void* client::GetISteamUGC(HSteamUser hSteamUser, HSteamPipe hSteamPipe, const char* pchVersion) void* client::GetISteamUGC(HSteamUser hSteamUser, HSteamPipe hSteamPipe, const char* pchVersion)
{ {
static auto x = []
{
steam_proxy::create_ugc();
return 0;
}();
(void)x;
static ugc u; static ugc u;
return &u; return &u;
} }

View File

@ -4,7 +4,7 @@
#include <utils/nt.hpp> #include <utils/nt.hpp>
#include <utils/io.hpp> #include <utils/io.hpp>
#include "loader/component_loader.hpp" #include "../component/steam_proxy.hpp"
namespace steam namespace steam
{ {
@ -118,6 +118,9 @@ namespace steam
::utils::nt::library::load(steam_path / "vstdlib_s64.dll"); ::utils::nt::library::load(steam_path / "vstdlib_s64.dll");
::utils::nt::library::load(steam_path / "gameoverlayrenderer64.dll"); ::utils::nt::library::load(steam_path / "gameoverlayrenderer64.dll");
::utils::nt::library::load(steam_path / "steamclient64.dll"); ::utils::nt::library::load(steam_path / "steamclient64.dll");
steam_proxy::initialize();
return true; return true;
} }