1
0
mirror of https://github.com/TerryCavanagh/VVVVVV.git synced 2024-06-04 20:13:32 +02:00

Hook Steam screenshots and send internal capture

Using the Steamworks API, we can hook the screenshot function and listen
for a screenshot request callback to send in our own screenshot. This
applies the screenshot improvements to Steam screenshots as well.

Doing this requires adding some C wrapper functions, as our interface
with the Steam API is only conducted through C.
This commit is contained in:
Misa 2024-01-09 11:30:17 -08:00 committed by Misa Elizabeth Kai
parent f05827f268
commit ae5ef9753c
3 changed files with 122 additions and 5 deletions

View File

@ -2,6 +2,8 @@
#include <SDL.h> #include <SDL.h>
#include "Graphics.h"
#include "GraphicsUtil.h"
#include "Localization.h" #include "Localization.h"
#include "UtilityClass.h" #include "UtilityClass.h"
@ -27,4 +29,14 @@ uint32_t LOC_toupper_ch(uint32_t ch)
return loc::toupper_ch(ch); return loc::toupper_ch(ch);
} }
SDL_Surface* GRAPHICS_tempScreenshot(void)
{
return graphics.tempScreenshot;
}
uint8_t UTIL_TakeScreenshot(SDL_Surface** surface)
{
return TakeScreenshot(surface);
}
} /* extern "C" */ } /* extern "C" */

View File

