Last active
January 12, 2024 21:21
-
-
Save phosphoer/28eb8e7da61cb25ea3472fe432f2cda8 to your computer and use it in GitHub Desktop.
Epic Game SDK Unity Integration
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Collections; | |
using System.Collections.Generic; | |
using UnityEngine; | |
#if BUILD_EPIC | |
using PlayEveryWare.EpicOnlineServices; | |
using Epic.OnlineServices; | |
using Epic.OnlineServices.Achievements; | |
using Epic.OnlineServices.Auth; | |
using Epic.OnlineServices.Presence; | |
public class EpicGameClient : MonoBehaviour, IEOSCoroutineOwner | |
{ | |
private static Dictionary<string, string> _commandLineArgs = new Dictionary<string, string>(); | |
private static readonly AuthScopeFlags kScopeFlags = AuthScopeFlags.FriendsList | AuthScopeFlags.Presence; | |
private static bool _isOverlayBlockingInput; | |
public static void UnlockAchievement(string achievementName) | |
{ | |
QAG.ConsoleDebug.Log($"EpicGameClient: Unlocking achievement {achievementName}..."); | |
var platformInterface = EOSManager.Instance.GetEOSPlatformInterface(); | |
if (platformInterface == null) | |
return; | |
var localUserId = EOSManager.Instance.GetProductUserId(); | |
if (localUserId == null) | |
{ | |
QAG.ConsoleDebug.Log("EpicGameClient: Local User is null! Aborting achievement unlock."); | |
return; | |
} | |
var eosAchievementOption = new Epic.OnlineServices.Achievements.UnlockAchievementsOptions | |
{ | |
UserId = localUserId, | |
AchievementIds = new Utf8String[] { achievementName } | |
}; | |
var achievementsInterface = platformInterface.GetAchievementsInterface(); | |
achievementsInterface.UnlockAchievements(ref eosAchievementOption, null, OnUnlockAchievementsCompleteCallback); | |
} | |
public static void SetPresence(string localizedText) | |
{ | |
QAG.ConsoleDebug.Log($"EpicGameClient: Setting Presence to {localizedText}..."); | |
var platformInterface = EOSManager.Instance.GetEOSPlatformInterface(); | |
if (platformInterface == null) | |
return; | |
var localUserId = EOSManager.Instance.GetLocalUserId(); | |
if (localUserId == null) | |
{ | |
QAG.ConsoleDebug.Log("EpicGameClient: Local User is null! Aborting presence update."); | |
return; | |
} | |
var modificationOptions = new CreatePresenceModificationOptions(); | |
modificationOptions.LocalUserId = localUserId; | |
var presenceInterface = platformInterface.GetPresenceInterface(); | |
Result result = presenceInterface.CreatePresenceModification(ref modificationOptions, out PresenceModification presenceModification); | |
if (result == Result.Success) | |
{ | |
var rawTextOptions = new PresenceModificationSetRawRichTextOptions(); | |
rawTextOptions.RichText = localizedText; | |
presenceModification.SetRawRichText(ref rawTextOptions); | |
var options = new SetPresenceOptions(); | |
options.LocalUserId = localUserId; | |
options.PresenceModificationHandle = presenceModification; | |
presenceInterface.SetPresence(ref options, null, OnSetPresenceComplete); | |
presenceModification.Release(); | |
} | |
} | |
private void Awake() | |
{ | |
EOSManager.Instance.Init(this); | |
} | |
private IEnumerator Start() | |
{ | |
yield return Tween.WaitForTime(1); | |
#if UNITY_EDITOR | |
TryPersistentLogin(); | |
#else | |
TryEpicLauncherLogin(); | |
#endif | |
} | |
private void Update() | |
{ | |
EOSManager.Instance.Tick(); | |
if (EOSManager.Instance.IsOverlayOpenWithExclusiveInput() && !_isOverlayBlockingInput) | |
{ | |
_isOverlayBlockingInput = true; | |
PlayerMenuInput.ForceDisableAllFocus = true; | |
CanvasCursor.PushVisible(); | |
} | |
else if (!EOSManager.Instance.IsOverlayOpenWithExclusiveInput() && _isOverlayBlockingInput) | |
{ | |
_isOverlayBlockingInput = false; | |
PlayerMenuInput.ForceDisableAllFocus = false; | |
CanvasCursor.PopVisible(); | |
} | |
} | |
private void OnApplicationQuit() | |
{ | |
EOSManager.Instance.OnShutdown(); | |
} | |
private void OnApplicationFocus(bool hasFocus) | |
{ | |
EOSManager.Instance.OnApplicationFocus(hasFocus); | |
} | |
private void OnApplicationPause(bool pauseStatus) | |
{ | |
EOSManager.Instance.OnApplicationPause(pauseStatus); | |
} | |
#if UNITY_EDITOR | |
[UnityEditor.MenuItem("Boat Game/Clear Epic Persistent Auth")] | |
private static void DeletePersistentAuth() | |
{ | |
var authInterface = EOSManager.Instance.GetEOSAuthInterface(); | |
DeletePersistentAuthOptions deleteAuthOptions = new DeletePersistentAuthOptions(); | |
authInterface.DeletePersistentAuth(ref deleteAuthOptions, null, OnPersistentDataDeleteCallback); | |
} | |
#endif | |
// This parses commandline args in the format "app.exe paramName=paramValue param2Name=param2Value | |
// which is what Epic launcher does | |
private static void ParseCommandLine() | |
{ | |
_commandLineArgs.Clear(); | |
string[] commandLineArgs = System.Environment.GetCommandLineArgs(); | |
string authToken = string.Empty; | |
for (int i = 0; i < commandLineArgs.Length; i++) | |
{ | |
string arg = commandLineArgs[i]; | |
string[] argParts = arg.Split('='); | |
if (argParts.Length == 2) | |
{ | |
string paramName = argParts[0]; | |
string paramValue = argParts[1]; | |
_commandLineArgs[paramName] = paramValue; | |
QAG.ConsoleDebug.Log($"Got commandline arg {paramName} with value {paramValue}"); | |
} | |
} | |
} | |
private static void OnSetPresenceComplete(ref Epic.OnlineServices.Presence.SetPresenceCallbackInfo callbackInfo) | |
{ | |
QAG.ConsoleDebug.Log($"EpicGameClient: Set Presence result {callbackInfo.ResultCode}"); | |
} | |
private static void OnUnlockAchievementsCompleteCallback(ref OnUnlockAchievementsCompleteCallbackInfo data) | |
{ | |
QAG.ConsoleDebug.Log($"EpicGameClient: Unlock Achievement result {data.ResultCode}"); | |
} | |
private static void OnPersistentDataDeleteCallback(ref DeletePersistentAuthCallbackInfo callbackInfo) | |
{ | |
QAG.ConsoleDebug.Log($"EpicGameClient: Delete persistent login result: {callbackInfo.ResultCode}"); | |
} | |
private void TryLoginWithOptions(LoginOptions options, bool fallbackToAccountPortal) | |
{ | |
EOSManager.Instance.StartLoginWithLoginOptions(options, callbackInfo => | |
{ | |
QAG.ConsoleDebug.Log($"EpicGameClient: Login result: {callbackInfo.ResultCode}"); | |
// If successful, the credentials were stored on local keychain but we may still need to link this | |
// login with an epic account id or something? | |
if (callbackInfo.ResultCode == Result.Success) | |
{ | |
TryLoginWithEpicAccount(callbackInfo.LocalUserId, tryCreateUserOnInvalidUser: true); | |
} | |
// Otherwise, we need to log in with account portal? | |
else if (fallbackToAccountPortal) | |
{ | |
TryAccountPortalLogin(); | |
} | |
else | |
{ | |
QAG.ConsoleDebug.LogError("EpicGameClient: Login failed and fallbackToAccountPortal is false...giving up."); | |
} | |
}); | |
} | |
private void TryEpicLauncherLogin() | |
{ | |
QAG.ConsoleDebug.Log("EpicGameClient: Attempting Epic Launcher Login..."); | |
ParseCommandLine(); | |
string authToken = string.Empty; | |
if (!_commandLineArgs.TryGetValue("-AUTH_PASSWORD", out authToken)) | |
{ | |
QAG.ConsoleDebug.LogError("EpicGameClient: No auth token provided by Epic Launcher, login will fallback to account portal!"); | |
} | |
LoginOptions options = new LoginOptions(); | |
var credentials = new Credentials(); | |
credentials.Type = LoginCredentialType.ExchangeCode; | |
credentials.ExternalType = ExternalCredentialType.Epic; | |
credentials.Token = authToken; | |
options.Credentials = credentials; | |
options.ScopeFlags = kScopeFlags; | |
TryLoginWithOptions(options, fallbackToAccountPortal: true); | |
} | |
private void TryPersistentLogin() | |
{ | |
QAG.ConsoleDebug.Log("EpicGameClient: Attempting Persistent Login..."); | |
LoginOptions options = new LoginOptions(); | |
var credentials = new Credentials(); | |
credentials.Type = LoginCredentialType.PersistentAuth; | |
credentials.ExternalType = ExternalCredentialType.Epic; | |
options.Credentials = credentials; | |
options.ScopeFlags = kScopeFlags; | |
TryLoginWithOptions(options, fallbackToAccountPortal: true); | |
} | |
private void TryAccountPortalLogin() | |
{ | |
QAG.ConsoleDebug.Log("EpicGameClient: Attempting Account Portal Login..."); | |
LoginOptions options = new LoginOptions(); | |
var credentials = new Credentials(); | |
credentials.Type = LoginCredentialType.AccountPortal; | |
credentials.ExternalType = ExternalCredentialType.Epic; | |
options.Credentials = credentials; | |
options.ScopeFlags = kScopeFlags; | |
TryLoginWithOptions(options, fallbackToAccountPortal: false); | |
} | |
private void TryLoginWithEpicAccount(EpicAccountId epicAccountId, bool tryCreateUserOnInvalidUser) | |
{ | |
// Try to login with the epic account, which might fail because it hasn't been connected or something? | |
EOSManager.Instance.StartConnectLoginWithEpicAccount(epicAccountId, onConnectInfo => | |
{ | |
QAG.ConsoleDebug.Log($"EpicGameClient: Epic Account Login Result: {onConnectInfo.ResultCode}"); | |
// If this succeeds, we are good to go | |
if (onConnectInfo.ResultCode == Result.Success) | |
{ | |
} | |
// If it fails, we have to do this other connect thing to turn my epic account id into...an epic account id?? | |
else if (onConnectInfo.ResultCode == Result.InvalidUser) | |
{ | |
if (tryCreateUserOnInvalidUser) | |
{ | |
QAG.ConsoleDebug.Log("EpicGameClient: Attempting to create user product Id..."); | |
EOSManager.Instance.CreateConnectUserWithContinuanceToken(onConnectInfo.ContinuanceToken, createUserCallbackInfo => | |
{ | |
QAG.ConsoleDebug.Log($"EpicGameClient: Create user callback result: {createUserCallbackInfo.ResultCode}"); | |
// Now try again logging in with the epic account | |
if (createUserCallbackInfo.ResultCode == Result.Success) | |
{ | |
TryLoginWithEpicAccount(epicAccountId, tryCreateUserOnInvalidUser: false); | |
} | |
// If we fail to connect the account...not sure what to do | |
else | |
{ | |
QAG.ConsoleDebug.LogError("EpicGameClient: Failed to log in to epic account and creating connect user has already failed"); | |
} | |
}); | |
} | |
// If we've already tried creating the user and logging in fails...not sure what to do | |
else | |
{ | |
QAG.ConsoleDebug.LogError("EpicGameClient: Failed to log in to epic account and creating connect user has already failed"); | |
} | |
} | |
}); | |
} | |
void IEOSCoroutineOwner.StartCoroutine(IEnumerator routine) | |
{ | |
StartCoroutine(routine); | |
} | |
} | |
#else | |
// Stubbed out implementation for non epic builds where the sdk is not included | |
public class EpicGameClient : MonoBehaviour | |
{ | |
public static void UnlockAchievement(string achievementName) | |
{ | |
// Do nothing | |
} | |
public static void SetPresence(string localizedText) | |
{ | |
// Do nothing | |
} | |
} | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Thank you so much for posting this code! I was having a related issue with OpenID validation (going from EOS to UGS) and seeing how you fetched
var authInterface = EOSManager.Instance.GetEOSAuthInterface();
put me on the path to stumble across how to generate and send Unity a token properly! Prob saved me days of digging, thanks again!
Also for posterity if anyone else googles for this problem, this code worked for my issue: