1 // Voidwrap - A Steam API wrapper.
2 
3 #define VOIDWRAP_ISEXPORTING
4 #include "voidwrap_steam.h"
5 #include "steam_api.h"
6 #include "compat.h"
7 
8 static uint64_t AppID;
9 static VW_VOID_CONSTCHARPTR Callback_PrintDebug;
10 
PrintDebug(const char * fmt,...)11 static void PrintDebug(const char * fmt, ...)
12 {
13     if (Callback_PrintDebug == nullptr)
14         return;
15 
16     static char tmpstr[8192];
17     va_list va;
18 
19     va_start(va, fmt);
20     Bvsnprintf(tmpstr, sizeof(tmpstr), fmt, va);
21     va_end(va);
22 
23     Callback_PrintDebug(tmpstr);
24 }
25 
SteamAPIWarningMessageHook(int nSeverity,const char * pchDebugText)26 static void SteamAPIWarningMessageHook(int nSeverity, const char * pchDebugText)
27 {
28     UNREFERENCED_PARAMETER(nSeverity);
29 
30     if (Callback_PrintDebug == nullptr)
31         return;
32 
33     Callback_PrintDebug(pchDebugText);
34 }
35 
36 #ifdef VWDEBUG
Voidwrap_Steam_SetCallback_PrintDebug(VW_VOID_CONSTCHARPTR function)37 VOIDWRAP_API void Voidwrap_Steam_SetCallback_PrintDebug(VW_VOID_CONSTCHARPTR function)
38 {
39     Callback_PrintDebug = function;
40 }
41 #endif
42 
43 
44 class SteamStatsAndAchievementsHandler
45 {
46 public:
SteamStatsAndAchievementsHandler()47     SteamStatsAndAchievementsHandler()
48         : m_pSteamUserStats{SteamUserStats()}
49     { }
50 
51     void SetAchievement(char const * id);
52     void SetStat(char const * id, int32_t value);
53     void ResetStats();
54 
55     STEAM_CALLBACK(SteamStatsAndAchievementsHandler, OnUserStatsReceived, UserStatsReceived_t);
56     STEAM_CALLBACK(SteamStatsAndAchievementsHandler, OnUserStatsStored, UserStatsStored_t);
57 
58     void Process();
59 
60 private:
61     ISteamUserStats * m_pSteamUserStats;
62 
63     bool m_bRequestedStats{};
64     bool m_bStatsValid{};
65 
66     bool m_bStoreStats{};
67 };
68 
SetAchievement(char const * id)69 void SteamStatsAndAchievementsHandler::SetAchievement(char const * id)
70 {
71     if (nullptr == m_pSteamUserStats)
72         return;
73 
74     m_pSteamUserStats->SetAchievement(id);
75 
76     m_bStoreStats = true;
77 }
78 
SetStat(char const * id,int32_t value)79 void SteamStatsAndAchievementsHandler::SetStat(char const * id, int32_t value)
80 {
81     if (nullptr == m_pSteamUserStats)
82         return;
83 
84     m_pSteamUserStats->SetStat(id, value);
85 
86     m_bStoreStats = true;
87 }
88 
ResetStats()89 void SteamStatsAndAchievementsHandler::ResetStats()
90 {
91     if (nullptr == m_pSteamUserStats)
92         return;
93 
94     m_pSteamUserStats->ResetAllStats(true);
95     m_bStatsValid     = false;
96     m_bRequestedStats = false;
97 }
98 
OnUserStatsReceived(UserStatsReceived_t * pCallback)99 void SteamStatsAndAchievementsHandler::OnUserStatsReceived(UserStatsReceived_t * pCallback)
100 {
101     if (nullptr == m_pSteamUserStats || AppID != pCallback->m_nGameID)
102         return;
103 
104     if (k_EResultOK == pCallback->m_eResult)
105         m_bStatsValid = true;
106     else
107         PrintDebug("RequestStats - failed, %d\n", pCallback->m_eResult);
108 }
109 
OnUserStatsStored(UserStatsStored_t * pCallback)110 void SteamStatsAndAchievementsHandler::OnUserStatsStored(UserStatsStored_t * pCallback)
111 {
112     if (AppID != pCallback->m_nGameID)
113         return;
114 
115     if (k_EResultInvalidParam == pCallback->m_eResult)
116         PrintDebug("StoreStats - some failed to validate\n");
117     else
118         PrintDebug("StoreStats - failed, %d\n", pCallback->m_eResult);
119 }
120 
Process()121 void SteamStatsAndAchievementsHandler::Process()
122 {
123     if (nullptr == m_pSteamUserStats)
124         return;
125 
126     if (!m_bRequestedStats)
127     {
128         m_bRequestedStats = m_pSteamUserStats->RequestCurrentStats();
129         return;
130     }
131 
132     if (!m_bStatsValid || !m_bStoreStats)
133         return;
134 
135     m_bStoreStats = !m_pSteamUserStats->StoreStats();
136 }
137 
138 static SteamStatsAndAchievementsHandler * StatsAndAchievementsHandler;
139 
Voidwrap_Steam_UnlockAchievement(char const * id)140 VOIDWRAP_API void Voidwrap_Steam_UnlockAchievement(char const * id)
141 {
142     if (nullptr == StatsAndAchievementsHandler)
143         return;
144 
145     StatsAndAchievementsHandler->SetAchievement(id);
146 }
147 
Voidwrap_Steam_SetStat(char const * id,int32_t value)148 VOIDWRAP_API void Voidwrap_Steam_SetStat(char const * id, int32_t value)
149 {
150     if (nullptr == StatsAndAchievementsHandler)
151         return;
152 
153     StatsAndAchievementsHandler->SetStat(id, value);
154 }
155 
Voidwrap_Steam_ResetStats()156 VOIDWRAP_API void Voidwrap_Steam_ResetStats()
157 {
158     if (nullptr == StatsAndAchievementsHandler)
159         return;
160 
161     StatsAndAchievementsHandler->ResetStats();
162 }
163 
164 #ifdef VWSCREENSHOT
165 class SteamScreenshotHandler
166 {
167 private:
168     STEAM_CALLBACK(SteamScreenshotHandler, screenshotRequested, ScreenshotRequested_t);
169     STEAM_CALLBACK(SteamScreenshotHandler, screenshotReady, ScreenshotReady_t);
170 };
171 
172 static SteamScreenshotHandler * ScreenHandler;
173 static VW_VOID Callback_ScreenshotRequested;
174 // static VW_VOID_INT32 Callback_ScreenshotReady;
175 
Voidwrap_Steam_SetCallback_ScreenshotRequested(VW_VOID function)176 VOIDWRAP_API void Voidwrap_Steam_SetCallback_ScreenshotRequested(VW_VOID function)
177 {
178     Callback_ScreenshotRequested = function;
179 }
180 
181 #if 0
182 VOIDWRAP_API void Voidwrap_Steam_SetCallback_ScreenshotReady(VW_VOID_INT32 function)
183 {
184     Callback_ScreenshotReady = function;
185 }
186 #endif
187 
Voidwrap_Steam_SendScreenshot(char * filepath,int32_t width,int32_t height)188 VOIDWRAP_API bool Voidwrap_Steam_SendScreenshot(char * filepath, int32_t width, int32_t height)
189 {
190     if (INVALID_SCREENSHOT_HANDLE == SteamScreenshots()->AddScreenshotToLibrary(filepath, nullptr, width, height))
191     {
192         return false;
193     }
194 
195     return true;
196 }
197 
screenshotRequested(ScreenshotRequested_t * pCallback)198 void SteamScreenshotHandler::screenshotRequested(ScreenshotRequested_t * pCallback)
199 {
200     if (Callback_ScreenshotRequested != nullptr)
201     {
202         PrintDebug("SteamScreenshotHandler::screenshotRequested executed.");
203         Callback_ScreenshotRequested();
204     }
205 }
206 
screenshotReady(ScreenshotReady_t * pCallback)207 void SteamScreenshotHandler::screenshotReady(ScreenshotReady_t * pCallback)
208 {
209     PrintDebug("SteamScreenshotHandler::screenshotReady executed. Result: %d", pCallback->m_eResult);
210 
211 #if 0
212     if (Callback_ScreenshotReady != nullptr)
213     {
214         Callback_ScreenshotReady(pCallback->m_eResult);
215     }
216 #endif
217 }
218 #endif
219 
220 
Voidwrap_Steam_Init()221 VOIDWRAP_API bool Voidwrap_Steam_Init()
222 {
223     if (!SteamAPI_Init())
224     {
225         SteamAPI_Shutdown();
226         return false;
227     }
228 
229     SteamUtils()->SetWarningMessageHook(&SteamAPIWarningMessageHook);
230     SteamUtils()->SetOverlayNotificationPosition(k_EPositionTopRight);
231     AppID = SteamUtils()->GetAppID();
232 
233 #if 0
234     PrintDebug("AppID is %llu", AppID);
235     if (SteamUtils()->IsOverlayEnabled()) { PrintDebug("Overlay is enabled."); }
236 #endif
237 
238     StatsAndAchievementsHandler = new SteamStatsAndAchievementsHandler{};
239 
240 #ifdef VWSCREENSHOT
241     SteamScreenshots()->HookScreenshots(true);
242     if (SteamScreenshots()->IsScreenshotsHooked()) { PrintDebug("Screenshots hooked."); }
243     ScreenHandler = new SteamScreenshotHandler();
244 #endif
245 
246     SteamAPI_RunCallbacks();
247 
248     return true;
249 }
250 
Voidwrap_Steam_Shutdown()251 VOIDWRAP_API void Voidwrap_Steam_Shutdown()
252 {
253     SteamAPI_Shutdown();
254 }
255 
Voidwrap_Steam_RunCallbacks()256 VOIDWRAP_API void Voidwrap_Steam_RunCallbacks()
257 {
258     StatsAndAchievementsHandler->Process();
259 
260     SteamAPI_RunCallbacks();
261 }
262