2020-08-03 05:35:00 +02:00
|
|
|
#include "MakeAndPlay.h"
|
|
|
|
|
|
|
|
#ifndef MAKEANDPLAY
|
|
|
|
|
2020-01-01 21:29:24 +01:00
|
|
|
#include <stdint.h>
|
|
|
|
#include <SDL.h>
|
|
|
|
|
2024-01-09 20:30:17 +01:00
|
|
|
#include "CWrappers.h"
|
2021-02-24 00:21:29 +01:00
|
|
|
#include "Vlogging.h"
|
|
|
|
|
2020-01-01 21:29:24 +01:00
|
|
|
/* Steamworks interface versions */
|
|
|
|
|
|
|
|
#define VVVVVV_STEAMCLIENT "SteamClient017"
|
|
|
|
#define VVVVVV_STEAMUSERSTATS "STEAMUSERSTATS_INTERFACE_VERSION011"
|
2024-01-09 20:30:17 +01:00
|
|
|
#define VVVVVV_STEAMSCREENSHOTS "STEAMSCREENSHOTS_INTERFACE_VERSION003"
|
2020-01-01 21:29:24 +01:00
|
|
|
|
|
|
|
/* Shared object file name */
|
|
|
|
|
|
|
|
#if defined(_WIN32)
|
2020-01-13 17:15:17 +01:00
|
|
|
#define STEAM_LIBRARY "steam_api.dll"
|
2020-01-01 21:29:24 +01:00
|
|
|
#elif defined(__APPLE__)
|
2020-01-13 17:15:17 +01:00
|
|
|
#define STEAM_LIBRARY "libsteam_api.dylib"
|
2020-04-20 15:41:11 +02:00
|
|
|
#elif defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) || defined(__DragonFly__)
|
2020-01-13 17:15:17 +01:00
|
|
|
#define STEAM_LIBRARY "libsteam_api.so"
|
2020-01-01 21:29:24 +01:00
|
|
|
#else
|
2020-01-13 17:15:17 +01:00
|
|
|
#error STEAM_LIBRARY: Unrecognized platform!
|
2020-01-01 21:29:24 +01:00
|
|
|
#endif
|
|
|
|
|
|
|
|
/* DLL, Entry Points */
|
|
|
|
|
2021-09-18 06:11:25 +02:00
|
|
|
struct ISteamClient;
|
|
|
|
struct ISteamUserStats;
|
2024-01-09 20:30:17 +01:00
|
|
|
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;
|
|
|
|
};
|
2021-09-18 06:11:25 +02:00
|
|
|
|
2021-09-17 22:53:52 +02:00
|
|
|
#define FUNC_LIST \
|
|
|
|
FOREACH_FUNC(uint8_t, SteamAPI_Init, (void)) \
|
|
|
|
FOREACH_FUNC(void, SteamAPI_Shutdown, (void)) \
|
|
|
|
FOREACH_FUNC(void, SteamAPI_RunCallbacks, (void)) \
|
2021-09-18 06:11:25 +02:00
|
|
|
FOREACH_FUNC(struct ISteamClient*, SteamInternal_CreateInterface, (const char*)) \
|
2021-09-17 22:53:52 +02:00
|
|
|
FOREACH_FUNC(int32_t, SteamAPI_GetHSteamUser, (void)) \
|
|
|
|
FOREACH_FUNC(int32_t, SteamAPI_GetHSteamPipe, (void)) \
|
2021-09-18 06:11:25 +02:00
|
|
|
FOREACH_FUNC(struct ISteamUserStats*, SteamAPI_ISteamClient_GetISteamUserStats, ( \
|
|
|
|
struct ISteamClient*, \
|
2021-09-17 22:53:52 +02:00
|
|
|
int32_t, \
|
|
|
|
int32_t, \
|
|
|
|
const char* \
|
|
|
|
)) \
|
2021-09-18 06:11:25 +02:00
|
|
|
FOREACH_FUNC(uint8_t, SteamAPI_ISteamUserStats_RequestCurrentStats, (struct ISteamUserStats*)) \
|
|
|
|
FOREACH_FUNC(uint8_t, SteamAPI_ISteamUserStats_StoreStats, (struct ISteamUserStats*)) \
|
2021-09-17 22:53:52 +02:00
|
|
|
FOREACH_FUNC(uint8_t, SteamAPI_ISteamUserStats_SetAchievement, ( \
|
2021-09-18 06:11:25 +02:00
|
|
|
struct ISteamUserStats*, \
|
2021-09-17 22:53:52 +02:00
|
|
|
const char* \
|
2024-01-09 20:30:17 +01:00
|
|
|
)) \
|
|
|
|
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* \
|
2021-09-17 22:53:52 +02:00
|
|
|
))
|
|
|
|
|
2024-01-09 20:30:17 +01:00
|
|
|
#define iScreenshotRequested 2302
|
|
|
|
|
|
|
|
static void* libHandle = NULL;
|
|
|
|
static struct ISteamUserStats* steamUserStats = NULL;
|
|
|
|
static struct ISteamScreenshots* steamScreenshots = NULL;
|
2020-01-01 21:29:24 +01:00
|
|
|
|
2021-09-17 22:58:44 +02:00
|
|
|
#define FOREACH_FUNC(rettype, name, params) static rettype (*name) params = NULL;
|
2021-09-17 22:53:52 +02:00
|
|
|
FUNC_LIST
|
|
|
|
#undef FOREACH_FUNC
|
2020-01-01 21:29:24 +01:00
|
|
|
|
|
|
|
/* Clean up after ourselves... */
|
|
|
|
|
Explicitly declare void for all void parameter functions (#628)
Apparently in C, if you have `void test();`, it's completely okay to do
`test(2);`. The function will take in the argument, but just discard it
and throw it away. It's like a trash can, and a rude one at that. If you
declare it like `void test(void);`, this is prevented.
This is not a problem in C++ - doing `void test();` and `test(2);` is
guaranteed to result in a compile error (this also means that right now,
at least in all `.cpp` files, nobody is ever calling a void parameter
function with arguments and having their arguments be thrown away).
However, we may not be using C++ in the future, so I just want to lay
down the precedent that if a function takes in no arguments, you must
explicitly declare it as such.
I would've added `-Wstrict-prototypes`, but it produces an annoying
warning message saying it doesn't work in C++ mode if you're compiling
in C++ mode. So it can be added later.
2021-02-25 23:23:59 +01:00
|
|
|
static void ClearPointers(void)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2021-09-07 03:56:39 +02:00
|
|
|
SDL_UnloadObject(libHandle);
|
|
|
|
libHandle = NULL;
|
2021-09-18 06:11:25 +02:00
|
|
|
steamUserStats = NULL;
|
2021-09-17 22:58:44 +02:00
|
|
|
#define FOREACH_FUNC(rettype, name, params) name = NULL;
|
2021-09-17 22:53:52 +02:00
|
|
|
FUNC_LIST
|
|
|
|
#undef FOREACH_FUNC
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
2024-01-09 20:30:17 +01:00
|
|
|
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;
|
|
|
|
}
|
2024-01-08 02:56:26 +01:00
|
|
|
SDL_Surface* surface2x = GRAPHICS_tempScreenshot2x();
|
|
|
|
success = UTIL_UpscaleScreenshot2x(surface, &surface2x);
|
|
|
|
if (!success)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
2024-01-09 20:30:17 +01:00
|
|
|
|
|
|
|
SteamAPI_ISteamScreenshots_WriteScreenshot(
|
|
|
|
steamScreenshots,
|
2024-01-08 02:56:26 +01:00
|
|
|
surface2x->pixels,
|
|
|
|
surface2x->w * surface2x->h * surface2x->format->BytesPerPixel,
|
|
|
|
surface2x->w,
|
|
|
|
surface2x->h
|
2024-01-09 20:30:17 +01:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2020-01-01 21:29:24 +01:00
|
|
|
/* NETWORK API Implementation */
|
|
|
|
|
2024-01-09 20:30:17 +01:00
|
|
|
static int32_t steamPipe = 0;
|
|
|
|
|
Explicitly declare void for all void parameter functions (#628)
Apparently in C, if you have `void test();`, it's completely okay to do
`test(2);`. The function will take in the argument, but just discard it
and throw it away. It's like a trash can, and a rude one at that. If you
declare it like `void test(void);`, this is prevented.
This is not a problem in C++ - doing `void test();` and `test(2);` is
guaranteed to result in a compile error (this also means that right now,
at least in all `.cpp` files, nobody is ever calling a void parameter
function with arguments and having their arguments be thrown away).
However, we may not be using C++ in the future, so I just want to lay
down the precedent that if a function takes in no arguments, you must
explicitly declare it as such.
I would've added `-Wstrict-prototypes`, but it produces an annoying
warning message saying it doesn't work in C++ mode if you're compiling
in C++ mode. So it can be added later.
2021-02-25 23:23:59 +01:00
|
|
|
int32_t STEAM_init(void)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-20 15:41:11 +02:00
|
|
|
#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) || defined(__DragonFly__)
|
2021-09-07 03:56:39 +02:00
|
|
|
return 0;
|
2020-01-10 22:38:33 +01:00
|
|
|
#endif
|
2021-09-18 06:11:25 +02:00
|
|
|
struct ISteamClient *steamClient;
|
2024-01-09 20:30:17 +01:00
|
|
|
int32_t steamUser;
|
2021-09-07 03:56:39 +02:00
|
|
|
|
|
|
|
libHandle = SDL_LoadObject(STEAM_LIBRARY);
|
|
|
|
if (!libHandle)
|
|
|
|
{
|
2021-09-17 23:05:23 +02:00
|
|
|
vlog_info(STEAM_LIBRARY " not found!");
|
2021-09-07 03:56:39 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2021-09-17 22:58:44 +02:00
|
|
|
#define FOREACH_FUNC(rettype, name, params) \
|
Silence GCC warnings about `void*`-to-function-pointer casts
GCC warns on casting `void*` to function pointers. This is because the C
standard makes a clear distinction between pointers to objects (`void*`)
and pointers to functions (function pointers), and does not specify
anything related to being able to cast object pointers to function
pointers.
The warning message is factually wrong, though - it states that it is
forbidden by ISO C, when in fact it is not, and is actually just
unspecified.
We can't get rid of the cast entirely, because we need the explicit cast
(the C standard _does_ mandate you need an explicit cast when converting
between object pointers and function pointers), and at the end of the
day, this is simply how `SDL_LoadFunction()` works (and more
importantly, how `dlsym()` works), so we can't get rid of it, and we
have no reason to anyways since it means we don't have a hard runtime
dependency on Steam (unlike some other games) and casting `void*` to
function pointers always behaves well on every single platform we ship
on that supports Steam.
Unfortunately, this warning seems to be a part of -Wpedantic, and
there's no way to disable this warning specifically without disabling
-Wpedantic. Luckily, I've found a workaround - just cast to `intptr_t`
before casting to the function pointer. Hopefully the compiler doesn't
get smarter in the future and this ends up breaking or anything...
2021-10-21 10:00:06 +02:00
|
|
|
name = (rettype (*) params) (intptr_t) SDL_LoadFunction(libHandle, #name); \
|
2021-09-17 22:53:52 +02:00
|
|
|
if (!name) \
|
|
|
|
{ \
|
2021-09-17 23:05:23 +02:00
|
|
|
vlog_error(STEAM_LIBRARY " symbol " #name " not found!"); \
|
2021-09-17 22:53:52 +02:00
|
|
|
ClearPointers(); \
|
|
|
|
return 0; \
|
|
|
|
}
|
|
|
|
FUNC_LIST
|
|
|
|
#undef FOREACH_FUNC
|
2021-09-07 03:56:39 +02:00
|
|
|
|
|
|
|
if (!SteamAPI_Init())
|
|
|
|
{
|
|
|
|
vlog_error("Steamworks not initialized!");
|
|
|
|
ClearPointers();
|
|
|
|
return 0;
|
|
|
|
}
|
2024-01-09 20:30:17 +01:00
|
|
|
SteamAPI_ManualDispatch_Init();
|
2021-09-07 03:56:39 +02:00
|
|
|
steamClient = SteamInternal_CreateInterface(VVVVVV_STEAMCLIENT);
|
|
|
|
steamUser = SteamAPI_GetHSteamUser();
|
|
|
|
steamPipe = SteamAPI_GetHSteamPipe();
|
|
|
|
if (!steamClient || !steamUser || !steamPipe)
|
|
|
|
{
|
|
|
|
SteamAPI_Shutdown();
|
|
|
|
vlog_error(VVVVVV_STEAMCLIENT " not created!");
|
|
|
|
ClearPointers();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
steamUserStats = SteamAPI_ISteamClient_GetISteamUserStats(
|
|
|
|
steamClient,
|
|
|
|
steamUser,
|
|
|
|
steamPipe,
|
|
|
|
VVVVVV_STEAMUSERSTATS
|
|
|
|
);
|
|
|
|
if (!steamUserStats)
|
|
|
|
{
|
|
|
|
SteamAPI_Shutdown();
|
|
|
|
vlog_error(VVVVVV_STEAMUSERSTATS " not created!");
|
|
|
|
ClearPointers();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
SteamAPI_ISteamUserStats_RequestCurrentStats(steamUserStats);
|
2024-01-09 20:30:17 +01:00
|
|
|
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);
|
2021-09-07 03:56:39 +02:00
|
|
|
return 1;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
Explicitly declare void for all void parameter functions (#628)
Apparently in C, if you have `void test();`, it's completely okay to do
`test(2);`. The function will take in the argument, but just discard it
and throw it away. It's like a trash can, and a rude one at that. If you
declare it like `void test(void);`, this is prevented.
This is not a problem in C++ - doing `void test();` and `test(2);` is
guaranteed to result in a compile error (this also means that right now,
at least in all `.cpp` files, nobody is ever calling a void parameter
function with arguments and having their arguments be thrown away).
However, we may not be using C++ in the future, so I just want to lay
down the precedent that if a function takes in no arguments, you must
explicitly declare it as such.
I would've added `-Wstrict-prototypes`, but it produces an annoying
warning message saying it doesn't work in C++ mode if you're compiling
in C++ mode. So it can be added later.
2021-02-25 23:23:59 +01:00
|
|
|
void STEAM_shutdown(void)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2021-09-07 03:56:39 +02:00
|
|
|
if (libHandle)
|
|
|
|
{
|
|
|
|
SteamAPI_Shutdown();
|
|
|
|
ClearPointers();
|
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
Explicitly declare void for all void parameter functions (#628)
Apparently in C, if you have `void test();`, it's completely okay to do
`test(2);`. The function will take in the argument, but just discard it
and throw it away. It's like a trash can, and a rude one at that. If you
declare it like `void test(void);`, this is prevented.
This is not a problem in C++ - doing `void test();` and `test(2);` is
guaranteed to result in a compile error (this also means that right now,
at least in all `.cpp` files, nobody is ever calling a void parameter
function with arguments and having their arguments be thrown away).
However, we may not be using C++ in the future, so I just want to lay
down the precedent that if a function takes in no arguments, you must
explicitly declare it as such.
I would've added `-Wstrict-prototypes`, but it produces an annoying
warning message saying it doesn't work in C++ mode if you're compiling
in C++ mode. So it can be added later.
2021-02-25 23:23:59 +01:00
|
|
|
void STEAM_update(void)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2024-01-09 20:30:17 +01:00
|
|
|
if (!libHandle)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
SteamAPI_ManualDispatch_RunFrame(steamPipe);
|
|
|
|
struct CallbackMsg_t callback;
|
|
|
|
SDL_zero(callback);
|
|
|
|
while (SteamAPI_ManualDispatch_GetNextCallback(steamPipe, &callback))
|
2021-09-07 03:56:39 +02:00
|
|
|
{
|
2024-01-09 20:30:17 +01:00
|
|
|
if (callback.m_iCallback == iScreenshotRequested)
|
|
|
|
{
|
|
|
|
run_screenshot();
|
|
|
|
}
|
|
|
|
SteamAPI_ManualDispatch_FreeLastCallback(steamPipe);
|
2021-09-07 03:56:39 +02:00
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
2020-01-13 17:15:17 +01:00
|
|
|
void STEAM_unlockAchievement(const char *name)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2021-09-07 03:56:39 +02:00
|
|
|
if (libHandle)
|
|
|
|
{
|
|
|
|
SteamAPI_ISteamUserStats_SetAchievement(
|
|
|
|
steamUserStats,
|
|
|
|
name
|
|
|
|
);
|
|
|
|
SteamAPI_ISteamUserStats_StoreStats(steamUserStats);
|
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
2020-08-03 05:35:00 +02:00
|
|
|
#endif /* MAKEANDPLAY */
|