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