RichPresence: support addon tracks and karts (#4506)

* RichPresence: support addon tracks and karts

* RichPresence: use 'Story Mode' for internal tracks

* RichPresence: only cache is assets has data

* RichPresence: update RPC after asset list retrieved

* RichPresence: move AssetRequest processing to main thread
This commit is contained in:
Mary 2021-03-19 11:37:06 -04:00 committed by GitHub
parent dd5fcfce47
commit 6631dbdfb9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 126 additions and 16 deletions

View File

@ -16,6 +16,8 @@
#include "network/protocols/client_lobby.hpp"
#include "network/protocols/lobby_protocol.hpp"
#include "network/server.hpp"
#include "online/request_manager.hpp"
#include "online/http_request.hpp"
#include <locale>
#include <codecvt>
@ -36,6 +38,26 @@
namespace RichPresenceNS
{
class AssetRequest : public Online::HTTPRequest {
private:
std::string* m_data;
RichPresence* m_rpc;
virtual void callback() OVERRIDE
{
if (UserConfigParams::m_rich_presence_debug)
Log::info("RichPresence", "Got asset list!");
m_data->append(Online::HTTPRequest::getData());
// Updated asset list! Maybe using addon, so we update:
m_rpc->update(true);
}
public:
AssetRequest(const std::string& url, std::string* data, RichPresence* rpc) :
Online::HTTPRequest(0), m_data(data), m_rpc(rpc)
{
setURL(url);
setDownloadAssetsRequest(true);
}
};
RichPresence* g_rich_presence = nullptr;
RichPresence* RichPresence::get()
@ -61,7 +83,10 @@ RichPresence::RichPresence() : m_connected(false), m_ready(false), m_last(0),
#else
m_socket(-1),
#endif
m_thread(nullptr)
m_assets_request(nullptr),
m_thread(nullptr),
m_asset_cache(),
m_assets()
{
doConnect();
}
@ -364,6 +389,17 @@ void RichPresence::sendData(int32_t op, std::string json)
#endif
}
void RichPresence::ensureCache()
{
if (m_assets_request != nullptr ||
Online::RequestManager::get() == nullptr) return;
std::string url = "https://discord.com/api/v8/oauth2/applications/";
url.append(UserConfigParams::m_discord_client_id);
url.append("/assets");
m_assets_request = std::make_shared<AssetRequest>(url, &m_assets, this);
m_assets_request->queue();
}
void RichPresence::update(bool force)
{
#ifndef DISABLE_RPC
@ -389,6 +425,11 @@ void RichPresence::update(bool force)
{
doConnect();
}
else
{
// Connected but not ready, ensure we have cache
ensureCache();
}
if (!m_ready)
{
return;
@ -439,9 +480,10 @@ void RichPresence::update(bool force)
HardwareStats::Json activity;
std::string trackName = convert.to_bytes(_("Getting ready to race").c_str());
Track* track;
if (world)
{
Track* track = track_manager->getTrack(trackId);
track = track_manager->getTrack(trackId);
if (track)
trackName = convert.to_bytes(track->getName().c_str());
}
@ -455,24 +497,85 @@ void RichPresence::update(bool force)
));
}
activity.add("state", std::string(trackName.c_str()));
if (world)
activity.add("details", minorModeName + " (" + difficulty + ")");
HardwareStats::Json assets;
if (world)
if (world && track)
{
Track* track = track_manager->getTrack(trackId);
assets.add("large_text", convert.to_bytes(track->getName().c_str()));
assets.add("large_image", track->isAddon() ?
bool useAddon = false;
if (track->isInternal())
{
assets.add("large_image", "logo");
trackName = convert.to_bytes(_("Story Mode").c_str());
}
else
{
activity.add("details", minorModeName + " (" + difficulty + ")");
if(track->isAddon())
{
std::string key = "\"track_";
key.append(track->getIdent());
key.append("\"");
auto existing = m_asset_cache.find(key);
if (existing == m_asset_cache.end())
{
if (!m_assets.empty())
{
useAddon = m_assets.find(key) == std::string::npos;
m_asset_cache.insert({key, useAddon});
}
else
useAddon = true;
}
else
{
useAddon = existing->second;
}
if (useAddon && UserConfigParams::m_rich_presence_debug)
{
Log::info("RichPresence", "Couldn't find icon for track %s", key.c_str());
}
}
assets.add("large_image", useAddon ?
"addons" : "track_" + trackId);
}
assets.add("large_text", trackName);
AbstractKart *abstractKart = world->getLocalPlayerKart(0);
if (abstractKart)
{
const KartProperties* kart = abstractKart->getKartModel()->getKartProperties();
assets.add("small_image", protocol && protocol->isSpectator() ?
"spectate" : kart->isAddon() ?
"addons" : "kart_" + abstractKart->getIdent());
if (protocol && protocol->isSpectator())
{
assets.add("small_image", "spectate");
}
else
{
bool useAddon = false;
if(kart->isAddon())
{
std::string key = "\"kart_";
key.append(abstractKart->getIdent());
key.append("\"");
auto existing = m_asset_cache.find(key);
if (existing == m_asset_cache.end())
{
if (!m_assets.empty())
{
useAddon = m_assets.find(key) == std::string::npos;
m_asset_cache.insert({key, useAddon});
}
else
useAddon = true;
}
else
{
useAddon = existing->second;
}
if (useAddon && UserConfigParams::m_rich_presence_debug)
{
Log::info("RichPresence", "Couldn't find icon for kart %s", key.c_str());
}
}
assets.add("small_image", useAddon ? "addons" : "kart_" + abstractKart->getIdent());
}
if (!protocol || !protocol->isSpectator())
{
std::string kartName = convert.to_bytes(kart->getName().c_str());
@ -488,6 +591,7 @@ void RichPresence::update(bool force)
// std::string filename = std::string(basename(player->getIconFilename().c_str()));
// assets->add("small_image", "kart_" + filename);
}
activity.add("state", std::string(trackName.c_str()));
assets.finish();
activity.add<std::string>("assets", assets.toString());

View File

@ -3,9 +3,11 @@
#include <namedpipeapi.h>
#endif
#include <thread>
#include <map>
namespace RichPresenceNS
{
class AssetRequest;
// There are more, but we don't need to use them
enum OPCodes
{
@ -29,13 +31,17 @@ namespace RichPresenceNS
#else
int m_socket;
#endif
std::shared_ptr<AssetRequest> m_assets_request;
std::thread* m_thread;
std::map<std::string, bool> m_asset_cache;
std::string m_assets;
bool tryConnect(std::string path);
bool doConnect();
void terminate();
void sendData(int32_t op, std::string json);
void handshake();
void readData();
void ensureCache();
static void finishConnection(RichPresence* self);
public:
RichPresence();