@ -1,6 +1,7 @@
#ifndef CWRAPPERS_H #ifndef CWRAPPERS_H
#define CWRAPPERS_H #define CWRAPPERS_H
#include <SDL_surface.h>
#include <stdint.h> #include <stdint.h>
#ifdef __cplusplus #ifdef __cplusplus
@ -9,6 +10,8 @@ extern "C" {
char* HELP_number_words(int _t, const char* number_class); char* HELP_number_words(int _t, const char* number_class);
uint32_t LOC_toupper_ch(uint32_t ch); uint32_t LOC_toupper_ch(uint32_t ch);
SDL_Surface* GRAPHICS_tempScreenshot(void);
uint8_t UTIL_TakeScreenshot(SDL_Surface** surface);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -5,12 +5,14 @@
#include <stdint.h> #include <stdint.h>
#include <SDL.h> #include <SDL.h>
#include "CWrappers.h"
#include "Vlogging.h" #include "Vlogging.h"
/* Steamworks interface versions */ /* Steamworks interface versions */
#define VVVVVV_STEAMCLIENT "SteamClient017" #define VVVVVV_STEAMCLIENT "SteamClient017"
#define VVVVVV_STEAMUSERSTATS "STEAMUSERSTATS_INTERFACE_VERSION011" #define VVVVVV_STEAMUSERSTATS "STEAMUSERSTATS_INTERFACE_VERSION011"
#define VVVVVV_STEAMSCREENSHOTS "STEAMSCREENSHOTS_INTERFACE_VERSION003"
/* Shared object file name */ /* Shared object file name */
@ -28,6 +30,20 @@
struct ISteamClient; struct ISteamClient;
struct ISteamUserStats; struct ISteamUserStats;
struct ISteamScreenshots;
struct CallbackMsg_t
{
int32_t m_hSteamUser;
int32_t m_iCallback;
uint8_t* m_pubParam;
int32_t m_cubParam;
};
struct SteamAPICallCompleted_t
{
uint64_t m_hAsyncCall;
int32_t m_iCallback;
uint32_t m_cubParam;
};
#define FUNC_LIST \ #define FUNC_LIST \
FOREACH_FUNC(uint8_t, SteamAPI_Init, (void)) \ FOREACH_FUNC(uint8_t, SteamAPI_Init, (void)) \
@ -47,10 +63,42 @@ struct ISteamUserStats;
FOREACH_FUNC(uint8_t, SteamAPI_ISteamUserStats_SetAchievement, ( \ FOREACH_FUNC(uint8_t, SteamAPI_ISteamUserStats_SetAchievement, ( \
struct ISteamUserStats*, \ struct ISteamUserStats*, \
const char* \ const char* \
)) \
FOREACH_FUNC(struct ISteamScreenshots*, SteamAPI_ISteamClient_GetISteamScreenshots, ( \
struct ISteamClient*, \
int32_t, \
int32_t, \
const char* \
)) \
FOREACH_FUNC(void, SteamAPI_ISteamScreenshots_HookScreenshots, (\
struct ISteamScreenshots*, \
uint8_t \
)) \
FOREACH_FUNC(uint32_t, SteamAPI_ISteamScreenshots_WriteScreenshot, ( \
struct ISteamScreenshots*, \
void*, \
uint32_t, \
int32_t, \
int32_t \
)) \
FOREACH_FUNC(void, SteamAPI_ManualDispatch_Init, (void)) \
FOREACH_FUNC(void, SteamAPI_ManualDispatch_RunFrame, (int32_t)) \
FOREACH_FUNC(uint8_t, SteamAPI_ManualDispatch_GetNextCallback, (int32_t, struct CallbackMsg_t*)) \
FOREACH_FUNC(void, SteamAPI_ManualDispatch_FreeLastCallback, (int32_t)) \
FOREACH_FUNC(uint8_t, SteamAPI_ManualDispatch_GetAPICallResult, ( \
int32_t, \
uint64_t, \
void*, \
int32_t, \
int32_t, \
uint8_t* \
)) ))
static void *libHandle = NULL; #define iScreenshotRequested 2302
static struct ISteamUserStats *steamUserStats = NULL;
static void* libHandle = NULL;
static struct ISteamUserStats* steamUserStats = NULL;
static struct ISteamScreenshots* steamScreenshots = NULL;
#define FOREACH_FUNC(rettype, name, params) static rettype (*name) params = NULL; #define FOREACH_FUNC(rettype, name, params) static rettype (*name) params = NULL;
FUNC_LIST FUNC_LIST
@ -68,15 +116,42 @@ static void ClearPointers(void)
#undef FOREACH_FUNC #undef FOREACH_FUNC
} }
static void run_screenshot()
{
if (!libHandle)
{
return;
}
vlog_info("taking a screenshot");
SDL_Surface* surface = GRAPHICS_tempScreenshot();
uint8_t success = UTIL_TakeScreenshot(&surface);
if (!success)
{
return;
}
SteamAPI_ISteamScreenshots_WriteScreenshot(
steamScreenshots,
surface->pixels,
surface->w * surface->h * surface->format->BytesPerPixel,
surface->w,
surface->h
);
}
/* NETWORK API Implementation */ /* NETWORK API Implementation */
static int32_t steamPipe = 0;
int32_t STEAM_init(void) int32_t STEAM_init(void)
{ {
#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) || defined(__DragonFly__) #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) || defined(__DragonFly__)
return 0; return 0;
#endif #endif
struct ISteamClient *steamClient; struct ISteamClient *steamClient;
int32_t steamUser, steamPipe; int32_t steamUser;
libHandle = SDL_LoadObject(STEAM_LIBRARY); libHandle = SDL_LoadObject(STEAM_LIBRARY);
if (!libHandle) if (!libHandle)
@ -102,6 +177,7 @@ int32_t STEAM_init(void)
ClearPointers(); ClearPointers();
return 0; return 0;
} }
SteamAPI_ManualDispatch_Init();
steamClient = SteamInternal_CreateInterface(VVVVVV_STEAMCLIENT); steamClient = SteamInternal_CreateInterface(VVVVVV_STEAMCLIENT);
steamUser = SteamAPI_GetHSteamUser(); steamUser = SteamAPI_GetHSteamUser();
steamPipe = SteamAPI_GetHSteamPipe(); steamPipe = SteamAPI_GetHSteamPipe();
@ -126,6 +202,20 @@ int32_t STEAM_init(void)
return 0; return 0;
} }
SteamAPI_ISteamUserStats_RequestCurrentStats(steamUserStats); SteamAPI_ISteamUserStats_RequestCurrentStats(steamUserStats);
steamScreenshots = SteamAPI_ISteamClient_GetISteamScreenshots(
steamClient,
steamUser,
steamPipe,
VVVVVV_STEAMSCREENSHOTS
);
if (!steamScreenshots)
{
SteamAPI_Shutdown();
vlog_error(VVVVVV_STEAMSCREENSHOTS " not created!");
ClearPointers();
return 0;
}
SteamAPI_ISteamScreenshots_HookScreenshots(steamScreenshots, 1);
return 1; return 1;
} }
@ -140,9 +230,21 @@ void STEAM_shutdown(void)
void STEAM_update(void) void STEAM_update(void)
{ {
if (libHandle) if (!libHandle)
{ {
SteamAPI_RunCallbacks(); return;
}
SteamAPI_ManualDispatch_RunFrame(steamPipe);
struct CallbackMsg_t callback;
SDL_zero(callback);
while (SteamAPI_ManualDispatch_GetNextCallback(steamPipe, &callback))
{
if (callback.m_iCallback == iScreenshotRequested)
{
run_screenshot();
}
SteamAPI_ManualDispatch_FreeLastCallback(steamPipe);
} }
} }