1 /*-------------------------------------------------------------------------------
2
3 BARONY
4 File: steam_shared.cpp
5 Desc: various callback functions for steam for editor and barony
6
7 Copyright 2013-2018 (c) Turning Wheel LLC, all rights reserved.
8 See LICENSE for details.
9
10 -------------------------------------------------------------------------------*/
11 #include "main.hpp"
12 #ifdef STEAMWORKS
13 #include <steam/steam_api.h>
14 #include "steam.hpp"
15 #endif
16
17 #ifdef STEAMWORKS
18
CSteamWorkshop()19 CSteamWorkshop::CSteamWorkshop() :
20 createItemResult(),
21 SubmitItemUpdateResult(),
22 UGCUpdateHandle(0),
23 UGCQueryHandle(0),
24 SteamUGCQueryCompleted(),
25 UnsubscribePublishedFileResult(),
26 LastActionResult(),
27 workshopItemTags(),
28 uploadSuccessTicks(0),
29 m_myWorkshopItemToModify(),
30 subscribedCallStatus(0)
31 {
32
33 }
34
CSteamStatistics(SteamStat_t * gStats,SteamGlobalStat_t * gGlobalStats,int numStatistics)35 CSteamStatistics::CSteamStatistics(SteamStat_t* gStats, SteamGlobalStat_t* gGlobalStats, int numStatistics) :
36 m_CallbackUserStatsReceived(this, &CSteamStatistics::OnUserStatsReceived),
37 m_CallbackUserStatsStored(this, &CSteamStatistics::OnUserStatsStored),
38 m_bInitialized(false)
39 //m_CallbackGlobalStatsReceived(this, &CSteamStatistics::OnGlobalStatsReceived),
40 {
41 m_iNumStats = numStatistics;
42 m_iNumGlobalStats = 2;
43 m_pStats = gStats;
44 m_pGlobalStats = gGlobalStats;
45 RequestStats();
46 }
47
CreateItem()48 void CSteamWorkshop::CreateItem()
49 {
50 SteamAPICall_t hSteamAPICall = SteamUGC()->CreateItem(STEAM_APPID, k_EWorkshopFileTypeCommunity);
51 m_callResultCreateItem.Set(hSteamAPICall, this,
52 &CSteamWorkshop::OnCreateItem);
53 }
54
OnCreateItem(CreateItemResult_t * pResult,bool bIOFailure)55 void CSteamWorkshop::OnCreateItem(CreateItemResult_t *pResult, bool bIOFailure)
56 {
57 if ( !bIOFailure )
58 {
59 createItemResult = *pResult;
60 StoreResultMessage("Item Create: OK", createItemResult.m_eResult);
61 return;
62 }
63 StoreResultMessage("Item Create: ERROR", createItemResult.m_eResult);
64 }
65
StartItemUpdate()66 void CSteamWorkshop::StartItemUpdate()
67 {
68 if ( createItemResult.m_nPublishedFileId != 0 )
69 {
70 UGCUpdateHandle = SteamUGC()->StartItemUpdate(STEAM_APPID, createItemResult.m_nPublishedFileId);
71 StoreResultMessage("Item Update Initialise: OK", createItemResult.m_eResult);
72 return;
73 }
74 StoreResultMessage("Item Update Initialise: ERROR", createItemResult.m_eResult);
75 }
76
StartItemExistingUpdate(PublishedFileId_t fileId)77 void CSteamWorkshop::StartItemExistingUpdate(PublishedFileId_t fileId)
78 {
79 if ( fileId != 0 )
80 {
81 UGCUpdateHandle = SteamUGC()->StartItemUpdate(STEAM_APPID, fileId);
82 StoreResultMessage("Item Update Initialise: OK", static_cast<EResult>(1));
83 return;
84 }
85 StoreResultMessage("Item Update Initialise: ERROR", static_cast<EResult>(0));
86 }
87
SubmitItemUpdate(char * changeNote)88 void CSteamWorkshop::SubmitItemUpdate(char* changeNote)
89 {
90 if ( UGCUpdateHandle != 0 )
91 {
92 SteamAPICall_t hSteamAPICall = SteamUGC()->SubmitItemUpdate(UGCUpdateHandle, changeNote);
93 m_callResultSubmitItemUpdateResult.Set(hSteamAPICall, this,
94 &CSteamWorkshop::OnSubmitItemUpdate);
95 }
96 }
97
OnSubmitItemUpdate(SubmitItemUpdateResult_t * pResult,bool bIOFailure)98 void CSteamWorkshop::OnSubmitItemUpdate(SubmitItemUpdateResult_t *pResult, bool bIOFailure)
99 {
100 if ( !bIOFailure )
101 {
102 SubmitItemUpdateResult = *pResult;
103 StoreResultMessage("Item Update: OK", SubmitItemUpdateResult.m_eResult);
104 return;
105 }
106 StoreResultMessage("Item Update: ERROR", SubmitItemUpdateResult.m_eResult);
107 }
108
CreateQuerySubscribedItems(EUserUGCList itemListType,EUGCMatchingUGCType searchType,EUserUGCListSortOrder sortOrder)109 void CSteamWorkshop::CreateQuerySubscribedItems(EUserUGCList itemListType, EUGCMatchingUGCType searchType, EUserUGCListSortOrder sortOrder)
110 {
111 // searchType can look for all results, items only, guides only etc.
112 // sortOrder will sort results by creation date, subscribed date etc.
113 CSteamID steamID = SteamUser()->GetSteamID();
114 if ( itemListType == k_EUserUGCList_Subscribed )
115 {
116 subscribedCallStatus = 1;
117 }
118 else
119 {
120 subscribedCallStatus = 0;
121 }
122 UGCQueryHandle = SteamUGC()->CreateQueryUserUGCRequest(steamID.GetAccountID(), itemListType,
123 searchType, sortOrder, STEAM_APPID, STEAM_APPID, 1);
124 if ( UGCQueryHandle != k_UGCQueryHandleInvalid )
125 {
126 SteamAPICall_t hSteamAPICall = SteamUGC()->SendQueryUGCRequest(UGCQueryHandle);
127 m_callResultSendQueryUGCRequest.Set(hSteamAPICall, this,
128 &CSteamWorkshop::OnSendQueryUGCRequest);
129 }
130 SteamUGC()->ReleaseQueryUGCRequest(UGCQueryHandle);
131 }
132
OnSendQueryUGCRequest(SteamUGCQueryCompleted_t * pResult,bool bIOFailure)133 void CSteamWorkshop::OnSendQueryUGCRequest(SteamUGCQueryCompleted_t *pResult, bool bIOFailure)
134 {
135 if ( !bIOFailure )
136 {
137 SteamUGCQueryCompleted = *pResult;
138 if ( SteamUGCQueryCompleted.m_eResult == k_EResultOK )
139 {
140 ReadSubscribedItems();
141 StoreResultMessage("Load Subscribed Items: OK", k_EResultOK);
142 if ( subscribedCallStatus == 1 )
143 {
144 subscribedCallStatus = 2;
145 }
146 return;
147 }
148 }
149 StoreResultMessage("Load Subscribed Items: ERROR", SteamUGCQueryCompleted.m_eResult);
150 }
151
ReadSubscribedItems()152 void CSteamWorkshop::ReadSubscribedItems()
153 {
154 if ( SteamUGCQueryCompleted.m_eResult == k_EResultOK )
155 {
156 for ( int i = 0; i < SteamUGCQueryCompleted.m_unNumResultsReturned; ++i )
157 {
158 SteamUGC()->GetQueryUGCResult(SteamUGCQueryCompleted.m_handle,
159 i, &m_subscribedItemListDetails[i]);
160 }
161
162 SteamUGC()->ReleaseQueryUGCRequest(SteamUGCQueryCompleted.m_handle);
163 }
164 }
165
UnsubscribeItemFileID(PublishedFileId_t fileId)166 void CSteamWorkshop::UnsubscribeItemFileID(PublishedFileId_t fileId)
167 {
168 SteamAPICall_t hSteamAPICall = SteamUGC()->UnsubscribeItem(fileId);
169 m_callResultUnsubscribeItemRequest.Set(hSteamAPICall, this,
170 &CSteamWorkshop::OnUnsubscribeItemRequest);
171 }
172
OnUnsubscribeItemRequest(RemoteStorageUnsubscribePublishedFileResult_t * pResult,bool bIOFailure)173 void CSteamWorkshop::OnUnsubscribeItemRequest(RemoteStorageUnsubscribePublishedFileResult_t *pResult, bool bIOFailure)
174 {
175 if ( !bIOFailure )
176 {
177 UnsubscribePublishedFileResult = *pResult;
178 if ( UnsubscribePublishedFileResult.m_eResult == k_EResultOK )
179 {
180 CreateQuerySubscribedItems(k_EUserUGCList_Subscribed, k_EUGCMatchingUGCType_All, k_EUserUGCListSortOrder_LastUpdatedDesc);
181 StoreResultMessage("Unsubscribe Item: OK", k_EResultOK);
182 return;
183 }
184 }
185 StoreResultMessage("Unsubscribe Item: ERROR", UnsubscribePublishedFileResult.m_eResult);
186 }
187
StoreResultMessage(std::string message,EResult result)188 void CSteamWorkshop::StoreResultMessage(std::string message, EResult result)
189 {
190 LastActionResult.actionMsg = message;
191 LastActionResult.lastResult = result;
192 LastActionResult.creationTick = ticks;
193 }
194
RequestStats()195 bool CSteamStatistics::RequestStats()
196 {
197 // Is Steam loaded? If not we can't get stats.
198 if ( NULL == SteamUserStats() || NULL == SteamUser() )
199 {
200 return false;
201 }
202 // Is the user logged on? If not we can't get stats.
203 if ( !SteamUser()->BLoggedOn() )
204 {
205 return false;
206 }
207 // Request user stats.
208 return SteamUserStats()->RequestCurrentStats();
209 }
210
OnUserStatsReceived(UserStatsReceived_t * pCallback)211 void CSteamStatistics::OnUserStatsReceived(UserStatsReceived_t *pCallback)
212 {
213 // we may get callbacks for other games' stats arriving, ignore them
214 if ( pCallback->m_nGameID == STEAM_APPID )
215 {
216 if ( pCallback->m_eResult == k_EResultOK )
217 {
218 // load stats
219 for ( int iStat = 0; iStat < m_iNumStats; ++iStat )
220 {
221 SteamStat_t &stat = m_pStats[iStat];
222 switch ( stat.m_eStatType )
223 {
224 case STEAM_STAT_INT:
225 SteamUserStats()->GetStat(stat.m_pchStatName, &stat.m_iValue);
226 //printlog("%s: %d", stat.m_pchStatName, stat.m_iValue);
227 break;
228 case STEAM_STAT_FLOAT:
229 case STEAM_STAT_AVGRATE:
230 SteamUserStats()->GetStat(stat.m_pchStatName, &stat.m_flValue);
231 break;
232 default:
233 break;
234 }
235 }
236 m_bInitialized = true;
237 SteamUserStats()->RequestGlobalStats(60);
238 printlog("[STEAM]: successfully received Steam user statistics.");
239 }
240 else
241 {
242 printlog("[STEAM]: unsuccessfully received Steam user statistics!");
243 }
244 }
245 else
246 {
247 printlog("[STEAM]: unsuccessfully received Steam user statistics, appID (%d) was invalid!", pCallback->m_nGameID);
248 }
249 }
250
StoreStats()251 bool CSteamStatistics::StoreStats()
252 {
253 if ( m_bInitialized )
254 {
255 // load stats
256 for ( int iStat = 0; iStat < m_iNumStats; ++iStat )
257 {
258 SteamStat_t &stat = m_pStats[iStat];
259 switch ( stat.m_eStatType )
260 {
261 case STEAM_STAT_INT:
262 SteamUserStats()->SetStat(stat.m_pchStatName, stat.m_iValue);
263 break;
264 case STEAM_STAT_FLOAT:
265 SteamUserStats()->SetStat(stat.m_pchStatName, stat.m_flValue);
266 break;
267 case STEAM_STAT_AVGRATE:
268 SteamUserStats()->UpdateAvgRateStat(stat.m_pchStatName, stat.m_flAvgNumerator, stat.m_flAvgDenominator);
269 // The averaged result is calculated for us
270 SteamUserStats()->GetStat(stat.m_pchStatName, &stat.m_flValue);
271 break;
272 default:
273 break;
274 }
275 }
276 return SteamUserStats()->StoreStats();
277 }
278 else
279 {
280 return false;
281 }
282 }
283
OnUserStatsStored(UserStatsStored_t * pCallback)284 void CSteamStatistics::OnUserStatsStored(UserStatsStored_t *pCallback)
285 {
286 // we may get callbacks for other games' stats arriving, ignore them
287 if ( pCallback->m_nGameID == STEAM_APPID )
288 {
289 if ( k_EResultOK == pCallback->m_eResult )
290 {
291 printlog("[STEAM]: successfully stored Steam user statistics.");
292 }
293 else if ( k_EResultInvalidParam == pCallback->m_eResult )
294 {
295 // One or more stats we set broke a constraint. They've been reverted,
296 // and we should re-iterate the values now to keep in sync.
297 printlog("[STEAM]: some Steam user statistics failed to validate, refreshing request!");
298 // Fake up a callback here so that we re-load the values.
299 UserStatsReceived_t callback;
300 callback.m_eResult = k_EResultOK;
301 callback.m_nGameID = STEAM_APPID;
302 OnUserStatsReceived(&callback);
303 }
304 else
305 {
306 printlog("[STEAM]: unsuccessfully stored Steam user statistics!");
307 }
308 }
309 }
310
311 //void CSteamStatistics::OnGlobalStatsReceived(GlobalStatsReceived_t *pCallback)
312 //{
313 // // we may get callbacks for other games' stats arriving, ignore them
314 // if ( pCallback->m_nGameID == STEAM_APPID )
315 // {
316 // if ( pCallback->m_eResult == k_EResultOK )
317 // {
318 // // load stats
319 // for ( int iStat = 0; iStat < m_iNumGlobalStats; ++iStat )
320 // {
321 // SteamGlobalStat_t &stat = m_pGlobalStats[iStat];
322 // switch ( stat.m_eStatType )
323 // {
324 // case STEAM_STAT_INT:
325 // SteamUserStats()->GetGlobalStat(stat.m_pchStatName, &stat.m_iValue);
326 // SteamUserStats()->SetStat(stat.m_pchStatName, static_cast<int>(1));
327 // printlog("%s: %d", stat.m_pchStatName, stat.m_iValue);
328 // break;
329 // case STEAM_STAT_FLOAT:
330 // case STEAM_STAT_AVGRATE:
331 // SteamUserStats()->GetStat(stat.m_pchStatName, &stat.m_flValue);
332 // break;
333 // default:
334 // break;
335 // }
336 // }
337 // //m_bInitialized = true;
338 // printlog("[STEAM]: successfully received Steam user statistics.");
339 // }
340 // else
341 // {
342 // printlog("[STEAM]: unsuccessfully received Steam user statistics!");
343 // }
344 // }
345 // else
346 // {
347 // printlog("[STEAM]: unsuccessfully received Steam user statistics, appID (%d) was invalid!", pCallback->m_nGameID);
348 // }
349 //}
350
ClearAllStats()351 bool CSteamStatistics::ClearAllStats()
352 {
353 if ( m_bInitialized )
354 {
355 if ( SteamUserStats()->ResetAllStats(false) )
356 {
357 RequestStats();
358 }
359 }
360 else
361 {
362 return false;
363 }
364 return true;
365 }
366
367 #endif // STEAMWORKS
368