1 /*-------------------------------------------------------------------------------
2 
3 	BARONY
4 	File: steam.cpp
5 	Desc: various callback functions for steam
6 
7 	Copyright 2013-2016 (c) Turning Wheel LLC, all rights reserved.
8 	See LICENSE for details.
9 
10 -------------------------------------------------------------------------------*/
11 
12 #include "main.hpp"
13 #include "game.hpp"
14 #include "stat.hpp"
15 #include "net.hpp"
16 #include "menu.hpp"
17 #include "monster.hpp"
18 #include "scores.hpp"
19 #include "entity.hpp"
20 #include "items.hpp"
21 #include "interface/interface.hpp"
22 #include <SDL_thread.h>
23 #include "player.hpp"
24 #include "mod_tools.hpp"
25 #include "interface/ui.hpp"
26 #ifdef STEAMWORKS
27 #include <steam/steam_api.h>
28 #include <steam/steam_gameserver.h>
29 #include "steam.hpp"
30 #include "lobbies.hpp"
31 #endif
32 
33 #ifdef STEAMWORKS
34 
35 Uint32 numSteamLobbies = 0;
36 int selectedSteamLobby = 0;
37 char lobbyText[MAX_STEAM_LOBBIES][64];
38 void* lobbyIDs[MAX_STEAM_LOBBIES] = { NULL };
39 int lobbyPlayers[MAX_STEAM_LOBBIES] = { 0 };
40 
41 void* steamIDRemote[MAXPLAYERS] = {NULL, NULL, NULL, NULL};
42 
43 char currentLobbyName[32] = { 0 };
44 Uint32 currentSvFlags = 0;
45 #ifdef STEAMWORKS
46 ELobbyType currentLobbyType = k_ELobbyTypePrivate;
47 #endif
48 bool stillConnectingToLobby = false;
49 
50 bool serverLoadingSaveGame = false; // determines whether lobbyToConnectTo is loading a savegame or not
51 void* currentLobby = NULL; // CSteamID to the current game lobby
52 void* lobbyToConnectTo = NULL; // CSteamID of the game lobby that user has been invited to
53 void* steamIDGameServer = NULL; // CSteamID to the current game server
54 uint32_t steamServerIP = 0; // ipv4 address for the current game server
55 uint16_t steamServerPort = 0; // port number for the current game server
56 char pchCmdLine[1024] = { 0 }; // for game join requests
57 
58 // menu stuff
59 bool connectingToLobby = false, connectingToLobbyWindow = false;
60 bool requestingLobbies = false;
61 bool joinLobbyWaitingForHostResponse = false;
62 bool denyLobbyJoinEvent = false;
63 int connectingToLobbyStatus = EResult::k_EResultOK;
64 
65 const std::string CSteamLeaderboards::leaderboardNames[CSteamLeaderboards::k_numLeaderboards] =
66 {
67 	"None",
68 
69 	"Fastest Time (Normal)",
70 	"Highest Score (Normal)",
71 
72 	"Fastest Time (Multiplayer)",
73 	"Highest Score (Multiplayer)",
74 
75 	"Fastest Time (Hell Route)",
76 	"Highest Score (Hell Route)",
77 
78 	"Fastest Time (Hardcore)",
79 	"Highest Score (Hardcore)",
80 
81 	"Fastest Time (Classic)",
82 	"Highest Score (Classic)",
83 
84 	"Fastest Time (Classic Hardcore)",
85 	"Highest Score (Classic Hardcore)",
86 
87 	"Fastest Time (Multiplayer Classic)",
88 	"Highest Score (Multiplayer Classic)",
89 
90 	"Fastest Time (Multiplayer Hell Route)",
91 	"Highest Score (Multiplayer Hell Route)",
92 
93 	"Fastest Time (Normal - Monsters Only)",
94 	"Highest Score (Normal - Monsters Only)",
95 
96 	"Fastest Time (Multiplayer - Monsters Only)",
97 	"Highest Score (Multiplayer - Monsters Only)",
98 
99 	"Fastest Time (Hell Route - Monsters Only)",
100 	"Highest Score (Hell Route - Monsters Only)",
101 
102 	"Fastest Time (Hardcore - Monsters Only)",
103 	"Highest Score (Hardcore - Monsters Only)",
104 
105 	"Fastest Time (Classic - Monsters Only)",
106 	"Highest Score (Classic - Monsters Only)",
107 
108 	"Fastest Time (Classic Hardcore - Monsters Only)",
109 	"Highest Score (Classic Hardcore - Monsters Only)",
110 
111 	"Fastest Time (Multiplayer Classic - Monsters Only)",
112 	"Highest Score (Multiplayer Classic - Monsters Only)",
113 
114 	"Fastest Time (Multiplayer Hell Route - Monsters Only)",
115 	"Highest Score (Multiplayer Hell Route - Monsters Only)"
116 };
117 #endif
118 
119 
120 
121 
122 
123 
124 /* ***** BEGIN UTTER BODGE ***** */
125 
126 //These are all an utter bodge. They really, really should not exist, but potato.
127 
128 
129 #ifdef STEAMWORKS
130 //TODO: Unused?
131 void (*cpp_SteamServerClientWrapper_GameServerPingOnServerResponded)(void* steamID);
132 void (*cpp_SteamServerClientWrapper_OnLobbyDataUpdate)(void* pCallback);
133 void (*cpp_SteamServerClientWrapper_OnSteamShutdown)(void* callback);
134 void (*cpp_SteamServerClientWrapper_OnIPCFailure)(void* failure);
135 void (*cpp_SteamServerClientWrapper_OnP2PSessionRequest)(void* pCallback);
136 void (*cpp_SteamServerClientWrapper_OnP2PSessionConnectFail)(void* pCallback);
137 void (*cpp_SteamServerClientWrapper_OnWorkshopItemInstalled)(void* pParam);
138 void (*cpp_SteamServerClientWrapper_OnGameWebCallback)(void* callback);
139 //void (*cpp_SteamServerClientWrapper_OnGameOverlayActivated)(void *callback);
140 void (*cpp_SteamServerClientWrapper_OnSteamServerConnectFailure)(void* callback);
141 void (*cpp_SteamServerClientWrapper_OnSteamServersDisconnected)(void* callback);
142 void (*cpp_SteamServerClientWrapper_OnSteamServersConnected)(void* callback);
143 void (*cpp_SteamServerClientWrapper_OnAvatarImageLoaded)(void* pCallback);
144 void (*cpp_SteamServerClientWrapper_OnGameJoinRequested)(void* pCallback);
145 void (*cpp_SteamServerClientWrapper_OnLobbyGameCreated)(void* pCallback);
146 void (*cpp_SteamServerClientWrapper_OnLobbyEntered)(void* pCallback, bool bIOFailure); //Where pCallback is a pointer to type LobbyEnter_t.
147 void (*cpp_SteamServerClientWrapper_OnLobbyMatchListCallback)(void* pCallback, bool bIOFailure); //Where pCallback is a pointer to type LobbyMatchList_t.
148 void (*cpp_SteamServerClientWrapper_OnLobbyCreated)(void* pCallback, bool bIOFailure); //Where pCallback is a pointer to type LobbyCreated_t.
149 
150 void (*cpp_SteamServerWrapper_OnValidateAuthTicketResponse)(void* pResponse);
151 void (*cpp_SteamServerWrapper_OnPolicyResponse)(void* pPolicyResponse);
152 void (*cpp_SteamServerWrapper_OnP2PSessionConnectFail)(void* pCallback);
153 void (*cpp_SteamServerWrapper_OnP2PSessionRequest)(void* p_Callback);
154 void (*cpp_SteamServerWrapper_OnSteamServersConnectFailure)(void* pConnectFailure);
155 void (*cpp_SteamServerWrapper_OnSteamServersDisconnected)(void* pLoggedOff);
156 void (*cpp_SteamServerWrapper_OnSteamServersConnected)(void* pLogonSuccess);
157 void (*cpp_SteamServerClientWrapper_OnRequestEncryptedAppTicket)(void* pEncryptedAppTicketResponse, bool bIOFailure); //Where pEncryptedAppTicketResponse is of type
158 
159 
160 
161 class SteamServerWrapper
162 {
163 public:
SteamServerWrapper()164 	SteamServerWrapper()
165 		:
166 		m_CallbackSteamServersConnected(this, &SteamServerWrapper::OnSteamServersConnected),
167 		m_CallbackSteamServersDisconnected(this, &SteamServerWrapper::OnSteamServersDisconnected),
168 		m_CallbackSteamServersConnectFailure( this, &SteamServerWrapper::OnSteamServersConnectFailure ),
169 		m_CallbackPolicyResponse(this, &SteamServerWrapper::OnPolicyResponse),
170 		m_CallbackGSAuthTicketResponse(this, &SteamServerWrapper::OnValidateAuthTicketResponse),
171 		m_CallbackP2PSessionRequest(this, &SteamServerWrapper::OnP2PSessionRequest),
172 		m_CallbackP2PSessionConnectFail(this, &SteamServerWrapper::OnP2PSessionConnectFail)
173 	{
174 		cpp_SteamServerWrapper_OnSteamServersConnected = nullptr;
175 		cpp_SteamServerWrapper_OnSteamServersDisconnected = nullptr;
176 		cpp_SteamServerWrapper_OnSteamServersConnectFailure = nullptr;
177 		cpp_SteamServerWrapper_OnP2PSessionRequest = nullptr;
178 		cpp_SteamServerWrapper_OnP2PSessionConnectFail = nullptr;
179 		cpp_SteamServerWrapper_OnPolicyResponse = nullptr;
180 		cpp_SteamServerWrapper_OnValidateAuthTicketResponse = nullptr;
181 	}
182 
183 	STEAM_GAMESERVER_CALLBACK(SteamServerWrapper, OnSteamServersConnected, SteamServersConnected_t, m_CallbackSteamServersConnected);
184 
185 	STEAM_GAMESERVER_CALLBACK(SteamServerWrapper, OnSteamServersDisconnected, SteamServersDisconnected_t, m_CallbackSteamServersDisconnected);
186 
187 	STEAM_GAMESERVER_CALLBACK(SteamServerWrapper, OnSteamServersConnectFailure, SteamServerConnectFailure_t, m_CallbackSteamServersConnectFailure);
188 
189 	STEAM_GAMESERVER_CALLBACK(SteamServerWrapper, OnPolicyResponse, GSPolicyResponse_t, m_CallbackPolicyResponse);
190 
191 	STEAM_GAMESERVER_CALLBACK(SteamServerWrapper, OnValidateAuthTicketResponse, ValidateAuthTicketResponse_t, m_CallbackGSAuthTicketResponse);
192 
193 	STEAM_GAMESERVER_CALLBACK(SteamServerWrapper, OnP2PSessionRequest, P2PSessionRequest_t, m_CallbackP2PSessionRequest);
194 
195 	STEAM_GAMESERVER_CALLBACK(SteamServerWrapper, OnP2PSessionConnectFail, P2PSessionConnectFail_t, m_CallbackP2PSessionConnectFail);
196 }* steam_server_wrapper;
197 
OnSteamServersConnected(SteamServersConnected_t * pLogonSuccess)198 void SteamServerWrapper::OnSteamServersConnected(SteamServersConnected_t* pLogonSuccess)
199 {
200 	if (cpp_SteamServerWrapper_OnSteamServersConnected)
201 	{
202 		(*cpp_SteamServerWrapper_OnSteamServersConnected)(pLogonSuccess);
203 	}
204 }
205 
OnSteamServersDisconnected(SteamServersDisconnected_t * pLoggedOff)206 void SteamServerWrapper::OnSteamServersDisconnected(SteamServersDisconnected_t* pLoggedOff)
207 {
208 	if (cpp_SteamServerWrapper_OnSteamServersDisconnected)
209 	{
210 		(*cpp_SteamServerWrapper_OnSteamServersDisconnected)(pLoggedOff);
211 	}
212 }
213 
OnSteamServersConnectFailure(SteamServerConnectFailure_t * pConnectFailure)214 void SteamServerWrapper::OnSteamServersConnectFailure(SteamServerConnectFailure_t* pConnectFailure)
215 {
216 	if (cpp_SteamServerWrapper_OnSteamServersConnectFailure)
217 	{
218 		(*cpp_SteamServerWrapper_OnSteamServersConnectFailure)(pConnectFailure);
219 	}
220 }
221 
OnPolicyResponse(GSPolicyResponse_t * pPolicyResponse)222 void SteamServerWrapper::OnPolicyResponse(GSPolicyResponse_t* pPolicyResponse)
223 {
224 	if (cpp_SteamServerWrapper_OnPolicyResponse)
225 	{
226 		(*cpp_SteamServerWrapper_OnPolicyResponse)(pPolicyResponse);
227 	}
228 }
229 
OnValidateAuthTicketResponse(ValidateAuthTicketResponse_t * pResponse)230 void SteamServerWrapper::OnValidateAuthTicketResponse(ValidateAuthTicketResponse_t* pResponse)
231 {
232 	if (cpp_SteamServerWrapper_OnValidateAuthTicketResponse)
233 	{
234 		(*cpp_SteamServerWrapper_OnValidateAuthTicketResponse)(pResponse);
235 	}
236 }
237 
OnP2PSessionRequest(P2PSessionRequest_t * pCallback)238 void SteamServerWrapper::OnP2PSessionRequest(P2PSessionRequest_t* pCallback)
239 {
240 	if (cpp_SteamServerWrapper_OnP2PSessionRequest)
241 	{
242 		(*cpp_SteamServerWrapper_OnP2PSessionRequest)(pCallback);
243 	}
244 }
245 
OnP2PSessionConnectFail(P2PSessionConnectFail_t * pCallback)246 void SteamServerWrapper::OnP2PSessionConnectFail(P2PSessionConnectFail_t* pCallback)
247 {
248 	if (cpp_SteamServerWrapper_OnP2PSessionConnectFail)
249 	{
250 		(*cpp_SteamServerWrapper_OnP2PSessionConnectFail)(pCallback);
251 	}
252 }
253 
cpp_SteamServerWrapper_Instantiate()254 void cpp_SteamServerWrapper_Instantiate()
255 {
256 	steam_server_wrapper = new SteamServerWrapper();
257 }
258 
cpp_SteamServerWrapper_Destroy()259 void cpp_SteamServerWrapper_Destroy()
260 {
261 	delete steam_server_wrapper;
262 	steam_server_wrapper = nullptr;
263 }
264 
265 
266 
267 
268 class SteamServerClientWrapper
269 {
270 public:
SteamServerClientWrapper()271 	SteamServerClientWrapper()
272 		:
273 		m_LobbyGameCreated(this, &SteamServerClientWrapper::OnLobbyGameCreated),
274 		m_GameJoinRequested(this, &SteamServerClientWrapper::OnGameJoinRequested),
275 		m_AvatarImageLoadedCreated(this, &SteamServerClientWrapper::OnAvatarImageLoaded),
276 		m_SteamServersConnected(this, &SteamServerClientWrapper::OnSteamServersConnected),
277 		m_SteamServersDisconnected(this, &SteamServerClientWrapper::OnSteamServersDisconnected),
278 		m_SteamServerConnectFailure(this, &SteamServerClientWrapper::OnSteamServerConnectFailure),
279 		m_CallbackGameOverlayActivated(this, &SteamServerClientWrapper::OnGameOverlayActivated),
280 		m_CallbackGameWebCallback( this, &SteamServerClientWrapper::OnGameWebCallback),
281 		m_CallbackWorkshopItemInstalled(this, &SteamServerClientWrapper::OnWorkshopItemInstalled),
282 		m_CallbackP2PSessionConnectFail(this, &SteamServerClientWrapper::OnP2PSessionConnectFail),
283 		m_CallbackP2PSessionRequest(this, &SteamServerClientWrapper::OnP2PSessionRequest),
284 		m_CallbackLobbyDataUpdate(this, &SteamServerClientWrapper::OnLobbyDataUpdate),
285 		m_IPCFailureCallback(this, &SteamServerClientWrapper::OnIPCFailure),
286 		m_SteamShutdownCallback(this, &SteamServerClientWrapper::OnSteamShutdown),
287 		m_CallbackLobbyMemberUpdate(this, &SteamServerClientWrapper::OnLobbyMemberUpdate)
288 	{
289 		cpp_SteamServerClientWrapper_OnLobbyGameCreated = nullptr;
290 		cpp_SteamServerClientWrapper_OnGameJoinRequested = nullptr;
291 		cpp_SteamServerClientWrapper_OnAvatarImageLoaded = nullptr;
292 		cpp_SteamServerClientWrapper_OnSteamServersConnected = nullptr;
293 		cpp_SteamServerClientWrapper_OnSteamServersDisconnected = nullptr;
294 		cpp_SteamServerClientWrapper_OnSteamServerConnectFailure = nullptr;
295 		//cpp_SteamServerClientWrapper_OnGameOverlayActivated = nullptr;
296 		cpp_SteamServerClientWrapper_OnGameWebCallback = nullptr;
297 		cpp_SteamServerClientWrapper_OnWorkshopItemInstalled = nullptr;
298 		cpp_SteamServerClientWrapper_OnP2PSessionConnectFail = nullptr;
299 		cpp_SteamServerClientWrapper_OnP2PSessionRequest = nullptr;
300 		cpp_SteamServerClientWrapper_OnIPCFailure = nullptr;
301 		cpp_SteamServerClientWrapper_OnSteamShutdown = nullptr;
302 		cpp_SteamServerClientWrapper_OnLobbyDataUpdate = nullptr;
303 	}
304 
305 	STEAM_CALLBACK(SteamServerClientWrapper, OnLobbyDataUpdate, LobbyDataUpdate_t, m_CallbackLobbyDataUpdate);
306 	STEAM_CALLBACK(SteamServerClientWrapper, OnLobbyMemberUpdate, LobbyChatUpdate_t, m_CallbackLobbyMemberUpdate);
307 
308 	STEAM_CALLBACK(SteamServerClientWrapper, OnLobbyGameCreated, LobbyGameCreated_t, m_LobbyGameCreated);
309 
310 	STEAM_CALLBACK(SteamServerClientWrapper, OnGameJoinRequested, GameLobbyJoinRequested_t, m_GameJoinRequested);
311 
312 	//STEAM_CALLBACK( CSpaceWarClient, OnAvatarImageLoaded, AvatarImageLoaded_t, m_AvatarImageLoadedCreated );
313 	STEAM_CALLBACK(SteamServerClientWrapper, OnAvatarImageLoaded, AvatarImageLoaded_t, m_AvatarImageLoadedCreated); //TODO: Finish.
314 
315 	STEAM_CALLBACK(SteamServerClientWrapper, OnSteamServersConnected, SteamServersConnected_t, m_SteamServersConnected);
316 
317 	STEAM_CALLBACK(SteamServerClientWrapper, OnSteamServersDisconnected, SteamServersDisconnected_t, m_SteamServersDisconnected);
318 
319 	STEAM_CALLBACK(SteamServerClientWrapper, OnSteamServerConnectFailure, SteamServerConnectFailure_t, m_SteamServerConnectFailure);
320 
321 	STEAM_CALLBACK(SteamServerClientWrapper, OnGameOverlayActivated, GameOverlayActivated_t, m_CallbackGameOverlayActivated);
322 
323 	//STEAM_CALLBACK( CSpaceWarClient, OnGameWebCallback, GameWebCallback_t, m_CallbackGameWebCallback );
324 	STEAM_CALLBACK(SteamServerClientWrapper, OnGameWebCallback, GameWebCallback_t, m_CallbackGameWebCallback); //TODO: Finish.
325 
326 	//STEAM_CALLBACK(CSpaceWarClient, OnWorkshopItemInstalled, ItemInstalled_t, m_CallbackWorkshopItemInstalled);
327 	STEAM_CALLBACK(SteamServerClientWrapper, OnWorkshopItemInstalled, ItemInstalled_t, m_CallbackWorkshopItemInstalled); //TODO: Finish.
328 
329 	STEAM_CALLBACK(SteamServerClientWrapper, OnP2PSessionConnectFail, P2PSessionConnectFail_t, m_CallbackP2PSessionConnectFail);
330 
331 	STEAM_CALLBACK(SteamServerClientWrapper, OnIPCFailure, IPCFailure_t, m_IPCFailureCallback);
332 
333 	STEAM_CALLBACK(SteamServerClientWrapper, OnSteamShutdown, SteamShutdown_t, m_SteamShutdownCallback);
334 
335 	STEAM_CALLBACK(SteamServerClientWrapper, OnP2PSessionRequest, P2PSessionRequest_t, m_CallbackP2PSessionRequest);
336 
337 	void OnLobbyCreated(LobbyCreated_t* pCallback, bool bIOFailure);
338 	CCallResult<SteamServerClientWrapper, LobbyCreated_t> m_SteamCallResultLobbyCreated;
339 	void m_SteamCallResultLobbyCreated_Set(SteamAPICall_t hSteamAPICall);
340 
341 	void OnLobbyEntered( LobbyEnter_t* pCallback, bool bIOFailure );
342 	CCallResult<SteamServerClientWrapper, LobbyEnter_t> m_SteamCallResultLobbyEntered; //Why isn't this set in the example?
343 	void m_SteamCallResultLobbyEntered_Set(SteamAPICall_t hSteamAPICall);
344 
345 	void OnLobbyMatchListCallback( LobbyMatchList_t* pCallback, bool bIOFailure );
346 	CCallResult<SteamServerClientWrapper, LobbyMatchList_t> m_SteamCallResultLobbyMatchList;
347 	void m_SteamCallResultLobbyMatchList_Set(SteamAPICall_t hSteamAPICall);
348 
349 	// Called when SteamUser()->RequestEncryptedAppTicket() returns asynchronously
350 	void OnRequestEncryptedAppTicket( EncryptedAppTicketResponse_t* pEncryptedAppTicketResponse, bool bIOFailure );
351 	CCallResult<SteamServerClientWrapper, EncryptedAppTicketResponse_t> m_SteamCallResultEncryptedAppTicket;
352 	void m_SteamCallResultEncryptedAppTicket_Set(SteamAPICall_t hSteamAPICall);
353 	void RetrieveSteamIDFromGameServer( uint32_t m_unServerIP, uint16_t m_usServerPort );
354 	void GetNumberOfCurrentPlayers();
355 private:
356 	void OnGetNumberOfCurrentPlayers( NumberOfCurrentPlayers_t *pCallback, bool bIOFailure );
357 	CCallResult< SteamServerClientWrapper, NumberOfCurrentPlayers_t > m_NumberOfCurrentPlayersCallResult;
358 	// simple class to marshal callbacks from pinging a game server
359 	class CGameServerPing : public ISteamMatchmakingPingResponse
360 	{
361 	public:
CGameServerPing()362 		CGameServerPing()
363 		{
364 			m_hGameServerQuery = HSERVERQUERY_INVALID;
365 			m_pClient = NULL;
366 		}
367 
RetrieveSteamIDFromGameServer(SteamServerClientWrapper * pClient,uint32_t unIP,uint16_t unPort)368 		void RetrieveSteamIDFromGameServer( SteamServerClientWrapper* pClient, uint32_t unIP, uint16_t unPort )
369 		{
370 			m_pClient = pClient;
371 			m_hGameServerQuery = SteamMatchmakingServers()->PingServer( unIP, unPort, this );
372 		}
373 
CancelPing()374 		void CancelPing()
375 		{
376 			m_hGameServerQuery = HSERVERQUERY_INVALID;
377 		}
378 
379 		// Server has responded successfully and has updated data
ServerResponded(gameserveritem_t & server)380 		virtual void ServerResponded( gameserveritem_t& server )
381 		{
382 			if ( m_hGameServerQuery != HSERVERQUERY_INVALID && server.m_steamID.IsValid() )
383 			{
384 				(*cpp_SteamServerClientWrapper_GameServerPingOnServerResponded)( static_cast<void*>(&server.m_steamID) );
385 			}
386 
387 			m_hGameServerQuery = HSERVERQUERY_INVALID;
388 		}
389 
390 		// Server failed to respond to the ping request
ServerFailedToRespond()391 		virtual void ServerFailedToRespond()
392 		{
393 			m_hGameServerQuery = HSERVERQUERY_INVALID;
394 		}
395 
396 	private:
397 		HServerQuery m_hGameServerQuery;	// we're pinging a game server so we can convert IP:Port to a steamID
398 		SteamServerClientWrapper* m_pClient;
399 	};
400 	CGameServerPing m_GameServerPing;
401 }* steam_server_client_wrapper; //TODO: Initialize this...where?
402 
403 
404 
OnLobbyDataUpdate(LobbyDataUpdate_t * pCallback)405 void SteamServerClientWrapper::OnLobbyDataUpdate(LobbyDataUpdate_t* pCallback)
406 {
407 	if (cpp_SteamServerClientWrapper_OnLobbyDataUpdate)
408 	{
409 		(*cpp_SteamServerClientWrapper_OnLobbyDataUpdate)(pCallback);
410 	}
411 }
412 
OnLobbyMemberUpdate(LobbyChatUpdate_t * pCallback)413 void SteamServerClientWrapper::OnLobbyMemberUpdate(LobbyChatUpdate_t* pCallback)
414 {
415 	if ( pCallback )
416 	{
417 		if ( !currentLobby )
418 		{
419 			printlog("[STEAM Lobbies]: Error: OnLobbyMemberUpdate: current lobby is null");
420 			printlog("[STEAM Lobbies]: Warning: OnLobbyMemberUpdate received for not current lobby, leaving received lobby");
421 			SteamMatchmaking()->LeaveLobby(pCallback->m_ulSteamIDLobby);
422 		}
423 		else
424 		{
425 			uint64 currentLobbyID = (static_cast<CSteamID*>(currentLobby))->ConvertToUint64();
426 			if ( pCallback->m_ulSteamIDLobby == currentLobbyID )
427 			{
428 				int numLobbyMembers = SteamMatchmaking()->GetNumLobbyMembers(currentLobbyID);
429 				printlog("[STEAM Lobbies]: Info: OnLobbyMemberUpdate received, %d players", numLobbyMembers);
430 				EResult userStatus = EResult::k_EResultFail;
431 				for ( int lobbyMember = 0; lobbyMember < numLobbyMembers; ++lobbyMember )
432 				{
433 					if ( SteamMatchmaking()->GetLobbyMemberByIndex(currentLobbyID, lobbyMember).ConvertToUint64() == pCallback->m_ulSteamIDUserChanged )
434 					{
435 						userStatus = EResult::k_EResultOK;
436 						break;
437 					}
438 				}
439 				if ( userStatus == EResult::k_EResultFail )
440 				{
441 					for ( int i = 0; i < MAXPLAYERS; ++i )
442 					{
443 						if ( steamIDRemote[i] )
444 						{
445 							if ( static_cast<CSteamID*>(steamIDRemote[i])->ConvertToUint64() == pCallback->m_ulSteamIDUserChanged )
446 							{
447 								printlog("[STEAM Lobbies]: Info: OnLobbyMemberUpdate Player has left, NOT freeing player index %d", i);
448 								//SteamNetworking()->CloseP2PSessionWithUser(*static_cast<CSteamID*>(steamIDRemote[i]));
449 								//cpp_Free_CSteamID(steamIDRemote[i]);
450 								//steamIDRemote[i] = nullptr;
451 							}
452 						}
453 					}
454 				}
455 				else if ( userStatus == EResult::k_EResultOK )
456 				{
457 					for ( int i = 0; i < MAXPLAYERS; ++i )
458 					{
459 						if ( steamIDRemote[i] )
460 						{
461 							if ( static_cast<CSteamID*>(steamIDRemote[i])->ConvertToUint64() == pCallback->m_ulSteamIDUserChanged )
462 							{
463 								printlog("[STEAM Lobbies]: Info: OnLobbyMemberUpdate Player index %d has been updated", i);
464 							}
465 						}
466 					}
467 				}
468 			}
469 			else
470 			{
471 				printlog("[STEAM Lobbies]: Warning: OnLobbyMemberUpdate received for not current lobby, leaving received lobby");
472 				SteamMatchmaking()->LeaveLobby(pCallback->m_ulSteamIDLobby);
473 			}
474 		}
475 	}
476 	else
477 	{
478 		printlog("[STEAM Lobbies]: Error: OnLobbyMemberUpdate: null data");
479 	}
480 }
481 
OnP2PSessionRequest(P2PSessionRequest_t * pCallback)482 void SteamServerClientWrapper::OnP2PSessionRequest(P2PSessionRequest_t* pCallback)
483 {
484 	if (cpp_SteamServerClientWrapper_OnP2PSessionRequest)
485 	{
486 		(*cpp_SteamServerClientWrapper_OnP2PSessionRequest)(pCallback);
487 	}
488 }
489 
c_RetrieveSteamIDFromGameServer(uint32_t m_unServerIP,uint16_t m_usServerPort)490 void c_RetrieveSteamIDFromGameServer( uint32_t m_unServerIP, uint16_t m_usServerPort )
491 {
492 	steam_server_client_wrapper->RetrieveSteamIDFromGameServer( m_unServerIP, m_usServerPort );
493 }
494 
RetrieveSteamIDFromGameServer(uint32_t m_unServerIP,uint16_t m_usServerPort)495 void SteamServerClientWrapper::RetrieveSteamIDFromGameServer( uint32_t m_unServerIP, uint16_t m_usServerPort )
496 {
497 	m_GameServerPing.RetrieveSteamIDFromGameServer( this, m_unServerIP, m_usServerPort );
498 }
499 
OnLobbyGameCreated(LobbyGameCreated_t * pCallback)500 void SteamServerClientWrapper::OnLobbyGameCreated(LobbyGameCreated_t* pCallback)
501 {
502 	if (cpp_SteamServerClientWrapper_OnLobbyGameCreated)
503 	{
504 		(*cpp_SteamServerClientWrapper_OnLobbyGameCreated)(pCallback);
505 	}
506 }
507 
OnGameJoinRequested(GameLobbyJoinRequested_t * pCallback)508 void SteamServerClientWrapper::OnGameJoinRequested(GameLobbyJoinRequested_t* pCallback)
509 {
510 	if (cpp_SteamServerClientWrapper_OnGameJoinRequested)
511 	{
512 		(*cpp_SteamServerClientWrapper_OnGameJoinRequested)(pCallback);
513 	}
514 }
515 
OnAvatarImageLoaded(AvatarImageLoaded_t * pCallback)516 void SteamServerClientWrapper::OnAvatarImageLoaded(AvatarImageLoaded_t* pCallback)
517 {
518 	if (cpp_SteamServerClientWrapper_OnAvatarImageLoaded)
519 	{
520 		(*cpp_SteamServerClientWrapper_OnAvatarImageLoaded)(pCallback);
521 	}
522 }
523 
OnSteamServersConnected(SteamServersConnected_t * callback)524 void SteamServerClientWrapper::OnSteamServersConnected(SteamServersConnected_t* callback)
525 {
526 	if (cpp_SteamServerClientWrapper_OnSteamServersConnected)
527 	{
528 		(*cpp_SteamServerClientWrapper_OnSteamServersConnected)(callback);
529 	}
530 }
531 
OnSteamServersDisconnected(SteamServersDisconnected_t * callback)532 void SteamServerClientWrapper::OnSteamServersDisconnected(SteamServersDisconnected_t* callback)
533 {
534 	if (cpp_SteamServerClientWrapper_OnSteamServersDisconnected)
535 	{
536 		(*cpp_SteamServerClientWrapper_OnSteamServersDisconnected)(callback);
537 	}
538 }
539 
OnSteamServerConnectFailure(SteamServerConnectFailure_t * callback)540 void SteamServerClientWrapper::OnSteamServerConnectFailure(SteamServerConnectFailure_t* callback)
541 {
542 	if (cpp_SteamServerClientWrapper_OnSteamServerConnectFailure)
543 	{
544 		(*cpp_SteamServerClientWrapper_OnSteamServerConnectFailure)(callback);
545 	}
546 }
547 
OnGameOverlayActivated(GameOverlayActivated_t * callback)548 void SteamServerClientWrapper::OnGameOverlayActivated(GameOverlayActivated_t* callback)
549 {
550 	if (!callback)
551 	{
552 		return;
553 	}
554 
555 #ifdef STEAMDEBUG
556 	printlog("OnGameOverlayActivated\n");
557 #endif
558 
559 	if (callback->m_bActive)
560 	{
561 		pauseGame(2, MAXPLAYERS);
562 		SDL_SetRelativeMouseMode(SDL_FALSE); //Uncapture mouse. (Workaround for OSX Steam's inability to display a mouse in the game overlay UI)
563 		SDL_ShowCursor(SDL_TRUE); //(Workaround for OSX Steam's inability to display a mouse in the game overlay UI)
564 	}
565 	else
566 	{
567 		if (shootmode && !gamePaused)
568 		{
569 			SDL_SetRelativeMouseMode(SDL_TRUE); //Recapture mouse.
570 		}
571 		SDL_ShowCursor(SDL_FALSE);
572 	}
573 }
574 
OnGameWebCallback(GameWebCallback_t * callback)575 void SteamServerClientWrapper::OnGameWebCallback(GameWebCallback_t* callback)
576 {
577 	if (cpp_SteamServerClientWrapper_OnGameWebCallback)
578 	{
579 		(*cpp_SteamServerClientWrapper_OnGameWebCallback)(callback);
580 	}
581 }
582 
OnWorkshopItemInstalled(ItemInstalled_t * pParam)583 void SteamServerClientWrapper::OnWorkshopItemInstalled(ItemInstalled_t* pParam)
584 {
585 	if (cpp_SteamServerClientWrapper_OnWorkshopItemInstalled)
586 	{
587 		(cpp_SteamServerClientWrapper_OnWorkshopItemInstalled)(pParam);
588 	}
589 }
590 
OnP2PSessionConnectFail(P2PSessionConnectFail_t * pCallback)591 void SteamServerClientWrapper::OnP2PSessionConnectFail(P2PSessionConnectFail_t* pCallback)
592 {
593 	if (cpp_SteamServerClientWrapper_OnP2PSessionConnectFail)
594 	{
595 		(*cpp_SteamServerClientWrapper_OnP2PSessionConnectFail)(pCallback);
596 	}
597 }
598 
OnIPCFailure(IPCFailure_t * failure)599 void SteamServerClientWrapper::OnIPCFailure(IPCFailure_t* failure)
600 {
601 	if (cpp_SteamServerClientWrapper_OnIPCFailure)
602 	{
603 		(*cpp_SteamServerClientWrapper_OnIPCFailure)(failure);
604 	}
605 }
606 
OnSteamShutdown(SteamShutdown_t * callback)607 void SteamServerClientWrapper::OnSteamShutdown(SteamShutdown_t* callback)
608 {
609 	if (cpp_SteamServerClientWrapper_OnSteamShutdown)
610 	{
611 		(*cpp_SteamServerClientWrapper_OnSteamShutdown)(callback);
612 	}
613 }
614 
OnLobbyCreated(LobbyCreated_t * pCallback,bool bIOFailure)615 void SteamServerClientWrapper::OnLobbyCreated(LobbyCreated_t* pCallback, bool bIOFailure)
616 {
617 	if (cpp_SteamServerClientWrapper_OnLobbyCreated)
618 	{
619 		(*cpp_SteamServerClientWrapper_OnLobbyCreated)(pCallback, bIOFailure);
620 	}
621 }
622 
m_SteamCallResultLobbyCreated_Set(SteamAPICall_t hSteamAPICall)623 void SteamServerClientWrapper::m_SteamCallResultLobbyCreated_Set(SteamAPICall_t hSteamAPICall)
624 {
625 	m_SteamCallResultLobbyCreated.Set(hSteamAPICall, this, &SteamServerClientWrapper::OnLobbyCreated);
626 }
627 
OnLobbyMatchListCallback(LobbyMatchList_t * pCallback,bool bIOFailure)628 void SteamServerClientWrapper::OnLobbyMatchListCallback(LobbyMatchList_t* pCallback, bool bIOFailure)
629 {
630 	if (cpp_SteamServerClientWrapper_OnLobbyMatchListCallback)
631 	{
632 		(*cpp_SteamServerClientWrapper_OnLobbyMatchListCallback)(pCallback, bIOFailure);
633 	}
634 }
635 
m_SteamCallResultLobbyMatchList_Set(SteamAPICall_t hSteamAPICall)636 void SteamServerClientWrapper::m_SteamCallResultLobbyMatchList_Set(SteamAPICall_t hSteamAPICall)
637 {
638 	m_SteamCallResultLobbyMatchList.Set( hSteamAPICall, this, &SteamServerClientWrapper::OnLobbyMatchListCallback );
639 }
640 
OnLobbyEntered(LobbyEnter_t * pCallback,bool bIOFailure)641 void SteamServerClientWrapper::OnLobbyEntered(LobbyEnter_t* pCallback, bool bIOFailure)
642 {
643 	if (cpp_SteamServerClientWrapper_OnLobbyEntered)
644 	{
645 		(*cpp_SteamServerClientWrapper_OnLobbyEntered)(pCallback, bIOFailure);
646 	}
647 }
648 
m_SteamCallResultLobbyEntered_Set(SteamAPICall_t hSteamAPICall)649 void SteamServerClientWrapper::m_SteamCallResultLobbyEntered_Set(SteamAPICall_t hSteamAPICall)
650 {
651 	m_SteamCallResultLobbyEntered.Set(hSteamAPICall, this, &SteamServerClientWrapper::OnLobbyEntered);
652 }
653 
OnRequestEncryptedAppTicket(EncryptedAppTicketResponse_t * pEncryptedAppTicketResponse,bool bIOFailure)654 void SteamServerClientWrapper::OnRequestEncryptedAppTicket(EncryptedAppTicketResponse_t* pEncryptedAppTicketResponse, bool bIOFailure)
655 {
656 	if (cpp_SteamServerClientWrapper_OnRequestEncryptedAppTicket)
657 	{
658 		(*cpp_SteamServerClientWrapper_OnRequestEncryptedAppTicket)(pEncryptedAppTicketResponse, bIOFailure);
659 	}
660 }
661 
m_SteamCallResultEncryptedAppTicket_Set(SteamAPICall_t hSteamAPICall)662 void SteamServerClientWrapper::m_SteamCallResultEncryptedAppTicket_Set(SteamAPICall_t hSteamAPICall)
663 {
664 	m_SteamCallResultEncryptedAppTicket.Set(hSteamAPICall, this, &SteamServerClientWrapper::OnRequestEncryptedAppTicket);
665 }
666 
cpp_SteamMatchmaking_RequestAppTicket()667 SteamAPICall_t cpp_SteamMatchmaking_RequestAppTicket()
668 {
669 	char someData[] = "data";
670 	SteamAPICall_t m_SteamCallResultEncryptedAppTicket = SteamUser()->RequestEncryptedAppTicket(someData, sizeof(someData));
671 	steam_server_client_wrapper->m_SteamCallResultEncryptedAppTicket_Set(m_SteamCallResultEncryptedAppTicket);
672 	return m_SteamCallResultEncryptedAppTicket;
673 }
674 
cpp_SteamMatchmaking_RequestLobbyList()675 SteamAPICall_t cpp_SteamMatchmaking_RequestLobbyList()
676 {
677 	SteamMatchmaking()->AddRequestLobbyListNearValueFilter("lobbyCreationTime", SteamUtils()->GetServerRealTime());
678 	SteamMatchmaking()->AddRequestLobbyListNumericalFilter("lobbyModifiedTime",
679 		SteamUtils()->GetServerRealTime() - 8, k_ELobbyComparisonEqualToOrGreaterThan);
680 	SteamAPICall_t m_SteamCallResultLobbyMatchList = SteamMatchmaking()->RequestLobbyList();
681 	steam_server_client_wrapper->m_SteamCallResultLobbyMatchList_Set(m_SteamCallResultLobbyMatchList);
682 	return m_SteamCallResultLobbyMatchList;
683 }
684 
cpp_SteamMatchmaking_JoinLobby(CSteamID steamIDLobby)685 SteamAPICall_t cpp_SteamMatchmaking_JoinLobby(CSteamID steamIDLobby)
686 {
687 	SteamAPICall_t steamAPICall = SteamMatchmaking()->JoinLobby(steamIDLobby);
688 	steam_server_client_wrapper->m_SteamCallResultLobbyEntered_Set(steamAPICall);
689 	return steamAPICall;
690 }
691 
cpp_SteamMatchmaking_CreateLobby(ELobbyType eLobbyType,int cMaxMembers)692 SteamAPICall_t cpp_SteamMatchmaking_CreateLobby(ELobbyType eLobbyType, int cMaxMembers)
693 {
694 	SteamAPICall_t steamAPICall = SteamMatchmaking()->CreateLobby(eLobbyType, cMaxMembers);
695 	steam_server_client_wrapper->m_SteamCallResultLobbyCreated_Set(steamAPICall);
696 	return steamAPICall;
697 }
698 
cpp_SteamServerClientWrapper_Instantiate()699 void cpp_SteamServerClientWrapper_Instantiate()
700 {
701 	steam_server_client_wrapper = new SteamServerClientWrapper();
702 }
703 
cpp_SteamServerClientWrapper_Destroy()704 void cpp_SteamServerClientWrapper_Destroy()
705 {
706 	delete steam_server_client_wrapper;
707 	steam_server_client_wrapper = nullptr;
708 }
709 
710 // Make the asynchronous request to receive the number of current players.
GetNumberOfCurrentPlayers()711 void SteamServerClientWrapper::GetNumberOfCurrentPlayers()
712 {
713 	//printlog("Getting Number of Current Players\n");
714 	SteamAPICall_t hSteamAPICall = SteamUserStats()->GetNumberOfCurrentPlayers();
715 	m_NumberOfCurrentPlayersCallResult.Set(hSteamAPICall, this, &SteamServerClientWrapper::OnGetNumberOfCurrentPlayers);
716 }
717 
718 // Called when SteamUserStats()->GetNumberOfCurrentPlayers() returns asynchronously, after a call to SteamAPI_RunCallbacks().
OnGetNumberOfCurrentPlayers(NumberOfCurrentPlayers_t * pCallback,bool bIOFailure)719 void SteamServerClientWrapper::OnGetNumberOfCurrentPlayers(NumberOfCurrentPlayers_t *pCallback, bool bIOFailure)
720 {
721 	if ( bIOFailure || !pCallback->m_bSuccess )
722 	{
723 		//printlog("NumberOfCurrentPlayers_t failed!\n");
724 		return;
725 	}
726 
727 	//printlog("Number of players currently playing: %d\n", pCallback->m_cPlayers);
728 }
729 
730 #endif //defined Steamworks
731 
732 /* ***** END UTTER BODGE ***** */
733 
734 
735 
736 
737 /*-------------------------------------------------------------------------------
738 
739 	achievementUnlocked
740 
741 	Returns true if the given achievement has been unlocked this game,
742 	false otherwise
743 
744 -------------------------------------------------------------------------------*/
745 
achievementUnlocked(const char * achName)746 bool achievementUnlocked(const char* achName)
747 {
748 	// check internal achievement record
749 	return (achievementUnlockedLookup.find(achName) != achievementUnlockedLookup.end());
750 }
751 
752 /*-------------------------------------------------------------------------------
753 
754 	steamAchievement
755 
756 	Unlocks a steam achievement
757 
758 -------------------------------------------------------------------------------*/
759 
steamAchievement(const char * achName)760 void steamAchievement(const char* achName)
761 {
762 #ifdef DEBUG_ACHIEVEMENTS
763 	messagePlayer(clientnum, "%s", achName);
764 #endif
765 
766 	if ( gameModeManager.getMode() == GameModeManager_t::GAME_MODE_TUTORIAL )
767 	{
768 		if ( !achievementObserver.bIsAchievementAllowedDuringTutorial(achName) )
769 		{
770 			return;
771 		}
772 		if ( conductGameChallenges[CONDUCT_CHEATS_ENABLED] )
773 		{
774 			return;
775 		}
776 	}
777 	else
778 	{
779 		if ( conductGameChallenges[CONDUCT_CHEATS_ENABLED]
780 			|| conductGameChallenges[CONDUCT_LIFESAVING]
781 			|| gamemods_disableSteamAchievements )
782 		{
783 		// cheats/mods have been enabled on savefile, disallow achievements.
784 #ifndef DEBUG_ACHIEVEMENTS
785 			return;
786 #endif
787 		}
788 	}
789 
790 	if ( !strcmp(achName, "BARONY_ACH_BOOTS_OF_SPEED") )
791 	{
792 		conductGameChallenges[CONDUCT_BOOTS_SPEED] = 1; // to cover bases when lich or devil dies as we can't remotely update this for clients.
793 	}
794 	//messagePlayer(clientnum, "%s", achName);
795 
796 	if ( !achievementUnlocked(achName) )
797 	{
798 		//messagePlayer(clientnum, "You've unlocked an achievement!\n [%s]",c_SteamUserStats_GetAchievementDisplayAttribute(achName,"name"));
799 
800 #ifdef STEAMWORKS
801 		SteamUserStats()->SetAchievement(achName);
802 		SteamUserStats()->StoreStats();
803 #else
804 #ifdef USE_EOS
805 		EOS.unlockAchievement(achName);
806 #endif
807 #endif
808 		achievementUnlockedLookup.insert(std::string(achName));
809 	}
810 }
811 
steamUnsetAchievement(const char * achName)812 void steamUnsetAchievement(const char* achName)
813 {
814 #ifdef USE_EOS
815 	printlog("unset achievement not supported for epic online services");
816 #endif
817 #ifndef STEAMWORKS
818 	return;
819 #else
820 #ifdef DEBUG_ACHIEVEMENTS
821 	SteamUserStats()->ClearAchievement(achName);
822 #endif // DEBUG_ACHIEVEMENTS
823 #endif
824 }
825 
826 /*-------------------------------------------------------------------------------
827 
828 	steamAchievementClient
829 
830 	Tells a client to unlock a steam achievement (server only)
831 
832 -------------------------------------------------------------------------------*/
833 
steamAchievementClient(int player,const char * achName)834 void steamAchievementClient(int player, const char* achName)
835 {
836 	if ( multiplayer == CLIENT )
837 	{
838 		return;
839 	}
840 
841 	if ( player < 0 || player >= MAXPLAYERS )
842 	{
843 		return;
844 	}
845 	else if ( player == 0 )
846 	{
847 		steamAchievement(achName);
848 	}
849 	else
850 	{
851 		if ( client_disconnected[player] || multiplayer == SINGLE )
852 		{
853 			return;
854 		}
855 		strcpy((char*)net_packet->data, "SACH");
856 		strcpy((char*)(&net_packet->data[4]), achName);
857 		net_packet->address.host = net_clients[player - 1].host;
858 		net_packet->address.port = net_clients[player - 1].port;
859 		net_packet->len = 4 + strlen(achName) + 1;
860 		sendPacketSafe(net_sock, -1, net_packet, player - 1);
861 	}
862 }
863 
steamAchievementEntity(Entity * my,const char * achName)864 void steamAchievementEntity(Entity* my, const char* achName)
865 {
866 	if ( !my )
867 	{
868 		return;
869 	}
870 
871 	if ( my->behavior == &actPlayer )
872 	{
873 		steamAchievementClient(my->skill[2], achName);
874 	}
875 }
876 
steamStatisticUpdate(int statisticNum,ESteamStatTypes type,int value)877 void steamStatisticUpdate(int statisticNum, ESteamStatTypes type, int value)
878 {
879 	if ( gameModeManager.getMode() == GameModeManager_t::GAME_MODE_TUTORIAL )
880 	{
881 		if ( !achievementObserver.bIsStatisticAllowedDuringTutorial(static_cast<SteamStatIndexes>(statisticNum)) )
882 		{
883 			return;
884 		}
885 		if ( conductGameChallenges[CONDUCT_CHEATS_ENABLED] )
886 		{
887 			return;
888 		}
889 	}
890 	else
891 	{
892 		if ( conductGameChallenges[CONDUCT_CHEATS_ENABLED]
893 			|| conductGameChallenges[CONDUCT_LIFESAVING]
894 			|| gamemods_disableSteamAchievements )
895 		{
896 		// cheats/mods have been enabled on savefile, disallow statistics update.
897 #ifndef DEBUG_ACHIEVEMENTS
898 		return;
899 #endif
900 		}
901 	}
902 
903 	if ( statisticNum >= NUM_STEAM_STATISTICS || statisticNum < 0 )
904 	{
905 		return;
906 	}
907 
908 	bool indicateProgress = true;
909 	bool result = false;
910 	switch ( type )
911 	{
912 		case STEAM_STAT_INT:
913 		{
914 			int oldValue = g_SteamStats[statisticNum].m_iValue;
915 			g_SteamStats[statisticNum].m_iValue += value;
916 			switch ( statisticNum )
917 			{
918 				case STEAM_STAT_RHINESTONE_COWBOY:
919 				case STEAM_STAT_TOUGH_AS_NAILS:
920 				case STEAM_STAT_UNSTOPPABLE_FORCE:
921 				case STEAM_STAT_BOMBARDIER:
922 				case STEAM_STAT_IN_THE_MIX:
923 				case STEAM_STAT_FREE_REFILLS:
924 				case STEAM_STAT_TAKE_THIS_OUTSIDE:
925 				case STEAM_STAT_BLOOD_SPORT:
926 				case STEAM_STAT_IRON_GUT:
927 				case STEAM_STAT_BOTTLE_NOSED:
928 				case STEAM_STAT_BARFIGHT_CHAMP:
929 				case STEAM_STAT_VOLATILE:
930 				case STEAM_STAT_SURROGATES:
931 				case STEAM_STAT_KILL_COMMAND:
932 				case STEAM_STAT_SPICY:
933 				case STEAM_STAT_TRADITION:
934 				case STEAM_STAT_POP_QUIZ:
935 				case STEAM_STAT_DYSLEXIA:
936 				case STEAM_STAT_BOOKWORM:
937 				case STEAM_STAT_MONARCH:
938 				case STEAM_STAT_MANY_PEDI_PALP:
939 				case STEAM_STAT_5000_SECOND_RULE:
940 				case STEAM_STAT_SOCIAL_BUTTERFLY:
941 				case STEAM_STAT_ROLL_THE_BONES:
942 				case STEAM_STAT_COWBOY_FROM_HELL:
943 				case STEAM_STAT_SELF_FLAGELLATION:
944 				case STEAM_STAT_CHOPPING_BLOCK:
945 				case STEAM_STAT_IF_YOU_LOVE_SOMETHING:
946 				case STEAM_STAT_RAGE_AGAINST:
947 				case STEAM_STAT_GUERILLA_RADIO:
948 				case STEAM_STAT_ITS_A_LIVING:
949 				case STEAM_STAT_FASCIST:
950 					g_SteamStats[statisticNum].m_iValue =
951 						std::min(g_SteamStats[statisticNum].m_iValue, steamStatAchStringsAndMaxVals[statisticNum].second);
952 					break;
953 				case STEAM_STAT_ALTER_EGO:
954 					indicateProgress = false;
955 					g_SteamStats[statisticNum].m_iValue =
956 						std::min(g_SteamStats[statisticNum].m_iValue, steamStatAchStringsAndMaxVals[statisticNum].second);
957 					if ( g_SteamStats[statisticNum].m_iValue == steamStatAchStringsAndMaxVals[statisticNum].second )
958 					{
959 						indicateProgress = true;
960 					}
961 					else if ( oldValue == 0 && g_SteamStats[statisticNum].m_iValue > 0 )
962 					{
963 						indicateProgress = true;
964 					}
965 					else if ( oldValue < 1000 && ((oldValue / 1000) < (g_SteamStats[statisticNum].m_iValue / 1000)) )
966 					{
967 						indicateProgress = true;
968 					}
969 					else if ( ((oldValue / 5000) < (g_SteamStats[statisticNum].m_iValue / 5000)) )
970 					{
971 						indicateProgress = true;
972 					}
973 					break;
974 				case STEAM_STAT_BAD_BLOOD:
975 					indicateProgress = false;
976 					g_SteamStats[statisticNum].m_iValue =
977 						std::min(g_SteamStats[statisticNum].m_iValue, steamStatAchStringsAndMaxVals[statisticNum].second);
978 					if ( g_SteamStats[statisticNum].m_iValue == steamStatAchStringsAndMaxVals[statisticNum].second )
979 					{
980 						indicateProgress = true;
981 					}
982 					else if ( oldValue == 0 && g_SteamStats[statisticNum].m_iValue > 0 )
983 					{
984 						indicateProgress = true;
985 					}
986 					else if ( oldValue < 20 && ((oldValue / 20) < (g_SteamStats[statisticNum].m_iValue / 20)) )
987 					{
988 						indicateProgress = true;
989 					}
990 					else if ( ((oldValue / 50) < (g_SteamStats[statisticNum].m_iValue / 50)) )
991 					{
992 						indicateProgress = true;
993 					}
994 					break;
995 				case STEAM_STAT_SUPER_SHREDDER:
996 					indicateProgress = false;
997 					g_SteamStats[statisticNum].m_iValue =
998 						std::min(g_SteamStats[statisticNum].m_iValue, steamStatAchStringsAndMaxVals[statisticNum].second);
999 					if ( g_SteamStats[statisticNum].m_iValue == steamStatAchStringsAndMaxVals[statisticNum].second )
1000 					{
1001 						indicateProgress = true;
1002 					}
1003 					else if ( oldValue == 0 && g_SteamStats[statisticNum].m_iValue > 0 )
1004 					{
1005 						indicateProgress = true;
1006 					}
1007 					else if ( oldValue < 25 && ((oldValue / 25) < (g_SteamStats[statisticNum].m_iValue / 25)) )
1008 					{
1009 						indicateProgress = true;
1010 					}
1011 					else if ( ((oldValue / 50) < (g_SteamStats[statisticNum].m_iValue / 50)) ) // show every 50.
1012 					{
1013 						indicateProgress = true;
1014 					}
1015 					break;
1016 				case STEAM_STAT_OVERCLOCKED:
1017 					indicateProgress = false;
1018 					g_SteamStats[statisticNum].m_iValue =
1019 						std::min(g_SteamStats[statisticNum].m_iValue, steamStatAchStringsAndMaxVals[statisticNum].second);
1020 					if ( g_SteamStats[statisticNum].m_iValue == steamStatAchStringsAndMaxVals[statisticNum].second )
1021 					{
1022 						indicateProgress = true;
1023 					}
1024 					else if ( oldValue == 0 && g_SteamStats[statisticNum].m_iValue > 0 )
1025 					{
1026 						indicateProgress = true;
1027 					}
1028 					else if ( oldValue < 30 && ((oldValue / 30) < (g_SteamStats[statisticNum].m_iValue / 30)) )
1029 					{
1030 						indicateProgress = true;
1031 					}
1032 					else if ( ((oldValue / 60) < (g_SteamStats[statisticNum].m_iValue / 60)) ) // show every 60.
1033 					{
1034 						indicateProgress = true;
1035 					}
1036 					break;
1037 				case STEAM_STAT_SERIAL_THRILLA:
1038 				case STEAM_STAT_TRASH_COMPACTOR:
1039 				case STEAM_STAT_TORCHERER:
1040 				case STEAM_STAT_FIXER_UPPER:
1041 					indicateProgress = false;
1042 					g_SteamStats[statisticNum].m_iValue =
1043 						std::min(g_SteamStats[statisticNum].m_iValue, steamStatAchStringsAndMaxVals[statisticNum].second);
1044 					if ( g_SteamStats[statisticNum].m_iValue == steamStatAchStringsAndMaxVals[statisticNum].second )
1045 					{
1046 						indicateProgress = true;
1047 					}
1048 					else if ( oldValue == 0 && g_SteamStats[statisticNum].m_iValue > 0 )
1049 					{
1050 						indicateProgress = true;
1051 					}
1052 					else if ( oldValue < 10 && ((oldValue / 10) < (g_SteamStats[statisticNum].m_iValue / 10)) )
1053 					{
1054 						indicateProgress = true;
1055 					}
1056 					else if ( ((oldValue / 25) < (g_SteamStats[statisticNum].m_iValue / 25)) ) // show every 25.
1057 					{
1058 						indicateProgress = true;
1059 					}
1060 					break;
1061 				case STEAM_STAT_DIPLOMA_LVLS:
1062 				case STEAM_STAT_EXTRA_CREDIT_LVLS:
1063 				case STEAM_STAT_BACK_TO_BASICS:
1064 					g_SteamStats[statisticNum].m_iValue =
1065 						std::min(g_SteamStats[statisticNum].m_iValue, steamStatAchStringsAndMaxVals[statisticNum].second);
1066 					indicateProgress = false;
1067 					break;
1068 				case STEAM_STAT_DIPLOMA:
1069 				case STEAM_STAT_EXTRA_CREDIT:
1070 					g_SteamStats[statisticNum].m_iValue =
1071 						std::min(g_SteamStats[statisticNum].m_iValue, steamStatAchStringsAndMaxVals[statisticNum].second);
1072 					if ( g_SteamStats[statisticNum].m_iValue == steamStatAchStringsAndMaxVals[statisticNum].second )
1073 					{
1074 						indicateProgress = true;
1075 					}
1076 					else if ( oldValue == g_SteamStats[statisticNum].m_iValue )
1077 					{
1078 						indicateProgress = false;
1079 					}
1080 					else
1081 					{
1082 						indicateProgress = true;
1083 					}
1084 					break;
1085 				case STEAM_STAT_TUTORIAL_ENTERED:
1086 					g_SteamStats[statisticNum].m_iValue =
1087 						std::min(g_SteamStats[statisticNum].m_iValue, steamStatAchStringsAndMaxVals[statisticNum].second);
1088 					if ( oldValue == 0 )
1089 					{
1090 						achievementObserver.updateGlobalStat(STEAM_GSTAT_TUTORIAL_ENTERED);
1091 					}
1092 					indicateProgress = false;
1093 					break;
1094 				default:
1095 					break;
1096 			}
1097 			break;
1098 		}
1099 		case STEAM_STAT_FLOAT:
1100 			break;
1101 		default:
1102 			break;
1103 	}
1104 #ifdef STEAMWORKS
1105 	g_SteamStatistics->StoreStats(); // update server's stat counter.
1106 #else
1107 #ifdef USE_EOS
1108 	EOS.ingestStat(statisticNum, g_SteamStats[statisticNum].m_iValue);
1109 #endif
1110 #endif
1111 	if ( indicateProgress )
1112 	{
1113 		steamIndicateStatisticProgress(statisticNum, type);
1114 	}
1115 }
1116 
steamStatisticUpdateClient(int player,int statisticNum,ESteamStatTypes type,int value)1117 void steamStatisticUpdateClient(int player, int statisticNum, ESteamStatTypes type, int value)
1118 {
1119 	if ( gameModeManager.getMode() == GameModeManager_t::GAME_MODE_TUTORIAL )
1120 	{
1121 		if ( !achievementObserver.bIsStatisticAllowedDuringTutorial(static_cast<SteamStatIndexes>(statisticNum)) )
1122 		{
1123 			return;
1124 		}
1125 		if ( conductGameChallenges[CONDUCT_CHEATS_ENABLED] )
1126 		{
1127 			return;
1128 		}
1129 	}
1130 	else
1131 	{
1132 		if ( conductGameChallenges[CONDUCT_CHEATS_ENABLED]
1133 			|| conductGameChallenges[CONDUCT_LIFESAVING]
1134 			|| gamemods_disableSteamAchievements )
1135 		{
1136 			// cheats/mods have been enabled on savefile, disallow statistics update.
1137 #ifndef DEBUG_ACHIEVEMENTS
1138 			return;
1139 #endif
1140 		}
1141 	}
1142 
1143 	if ( statisticNum >= NUM_STEAM_STATISTICS || statisticNum < 0 )
1144 	{
1145 		return;
1146 	}
1147 
1148 	if ( multiplayer == CLIENT )
1149 	{
1150 		return;
1151 	}
1152 
1153 	if ( player == 0 )
1154 	{
1155 		steamStatisticUpdate(statisticNum, type, value);
1156 		return;
1157 	}
1158 	else if ( player < 0 || player >= MAXPLAYERS )
1159 	{
1160 		return;
1161 	}
1162 	else
1163 	{
1164 		if ( client_disconnected[player] || multiplayer == SINGLE )
1165 		{
1166 			return;
1167 		}
1168 		strcpy((char*)net_packet->data, "SSTA");
1169 		net_packet->data[4] = static_cast<Uint8>(statisticNum);
1170 		net_packet->data[5] = static_cast<Uint8>(type);
1171 		SDLNet_Write16(value, &net_packet->data[6]);
1172 		net_packet->address.host = net_clients[player - 1].host;
1173 		net_packet->address.port = net_clients[player - 1].port;
1174 		net_packet->len = 8;
1175 		sendPacketSafe(net_sock, -1, net_packet, player - 1);
1176 	}
1177 }
1178 
indicateAchievementProgressAndUnlock(const char * achName,int currentValue,int maxValue)1179 void indicateAchievementProgressAndUnlock(const char* achName, int currentValue, int maxValue)
1180 {
1181 #ifdef STEAMWORKS
1182 	SteamUserStats()->IndicateAchievementProgress(achName, currentValue, maxValue);
1183 #elif defined USE_EOS
1184 	UIToastNotificationManager.createStatisticUpdateNotification(achName, currentValue, maxValue);
1185 #endif
1186 	if ( currentValue == maxValue )
1187 	{
1188 		steamAchievement(achName);
1189 	}
1190 }
1191 
steamIndicateStatisticProgress(int statisticNum,ESteamStatTypes type)1192 void steamIndicateStatisticProgress(int statisticNum, ESteamStatTypes type)
1193 {
1194 #if (!defined STEAMWORKS && !defined USE_EOS)
1195 	return;
1196 #else
1197 
1198 	if ( statisticNum >= NUM_STEAM_STATISTICS || statisticNum < 0 )
1199 	{
1200 		return;
1201 	}
1202 
1203 	int iVal = g_SteamStats[statisticNum].m_iValue;
1204 	float fVal = g_SteamStats[statisticNum].m_flValue;
1205 	if ( type == STEAM_STAT_INT )
1206 	{
1207 		switch ( statisticNum )
1208 		{
1209 			// below are 30-50 max value
1210 			case STEAM_STAT_RHINESTONE_COWBOY:
1211 			case STEAM_STAT_TOUGH_AS_NAILS:
1212 			case STEAM_STAT_UNSTOPPABLE_FORCE:
1213 			case STEAM_STAT_BOMBARDIER:
1214 			case STEAM_STAT_IN_THE_MIX:
1215 			case STEAM_STAT_FREE_REFILLS:
1216 			case STEAM_STAT_BLOOD_SPORT:
1217 			case STEAM_STAT_BARFIGHT_CHAMP:
1218 			case STEAM_STAT_SURROGATES:
1219 			case STEAM_STAT_KILL_COMMAND:
1220 			case STEAM_STAT_DYSLEXIA:
1221 			case STEAM_STAT_BOOKWORM:
1222 			case STEAM_STAT_5000_SECOND_RULE:
1223 			case STEAM_STAT_SOCIAL_BUTTERFLY:
1224 			case STEAM_STAT_ROLL_THE_BONES:
1225 			case STEAM_STAT_COWBOY_FROM_HELL:
1226 			case STEAM_STAT_SELF_FLAGELLATION:
1227 			case STEAM_STAT_FASCIST:
1228 			case STEAM_STAT_ITS_A_LIVING:
1229 			case STEAM_STAT_CHOPPING_BLOCK:
1230 			case STEAM_STAT_MANY_PEDI_PALP:
1231 				if ( !achievementUnlocked(steamStatAchStringsAndMaxVals[statisticNum].first.c_str()) )
1232 				{
1233 					if ( iVal == 1 || (iVal > 0 && iVal % 5 == 0) )
1234 					{
1235 						indicateAchievementProgressAndUnlock(steamStatAchStringsAndMaxVals[statisticNum].first.c_str(),
1236 							iVal, steamStatAchStringsAndMaxVals[statisticNum].second);
1237 					}
1238 				}
1239 				break;
1240 			// below are 20 max value
1241 			case STEAM_STAT_IRON_GUT:
1242 			case STEAM_STAT_BOTTLE_NOSED:
1243 			case STEAM_STAT_VOLATILE:
1244 			case STEAM_STAT_TRADITION:
1245 			case STEAM_STAT_POP_QUIZ:
1246 			case STEAM_STAT_MONARCH:
1247 			case STEAM_STAT_RAGE_AGAINST:
1248 			case STEAM_STAT_GUERILLA_RADIO:
1249 				if ( !achievementUnlocked(steamStatAchStringsAndMaxVals[statisticNum].first.c_str()) )
1250 				{
1251 					if ( iVal == 1 || (iVal > 0 && iVal % 4 == 0) )
1252 					{
1253 						indicateAchievementProgressAndUnlock(steamStatAchStringsAndMaxVals[statisticNum].first.c_str(),
1254 							iVal, steamStatAchStringsAndMaxVals[statisticNum].second);
1255 					}
1256 				}
1257 				break;
1258 			case STEAM_STAT_BAD_BLOOD:
1259 			case STEAM_STAT_ALTER_EGO:
1260 				if ( !achievementUnlocked(steamStatAchStringsAndMaxVals[statisticNum].first.c_str()) )
1261 				{
1262 					indicateAchievementProgressAndUnlock(steamStatAchStringsAndMaxVals[statisticNum].first.c_str(),
1263 						iVal, steamStatAchStringsAndMaxVals[statisticNum].second);
1264 				}
1265 				break;
1266 			// below is 100 max value
1267 			case STEAM_STAT_SERIAL_THRILLA:
1268 			case STEAM_STAT_TRASH_COMPACTOR:
1269 			case STEAM_STAT_TORCHERER:
1270 			case STEAM_STAT_FIXER_UPPER:
1271 			// below are 1000 max value
1272 			case STEAM_STAT_SUPER_SHREDDER:
1273 				if ( !achievementUnlocked(steamStatAchStringsAndMaxVals[statisticNum].first.c_str()) )
1274 				{
1275 					indicateAchievementProgressAndUnlock(steamStatAchStringsAndMaxVals[statisticNum].first.c_str(),
1276 						iVal, steamStatAchStringsAndMaxVals[statisticNum].second);
1277 				}
1278 				break;
1279 			// below is 600 max value
1280 			case STEAM_STAT_OVERCLOCKED:
1281 				if ( !achievementUnlocked(steamStatAchStringsAndMaxVals[statisticNum].first.c_str()) )
1282 				{
1283 					indicateAchievementProgressAndUnlock(steamStatAchStringsAndMaxVals[statisticNum].first.c_str(),
1284 						iVal, steamStatAchStringsAndMaxVals[statisticNum].second);
1285 				}
1286 				break;
1287 			// below are 100 max value
1288 			case STEAM_STAT_IF_YOU_LOVE_SOMETHING:
1289 				if ( !achievementUnlocked(steamStatAchStringsAndMaxVals[statisticNum].first.c_str()) )
1290 				{
1291 					if ( iVal == 1 || iVal == 5 || (iVal > 0 && iVal % 10 == 0) || (iVal > 0 && iVal % 25 == 0) )
1292 					{
1293 						indicateAchievementProgressAndUnlock(steamStatAchStringsAndMaxVals[statisticNum].first.c_str(),
1294 							iVal, steamStatAchStringsAndMaxVals[statisticNum].second);
1295 					}
1296 				}
1297 				break;
1298 			// below are 10 max value
1299 			case STEAM_STAT_TAKE_THIS_OUTSIDE:
1300 			case STEAM_STAT_SPICY:
1301 				if ( !achievementUnlocked(steamStatAchStringsAndMaxVals[statisticNum].first.c_str()) )
1302 				{
1303 					if ( iVal == 1 || (iVal > 0 && iVal % 2 == 0) )
1304 					{
1305 						indicateAchievementProgressAndUnlock(steamStatAchStringsAndMaxVals[statisticNum].first.c_str(),
1306 							iVal, steamStatAchStringsAndMaxVals[statisticNum].second);
1307 					}
1308 				}
1309 				break;
1310 			case STEAM_STAT_DIPLOMA:
1311 			case STEAM_STAT_EXTRA_CREDIT:
1312 				if ( !achievementUnlocked(steamStatAchStringsAndMaxVals[statisticNum].first.c_str()) )
1313 				{
1314 					indicateAchievementProgressAndUnlock(steamStatAchStringsAndMaxVals[statisticNum].first.c_str(),
1315 						iVal, steamStatAchStringsAndMaxVals[statisticNum].second);
1316 				}
1317 				break;
1318 			default:
1319 				break;
1320 		}
1321 #ifdef DEBUG_ACHIEVEMENTS
1322 		messagePlayer(clientnum, "%s: %d, %d", steamStatAchStringsAndMaxVals[statisticNum].first.c_str(),
1323 			iVal, steamStatAchStringsAndMaxVals[statisticNum].second);
1324 #endif
1325 	}
1326 #endif // !STEAMWORKS
1327 }
1328 
1329 #ifdef STEAMWORKS
1330 //#define STEAMDEBUG
1331 
1332 /*-------------------------------------------------------------------------------
1333 
1334 	steam callback functions
1335 
1336 	handle various steam callbacks; bound in init_game.c
1337 
1338 -------------------------------------------------------------------------------*/
1339 
1340 //Helper func. //TODO: Bugger.
cpp_P2PSessionRequest_t_m_steamIDRemote(void * P2PSessionRequest_t_instance)1341 void* cpp_P2PSessionRequest_t_m_steamIDRemote(void* P2PSessionRequest_t_instance)
1342 {
1343 	CSteamID* id = new CSteamID; //TODO: Memleak?
1344 	*id = static_cast<P2PSessionRequest_t*>(P2PSessionRequest_t_instance)->m_steamIDRemote;
1345 	return id;
1346 }
1347 
steam_OnP2PSessionRequest(void * p_Callback)1348 void steam_OnP2PSessionRequest( void* p_Callback )
1349 {
1350 #ifdef STEAMDEBUG
1351 	printlog( "OnP2PSessionRequest\n" );
1352 #endif
1353 	printlog("[STEAM P2P]: Received P2P session request");
1354 	SteamNetworking()->AcceptP2PSessionWithUser(*static_cast<CSteamID* >(cpp_P2PSessionRequest_t_m_steamIDRemote(p_Callback)));
1355 }
1356 
1357 //Helper func. //TODO: Bugger.
cpp_Free_CSteamID(void * steamID)1358 void cpp_Free_CSteamID(void* steamID)
1359 {
1360 	CSteamID* id = static_cast<CSteamID*>(steamID);
1361 	delete id;
1362 }
1363 
1364 //Helper func. //TODO: Bugger.
cpp_SteamMatchmaking_GetLobbyByIndex(int iLobby)1365 void* cpp_SteamMatchmaking_GetLobbyByIndex(int iLobby)
1366 {
1367 	CSteamID* id = new CSteamID();
1368 	*id = SteamMatchmaking()->GetLobbyByIndex(iLobby);
1369 	return id;
1370 }
1371 
steam_OnLobbyMatchListCallback(void * pCallback,bool bIOFailure)1372 void steam_OnLobbyMatchListCallback( void* pCallback, bool bIOFailure )
1373 {
1374 	if ( !requestingLobbies )
1375 	{
1376 		return;
1377 	}
1378 
1379 	for ( Uint32 iLobby = 0; iLobby < MAX_STEAM_LOBBIES; iLobby++ )
1380 	{
1381 		if ( lobbyIDs[iLobby] )
1382 		{
1383 			cpp_Free_CSteamID(lobbyIDs[iLobby]); //TODO: This is an utter bodge. Make it not a list of void pointers and then just directly delete the ID.
1384 			lobbyIDs[iLobby] = NULL;
1385 		}
1386 	}
1387 	requestingLobbies = false;
1388 
1389 	if ( bIOFailure )
1390 	{
1391 		// we had a Steam I/O failure - we probably timed out talking to the Steam back-end servers
1392 		// doesn't matter in this case, we can just act if no lobbies were received
1393 	}
1394 
1395 	// lobbies are returned in order of closeness to the user, so add them to the list in that order
1396 	numSteamLobbies = std::min<uint32>(static_cast<LobbyMatchList_t*>(pCallback)->m_nLobbiesMatching, MAX_STEAM_LOBBIES);
1397 	for ( Uint32 iLobby = 0; iLobby < numSteamLobbies; iLobby++ )
1398 	{
1399 		void* steamIDLobby = cpp_SteamMatchmaking_GetLobbyByIndex( iLobby ); //TODO: Bugger this void pointer!
1400 
1401 		// add the lobby to the list
1402 		lobbyIDs[iLobby] = steamIDLobby;
1403 
1404 		// pull some info from the lobby metadata (name, players, etc)
1405 		const char* lobbyName = SteamMatchmaking()->GetLobbyData(*static_cast<CSteamID*>(steamIDLobby), "name"); //TODO: Again with the void pointers.
1406 		const char* lobbyVersion = SteamMatchmaking()->GetLobbyData(*static_cast<CSteamID*>(steamIDLobby), "ver"); //TODO: VOID.
1407 		int numPlayers = SteamMatchmaking()->GetNumLobbyMembers(*static_cast<CSteamID*>(steamIDLobby)); //TODO MORE VOID POINTERS.
1408 		const char* lobbyNumMods = SteamMatchmaking()->GetLobbyData(*static_cast<CSteamID*>(steamIDLobby), "svNumMods"); //TODO: VOID.
1409 		int numMods = atoi(lobbyNumMods);
1410 		string versionText = lobbyVersion;
1411 		if ( versionText ==  "" )
1412 		{
1413 			//If the lobby version is null
1414 			versionText = "Unknown version";
1415 		}
1416 
1417 		const Uint32 maxCharacters = 54;
1418 		if ( lobbyName && lobbyName[0] && numPlayers )
1419 		{
1420 			// set the lobby data
1421 			const Uint32 lobbyNameSize = strlen(lobbyName);
1422 			std::string lobbyDetailText = " ";
1423 			lobbyDetailText += "(";
1424 			lobbyDetailText += versionText;
1425 			lobbyDetailText += ") ";
1426 			if ( numMods > 0 )
1427 			{
1428 				lobbyDetailText += "[MODDED]";
1429 			}
1430 
1431 			std::string displayedLobbyName = lobbyName;
1432 			if ( displayedLobbyName.size() > (maxCharacters - lobbyDetailText.size()) )
1433 			{
1434 				// no room, need to truncate lobbyName
1435 				displayedLobbyName = displayedLobbyName.substr(0, (maxCharacters - lobbyDetailText.size()) - 2);
1436 				displayedLobbyName += "..";
1437 			}
1438 			snprintf( lobbyText[iLobby], maxCharacters - 1, "%s%s", displayedLobbyName.c_str(), lobbyDetailText.c_str()); //TODO: Perhaps a better method would be to print the name and the version as two separate strings ( because some steam names are ridiculously long).
1439 			lobbyPlayers[iLobby] = numPlayers;
1440 		}
1441 		else
1442 		{
1443 			// we don't have info about the lobby yet, request it
1444 			SteamMatchmaking()->RequestLobbyData(*static_cast<CSteamID*>(steamIDLobby));
1445 
1446 			// results will be returned via LobbyDataUpdate_t callback
1447 			snprintf( lobbyText[iLobby], maxCharacters - 1, "Lobby %d", static_cast<CSteamID*>(steamIDLobby)->GetAccountID() ); //TODO: MORE VOID POINTER BUGGERY.
1448 			lobbyPlayers[iLobby] = 0;
1449 		}
1450 	}
1451 }
1452 
1453 //Helper func. //TODO: Bugger it!
cpp_LobbyDataUpdated_pCallback_m_ulSteamIDLobby(void * pCallback)1454 void* cpp_LobbyDataUpdated_pCallback_m_ulSteamIDLobby(void* pCallback)
1455 {
1456 	CSteamID* id = new CSteamID();
1457 	*id = static_cast<LobbyDataUpdate_t*>(pCallback)->m_ulSteamIDLobby;
1458 	return id;
1459 }
1460 
steam_OnLobbyDataUpdatedCallback(void * pCallback)1461 void steam_OnLobbyDataUpdatedCallback( void* pCallback )
1462 {
1463 #ifdef STEAMDEBUG
1464 	printlog( "OnLobbyDataUpdatedCallback\n" );
1465 #endif
1466 	if ( LobbyHandler.steamLobbyToValidate.GetAccountID() != 0 )
1467 	{
1468 		LobbyDataUpdate_t* cb = static_cast<LobbyDataUpdate_t*>(pCallback);
1469 		if ( cb )
1470 		{
1471 			if ( !cb->m_bSuccess )
1472 			{
1473 				printlog("[STEAM Lobbies]: Lobby to join no longer exists");
1474 				connectingToLobbyStatus = LobbyHandler_t::EResult_LobbyFailures::LOBBY_NOT_FOUND;
1475 				connectingToLobbyWindow = false;
1476 				connectingToLobby = false;
1477 			}
1478 			else if ( cb->m_ulSteamIDLobby == LobbyHandler.steamLobbyToValidate.ConvertToUint64() )
1479 			{
1480 				printlog("[STEAM Lobbies]: Received update for join lobby request");
1481 				if ( LobbyHandler.validateSteamLobbyDataOnJoin() )
1482 				{
1483 					printlog("[STEAM Lobbies]: Join lobby request initiated");
1484 					cpp_SteamMatchmaking_JoinLobby(LobbyHandler.steamLobbyToValidate);
1485 				}
1486 				else
1487 				{
1488 					printlog("[STEAM Lobbies]: Incompatible lobby to join");
1489 				}
1490 			}
1491 			LobbyHandler.steamLobbyToValidate.SetAccountID(0);
1492 			return;
1493 		}
1494 	}
1495 
1496 	// finish processing lobby invite?
1497 	if ( stillConnectingToLobby )
1498 	{
1499 		stillConnectingToLobby = false;
1500 
1501 		void processLobbyInvite();
1502 		processLobbyInvite();
1503 		return;
1504 	}
1505 
1506 	// update current lobby info
1507 	void* tempSteamID = cpp_LobbyDataUpdated_pCallback_m_ulSteamIDLobby(pCallback); //TODO: BUGGER VOID POINTER.
1508 	if ( currentLobby )
1509 	{
1510 		if ( (static_cast<CSteamID*>(currentLobby))->ConvertToUint64() == (static_cast<CSteamID*>(tempSteamID))->ConvertToUint64() )
1511 		{
1512 			// extract the display name from the lobby metadata
1513 			const char* lobbyName = SteamMatchmaking()->GetLobbyData( *static_cast<CSteamID*>(currentLobby), "name" );
1514 			if ( lobbyName )
1515 			{
1516 				snprintf( currentLobbyName, 31, lobbyName );
1517 			}
1518 
1519 			// get the server flags
1520 			const char* svFlagsChar = SteamMatchmaking()->GetLobbyData( *static_cast<CSteamID*>(currentLobby), "svFlags" );
1521 			if ( svFlagsChar )
1522 			{
1523 				svFlags = atoi(svFlagsChar);
1524 			}
1525 		}
1526 	}
1527 	cpp_Free_CSteamID(tempSteamID);
1528 }
1529 
1530 //Helper func. //TODO: BUGGER THIS.
cpp_LobbyCreated_Lobby(void * pCallback)1531 void* cpp_LobbyCreated_Lobby(void* pCallback)
1532 {
1533 	CSteamID* id = new CSteamID;
1534 	*id = static_cast<LobbyCreated_t*>(pCallback)->m_ulSteamIDLobby;
1535 	return id;
1536 }
1537 
steam_OnLobbyCreated(void * pCallback,bool bIOFailure)1538 void steam_OnLobbyCreated( void* pCallback, bool bIOFailure )
1539 {
1540 #ifdef STEAMDEBUG
1541 	printlog( "OnLobbyCreated\n" );
1542 #endif
1543 	if ( static_cast<EResult>(static_cast<LobbyCreated_t*>(pCallback)->m_eResult) == k_EResultOK )   //TODO: Make sure port from c_EResult to EResult works flawlessly.
1544 	{
1545 		if ( currentLobby )
1546 		{
1547 			SteamMatchmaking()->LeaveLobby(*static_cast<CSteamID*>(currentLobby));
1548 			cpp_Free_CSteamID(currentLobby); //TODO: BUGGER THIS.
1549 			currentLobby = nullptr;
1550 		}
1551 		currentLobby = cpp_LobbyCreated_Lobby(pCallback);
1552 
1553 		// set the name of the lobby
1554 		snprintf( currentLobbyName, 31, "%s's lobby", SteamFriends()->GetPersonaName() );
1555 		SteamMatchmaking()->SetLobbyData(*static_cast<CSteamID*>(currentLobby), "name", currentLobbyName); //TODO: Bugger void pointer!
1556 
1557 		// set the game version of the lobby
1558 		SteamMatchmaking()->SetLobbyData(*static_cast<CSteamID*>(currentLobby), "ver", VERSION); //TODO: Bugger void pointer!
1559 
1560 		// set lobby server flags
1561 		char svFlagsChar[16];
1562 		snprintf(svFlagsChar, 15, "%d", svFlags);
1563 		SteamMatchmaking()->SetLobbyData(*static_cast<CSteamID*>(currentLobby), "svFlags", svFlagsChar); //TODO: Bugger void pointer!
1564 
1565 		// set load game status on lobby
1566 		char loadingsavegameChar[16];
1567 		snprintf(loadingsavegameChar, 15, "%d", loadingsavegame);
1568 		SteamMatchmaking()->SetLobbyData(*static_cast<CSteamID*>(currentLobby), "loadingsavegame", loadingsavegameChar); //TODO: Bugger void pointer!
1569 
1570 		char svNumMods[16];
1571 		snprintf(svNumMods, 15, "%d", gamemods_numCurrentModsLoaded);
1572 		SteamMatchmaking()->SetLobbyData(*static_cast<CSteamID*>(currentLobby), "svNumMods", svNumMods); //TODO: Bugger void pointer!
1573 
1574 		char modifiedTime[32];
1575 		snprintf(modifiedTime, 31, "%d", SteamUtils()->GetServerRealTime());
1576 		SteamMatchmaking()->SetLobbyData(*static_cast<CSteamID*>(currentLobby), "lobbyModifiedTime", modifiedTime); //TODO: Bugger void pointer!
1577 		SteamMatchmaking()->SetLobbyData(*static_cast<CSteamID*>(currentLobby), "lobbyCreationTime", modifiedTime); //TODO: Bugger void pointer!
1578 
1579 		if ( gamemods_numCurrentModsLoaded > 0 )
1580 		{
1581 			int count = 0;
1582 			for ( std::vector<std::pair<std::string, std::string>>::iterator it = gamemods_mountedFilepaths.begin(); it != gamemods_mountedFilepaths.end(); ++it )
1583 			{
1584 				for ( std::vector<std::pair<std::string, uint64>>::iterator itMap = gamemods_workshopLoadedFileIDMap.begin();
1585 					itMap != gamemods_workshopLoadedFileIDMap.end(); ++itMap )
1586 				{
1587 					if ( (itMap->first).compare(it->second) == 0 )
1588 					{
1589 						char svModFileID[64];
1590 						snprintf(svModFileID, 64, "%d", static_cast<int>(itMap->second));
1591 						char tagName[32] = "";
1592 						snprintf(tagName, 32, "svMod%d", count);
1593 						SteamMatchmaking()->SetLobbyData(*static_cast<CSteamID*>(currentLobby), tagName, svModFileID); //TODO: Bugger void pointer!
1594 						++count;
1595 						break;
1596 					}
1597 				}
1598 			}
1599 		}
1600 	}
1601 	else
1602 	{
1603 		printlog( "warning: failed to create steam lobby.\n");
1604 	}
1605 }
1606 
1607 #ifdef USE_EOS
steam_OnRequestEncryptedAppTicket(void * pCallback,bool bIOFailure)1608 void steam_OnRequestEncryptedAppTicket(void* pCallback, bool bIOFailure)
1609 {
1610 	if ( bIOFailure )
1611 	{
1612 		printlog("OnRequestEncryptedAppTicket failure");
1613 		return;
1614 	}
1615 
1616 	EncryptedAppTicketResponse_t* cb = static_cast<EncryptedAppTicketResponse_t*>(pCallback);
1617 	switch ( cb->m_eResult )
1618 	{
1619 		case k_EResultOK:
1620 		{
1621 			uint8 rgubTicket[1024];
1622 			uint32 cubTicket;
1623 			if ( SteamUser()->GetEncryptedAppTicket(rgubTicket, sizeof(rgubTicket), &cubTicket) )
1624 			{
1625 				char buf[1024] = "";
1626 				Uint32 len = 1024;
1627 				EOS_EResult result = EOS_ByteArray_ToString(rgubTicket, cubTicket, buf, &len);
1628 				if ( result != EOS_EResult::EOS_Success )
1629 				{
1630 					printlog("EOS_ByteArray_ToString failed, error code: %d", static_cast<int>(result));
1631 				}
1632 				EOS.ConnectHandle = EOS_Platform_GetConnectInterface(EOS.PlatformHandle);
1633 				EOS_Connect_Credentials Credentials;
1634 				Credentials.ApiVersion = EOS_CONNECT_CREDENTIALS_API_LATEST;
1635 				Credentials.Token = buf;
1636 				Credentials.Type = EOS_EExternalCredentialType::EOS_ECT_STEAM_APP_TICKET; // change this to steam etc for different account providers.
1637 
1638 				EOS_Connect_LoginOptions Options;
1639 				Options.ApiVersion = EOS_CONNECT_LOGIN_API_LATEST;
1640 				Options.Credentials = &Credentials;
1641 				Options.UserLoginInfo = nullptr;
1642 
1643 				EOS_Connect_Login(EOS.ConnectHandle, &Options, nullptr, EOS.ConnectLoginCrossplayCompleteCallback);
1644 				EOS.CrossplayAccountManager.awaitingConnectCallback = true;
1645 				EOS.CrossplayAccountManager.awaitingAppTicketResponse = false;
1646 				printlog("[STEAM]: AppTicket request success");
1647 			}
1648 			else
1649 			{
1650 				printlog("GetEncryptedAppTicket failed");
1651 			}
1652 		}
1653 		break;
1654 		case k_EResultNoConnection:
1655 			printlog("OnRequestEncryptedAppTicket no steam connection");
1656 			break;
1657 		case k_EResultDuplicateRequest:
1658 			printlog("OnRequestEncryptedAppTicket duplicate request outstanding");
1659 			break;
1660 		case k_EResultLimitExceeded:
1661 			printlog("OnRequestEncryptedAppTicket called more than once per minute");
1662 			break;
1663 		default:
1664 			break;
1665 	}
1666 }
1667 #endif //USE_EOS
1668 
processLobbyInvite()1669 void processLobbyInvite()
1670 {
1671 	if ( !intro )
1672 	{
1673 		stillConnectingToLobby = true;
1674 		return;
1675 	}
1676 	if ( !lobbyToConnectTo )
1677 	{
1678 		printlog( "warning: tried to process invitation to null lobby" );
1679 		stillConnectingToLobby = false;
1680 		return;
1681 	}
1682 	const char* loadingSaveGameChar = SteamMatchmaking()->GetLobbyData( *static_cast<CSteamID*>(lobbyToConnectTo), "loadingsavegame" );
1683 
1684 	if ( loadingSaveGameChar && loadingSaveGameChar[0] )
1685 	{
1686 		Uint32 temp32 = atoi(loadingSaveGameChar);
1687 		Uint32 gameKey = getSaveGameUniqueGameKey(false);
1688 		if ( temp32 && temp32 == gameKey )
1689 		{
1690 			loadingsavegame = temp32;
1691 			buttonLoadMultiplayerGame(NULL);
1692 		}
1693 		else if ( !temp32 )
1694 		{
1695 			loadingsavegame = 0;
1696 			buttonOpenCharacterCreationWindow(NULL);
1697 		}
1698 		else
1699 		{
1700 			// try reload from your other savefiles since this didn't match the default savegameIndex.
1701 			if ( savegamesList.empty() )
1702 			{
1703 				reloadSavegamesList(false);
1704 			}
1705 			bool foundSave = false;
1706 			for ( auto it = savegamesList.begin(); it != savegamesList.end(); ++it )
1707 			{
1708 				auto entry = *it;
1709 				savegameCurrentFileIndex = std::get<2>(entry);
1710 				gameKey = getSaveGameUniqueGameKey(false, savegameCurrentFileIndex);
1711 				if ( std::get<1>(entry) != SINGLE && temp32 == gameKey )
1712 				{
1713 					foundSave = true;
1714 					break;
1715 				}
1716 			}
1717 
1718 			if ( !foundSave )
1719 			{
1720 				savegameCurrentFileIndex = 0;
1721 				printlog("warning: received invitation to lobby with which you have an incompatible save game.\n");
1722 				if ( lobbyToConnectTo )
1723 				{
1724 					cpp_Free_CSteamID(lobbyToConnectTo);    //TODO: Bodge this bodge!
1725 				}
1726 				lobbyToConnectTo = NULL;
1727 			}
1728 			else
1729 			{
1730 				loadingsavegame = temp32;
1731 				buttonLoadMultiplayerGame(NULL);
1732 			}
1733 		}
1734 		stillConnectingToLobby = false;
1735 	}
1736 	else
1737 	{
1738 		stillConnectingToLobby = true;
1739 		SteamMatchmaking()->RequestLobbyData(*static_cast<CSteamID*>(lobbyToConnectTo));
1740 		printlog("warning: failed to determine whether lobby is using a saved game or not...\n");
1741 	}
1742 }
1743 
1744 //Helper func. //TODO: Bugger.
cpp_GameJoinRequested_m_steamIDLobby(void * pCallback)1745 void* cpp_GameJoinRequested_m_steamIDLobby(void* pCallback)
1746 {
1747 	CSteamID* id = new CSteamID;
1748 	*id = static_cast<GameLobbyJoinRequested_t*>(pCallback)->m_steamIDLobby;
1749 	return id;
1750 }
1751 
steam_OnGameJoinRequested(void * pCallback)1752 void steam_OnGameJoinRequested( void* pCallback )
1753 {
1754 #ifdef STEAMDEBUG
1755 	printlog( "OnGameJoinRequested\n" );
1756 #endif
1757 
1758 	// return to a state where we can join the lobby
1759 	if ( !intro )
1760 	{
1761 		buttonEndGameConfirm(NULL);
1762 	}
1763 	else if ( multiplayer != SINGLE )
1764 	{
1765 		buttonDisconnect(NULL);
1766 	}
1767 
1768 	// close current window
1769 	if ( subwindow )
1770 	{
1771 		if ( score_window )
1772 		{
1773 			// reset class loadout
1774 			stats[0]->sex = static_cast<sex_t>(0);
1775 			stats[0]->appearance = 0;
1776 			stats[0]->playerRace = RACE_HUMAN;
1777 			strcpy(stats[0]->name, "");
1778 			stats[0]->type = HUMAN;
1779 			client_classes[0] = 0;
1780 			stats[0]->clearStats();
1781 			initClass(0);
1782 		}
1783 		score_window = 0;
1784 		gamemods_window = 0;
1785 		lobby_window = false;
1786 		settings_window = false;
1787 		charcreation_step = 0;
1788 		subwindow = 0;
1789 		if ( SDL_IsTextInputActive() )
1790 		{
1791 			SDL_StopTextInput();
1792 		}
1793 	}
1794 	list_FreeAll(&button_l);
1795 	deleteallbuttons = true;
1796 
1797 	if ( lobbyToConnectTo )
1798 	{
1799 		cpp_Free_CSteamID(lobbyToConnectTo); //TODO: Utter bodge.
1800 	}
1801 	lobbyToConnectTo = cpp_GameJoinRequested_m_steamIDLobby(pCallback);
1802 	processLobbyInvite();
1803 }
1804 
1805 //Helper func. //TODO: Bugger.
cpp_SteamMatchmaking_JoinLobbyPCH(const char * pchLobbyID)1806 void cpp_SteamMatchmaking_JoinLobbyPCH(const char* pchLobbyID)
1807 {
1808 	CSteamID steamIDLobby( (uint64)atoll( pchLobbyID ) );
1809 	if ( steamIDLobby.IsValid() )
1810 	{
1811 		SteamAPICall_t steamAPICall = SteamMatchmaking()->JoinLobby(steamIDLobby);
1812 		steam_server_client_wrapper->m_SteamCallResultLobbyEntered_Set(steamAPICall);
1813 	}
1814 }
1815 
1816 // searches (char pchCmdLine[]) for a connect lobby command
steam_ConnectToLobby()1817 void steam_ConnectToLobby()
1818 {
1819 #ifdef STEAMDEBUG
1820 	printlog( "ConnectToLobby\n" );
1821 #endif
1822 
1823 	// parse out the connect
1824 	char pchLobbyID[1024];
1825 
1826 	// look for +connect_lobby command
1827 	const char* pchConnectLobbyParam = "+connect_lobby";
1828 	const char* pchConnectLobby = strstr( pchCmdLine, pchConnectLobbyParam );
1829 	if ( pchConnectLobby )
1830 	{
1831 		// address should be right after the +connect_lobby, +1 on the end to skip the space
1832 		strcpy( pchLobbyID, (char*)(pchConnectLobby + strlen(pchConnectLobbyParam) + 1 ));
1833 	}
1834 
1835 	// join lobby
1836 	if (  pchLobbyID )
1837 	{
1838 		//c_SteamMatchmaking_JoinLobbyPCH( pchLobbyID, &steam_OnLobbyEntered );
1839 		cpp_SteamMatchmaking_JoinLobbyPCH( pchLobbyID);
1840 	}
1841 }
1842 
cpp_pCallback_m_ulSteamIDLobby(void * pCallback)1843 void* cpp_pCallback_m_ulSteamIDLobby( void* pCallback )
1844 {
1845 	CSteamID* id = new CSteamID();
1846 	*id = static_cast<LobbyEnter_t*>(pCallback)->m_ulSteamIDLobby;
1847 	return id;
1848 }
1849 
steam_OnLobbyEntered(void * pCallback,bool bIOFailure)1850 void steam_OnLobbyEntered( void* pCallback, bool bIOFailure )
1851 {
1852 #ifdef STEAMDEBUG
1853 	printlog( "OnLobbyEntered\n" );
1854 #endif
1855 	if ( denyLobbyJoinEvent || !connectingToLobby )
1856 	{
1857 		if ( denyLobbyJoinEvent )
1858 		{
1859 			printlog("[STEAM Lobbies]: Forcibly denying joining current lobby");
1860 		}
1861 		else if ( !connectingToLobby )
1862 		{
1863 			printlog("[STEAM Lobbies]: On lobby entered, unexpected closed window. Leaving lobby");
1864 		}
1865 		denyLobbyJoinEvent = false;
1866 		if ( pCallback )
1867 		{
1868 			if ( static_cast<LobbyEnter_t*>(pCallback)->m_EChatRoomEnterResponse == k_EChatRoomEnterResponseSuccess )
1869 			{
1870 				SteamMatchmaking()->LeaveLobby(static_cast<LobbyEnter_t*>(pCallback)->m_ulSteamIDLobby);
1871 			}
1872 		}
1873 		if ( currentLobby )
1874 		{
1875 			SteamMatchmaking()->LeaveLobby(*static_cast<CSteamID*>(currentLobby));
1876 			cpp_Free_CSteamID(currentLobby); //TODO: Bugger.
1877 			currentLobby = nullptr;
1878 		}
1879 		connectingToLobby = false;
1880 		connectingToLobbyWindow = false;
1881 		return;
1882 	}
1883 
1884 	denyLobbyJoinEvent = false;
1885 
1886 	if ( static_cast<LobbyEnter_t*>(pCallback)->m_EChatRoomEnterResponse != k_EChatRoomEnterResponseSuccess )
1887 	{
1888 		// lobby join failed
1889 		connectingToLobby = false;
1890 		connectingToLobbyWindow = false;
1891 		openFailedConnectionWindow(CLIENT);
1892 		return;
1893 	}
1894 
1895 	// success
1896 
1897 	// move forward the state
1898 	if ( currentLobby )
1899 	{
1900 		SteamMatchmaking()->LeaveLobby(*static_cast<CSteamID*>(currentLobby));
1901 		cpp_Free_CSteamID(currentLobby); //TODO: Bugger.
1902 		currentLobby = nullptr;
1903 	}
1904 	currentLobby = cpp_pCallback_m_ulSteamIDLobby(pCallback); //TODO: More buggery.
1905 	connectingToLobby = false;
1906 }
1907 
steam_GameServerPingOnServerResponded(void * steamID)1908 void steam_GameServerPingOnServerResponded(void* steamID)
1909 {
1910 #ifdef STEAMDEBUG
1911 	printlog( "GameServerPingOnServerResponded\n" );
1912 #endif
1913 
1914 	steamIDGameServer = steamID;
1915 }
1916 
steam_OnP2PSessionConnectFail(void * pCallback)1917 void steam_OnP2PSessionConnectFail( void* pCallback )
1918 {
1919 #ifdef STEAMDEBUG
1920 	printlog( "OnP2PSessionConnectFail\n" );
1921 #endif
1922 
1923 	printlog("[STEAM P2P]: Warning: failed to establish steam P2P connection.\n");
1924 
1925 	/*if ( intro )
1926 	{
1927 		connectingToLobby = false;
1928 		connectingToLobbyWindow = false;
1929 		buttonDisconnect(nullptr);
1930 		openFailedConnectionWindow(SINGLE);
1931 	}*/
1932 }
1933 
FindLeaderboard(const char * pchLeaderboardName)1934 void CSteamLeaderboards::FindLeaderboard(const char *pchLeaderboardName)
1935 {
1936 	if ( !SteamUser()->BLoggedOn() )
1937 	{
1938 		return;
1939 	}
1940 	m_CurrentLeaderboard = NULL;
1941 	b_LeaderboardInit = false;
1942 	SteamAPICall_t hSteamAPICall = SteamUserStats()->FindLeaderboard(pchLeaderboardName);
1943 	m_callResultFindLeaderboard.Set(hSteamAPICall, this,
1944 		&CSteamLeaderboards::OnFindLeaderboard);
1945 	// call OnFindLeaderboard when result of async API call
1946 }
1947 
OnFindLeaderboard(LeaderboardFindResult_t * pCallback,bool bIOFailure)1948 void CSteamLeaderboards::OnFindLeaderboard(LeaderboardFindResult_t *pCallback, bool bIOFailure)
1949 {
1950 	// see if we encountered an error during the call
1951 	if ( !pCallback->m_bLeaderboardFound || bIOFailure )
1952 	{
1953 		printlog("[STEAM]: Error, could not find leaderboard %s!", leaderboardNames[LeaderboardUpload.boardIndex].c_str());
1954 		ClearUploadData();
1955 		return;
1956 	}
1957 	b_LeaderboardInit = true;
1958 	m_CurrentLeaderboard = pCallback->m_hSteamLeaderboard;
1959 	//DownloadScores(k_ELeaderboardDataRequestGlobal, 0, k_numEntriesToRetrieve);
1960 }
1961 
DownloadScores(ELeaderboardDataRequest dataRequestType,int rangeStart,int rangeEnd)1962 bool CSteamLeaderboards::DownloadScores(ELeaderboardDataRequest dataRequestType, int rangeStart, int rangeEnd)
1963 {
1964 	if ( !m_CurrentLeaderboard )
1965 	{
1966 		return false;
1967 	}
1968 	b_ScoresDownloaded = false;
1969 
1970 	// load the specified leaderboard data around the current user
1971 	SteamAPICall_t hSteamAPICall = SteamUserStats()->DownloadLeaderboardEntries(
1972 		m_CurrentLeaderboard, dataRequestType, rangeStart, rangeEnd);
1973 	m_callResultDownloadScore.Set(hSteamAPICall, this,
1974 		&CSteamLeaderboards::OnDownloadScore);
1975 
1976 	return true;
1977 }
1978 
OnDownloadScore(LeaderboardScoresDownloaded_t * pCallback,bool bIOFailure)1979 void CSteamLeaderboards::OnDownloadScore(LeaderboardScoresDownloaded_t *pCallback, bool bIOFailure)
1980 {
1981 	if ( !bIOFailure )
1982 	{
1983 		m_nLeaderboardEntries = std::min(pCallback->m_cEntryCount, (int)CSteamLeaderboards::k_numEntriesToRetrieve);
1984 		for ( int i = 0; i < m_nLeaderboardEntries; ++i )
1985 		{
1986 			SteamUserStats()->GetDownloadedLeaderboardEntry(pCallback->m_hSteamLeaderboardEntries,
1987 				i, &m_leaderboardEntries[i], downloadedTags[i], k_numLeaderboardTags);
1988 			leaderBoardSteamUsernames[i] = SteamFriends()->GetFriendPersonaName(m_leaderboardEntries[i].m_steamIDUser);
1989 		}
1990 		b_ScoresDownloaded = true;
1991 	}
1992 }
1993 
UploadScore(int scoreToSet,int tags[k_numLeaderboardTags])1994 void CSteamLeaderboards::UploadScore(int scoreToSet, int tags[k_numLeaderboardTags])
1995 {
1996 	if ( !m_CurrentLeaderboard )
1997 	{
1998 		return;
1999 	}
2000 
2001 	// load the specified leaderboard data around the current user
2002 	SteamAPICall_t hSteamAPICall = SteamUserStats()->UploadLeaderboardScore(m_CurrentLeaderboard,
2003 		k_ELeaderboardUploadScoreMethodKeepBest, scoreToSet, tags,
2004 		k_numLeaderboardTags);
2005 	m_callResultUploadScore.Set(hSteamAPICall, this,
2006 		&CSteamLeaderboards::OnUploadScore);
2007 }
2008 
OnUploadScore(LeaderboardScoreUploaded_t * pCallback,bool bIOFailure)2009 void CSteamLeaderboards::OnUploadScore(LeaderboardScoreUploaded_t *pCallback, bool bIOFailure)
2010 {
2011 	if ( !bIOFailure && pCallback->m_bSuccess )
2012 	{
2013 		m_CurrentLeaderboard = pCallback->m_hSteamLeaderboard;
2014 		LastUploadResult.b_ScoreUploadComplete = (pCallback->m_bSuccess == 1);
2015 		LastUploadResult.b_ScoreChanged = (pCallback->m_bScoreChanged != 0);
2016 		LastUploadResult.globalRankNew = pCallback->m_nGlobalRankNew;
2017 		LastUploadResult.globalRankPrev = pCallback->m_nGlobalRankPrevious;
2018 		LastUploadResult.scoreUploaded = pCallback->m_nScore;
2019 	}
2020 	else
2021 	{
2022 		LastUploadResult.b_ScoreUploadComplete = false;
2023 		LastUploadResult.b_ScoreChanged = false;
2024 		LastUploadResult.globalRankNew = 0;
2025 		LastUploadResult.globalRankPrev = 0;
2026 		LastUploadResult.scoreUploaded = 0;
2027 	}
2028 }
2029 
ClearUploadData()2030 void CSteamLeaderboards::ClearUploadData()
2031 {
2032 	for ( int c = 0; c < k_numLeaderboardTags; ++c )
2033 	{
2034 		LeaderboardUpload.tags[c] = 0;
2035 	}
2036 	LeaderboardUpload.score = 0;
2037 	LeaderboardUpload.time = 0;
2038 	LeaderboardUpload.status = LEADERBOARD_STATE_NONE;
2039 	LeaderboardUpload.boardIndex = LEADERBOARD_NONE;
2040 	LeaderboardUpload.uploadInit = false;
2041 
2042 	LastUploadResult.b_ScoreChanged = false;
2043 	LastUploadResult.b_ScoreUploadComplete = false;
2044 	LastUploadResult.globalRankNew = 0;
2045 	LastUploadResult.globalRankPrev;
2046 	LastUploadResult.scoreUploaded = 0;
2047 }
2048 
ProcessLeaderboardUpload()2049 void CSteamLeaderboards::ProcessLeaderboardUpload()
2050 {
2051 	if ( LeaderboardUpload.status == LEADERBOARD_STATE_NONE )
2052 	{
2053 		return;
2054 	}
2055 
2056 	if ( ticks % 25 == 0 )
2057 	{
2058 		if ( LeaderboardUpload.status == LEADERBOARD_STATE_FIND_LEADERBOARD_TIME )
2059 		{
2060 			FindLeaderboard(leaderboardNames[LeaderboardUpload.boardIndex].c_str());
2061 			LeaderboardUpload.status = LEADERBOARD_STATE_UPLOADING_TIME;
2062 			LastUploadResult.b_ScoreUploadComplete = false;
2063 			LastUploadResult.b_ScoreChanged = false;
2064 		}
2065 		else if ( LeaderboardUpload.status == LEADERBOARD_STATE_UPLOADING_TIME )
2066 		{
2067 			if ( b_LeaderboardInit )
2068 			{
2069 				if ( !LeaderboardUpload.uploadInit )
2070 				{
2071 					UploadScore(LeaderboardUpload.time, LeaderboardUpload.tags);
2072 					LeaderboardUpload.uploadInit = true;
2073 				}
2074 				if ( LastUploadResult.b_ScoreUploadComplete == true )
2075 				{
2076 					LeaderboardUpload.uploadInit = false;
2077 					LeaderboardUpload.status = LEADERBOARD_STATE_READY_TIME;
2078 					printlog("[STEAM]: Successfully uploaded leaderboard time to board name %s.", leaderboardNames[LeaderboardUpload.boardIndex].c_str());
2079 					if ( LastUploadResult.b_ScoreChanged )
2080 					{
2081 						printlog("[STEAM]: Registered a new fastest time on the leaderboard!");
2082 					}
2083 					else
2084 					{
2085 						printlog("[STEAM]: You did not beat your previous leaderboard time.");
2086 					}
2087 					LastUploadResult.b_ScoreUploadComplete = false;
2088 				}
2089 			}
2090 		}
2091 		else if ( LeaderboardUpload.status == LEADERBOARD_STATE_READY_TIME )
2092 		{
2093 			FindLeaderboard(leaderboardNames[LeaderboardUpload.boardIndex + 1].c_str());
2094 			LeaderboardUpload.status = LEADERBOARD_STATE_UPLOADING_SCORE;
2095 			LastUploadResult.b_ScoreUploadComplete = false;
2096 			LastUploadResult.b_ScoreChanged = false;
2097 		}
2098 		else if ( LeaderboardUpload.status == LEADERBOARD_STATE_UPLOADING_SCORE )
2099 		{
2100 			if ( b_LeaderboardInit )
2101 			{
2102 				if ( !LeaderboardUpload.uploadInit )
2103 				{
2104 					UploadScore(LeaderboardUpload.score, LeaderboardUpload.tags);
2105 					LeaderboardUpload.uploadInit = true;
2106 				}
2107 				if ( LastUploadResult.b_ScoreUploadComplete == true )
2108 				{
2109 					LeaderboardUpload.uploadInit = false;
2110 					LeaderboardUpload.status = LEADERBOARD_STATE_NONE;
2111 					printlog("[STEAM]: Successfully uploaded leaderboard score to board name %s.", leaderboardNames[LeaderboardUpload.boardIndex + 1].c_str());
2112 					LastUploadResult.b_ScoreUploadComplete = false;
2113 					if ( LastUploadResult.b_ScoreChanged )
2114 					{
2115 						printlog("[STEAM]: Registered a new highest score on the leaderboard!");
2116 					}
2117 					else
2118 					{
2119 						printlog("[STEAM]: You did not beat your previous leaderboard score.");
2120 					}
2121 					ClearUploadData();
2122 					DownloadScores(k_ELeaderboardDataRequestGlobal, 0, k_numEntriesToRetrieve);
2123 				}
2124 			}
2125 		}
2126 	}
2127 }
2128 #endif