1 #pragma once
2 
3 #include "Config.hpp"
4 
5 #ifdef USE_EOS
6 #include "eos_sdk.h"
7 #include "eos_logging.h"
8 #include "eos_auth.h"
9 #include "eos_friends.h"
10 #include "eos_userinfo.h"
11 #include "eos_lobby.h"
12 #include "eos_p2p.h"
13 #include "eos_ui.h"
14 #include "eos_ecom.h"
15 #include "eos_achievements.h"
16 #include "eos_stats.h"
17 #include "eos_metrics.h"
18 #include <vector>
19 #include <iostream>
20 #include <map>
21 #include <atomic>
22 #include "net.hpp"
23 #include "stat.hpp"
24 #include "physfs.h"
25 
26 class EOSFuncs
27 {
28 	std::unordered_map<std::string, SteamStat_t*> statMappings;
29 public:
30 	std::string ProductId = "";
31 	std::string SandboxId = "";
32 	std::string DeploymentId = "";
33 	std::string ClientCredentialsId = "";
34 	std::string ClientCredentialsSecret = "";
35 	std::string CredentialName = "";
36 	std::string CredentialHost = "";
37 	std::vector<std::string> CommandLineArgs;
38 	class Accounts_t
39 	{
40 	public:
41 		EOS_ELoginCredentialType AuthType = EOS_ELoginCredentialType::EOS_LCT_Developer;
42 		EOS_EResult AccountAuthenticationStatus = EOS_EResult::EOS_NotConfigured;
43 		EOS_EResult AccountAuthenticationCompleted = EOS_EResult::EOS_NotConfigured;
44 
45 		bool waitingForCallback = false;
46 		bool firstTimeSetupCompleted = false;
47 		bool initPopupWindow = false;
48 		Uint32 popupInitTicks = 0;
49 		Uint32 popupCurrentTicks = 0;
50 		Uint32 loadingTicks = 0;
51 		bool loginCriticalErrorOccurred = false;
52 		enum PopupType
53 		{
54 			POPUP_FULL,
55 			POPUP_TOAST
56 		};
57 		PopupType popupType = POPUP_TOAST;
58 
59 		SDL_Surface* loginBanner = nullptr;
60 
61 		void createLoginDialogue();
62 		void drawDialogue();
63 		void handleLogin();
64 
deinit()65 		void deinit()
66 		{
67 			if ( loginBanner )
68 			{
69 				SDL_FreeSurface(loginBanner);
70 			}
71 		}
72 	} AccountManager;
73 
74 
75 	class CrossplayAccounts_t
76 	{
77 		enum PromptTypes : int
78 		{
79 			PROMPT_CLOSED,
80 			PROMPT_SETUP,
81 			PROMPT_ABOUT
82 		};
83 	public:
84 		EOS_ContinuanceToken continuanceToken = nullptr;
85 		EOS_EResult connectLoginStatus = EOS_EResult::EOS_NotConfigured;
86 		EOS_EResult connectLoginCompleted = EOS_EResult::EOS_NotConfigured;
87 
88 		bool awaitingConnectCallback = false;
89 		bool awaitingCreateUserCallback = false;
90 		bool awaitingAppTicketResponse = false;
91 
92 		bool acceptedEula = false;
93 		bool trySetupFromSettingsMenu = false;
94 		bool logOut = false;
95 		bool autologin = false;
96 		PromptTypes promptStatus = PROMPT_CLOSED;
getPromptStatus()97 		PromptTypes getPromptStatus() { return promptStatus; };
openPromptSetup()98 		void openPromptSetup() { promptStatus = PROMPT_SETUP;  }
openPromptAbout()99 		void openPromptAbout() { promptStatus = PROMPT_ABOUT; }
closePrompt()100 		void closePrompt() { promptStatus = PROMPT_CLOSED; }
101 
102 		void handleLogin();
103 		void createDialogue();
104 		void drawDialogue();
105 		void createNotification();
106 
107 		void resetOnFailure();
108 		static void retryCrossplaySetupOnFailure();
109 	} CrossplayAccountManager;
110 
111 	const int kMaxLobbiesToSearch = 100;
112 
113 	// global shenanigans
114 	bool bRequestingLobbies = false; // client is waiting for lobby data to display
115 	bool bConnectingToLobby = false; // if true, client is waiting for lobby join callback
116 	bool bConnectingToLobbyWindow = false; // client has a valid lobby window and has not encountered a new error window
117 	int ConnectingToLobbyStatus = static_cast<int>(EOS_EResult::EOS_Success); // if invalid lobby join attempt, set to non-success
118 	bool bJoinLobbyWaitingForHostResponse = false;
119 	//bool bStillConnectingToLobby = false; // TODO: client got a lobby invite and booted up the game with this?
120 	char currentLobbyName[32] = "";
121 	EOS_ELobbyPermissionLevel currentPermissionLevel = EOS_ELobbyPermissionLevel::EOS_LPL_PUBLICADVERTISED;
122 	char lobbySearchByCode[32] = "";
123 
124 	std::unordered_set<EOS_ProductUserId> ProductIdsAwaitingAccountMappingCallback;
125 	std::unordered_map<EOS_ProductUserId, EOS_EpicAccountId> AccountMappings;
126 	std::unordered_map<EOS_ProductUserId, std::string> ExternalAccountMappings;
127 
128 	EOS_EResult appRequiresRestart = EOS_EResult::EOS_NotConfigured;
129 
130 	class Achievements_t
131 	{
132 	public:
133 		bool playerDataAwaitingCallback = false;
134 		bool definitionsAwaitingCallback = false;
135 		bool playerDataLoaded = false;
136 		bool definitionsLoaded = false;
137 		void sortAchievementsForDisplay();
138 		bool bAchievementsInit = false;
139 	} Achievements;
140 
141 	class StatGlobal_t
142 	{
143 		EOS_ProductUserId productUserId = nullptr;
144 		bool bIsInit = false;
145 		Uint32 lastUpdateTicks = 0;
146 	public:
147 		bool bPromoEnabled = false;
148 		bool bDataQueued = false;
149 		bool bIsDisabled = false;
getProductUserIdHandle()150 		EOS_ProductUserId getProductUserIdHandle() { return productUserId; }
151 		void init();
152 		void queryGlobalStatUser();
153 		void updateQueuedStats();
154 	} StatGlobalManager;
155 
156 	// actually all pointers...
157 	EOS_HPlatform PlatformHandle = nullptr;
158 	EOS_HPlatform ServerPlatformHandle = nullptr;
159 	EOS_HAuth AuthHandle = nullptr;
160 	EOS_HConnect ConnectHandle = nullptr;
161 	EOS_HFriends FriendsHandle = nullptr;
162 	EOS_HUserInfo UserInfoHandle = nullptr;
163 	EOS_HLobby LobbyHandle = nullptr;
164 	EOS_HLobbyModification LobbyModificationHandle = nullptr;
165 	EOS_HLobbyModification LobbyMemberModificationHandle = nullptr;
166 	EOS_HUI UIHandle = nullptr;
167 	EOS_HEcom EcomHandle = nullptr;
168 	EOS_HAchievements AchievementsHandle = nullptr;
169 	EOS_HStats StatsHandle = nullptr;
170 
171 	class LobbyParameters_t {
172 	public:
173 		enum LobbySearchOptions : int
174 		{
175 			LOBBY_SEARCH_ALL,
176 			LOBBY_SEARCH_BY_LOBBYID
177 		};
178 		enum LobbyJoinOptions : int
179 		{
180 			LOBBY_DONT_JOIN,
181 			LOBBY_JOIN_FIRST_SEARCH_RESULT,
182 			LOBBY_UPDATE_CURRENTLOBBY
183 		};
184 		enum LobbySearchOptionIndices : int
185 		{
186 			SEARCH_OPTIONS,
187 			JOIN_OPTIONS
188 		};
189 
190 		static const int kNumLobbySearchOptions = 2;
191 		EOS_HLobbyDetails lobbyToJoin = nullptr;
192 		int lobbySearchOptions[kNumLobbySearchOptions] = { 0 };
LobbyParameters_t()193 		LobbyParameters_t()
194 		{
195 			clearLobbySearchOptions();
196 		};
setLobbySearchOptions(LobbyParameters_t::LobbySearchOptions searchType,LobbyParameters_t::LobbyJoinOptions joinOptions)197 		void setLobbySearchOptions(LobbyParameters_t::LobbySearchOptions searchType, LobbyParameters_t::LobbyJoinOptions joinOptions)
198 		{
199 			lobbySearchOptions[SEARCH_OPTIONS] = searchType;
200 			lobbySearchOptions[JOIN_OPTIONS] = joinOptions;
201 		}
clearLobbySearchOptions()202 		void clearLobbySearchOptions()
203 		{
204 			for ( int i = 0; i < kNumLobbySearchOptions; ++i )
205 			{
206 				lobbySearchOptions[i] = 0;
207 			}
208 		}
setLobbyToJoin(EOS_HLobbyDetails newLobby)209 		void setLobbyToJoin(EOS_HLobbyDetails newLobby)
210 		{
211 			clearLobbyToJoin();
212 			lobbyToJoin = newLobby;
213 		}
clearLobbyToJoin()214 		void clearLobbyToJoin()
215 		{
216 			if ( lobbyToJoin )
217 			{
218 				EOS_LobbyDetails_Release(lobbyToJoin);
219 				lobbyToJoin = nullptr;
220 			}
221 		}
222 
223 	} LobbyParameters;
224 
EOSFuncs()225 	EOSFuncs() {};
~EOSFuncs()226 	~EOSFuncs() {};
227 
228 	static void EOS_CALL LoggingCallback(const EOS_LogMessage* log);
229 	static void EOS_CALL AuthLoginCompleteCallback(const EOS_Auth_LoginCallbackInfo* data);
230 	static void EOS_CALL FriendsQueryCallback(const EOS_Friends_QueryFriendsCallbackInfo* data);
231 	static void EOS_CALL UserInfoCallback(const EOS_UserInfo_QueryUserInfoCallbackInfo* data);
232 	static void EOS_CALL ConnectLoginCompleteCallback(const EOS_Connect_LoginCallbackInfo* Data);
233 	static void EOS_CALL ConnectLoginCrossplayCompleteCallback(const EOS_Connect_LoginCallbackInfo* Data);
234 	static void EOS_CALL OnCreateLobbyFinished(const EOS_Lobby_CreateLobbyCallbackInfo* Data);
235 	static void EOS_CALL OnLobbySearchFinished(const EOS_LobbySearch_FindCallbackInfo* data);
236 	static void EOS_CALL OnLobbyJoinCallback(const EOS_Lobby_JoinLobbyCallbackInfo* data);
237 	static void EOS_CALL OnLobbyLeaveCallback(const EOS_Lobby_LeaveLobbyCallbackInfo* data);
238 	static void EOS_CALL OnIncomingConnectionRequest(const EOS_P2P_OnIncomingConnectionRequestInfo* data);
239 	static void EOS_CALL OnLobbyUpdateFinished(const EOS_Lobby_UpdateLobbyCallbackInfo* data);
240 	static void EOS_CALL OnLobbyMemberUpdateFinished(const EOS_Lobby_UpdateLobbyCallbackInfo* data);
241 	static void EOS_CALL OnQueryAccountMappingsCallback(const EOS_Connect_QueryProductUserIdMappingsCallbackInfo* Data);
242 	static void EOS_CALL OnMemberUpdateReceived(const EOS_Lobby_LobbyMemberUpdateReceivedCallbackInfo* data);
243 	static void EOS_CALL OnMemberStatusReceived(const EOS_Lobby_LobbyMemberStatusReceivedCallbackInfo* data);
244 	static void EOS_CALL OnDestroyLobbyFinished(const EOS_Lobby_DestroyLobbyCallbackInfo* data);
245 	static void EOS_CALL OnLobbyUpdateReceived(const EOS_Lobby_LobbyUpdateReceivedCallbackInfo* data);
246 	static void EOS_CALL ConnectAuthExpirationCallback(const EOS_Connect_AuthExpirationCallbackInfo* data);
247 	static void EOS_CALL ShowFriendsCallback(const EOS_UI_ShowFriendsCallbackInfo* data);
248 	static void EOS_CALL OnCreateUserCallback(const EOS_Connect_CreateUserCallbackInfo* data);
249 	static void EOS_CALL OnCreateUserCrossplayCallback(const EOS_Connect_CreateUserCallbackInfo* data);
250 	static void EOS_CALL OnEcomQueryOwnershipCallback(const EOS_Ecom_QueryOwnershipCallbackInfo* data);
251 	static void EOS_CALL OnEcomQueryEntitlementsCallback(const EOS_Ecom_QueryEntitlementsCallbackInfo* data);
252 	static void EOS_CALL OnUnlockAchievement(const EOS_Achievements_OnUnlockAchievementsCompleteCallbackInfo* data);
253 	static void EOS_CALL OnAchievementQueryComplete(const EOS_Achievements_OnQueryDefinitionsCompleteCallbackInfo* data);
254 	static void EOS_CALL OnPlayerAchievementQueryComplete(const EOS_Achievements_OnQueryPlayerAchievementsCompleteCallbackInfo* data);
255 	static void EOS_CALL OnIngestStatComplete(const EOS_Stats_IngestStatCompleteCallbackInfo* data);
256 	static void EOS_CALL OnQueryAllStatsCallback(const EOS_Stats_OnQueryStatsCompleteCallbackInfo* data);
257 
258 	class FriendInfo_t {
259 	public:
260 		std::string EpicAccountId = "";
261 		std::string Name = "Pending...";
262 		EOS_EFriendsStatus Status;
263 		bool bUserInfoRequireUpdate = true;
FriendInfo_t(EOS_EFriendsStatus status,std::string epicIdStr)264 		FriendInfo_t(EOS_EFriendsStatus status, std::string epicIdStr)
265 		{
266 			EpicAccountId = epicIdStr;
267 			Status = status;
268 		};
269 	};
270 	class LobbyData_t {
271 	public:
272 		Uint32 MaxPlayers = 0;
273 		std::string LobbyId = "";
274 		std::string OwnerProductUserId = "";
275 		Uint32 FreeSlots = 0;
276 		bool bLobbyHasFullDetailsRead = false;
277 		bool bLobbyHasBasicDetailsRead = false;
278 		bool bAwaitingLeaveCallback = false;
279 		bool bAwaitingCreationCallback = false;
280 		bool bDenyLobbyJoinEvent = false;
281 
282 		class PlayerLobbyData_t {
283 		public:
284 			std::string memberProductUserId = "";
285 			std::string memberEpicAccountId = "";
286 			std::string name = "";
287 			int clientNumber = -1;
288 			bool bUserInfoRequireUpdate = true;
289 			EOS_EExternalAccountType accountType = EOS_EExternalAccountType::EOS_EAT_EPIC;
290 		};
291 		std::vector<PlayerLobbyData_t> playersInLobby;
292 		std::vector<EOS_ProductUserId> lobbyMembersQueueToMappingUpdate;
293 
294 		EOS_NotificationId LobbyMemberUpdateNotification = EOS_INVALID_NOTIFICATIONID;
295 		EOS_NotificationId LobbyMemberStatusNotification = EOS_INVALID_NOTIFICATIONID;
296 		EOS_NotificationId LobbyUpdateNotification = EOS_INVALID_NOTIFICATIONID;
297 		//std::vector<EOS_ProductUserId> lobbyMembersReceivedUpdate;
298 
ClearData()299 		void ClearData()
300 		{
301 			MaxPlayers = 0;
302 			FreeSlots = 0;
303 			LobbyId = "";
304 			OwnerProductUserId = "";
305 			playersInLobby.clear();
306 			bLobbyHasFullDetailsRead = false;
307 			bLobbyHasBasicDetailsRead = false;
308 			bDenyLobbyJoinEvent = false;
309 			LobbyAttributes.ClearData();
310 		};
currentLobbyIsValid()311 		bool currentLobbyIsValid()
312 		{
313 			if ( LobbyId.compare("") == 0 )
314 			{
315 				return false;
316 			}
317 			return true;
318 		}
319 		class LobbyAttributes_t
320 		{
321 			public:
322 				std::string lobbyName = "";
323 				std::string gameVersion = "";
324 				Uint32 isLobbyLoadingSavedGame = 0;
325 				Uint32 serverFlags = 0;
326 				Uint32 numServerMods = 0;
327 				long long lobbyCreationTime = 0;
328 				int gameCurrentLevel = -1;
329 				std::string gameJoinKey = "";
330 				Uint32 PermissionLevel = static_cast<Uint32>(EOS_ELobbyPermissionLevel::EOS_LPL_PUBLICADVERTISED);
331 				Uint32 maxplayersCompatible = MAXPLAYERS;
ClearData()332 				void ClearData()
333 				{
334 					lobbyName = "";
335 					gameVersion = "";
336 					gameJoinKey = "";
337 					isLobbyLoadingSavedGame = 0;
338 					serverFlags = 0;
339 					numServerMods = 0;
340 					lobbyCreationTime = 0;
341 					gameCurrentLevel = -1;
342 					maxplayersCompatible = MAXPLAYERS;
343 					PermissionLevel = static_cast<Uint32>(EOS_ELobbyPermissionLevel::EOS_LPL_PUBLICADVERTISED);
344 				}
345 		} LobbyAttributes;
346 		enum HostUpdateLobbyTypes : int
347 		{
348 			LOBBY_UPDATE_MAIN_MENU,
349 			LOBBY_UPDATE_DURING_GAME
350 		};
351 		bool updateLobbyForHost(HostUpdateLobbyTypes updateType);
352 		void getLobbyAttributes(EOS_HLobbyDetails LobbyDetails);
353 		void getLobbyMemberInfo(EOS_HLobbyDetails LobbyDetails);
354 		void setLobbyAttributesAfterReading(EOS_Lobby_AttributeData* data);
355 		void setLobbyAttributesFromGame(HostUpdateLobbyTypes updateType);
356 		void setBasicCurrentLobbyDataFromInitialJoin(LobbyData_t* lobbyToJoin);
357 		void destroyLobby();
358 		bool currentUserIsOwner();
359 		void updateLobby();
360 		void updateLobbyDuringGameLoop();
361 		bool assignClientnumMemberAttribute(EOS_ProductUserId targetId, int clientNumToSet);
362 		int getClientnumMemberAttribute(EOS_ProductUserId targetId);
363 		bool modifyLobbyMemberAttributeForCurrentUser();
364 
365 		void SubscribeToLobbyUpdates();
366 		void UnsubscribeFromLobbyUpdates();
367 
368 		enum AttributeTypes : int
369 		{
370 			LOBBY_NAME,
371 			GAME_VERSION,
372 			LOADING_SAVEGAME,
373 			SERVER_FLAGS,
374 			GAME_MODS,
375 			CREATION_TIME,
376 			GAME_CURRENT_LEVEL,
377 			GAME_JOIN_KEY,
378 			LOBBY_PERMISSION_LEVEL,
379 			GAME_MAXPLAYERS
380 		};
381 		const int kNumAttributes = 10;
382 		std::pair<std::string, std::string> getAttributePair(AttributeTypes type);
383 
384 	} CurrentLobbyData;
385 
386 	class LobbySearchResults_t {
387 	public:
388 		EOS_HLobbySearch CurrentLobbySearch = nullptr;
389 		std::vector<LobbyData_t> results;
390 		std::vector<std::pair<LobbyData_t::LobbyAttributes_t, int>> resultsSortedForDisplay;
391 		int selectedLobby = 0;
392 		void sortResults();
393 		bool showLobbiesInProgress = false;
394 		bool useLobbyCode = false;
395 		bool lastResultWasFiltered = false;
396 		char lobbyLastSearchByCode[32] = "";
getResultFromDisplayedIndex(int index)397 		LobbyData_t* getResultFromDisplayedIndex(int index)
398 		{
399 			return &results.at(resultsSortedForDisplay.at(index).second);
400 		}
401 	} LobbySearchResults;
402 
403 	class CurrentUserInfo_t {
404 		EOS_ProductUserId productUserIdHandle = nullptr;
405 		std::string productUserId = "";
406 	public:
407 		std::string epicAccountId = "";
408 		bool bUserLoggedIn = false;
409 		std::vector<FriendInfo_t> Friends;
410 		bool bUserInfoRequireUpdate = true;
411 		bool bFriendsUserInfoRequireUpdate = false;
412 		std::string Name = "Pending...";
413 
isLoggedIn()414 		bool isLoggedIn()
415 		{
416 			return bUserLoggedIn;
417 		}
isValid()418 		bool isValid()
419 		{
420 			if ( !productUserIdHandle || productUserId.compare("") == 0 )
421 			{
422 				return false;
423 			}
424 			return true;
425 		}
setProductUserIdHandle(EOS_ProductUserId id)426 		void setProductUserIdHandle(EOS_ProductUserId id)
427 		{
428 			productUserIdHandle = id;
429 			productUserId = EOSFuncs::Helpers_t::productIdToString(id);
430 		}
getProductUserIdHandle()431 		EOS_ProductUserId getProductUserIdHandle() { return productUserIdHandle; }
getProductUserIdStr()432 		const char* getProductUserIdStr() { return productUserId.c_str(); }
433 	} CurrentUserInfo;
434 
435 	class Notifications_t {
436 	public:
437 		EOS_NotificationId P2PConnection = EOS_INVALID_NOTIFICATIONID;
438 		EOS_NotificationId ConnectAuthExpirationId = EOS_INVALID_NOTIFICATIONID;
439 	} NotificationIds;
440 
441 	class P2PConnectionInfo_t {
442 	public:
443 		std::vector<std::pair<EOS_ProductUserId, int>> peerProductIds;
444 		EOS_ProductUserId serverProductId = nullptr;
445 		EOS_ProductUserId getPeerIdFromIndex(int index) const;
446 		int getIndexFromPeerId(EOS_ProductUserId id) const;
insertProductIdIntoPeers(EOS_ProductUserId newId)447 		void insertProductIdIntoPeers(EOS_ProductUserId newId)
448 		{
449 			if ( newId == nullptr )
450 			{
451 				return;
452 			}
453 			bool found = false;
454 			for ( auto& pair : peerProductIds )
455 			{
456 				if ( pair.first == newId )
457 				{
458 					found = true;
459 					break;
460 				}
461 			}
462 			if ( !found )
463 			{
464 				peerProductIds.push_back(std::make_pair(newId, -1));
465 			}
466 		}
467 		bool isPeerIndexed(EOS_ProductUserId id);
468 		bool assignPeerIndex(EOS_ProductUserId id, int index);
469 		bool isPeerStillValid(int index) const;
470 		void resetPeersAndServerData();
471 	} P2PConnectionInfo;
472 
473 	enum UserInfoQueryType : int
474 	{
475 		USER_INFO_QUERY_NONE,
476 		USER_INFO_QUERY_LOCAL,
477 		USER_INFO_QUERY_LOBBY_MEMBER,
478 		USER_INFO_QUERY_FRIEND
479 	};
480 
481 	struct UserInfoQueryData_t
482 	{
483 		EOS_EpicAccountId epicAccountId;
484 		UserInfoQueryType queryType;
485 		int optionalIndex;
486 	};
487 
shutdown()488 	void shutdown()
489 	{
490 		UnsubscribeFromConnectionRequests();
491 		if ( PlatformHandle )
492 		{
493 			EOS_Platform_Release(PlatformHandle);
494 			EOS_Platform_Release(ServerPlatformHandle);
495 			PlatformHandle = nullptr;
496 			ServerPlatformHandle = nullptr;
497 		}
498 		EOS_EResult result = EOS_Shutdown();
499 		if ( result != EOS_EResult::EOS_Success )
500 		{
501 			logError("Shutdown error! code: %d", static_cast<int>(result));
502 		}
503 
504 		logInfo("Shutdown completed.");
505 	}
506 
507 	bool initPlatform(bool enableLogging);
initAuth()508 	bool initAuth()
509 	{
510 		return initAuth(CredentialHost, CredentialName);
511 	}
512 	bool initAchievements();
513 	bool initAuth(std::string hostname, std::string tokenName);
514 	void initConnectLogin();
515 
queryFriends()516 	void queryFriends()
517 	{
518 		FriendsHandle = EOS_Platform_GetFriendsInterface(PlatformHandle);
519 		EOS_Friends_QueryFriendsOptions FriendsOptions;
520 		FriendsOptions.ApiVersion = EOS_FRIENDS_QUERYFRIENDS_API_LATEST;
521 		FriendsOptions.LocalUserId = EOSFuncs::Helpers_t::epicIdFromString(CurrentUserInfo.epicAccountId.c_str());
522 		EOS_Friends_QueryFriends(FriendsHandle, &FriendsOptions, nullptr, FriendsQueryCallback);
523 	}
524 
getUserInfo(EOS_EpicAccountId targetId,UserInfoQueryType queryType,int index)525 	void getUserInfo(EOS_EpicAccountId targetId, UserInfoQueryType queryType, int index)
526 	{
527 		UserInfoHandle = EOS_Platform_GetUserInfoInterface(PlatformHandle);
528 		EOS_UserInfo_QueryUserInfoOptions UserInfoQueryOptions;
529 		UserInfoQueryOptions.ApiVersion = EOS_USERINFO_QUERYUSERINFO_API_LATEST;
530 		UserInfoQueryOptions.LocalUserId = EOSFuncs::Helpers_t::epicIdFromString(CurrentUserInfo.epicAccountId.c_str());
531 		UserInfoQueryOptions.TargetUserId = targetId;
532 
533 		UserInfoQueryData_t* userInfoQueryData = new UserInfoQueryData_t();
534 		userInfoQueryData->epicAccountId = targetId;
535 		userInfoQueryData->queryType = queryType;
536 		userInfoQueryData->optionalIndex = index;
537 
538 		EOS_UserInfo_QueryUserInfo(UserInfoHandle, &UserInfoQueryOptions, userInfoQueryData, UserInfoCallback);
539 	}
540 
541 	void getExternalAccountUserInfo(EOS_ProductUserId targetId, UserInfoQueryType queryType);
542 
543 	void createLobby();
544 	void joinLobby(LobbyData_t* lobby);
545 	void leaveLobby();
546 	void searchLobbies(LobbyParameters_t::LobbySearchOptions searchType,
547 		LobbyParameters_t::LobbyJoinOptions joinOptions, EOS_LobbyId lobbyIdToSearch);
548 	std::string getLobbyCodeFromGameKey(Uint32 key);
549 	Uint32 getGameKeyFromLobbyCode(std::string& code);
550 
setLobbyDetailsFromHandle(EOS_HLobbyDetails LobbyDetails,LobbyData_t * LobbyToSet)551 	void setLobbyDetailsFromHandle(EOS_HLobbyDetails LobbyDetails, LobbyData_t* LobbyToSet)
552 	{
553 		//get owner
554 		EOS_LobbyDetails_GetLobbyOwnerOptions GetOwnerOptions;
555 		GetOwnerOptions.ApiVersion = EOS_LOBBYDETAILS_GETLOBBYOWNER_API_LATEST;
556 		EOS_ProductUserId lobbyOwner = EOS_LobbyDetails_GetLobbyOwner(LobbyDetails, &GetOwnerOptions);
557 		/*if (NewLobbyOwner != LobbyOwner)
558 		{
559 		LobbyOwner = NewLobbyOwner;
560 		LobbyOwnerAccountId = FEpicAccountId();
561 		LobbyOwnerDisplayName.clear();
562 		}*/
563 
564 		//copy lobby info
565 		EOS_LobbyDetails_CopyInfoOptions CopyInfoDetails;
566 		CopyInfoDetails.ApiVersion = EOS_LOBBYDETAILS_COPYINFO_API_LATEST;
567 		EOS_LobbyDetails_Info* LobbyInfo = nullptr;
568 		EOS_EResult result = EOS_LobbyDetails_CopyInfo(LobbyDetails, &CopyInfoDetails, &LobbyInfo);
569 		if ( result != EOS_EResult::EOS_Success || !LobbyInfo )
570 		{
571 			logError("setLobbyDetailsFromHandle: Lobbies can't copy lobby info: %d", static_cast<int>(result));
572 			return;
573 		}
574 
575 		LobbyToSet->LobbyId = LobbyInfo->LobbyId;
576 		LobbyToSet->MaxPlayers = LobbyInfo->MaxMembers;
577 		LobbyToSet->FreeSlots = LobbyInfo->AvailableSlots;
578 		LobbyToSet->OwnerProductUserId = EOSFuncs::Helpers_t::productIdToString(lobbyOwner);
579 		EOS_LobbyDetails_Info_Release(LobbyInfo);
580 
581 		LobbyToSet->getLobbyAttributes(LobbyDetails);
582 		LobbyToSet->getLobbyMemberInfo(LobbyDetails);
583 
584 	}
585 
SubscribeToConnectionRequests()586 	void SubscribeToConnectionRequests()
587 	{
588 		if ( NotificationIds.P2PConnection == EOS_INVALID_NOTIFICATIONID )
589 		{
590 			EOS_HP2P P2PHandle = EOS_Platform_GetP2PInterface(PlatformHandle);
591 
592 			EOS_P2P_SocketId SocketId = {};
593 			SocketId.ApiVersion = EOS_P2P_SOCKETID_API_LATEST;
594 			strncpy(SocketId.SocketName, "CHAT", 5);
595 
596 			EOS_P2P_AddNotifyPeerConnectionRequestOptions ConnectionRequestOptions;
597 			ConnectionRequestOptions.ApiVersion = EOS_P2P_ADDNOTIFYPEERCONNECTIONREQUEST_API_LATEST;
598 			ConnectionRequestOptions.LocalUserId = CurrentUserInfo.getProductUserIdHandle();
599 			ConnectionRequestOptions.SocketId = &SocketId;
600 
601 			NotificationIds.P2PConnection = EOS_P2P_AddNotifyPeerConnectionRequest(P2PHandle,
602 				&ConnectionRequestOptions, nullptr, OnIncomingConnectionRequest);
603 			if ( NotificationIds.P2PConnection == EOS_INVALID_NOTIFICATIONID )
604 			{
605 				logError("SubscribeToConnectionRequests: could not subscribe, bad notification id returned.");
606 			}
607 		}
608 	}
609 
UnsubscribeFromConnectionRequests()610 	void UnsubscribeFromConnectionRequests()
611 	{
612 		if ( NotificationIds.P2PConnection == EOS_INVALID_NOTIFICATIONID )
613 		{
614 			return;
615 		}
616 		EOS_HP2P P2PHandle = EOS_Platform_GetP2PInterface(PlatformHandle);
617 		EOS_P2P_RemoveNotifyPeerConnectionRequest(P2PHandle, NotificationIds.P2PConnection);
618 		NotificationIds.P2PConnection = EOS_INVALID_NOTIFICATIONID;
619 	}
620 
AddConnectAuthExpirationNotification()621 	void AddConnectAuthExpirationNotification()
622 	{
623 		EOS_HConnect ConnectHandle = EOS_Platform_GetConnectInterface(PlatformHandle);
624 		if ( NotificationIds.ConnectAuthExpirationId == EOS_INVALID_NOTIFICATIONID )
625 		{
626 			EOS_Connect_AddNotifyAuthExpirationOptions Options;
627 			Options.ApiVersion = EOS_CONNECT_ADDNOTIFYAUTHEXPIRATION_API_LATEST;
628 			NotificationIds.ConnectAuthExpirationId = EOS_Connect_AddNotifyAuthExpiration(ConnectHandle, &Options, NULL, ConnectAuthExpirationCallback);
629 		}
630 	}
631 
632 	class Helpers_t
633 	{
634 		public:
productIdIsValid(EOS_ProductUserId id)635 			static bool productIdIsValid(EOS_ProductUserId id)
636 			{
637 				return (EOS_ProductUserId_IsValid(id) == EOS_TRUE);
638 			}
productIdToString(EOS_ProductUserId id)639 			static const char* productIdToString(EOS_ProductUserId id)
640 			{
641 				if ( !id )
642 				{
643 					return "NULL";
644 				}
645 				if ( !productIdIsValid(id) )
646 				{
647 					return "Invalid EOS_ProductUserId";
648 				}
649 				else
650 				{
651 					static char buffer[EOS_PRODUCTUSERID_MAX_LENGTH];
652 					int bufferSize = sizeof(buffer);
653 					EOS_EResult result = EOS_ProductUserId_ToString(id, buffer, &bufferSize);
654 					if ( result == EOS_EResult::EOS_Success )
655 					{
656 						return buffer;
657 					}
658 					return "Error";
659 				}
660 			}
shortProductIdToString(EOS_ProductUserId id)661 			static std::string shortProductIdToString(EOS_ProductUserId id)
662 			{
663 				std::string str = productIdToString(id);
664 				if ( id && productIdIsValid(id) && str.compare("Error") )
665 				{
666 					std::string shortStr = str.substr(0, 3);
667 					shortStr.append("...");
668 					shortStr.append(str.substr(str.size() - 3));
669 					return shortStr;
670 				}
671 				return str;
672 			}
epicIdIsValid(EOS_EpicAccountId id)673 			static bool epicIdIsValid(EOS_EpicAccountId id)
674 			{
675 				return (EOS_EpicAccountId_IsValid(id) == EOS_TRUE);
676 			}
epicIdToString(EOS_EpicAccountId id)677 			static const char* epicIdToString(EOS_EpicAccountId id)
678 			{
679 				if ( !id )
680 				{
681 					return "NULL";
682 				}
683 				if ( !epicIdIsValid(id) )
684 				{
685 					return "Invalid EOS_EpicAccountId";
686 				}
687 				else
688 				{
689 					static char buffer[EOS_EPICACCOUNTID_MAX_LENGTH];
690 					int bufferSize = sizeof(buffer);
691 					EOS_EResult result = EOS_EpicAccountId_ToString(id, buffer, &bufferSize);
692 					if ( result == EOS_EResult::EOS_Success )
693 					{
694 						return buffer;
695 					}
696 					return "Error";
697 				}
698 			}
isMatchingProductIds(std::string str1,std::string str2)699 			static bool isMatchingProductIds(std::string str1, std::string str2)
700 			{
701 				EOS_ProductUserId id1 = productIdFromString(str1.c_str());
702 				EOS_ProductUserId id2 = productIdFromString(str2.c_str());
703 				return isMatchingProductIds(id1, id2);
704 			}
isMatchingProductIds(EOS_ProductUserId id1,EOS_ProductUserId id2)705 			static bool isMatchingProductIds(EOS_ProductUserId id1, EOS_ProductUserId id2)
706 			{
707 				if ( !id1 || !id2 )
708 				{
709 					return false;
710 				}
711 				if ( !productIdIsValid(id1) || !productIdIsValid(id2) )
712 				{
713 					logError("isMatchingProductIds: mismatch one or more id invalid: %s | %s", productIdToString(id1), productIdToString(id2));
714 					return false;
715 				}
716 				//std::string str1 = productIdToString(id1);
717 				//std::string str2 = productIdToString(id2);
718 				if ( id1 == id2 )
719 				{
720 					return true;
721 				}
722 				//logError("isMatchingProductIds: mismatch: %s | %s", str1.c_str(), str2.c_str());
723 				return false;
724 			}
epicIdFromString(const char * string)725 			static EOS_EpicAccountId epicIdFromString(const char* string)
726 			{
727 				if ( !string )
728 				{
729 					return nullptr;
730 				}
731 				return EOS_EpicAccountId_FromString(string);
732 			}
productIdFromString(const char * string)733 			static EOS_ProductUserId productIdFromString(const char* string)
734 			{
735 				if ( !string )
736 				{
737 					return nullptr;
738 				}
739 				return EOS_ProductUserId_FromString(string);
740 			}
741 	};
742 
743 	bool HandleReceivedMessages(EOS_ProductUserId* remoteIdReturn);
744 	bool HandleReceivedMessagesAndIgnore(EOS_ProductUserId* remoteIdReturn); // function to empty the packet queue on main lobby.
745 	void SendMessageP2P(EOS_ProductUserId RemoteId, const void* data, int len);
746 	void serialize(void* file);
747 	void readFromFile();
748 	void readFromCmdLineArgs();
749 	void queryAccountIdFromProductId(LobbyData_t* lobby/*, std::vector<EOS_ProductUserId>& accountsToQuery*/);
750 	void queryLocalExternalAccountId(EOS_EExternalAccountType accountType);
751 	void showFriendsOverlay();
752 	void queryDLCOwnership();
753 	void unlockAchievement(const char* name);
754 	void loadAchievementData();
755 	void ingestStat(int stat_num, int value);
756 	void ingestGlobalStats();
757 	void queueGlobalStatUpdate(int stat_num, int value);
758 	void queryAllStats();
759 	SteamStat_t* getStatStructFromString(const std::string& str);
logInfo(const char * str,...)760 	static void logInfo(const char* str, ...)
761 	{
762 		char newstr[1024] = { 0 };
763 		va_list argptr;
764 
765 		// format the content
766 		va_start(argptr, str);
767 		vsnprintf(newstr, 1023, str, argptr);
768 		va_end(argptr);
769 		printlog("[EOS Info]: %s", newstr);
770 	}
logError(const char * str,...)771 	static void logError(const char* str, ...)
772 	{
773 		char newstr[1024] = { 0 };
774 		va_list argptr;
775 
776 		// format the content
777 		va_start(argptr, str);
778 		vsnprintf(newstr, 1023, str, argptr);
779 		va_end(argptr);
780 		printlog("[EOS Error]: %s", newstr);
781 	}
782 };
783 
784 extern EOSFuncs EOS;
785 
786 #endif //USE_EOS
787