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