From 6a58678075ca09389a2133eb857e794c2c2e0f7e Mon Sep 17 00:00:00 2001 From: Kevin Yang <68880349+MadkevOP7@users.noreply.github.com> Date: Thu, 30 Dec 2021 22:38:05 -0800 Subject: [PATCH 01/11] Added Mac OS editor .dylib getlibrary --- .../EpicOnlineTransport/EOSSDKComponent.cs | 62 ++++++++++++++++--- 1 file changed, 53 insertions(+), 9 deletions(-) diff --git a/Mirror/Runtime/Transport/EpicOnlineTransport/EOSSDKComponent.cs b/Mirror/Runtime/Transport/EpicOnlineTransport/EOSSDKComponent.cs index 93162f8c..9d4bebde 100644 --- a/Mirror/Runtime/Transport/EpicOnlineTransport/EOSSDKComponent.cs +++ b/Mirror/Runtime/Transport/EpicOnlineTransport/EOSSDKComponent.cs @@ -15,9 +15,10 @@ /// In the unity editor the OnDestroy function will not run so that we dont have to restart the editor after play. /// namespace EpicTransport { + [DefaultExecutionOrder(-32000)] public class EOSSDKComponent : MonoBehaviour { - + // Unity Inspector shown variables [SerializeField] @@ -143,6 +144,15 @@ protected static EOSSDKComponent Instance { } public static void Tick() { + if (instance == null) + { + Debug.LogError("INSTANCE NULL"); + + } + else + { + Debug.Log(instance.gameObject.name); + } instance.platformTickTimer -= Time.deltaTime; instance.EOS.Tick(); } @@ -161,7 +171,7 @@ public static void Tick() { private IntPtr libraryPointer; #endif - + #if UNITY_EDITOR_LINUX [DllImport("libdl.so", EntryPoint = "dlopen")] private static extern IntPtr LoadLibrary(String lpFileName, int flags = 2); @@ -187,7 +197,35 @@ private static IntPtr GetProcAddress(IntPtr hModule, string lpProcName) { } private IntPtr libraryPointer; #endif +#if UNITY_EDITOR_OSX + [DllImport("libdl.dylib", EntryPoint = "dlopen")] + private static extern IntPtr LoadLibrary(String lpFileName, int flags = 2); + + [DllImport("libdl.dylib", EntryPoint = "dlclose")] + private static extern int FreeLibrary(IntPtr hLibModule); + + [DllImport("libdl.dylib")] + private static extern IntPtr dlsym(IntPtr handle, String symbol); + + [DllImport("libdl.dylib")] + private static extern IntPtr dlerror(); + + private static IntPtr GetProcAddress(IntPtr hModule, string lpProcName) + { + // clear previous errors if any + dlerror(); + var res = dlsym(hModule, lpProcName); + var errPtr = dlerror(); + if (errPtr != IntPtr.Zero) + { + throw new Exception("dlsym: " + Marshal.PtrToStringAnsi(errPtr)); + } + + return res; + } + private IntPtr libraryPointer; +#endif private void Awake() { // Initialize Java version of the SDK with a reference to the VM with JNI // See https://eoshelp.epicgames.com/s/question/0D54z00006ufJBNCA2/cant-get-createdeviceid-to-work-in-unity-android-c-sdk?language=en_US @@ -199,13 +237,15 @@ private void Awake() { AndroidJavaClass EOS_SDK_JAVA = new AndroidJavaClass("com.epicgames.mobile.eossdk.EOSSDK"); EOS_SDK_JAVA.CallStatic("init", context); } - + // Prevent multiple instances + if (instance != null) { Destroy(gameObject); return; } instance = this; + DontDestroyOnLoad(instance); #if UNITY_EDITOR var libraryPath = "Assets/Mirror/Runtime/Transport/EpicOnlineTransport/EOSSDK/" + Config.LibraryName; @@ -412,21 +452,25 @@ private void LateUpdate() { } private void OnApplicationQuit() { - if (EOS != null) { +#if !UNITY_EDITOR + if (EOS != null) + { EOS.Release(); EOS = null; PlatformInterface.Shutdown(); } - +#endif // Unhook the library in the editor, this makes it possible to load the library again after stopping to play #if UNITY_EDITOR if (libraryPointer != IntPtr.Zero) { - Bindings.Unhook(); - - // Free until the module ref count is 0 - while (FreeLibrary(libraryPointer) != 0) { } + Bindings.Unhook(); + // // Free until the module ref count is 0 + while (FreeLibrary(libraryPointer) != 0) + { + } libraryPointer = IntPtr.Zero; + } #endif } From 04d54bfb8615f5f40639f915d69fa068797f8127 Mon Sep 17 00:00:00 2001 From: Kevin Yang <68880349+MadkevOP7@users.noreply.github.com> Date: Thu, 30 Dec 2021 22:39:16 -0800 Subject: [PATCH 02/11] Modified .dylib extension in Config --- .../Transport/EpicOnlineTransport/EOSSDK/Core/Config.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Mirror/Runtime/Transport/EpicOnlineTransport/EOSSDK/Core/Config.cs b/Mirror/Runtime/Transport/EpicOnlineTransport/EOSSDK/Core/Config.cs index 8bd20ad2..d2c1b1ba 100644 --- a/Mirror/Runtime/Transport/EpicOnlineTransport/EOSSDK/Core/Config.cs +++ b/Mirror/Runtime/Transport/EpicOnlineTransport/EOSSDK/Core/Config.cs @@ -59,8 +59,8 @@ public static class Config #elif EOS_PLATFORM_WINDOWS_64 "EOSSDK-Win64-Shipping.dll" - #elif EOS_PLATFORM_OSX && EOS_UNITY - "libEOSSDK-Mac-Shipping" + #elif UNITY_EDITOR_OSX + "libEOSSDK-Mac-Shipping.dylib" #elif EOS_PLATFORM_OSX "libEOSSDK-Mac-Shipping.dylib" From 0b68f9852f75841d246dd1ab57f44158d734e960 Mon Sep 17 00:00:00 2001 From: Kevin Yang <68880349+MadkevOP7@users.noreply.github.com> Date: Fri, 31 Dec 2021 23:02:28 -0800 Subject: [PATCH 03/11] iOS Build Support by MADKEV Updated: -Added EOSSDK.framework -iOS Post Process build to automatically disable bitcode for running correctly --- .../EOSSDK/EOSSDK-Win32-Shipping.dll.meta | 50 ++++++++++++++++++- .../EOSSDK/EOSSDK-Win64-Shipping.dll.meta | 50 ++++++++++++++++++- .../EOSSDK/EOSSDK.framework/EOSSDK.meta | 7 +++ .../EOSSDK/EOSSDK.framework/Info.plist.meta | 7 +++ 4 files changed, 110 insertions(+), 4 deletions(-) create mode 100644 Mirror/Runtime/Transport/EpicOnlineTransport/EOSSDK/EOSSDK.framework/EOSSDK.meta create mode 100644 Mirror/Runtime/Transport/EpicOnlineTransport/EOSSDK/EOSSDK.framework/Info.plist.meta diff --git a/Mirror/Runtime/Transport/EpicOnlineTransport/EOSSDK/EOSSDK-Win32-Shipping.dll.meta b/Mirror/Runtime/Transport/EpicOnlineTransport/EOSSDK/EOSSDK-Win32-Shipping.dll.meta index 806feb83..b9fca1be 100644 --- a/Mirror/Runtime/Transport/EpicOnlineTransport/EOSSDK/EOSSDK-Win32-Shipping.dll.meta +++ b/Mirror/Runtime/Transport/EpicOnlineTransport/EOSSDK/EOSSDK-Win32-Shipping.dll.meta @@ -11,17 +11,63 @@ PluginImporter: isExplicitlyReferenced: 0 validateReferences: 1 platformData: + - first: + : Any + second: + enabled: 0 + settings: + Exclude Editor: 0 + Exclude Linux64: 1 + Exclude OSXUniversal: 1 + Exclude Win: 1 + Exclude Win64: 1 + Exclude iOS: 1 - first: Any: second: - enabled: 1 + enabled: 0 settings: {} - first: Editor: Editor second: - enabled: 0 + enabled: 1 settings: + CPU: x86 DefaultValueInitialized: true + OS: Windows + - first: + Standalone: Linux64 + second: + enabled: 0 + settings: + CPU: None + - first: + Standalone: OSXUniversal + second: + enabled: 0 + settings: + CPU: None + - first: + Standalone: Win + second: + enabled: 0 + settings: + CPU: None + - first: + Standalone: Win64 + second: + enabled: 0 + settings: + CPU: None + - first: + iPhone: iOS + second: + enabled: 0 + settings: + AddToEmbeddedBinaries: false + CPU: AnyCPU + CompileFlags: + FrameworkDependencies: userData: assetBundleName: assetBundleVariant: diff --git a/Mirror/Runtime/Transport/EpicOnlineTransport/EOSSDK/EOSSDK-Win64-Shipping.dll.meta b/Mirror/Runtime/Transport/EpicOnlineTransport/EOSSDK/EOSSDK-Win64-Shipping.dll.meta index b59dedff..c675f356 100644 --- a/Mirror/Runtime/Transport/EpicOnlineTransport/EOSSDK/EOSSDK-Win64-Shipping.dll.meta +++ b/Mirror/Runtime/Transport/EpicOnlineTransport/EOSSDK/EOSSDK-Win64-Shipping.dll.meta @@ -11,17 +11,63 @@ PluginImporter: isExplicitlyReferenced: 0 validateReferences: 1 platformData: + - first: + : Any + second: + enabled: 0 + settings: + Exclude Editor: 0 + Exclude Linux64: 1 + Exclude OSXUniversal: 1 + Exclude Win: 1 + Exclude Win64: 1 + Exclude iOS: 1 - first: Any: second: - enabled: 1 + enabled: 0 settings: {} - first: Editor: Editor second: - enabled: 0 + enabled: 1 settings: + CPU: x86_64 DefaultValueInitialized: true + OS: Windows + - first: + Standalone: Linux64 + second: + enabled: 0 + settings: + CPU: None + - first: + Standalone: OSXUniversal + second: + enabled: 0 + settings: + CPU: None + - first: + Standalone: Win + second: + enabled: 0 + settings: + CPU: None + - first: + Standalone: Win64 + second: + enabled: 0 + settings: + CPU: None + - first: + iPhone: iOS + second: + enabled: 0 + settings: + AddToEmbeddedBinaries: false + CPU: AnyCPU + CompileFlags: + FrameworkDependencies: userData: assetBundleName: assetBundleVariant: diff --git a/Mirror/Runtime/Transport/EpicOnlineTransport/EOSSDK/EOSSDK.framework/EOSSDK.meta b/Mirror/Runtime/Transport/EpicOnlineTransport/EOSSDK/EOSSDK.framework/EOSSDK.meta new file mode 100644 index 00000000..e1b89092 --- /dev/null +++ b/Mirror/Runtime/Transport/EpicOnlineTransport/EOSSDK/EOSSDK.framework/EOSSDK.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 03016ec018d7746e196cdd42a5e8e68a +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Mirror/Runtime/Transport/EpicOnlineTransport/EOSSDK/EOSSDK.framework/Info.plist.meta b/Mirror/Runtime/Transport/EpicOnlineTransport/EOSSDK/EOSSDK.framework/Info.plist.meta new file mode 100644 index 00000000..1d071386 --- /dev/null +++ b/Mirror/Runtime/Transport/EpicOnlineTransport/EOSSDK/EOSSDK.framework/Info.plist.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 074430e7c093a4d87acb603bec6ce27e +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: From 467e4b5660f0e6046d79210dc83d443fdc9bef9d Mon Sep 17 00:00:00 2001 From: Kevin Yang <68880349+MadkevOP7@users.noreply.github.com> Date: Fri, 31 Dec 2021 23:19:34 -0800 Subject: [PATCH 04/11] Revert "iOS Build Support by MADKEV" This reverts commit 0b68f9852f75841d246dd1ab57f44158d734e960. --- .../EOSSDK/EOSSDK-Win32-Shipping.dll.meta | 50 +------------------ .../EOSSDK/EOSSDK-Win64-Shipping.dll.meta | 50 +------------------ .../EOSSDK/EOSSDK.framework/EOSSDK.meta | 7 --- .../EOSSDK/EOSSDK.framework/Info.plist.meta | 7 --- 4 files changed, 4 insertions(+), 110 deletions(-) delete mode 100644 Mirror/Runtime/Transport/EpicOnlineTransport/EOSSDK/EOSSDK.framework/EOSSDK.meta delete mode 100644 Mirror/Runtime/Transport/EpicOnlineTransport/EOSSDK/EOSSDK.framework/Info.plist.meta diff --git a/Mirror/Runtime/Transport/EpicOnlineTransport/EOSSDK/EOSSDK-Win32-Shipping.dll.meta b/Mirror/Runtime/Transport/EpicOnlineTransport/EOSSDK/EOSSDK-Win32-Shipping.dll.meta index b9fca1be..806feb83 100644 --- a/Mirror/Runtime/Transport/EpicOnlineTransport/EOSSDK/EOSSDK-Win32-Shipping.dll.meta +++ b/Mirror/Runtime/Transport/EpicOnlineTransport/EOSSDK/EOSSDK-Win32-Shipping.dll.meta @@ -11,63 +11,17 @@ PluginImporter: isExplicitlyReferenced: 0 validateReferences: 1 platformData: - - first: - : Any - second: - enabled: 0 - settings: - Exclude Editor: 0 - Exclude Linux64: 1 - Exclude OSXUniversal: 1 - Exclude Win: 1 - Exclude Win64: 1 - Exclude iOS: 1 - first: Any: second: - enabled: 0 + enabled: 1 settings: {} - first: Editor: Editor - second: - enabled: 1 - settings: - CPU: x86 - DefaultValueInitialized: true - OS: Windows - - first: - Standalone: Linux64 - second: - enabled: 0 - settings: - CPU: None - - first: - Standalone: OSXUniversal - second: - enabled: 0 - settings: - CPU: None - - first: - Standalone: Win - second: - enabled: 0 - settings: - CPU: None - - first: - Standalone: Win64 second: enabled: 0 settings: - CPU: None - - first: - iPhone: iOS - second: - enabled: 0 - settings: - AddToEmbeddedBinaries: false - CPU: AnyCPU - CompileFlags: - FrameworkDependencies: + DefaultValueInitialized: true userData: assetBundleName: assetBundleVariant: diff --git a/Mirror/Runtime/Transport/EpicOnlineTransport/EOSSDK/EOSSDK-Win64-Shipping.dll.meta b/Mirror/Runtime/Transport/EpicOnlineTransport/EOSSDK/EOSSDK-Win64-Shipping.dll.meta index c675f356..b59dedff 100644 --- a/Mirror/Runtime/Transport/EpicOnlineTransport/EOSSDK/EOSSDK-Win64-Shipping.dll.meta +++ b/Mirror/Runtime/Transport/EpicOnlineTransport/EOSSDK/EOSSDK-Win64-Shipping.dll.meta @@ -11,63 +11,17 @@ PluginImporter: isExplicitlyReferenced: 0 validateReferences: 1 platformData: - - first: - : Any - second: - enabled: 0 - settings: - Exclude Editor: 0 - Exclude Linux64: 1 - Exclude OSXUniversal: 1 - Exclude Win: 1 - Exclude Win64: 1 - Exclude iOS: 1 - first: Any: second: - enabled: 0 + enabled: 1 settings: {} - first: Editor: Editor - second: - enabled: 1 - settings: - CPU: x86_64 - DefaultValueInitialized: true - OS: Windows - - first: - Standalone: Linux64 - second: - enabled: 0 - settings: - CPU: None - - first: - Standalone: OSXUniversal - second: - enabled: 0 - settings: - CPU: None - - first: - Standalone: Win - second: - enabled: 0 - settings: - CPU: None - - first: - Standalone: Win64 second: enabled: 0 settings: - CPU: None - - first: - iPhone: iOS - second: - enabled: 0 - settings: - AddToEmbeddedBinaries: false - CPU: AnyCPU - CompileFlags: - FrameworkDependencies: + DefaultValueInitialized: true userData: assetBundleName: assetBundleVariant: diff --git a/Mirror/Runtime/Transport/EpicOnlineTransport/EOSSDK/EOSSDK.framework/EOSSDK.meta b/Mirror/Runtime/Transport/EpicOnlineTransport/EOSSDK/EOSSDK.framework/EOSSDK.meta deleted file mode 100644 index e1b89092..00000000 --- a/Mirror/Runtime/Transport/EpicOnlineTransport/EOSSDK/EOSSDK.framework/EOSSDK.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 03016ec018d7746e196cdd42a5e8e68a -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Mirror/Runtime/Transport/EpicOnlineTransport/EOSSDK/EOSSDK.framework/Info.plist.meta b/Mirror/Runtime/Transport/EpicOnlineTransport/EOSSDK/EOSSDK.framework/Info.plist.meta deleted file mode 100644 index 1d071386..00000000 --- a/Mirror/Runtime/Transport/EpicOnlineTransport/EOSSDK/EOSSDK.framework/Info.plist.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 074430e7c093a4d87acb603bec6ce27e -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: From f66c301ec6639d8eeb27a6f8435d51fe80944547 Mon Sep 17 00:00:00 2001 From: Kevin Yang <68880349+MadkevOP7@users.noreply.github.com> Date: Sat, 1 Jan 2022 09:59:43 -0800 Subject: [PATCH 05/11] iOS Build Support Changes: -EOSSDK.framework couldn't be uploaded as it exceeds 100 MB -iOSPostProcessBuild to automatically disable bitcode --- .../EOSSDK/iOSPostProcessBuild.cs | 30 +++++++++++++++++++ .../EOSSDK/iOSPostProcessBuild.cs.meta | 11 +++++++ 2 files changed, 41 insertions(+) create mode 100644 Mirror/Runtime/Transport/EpicOnlineTransport/EOSSDK/iOSPostProcessBuild.cs create mode 100644 Mirror/Runtime/Transport/EpicOnlineTransport/EOSSDK/iOSPostProcessBuild.cs.meta diff --git a/Mirror/Runtime/Transport/EpicOnlineTransport/EOSSDK/iOSPostProcessBuild.cs b/Mirror/Runtime/Transport/EpicOnlineTransport/EOSSDK/iOSPostProcessBuild.cs new file mode 100644 index 00000000..04051b52 --- /dev/null +++ b/Mirror/Runtime/Transport/EpicOnlineTransport/EOSSDK/iOSPostProcessBuild.cs @@ -0,0 +1,30 @@ +#if UNITY_EDITOR&&UNITY_IOS +using System.Collections.Generic; +using UnityEngine; +using UnityEditor; +using UnityEditor.Callbacks; +using UnityEditor.iOS.Xcode; + + +public static class iOSPostProcessBuild +{ + [PostProcessBuild(1000)] + public static void OnPostProcessBuild(BuildTarget target, string path) + { + if (target == BuildTarget.iOS) + { + string projectPath = PBXProject.GetPBXProjectPath(path); + + PBXProject pbxProject = new PBXProject(); + pbxProject.ReadFromFile(projectPath); + string[] targetGuids = new string[2] { pbxProject.GetUnityMainTargetGuid(), pbxProject.GetUnityFrameworkTargetGuid()}; + foreach(string t in targetGuids) + { + pbxProject.SetBuildProperty(t, "ENABLE_BITCODE", "NO"); + } + + pbxProject.WriteToFile(projectPath); + } + } +} +#endif \ No newline at end of file diff --git a/Mirror/Runtime/Transport/EpicOnlineTransport/EOSSDK/iOSPostProcessBuild.cs.meta b/Mirror/Runtime/Transport/EpicOnlineTransport/EOSSDK/iOSPostProcessBuild.cs.meta new file mode 100644 index 00000000..76023755 --- /dev/null +++ b/Mirror/Runtime/Transport/EpicOnlineTransport/EOSSDK/iOSPostProcessBuild.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9b479edc725f243e7b549169b369e2ec +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: From 316289dbc2fb622c78f92aaa401b330940d1e155 Mon Sep 17 00:00:00 2001 From: Kevin Yang <68880349+MadkevOP7@users.noreply.github.com> Date: Sat, 1 Jan 2022 10:14:10 -0800 Subject: [PATCH 06/11] Update README.md for iOS Build Instruction --- README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.md b/README.md index 442a5549..0b308987 100644 --- a/README.md +++ b/README.md @@ -44,6 +44,15 @@ This is our [Epic Online Services](https://dev.epicgames.com/en-US/services) (EO 2. In Unity -> Edit -> Project Settings... -> Player -> Android -> Other Settings -> Identification set Minimum API Level to Android 6.0 'Marshmallow' (API Level 23) as required by the EOS Android SDK 3. (Optional) Install Android Logcat through Package Manager to see logs when running on Android device over USB (Window -> Package Manager -> Packages: Unity Registry -> Android Logcat -> Install) then open with Alt+6 or Window -> Analysis -> Android Logcat +## Building for iOS +0. Install the iOS Module through Unity Hub +1. Switch platform to iOS in Build Settings +2. In Unity -> Edit -> Project Settings -> Player -> set Target minimum iOS Version to 11.0 as required by the EOS iOS SDK +3. Download EOSSDK.framework from Epic Developer Portal -> SDK -> iOSSDK +4. Extract the .zip file, and navigate to the folder -> SDK -> Bin -> IOS to find EOSSDK.framework (appears as a folder) +5. Copy EOSSDK.framework or move it into the EOSSDK folder (EpicOnlineTransport/EOSSDK) +6. (Optional) In the generated XCode Project, verify bitcode is set to NO on Unity-iPhone and UnityFramework, which should be automatically completed by iOSPostProcessBuild.cs + ## Testing multiplayer on one device Running multiple instances of your game on one device for testing requires you to have multiple epic accounts. Even if your game doesn't use epic accounts you will need them for testing. From d7acf291245babfdef632c1e8d3b013e7ba03324 Mon Sep 17 00:00:00 2001 From: Kevin Yang <68880349+MadkevOP7@users.noreply.github.com> Date: Sat, 1 Jan 2022 10:22:08 -0800 Subject: [PATCH 07/11] README.md update for iOS Build Support --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 0b308987..43cc3b82 100644 --- a/README.md +++ b/README.md @@ -51,7 +51,8 @@ This is our [Epic Online Services](https://dev.epicgames.com/en-US/services) (EO 3. Download EOSSDK.framework from Epic Developer Portal -> SDK -> iOSSDK 4. Extract the .zip file, and navigate to the folder -> SDK -> Bin -> IOS to find EOSSDK.framework (appears as a folder) 5. Copy EOSSDK.framework or move it into the EOSSDK folder (EpicOnlineTransport/EOSSDK) -6. (Optional) In the generated XCode Project, verify bitcode is set to NO on Unity-iPhone and UnityFramework, which should be automatically completed by iOSPostProcessBuild.cs +6. In Unity Editor, select EOSSDK.framework and in Inspector, check Add to Embedded Binaries and Load on startup +7. (Optional) In the generated XCode Project, verify bitcode is set to NO on Unity-iPhone and UnityFramework, which should be automatically completed by iOSPostProcessBuild.cs ## Testing multiplayer on one device Running multiple instances of your game on one device for testing requires you to have multiple epic accounts. From c8d648658a04b179ec7c859a09d65d7f89422cbc Mon Sep 17 00:00:00 2001 From: Kevin Yang <68880349+MadkevOP7@users.noreply.github.com> Date: Mon, 3 Jul 2023 17:28:52 -0700 Subject: [PATCH 08/11] EOS Player Data Storage Support --- .../Player Data Storage/BaseDataManager.cs | 758 ++++++++++++++++++ .../BaseDataManager.cs.meta | 11 + .../EOSTransferInProgress.cs | 32 + .../EOSTransferInProgress.cs.meta | 11 + .../EOS_iOSLoginOptionsHelper.cs | 67 ++ .../EOS_iOSLoginOptionsHelper.cs.meta | 11 + 6 files changed, 890 insertions(+) create mode 100644 Mirror/Runtime/Transport/EpicOnlineTransport/Player Data Storage/BaseDataManager.cs create mode 100644 Mirror/Runtime/Transport/EpicOnlineTransport/Player Data Storage/BaseDataManager.cs.meta create mode 100644 Mirror/Runtime/Transport/EpicOnlineTransport/Player Data Storage/EOSTransferInProgress.cs create mode 100644 Mirror/Runtime/Transport/EpicOnlineTransport/Player Data Storage/EOSTransferInProgress.cs.meta create mode 100644 Mirror/Runtime/Transport/EpicOnlineTransport/Player Data Storage/EOS_iOSLoginOptionsHelper.cs create mode 100644 Mirror/Runtime/Transport/EpicOnlineTransport/Player Data Storage/EOS_iOSLoginOptionsHelper.cs.meta diff --git a/Mirror/Runtime/Transport/EpicOnlineTransport/Player Data Storage/BaseDataManager.cs b/Mirror/Runtime/Transport/EpicOnlineTransport/Player Data Storage/BaseDataManager.cs new file mode 100644 index 00000000..1625db00 --- /dev/null +++ b/Mirror/Runtime/Transport/EpicOnlineTransport/Player Data Storage/BaseDataManager.cs @@ -0,0 +1,758 @@ +using Epic.OnlineServices; +using Epic.OnlineServices.PlayerDataStorage; +using System; +using System.Collections.Generic; +using UnityEngine; +using EpicTransport; +public class BaseDataManager : MonoBehaviour +{ + private static string PLAYERDATA = "PLAYERDATA"; + private static string WORLDDATA = "WORLDDATA"; + private const uint MAX_CHUNK_SIZE = 4096; +#pragma warning disable CS0436 // Type conflicts with imported type + private PlayerDataStorageFileTransferRequest CurrentTransferHandle; +#pragma warning restore CS0436 // Type conflicts with imported type + private Dictionary TransfersInProgress; + private float CurrentTransferProgress; + private string CurrentTransferName; + + private Dictionary StorageData; + + public List FileListUpdateCallbacks; + + public BaseDataManager() + { + TransfersInProgress = new Dictionary(); + StorageData = new Dictionary(); + FileListUpdateCallbacks = new List(); + } + + #region EOS Handling + //------------------------------------------------------------------------- + /// Returns cached Storage Data list. + /// Dictionary(string, string) cached StorageData where FileName is key and FileContent is value. + public Dictionary GetCachedStorageData() + { + return StorageData; + } + + //------------------------------------------------------------------------- + /// (async) Query list of files. + public void QueryFileList() + { +#pragma warning disable CS0436 // Type conflicts with imported type + ProductUserId localUserId = EOSSDKComponent.LocalUserProductId; +#pragma warning restore CS0436 // Type conflicts with imported type + if (localUserId == null || !localUserId.IsValid()) + { + return; + } + + QueryFileListOptions options = new QueryFileListOptions + { + LocalUserId = localUserId + }; + + EOSSDKComponent.GetPlayerDataStorageInterface().QueryFileList(options, null, OnFileListRetrieved); + } + + //------------------------------------------------------------------------- + /// Add listener callback that will be called when the queried file list is updated. + /// Function called when file list is updated. + public void AddNotifyFileListUpdated(Action fileListUpdatedCallback) + { + FileListUpdateCallbacks.Add(fileListUpdatedCallback); + } + + public void RemoveNotifyFileListUpdated(Action fileListUpdatedCallback) + { + FileListUpdateCallbacks.Remove(fileListUpdatedCallback); + } + + //------------------------------------------------------------------------- + /// (async) Begin file data download. + /// Name of file. + /// Function called when download is completed. + public void StartFileDataDownload(string fileName, Action downloadCompletedCallback = null) + { + ProductUserId localUserId = EOSSDKComponent.LocalUserProductId; + if (localUserId == null || !localUserId.IsValid()) + { + return; + } + + ReadFileOptions options = new ReadFileOptions + { + LocalUserId = localUserId, + Filename = fileName, + ReadChunkLengthBytes = MAX_CHUNK_SIZE, + ReadFileDataCallback = OnFileDataReceived, + FileTransferProgressCallback = OnFileTransferProgressUpdated + }; + + var queryFileOptions = new QueryFileOptions { Filename = fileName, LocalUserId = localUserId }; + EOSSDKComponent.GetPlayerDataStorageInterface().QueryFile(queryFileOptions, null, (QueryFileCallbackInfo data) => + { + if (data.ResultCode == Result.Success) + { + + var copyFileMetadataOptions = new CopyFileMetadataByFilenameOptions { Filename = fileName, LocalUserId = localUserId }; + EOSSDKComponent.GetPlayerDataStorageInterface().CopyFileMetadataByFilename(copyFileMetadataOptions, out FileMetadata? fileMetadata); + + PlayerDataStorageFileTransferRequest req = EOSSDKComponent.GetPlayerDataStorageInterface().ReadFile( options, downloadCompletedCallback, OnFileReceived); + if (req == null) + { + Debug.LogErrorFormat("[EOS SDK] Player data storage: can't start file download, bad handle returned for filename '{0}'", fileName); + return; + } + + CancelCurrentTransfer(); + CurrentTransferHandle = req; + + EOSTransferInProgress newTransfer = new EOSTransferInProgress() + { + Download = true, + Data = new byte[(uint)fileMetadata?.FileSizeBytes], + }; + + TransfersInProgress[fileName] = newTransfer; + + CurrentTransferProgress = 0.0f; + CurrentTransferName = fileName; + } + else + { + Debug.LogErrorFormat("[EOS SDK] Player data storage: can't start file download, unable to query file info {0}", fileName); + } + }); + } + + //------------------------------------------------------------------------- + /// (async) Begin file data upload. + /// Name of file. + /// True if upload started + public bool StartFileDataUpload(string fileName, Action fileCreatedCallback = null) + { + ProductUserId localUserId = EOSSDKComponent.LocalUserProductId; + if (localUserId == null || !localUserId.IsValid()) + { + return false; + } + + string fileData = null; + if (StorageData.TryGetValue(fileName, out string entry)) + { + fileData = entry; + } + + WriteFileOptions options = new WriteFileOptions() + { + LocalUserId = localUserId, + Filename = fileName, + ChunkLengthBytes = MAX_CHUNK_SIZE, + //WriteFileDataCallback = OnFileDataSend, + FileTransferProgressCallback = OnFileTransferProgressUpdated + }; + + PlayerDataStorageFileTransferRequest req = EOSSDKComponent.GetPlayerDataStorageInterface().WriteFile(options, fileCreatedCallback, OnFileSent); + if (req == null) + { + Debug.LogErrorFormat("[EOS SDK] Player data storage: can't start file download, bad handle returned for filename '{0}'", fileName); + return false; + } + + CancelCurrentTransfer(); + CurrentTransferHandle = req; + + EOSTransferInProgress newTransfer = new EOSTransferInProgress(); + newTransfer.Download = false; + + newTransfer.TotalSize = (uint)fileData.Length; + if (newTransfer.TotalSize > 0) + { + byte[] utf8ByteArray = System.Text.Encoding.UTF8.GetBytes(fileData); + + newTransfer.Data = utf8ByteArray; + } + newTransfer.CurrentIndex = 0; + + TransfersInProgress[fileName] = newTransfer; + + CurrentTransferProgress = 0.0f; + CurrentTransferName = fileName; + + return true; + } + + //------------------------------------------------------------------------- + /// Get cached file list. + /// List fileList + public List GetCachedFileList() + { + List fileList = null; + + if (StorageData.Count > 0) + { + fileList = new List(StorageData.Keys); + } + + return fileList; + } + + //------------------------------------------------------------------------- + private void SetFileList(List fileNames) + { + foreach (string fileName in fileNames) + { + if (!StorageData.TryGetValue(fileName, out string fileData)) + { + // New file, no cache data + StorageData.Add(fileName, null); + } + } + + // Remove files no longer in cloud + List toRemove = new List(); + + foreach (string localFileName in StorageData.Keys) + { + if (!fileNames.Contains(localFileName)) + { + toRemove.Add(localFileName); + } + } + + foreach (string removerFile in toRemove) + { + StorageData.Remove(removerFile); + } + } + + //------------------------------------------------------------------------- + /// (async) Begin file data upload. + /// Name of file. + /// File content. + /// Function called when file creation and upload is completed. + public void AddFile(string fileName, string fileContent, Action fileCreatedCallback = null) + { + SetLocalData(fileName, fileContent); + + if (!StartFileDataUpload(fileName, fileCreatedCallback)) + { + EraseLocalData(fileName); + } + } + + //------------------------------------------------------------------------- + /// (async) Begin file data copy. + /// Name of source file in EOS backend. + /// Name of target file to copy to. + public void CopyFile(string sourceFileName, string destinationFileName) + { + ProductUserId localUserId = EOSSDKComponent.LocalUserProductId; + if (localUserId == null || !localUserId.IsValid()) + { + return; + } + + DuplicateFileOptions options = new DuplicateFileOptions() + { + LocalUserId = localUserId, + SourceFilename = sourceFileName, + DestinationFilename = destinationFileName + }; + + EOSSDKComponent.GetPlayerDataStorageInterface().DuplicateFile(options, null, OnFileCopied); + } + + //------------------------------------------------------------------------- + /// (async) Begin file delete. + /// Name of source file to delete. + public void DeleteFile(string fileName) + { + ProductUserId localUserId = EOSSDKComponent.LocalUserProductId; + if (localUserId == null || !localUserId.IsValid()) + { + return; + } + + EraseLocalData(fileName); + + DeleteFileOptions options = new DeleteFileOptions() + { + LocalUserId = localUserId, + Filename = fileName + }; + + EOSSDKComponent.GetPlayerDataStorageInterface().DeleteFile(options, null, OnFileRemoved); + } + + //------------------------------------------------------------------------- + /// Get cached file content for specified file name. + /// Name of file. + /// File content + public string GetCachedFileContent(string fileName) + { + StorageData.TryGetValue(fileName, out string data); + + return data; + } + + private void SetLocalData(string fileName, string data) + { + if (StorageData.ContainsKey(fileName)) + { + StorageData[fileName] = data; + } + else + { + StorageData.Add(fileName, data); + } + } + + private bool EraseLocalData(string entryName) + { + return StorageData.Remove(entryName); + } + + private void CancelCurrentTransfer() + { + if (CurrentTransferHandle != null) + { + Result result = CurrentTransferHandle.CancelRequest(); + CurrentTransferHandle.Release(); + CurrentTransferHandle = null; + + if (result == Result.Success) + { + if (TransfersInProgress.TryGetValue(CurrentTransferName, out EOSTransferInProgress transfer)) + { + TransfersInProgress.Remove(CurrentTransferName); + } + } + } + + ClearCurrentTransfer(); + } + + private ReadResult ReceiveData(string fileName, ArraySegment data, uint totalSize, bool isLastChunk) + { + if (data == null) + { + Debug.LogError("[EOS SDK] Player data storage: could not receive data: Data pointer is null."); + return ReadResult.FailRequest; + } + + if (TransfersInProgress.TryGetValue(fileName, out EOSTransferInProgress transfer)) + { + if (!transfer.Download) + { + Debug.LogError("[EOS SDK] Player data storage: can't load file data: download/upload mismatch."); + return ReadResult.FailRequest; + } + + // First update + if (transfer.CurrentIndex == 0 && transfer.TotalSize == 0) + { + transfer.TotalSize = totalSize; + + if (transfer.TotalSize == 0) + { + return ReadResult.ContinueReading; + } + } + + if (isLastChunk)//transfer.TotalSize - transfer.CurrentIndex >= numBytes) + { + data.Array.CopyTo(transfer.Data, transfer.CurrentIndex); + + transfer.CurrentIndex = transfer.TotalSize; // Done + + return ReadResult.ContinueReading; + } + else + { + Debug.LogError("[EOS SDK] Player data storage: could not receive data: too much of it."); + return ReadResult.FailRequest; + } + } + + return ReadResult.CancelRequest; + } + + //------------------------------------------------------------------------- + private WriteResult SendData(string fileName, out ArraySegment data) + { + data = new ArraySegment(); + + if (TransfersInProgress.TryGetValue(fileName, out EOSTransferInProgress transfer)) + { + if (transfer.Download) + { + Debug.LogError("[EOS SDK] Player data storage: can't send file data: download/upload mismatch."); + return WriteResult.FailRequest; + } + + if (transfer.Done()) + { + return WriteResult.CompleteRequest; + } + + uint bytesToWrite = Math.Min(MAX_CHUNK_SIZE, transfer.TotalSize - transfer.CurrentIndex); + + if (bytesToWrite > 0) + { + data = new ArraySegment(transfer.Data, (int)transfer.CurrentIndex, (int)bytesToWrite); + } + + transfer.CurrentIndex += bytesToWrite; + + if (transfer.Done()) + { + return WriteResult.CompleteRequest; + } + else + { + return WriteResult.ContinueWriting; + } + } + else + { + Debug.LogError("[EOS SDK] Player data storage: could not send data as this file is not being uploaded at the moment."); + return WriteResult.CancelRequest; + } + } + + private void UpdateProgress(string fileName, float progress) + { + if (fileName.Equals(CurrentTransferName, StringComparison.OrdinalIgnoreCase)) + { + CurrentTransferProgress = progress; + } + } + + private void FinishFileDownload(string fileName, bool success) + { + if (TransfersInProgress.TryGetValue(fileName, out EOSTransferInProgress transfer)) + { + if (!transfer.Download) + { + Debug.LogError("[EOS SDK] Player data storage: error while file read operation: can't finish because of download/upload mismatch."); + return; + } + + if (!transfer.Done() || !success) + { + if (!transfer.Done()) + { + Debug.LogError("[EOS SDK] Player data storage: error while file read operation: expecting more data. File can be corrupted."); + } + TransfersInProgress.Remove(fileName); + if (fileName.Equals(CurrentTransferName, StringComparison.OrdinalIgnoreCase)) + { + ClearCurrentTransfer(); + } + return; + } + + // Files larger than 5 MB + string fileData = null; + if (transfer.TotalSize > 5 * 1024 * 1024) + { + fileData = "*** File is too large to be viewed in this sample. ***"; + } + else if (transfer.TotalSize > 0) + { + fileData = System.Text.Encoding.UTF8.GetString(transfer.Data); + } + else + { + fileData = string.Empty; + } + + // TODO check for binary data and don't display + + StorageData[fileName] = fileData; + + int fileSize = 0; + if (fileData != null) + { + fileSize = fileData.Length; + } + + Debug.LogFormat("[EOS SDK] Player data storage: file read finished: '{0}' Size: {1}.", fileName, fileSize); + + TransfersInProgress.Remove(fileName); + + if (fileName.Equals(CurrentTransferName, StringComparison.OrdinalIgnoreCase)) + { + ClearCurrentTransfer(); + } + } + } + + private void FinishFileUpload(string fileName, Action fileUploadCallback = null) + { + if (TransfersInProgress.TryGetValue(fileName, out EOSTransferInProgress transfer)) + { + if (transfer.Download) + { + Debug.LogError("[EOS SDK] Player data storage: error while file write operation: can't finish because of download/upload mismatch."); + return; + } + + if (!transfer.Done()) + { + Debug.LogError("[EOS SDK] Player data storage: error while file write operation: unexpected end of transfer."); + } + + TransfersInProgress.Remove(fileName); + + if (fileName.Equals(CurrentTransferName, StringComparison.OrdinalIgnoreCase)) + { + ClearCurrentTransfer(); + } + + fileUploadCallback?.Invoke(); + } + } + + /// User Logged In actions + /// + /// QueryFileList() + /// + public void OnLoggedIn() + { + QueryFileList(); + } + + /// User Logged Out actions + /// + /// Clear Cache and Current Transfer + /// + public void OnLoggedOut() + { + StorageData.Clear(); + ClearCurrentTransfer(); + } + + private void ClearCurrentTransfer() + { + CurrentTransferName = string.Empty; + CurrentTransferProgress = 0.0f; + + if (CurrentTransferHandle != null) + { + CurrentTransferHandle.Release(); + CurrentTransferHandle = null; + } + } + + //------------------------------------------------------------------------- + private void OnFileListRetrieved(QueryFileListCallbackInfo data) + { + if (data.ResultCode != Result.Success && data.ResultCode != Result.NotFound) + { + Debug.LogErrorFormat("[EOS SDK] Player data storage: file list retrieval error: {0}", data.ResultCode); + return; + } + + ProductUserId localUserId = EOSSDKComponent.LocalUserProductId; + if (localUserId == null || !localUserId.IsValid()) + { + return; + } + + Debug.Log("[EOS SDK] Player data storage file list is successfully retrieved."); + + uint fileCount = data.FileCount; + + PlayerDataStorageInterface playerStorageHandle = EOSSDKComponent.GetPlayerDataStorageInterface(); + List fileNames = new List(); + + for (uint fileIndex = 0; fileIndex < data.FileCount; fileIndex++) + { + CopyFileMetadataAtIndexOptions options = new CopyFileMetadataAtIndexOptions() + { + LocalUserId = localUserId, + Index = fileIndex + }; + + Result result = playerStorageHandle.CopyFileMetadataAtIndex(options, out FileMetadata? fileMetadata); + + if (result != Result.Success) + { + Debug.LogErrorFormat("Player Data Storage (OnFileListRetrieved): CopyFileMetadataAtIndex returned error result = {0}", result); + return; + } + else if (fileMetadata != null) + { + if (!string.IsNullOrEmpty(fileMetadata?.Filename)) + { + fileNames.Add(fileMetadata?.Filename); + } + } + } + + SetFileList(fileNames); + foreach (var callback in FileListUpdateCallbacks) + { + callback?.Invoke(); + } + } + + //------------------------------------------------------------------------- + private ReadResult OnFileDataReceived( ReadFileDataCallbackInfo data) + { + //if (data == null) + //{ + // Debug.LogError("Player Data Storage (OnFileDataReceived): data parameter is null!"); + // return ReadResult.FailRequest; + //} + + return ReceiveData(data.Filename, data.DataChunk, data.TotalFileSizeBytes, data.IsLastChunk); + } + + //------------------------------------------------------------------------- + private void OnFileReceived( ReadFileCallbackInfo data) + { + var callback = data.ClientData as Action; + //if (data == null) + //{ + // Debug.LogError("Player Data Storage (OnFileReceived): data parameter is null!"); + // FinishFileDownload(data.Filename, false); + // return; + //} + + if (data.ResultCode != Result.Success) + { + Debug.LogErrorFormat("[EOS SDK] Player data storage: could not download file: {0}", data.ResultCode); + FinishFileDownload(data.Filename, false); + } + + FinishFileDownload(data.Filename, true); + + callback?.Invoke(); + } + + private WriteResult OnFileDataSend(WriteFileDataCallbackInfo data, out ArraySegment outDataBuffer) + { + //if (data == null) + //{ + // Debug.LogError("Player Data Storage (OnFileDataSend): data parameter is null!"); + // outDataBuffer = new byte[0]; + // return WriteResult.FailRequest; + //} + + WriteResult result = SendData(data.Filename, out ArraySegment dataBuffer); + + if (dataBuffer != null) + { + outDataBuffer = dataBuffer; + } + else + { + outDataBuffer = new ArraySegment(); + } + + return result; + } + + private void OnFileSent(WriteFileCallbackInfo data) + { + var callback = data.ClientData as Action; + //if (data == null) + //{ + // Debug.LogError("Player Data Storage (OnFileSent): data parameter is null!"); + // return; + //} + + if (data.ResultCode != Result.Success) + { + Debug.LogErrorFormat("[EOS SDK] Player data storage: could not upload file: {0}", data.ResultCode); + FinishFileUpload(data.Filename, callback); + return; + } + + FinishFileUpload(data.Filename, callback); + } + + private void OnFileTransferProgressUpdated(FileTransferProgressCallbackInfo data) + { + //if (data == null) + //{ + // Debug.LogError("Player Data Storage (OnFileTransferProgressUpdated): data parameter is null!"); + // return; + //} + + if (data.TotalFileSizeBytes > 0) + { + UpdateProgress(data.Filename, data.BytesTransferred / data.TotalFileSizeBytes); + Debug.LogFormat("[EOS SDK] Player data storage: transfer progress {0} / {1}", data.BytesTransferred, data.TotalFileSizeBytes); + } + } + + private void OnFileCopied(DuplicateFileCallbackInfo data) + { + //if (data == null) + //{ + // Debug.LogError("Player Data Storage (OnFileCopied): data parameter is null!"); + // return; + //} + + if (data.ResultCode != Result.Success) + { + Debug.LogErrorFormat("[EOS SDK] Player data storage: error while copying the file: {0}", data.ResultCode); + return; + } + + QueryFileList(); + } + + private void OnFileRemoved(DeleteFileCallbackInfo data) + { + //if (data == null) + //{ + // Debug.LogError("Player Data Storage (OnFileRemoved): data parameter is null!"); + // return; + //} + + if (data.ResultCode != Result.Success) + { + Debug.LogErrorFormat("[EOS SDK] Player data storage: error while removing file: {0}", data.ResultCode); + return; + } + + QueryFileList(); + } + #endregion + + #region Core Unity + private void UpdateRemoteView(string fileName) + { + string fileContent = GetCachedFileContent(fileName); + + if (fileContent == null) + { + Debug.Log("Downloading: " + fileName); + StartFileDataDownload(fileName, () => UpdateRemoteView(fileName)); + } + else if (fileContent.Length == 0) + { + Debug.Log("File: " + fileName + " is empty"); + } + else + { + Debug.Log("Downloaded: " + fileName); + } + } + public void RefreshD() + { + GetCachedStorageData().Clear(); + QueryFileList(); + + StartFileDataDownload(PLAYERDATA, () => UpdateRemoteView(PLAYERDATA)); + StartFileDataDownload(WORLDDATA, () => UpdateRemoteView(WORLDDATA)); + } + #endregion +} \ No newline at end of file diff --git a/Mirror/Runtime/Transport/EpicOnlineTransport/Player Data Storage/BaseDataManager.cs.meta b/Mirror/Runtime/Transport/EpicOnlineTransport/Player Data Storage/BaseDataManager.cs.meta new file mode 100644 index 00000000..2c3a4042 --- /dev/null +++ b/Mirror/Runtime/Transport/EpicOnlineTransport/Player Data Storage/BaseDataManager.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7f40e6d304e04494e817855fb0e419c8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Mirror/Runtime/Transport/EpicOnlineTransport/Player Data Storage/EOSTransferInProgress.cs b/Mirror/Runtime/Transport/EpicOnlineTransport/Player Data Storage/EOSTransferInProgress.cs new file mode 100644 index 00000000..2a5bccfc --- /dev/null +++ b/Mirror/Runtime/Transport/EpicOnlineTransport/Player Data Storage/EOSTransferInProgress.cs @@ -0,0 +1,32 @@ +using UnityEngine; +using Epic.OnlineServices.PlayerDataStorage; +public class EOSTransferInProgress : MonoBehaviour +{ + public bool Download = true; + public uint CurrentIndex = 0; + public byte[] Data; + private uint transferSize = 0; + + public uint TotalSize + { + get + { + return transferSize; + } + set + { + transferSize = value; + + if (transferSize > PlayerDataStorageInterface.FileMaxSizeBytes) + { + Debug.LogError("[EOS SDK] Player data storage: data transfer size exceeds max file size."); + transferSize = PlayerDataStorageInterface.FileMaxSizeBytes; + } + } + } + + public bool Done() + { + return TotalSize == CurrentIndex; + } +} diff --git a/Mirror/Runtime/Transport/EpicOnlineTransport/Player Data Storage/EOSTransferInProgress.cs.meta b/Mirror/Runtime/Transport/EpicOnlineTransport/Player Data Storage/EOSTransferInProgress.cs.meta new file mode 100644 index 00000000..24a25a28 --- /dev/null +++ b/Mirror/Runtime/Transport/EpicOnlineTransport/Player Data Storage/EOSTransferInProgress.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9ccae13c552664f1eb8ecd03ecefea77 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Mirror/Runtime/Transport/EpicOnlineTransport/Player Data Storage/EOS_iOSLoginOptionsHelper.cs b/Mirror/Runtime/Transport/EpicOnlineTransport/Player Data Storage/EOS_iOSLoginOptionsHelper.cs new file mode 100644 index 00000000..75b9140d --- /dev/null +++ b/Mirror/Runtime/Transport/EpicOnlineTransport/Player Data Storage/EOS_iOSLoginOptionsHelper.cs @@ -0,0 +1,67 @@ +/* +* Copyright (c) 2023 PlayEveryWare +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + + +#if !EOS_DISABLE +using System; +using System.Runtime.InteropServices; + +#if UNITY_IOS && !UNITY_EDITOR +public static class EOS_iOSLoginOptionsHelper +{ + //------------------------------------------------------------------------- + /// + /// Create App Controller necessary for iOS login options + /// + [DllImport("__Internal")] + static private extern IntPtr LoginUtility_get_app_controller(); + + //------------------------------------------------------------------------- + /// + /// Make Login Options for iOS Specific + /// + + public static Epic.OnlineServices.Auth.IOSLoginOptions MakeIOSLoginOptionsFromDefualt(Epic.OnlineServices.Auth.LoginOptions loginOptions) + { + Epic.OnlineServices.Auth.IOSLoginOptions modifiedLoginOptions = new Epic.OnlineServices.Auth.IOSLoginOptions(); + modifiedLoginOptions.ScopeFlags = loginOptions.ScopeFlags; + + var credentials = new Epic.OnlineServices.Auth.IOSCredentials(); + + credentials.Token = loginOptions.Credentials.Token; + credentials.Id = loginOptions.Credentials.Id; + credentials.Type = loginOptions.Credentials.Type; + credentials.ExternalType = loginOptions.Credentials.ExternalType; + + var systemAuthCredentialsOptions = new Epic.OnlineServices.Auth.IOSCredentialsSystemAuthCredentialsOptions(); + + systemAuthCredentialsOptions.PresentationContextProviding = LoginUtility_get_app_controller(); + credentials.SystemAuthCredentialsOptions = systemAuthCredentialsOptions; + + modifiedLoginOptions.Credentials = credentials; + + return modifiedLoginOptions; + } + +} +#endif +#endif \ No newline at end of file diff --git a/Mirror/Runtime/Transport/EpicOnlineTransport/Player Data Storage/EOS_iOSLoginOptionsHelper.cs.meta b/Mirror/Runtime/Transport/EpicOnlineTransport/Player Data Storage/EOS_iOSLoginOptionsHelper.cs.meta new file mode 100644 index 00000000..e350b187 --- /dev/null +++ b/Mirror/Runtime/Transport/EpicOnlineTransport/Player Data Storage/EOS_iOSLoginOptionsHelper.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 55f0507e3d69b46a99ea023175d01333 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: From a425c14a9fee221ffbecadf0c434917011314f27 Mon Sep 17 00:00:00 2001 From: Kevin Yang <68880349+MadkevOP7@users.noreply.github.com> Date: Mon, 3 Jul 2023 17:29:34 -0700 Subject: [PATCH 09/11] iOS Auth interface support --- .../iOS/DynamicLibraryLoaderHelper_iOS.cpp | 81 +++++++++++++++++++ .../DynamicLibraryLoaderHelper_iOS.cpp.meta | 80 ++++++++++++++++++ Plugins/iOS/LoginUtility.mm | 56 +++++++++++++ Plugins/iOS/LoginUtility.mm.meta | 80 ++++++++++++++++++ Plugins/iOS/Memory_iOS.cpp | 57 +++++++++++++ Plugins/iOS/Memory_iOS.cpp.meta | 33 ++++++++ Plugins/iOS/MicrophoneUtility_iOS.mm | 30 +++++++ Plugins/iOS/MicrophoneUtility_iOS.mm.meta | 73 +++++++++++++++++ 8 files changed, 490 insertions(+) create mode 100644 Plugins/iOS/DynamicLibraryLoaderHelper_iOS.cpp create mode 100644 Plugins/iOS/DynamicLibraryLoaderHelper_iOS.cpp.meta create mode 100644 Plugins/iOS/LoginUtility.mm create mode 100644 Plugins/iOS/LoginUtility.mm.meta create mode 100644 Plugins/iOS/Memory_iOS.cpp create mode 100644 Plugins/iOS/Memory_iOS.cpp.meta create mode 100644 Plugins/iOS/MicrophoneUtility_iOS.mm create mode 100644 Plugins/iOS/MicrophoneUtility_iOS.mm.meta diff --git a/Plugins/iOS/DynamicLibraryLoaderHelper_iOS.cpp b/Plugins/iOS/DynamicLibraryLoaderHelper_iOS.cpp new file mode 100644 index 00000000..1144900f --- /dev/null +++ b/Plugins/iOS/DynamicLibraryLoaderHelper_iOS.cpp @@ -0,0 +1,81 @@ +// DynamicLibraryLoaderHelper.cpp : Defines the functions for the static library. +// + +#include +#include + +#define STATIC_EXPORT(return_type) extern "C" return_type + +struct DLLHContext +{ +}; + +void* DLLH_iOS_load_library_at_path(DLLHContext *ctx, const char *library_path); +void* DLLH_iOS_load_function_with_name(DLLHContext *ctx, void *library_handle, const char *function); + +//------------------------------------------------------------------------- +// Create heap data for storing random things, if need be on a given platform +STATIC_EXPORT(void*) DLLH_create_context() +{ + return new DLLHContext(); +} + +//------------------------------------------------------------------------- +STATIC_EXPORT(void) DLLH_destroy_context(void *context) +{ + delete static_cast(context); +} + +//------------------------------------------------------------------------- +STATIC_EXPORT(void *) DLLH_load_library_at_path(void *ctx, const char *library_path) +{ + if (ctx == nullptr) { + return nullptr; + } + + DLLHContext *dllh_ctx = static_cast(ctx); + void *to_return = nullptr; + + to_return = DLLH_iOS_load_library_at_path(dllh_ctx, library_path); + + return to_return; +} + +//------------------------------------------------------------------------- +// This returns a bare function pointer that is only valid as long as the library_handle and context are +// valid +STATIC_EXPORT(void*) DLLH_load_function_with_name(void *ctx, void *library_handle, const char *function) +{ + void *to_return = nullptr; + DLLHContext *dllh_ctx = static_cast(ctx); + + to_return = DLLH_iOS_load_function_with_name(dllh_ctx, library_handle, function); + + return to_return; +} + +//------------------------------------------------------------------------- +void * DLLH_iOS_load_library_at_path(DLLHContext *ctx, const char *library_path) +{ + void *to_return = dlopen(library_path, RTLD_NOW); + + return to_return; +} + +//------------------------------------------------------------------------- +// TODO: Handle the actual module instead of all symbols +void * DLLH_iOS_load_function_with_name(DLLHContext *ctx, void *library_handle, const char *function) +{ + void *output_ptr = nullptr; + + output_ptr = dlsym(library_handle, function); + + return output_ptr; +} + +//------------------------------------------------------------------------- +// TODO: unload the library correct? I don't know if that's actually a good +// idea on macos or not +STATIC_EXPORT(void) DLLH_unload_library_at_path(const char *library_path) +{ +} diff --git a/Plugins/iOS/DynamicLibraryLoaderHelper_iOS.cpp.meta b/Plugins/iOS/DynamicLibraryLoaderHelper_iOS.cpp.meta new file mode 100644 index 00000000..c4f9b962 --- /dev/null +++ b/Plugins/iOS/DynamicLibraryLoaderHelper_iOS.cpp.meta @@ -0,0 +1,80 @@ +fileFormatVersion: 2 +guid: cb8ed33fc202c4600b4c29bc1e2834a3 +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + : Any + second: + enabled: 0 + settings: + Exclude Android: 1 + Exclude Editor: 1 + Exclude Linux64: 1 + Exclude OSXUniversal: 1 + Exclude Win: 1 + Exclude Win64: 1 + Exclude iOS: 0 + - first: + Android: Android + second: + enabled: 0 + settings: + CPU: ARMv7 + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + CPU: AnyCPU + DefaultValueInitialized: true + OS: AnyOS + - first: + Standalone: Linux64 + second: + enabled: 0 + settings: + CPU: AnyCPU + - first: + Standalone: OSXUniversal + second: + enabled: 0 + settings: + CPU: x86_64 + - first: + Standalone: Win + second: + enabled: 0 + settings: + CPU: x86 + - first: + Standalone: Win64 + second: + enabled: 0 + settings: + CPU: x86_64 + - first: + iPhone: iOS + second: + enabled: 1 + settings: + AddToEmbeddedBinaries: false + CPU: AnyCPU + CompileFlags: + FrameworkDependencies: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Plugins/iOS/LoginUtility.mm b/Plugins/iOS/LoginUtility.mm new file mode 100644 index 00000000..7ea1cf5a --- /dev/null +++ b/Plugins/iOS/LoginUtility.mm @@ -0,0 +1,56 @@ +#import +#import + +#define kUnityFrameworkPath @"/Frameworks/UnityFramework.framework" + +@interface UnityAppController(EOS) +@end + +@implementation UnityAppController(EOS) + +extern "C" +{ + UnityFramework* GetUnityFramework() + { + NSString* bundlePath = [[NSBundle mainBundle] bundlePath]; + bundlePath = [bundlePath stringByAppendingString:kUnityFrameworkPath]; + + NSBundle* bundle = [NSBundle bundleWithPath: bundlePath]; + if ([bundle isLoaded] == false) + { + [bundle load]; + } + + return [bundle.principalClass getInstance]; + } + + //void* should be casted from a UnityAppController* + void* LoginUtility_get_app_controller() + { + if (@available(iOS 13.0, *)) + { + UnityFramework* unityFramework = GetUnityFramework(); + + UnityAppController* unityAppController = [unityFramework appController]; + if (unityAppController != nil) + { + return (void*)CFBridgingRetain(unityAppController); + } + } + return nil; + } + +} + +- (ASPresentationAnchor)presentationAnchorForAuthorizationController:(ASAuthorizationController *)controller +API_AVAILABLE(ios(13.0)){ + return self.window; +} + +- (ASPresentationAnchor)presentationAnchorForWebAuthenticationSession:(ASWebAuthenticationSession *)session +API_AVAILABLE(ios(12.0)){ + return self.window; +} + + +@end diff --git a/Plugins/iOS/LoginUtility.mm.meta b/Plugins/iOS/LoginUtility.mm.meta new file mode 100644 index 00000000..16e27437 --- /dev/null +++ b/Plugins/iOS/LoginUtility.mm.meta @@ -0,0 +1,80 @@ +fileFormatVersion: 2 +guid: e8d0d0214710d4035a87df403dfc4852 +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 1 + isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + : Any + second: + enabled: 0 + settings: + Exclude Android: 1 + Exclude Editor: 1 + Exclude Linux64: 1 + Exclude OSXUniversal: 1 + Exclude Win: 1 + Exclude Win64: 1 + Exclude iOS: 0 + - first: + Android: Android + second: + enabled: 0 + settings: + CPU: ARMv7 + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + CPU: AnyCPU + DefaultValueInitialized: true + OS: AnyOS + - first: + Standalone: Linux64 + second: + enabled: 0 + settings: + CPU: AnyCPU + - first: + Standalone: OSXUniversal + second: + enabled: 0 + settings: + CPU: x86_64 + - first: + Standalone: Win + second: + enabled: 0 + settings: + CPU: x86 + - first: + Standalone: Win64 + second: + enabled: 0 + settings: + CPU: x86_64 + - first: + iPhone: iOS + second: + enabled: 1 + settings: + AddToEmbeddedBinaries: false + CPU: AnyCPU + CompileFlags: + FrameworkDependencies: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Plugins/iOS/Memory_iOS.cpp b/Plugins/iOS/Memory_iOS.cpp new file mode 100644 index 00000000..8cc14914 --- /dev/null +++ b/Plugins/iOS/Memory_iOS.cpp @@ -0,0 +1,57 @@ +#include + +#define STATIC_EXPORT(return_type) extern "C" return_type + +//------------------------------------------------------------------------- +// Wrapper around the standard aligned_alloc that asserts on error cases. +// Useful for debugging memory issues. +STATIC_EXPORT(void *) Mem_generic_align_alloc(size_t size_in_bytes, size_t alignment_in_bytes) +{ + //TODO: replace with posix version so we can support lower iOS versions + void *to_return = aligned_alloc(alignment_in_bytes, size_in_bytes); + + return to_return; +} + +//------------------------------------------------------------------------- +// Wrapper around the standard c function for reallocating memory. +// Has asserts to ensure that memory allocation is working. +// Handles case where size_in_bytes is 0 in the EOS, which isn't handled by the ios version of +// realloc +STATIC_EXPORT(void *) Mem_generic_align_realloc(void *ptr, size_t size_in_bytes, size_t alignment_in_bytes) +{ + // Some objects in EOS try to realloc with a zero sized increase in bytes + if (size_in_bytes == 0) { + return ptr; + } + + if (ptr == nullptr) { + return Mem_generic_align_alloc(size_in_bytes, alignment_in_bytes); + } + + void *to_return = realloc(ptr, size_in_bytes); + return to_return; +} + +//------------------------------------------------------------------------- +// Wrapper around free for EOS. One could just use free() and pass that in, +// but for completeness it's included here +STATIC_EXPORT(void) Mem_generic_free(void *ptr) +{ + free(ptr); +} + +//------------------------------------------------------------------------- +// wrapper around malloc, Originally written for ios SDK, but could be used +// elsewhere. +STATIC_EXPORT(void *) Mem_generic_allocator(size_t size) +{ + return malloc(size); +} + +//------------------------------------------------------------------------- +// The matching wrapper function for generic_allocator +STATIC_EXPORT(void) Mem_generic_deallocate(void* to_deallocate, size_t size) +{ + free(to_deallocate); +} diff --git a/Plugins/iOS/Memory_iOS.cpp.meta b/Plugins/iOS/Memory_iOS.cpp.meta new file mode 100644 index 00000000..3126748b --- /dev/null +++ b/Plugins/iOS/Memory_iOS.cpp.meta @@ -0,0 +1,33 @@ +fileFormatVersion: 2 +guid: ec7d38b5bab3e4c498fd494f3a9a5056 +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + - first: + iPhone: iOS + second: + enabled: 1 + settings: + AddToEmbeddedBinaries: false + userData: + assetBundleName: + assetBundleVariant: diff --git a/Plugins/iOS/MicrophoneUtility_iOS.mm b/Plugins/iOS/MicrophoneUtility_iOS.mm new file mode 100644 index 00000000..35ce522b --- /dev/null +++ b/Plugins/iOS/MicrophoneUtility_iOS.mm @@ -0,0 +1,30 @@ +#import +#import + +extern "C" void MicrophoneUtility_set_default_audio_session() +{ + AVAudioSession *session = AVAudioSession.sharedInstance; + NSError *error = nil; + [session setCategory:AVAudioSessionCategoryPlayAndRecord + mode:AVAudioSessionModeVoiceChat + options:AVAudioSessionCategoryOptionDefaultToSpeaker|AVAudioSessionCategoryOptionDuckOthers + error:&error]; + if (nil == error) + { + // continue here + } +} + +extern "C" bool MicrophoneUtility_get_mic_permission() +{ + AVAudioSession *session = AVAudioSession.sharedInstance; + switch ([session recordPermission]) + { + case AVAudioSessionRecordPermissionGranted: + return true; + default: + return false; + } +} + + diff --git a/Plugins/iOS/MicrophoneUtility_iOS.mm.meta b/Plugins/iOS/MicrophoneUtility_iOS.mm.meta new file mode 100644 index 00000000..e53e74ad --- /dev/null +++ b/Plugins/iOS/MicrophoneUtility_iOS.mm.meta @@ -0,0 +1,73 @@ +fileFormatVersion: 2 +guid: 2a7564f4e0bf04e83846e05c5341ca36 +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 1 + isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + : Any + second: + enabled: 0 + settings: + Exclude Editor: 1 + Exclude Linux64: 1 + Exclude OSXUniversal: 1 + Exclude Win: 1 + Exclude Win64: 1 + Exclude iOS: 0 + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + CPU: AnyCPU + DefaultValueInitialized: true + OS: AnyOS + - first: + Standalone: Linux64 + second: + enabled: 0 + settings: + CPU: AnyCPU + - first: + Standalone: OSXUniversal + second: + enabled: 0 + settings: + CPU: x86_64 + - first: + Standalone: Win + second: + enabled: 0 + settings: + CPU: x86 + - first: + Standalone: Win64 + second: + enabled: 0 + settings: + CPU: x86_64 + - first: + iPhone: iOS + second: + enabled: 1 + settings: + AddToEmbeddedBinaries: false + CPU: AnyCPU + CompileFlags: + FrameworkDependencies: + userData: + assetBundleName: + assetBundleVariant: From 35481a495a528b1efcd92ceca5f4d40496eaa24d Mon Sep 17 00:00:00 2001 From: Kevin Yang <68880349+MadkevOP7@users.noreply.github.com> Date: Mon, 3 Jul 2023 17:32:43 -0700 Subject: [PATCH 10/11] iOS auth support EOSSDKComponent.cs --- .../EpicOnlineTransport/EOSSDKComponent.cs | 258 ++++++++++++------ 1 file changed, 167 insertions(+), 91 deletions(-) diff --git a/Mirror/Runtime/Transport/EpicOnlineTransport/EOSSDKComponent.cs b/Mirror/Runtime/Transport/EpicOnlineTransport/EOSSDKComponent.cs index 9d4bebde..b1f887fd 100644 --- a/Mirror/Runtime/Transport/EpicOnlineTransport/EOSSDKComponent.cs +++ b/Mirror/Runtime/Transport/EpicOnlineTransport/EOSSDKComponent.cs @@ -1,4 +1,4 @@ -using Epic.OnlineServices; +using Epic.OnlineServices; using Epic.OnlineServices.Logging; using Epic.OnlineServices.Platform; @@ -14,13 +14,15 @@ /// after releasing the SDK the game has to be restarted in order to initialize the SDK again. /// In the unity editor the OnDestroy function will not run so that we dont have to restart the editor after play. /// -namespace EpicTransport { - +namespace EpicTransport +{ + [DefaultExecutionOrder(-32000)] - public class EOSSDKComponent : MonoBehaviour { - + public class EOSSDKComponent : MonoBehaviour + { + // Unity Inspector shown variables - + [SerializeField] private EosApiKey apiKeys; @@ -32,11 +34,14 @@ public class EOSSDKComponent : MonoBehaviour { public Epic.OnlineServices.ExternalCredentialType connectInterfaceCredentialType = Epic.OnlineServices.ExternalCredentialType.DeviceidAccessToken; public string deviceModel = "PC Windows 64bit"; [SerializeField] private string displayName = "User"; - public static string DisplayName { - get { + public static string DisplayName + { + get + { return Instance.displayName; } - set { + set + { Instance.displayName = value; } } @@ -45,8 +50,10 @@ public static string DisplayName { public LogLevel epicLoggerLevel = LogLevel.Error; [SerializeField] private bool collectPlayerMetrics = true; - public static bool CollectPlayerMetrics { - get { + public static bool CollectPlayerMetrics + { + get + { return Instance.collectPlayerMetrics; } } @@ -91,68 +98,77 @@ public static bool CollectPlayerMetrics { protected EpicAccountId localUserAccountId; - public static EpicAccountId LocalUserAccountId { - get { + public static EpicAccountId LocalUserAccountId + { + get + { return Instance.localUserAccountId; } } protected string localUserAccountIdString; - public static string LocalUserAccountIdString { - get { + public static string LocalUserAccountIdString + { + get + { return Instance.localUserAccountIdString; } } protected ProductUserId localUserProductId; - public static ProductUserId LocalUserProductId { - get { + public static ProductUserId LocalUserProductId + { + get + { return Instance.localUserProductId; } } protected string localUserProductIdString; - public static string LocalUserProductIdString { - get { + public static string LocalUserProductIdString + { + get + { return Instance.localUserProductIdString; } } protected bool initialized; - public static bool Initialized { - get { + public static bool Initialized + { + get + { return Instance.initialized; } } protected bool isConnecting; - public static bool IsConnecting { - get { + public static bool IsConnecting + { + get + { return Instance.isConnecting; } } protected static EOSSDKComponent instance; - protected static EOSSDKComponent Instance { - get { - if (instance == null) { + protected static EOSSDKComponent Instance + { + get + { + if (instance == null) + { return new GameObject("EOSSDKComponent").AddComponent(); - } else { + } + else + { return instance; } } } - public static void Tick() { - if (instance == null) - { - Debug.LogError("INSTANCE NULL"); - - } - else - { - Debug.Log(instance.gameObject.name); - } + public static void Tick() + { instance.platformTickTimer -= Time.deltaTime; instance.EOS.Tick(); } @@ -226,7 +242,8 @@ private static IntPtr GetProcAddress(IntPtr hModule, string lpProcName) private IntPtr libraryPointer; #endif - private void Awake() { + private void Awake() + { // Initialize Java version of the SDK with a reference to the VM with JNI // See https://eoshelp.epicgames.com/s/question/0D54z00006ufJBNCA2/cant-get-createdeviceid-to-work-in-unity-android-c-sdk?language=en_US if (Application.platform == RuntimePlatform.Android) @@ -239,8 +256,9 @@ private void Awake() { } // Prevent multiple instances - - if (instance != null) { + + if (instance != null) + { Destroy(gameObject); return; } @@ -251,22 +269,26 @@ private void Awake() { var libraryPath = "Assets/Mirror/Runtime/Transport/EpicOnlineTransport/EOSSDK/" + Config.LibraryName; libraryPointer = LoadLibrary(libraryPath); - if (libraryPointer == IntPtr.Zero) { + if (libraryPointer == IntPtr.Zero) + { throw new Exception("Failed to load library" + libraryPath); } Bindings.Hook(libraryPointer, GetProcAddress); #endif - if (!delayedInitialization) { + if (!delayedInitialization) + { Initialize(); } } - protected void InitializeImplementation() { + protected void InitializeImplementation() + { isConnecting = true; - var initializeOptions = new InitializeOptions() { + var initializeOptions = new InitializeOptions() + { ProductName = apiKeys.epicProductName, ProductVersion = apiKeys.epicProductVersion }; @@ -275,7 +297,8 @@ protected void InitializeImplementation() { // This code is called each time the game is run in the editor, so we catch the case where the SDK has already been initialized in the editor. var isAlreadyConfiguredInEditor = Application.isEditor && initializeResult == Result.AlreadyConfigured; - if (initializeResult != Result.Success && !isAlreadyConfiguredInEditor) { + if (initializeResult != Result.Success && !isAlreadyConfiguredInEditor) + { throw new System.Exception("Failed to initialize platform: " + initializeResult); } @@ -284,11 +307,14 @@ protected void InitializeImplementation() { LoggingInterface.SetLogLevel(LogCategory.AllCategories, epicLoggerLevel); LoggingInterface.SetCallback(message => Logger.EpicDebugLog(message)); - var options = new Options() { + var options = new Options() + { + EncryptionKey = apiKeys.encryptionKey, ProductId = apiKeys.epicProductId, SandboxId = apiKeys.epicSandboxId, DeploymentId = apiKeys.epicDeploymentId, - ClientCredentials = new ClientCredentials() { + ClientCredentials = new ClientCredentials() + { ClientId = apiKeys.epicClientId, ClientSecret = apiKeys.epicClientSecret }, @@ -296,18 +322,22 @@ protected void InitializeImplementation() { }; EOS = PlatformInterface.Create(options); - if (EOS == null) { + if (EOS == null) + { throw new System.Exception("Failed to create platform"); } - if (checkForEpicLauncherAndRestart) { + if (checkForEpicLauncherAndRestart) + { Result result = EOS.CheckForLauncherAndRestart(); // If not started through epic launcher the app will be restarted and we can quit - if (result != Result.NoChange) { + if (result != Result.NoChange) + { // Log error if launcher check failed, but still quit to prevent hacking - if (result == Result.UnexpectedError) { + if (result == Result.UnexpectedError) + { Debug.LogError("Unexpected Error while checking if app was started through epic launcher"); } @@ -317,83 +347,116 @@ protected void InitializeImplementation() { // If we use the Auth interface then only login into the Connect interface after finishing the auth interface login // If we don't use the Auth interface we can directly login to the Connect interface - if (authInterfaceLogin) { - if (authInterfaceCredentialType == Epic.OnlineServices.Auth.LoginCredentialType.Developer) { + if (authInterfaceLogin) + { + if (authInterfaceCredentialType == Epic.OnlineServices.Auth.LoginCredentialType.Developer) + { authInterfaceLoginCredentialId = "localhost:" + devAuthToolPort; authInterfaceCredentialToken = devAuthToolCredentialName; } // Login to Auth Interface - Epic.OnlineServices.Auth.LoginOptions loginOptions = new Epic.OnlineServices.Auth.LoginOptions() { - Credentials = new Epic.OnlineServices.Auth.Credentials() { + Epic.OnlineServices.Auth.LoginOptions loginOptions = new Epic.OnlineServices.Auth.LoginOptions() + { + Credentials = new Epic.OnlineServices.Auth.Credentials() + { Type = authInterfaceCredentialType, Id = authInterfaceLoginCredentialId, Token = authInterfaceCredentialToken }, ScopeFlags = Epic.OnlineServices.Auth.AuthScopeFlags.BasicProfile | Epic.OnlineServices.Auth.AuthScopeFlags.FriendsList | Epic.OnlineServices.Auth.AuthScopeFlags.Presence }; - +#if UNITY_IOS && !UNITY_EDITOR && !UNITY_EDITOR_OSX + Debug.Log("EOS: Attempting iOS Auth login"); + Epic.OnlineServices.Auth.IOSLoginOptions modifiedLoginOptions = EOS_iOSLoginOptionsHelper.MakeIOSLoginOptionsFromDefualt(loginOptions); + EOS.GetAuthInterface().Login(modifiedLoginOptions, null, OnAuthInterfaceLogin); +#else + Debug.Log("EOS: Attempting regular Auth login"); EOS.GetAuthInterface().Login(loginOptions, null, OnAuthInterfaceLogin); - } else { +#endif + } + else + { // Login to Connect Interface - if (connectInterfaceCredentialType == Epic.OnlineServices.ExternalCredentialType.DeviceidAccessToken) { + if (connectInterfaceCredentialType == Epic.OnlineServices.ExternalCredentialType.DeviceidAccessToken) + { Epic.OnlineServices.Connect.CreateDeviceIdOptions createDeviceIdOptions = new Epic.OnlineServices.Connect.CreateDeviceIdOptions(); createDeviceIdOptions.DeviceModel = deviceModel; EOS.GetConnectInterface().CreateDeviceId(createDeviceIdOptions, null, OnCreateDeviceId); - } else { + } + else + { ConnectInterfaceLogin(); } } } - public static void Initialize() { - if (Instance.initialized || Instance.isConnecting) { + public static void Initialize() + { + if (Instance.initialized || Instance.isConnecting) + { return; } Instance.InitializeImplementation(); } - private void OnAuthInterfaceLogin(Epic.OnlineServices.Auth.LoginCallbackInfo loginCallbackInfo) { - if (loginCallbackInfo.ResultCode == Result.Success) { + private void OnAuthInterfaceLogin(Epic.OnlineServices.Auth.LoginCallbackInfo loginCallbackInfo) + { + if (loginCallbackInfo.ResultCode == Result.Success) + { Debug.Log("Auth Interface Login succeeded"); string accountIdString; Result result = loginCallbackInfo.LocalUserId.ToString(out accountIdString); - if (Result.Success == result) { + if (Result.Success == result) + { Debug.Log("EOS User ID:" + accountIdString); localUserAccountIdString = accountIdString; localUserAccountId = loginCallbackInfo.LocalUserId; } - + ConnectInterfaceLogin(); - } else if(Epic.OnlineServices.Common.IsOperationComplete(loginCallbackInfo.ResultCode)){ + } + else if (Epic.OnlineServices.Common.IsOperationComplete(loginCallbackInfo.ResultCode)) + { Debug.Log("Login returned " + loginCallbackInfo.ResultCode); } } - private void OnCreateDeviceId(Epic.OnlineServices.Connect.CreateDeviceIdCallbackInfo createDeviceIdCallbackInfo) { - if (createDeviceIdCallbackInfo.ResultCode == Result.Success || createDeviceIdCallbackInfo.ResultCode == Result.DuplicateNotAllowed) { + private void OnCreateDeviceId(Epic.OnlineServices.Connect.CreateDeviceIdCallbackInfo createDeviceIdCallbackInfo) + { + if (createDeviceIdCallbackInfo.ResultCode == Result.Success || createDeviceIdCallbackInfo.ResultCode == Result.DuplicateNotAllowed) + { ConnectInterfaceLogin(); - } else if(Epic.OnlineServices.Common.IsOperationComplete(createDeviceIdCallbackInfo.ResultCode)) { + } + else if (Epic.OnlineServices.Common.IsOperationComplete(createDeviceIdCallbackInfo.ResultCode)) + { Debug.Log("Device ID creation returned " + createDeviceIdCallbackInfo.ResultCode); } } - private void ConnectInterfaceLogin() { + private void ConnectInterfaceLogin() + { var loginOptions = new Epic.OnlineServices.Connect.LoginOptions(); - if (connectInterfaceCredentialType == Epic.OnlineServices.ExternalCredentialType.Epic) { + if (connectInterfaceCredentialType == Epic.OnlineServices.ExternalCredentialType.Epic) + { Epic.OnlineServices.Auth.Token token; Result result = EOS.GetAuthInterface().CopyUserAuthToken(new Epic.OnlineServices.Auth.CopyUserAuthTokenOptions(), localUserAccountId, out token); - if (result == Result.Success) { + if (result == Result.Success) + { connectInterfaceCredentialToken = token.AccessToken; - } else { + } + else + { Debug.LogError("Failed to retrieve User Auth Token"); } - } else if (connectInterfaceCredentialType == Epic.OnlineServices.ExternalCredentialType.DeviceidAccessToken) { + } + else if (connectInterfaceCredentialType == Epic.OnlineServices.ExternalCredentialType.DeviceidAccessToken) + { loginOptions.UserLoginInfo = new Epic.OnlineServices.Connect.UserLoginInfo(); loginOptions.UserLoginInfo.DisplayName = displayName; } @@ -405,65 +468,78 @@ private void ConnectInterfaceLogin() { EOS.GetConnectInterface().Login(loginOptions, null, OnConnectInterfaceLogin); } - private void OnConnectInterfaceLogin(Epic.OnlineServices.Connect.LoginCallbackInfo loginCallbackInfo) { - if (loginCallbackInfo.ResultCode == Result.Success) { + private void OnConnectInterfaceLogin(Epic.OnlineServices.Connect.LoginCallbackInfo loginCallbackInfo) + { + if (loginCallbackInfo.ResultCode == Result.Success) + { Debug.Log("Connect Interface Login succeeded"); string productIdString; Result result = loginCallbackInfo.LocalUserId.ToString(out productIdString); - if (Result.Success == result) { + if (Result.Success == result) + { Debug.Log("EOS User Product ID:" + productIdString); localUserProductIdString = productIdString; localUserProductId = loginCallbackInfo.LocalUserId; } - + initialized = true; isConnecting = false; var authExpirationOptions = new Epic.OnlineServices.Connect.AddNotifyAuthExpirationOptions(); authExpirationHandle = EOS.GetConnectInterface().AddNotifyAuthExpiration(authExpirationOptions, null, OnAuthExpiration); - } else if (Epic.OnlineServices.Common.IsOperationComplete(loginCallbackInfo.ResultCode)) { + } + else if (Epic.OnlineServices.Common.IsOperationComplete(loginCallbackInfo.ResultCode)) + { Debug.Log("Login returned " + loginCallbackInfo.ResultCode + "\nRetrying..."); - EOS.GetConnectInterface().CreateUser(new Epic.OnlineServices.Connect.CreateUserOptions() { ContinuanceToken = loginCallbackInfo.ContinuanceToken }, null, (Epic.OnlineServices.Connect.CreateUserCallbackInfo cb) => { + EOS.GetConnectInterface().CreateUser(new Epic.OnlineServices.Connect.CreateUserOptions() { ContinuanceToken = loginCallbackInfo.ContinuanceToken }, null, (Epic.OnlineServices.Connect.CreateUserCallbackInfo cb) => + { if (cb.ResultCode != Result.Success) { Debug.Log(cb.ResultCode); return; } localUserProductId = cb.LocalUserId; ConnectInterfaceLogin(); }); } } - - private void OnAuthExpiration(Epic.OnlineServices.Connect.AuthExpirationCallbackInfo authExpirationCallbackInfo) { + + private void OnAuthExpiration(Epic.OnlineServices.Connect.AuthExpirationCallbackInfo authExpirationCallbackInfo) + { Debug.Log("AuthExpiration callback"); EOS.GetConnectInterface().RemoveNotifyAuthExpiration(authExpirationHandle); ConnectInterfaceLogin(); } // Calling tick on a regular interval is required for callbacks to work. - private void LateUpdate() { - if (EOS != null) { + private void LateUpdate() + { + if (EOS != null) + { platformTickTimer += Time.deltaTime; - if (platformTickTimer >= platformTickIntervalInSeconds) { + if (platformTickTimer >= platformTickIntervalInSeconds) + { platformTickTimer = 0; EOS.Tick(); } } } - private void OnApplicationQuit() { -#if !UNITY_EDITOR + private void OnApplicationQuit() + { +#if !UNITY_EDITOR_OSX if (EOS != null) { EOS.Release(); EOS = null; PlatformInterface.Shutdown(); } -#endif +#endif + // Unhook the library in the editor, this makes it possible to load the library again after stopping to play #if UNITY_EDITOR - if (libraryPointer != IntPtr.Zero) { - Bindings.Unhook(); + if (libraryPointer != IntPtr.Zero) + { + Bindings.Unhook(); // // Free until the module ref count is 0 while (FreeLibrary(libraryPointer) != 0) @@ -475,4 +551,4 @@ private void OnApplicationQuit() { #endif } } -} \ No newline at end of file +} From 9caba8adb7f5ec45eb988cf6a8eddf89b4483dea Mon Sep 17 00:00:00 2001 From: Kevin Yang <68880349+MadkevOP7@users.noreply.github.com> Date: Mon, 3 Jul 2023 17:33:53 -0700 Subject: [PATCH 11/11] Auth loging support To use updated EOS auth interface, we must provide an encryption key. --- Mirror/Runtime/Transport/EpicOnlineTransport/EosApiKey.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Mirror/Runtime/Transport/EpicOnlineTransport/EosApiKey.cs b/Mirror/Runtime/Transport/EpicOnlineTransport/EosApiKey.cs index ddc037d1..ece6dd7e 100644 --- a/Mirror/Runtime/Transport/EpicOnlineTransport/EosApiKey.cs +++ b/Mirror/Runtime/Transport/EpicOnlineTransport/EosApiKey.cs @@ -20,4 +20,5 @@ public class EosApiKey : ScriptableObject { public string epicDeploymentId = ""; public string epicClientId = ""; public string epicClientSecret = ""; + public string encryptionKey = ""; }