mirror of
https://github.com/aseprite/aseprite.git
synced 2024-10-03 21:46:20 +00:00
274 lines
7.4 KiB
C++
274 lines
7.4 KiB
C++
// Aseprite Steam Wrapper
|
|
// Copyright (c) 2020 Igara Studio S.A.
|
|
// Copyright (c) 2016 David Capello
|
|
//
|
|
// This file is released under the terms of the MIT license.
|
|
// Read LICENSE.txt for more information.
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#include "steam/steam.h"
|
|
|
|
#include "base/convert_to.h"
|
|
#include "base/dll.h"
|
|
#include "base/fs.h"
|
|
#include "base/ints.h"
|
|
#include "base/launcher.h"
|
|
#include "base/log.h"
|
|
#include "base/string.h"
|
|
|
|
namespace steam {
|
|
|
|
typedef uint32_t HSteamPipe;
|
|
typedef uint32_t HSteamUser;
|
|
typedef uint32_t ScreenshotHandle;
|
|
struct ISteamScreenshots;
|
|
struct ISteamUtils;
|
|
|
|
enum {
|
|
// Last callback received from Steam client when it's Steam is closed
|
|
kSteamServersDisconnected = 103,
|
|
kSteamUndocumentedLastCallback = 1009,
|
|
// When a screenshot is ready in the library
|
|
kScreenshotReady = 2301,
|
|
};
|
|
|
|
struct CallbackMsg_t {
|
|
HSteamUser steamUser;
|
|
int callback;
|
|
uint8_t* pubParam;
|
|
int cubParam;
|
|
};
|
|
|
|
#ifdef __GNUC__
|
|
#define __cdecl
|
|
#endif
|
|
|
|
// Steam main API
|
|
typedef bool (__cdecl *SteamAPI_Init_Func)();
|
|
typedef void (__cdecl *SteamAPI_Shutdown_Func)();
|
|
typedef HSteamPipe (__cdecl *SteamAPI_GetHSteamPipe_Func)();
|
|
|
|
// Steam callbacks
|
|
typedef void (__cdecl *SteamAPI_ManualDispatch_Init_Func)();
|
|
typedef void (__cdecl *SteamAPI_ManualDispatch_RunFrame_Func)(HSteamPipe);
|
|
typedef bool (__cdecl *SteamAPI_ManualDispatch_GetNextCallback_Func)(HSteamPipe, CallbackMsg_t*);
|
|
typedef void (__cdecl *SteamAPI_ManualDispatch_FreeLastCallback_Func)(HSteamPipe);
|
|
|
|
// ISteamScreenshots
|
|
typedef ISteamScreenshots* (__cdecl *SteamAPI_SteamScreenshots_v003_Func)();
|
|
typedef ScreenshotHandle (__cdecl *SteamAPI_ISteamScreenshots_WriteScreenshot_Func)(ISteamScreenshots*, void*, uint32_t, int, int);
|
|
|
|
// ISteamUtils
|
|
typedef ISteamUtils* (__cdecl *SteamAPI_SteamUtils_v009_Func)();
|
|
typedef uint32_t (__cdecl *SteamAPI_ISteamUtils_GetAppID_Func)(ISteamUtils*);
|
|
|
|
#ifdef _WIN32
|
|
#ifdef _WIN64
|
|
#define STEAM_API_DLL_FILENAME "steam_api64.dll"
|
|
#else
|
|
#define STEAM_API_DLL_FILENAME "steam_api.dll"
|
|
#endif
|
|
#elif defined(__APPLE__)
|
|
#define STEAM_API_DLL_FILENAME "libsteam_api.dylib"
|
|
#else
|
|
#define STEAM_API_DLL_FILENAME "libsteam_api.so"
|
|
#endif
|
|
|
|
#define GETPROC(name) base::get_dll_proc<name##_Func>(m_steamLib, #name)
|
|
|
|
class SteamAPI::Impl {
|
|
public:
|
|
Impl() {
|
|
m_steamLib = base::load_dll(
|
|
base::join_path(base::get_file_path(base::get_app_path()),
|
|
STEAM_API_DLL_FILENAME));
|
|
if (!m_steamLib) {
|
|
LOG("STEAM: Steam library not found...\n");
|
|
return;
|
|
}
|
|
|
|
auto SteamAPI_Init = GETPROC(SteamAPI_Init);
|
|
if (!SteamAPI_Init) {
|
|
LOG("STEAM: SteamAPI_Init not found...\n");
|
|
return;
|
|
}
|
|
|
|
// Call SteamAPI_Init() to connect to Steam
|
|
if (!SteamAPI_Init()) {
|
|
LOG("STEAM: Steam is not initialized...\n");
|
|
return;
|
|
}
|
|
|
|
// Get functions to dispatch callbacks manually
|
|
auto SteamAPI_ManualDispatch_Init = GETPROC(SteamAPI_ManualDispatch_Init);
|
|
SteamAPI_ManualDispatch_RunFrame = GETPROC(SteamAPI_ManualDispatch_RunFrame);
|
|
SteamAPI_ManualDispatch_GetNextCallback = GETPROC(SteamAPI_ManualDispatch_GetNextCallback);
|
|
SteamAPI_ManualDispatch_FreeLastCallback = GETPROC(SteamAPI_ManualDispatch_FreeLastCallback);
|
|
auto SteamAPI_GetHSteamPipe = GETPROC(SteamAPI_GetHSteamPipe);
|
|
if (SteamAPI_ManualDispatch_Init &&
|
|
SteamAPI_ManualDispatch_RunFrame &&
|
|
SteamAPI_ManualDispatch_GetNextCallback &&
|
|
SteamAPI_ManualDispatch_FreeLastCallback &&
|
|
SteamAPI_GetHSteamPipe) {
|
|
SteamAPI_ManualDispatch_Init();
|
|
m_pipe = SteamAPI_GetHSteamPipe();
|
|
}
|
|
|
|
LOG("STEAM: Steam initialized\n");
|
|
m_initialized = true;
|
|
}
|
|
|
|
~Impl() {
|
|
if (!m_steamLib)
|
|
return;
|
|
|
|
auto SteamAPI_Shutdown = GETPROC(SteamAPI_Shutdown);
|
|
if (SteamAPI_Shutdown) {
|
|
LOG("STEAM: Steam shutdown...\n");
|
|
SteamAPI_Shutdown();
|
|
}
|
|
|
|
unloadLib();
|
|
}
|
|
|
|
bool initialized() const {
|
|
return m_initialized;
|
|
}
|
|
|
|
void runCallbacks() {
|
|
if (!m_pipe)
|
|
return;
|
|
|
|
ASSERT(SteamAPI_ManualDispatch_RunFrame);
|
|
ASSERT(SteamAPI_ManualDispatch_GetNextCallback);
|
|
ASSERT(SteamAPI_ManualDispatch_FreeLastCallback);
|
|
|
|
SteamAPI_ManualDispatch_RunFrame(m_pipe);
|
|
|
|
CallbackMsg_t msg;
|
|
if (SteamAPI_ManualDispatch_GetNextCallback(m_pipe, &msg)) {
|
|
//TRACEARGS("SteamAPI_ManualDispatch_GetNextCallback", msg.callback);
|
|
|
|
bool disconnected = false;
|
|
switch (msg.callback) {
|
|
case kSteamServersDisconnected:
|
|
case kSteamUndocumentedLastCallback:
|
|
disconnected = true;
|
|
break;
|
|
|
|
// When a screenshot is ready, we open the Steam library of screenshots
|
|
case kScreenshotReady: {
|
|
std::string url = "steam://open/screenshots/";
|
|
|
|
auto SteamAPI_SteamUtils_v009 = GETPROC(SteamAPI_SteamUtils_v009);
|
|
auto SteamAPI_ISteamUtils_GetAppID = GETPROC(SteamAPI_ISteamUtils_GetAppID);
|
|
if (SteamAPI_SteamUtils_v009 &&
|
|
SteamAPI_ISteamUtils_GetAppID) {
|
|
ISteamUtils* utils = SteamAPI_SteamUtils_v009();
|
|
if (utils) {
|
|
int appId = SteamAPI_ISteamUtils_GetAppID(utils);
|
|
url += base::convert_to<std::string>(appId);
|
|
}
|
|
}
|
|
base::launcher::open_url(url);
|
|
break;
|
|
}
|
|
}
|
|
SteamAPI_ManualDispatch_FreeLastCallback(m_pipe);
|
|
|
|
// If the Steam client is closed, we have to unload the DLL and
|
|
// don't use the pipe or any Steam API at all, in other case we
|
|
// would crash.
|
|
if (disconnected) {
|
|
LOG("STEAM: Disconnected\n");
|
|
unloadLib();
|
|
}
|
|
}
|
|
}
|
|
|
|
bool writeScreenshot(void* rgbBuffer,
|
|
uint32_t sizeInBytes,
|
|
int width, int height) {
|
|
if (!m_initialized)
|
|
return false;
|
|
|
|
auto SteamScreenshots = GETPROC(SteamAPI_SteamScreenshots_v003);
|
|
auto WriteScreenshot = GETPROC(SteamAPI_ISteamScreenshots_WriteScreenshot);
|
|
if (!SteamScreenshots || !WriteScreenshot) {
|
|
LOG("STEAM: Error getting Steam Screenshot API functions\n");
|
|
return false;
|
|
}
|
|
|
|
auto screenshots = SteamScreenshots();
|
|
if (!screenshots) {
|
|
LOG("STEAM: Error getting Steam Screenshot API instance\n");
|
|
return false;
|
|
}
|
|
|
|
WriteScreenshot(screenshots, rgbBuffer, sizeInBytes, width, height);
|
|
return true;
|
|
}
|
|
|
|
private:
|
|
void unloadLib() {
|
|
base::unload_dll(m_steamLib);
|
|
m_steamLib = nullptr;
|
|
m_initialized = false;
|
|
m_pipe = 0;
|
|
}
|
|
|
|
bool m_initialized = false;
|
|
base::dll m_steamLib = nullptr;
|
|
|
|
// To handle callbacks manually
|
|
HSteamPipe m_pipe = 0;
|
|
SteamAPI_ManualDispatch_RunFrame_Func SteamAPI_ManualDispatch_RunFrame = nullptr;
|
|
SteamAPI_ManualDispatch_GetNextCallback_Func SteamAPI_ManualDispatch_GetNextCallback = nullptr;
|
|
SteamAPI_ManualDispatch_FreeLastCallback_Func SteamAPI_ManualDispatch_FreeLastCallback = nullptr;
|
|
};
|
|
|
|
SteamAPI* g_instance = nullptr;
|
|
|
|
// static
|
|
SteamAPI* SteamAPI::instance()
|
|
{
|
|
return g_instance;
|
|
}
|
|
|
|
SteamAPI::SteamAPI()
|
|
: m_impl(new Impl)
|
|
{
|
|
ASSERT(g_instance == nullptr);
|
|
g_instance = this;
|
|
}
|
|
|
|
SteamAPI::~SteamAPI()
|
|
{
|
|
delete m_impl;
|
|
|
|
ASSERT(g_instance == this);
|
|
g_instance = nullptr;
|
|
}
|
|
|
|
bool SteamAPI::initialized() const
|
|
{
|
|
return m_impl->initialized();
|
|
}
|
|
|
|
void SteamAPI::runCallbacks()
|
|
{
|
|
m_impl->runCallbacks();
|
|
}
|
|
|
|
bool SteamAPI::writeScreenshot(void* rgbBuffer,
|
|
uint32_t sizeInBytes,
|
|
int width, int height)
|
|
{
|
|
return m_impl->writeScreenshot(rgbBuffer, sizeInBytes, width, height);
|
|
}
|
|
|
|
} // namespace steam
|