diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md
index 7e20396ec..e4d92fdde 100644
--- a/.github/ISSUE_TEMPLATE/feature_request.md
+++ b/.github/ISSUE_TEMPLATE/feature_request.md
@@ -10,7 +10,7 @@ assignees: ''
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...].
Also consider if this is an issue that the plugin handles, or something that the Epic Online Services
-SDK handles, E.G. "It would be nice if the EOS ran on the Plan 9 Operating System". Such requests are usually best posted to the Epic's [forum](https://eoshelp.epicgames.com/s/).
+SDK handles, E.G. "It would be nice if the EOS ran on the Plan 9 Operating System". Such requests are usually best posted to the Epic's [forum](https://eoshelp.epicgames.com/).
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
diff --git a/.github/workflows/check-markdown-links.yml b/.github/workflows/check-markdown-links.yml
new file mode 100644
index 000000000..a962bbe67
--- /dev/null
+++ b/.github/workflows/check-markdown-links.yml
@@ -0,0 +1,24 @@
+name: Check Markdown Links
+
+on:
+ push:
+ branches: ["feat/documentation-link-checker"]
+ #paths:
+ # - '**/*.md'
+ pull_request:
+ paths:
+ - '**/*.md'
+
+jobs:
+ link-check:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v3
+ - name: Set up Python
+ uses: actions/setup-python@v4
+ with:
+ python-version: '3.x'
+ - name: Install dependencies
+ run: pip install requests tqdm beautifulsoup4
+ - name: Run link checker
+ run: python tools/scripts/check_links.py
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index 683b80225..617df5ae3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -41,7 +41,10 @@
# Autogenerated VS/MD/Consulo solution and project files
ExportedObj/
.consulo/
-*.csproj
+
+# Only exclude csproj files in the root of the repository
+/*.csproj
+
*.unityproj
*.sln
*.suo
diff --git a/Assets/Plugins/Android/Core/AndroidConfig.cs b/Assets/Plugins/Android/Core/AndroidConfig.cs
index 446e421c3..58501ce4d 100644
--- a/Assets/Plugins/Android/Core/AndroidConfig.cs
+++ b/Assets/Plugins/Android/Core/AndroidConfig.cs
@@ -22,9 +22,33 @@
namespace PlayEveryWare.EpicOnlineServices
{
- // Flags specifically for Android
+ // Flags specifically for Android. Note that labels for the baser
+ // PlatformConfig need to be specified here.
+ [ConfigGroup("Android Config", new[]
+ {
+ "Android-Specific Options",
+ "Deployment",
+ "Flags",
+ "Tick Budgets",
+ "Overlay Options"
+ }, false)]
public class AndroidConfig : PlatformConfig
{
+ [ConfigField("Google Login Client ID",
+ ConfigFieldType.Text,
+ "Get your project's Google Login Client ID from the " +
+ "Google Cloud dashboard",
+ 0,
+ "https://console.cloud.google.com/apis/dashboard")]
+ public string GoogleLoginClientID;
+
+ [ConfigField("Google Login Nonce",
+ ConfigFieldType.Text,
+ "Use a nonce to improve sign-ing security on Android.",
+ 0,
+ "https://developer.android.com/google/play/integrity/classic#nonce")]
+ public string GoogleLoginNonce;
+
static AndroidConfig()
{
RegisterFactory(() => new AndroidConfig());
diff --git a/Assets/Plugins/Android/login.java b/Assets/Plugins/Android/login.java
new file mode 100644
index 000000000..174dcfb07
--- /dev/null
+++ b/Assets/Plugins/Android/login.java
@@ -0,0 +1,121 @@
+/*
+* Copyright (c) 2024 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.
+*/
+
+package com.playeveryware.googlelogin;
+
+import com.google.android.libraries.identity.googleid.GetSignInWithGoogleOption;
+import com.google.android.libraries.identity.googleid.GoogleIdTokenCredential;
+import com.google.android.libraries.identity.googleid.GoogleIdTokenParsingException;
+
+import androidx.credentials.GetCredentialRequest;
+import androidx.credentials.GetCredentialResponse;
+import androidx.credentials.exceptions.GetCredentialException;
+import androidx.credentials.Credential;
+import androidx.credentials.CustomCredential;
+import androidx.credentials.CredentialManager;
+import androidx.credentials.CredentialManagerCallback;
+
+import android.app.Activity;
+import android.content.Context;
+import android.os.CancellationSignal;
+import android.util.Log;
+
+import java.util.concurrent.Executors;
+
+
+public class login extends Activity
+{
+ private String name;
+ private String token;
+ private static login instance;
+
+ public login()
+ {
+ this.instance = this;
+ }
+ public static login instance()
+ {
+ if(instance == null)
+ {
+ instance = new login();
+ }
+ return instance;
+ }
+
+ public String getResultName()
+ {
+ return name;
+ }
+ public String getResultIdToken()
+ {
+ return token;
+ }
+
+ public void SignInWithGoogle(String clientID, String nonce, Context context, CredentialManagerCallback callback)
+ {
+ GetSignInWithGoogleOption signInWithGoogleOption = new GetSignInWithGoogleOption.Builder(clientID)
+ .setNonce(nonce)
+ .build();
+
+ GetCredentialRequest request = new GetCredentialRequest.Builder()
+ .addCredentialOption(signInWithGoogleOption)
+ .build();
+
+ CredentialManager credentialManager = CredentialManager.create(this);
+ credentialManager.getCredentialAsync(context,request,new CancellationSignal(),Executors.newSingleThreadExecutor(),callback);
+ }
+
+ public void handleFailure(GetCredentialException e)
+ {
+ Log.e("Unity", "Received an invalid google id token response", e);
+ }
+
+ public void handleSignIn(GetCredentialResponse result)
+ {
+ Credential credential = result.getCredential();
+
+ if (credential instanceof CustomCredential)
+ {
+ if (GoogleIdTokenCredential.TYPE_GOOGLE_ID_TOKEN_CREDENTIAL.equals(credential.getType()))
+ {
+ try
+ {
+ GoogleIdTokenCredential googleIdTokenCredential = GoogleIdTokenCredential.createFrom(credential.getData());
+ name = googleIdTokenCredential.getDisplayName();
+ token = googleIdTokenCredential.getIdToken();
+ }
+ catch (Exception e)
+ {
+ if (e instanceof GoogleIdTokenParsingException)
+ {
+ Log.e("Unity", "Received an invalid google id token response", e);
+ }
+ else
+ {
+ Log.e("Unity", "Some exception", e);
+ }
+ }
+ }
+ }
+ }
+}
+
diff --git a/Assets/Plugins/Android/login.java.meta b/Assets/Plugins/Android/login.java.meta
new file mode 100644
index 000000000..f820db864
--- /dev/null
+++ b/Assets/Plugins/Android/login.java.meta
@@ -0,0 +1,32 @@
+fileFormatVersion: 2
+guid: 89ca82eb8db76ec47b323edb4fe70f92
+PluginImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ iconMap: {}
+ executionOrder: {}
+ defineConstraints: []
+ isPreloaded: 0
+ isOverridable: 0
+ isExplicitlyReferenced: 0
+ validateReferences: 1
+ platformData:
+ - first:
+ Android: Android
+ second:
+ enabled: 1
+ settings: {}
+ - first:
+ Any:
+ second:
+ enabled: 0
+ settings: {}
+ - first:
+ Editor: Editor
+ second:
+ enabled: 0
+ settings:
+ DefaultValueInitialized: true
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Plugins/Android/mainTemplate.gradle b/Assets/Plugins/Android/mainTemplate.gradle
index a699ead06..5217abc98 100644
--- a/Assets/Plugins/Android/mainTemplate.gradle
+++ b/Assets/Plugins/Android/mainTemplate.gradle
@@ -4,6 +4,9 @@ apply plugin: 'com.android.library'
**APPLY_PLUGINS**
dependencies {
+ implementation 'androidx.credentials:credentials-play-services-auth:1.3.0'
+ implementation 'androidx.credentials:credentials:1.3.0'
+ implementation 'com.google.android.libraries.identity.googleid:googleid:1.1.1'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation fileTree(dir: 'libs', include: ['*.jar'])
**DEPS**}
diff --git a/Assets/Plugins/Linux/Core/LinuxConfig.cs b/Assets/Plugins/Linux/Core/LinuxConfig.cs
index 349a23fcc..b83e0cc20 100644
--- a/Assets/Plugins/Linux/Core/LinuxConfig.cs
+++ b/Assets/Plugins/Linux/Core/LinuxConfig.cs
@@ -22,10 +22,16 @@
namespace PlayEveryWare.EpicOnlineServices
{
- using System;
-
- // Flags specifically for Linux
- [Serializable]
+ // Flags specifically for Linux. Note that labels for the baser
+ // PlatformConfig need to be specified here.
+ [ConfigGroup("Linux Config", new[]
+ {
+ "Linux-Specific Options",
+ "Deployment",
+ "Flags",
+ "Tick Budgets",
+ "Overlay Options"
+ }, false)]
public class LinuxConfig : PlatformConfig
{
static LinuxConfig()
diff --git a/Assets/Plugins/Source/Editor/Build/BuildRunner.cs b/Assets/Plugins/Source/Editor/Build/BuildRunner.cs
index 5052a33cb..469d56fda 100644
--- a/Assets/Plugins/Source/Editor/Build/BuildRunner.cs
+++ b/Assets/Plugins/Source/Editor/Build/BuildRunner.cs
@@ -22,7 +22,7 @@
namespace PlayEveryWare.EpicOnlineServices.Editor.Build
{
- using Config;
+ using PlayEveryWare.EpicOnlineServices;
using Utility;
using UnityEditor.Build;
using UnityEditor.Build.Reporting;
@@ -64,10 +64,9 @@ public static PlatformSpecificBuilder Builder
/// The pre-process build report.
public void OnPreprocessBuild(BuildReport report)
{
- // Set the current platform that is being built against
- if (PlatformManager.TryGetPlatform(report.summary.platform, out PlatformManager.Platform platform))
+ if (ScriptingDefineUtility.IsEOSDisabled(report))
{
- PlatformManager.CurrentPlatform = platform;
+ return;
}
// Run the static builder's prebuild.
@@ -76,7 +75,7 @@ public void OnPreprocessBuild(BuildReport report)
#if !DISABLESTEAMWORKS
// If we're using Steamworks, then look at the user's Steam configuration file
// If the "steamApiInterfaceVersionsArray" is empty, try to set it for the user
- SteamConfig config = SteamConfig.Get();
+ SteamConfig config = Config.Get();
if (config != null && (config.steamApiInterfaceVersionsArray == null || config.steamApiInterfaceVersionsArray.Count == 0))
{
config.steamApiInterfaceVersionsArray = SteamworksUtility.GetSteamInterfaceVersions();
@@ -88,7 +87,7 @@ public void OnPreprocessBuild(BuildReport report)
else
{
UnityEngine.Debug.Log($"BuildRunner: This project is using Steamworks, but has not yet configured the steamApiInterfaceVersionsArray. The builder has automatically configured this field and will now try to save the value.");
- config.Write(true, false);
+ config.Write(true);
}
}
#endif
@@ -101,6 +100,11 @@ public void OnPreprocessBuild(BuildReport report)
/// The report from the post-process build.
public void OnPostprocessBuild(BuildReport report)
{
+ if (ScriptingDefineUtility.IsEOSDisabled(report))
+ {
+ return;
+ }
+
// Run the static builder's postbuild
s_builder?.PostBuild(report);
}
diff --git a/Assets/Plugins/Source/Editor/Build/PlatformSpecificBuilder.cs b/Assets/Plugins/Source/Editor/Build/PlatformSpecificBuilder.cs
index a496cb527..16d25a3c0 100644
--- a/Assets/Plugins/Source/Editor/Build/PlatformSpecificBuilder.cs
+++ b/Assets/Plugins/Source/Editor/Build/PlatformSpecificBuilder.cs
@@ -22,6 +22,7 @@
namespace PlayEveryWare.EpicOnlineServices.Editor.Build
{
+ using Common;
using Config;
using System.Collections.Generic;
using System.IO;
@@ -241,19 +242,18 @@ private static void ConfigureVersion()
///
private static async void AutoSetProductVersion()
{
- var eosConfig = await Config.GetAsync();
- var prebuildConfig = await Config.GetAsync();
- var previousProdVer = eosConfig.productVersion;
+ PrebuildConfig prebuildConfig = await Config.GetAsync();
+ ProductConfig productConfig = Config.Get();
- if (prebuildConfig.useAppVersionAsProductVersion)
+ // If the product version is set by config, or if it already equals the product config, stop here.
+ if (!prebuildConfig.useAppVersionAsProductVersion || productConfig.ProductVersion == Application.version)
{
- eosConfig.productVersion = Application.version;
+ return;
}
- if (previousProdVer != eosConfig.productVersion)
- {
- await eosConfig.WriteAsync(true);
- }
+ // Otherwise, set the new product version and write the config.
+ productConfig.ProductVersion = Application.version;
+ await productConfig.WriteAsync();
}
///
diff --git a/Assets/Plugins/Source/Editor/ConfigEditors/ConfigEditor.cs b/Assets/Plugins/Source/Editor/ConfigEditors/ConfigEditor.cs
index b8acba4e9..9aaaf0347 100644
--- a/Assets/Plugins/Source/Editor/ConfigEditors/ConfigEditor.cs
+++ b/Assets/Plugins/Source/Editor/ConfigEditors/ConfigEditor.cs
@@ -20,11 +20,10 @@
* SOFTWARE.
*/
+
namespace PlayEveryWare.EpicOnlineServices.Editor
{
using System;
- using System.Collections.Generic;
- using System.Linq;
using System.Reflection;
using UnityEditor;
using UnityEditor.AnimatedValues;
@@ -41,7 +40,7 @@ namespace PlayEveryWare.EpicOnlineServices.Editor
/// The type of config that this editor is responsible for providing an
/// interface to edit for.
///
- public class ConfigEditor : IConfigEditor where T :
+ public class ConfigEditor : IConfigEditor where T :
EpicOnlineServices.Config
{
///
@@ -94,7 +93,7 @@ public class ConfigEditor : IConfigEditor where T :
/// collapsed.
///
public ConfigEditor(
- UnityAction repaintFn = null,
+ UnityAction repaintFn = null,
bool startsExpanded = false)
{
_expanded = startsExpanded;
@@ -104,7 +103,7 @@ public ConfigEditor(
if (null != attribute)
{
- _collapsible = attribute.Collapsible;
+ _collapsible = attribute.Collapsible;
_labelText = attribute.Label;
_groupLabels = attribute.GroupLabels;
}
@@ -158,116 +157,6 @@ protected virtual void OnExpanded(EventArgs e)
handler?.Invoke(this, e);
}
- ///
- /// Use reflection to retrieve a collection of fields that have been
- /// assigned custom ConfigFieldAttribute attributes, grouping by group,
- /// and sorting by group.
- ///
- /// A collection of config fields.
- private static IOrderedEnumerable> GetFieldsByGroup()
- {
- return typeof(T).GetFields(BindingFlags.Public | BindingFlags.Instance)
- .Where(field => field.GetCustomAttribute() != null)
- .Select(info => (info, info.GetCustomAttribute()))
- .GroupBy(r => r.Item2.Group)
- .OrderBy(group => group.Key);
- }
-
- ///
- /// Using a collection of FieldInfo and ConfigFieldAttribute classes,
- /// representing the fields in a Config, determine which field in a
- /// given group is the longest, and return that length.
- ///
- ///
- /// A group of fields that have ConfigFieldAttribute and the same group
- /// number.
- ///
- ///
- /// The length of the longest label to create
- ///
- private static float GetMaximumLabelWidth(IEnumerable<(FieldInfo, ConfigFieldAttribute)> group)
- {
- GUIStyle labelStyle = new(GUI.skin.label);
-
- float maxWidth = 0f;
- foreach (var field in group)
- {
- string labelText = field.Item2.Label;
-
- Vector2 labelSize = labelStyle.CalcSize(new GUIContent(labelText));
- if (maxWidth < labelSize.x)
- {
- maxWidth = labelSize.x;
- }
- }
-
- return maxWidth;
- }
-
- ///
- /// Render the config fields for the config that has been set to edit.
- ///
- ///
- /// Thrown for types that are not yet implemented.
- ///
- ///
- /// Thrown for types that are not yet implemented, and not accounted for
- /// in the switch statement.
- ///
- protected void RenderConfigFields()
- {
- foreach (var fieldGroup in GetFieldsByGroup())
- {
- float labelWidth = GetMaximumLabelWidth(fieldGroup);
-
- // If there is a label for the field group, then display it.
- if (0 >= fieldGroup.Key && _groupLabels?.Length > fieldGroup.Key)
- {
- GUILayout.Label(_groupLabels[fieldGroup.Key], EditorStyles.boldLabel);
- }
-
- foreach (var field in fieldGroup)
- {
- switch (field.FieldDetails.FieldType)
- {
- case ConfigFieldType.Text:
- field.FieldInfo.SetValue(config, GUIEditorUtility.RenderInputField(field.FieldDetails, (string)field.FieldInfo.GetValue(config), labelWidth));
- break;
- case ConfigFieldType.FilePath:
- field.FieldInfo.SetValue(config, GUIEditorUtility.RenderInputField(field.FieldDetails as FilePathFieldAttribute, (string)field.FieldInfo.GetValue(config), labelWidth));
- break;
- case ConfigFieldType.Flag:
- field.FieldInfo.SetValue(config, GUIEditorUtility.RenderInputField(field.FieldDetails, (bool)field.FieldInfo.GetValue(config), labelWidth));
- break;
- case ConfigFieldType.DirectoryPath:
- field.FieldInfo.SetValue(config, GUIEditorUtility.RenderInputField(field.FieldDetails as DirectoryPathFieldAttribute, (string)field.FieldInfo.GetValue(config), labelWidth));
- break;
- case ConfigFieldType.Ulong:
- field.FieldInfo.SetValue(config, GUIEditorUtility.RenderInputField(field.FieldDetails, (ulong)field.FieldInfo.GetValue(config), labelWidth));
- break;
- case ConfigFieldType.Double:
- field.FieldInfo.SetValue(config, GUIEditorUtility.RenderInputField(field.FieldDetails, (double)field.FieldInfo.GetValue(config), labelWidth));
- break;
- case ConfigFieldType.TextList:
- field.FieldInfo.SetValue(config, GUIEditorUtility.RenderInputField(field.FieldDetails, (List)field.FieldInfo.GetValue(config), labelWidth));
- break;
- case ConfigFieldType.Uint:
- field.FieldInfo.SetValue(config, GUIEditorUtility.RenderInputField(field.FieldDetails, (uint)field.FieldInfo.GetValue(config), labelWidth));
- break;
- case ConfigFieldType.Button:
- if (GUILayout.Button(field.FieldDetails.Label) &&
- field.FieldInfo.GetValue(config) is Action onClick)
- {
- onClick();
- }
- break;
- default:
- throw new ArgumentOutOfRangeException();
- }
- }
- }
- }
-
public string GetLabelText()
{
return _labelText;
@@ -289,7 +178,7 @@ public void Load()
Task.Run(LoadAsync).GetAwaiter().GetResult();
}
- public async Task Save(bool prettyPrint)
+ public async Task Save(bool prettyPrint = true)
{
await config.WriteAsync(prettyPrint);
}
@@ -302,8 +191,8 @@ public virtual void RenderContents()
}
else
{
- GUILayout.Label(GetLabelText(), EditorStyles.boldLabel);
- RenderConfigFields();
+ GUIEditorUtility.RenderSectionHeader(GetLabelText());
+ GUIEditorUtility.RenderInputs(ref config);
}
}
@@ -338,7 +227,7 @@ private void RenderCollapsibleContents()
if (EditorGUILayout.BeginFadeGroup(_animExpanded.faded))
{
EditorGUILayout.BeginVertical(GUI.skin.box);
- RenderConfigFields();
+ GUIEditorUtility.RenderInputs(ref config);
EditorGUILayout.EndVertical();
}
EditorGUILayout.EndFadeGroup();
diff --git a/Assets/Plugins/Source/Editor/ConfigEditors/IPlatformConfigEditor.cs b/Assets/Plugins/Source/Editor/ConfigEditors/IPlatformConfigEditor.cs
index 8e76420af..9a01e74cb 100644
--- a/Assets/Plugins/Source/Editor/ConfigEditors/IPlatformConfigEditor.cs
+++ b/Assets/Plugins/Source/Editor/ConfigEditors/IPlatformConfigEditor.cs
@@ -22,6 +22,8 @@
namespace PlayEveryWare.EpicOnlineServices.Editor
{
+ using UnityEngine;
+
// Interface for allowing adding additional config files to the Config editor
public interface IPlatformConfigEditor : IConfigEditor
{
@@ -33,5 +35,7 @@ public interface IPlatformConfigEditor : IConfigEditor
/// True if the platform can be targetted by the Unity Editor.
///
bool IsPlatformAvailable();
+
+ Texture GetPlatformIconTexture();
}
}
\ No newline at end of file
diff --git a/Assets/Plugins/Source/Editor/ConfigEditors/PlatformConfigEditor.cs b/Assets/Plugins/Source/Editor/ConfigEditors/PlatformConfigEditor.cs
index 1b395c3ea..366e446e1 100644
--- a/Assets/Plugins/Source/Editor/ConfigEditors/PlatformConfigEditor.cs
+++ b/Assets/Plugins/Source/Editor/ConfigEditors/PlatformConfigEditor.cs
@@ -19,10 +19,10 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
+
namespace PlayEveryWare.EpicOnlineServices.Editor
{
using System.Linq;
- using UnityEditor;
using UnityEngine;
using Utility;
@@ -32,9 +32,9 @@ namespace PlayEveryWare.EpicOnlineServices.Editor
/// platform.
///
/// Intended to be a type accepted by the templated class ConfigHandler.
- public abstract class PlatformConfigEditor : ConfigEditor, IPlatformConfigEditor where T : PlatformConfig
+ public class PlatformConfigEditor : ConfigEditor, IPlatformConfigEditor where T : PlatformConfig
{
- protected PlatformConfigEditor()
+ public PlatformConfigEditor()
{
Load();
@@ -42,57 +42,19 @@ protected PlatformConfigEditor()
_labelText = PlatformManager.GetFullName(config.Platform);
}
- ///
- /// Given that most platform configurations allow for override values of a specific subset of the standard
- /// options applied to all platforms, the rendering of these options is shared by all PlatformConfigEditor implementations.
- ///
- /// TODO: Consider the scenario where there are values that need to be overriden for one platform, but not for another. How would this work?
- /// NOTE: Currently, all platforms override the same set of values, so this is not currently an issue.
- ///
- public virtual void RenderOverrides()
- {
- GUILayout.Label($"{PlatformManager.GetFullName(config.Platform)} Override Configuration Values",
- EditorStyles.boldLabel);
-
- GUIEditorUtility.AssigningFlagTextField("Integrated Platform Management Flags (Separated by '|')", ref config.flags, 345);
-
- GUIEditorUtility.AssigningFlagTextField("Override Platform Flags (Separated by '|')", ref config.overrideValues.platformOptionsFlags, 250);
-
- GUIEditorUtility.AssigningFloatToStringField("Override initial button delay for overlay", ref config.overrideValues.initialButtonDelayForOverlay, 250);
-
- GUIEditorUtility.AssigningFloatToStringField("Override repeat button delay for overlay", ref config.overrideValues.repeatButtonDelayForOverlay, 250);
-
- // TODO: As far as can be determined, it appears that the following
- // values are the only ones within "overrideValues" that are
- // actually being used to override the otherwise defined
- // values within EOSConfig. Changing the values in the fields
- // for which the input fields are rendered above does not
- // seem to have any affect.
- //
- // This is a bug, but is not relevant to the current task as
- // of this writing, which is to simply add the field member
- // "integratedPlatformManagementFlags" to EOSConfig, and make
- // sure that field is editable within the editor.
-
- GUIEditorUtility.AssigningULongToStringField("Thread Affinity: networkWork", ref config.overrideValues.ThreadAffinity_networkWork);
- GUIEditorUtility.AssigningULongToStringField("Thread Affinity: storageIO", ref config.overrideValues.ThreadAffinity_storageIO);
- GUIEditorUtility.AssigningULongToStringField("Thread Affinity: webSocketIO", ref config.overrideValues.ThreadAffinity_webSocketIO);
- GUIEditorUtility.AssigningULongToStringField("Thread Affinity: P2PIO", ref config.overrideValues.ThreadAffinity_P2PIO);
- GUIEditorUtility.AssigningULongToStringField("Thread Affinity: HTTPRequestIO", ref config.overrideValues.ThreadAffinity_HTTPRequestIO);
- GUIEditorUtility.AssigningULongToStringField("Thread Affinity: RTCIO", ref config.overrideValues.ThreadAffinity_RTCIO);
- }
-
public bool IsPlatformAvailable()
{
return PlatformManager.GetAvailableBuildTargets().Contains(config.Platform);
}
- public virtual void RenderPlatformSpecificOptions() { }
+ public Texture GetPlatformIconTexture()
+ {
+ return PlatformManager.GetPlatformIcon(config.Platform);
+ }
public override sealed void RenderContents()
{
- RenderPlatformSpecificOptions();
- RenderOverrides();
+ GUIEditorUtility.RenderInputs(ref config);
}
}
}
\ No newline at end of file
diff --git a/Assets/Plugins/Source/Editor/Configs/EditorConfig.cs b/Assets/Plugins/Source/Editor/Configs/EditorConfig.cs
index f6ff8cbc7..3370bcf94 100644
--- a/Assets/Plugins/Source/Editor/Configs/EditorConfig.cs
+++ b/Assets/Plugins/Source/Editor/Configs/EditorConfig.cs
@@ -23,30 +23,19 @@
namespace PlayEveryWare.EpicOnlineServices.Editor.Config
{
using EpicOnlineServices.Utility;
- using System.IO;
- using System.Threading.Tasks;
using Config = EpicOnlineServices.Config;
///
- /// Used for configurations that are editor-only.
- /// Configurations are serialized into JSON strings, and then added to EditorPrefs
- /// using their filename as the key.
+ /// Used for configurations that are editor-only. Configurations are
+ /// serialized into JSON strings, and then added to EditorPrefs using their
+ /// filename as the key.
///
public abstract class EditorConfig : Config
{
- protected EditorConfig(string filename) : base(filename, Path.Combine(FileSystemUtility.GetProjectPath(), "etc/config/")) { }
-
- // NOTE: This compiler block is here because the base class "Config" has
- // the WriteAsync function surrounded by the same conditional.
-#if UNITY_EDITOR
- // Overridden functionality changes the default parameter value for updateAssetDatabase, because EditorConfig
- // should not be anywhere within Assets.
- public override async Task WriteAsync(bool prettyPrint = true, bool updateAssetDatabase = false)
- {
- // Override the base function
- await base.WriteAsync(prettyPrint, updateAssetDatabase);
- }
-#endif
+ protected EditorConfig(string filename) :
+ base(filename,
+ FileSystemUtility.CombinePaths(
+ FileSystemUtility.GetProjectPath(),
+ "etc/config/")) { }
}
-
}
\ No newline at end of file
diff --git a/Assets/Plugins/Source/Editor/Configs/SteamConfig.cs b/Assets/Plugins/Source/Editor/Configs/SteamConfig.cs
index 95b2146a5..fd49a9f59 100644
--- a/Assets/Plugins/Source/Editor/Configs/SteamConfig.cs
+++ b/Assets/Plugins/Source/Editor/Configs/SteamConfig.cs
@@ -24,36 +24,69 @@ namespace PlayEveryWare.EpicOnlineServices
{
using System;
using System.Collections.Generic;
- using Editor;
+ using Editor.Config;
using Editor.Utility;
+ using Epic.OnlineServices.IntegratedPlatform;
+ using Newtonsoft.Json;
using Utility;
- [Serializable]
- [ConfigGroup("Steam Configuration")]
- // TODO: Make SteamConfig derive from EditorConfig, and update the native code
- // to properly reference the correct file where appropriate.
- public class SteamConfig : EpicOnlineServices.Config
+ [ConfigGroup("Steam Configuration", new string[]
+ {
+ "Steamworks SDK",
+ })]
+ public class SteamConfig : EditorConfig
{
- [ConfigField("Steam Flags", ConfigFieldType.TextList)]
- public List flags;
-
#region These fields are referenced by the native code
- [DirectoryPathField("Override Library Path")]
+ [DirectoryPathField("Override Library Path",
+ "Path to where you have your Steamworks SDK installed.", 0)]
public string overrideLibraryPath;
- [ConfigField("Steamworks SDK Major Version", ConfigFieldType.Uint)]
+ [ConfigField("SDK Major Version",
+ ConfigFieldType.Uint,
+ "The major version for the Steamworks SDK you have installed.", 0)]
public uint steamSDKMajorVersion;
- [ConfigField("Steamworks SDK Minor Version", ConfigFieldType.Uint)]
+ [ConfigField("SDK Minor Version",
+ ConfigFieldType.Uint,
+ "The minor version for the Steamworks SDK you have installed.", 0)]
public uint steamSDKMinorVersion;
- [ConfigField("Steamworks Interface Versions", ConfigFieldType.TextList)]
+ [ConfigField("Steamworks Interface Versions", ConfigFieldType.TextList, null, 0)]
public List steamApiInterfaceVersionsArray;
+ ///
+ /// Used to store integrated platform management flags.
+ ///
+ [ConfigField("Integrated Platform Management Flags",
+ ConfigFieldType.Enum, "Integrated Platform Management " +
+ "Flags for platform specific options.",
+ 1, "https://dev.epicgames.com/docs/api-ref/enums/eos-e-integrated-platform-management-flags")]
+ [JsonConverter(typeof(ListOfStringsToIntegratedPlatformManagementFlags))]
+ public IntegratedPlatformManagementFlags integratedPlatformManagementFlags;
+
+ // This property exists to maintain backwards-compatibility with
+ // previous versions of the config json structures.
+ [JsonProperty] // Mark it so that it gets read
+ [JsonIgnore] // Ignore so that it does not get written
+ [Obsolete("This property is deprecated. Use the property integratedPlatformManagementFlags instead.")]
+ [JsonConverter(typeof(ListOfStringsToIntegratedPlatformManagementFlags))]
+ public IntegratedPlatformManagementFlags flags
+ {
+ get
+ {
+ return integratedPlatformManagementFlags;
+ }
+ set
+ {
+ integratedPlatformManagementFlags = value;
+ }
+ }
+
#endregion
- [ButtonField("Update from Steamworks.NET")]
+ [ButtonField("Update from Steamworks.NET", "Click here to try and import the SDK versions from the indicated Steamworks SDK Library referenced above", 0)]
+ [JsonIgnore]
public Action UpdateFromSteamworksNET;
static SteamConfig()
@@ -61,7 +94,7 @@ static SteamConfig()
RegisterFactory(() => new SteamConfig());
}
- protected SteamConfig() : base("eos_steam_config.json")
+ protected SteamConfig() : base("eos_plugin_steam_config.json")
{
UpdateFromSteamworksNET = () =>
{
diff --git a/Assets/Plugins/Source/Editor/EditorWindows/CheckDeploymentWindow.cs b/Assets/Plugins/Source/Editor/EditorWindows/CheckDeploymentWindow.cs
index 83002aa79..a40d384b3 100644
--- a/Assets/Plugins/Source/Editor/EditorWindows/CheckDeploymentWindow.cs
+++ b/Assets/Plugins/Source/Editor/EditorWindows/CheckDeploymentWindow.cs
@@ -47,7 +47,7 @@ public class CheckDeploymentWindow : EOSEditorWindow
public CheckDeploymentWindow() : base("Deployment Checker") { }
- [MenuItem("Tools/EOS Plugin/Check Deployment")]
+ [MenuItem("EOS Plugin/Advanced/Check Deployment")]
public static void ShowWindow()
{
GetWindow();
diff --git a/Assets/Plugins/Source/Editor/EditorWindows/CreatePackageWindow.cs b/Assets/Plugins/Source/Editor/EditorWindows/CreatePackageWindow.cs
index 39ab8b2f2..d1597fcae 100644
--- a/Assets/Plugins/Source/Editor/EditorWindows/CreatePackageWindow.cs
+++ b/Assets/Plugins/Source/Editor/EditorWindows/CreatePackageWindow.cs
@@ -72,7 +72,7 @@ public CreatePackageWindow() : base("Create Package") { }
#endregion
- [MenuItem("Tools/EOS Plugin/Create Package")]
+ [MenuItem("EOS Plugin/Advanced/Create Package")]
public static void ShowWindow()
{
GetWindow();
@@ -143,7 +143,7 @@ protected override void RenderWindow()
GUILayout.Space(10f);
- GUIEditorUtility.RenderFoldout(ref _showAdvanced, "Hide Advanced Options", "Show Advanced Options", RenderAdvanced);
+ _showAdvanced = GUIEditorUtility.RenderFoldout(_showAdvanced, "Hide Advanced Options", "Show Advanced Options", RenderAdvanced);
GUILayout.Space(10f);
@@ -269,7 +269,7 @@ protected void RenderAdvanced()
if (jsonPackageFile != _packagingConfig.pathToJSONPackageDescription)
{
_packagingConfig.pathToJSONPackageDescription = jsonPackageFile;
- _packagingConfig.Write(true, false);
+ _packagingConfig.Write(true);
}
GUIEditorUtility.AssigningBoolField("Clean target directory", ref _cleanBeforeCreate, 150f,
diff --git a/Assets/Plugins/Source/Editor/EditorWindows/EOSPluginSettingsWindow.cs b/Assets/Plugins/Source/Editor/EditorWindows/EOSPluginSettingsWindow.cs
index 14cbf771e..1a32b3326 100644
--- a/Assets/Plugins/Source/Editor/EditorWindows/EOSPluginSettingsWindow.cs
+++ b/Assets/Plugins/Source/Editor/EditorWindows/EOSPluginSettingsWindow.cs
@@ -20,20 +20,18 @@
* SOFTWARE.
*/
-using System;
-using System.IO;
-using UnityEditor;
-using UnityEngine;
-using System.Collections.Generic;
+#if !EOS_DISABLE
namespace PlayEveryWare.EpicOnlineServices.Editor.Windows
{
+ using System;
+ using System.IO;
+ using UnityEditor;
+ using UnityEngine;
+ using System.Collections.Generic;
using Config;
using System.Linq;
using System.Threading.Tasks;
- using UnityEditor.AnimatedValues;
- using Utility;
- using Config = EpicOnlineServices.Config;
///
/// Creates the view for showing the eos plugin editor config values.
@@ -64,7 +62,7 @@ public static SettingsProvider CreateSettingsProvider()
return provider;
}
- [MenuItem("Tools/EOS Plugin/Plugin Configuration")]
+ [MenuItem("EOS Plugin/Plugin Configuration", priority = 2)]
public static void ShowWindow()
{
var window = GetWindow();
@@ -164,4 +162,6 @@ private void Save()
AssetDatabase.Refresh();
}
}
-}
\ No newline at end of file
+}
+
+#endif
\ No newline at end of file
diff --git a/Assets/Plugins/Source/Editor/EditorWindows/EOSSettingsWindow.cs b/Assets/Plugins/Source/Editor/EditorWindows/EOSSettingsWindow.cs
index eb0c0a895..d4f9322bc 100644
--- a/Assets/Plugins/Source/Editor/EditorWindows/EOSSettingsWindow.cs
+++ b/Assets/Plugins/Source/Editor/EditorWindows/EOSSettingsWindow.cs
@@ -1,405 +1,190 @@
/*
-* Copyright (c) 2021 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.
-*/
+ * Copyright (c) 2024 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.
+ */
+
+// Uncomment the following line to see all platforms, even ones that are not
+// available
+#define DEBUG_SHOW_UNAVAILABLE_PLATFORMS
-//#define ALLOW_CREATION_OF_EOS_CONFIG_AS_C_FILE
+#if !EOS_DISABLE
namespace PlayEveryWare.EpicOnlineServices.Editor.Windows
{
#if !EOS_DISABLE
using Epic.OnlineServices.UI;
#endif
- using PlayEveryWare.EpicOnlineServices.Extensions;
using PlayEveryWare.EpicOnlineServices.Utility;
using System;
- using System.Collections.Generic;
- using System.IO;
- using System.Linq;
- using System.Reflection;
- using System.Threading.Tasks;
- using UnityEditor;
+ using System.Collections.Generic;
+ using System.Threading.Tasks;
+ using UnityEditor;
using UnityEngine;
- using Utility;
- using Config = EpicOnlineServices.Config;
- using Random = System.Random;
+ ///
+ /// Creates the view for showing the eos plugin editor config values.
+ ///
[Serializable]
- public class EOSSettingsWindow : EOSEditorWindow
+ public class NEW_EOSSettingsWindow : EOSEditorWindow
{
- private List platformSpecificConfigEditors;
-
- private static readonly string ConfigDirectory = Path.Combine("Assets", "StreamingAssets", "EOS");
-
- int toolbarInt;
- string[] toolbarTitleStrings;
-
- EOSConfig mainEOSConfigFile;
-
-#if ALLOW_CREATION_OF_EOS_CONFIG_AS_C_FILE
- string eosGeneratedCFilePath = "";
-#endif
- bool prettyPrint;
-
- public EOSSettingsWindow() : base("EOS Configuration")
+ ///
+ /// The editor for the product information that is shared across all
+ /// platforms (represents information that is common to all
+ /// circumstances).
+ ///
+ private ConfigEditor _productConfigEditor = new();
+
+ ///
+ /// Stores the config editors for each of the platforms.
+ ///
+ private readonly IList _platformConfigEditors = new List();
+
+ ///
+ /// Contains the GUIContent that represents the set of tabs that contain
+ /// platform icons and platform text (this is not the tab _content_).
+ ///
+ private GUIContent[] _platformTabs;
+
+ ///
+ /// The tab that is currently selected.
+ ///
+ private int _selectedTab = -1;
+
+ ///
+ /// The style to apply to the platform tabs.
+ ///
+ private static GUIStyle _platformTabsStyle;
+
+ ///
+ /// The style to apply to the platform tabs, uses lazy initialization.
+ ///
+ private static GUIStyle TAB_STYLE => _platformTabsStyle ??= new(GUI.skin.button)
{
- }
+ fontSize = 14,
+ padding = new RectOffset(10, 10, 10, 10),
+ alignment = TextAnchor.MiddleCenter,
+ fixedHeight = 40
+ };
+
+ public NEW_EOSSettingsWindow() : base("EOS Configuration") { }
- [MenuItem("Tools/EOS Plugin/EOS Configuration")]
+ [MenuItem("EOS Plugin/EOS Configuration", priority = 1)]
public static void ShowWindow()
{
- var window = GetWindow();
+ var window = GetWindow();
window.SetIsEmbedded(false);
}
- [SettingsProvider]
- public static SettingsProvider CreateProjectSettingsProvider()
- {
- var settingsWindow = CreateInstance();
- string[] keywords = {"Epic", "EOS", "Online", "Services", "PlayEveryWare"};
- // mark the editor window as being embedded, so it skips auto formatting stuff.
- settingsWindow.SetIsEmbedded(true);
- var provider = new SettingsProvider($"Preferences/{settingsWindow.WindowTitle}", SettingsScope.Project)
- {
- label = settingsWindow.WindowTitle,
- keywords = keywords,
- guiHandler = searchContext =>
- {
- settingsWindow.OnGUI();
- }
- };
-
- return provider;
- }
-
- private string GenerateEOSGeneratedFile(EOSConfig aEOSConfig)
- {
- return string.Format(
- String.Join("\n", "#define EOS_PRODUCT_NAME \"{0}\"", "#define EOS_PRODUCT_VERSION \"{1}\"",
- "#define EOS_SANDBOX_ID \"{2}\"", "#define EOS_PRODUCT_ID \"{3}\"",
- "#define EOS_DEPLOYMENT_ID \"{4}\"", "#define EOS_CLIENT_SECRET \"{5}\"",
- "#define EOS_CLIENT_ID \"{6}\""), aEOSConfig.productName,
- aEOSConfig.productVersion,
- aEOSConfig.productID,
- aEOSConfig.sandboxID,
- aEOSConfig.deploymentID,
- aEOSConfig.clientSecret,
- aEOSConfig.clientID) +
- @"
-_WIN32 || _WIN64
-#define PLATFORM_WINDOWS 1
-#endif
-
-#if _WIN64
-#define PLATFORM_64BITS 1
-#else
-#define PLATFORM_32BITS 1
-#endif
-
- extern ""C"" __declspec(dllexport) char* __stdcall GetConfigAsJSONString()
-{
- return ""{""
- ""productName:"" EOS_PRODUCT_NAME "",""
- ""productVersion: "" EOS_PRODUCT_VERSION "",""
- ""productID: "" EOS_PRODUCT_ID "",""
- ""sandboxID: "" EOS_SANDBOX_ID "",""
- ""deploymentID: "" EOS_DEPLOYMENT_ID "",""
- ""clientSecret: "" EOS_CLIENT_SECRET "",""
- ""clientID: "" EOS_CLIENT_ID
-
- ""}""
- ;
- }";
- }
-
protected override async Task AsyncSetup()
{
- if (!Directory.Exists(ConfigDirectory))
- {
- Directory.CreateDirectory(ConfigDirectory);
- }
-
- mainEOSConfigFile = await Config.GetAsync();
-
- platformSpecificConfigEditors ??= new List();
- var configEditors = ReflectionUtility.CreateInstancesOfDerivedGenericClasses(typeof(PlatformConfigEditor<>));
- List toolbarStrings = new(new[] { "Main" });
- foreach (IPlatformConfigEditor editor in configEditors.Cast())
- {
- // If the platform for the editor is not available, then do not
- // display the editor for it.
- if (!editor.IsPlatformAvailable())
- continue;
-
- toolbarStrings.Add(editor.GetLabelText());
-
- platformSpecificConfigEditors.Add(editor);
- }
-
- toolbarTitleStrings = toolbarStrings.ToArray();
-
- await base.AsyncSetup();
- }
-
- private async Task Save(bool usePrettyFormat)
- {
- await mainEOSConfigFile.WriteAsync(usePrettyFormat);
-
- foreach (var platformSpecificConfigEditor in platformSpecificConfigEditors)
- {
- await platformSpecificConfigEditor.Save(usePrettyFormat);
- }
-
-#if ALLOW_CREATION_OF_EOS_CONFIG_AS_C_FILE
- string generatedCFile = GenerateEOSGeneratedFile(mainEOSConfigFile.Data);
- File.WriteAllText(Path.Combine(eosGeneratedCFilePath, "EOSGenerated.c"), generatedCFile);
-#endif
-
- AssetDatabase.SaveAssets();
- AssetDatabase.Refresh();
- }
-
- private void OnDefaultGUI()
- {
- GUILayout.Label("Epic Online Services", EditorStyles.boldLabel);
-
- float originalLabelWidth = EditorGUIUtility.labelWidth;
-
- EditorGUIUtility.labelWidth = 200;
-
- // TODO: Id the Product Name userfacing? If so, we need loc
- GUIEditorUtility.AssigningTextField("Product Name", ref mainEOSConfigFile.productName,
- tooltip: "Product Name defined in the EOS Development Portal");
-
- // TODO: bool to take product version form application version; should be automatic?
- GUIEditorUtility.AssigningTextField("Product Version", ref mainEOSConfigFile.productVersion,
- tooltip: "Version of Product");
- GUIEditorUtility.AssigningTextField("Product ID", ref mainEOSConfigFile.productID,
- tooltip: "Product ID defined in the EOS Development Portal");
- GUIEditorUtility.AssigningTextField("Sandbox ID", ref mainEOSConfigFile.sandboxID,
- tooltip: "Sandbox ID defined in the EOS Development Portal");
- GUIEditorUtility.AssigningTextField("Deployment ID", ref mainEOSConfigFile.deploymentID,
- tooltip: "Deployment ID defined in the EOS Development Portal");
+ await _productConfigEditor.LoadAsync();
- GUIEditorUtility.AssigningBoolField("Is Server", ref mainEOSConfigFile.isServer,
- tooltip: "Set to 'true' if the application is a dedicated game serve");
-
- EditorGUILayout.LabelField("Sandbox Deployment Overrides");
- if (mainEOSConfigFile.sandboxDeploymentOverrides == null)
- {
- mainEOSConfigFile.sandboxDeploymentOverrides = new List();
- }
-
- for (int i = 0; i < mainEOSConfigFile.sandboxDeploymentOverrides.Count; ++i)
+ List tabContents = new();
+ int tabIndex = 0;
+ foreach (PlatformManager.Platform platform in Enum.GetValues(typeof(PlatformManager.Platform)))
{
- EditorGUILayout.BeginHorizontal();
- GUIEditorUtility.AssigningTextField("Sandbox ID",
- ref mainEOSConfigFile.sandboxDeploymentOverrides[i].sandboxID,
- tooltip: "Deployment ID will be overridden when Sandbox ID is set to this", labelWidth: 70);
- mainEOSConfigFile.sandboxDeploymentOverrides[i].sandboxID =
- mainEOSConfigFile.sandboxDeploymentOverrides[i].sandboxID.Trim();
- GUIEditorUtility.AssigningTextField("Deployment ID",
- ref mainEOSConfigFile.sandboxDeploymentOverrides[i].deploymentID,
- tooltip: "Deployment ID to use for override", labelWidth: 90);
- mainEOSConfigFile.sandboxDeploymentOverrides[i].deploymentID =
- mainEOSConfigFile.sandboxDeploymentOverrides[i].deploymentID.Trim();
- if (GUILayout.Button("Remove", GUILayout.MaxWidth(70)))
+ // This makes sure that the currently selected tab (upon first loading the window) is always the current platform.
+ if (_selectedTab != -1 || platform == PlatformManager.CurrentPlatform)
{
- mainEOSConfigFile.sandboxDeploymentOverrides.RemoveAt(i);
+ _selectedTab = tabIndex;
}
- EditorGUILayout.EndHorizontal();
- }
-
- if (GUILayout.Button("Add", GUILayout.MaxWidth(100)))
- {
- mainEOSConfigFile.sandboxDeploymentOverrides.Add(new SandboxDeploymentOverride());
- }
-
- GUIEditorUtility.AssigningULongToStringField("Thread Affinity: networkWork",
- ref mainEOSConfigFile.ThreadAffinity_networkWork,
- tooltip: "(Optional) Specifies thread affinity for network management that is not IO");
- GUIEditorUtility.AssigningULongToStringField("Thread Affinity: storageIO",
- ref mainEOSConfigFile.ThreadAffinity_storageIO,
- tooltip: "(Optional) Specifies affinity for threads that will interact with a storage device");
- GUIEditorUtility.AssigningULongToStringField("Thread Affinity: webSocketIO",
- ref mainEOSConfigFile.ThreadAffinity_webSocketIO,
- tooltip: "(Optional) Specifies affinity for threads that generate web socket IO");
- GUIEditorUtility.AssigningULongToStringField("Thread Affinity: P2PIO",
- ref mainEOSConfigFile.ThreadAffinity_P2PIO,
- tooltip:
- "(Optional) Specifies affinity for any thread that will generate IO related to P2P traffic and management");
- GUIEditorUtility.AssigningULongToStringField("Thread Affinity: HTTPRequestIO",
- ref mainEOSConfigFile.ThreadAffinity_HTTPRequestIO,
- tooltip: "(Optional) Specifies affinity for any thread that will generate http request IO");
- GUIEditorUtility.AssigningULongToStringField("Thread Affinity: RTCIO",
- ref mainEOSConfigFile.ThreadAffinity_RTCIO,
- tooltip:
- "(Optional) Specifies affinity for any thread that will generate IO related to RTC traffic and management");
-
- string timeBudgetAsString = "";
-
- if (mainEOSConfigFile.tickBudgetInMilliseconds != 0)
- {
- timeBudgetAsString = mainEOSConfigFile.tickBudgetInMilliseconds.ToString();
- }
-
- GUIEditorUtility.AssigningTextField("Time Budget in milliseconds", ref timeBudgetAsString,
- tooltip: "(Optional) Define the maximum amount of execution time the EOS SDK can use each frame");
-
- if (timeBudgetAsString.Length != 0)
- {
- try
+ if (!PlatformManager.TryGetConfigType(platform, out Type configType) || null == configType)
{
- mainEOSConfigFile.tickBudgetInMilliseconds = Convert.ToUInt32(timeBudgetAsString, 10);
- }
- catch
- {
- Debug.LogWarning($"{nameof(EOSSettingsWindow)} ({nameof(OnDefaultGUI)}): {nameof(mainEOSConfigFile.tickBudgetInMilliseconds)} must be convertable to int, but string could not be parsed. The provided string is \"{timeBudgetAsString}\". This value is ignored.");
+ continue;
}
- }
- else
- {
- mainEOSConfigFile.tickBudgetInMilliseconds = 0;
- }
- string taskNetworkTimeoutSecondsAsString = "";
+ Type constructedType =
+ typeof(PlatformConfigEditor<>).MakeGenericType(configType);
- if (mainEOSConfigFile.taskNetworkTimeoutSeconds != 0)
- {
- taskNetworkTimeoutSecondsAsString = mainEOSConfigFile.taskNetworkTimeoutSeconds.ToString();
- }
-#if !EOS_DISABLE
- GUIEditorUtility.AssigningTextField("Task Network Timeout Seconds", ref taskNetworkTimeoutSecondsAsString,
- tooltip: $"(Optional) Define the maximum amount of time network calls will run in the EOS SDK before timing out while the {nameof(Epic.OnlineServices.Platform.NetworkStatus)} is not {nameof(Epic.OnlineServices.Platform.NetworkStatus.Online)}. Defaults to 30 seconds if not set or less than or equal to zero.");
-#endif
- if (taskNetworkTimeoutSecondsAsString.Length != 0)
- {
- try
+ if (Activator.CreateInstance(constructedType) is not IPlatformConfigEditor editor)
{
- mainEOSConfigFile.taskNetworkTimeoutSeconds = Convert.ToDouble(taskNetworkTimeoutSecondsAsString);
+ Debug.LogError($"Could not load config editor for platform \"{platform}\".");
+ continue;
}
- catch
+
+#if !DEBUG_SHOW_UNAVAILABLE_PLATFORMS
+ // Do not add the platform if it is not currently available.
+ if (!editor.IsPlatformAvailable())
{
- Debug.LogWarning($"{nameof(EOSSettingsWindow)} ({nameof(OnDefaultGUI)}): {nameof(mainEOSConfigFile.taskNetworkTimeoutSeconds)} must be convertable to int, but string could not be parsed. The provided string is \"{taskNetworkTimeoutSecondsAsString}\". This value is ignored.");
+ // We only increment the tab index if the editor has been
+ // added to the tabs.
+ tabIndex++;
+ continue;
}
- }
- else
- {
- mainEOSConfigFile.taskNetworkTimeoutSeconds = 0;
- }
+#endif
- EditorGUIUtility.labelWidth = originalLabelWidth;
+ _platformConfigEditors.Add(editor);
+
+ tabContents.Add(new GUIContent($" {editor.GetLabelText()}", editor.GetPlatformIconTexture()));
- // This will be used on Windows via the nativerender code, unless otherwise specified
- EditorGUILayout.Separator();
- GUILayout.Label("Default Client Credentials", EditorStyles.boldLabel);
- GUIEditorUtility.AssigningTextField("Client ID", ref mainEOSConfigFile.clientID,
- tooltip: "Client ID defined in the EOS Development Portal");
- GUIEditorUtility.AssigningTextField("Client Secret", ref mainEOSConfigFile.clientSecret,
- tooltip: "Client Secret defined in the EOS Development Portal");
- GUI.SetNextControlName("KeyText");
- GUIEditorUtility.AssigningTextField("Encryption Key", ref mainEOSConfigFile.encryptionKey,
- tooltip: "Used to decode files previously encoded and stored in EOS");
- GUI.SetNextControlName("GenerateButton");
- if (GUILayout.Button("Generate"))
- {
- //generate random 32-byte hex sequence
- var rng = new Random(SystemInfo.deviceUniqueIdentifier.GetHashCode() *
- (int)(EditorApplication.timeSinceStartup * 1000));
- var keyBytes = new byte[32];
- rng.NextBytes(keyBytes);
- mainEOSConfigFile.encryptionKey = BitConverter.ToString(keyBytes).Replace("-", "");
- //unfocus key input field so the new key is shown
- if (GUI.GetNameOfFocusedControl() == "KeyText")
- {
- GUI.FocusControl("GenerateButton");
- }
}
- if (!mainEOSConfigFile.IsEncryptionKeyValid())
+ // If (for some reason) a default platform was not selected, then
+ // default to the first tab being selected
+ if (_selectedTab == -1)
{
- int keyLength = mainEOSConfigFile.encryptionKey?.Length ?? 0;
- EditorGUILayout.HelpBox(
- "Used for Player Data Storage and Title Storage. Must be left blank if unused. Encryption key must be 64 hex characters (0-9,A-F). Current length is " +
- keyLength + ".", MessageType.Warning);
+ _selectedTab = 0;
}
- GUIEditorUtility.AssigningFlagTextField("Platform Flags (Seperated by '|')",
- ref mainEOSConfigFile.platformOptionsFlags, 190,
- "Flags used to initialize EOS Platform. Available flags are defined in PlatformFlags.cs");
- GUIEditorUtility.AssigningFlagTextField("Auth Scope Flags (Seperated by '|')",
- ref mainEOSConfigFile.authScopeOptionsFlags, 210,
- "Flags used to specify Auth Scope during login. Available flags are defined in AuthScopeFlags.cs");
-
- GUIEditorUtility.AssigningBoolField("Always send Input to Overlay",
- ref mainEOSConfigFile.alwaysSendInputToOverlay, 190,
- "If true, the plugin will always send input to the overlay from the C# side to native, and handle showing the overlay. This doesn't always mean input makes it to the EOS SDK.");
-
-#if !EOS_DISABLE
- InputStateButtonFlags toggleFriendsButtonCombinationEnum = mainEOSConfigFile.GetToggleFriendsButtonCombinationFlags();
- GUIEditorUtility.AssigningEnumField("Default Activate Overlay Button",
- ref toggleFriendsButtonCombinationEnum, 190,
- "Users can press the button(s) associated with this value to activate the Epic Social Overlay. Not all combinations are valid; the SDK will log an error at the start of runtime if an invalid combination is selected.");
- mainEOSConfigFile.toggleFriendsButtonCombination = EnumUtility.GetEnumerator(toggleFriendsButtonCombinationEnum)
- .Select(enumValue => enumValue.ToString())
- .ToList();
-#endif
+ _platformTabs = tabContents.ToArray();
}
protected override void RenderWindow()
{
- int xCount = (int)(EditorGUIUtility.currentViewWidth / 200);
- toolbarInt = GUILayout.SelectionGrid(toolbarInt, toolbarTitleStrings, xCount);
- switch (toolbarInt)
+ if (_selectedTab < 0)
{
- case 0:
- OnDefaultGUI();
- break;
- default:
- if (platformSpecificConfigEditors.Count > toolbarInt - 1)
- {
- platformSpecificConfigEditors[toolbarInt - 1].RenderAsync();
- }
-
- break;
+ _selectedTab = 0;
}
-#if ALLOW_CREATION_OF_EOS_CONFIG_AS_C_FILE
- if (GUILayout.Button("Pick Path For Generated C File"))
+ // Render the generic product configuration stuff.
+ _ = _productConfigEditor.RenderAsync();
+
+ if (_platformTabs != null && _platformConfigEditors.Count != 0)
{
- eosGeneratedCFilePath = EditorUtility.OpenFolderPanel("Pick Path For Generated C File", "", "");
+ _selectedTab = GUILayout.Toolbar(_selectedTab, _platformTabs, TAB_STYLE);
+ GUILayout.Space(30);
+
+ _ = _platformConfigEditors[_selectedTab].RenderAsync();
}
-#endif
- EditorGUILayout.Separator();
- GUILayout.Label("Config Format Options", EditorStyles.boldLabel);
- GUIEditorUtility.AssigningBoolField("Save JSON in 'Pretty' Format", ref prettyPrint, 190);
+
+ GUI.SetNextControlName("Save");
if (GUILayout.Button("Save All Changes"))
{
- Task.Run(() => Save(prettyPrint));
+ GUI.FocusControl("Save");
+ Save();
}
+ }
- if (GUILayout.Button("Show in Explorer"))
+ private async void Save()
+ {
+ // Save the product config editor
+ await _productConfigEditor.Save();
+
+ // Save each of the platform config editors.
+ foreach (IConfigEditor editor in _platformConfigEditors)
{
- EditorUtility.RevealInFinder(ConfigDirectory);
+ await editor.Save();
}
}
}
-}
\ No newline at end of file
+}
+
+#endif
\ No newline at end of file
diff --git a/Assets/Plugins/Source/Editor/EditorWindows/EOSSettingsWindow.cs.meta b/Assets/Plugins/Source/Editor/EditorWindows/EOSSettingsWindow.cs.meta
index 2a409affd..1b6a004bd 100644
--- a/Assets/Plugins/Source/Editor/EditorWindows/EOSSettingsWindow.cs.meta
+++ b/Assets/Plugins/Source/Editor/EditorWindows/EOSSettingsWindow.cs.meta
@@ -1,5 +1,5 @@
fileFormatVersion: 2
-guid: bf93ccfa48b65594caf161002f4d3562
+guid: 43e463f37d0d1024eb3c8cff22f5f0be
MonoImporter:
externalObjects: {}
serializedVersion: 2
diff --git a/Assets/Plugins/Source/Editor/EditorWindows/EOSSettingsWindow_DEPRECATED.cs b/Assets/Plugins/Source/Editor/EditorWindows/EOSSettingsWindow_DEPRECATED.cs
new file mode 100644
index 000000000..021f02a57
--- /dev/null
+++ b/Assets/Plugins/Source/Editor/EditorWindows/EOSSettingsWindow_DEPRECATED.cs
@@ -0,0 +1,469 @@
+/*
+* Copyright (c) 2021 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.
+*/
+
+//#define ALLOW_CREATION_OF_EOS_CONFIG_AS_C_FILE
+
+// Uncomment the following line to show the old configuration window.
+//#define SHOW_DEPRECATED_SETTINGS_WINDOW
+
+namespace PlayEveryWare.EpicOnlineServices.Editor.Windows
+{
+#if !EOS_DISABLE
+ using Epic.OnlineServices.UI;
+#endif
+ using PlayEveryWare.EpicOnlineServices.Utility;
+ using System;
+ using System.Collections.Generic;
+ using System.IO;
+ using System.Linq;
+ using System.Reflection;
+ using System.Threading.Tasks;
+ using UnityEditor;
+ using UnityEngine;
+ using Utility;
+ using Config = EpicOnlineServices.Config;
+ using Random = System.Random;
+
+ [Serializable]
+ [Obsolete]
+ public class EOSSettingsWindow_DEPRECATED : EOSEditorWindow
+ {
+ private List platformSpecificConfigEditors;
+
+ private static readonly string ConfigDirectory = Path.Combine("Assets", "StreamingAssets", "EOS");
+
+ ///
+ /// Stores the current selected configuration tab.
+ /// "Main" is hard wired to be 0. By default "Main" is the selected tab.
+ /// Everything else is based on its position inside the
+ /// list, offset by -1.
+ /// For example if Android is at index 0 of the list, then when
+ /// toolbarInt is set to 1, the Android configuration should render.
+ ///
+ int toolbarInt { get; set; }
+
+ string[] toolbarTitleStrings;
+
+ EOSConfig mainEOSConfigFile;
+
+#if ALLOW_CREATION_OF_EOS_CONFIG_AS_C_FILE
+ string eosGeneratedCFilePath = "";
+#endif
+ bool prettyPrint;
+
+ public EOSSettingsWindow_DEPRECATED() : base("EOS Configuration")
+ {
+ }
+
+ // This compile conditional is here so that the old settings window
+ // is not available by default, but can be turned on if the scripting
+ // define exists (optionally by uncommenting the define at the top of
+ // this file).
+#if SHOW_DEPRECATED_SETTINGS_WINDOW
+ [MenuItem("EOS Plugin/EOS Configuration [DEPRECATED]", priority = 1)]
+ public static void ShowWindow()
+ {
+ var window = GetWindow();
+ window.SetIsEmbedded(false);
+ }
+#endif
+
+ [SettingsProvider]
+ public static SettingsProvider CreateProjectSettingsProvider()
+ {
+ var settingsWindow = CreateInstance();
+ string[] keywords = {"Epic", "EOS", "Online", "Services", "PlayEveryWare"};
+ // mark the editor window as being embedded, so it skips auto formatting stuff.
+ settingsWindow.SetIsEmbedded(true);
+ var provider = new SettingsProvider($"Preferences/{settingsWindow.WindowTitle}", SettingsScope.Project)
+ {
+ label = settingsWindow.WindowTitle,
+ keywords = keywords,
+ guiHandler = searchContext =>
+ {
+ settingsWindow.OnGUI();
+ }
+ };
+
+ return provider;
+ }
+
+ private string GenerateEOSGeneratedFile(EOSConfig aEOSConfig)
+ {
+ return string.Format(
+ String.Join("\n", "#define EOS_PRODUCT_NAME \"{0}\"", "#define EOS_PRODUCT_VERSION \"{1}\"",
+ "#define EOS_SANDBOX_ID \"{2}\"", "#define EOS_PRODUCT_ID \"{3}\"",
+ "#define EOS_DEPLOYMENT_ID \"{4}\"", "#define EOS_CLIENT_SECRET \"{5}\"",
+ "#define EOS_CLIENT_ID \"{6}\""), aEOSConfig.productName,
+ aEOSConfig.productVersion,
+ aEOSConfig.productID,
+ aEOSConfig.sandboxID,
+ aEOSConfig.deploymentID,
+ aEOSConfig.clientSecret,
+ aEOSConfig.clientID) +
+ @"
+_WIN32 || _WIN64
+#define PLATFORM_WINDOWS 1
+#endif
+
+#if _WIN64
+#define PLATFORM_64BITS 1
+#else
+#define PLATFORM_32BITS 1
+#endif
+
+ extern ""C"" __declspec(dllexport) char* __stdcall GetConfigAsJSONString()
+{
+ return ""{""
+ ""productName:"" EOS_PRODUCT_NAME "",""
+ ""productVersion: "" EOS_PRODUCT_VERSION "",""
+ ""productID: "" EOS_PRODUCT_ID "",""
+ ""sandboxID: "" EOS_SANDBOX_ID "",""
+ ""deploymentID: "" EOS_DEPLOYMENT_ID "",""
+ ""clientSecret: "" EOS_CLIENT_SECRET "",""
+ ""clientID: "" EOS_CLIENT_ID
+
+ ""}""
+ ;
+ }";
+ }
+
+ protected override async Task AsyncSetup()
+ {
+ if (!Directory.Exists(ConfigDirectory))
+ {
+ Directory.CreateDirectory(ConfigDirectory);
+ }
+
+ mainEOSConfigFile = await Config.GetAsync();
+
+ platformSpecificConfigEditors ??= new List();
+ List toolbarStrings = new(new[] { "Main" });
+ foreach (PlatformManager.Platform platform in Enum.GetValues(typeof(PlatformManager.Platform)))
+ {
+ // Windows platform overrides are currently not displayed,
+ // because the values for Windows are read from the main
+ // EpicOnlineServicesConfig.json file.
+ if (platform == PlatformManager.Platform.Windows)
+ {
+ continue;
+ }
+
+ if (!PlatformManager.TryGetConfigType(platform, out Type configType) || null == configType)
+ {
+ continue;
+ }
+
+ Type constructedType =
+ typeof(PlatformConfigEditor<>).MakeGenericType(configType);
+
+ if (Activator.CreateInstance(constructedType) is not IPlatformConfigEditor editor)
+ {
+ Debug.LogError($"Could not load config editor for platform \"{platform}\".");
+ continue;
+ }
+
+ // Do not add the platform if it is not currently available.
+ if (!editor.IsPlatformAvailable())
+ {
+ continue;
+ }
+
+ platformSpecificConfigEditors.Add(editor);
+
+ toolbarStrings.Add(editor.GetLabelText());
+ }
+
+ toolbarTitleStrings = toolbarStrings.ToArray();
+
+ await base.AsyncSetup();
+ }
+
+ private async Task Save(bool usePrettyFormat)
+ {
+ await mainEOSConfigFile.WriteAsync(usePrettyFormat);
+
+ foreach (var platformSpecificConfigEditor in platformSpecificConfigEditors)
+ {
+ await platformSpecificConfigEditor.Save(usePrettyFormat);
+ }
+
+#if ALLOW_CREATION_OF_EOS_CONFIG_AS_C_FILE
+ string generatedCFile = GenerateEOSGeneratedFile(mainEOSConfigFile.Data);
+ File.WriteAllText(Path.Combine(eosGeneratedCFilePath, "EOSGenerated.c"), generatedCFile);
+#endif
+
+ AssetDatabase.SaveAssets();
+ AssetDatabase.Refresh();
+ }
+
+ private void OnDefaultGUI()
+ {
+ GUILayout.Label("Epic Online Services", EditorStyles.boldLabel);
+
+ float originalLabelWidth = EditorGUIUtility.labelWidth;
+
+ EditorGUIUtility.labelWidth = 200;
+
+ // TODO: Id the Product Name userfacing? If so, we need loc
+ GUIEditorUtility.AssigningTextField("Product Name", ref mainEOSConfigFile.productName,
+ tooltip: "Product Name defined in the EOS Development Portal");
+
+ // TODO: bool to take product version form application version; should be automatic?
+ GUIEditorUtility.AssigningTextField("Product Version", ref mainEOSConfigFile.productVersion,
+ tooltip: "Version of Product");
+ GUIEditorUtility.AssigningTextField("Product ID", ref mainEOSConfigFile.productID,
+ tooltip: "Product ID defined in the EOS Development Portal");
+ GUIEditorUtility.AssigningTextField("Sandbox ID", ref mainEOSConfigFile.sandboxID,
+ tooltip: "Sandbox ID defined in the EOS Development Portal");
+ GUIEditorUtility.AssigningTextField("Deployment ID", ref mainEOSConfigFile.deploymentID,
+ tooltip: "Deployment ID defined in the EOS Development Portal");
+
+ GUIEditorUtility.AssigningBoolField("Is Server", ref mainEOSConfigFile.isServer,
+ tooltip: "Set to 'true' if the application is a dedicated game serve");
+
+ EditorGUILayout.LabelField("Sandbox Deployment Overrides");
+ if (mainEOSConfigFile.sandboxDeploymentOverrides == null)
+ {
+ mainEOSConfigFile.sandboxDeploymentOverrides = new List();
+ }
+
+ for (int i = 0; i < mainEOSConfigFile.sandboxDeploymentOverrides.Count; ++i)
+ {
+ EditorGUILayout.BeginHorizontal();
+ GUIEditorUtility.AssigningTextField("Sandbox ID",
+ ref mainEOSConfigFile.sandboxDeploymentOverrides[i].sandboxID,
+ tooltip: "Deployment ID will be overridden when Sandbox ID is set to this", labelWidth: 70);
+ mainEOSConfigFile.sandboxDeploymentOverrides[i].sandboxID =
+ mainEOSConfigFile.sandboxDeploymentOverrides[i].sandboxID.Trim();
+ GUIEditorUtility.AssigningTextField("Deployment ID",
+ ref mainEOSConfigFile.sandboxDeploymentOverrides[i].deploymentID,
+ tooltip: "Deployment ID to use for override", labelWidth: 90);
+ mainEOSConfigFile.sandboxDeploymentOverrides[i].deploymentID =
+ mainEOSConfigFile.sandboxDeploymentOverrides[i].deploymentID.Trim();
+ if (GUILayout.Button("Remove", GUILayout.MaxWidth(70)))
+ {
+ mainEOSConfigFile.sandboxDeploymentOverrides.RemoveAt(i);
+ }
+
+ EditorGUILayout.EndHorizontal();
+ }
+
+ if (GUILayout.Button("Add", GUILayout.MaxWidth(100)))
+ {
+ mainEOSConfigFile.sandboxDeploymentOverrides.Add(new SandboxDeploymentOverride());
+ }
+
+ GUIEditorUtility.AssigningULongToStringField("Thread Affinity: networkWork",
+ ref mainEOSConfigFile.ThreadAffinity_networkWork,
+ tooltip: "(Optional) Specifies thread affinity for network management that is not IO");
+ GUIEditorUtility.AssigningULongToStringField("Thread Affinity: storageIO",
+ ref mainEOSConfigFile.ThreadAffinity_storageIO,
+ tooltip: "(Optional) Specifies affinity for threads that will interact with a storage device");
+ GUIEditorUtility.AssigningULongToStringField("Thread Affinity: webSocketIO",
+ ref mainEOSConfigFile.ThreadAffinity_webSocketIO,
+ tooltip: "(Optional) Specifies affinity for threads that generate web socket IO");
+ GUIEditorUtility.AssigningULongToStringField("Thread Affinity: P2PIO",
+ ref mainEOSConfigFile.ThreadAffinity_P2PIO,
+ tooltip:
+ "(Optional) Specifies affinity for any thread that will generate IO related to P2P traffic and management");
+ GUIEditorUtility.AssigningULongToStringField("Thread Affinity: HTTPRequestIO",
+ ref mainEOSConfigFile.ThreadAffinity_HTTPRequestIO,
+ tooltip: "(Optional) Specifies affinity for any thread that will generate http request IO");
+ GUIEditorUtility.AssigningULongToStringField("Thread Affinity: RTCIO",
+ ref mainEOSConfigFile.ThreadAffinity_RTCIO,
+ tooltip:
+ "(Optional) Specifies affinity for any thread that will generate IO related to RTC traffic and management");
+
+ string timeBudgetAsString = "";
+
+ if (mainEOSConfigFile.tickBudgetInMilliseconds != 0)
+ {
+ timeBudgetAsString = mainEOSConfigFile.tickBudgetInMilliseconds.ToString();
+ }
+
+ GUIEditorUtility.AssigningTextField("Time Budget in milliseconds", ref timeBudgetAsString,
+ tooltip: "(Optional) Define the maximum amount of execution time the EOS SDK can use each frame");
+
+ if (timeBudgetAsString.Length != 0)
+ {
+ try
+ {
+ mainEOSConfigFile.tickBudgetInMilliseconds = Convert.ToUInt32(timeBudgetAsString, 10);
+ }
+ catch
+ {
+ Debug.LogWarning($"{nameof(EOSSettingsWindow_DEPRECATED)} ({nameof(OnDefaultGUI)}): {nameof(mainEOSConfigFile.tickBudgetInMilliseconds)} must be convertable to int, but string could not be parsed. The provided string is \"{timeBudgetAsString}\". This value is ignored.");
+ }
+ }
+ else
+ {
+ mainEOSConfigFile.tickBudgetInMilliseconds = 0;
+ }
+
+ string taskNetworkTimeoutSecondsAsString = "";
+
+ if (mainEOSConfigFile.taskNetworkTimeoutSeconds != 0)
+ {
+ taskNetworkTimeoutSecondsAsString = mainEOSConfigFile.taskNetworkTimeoutSeconds.ToString();
+ }
+#if !EOS_DISABLE
+ GUIEditorUtility.AssigningTextField("Task Network Timeout Seconds", ref taskNetworkTimeoutSecondsAsString,
+ tooltip: $"(Optional) Define the maximum amount of time network calls will run in the EOS SDK before timing out while the {nameof(Epic.OnlineServices.Platform.NetworkStatus)} is not {nameof(Epic.OnlineServices.Platform.NetworkStatus.Online)}. Defaults to 30 seconds if not set or less than or equal to zero.");
+#endif
+ if (taskNetworkTimeoutSecondsAsString.Length != 0)
+ {
+ try
+ {
+ mainEOSConfigFile.taskNetworkTimeoutSeconds = Convert.ToDouble(taskNetworkTimeoutSecondsAsString);
+ }
+ catch
+ {
+ Debug.LogWarning($"{nameof(EOSSettingsWindow_DEPRECATED)} ({nameof(OnDefaultGUI)}): {nameof(mainEOSConfigFile.taskNetworkTimeoutSeconds)} must be convertable to int, but string could not be parsed. The provided string is \"{taskNetworkTimeoutSecondsAsString}\". This value is ignored.");
+ }
+ }
+ else
+ {
+ mainEOSConfigFile.taskNetworkTimeoutSeconds = 0;
+ }
+
+ EditorGUIUtility.labelWidth = originalLabelWidth;
+
+ // This will be used on Windows via the nativerender code, unless otherwise specified
+ EditorGUILayout.Separator();
+ GUILayout.Label("Default Client Credentials", EditorStyles.boldLabel);
+ GUIEditorUtility.AssigningTextField("Client ID", ref mainEOSConfigFile.clientID,
+ tooltip: "Client ID defined in the EOS Development Portal");
+ GUIEditorUtility.AssigningTextField("Client Secret", ref mainEOSConfigFile.clientSecret,
+ tooltip: "Client Secret defined in the EOS Development Portal");
+ GUI.SetNextControlName("KeyText");
+ GUIEditorUtility.AssigningTextField("Encryption Key", ref mainEOSConfigFile.encryptionKey,
+ tooltip: "Used to decode files previously encoded and stored in EOS");
+ GUI.SetNextControlName("GenerateButton");
+ if (GUILayout.Button("Generate"))
+ {
+ //generate random 32-byte hex sequence
+ var rng = new Random(SystemInfo.deviceUniqueIdentifier.GetHashCode() *
+ (int)(EditorApplication.timeSinceStartup * 1000));
+ var keyBytes = new byte[32];
+ rng.NextBytes(keyBytes);
+ mainEOSConfigFile.encryptionKey = BitConverter.ToString(keyBytes).Replace("-", "");
+ //unfocus key input field so the new key is shown
+ if (GUI.GetNameOfFocusedControl() == "KeyText")
+ {
+ GUI.FocusControl("GenerateButton");
+ }
+ }
+
+#if !EOS_DISABLE
+ if (!EOSClientCredentials.IsEncryptionKeyValid(mainEOSConfigFile.encryptionKey))
+ {
+ int keyLength = mainEOSConfigFile.encryptionKey?.Length ?? 0;
+ EditorGUILayout.HelpBox(
+ "Used for Player Data Storage and Title Storage. Must be left blank if unused. Encryption key must be 64 hex characters (0-9,A-F). Current length is " +
+ keyLength + ".", MessageType.Warning);
+ }
+
+ GUIEditorUtility.AssigningEnumField(
+ "Platform Flags",
+ ref mainEOSConfigFile.platformOptionsFlags,
+ 190,
+ "Flags used to initialize EOS Platform. Available " +
+ "flags are defined in PlatformFlags.cs");
+
+ GUIEditorUtility.AssigningEnumField(
+ "Auth Scope Flags",
+ ref mainEOSConfigFile.authScopeOptionsFlags,
+ 190,
+ "Flags used to specify Auth Scope during login. " +
+ "Available flags are defined in AuthScopeFlags.cs");
+
+ GUIEditorUtility.AssigningEnumField(
+ "Default Activate Overlay Button",
+ ref mainEOSConfigFile.toggleFriendsButtonCombination,
+ 190,
+ "Users can press the button(s) associated with this " +
+ "value to activate the Epic Social Overlay. Not all " +
+ "combinations are valid; the SDK will log an error at the " +
+ "start of runtime if an invalid combination is selected.");
+#endif
+
+ GUIEditorUtility.AssigningBoolField("Always send Input to Overlay",
+ ref mainEOSConfigFile.alwaysSendInputToOverlay, 190,
+ "If true, the plugin will always send input to the overlay from the C# side to native, and handle showing the overlay. This doesn't always mean input makes it to the EOS SDK.");
+
+ }
+
+ protected override void RenderWindow()
+ {
+ int xCount = (int)(EditorGUIUtility.currentViewWidth / 200);
+
+ // Determine the new toolbarInt state, so that it can be compared
+ // against the current value, determining if this changed
+ int newToolbarInt = GUILayout.SelectionGrid(toolbarInt, toolbarTitleStrings, xCount);
+
+ // If the selection is now different, deselect all selected textboxes
+ // This is to address #EOS-2085: Fix Editor Phantom Fields,
+ // wherein selecting a text box, then navigating to another config
+ // tab, would result in a "phantom" value appearing
+ if (newToolbarInt != toolbarInt && EditorGUIUtility.keyboardControl > 0)
+ {
+ GUI.FocusControl(null);
+ }
+
+ toolbarInt = newToolbarInt;
+
+ switch (toolbarInt)
+ {
+ case 0:
+ OnDefaultGUI();
+ break;
+ default:
+ if (platformSpecificConfigEditors.Count > toolbarInt - 1)
+ {
+ platformSpecificConfigEditors[toolbarInt - 1].RenderAsync();
+ }
+
+ break;
+ }
+
+#if ALLOW_CREATION_OF_EOS_CONFIG_AS_C_FILE
+ if (GUILayout.Button("Pick Path For Generated C File"))
+ {
+ eosGeneratedCFilePath = EditorUtility.OpenFolderPanel("Pick Path For Generated C File", "", "");
+ }
+#endif
+ EditorGUILayout.Separator();
+ GUILayout.Label("Config Format Options", EditorStyles.boldLabel);
+ GUIEditorUtility.AssigningBoolField("Save JSON in 'Pretty' Format", ref prettyPrint, 190);
+ if (GUILayout.Button("Save All Changes"))
+ {
+ Task.Run(() => Save(prettyPrint));
+ }
+
+ if (GUILayout.Button("Show in Explorer"))
+ {
+ EditorUtility.RevealInFinder(ConfigDirectory);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Assets/Plugins/Source/Editor/Platforms/iOS/IOSConfigEditor.cs.meta b/Assets/Plugins/Source/Editor/EditorWindows/EOSSettingsWindow_DEPRECATED.cs.meta
similarity index 83%
rename from Assets/Plugins/Source/Editor/Platforms/iOS/IOSConfigEditor.cs.meta
rename to Assets/Plugins/Source/Editor/EditorWindows/EOSSettingsWindow_DEPRECATED.cs.meta
index b845c2b64..2a409affd 100644
--- a/Assets/Plugins/Source/Editor/Platforms/iOS/IOSConfigEditor.cs.meta
+++ b/Assets/Plugins/Source/Editor/EditorWindows/EOSSettingsWindow_DEPRECATED.cs.meta
@@ -1,5 +1,5 @@
fileFormatVersion: 2
-guid: b60dbeaa4bae3b444b1ffaffa25f9d74
+guid: bf93ccfa48b65594caf161002f4d3562
MonoImporter:
externalObjects: {}
serializedVersion: 2
diff --git a/Assets/Plugins/Source/Editor/EditorWindows/EOSUnitTestSettingsWindow.cs b/Assets/Plugins/Source/Editor/EditorWindows/EOSUnitTestSettingsWindow.cs
index df137eb8b..e7378acb0 100644
--- a/Assets/Plugins/Source/Editor/EditorWindows/EOSUnitTestSettingsWindow.cs
+++ b/Assets/Plugins/Source/Editor/EditorWindows/EOSUnitTestSettingsWindow.cs
@@ -20,6 +20,8 @@
* SOFTWARE.
*/
+#if !EOS_DISABLE
+
namespace PlayEveryWare.EpicOnlineServices.Tests.Editor
{
using EpicOnlineServices.Editor;
@@ -37,7 +39,7 @@ public class EOSUnitTestSettingsWindow : EOSEditorWindow
public EOSUnitTestSettingsWindow() : base("EOS Unit Test Configuration") { }
- [MenuItem("Tools/EOS Plugin/Advanced/Unit Test Configuration")]
+ [MenuItem("EOS Plugin/Advanced/Unit Test Configuration")]
public static void OpenUnitTestSettingsWindow()
{
GetWindow();
@@ -60,3 +62,4 @@ protected async override void RenderWindow()
}
}
}
+#endif
\ No newline at end of file
diff --git a/Assets/Plugins/Source/Editor/EditorWindows/InstallEOSZipWindow.cs b/Assets/Plugins/Source/Editor/EditorWindows/InstallEOSZipWindow.cs
index afa45e6d6..13d06f69f 100644
--- a/Assets/Plugins/Source/Editor/EditorWindows/InstallEOSZipWindow.cs
+++ b/Assets/Plugins/Source/Editor/EditorWindows/InstallEOSZipWindow.cs
@@ -66,7 +66,7 @@ private class PlatformImportInfoList
private string pathToImportDescDirectory;
private PlatformImportInfoList importInfoList;
- [MenuItem("Tools/EOS Plugin/Install EOS zip")]
+ [MenuItem("EOS Plugin/Advanced/Install EOS zip")]
public static void ShowWindow()
{
GetWindow();
diff --git a/Assets/Plugins/Source/Editor/EditorWindows/LogLevelWindow.cs b/Assets/Plugins/Source/Editor/EditorWindows/LogLevelWindow.cs
index 37ad0b31b..525bfce4c 100644
--- a/Assets/Plugins/Source/Editor/EditorWindows/LogLevelWindow.cs
+++ b/Assets/Plugins/Source/Editor/EditorWindows/LogLevelWindow.cs
@@ -45,7 +45,7 @@ public LogLevelWindow() : base("Log Level Configuration")
{
}
- [MenuItem("Tools/EOS Plugin/Log Level Configuration")]
+ [MenuItem("EOS Plugin/Log Level Configuration", priority = 3)]
public static void ShowWindow()
{
GetWindow();
diff --git a/Assets/Plugins/Source/Editor/EditorWindows/PluginVersionWindow.cs b/Assets/Plugins/Source/Editor/EditorWindows/PluginVersionWindow.cs
index a0171048e..dfd478231 100644
--- a/Assets/Plugins/Source/Editor/EditorWindows/PluginVersionWindow.cs
+++ b/Assets/Plugins/Source/Editor/EditorWindows/PluginVersionWindow.cs
@@ -54,7 +54,7 @@ private class UPMPackage
public string version;
}
- [MenuItem("Tools/EOS Plugin/Version", false, 100)]
+ [MenuItem("EOS Plugin/Version", false, 4)]
public static void ShowWindow()
{
GetWindow();
diff --git a/Assets/Plugins/Source/Editor/Platforms/Android/AndroidBuilder.cs b/Assets/Plugins/Source/Editor/Platforms/Android/AndroidBuilder.cs
index f87030fe9..b540cd9d2 100644
--- a/Assets/Plugins/Source/Editor/Platforms/Android/AndroidBuilder.cs
+++ b/Assets/Plugins/Source/Editor/Platforms/Android/AndroidBuilder.cs
@@ -20,6 +20,8 @@
* SOFTWARE.
*/
+#if !EOS_DISABLE
+
namespace PlayEveryWare.EpicOnlineServices.Editor.Build
{
using Config;
@@ -344,7 +346,7 @@ private static void ConfigureGradleTemplateProperties()
private static void ConfigureEOSDependentLibrary()
{
- string clientIDAsLower = Config.Get().clientID.ToLower();
+ string clientIDAsLower = PlatformManager.GetPlatformConfig().clientCredentials.ClientId.ToLower();
var pathToEOSValuesConfig = GetAndroidEOSValuesConfigPath();
var currentEOSValuesConfigAsXML = new System.Xml.XmlDocument();
@@ -398,4 +400,6 @@ private static void CopyFromSourceToPluginFolder_Android(string sourcePath, stri
Path.Combine(destPath, filename), true);
}
}
-}
\ No newline at end of file
+}
+
+#endif
\ No newline at end of file
diff --git a/Assets/Plugins/Source/Editor/Platforms/Windows/WindowsBuilder.cs b/Assets/Plugins/Source/Editor/Platforms/Windows/WindowsBuilder.cs
index 8bc9be356..a8cbfefc3 100644
--- a/Assets/Plugins/Source/Editor/Platforms/Windows/WindowsBuilder.cs
+++ b/Assets/Plugins/Source/Editor/Platforms/Windows/WindowsBuilder.cs
@@ -24,6 +24,7 @@ namespace PlayEveryWare.EpicOnlineServices.Editor.Build
{
#if !EOS_DISABLE
using Epic.OnlineServices.Platform;
+ using Extensions;
#endif
using Config;
using Config = EpicOnlineServices.Config;
@@ -83,17 +84,21 @@ public override void PostBuild(BuildReport report)
private static async void ConfigureAndInstallBootstrapper(BuildReport report)
{
-#if !EOS_DISABLE
+#if EOS_DISABLE
+ // If EOS_DISABLE is defined, then the bootstrapper should never be included
+ await System.Threading.Tasks.Task.CompletedTask;
+ return;
+#else
// Determine if 'DisableOverlay' is set in Platform Flags. If it is, then the EOSBootstrapper.exe is not included in the build,
// because without needing the overlay, the EOSBootstrapper.exe is not useful to users of the plugin
- EOSConfig configuration = await Config.GetAsync();
- PlatformFlags configuredFlags = configuration.GetPlatformFlags();
+ PlatformConfig configuration = PlatformManager.GetPlatformConfig();
+ PlatformFlags configuredFlags = configuration.platformOptionsFlags.Unwrap();
if (configuredFlags.HasFlag(PlatformFlags.DisableOverlay))
{
Debug.Log($"The '{nameof(PlatformFlags.DisableOverlay)}' flag has been configured, EOSBootstrapper.exe will not be included in this build.");
return;
}
-#endif
+
/*
* NOTE:
*
@@ -123,7 +128,7 @@ private static async void ConfigureAndInstallBootstrapper(BuildReport report)
*/
// Determine whether to install EAC
-
+
ToolsConfig toolsConfig = await Config.GetAsync();
string bootstrapperName = null;
@@ -150,6 +155,7 @@ private static async void ConfigureAndInstallBootstrapper(BuildReport report)
InstallBootStrapper(bootstrapperTarget, installDirectory, pathToEOSBootStrapperTool,
bootstrapperName);
+#endif
}
private static void InstallBootStrapper(string appFilenameExe, string installDirectory,
diff --git a/Assets/Plugins/Source/Editor/Platforms/iOS/IOSBuilder.cs b/Assets/Plugins/Source/Editor/Platforms/iOS/IOSBuilder.cs
index 569a640b4..615e61452 100644
--- a/Assets/Plugins/Source/Editor/Platforms/iOS/IOSBuilder.cs
+++ b/Assets/Plugins/Source/Editor/Platforms/iOS/IOSBuilder.cs
@@ -26,7 +26,6 @@ namespace PlayEveryWare.EpicOnlineServices.Editor.Build
using System.IO;
using UnityEditor;
using UnityEditor.Build.Reporting;
- using Utility;
// This conditional is here so that no compiler errors will happen if the
// Unity Editor is not configured to build for iOS.
diff --git a/Assets/Plugins/Source/Editor/Utility/CreateXMLLinkUtility.cs b/Assets/Plugins/Source/Editor/Utility/CreateXMLLinkUtility.cs
index 4aaff04c5..cd69fee9c 100644
--- a/Assets/Plugins/Source/Editor/Utility/CreateXMLLinkUtility.cs
+++ b/Assets/Plugins/Source/Editor/Utility/CreateXMLLinkUtility.cs
@@ -28,7 +28,7 @@ namespace PlayEveryWare.EpicOnlineServices.Editor.Utility
{
public static class CreateXMLLinkUtility
{
- [MenuItem("Tools/EOS Plugin/Create link.xml")]
+ [MenuItem("EOS Plugin/Advanced/Create link.xml")]
static void CreateLinkXml()
{
var linkSourceFilePath = Path.Combine("Packages", EOSPackageInfo.PackageName, "Editor", "link.xml");
@@ -55,7 +55,7 @@ static void CreateLinkXml()
}
//disable menu item if not running within a UPM package
- [MenuItem("Tools/EOS Plugin/Create link.xml", true)]
+ [MenuItem("EOS Plugin/Advanced/Create link.xml", true)]
static bool ValidateCreateLinkXml()
{
return Directory.Exists(Path.Combine("Packages", EOSPackageInfo.PackageName, "Editor"));
diff --git a/Assets/Plugins/Source/Editor/Utility/EACUtility.cs b/Assets/Plugins/Source/Editor/Utility/EACUtility.cs
index 23a6484cb..42f74a7b8 100644
--- a/Assets/Plugins/Source/Editor/Utility/EACUtility.cs
+++ b/Assets/Plugins/Source/Editor/Utility/EACUtility.cs
@@ -22,6 +22,7 @@
namespace PlayEveryWare.EpicOnlineServices.Editor.Build
{
+ using Common.Extensions;
using UnityEditor.Build.Reporting;
using UnityEditor;
using UnityEngine;
@@ -365,17 +366,18 @@ private static void ReplaceFileContentVars(string filepath, string buildExeName)
string fileContents = reader.ReadToEnd();
reader.Close();
- EOSConfig eosConfig = Config.Get();
+ ProductConfig productConfig = Config.Get();
+ PlatformConfig platformConfig = PlatformManager.GetPlatformConfig();
var sb = new System.Text.StringBuilder(fileContents);
sb.Replace("", Application.productName);
sb.Replace("", buildExeName);
sb.Replace("", Path.GetFileNameWithoutExtension(buildExeName));
- sb.Replace("", eosConfig.productName);
- sb.Replace("", eosConfig.productID);
- sb.Replace("", eosConfig.sandboxID);
- sb.Replace("", eosConfig.deploymentID);
+ sb.Replace("", productConfig.ProductName);
+ sb.Replace("", productConfig.ProductId.ToString("N").ToLowerInvariant());
+ sb.Replace("", platformConfig.deployment.SandboxId.ToString());
+ sb.Replace("", platformConfig.deployment.DeploymentId.ToString("N").ToLowerInvariant());
fileContents = sb.ToString();
@@ -420,7 +422,7 @@ public static void ConfigureEAC(BuildReport report)
if (!string.IsNullOrWhiteSpace(toolPath))
{
- var productId = (Config.Get()).productID;
+ var productId = Config.Get().ProductId.ToString("N").ToLowerInvariant();
GenerateIntegrityCert(report, toolPath, productId,
toolsConfig.pathToEACPrivateKey, toolsConfig.pathToEACCertificate, cfgPath);
}
diff --git a/Assets/Plugins/Source/Editor/Utility/GUIEditorUtility.cs b/Assets/Plugins/Source/Editor/Utility/GUIEditorUtility.cs
index c9055ce5b..3e53c77a6 100644
--- a/Assets/Plugins/Source/Editor/Utility/GUIEditorUtility.cs
+++ b/Assets/Plugins/Source/Editor/Utility/GUIEditorUtility.cs
@@ -22,17 +22,42 @@
namespace PlayEveryWare.EpicOnlineServices.Editor.Utility
{
+ using Common;
+
+
+ using Epic.OnlineServices.Platform;
+
using EpicOnlineServices.Utility;
using System;
using System.Collections.Generic;
+ using System.Globalization;
+ using System.Linq;
+ using System.Reflection;
using UnityEditor;
+ using UnityEditorInternal;
using UnityEngine;
+ using Config = EpicOnlineServices.Config;
public static class GUIEditorUtility
{
- private const float MaximumButtonWidth = 100f;
+ ///
+ /// Maximum width allowed for a button.
+ ///
+ private const float MAXIMUM_BUTTON_WIDTH = 100f;
+
+ ///
+ /// Style utilized for hint label overlays.
+ ///
+ private static readonly GUIStyle HINT_STYLE = new(GUI.skin.label)
+ {
+ normal = new GUIStyleState() { textColor = Color.gray },
+ fontStyle = FontStyle.Italic
+ };
- private static GUIContent CreateGUIContent(string label, string tooltip = null)
+ private const int HINT_RECT_ADJUST_X = 2;
+ private const int HINT_RECT_ADJUST_Y = 1;
+
+ private static GUIContent CreateGUIContent(string label, string tooltip = null, bool bold = false)
{
label ??= "";
return tooltip == null ? new GUIContent(label) : new GUIContent(label, tooltip);
@@ -45,26 +70,21 @@ private static GUIContent CreateGUIContent(string label, string tooltip = null)
/// Text to display when the foldout is shown.
/// Text to display when the foldout is closed.
/// Function to call when foldout is open.
- public static void RenderFoldout(ref bool isOpen, string hideLabel, string showLabel, Action renderContents)
+ public static bool RenderFoldout(bool isOpen, string hideLabel, string showLabel, Action renderContents, string tooltip = null)
{
- isOpen = EditorGUILayout.Foldout(isOpen, (isOpen) ? hideLabel : showLabel);
+ isOpen = EditorGUILayout.Foldout(isOpen, isOpen ? hideLabel : showLabel);
if (!isOpen)
{
- return;
+ return false;
}
- // This simulates the foldout being indented
- GUILayout.BeginVertical();
- GUILayout.BeginHorizontal();
- GUILayout.Space(20f);
renderContents();
- GUILayout.EndHorizontal();
- GUILayout.Space(10f);
- GUILayout.EndVertical();
+ return true;
}
- public static void AssigningFlagTextField(string label, ref List flags, float labelWidth = -1, string tooltip = null)
+ public static void AssigningTextField(string label, ref string value, float labelWidth = -1,
+ string tooltip = null)
{
float originalLabelWidth = EditorGUIUtility.labelWidth;
if (labelWidth >= 0)
@@ -72,14 +92,18 @@ public static void AssigningFlagTextField(string label, ref List flags,
EditorGUIUtility.labelWidth = labelWidth;
}
- var collectedEOSplatformFlags = String.Join("|", flags ?? new List());
- var platformFlags = EditorGUILayout.TextField(CreateGUIContent(label, tooltip), collectedEOSplatformFlags);
- flags = new List(platformFlags.Split('|'));
+ var newValue = EditorGUILayout.TextField(CreateGUIContent(label, tooltip), value ?? "",
+ GUILayout.ExpandWidth(true));
+ if (newValue != null)
+ {
+ value = newValue;
+ }
EditorGUIUtility.labelWidth = originalLabelWidth;
}
- public static void AssigningTextField(string label, ref string value, float labelWidth = -1, string tooltip = null)
+ public static void AssigningULongToStringField(string label, ref ulong? value, float labelWidth = -1,
+ string tooltip = null)
{
float originalLabelWidth = EditorGUIUtility.labelWidth;
if (labelWidth >= 0)
@@ -87,16 +111,45 @@ public static void AssigningTextField(string label, ref string value, float labe
EditorGUIUtility.labelWidth = labelWidth;
}
- var newValue = EditorGUILayout.TextField(CreateGUIContent(label, tooltip), value ?? "", GUILayout.ExpandWidth(true));
- if (newValue != null)
+ EditorGUILayout.BeginHorizontal();
+
+ var guiLabel = CreateGUIContent(label, tooltip);
+ string textToDisplay = string.Empty;
+
+ if (value.HasValue)
{
- value = newValue;
+ textToDisplay = value.Value.ToString();
}
+ string newTextValue = EditorGUILayout.TextField(guiLabel, textToDisplay, GUILayout.ExpandWidth(true));
+
+ if (GUILayout.Button("Clear", GUILayout.MaxWidth(50)))
+ {
+ value = null;
+
+ // Remove focus from the control so it doesn't display "phantom"
+ // values
+ GUI.FocusControl(null);
+ }
+ else
+ {
+ if (string.IsNullOrEmpty(newTextValue))
+ {
+ value = null;
+ }
+ else if (ulong.TryParse(newTextValue, out ulong newLongValue))
+ {
+ value = newLongValue;
+ }
+ }
+
+ EditorGUILayout.EndHorizontal();
+
EditorGUIUtility.labelWidth = originalLabelWidth;
}
- public static void AssigningULongToStringField(string label, ref string value, float labelWidth = -1, string tooltip = null)
+ public static void AssigningBoolField(string label, ref bool value, float labelWidth = -1,
+ string tooltip = null)
{
float originalLabelWidth = EditorGUIUtility.labelWidth;
if (labelWidth >= 0)
@@ -104,43 +157,60 @@ public static void AssigningULongToStringField(string label, ref string value, f
EditorGUIUtility.labelWidth = labelWidth;
}
- try
- {
- EditorGUILayout.BeginHorizontal();
- var newValueAsString = EditorGUILayout.TextField(CreateGUIContent(label, tooltip), value == null ? "" : value, GUILayout.ExpandWidth(true));
+ var newValue = EditorGUILayout.Toggle(CreateGUIContent(label, tooltip), value, GUILayout.ExpandWidth(true));
+ value = newValue;
- if (GUILayout.Button("Clear", GUILayout.MaxWidth(50)))
- {
- value = null;
- }
- else
- {
- if (string.IsNullOrWhiteSpace(newValueAsString))
- {
- value = null;
- return;
- }
+ EditorGUIUtility.labelWidth = originalLabelWidth;
+ }
- var valueAsLong = ulong.Parse(newValueAsString);
- value = valueAsLong.ToString();
- }
+ public static void AssigningFloatToStringField(string label, ref float? value, float labelWidth = -1,
+ string tooltip = null)
+ {
+ float originalLabelWidth = EditorGUIUtility.labelWidth;
+ if (labelWidth >= 0)
+ {
+ EditorGUIUtility.labelWidth = labelWidth;
}
- catch (FormatException)
+
+ EditorGUILayout.BeginHorizontal();
+ var guiLabel = CreateGUIContent(label, tooltip);
+ string textToDisplay = string.Empty;
+
+ if (value.HasValue)
{
- value = null;
+ textToDisplay = value.Value.ToString(CultureInfo.InvariantCulture);
}
- catch (OverflowException)
+
+ string newTextValue = EditorGUILayout.TextField(guiLabel, textToDisplay, GUILayout.ExpandWidth(true));
+
+ if (GUILayout.Button("Clear", GUILayout.MaxWidth(50)))
{
+ value = null;
+
+ // Remove focus from the control so it doesn't display "phantom"
+ // values
+ GUI.FocusControl(null);
}
- finally
+ else
{
- EditorGUILayout.EndHorizontal();
+ if (string.IsNullOrEmpty(newTextValue))
+ {
+ value = null;
+ }
+ else if (float.TryParse(newTextValue, out float newFloatValue))
+ {
+ value = newFloatValue;
+ }
}
+ GUILayout.EndHorizontal();
+
+
EditorGUIUtility.labelWidth = originalLabelWidth;
}
-
- public static void AssigningBoolField(string label, ref bool value, float labelWidth = -1, string tooltip = null)
+
+ public static void AssigningEnumField(string label, ref T value, float labelWidth = -1,
+ string tooltip = null) where T : Enum
{
float originalLabelWidth = EditorGUIUtility.labelWidth;
if (labelWidth >= 0)
@@ -148,76 +218,992 @@ public static void AssigningBoolField(string label, ref bool value, float labelW
EditorGUIUtility.labelWidth = labelWidth;
}
- var newValue = EditorGUILayout.Toggle(CreateGUIContent(label, tooltip), value, GUILayout.ExpandWidth(true));
+ var newValue =
+ (T)EditorGUILayout.EnumFlagsField(CreateGUIContent(label, tooltip), value, GUILayout.ExpandWidth(true));
value = newValue;
EditorGUIUtility.labelWidth = originalLabelWidth;
}
- public static void AssigningFloatToStringField(string label, ref string value, float labelWidth = -1, string tooltip = null)
+ #region New methods for rendering input fields
+
+ ///
+ /// Use reflection to retrieve a collection of fields that have been
+ /// assigned custom ConfigFieldAttribute attributes, grouping by group,
+ /// and sorting by group.
+ ///
+ /// A collection of config fields.
+ private static IOrderedEnumerable> GetFieldsByGroup()
+ {
+ return typeof(T).GetFields(BindingFlags.Public | BindingFlags.Instance)
+ .Where(field => field.GetCustomAttribute() != null)
+ .Select(info => (info, info.GetCustomAttribute()))
+ .GroupBy(r => r.Item2.Group)
+ .OrderBy(group => group.Key);
+ }
+
+ private static IOrderedEnumerable> GetMembersByGroup()
{
- float originalLabelWidth = EditorGUIUtility.labelWidth;
- if (labelWidth >= 0)
+ var fields = typeof(T).GetFields(BindingFlags.Public | BindingFlags.Instance);
+ var properties = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);
+
+ var members = fields.Cast().Concat(properties.Cast());
+
+ return members
+ .Where(member => member.GetCustomAttribute() != null)
+ .Select(member => (MemberInfo: member, FieldDetails: member.GetCustomAttribute()))
+ .GroupBy(r => r.FieldDetails.Group)
+ .OrderBy(group => group.Key);
+ }
+
+ delegate object RenderInputDelegate(ConfigFieldAttribute attribute, object value, float labelWidth);
+
+ static readonly Dictionary RenderInputMethods = new()
+ {
+ { typeof(Deployment), (attr, val, width) => RenderInput(attr, (Deployment)val, width) },
+ { typeof(string), (attr, val, width) => RenderInput(attr, (string)val, width) },
+ { typeof(ulong), (attr, val, width) => RenderInput(attr, (ulong)val, width) },
+ { typeof(uint), (attr, val, width) => RenderInput(attr, (uint)val, width) },
+ { typeof(ProductionEnvironments), (attr, val, width) => RenderInput(attr, (ProductionEnvironments)val, width) },
+ { typeof(float), (attr, val, width) => RenderInput(attr, (float)val, width) },
+ { typeof(double), (attr, val, width) => RenderInput(attr, (double)val, width) },
+ { typeof(bool), (attr, val, width) => RenderInput(attr, (bool)val, width) },
+ { typeof(Version), (attr, val, width) => RenderInput(attr, (Version)val, width) },
+ { typeof(Guid), (attr, val, width) => RenderInput(attr, (Guid)val, width)},
+ { typeof(List), (attr, val, width) => RenderInput(attr, (List)val, width)},
+ { typeof(EOSClientCredentials), (attr, val, width) => RenderInput(attr, (EOSClientCredentials)val, width) },
+ { typeof(SetOfNamed), (attr, val, width) => RenderInput(attr, (SetOfNamed)val, width) },
+ { typeof(WrappedInitializeThreadAffinity), (attr, val, width) => RenderInput(attr, (WrappedInitializeThreadAffinity)val, width) },
+
+ // Add other specific types as needed
+ };
+
+ static readonly Dictionary FieldHandlers = new()
+ {
+ { ConfigFieldType.SetOfClientCredentials, HandleField> },
+ { ConfigFieldType.ClientCredentials, HandleField },
+ { ConfigFieldType.WrappedInitializeThreadAffinity, HandleField },
+ { ConfigFieldType.Text, HandleField },
+ { ConfigFieldType.FilePath, (target, fieldDetails, getValue, setValue, labelWidth) =>
+ HandleField(target, (FilePathFieldAttribute)fieldDetails, getValue, setValue, labelWidth) },
+ { ConfigFieldType.Flag, HandleField },
+ { ConfigFieldType.DirectoryPath, (target, fieldDetails, getValue, setValue, labelWidth) =>
+ HandleField(target, (DirectoryPathFieldAttribute)fieldDetails, getValue, setValue, labelWidth) },
+ { ConfigFieldType.Ulong, HandleField },
+ { ConfigFieldType.Double, HandleField },
+ { ConfigFieldType.TextList, HandleField> },
+ { ConfigFieldType.Uint, HandleField },
+ { ConfigFieldType.Float, HandleField },
+ { ConfigFieldType.ProductionEnvironments, HandleField },
+ { ConfigFieldType.Version, HandleField },
+ { ConfigFieldType.Deployment, HandleField },
+ { ConfigFieldType.Guid, HandleField },
+ { ConfigFieldType.Button, HandleButtonField },
+ { ConfigFieldType.Enum, HandleEnumField },
+
+ // Add other field types as needed
+ };
+
+ private static Dictionary _foldoutStates = new();
+
+ private static T RenderInput(ConfigFieldAttribute attribute, T value, float labelWidth)
+ {
+ if (typeof(T) != typeof(WrappedInitializeThreadAffinity))
{
- EditorGUIUtility.labelWidth = labelWidth;
+ return value;
}
- try
+ // Create a foldout label with a tooltip
+ GUIContent foldoutContent = new(attribute.Label, attribute.ToolTip);
+
+ if (!_foldoutStates.ContainsKey(attribute.GetHashCode()))
+ {
+ _foldoutStates.Add(attribute.GetHashCode(), false);
+ }
+
+ GUIStyle boldFoldoutStyle = new(EditorStyles.foldout)
+ {
+ fontStyle = FontStyle.Bold
+ };
+
+ if (!string.IsNullOrEmpty(attribute.HelpURL))
{
EditorGUILayout.BeginHorizontal();
- var newValueAsString = EditorGUILayout.TextField(CreateGUIContent(label, tooltip), value == null ? "" : value, GUILayout.ExpandWidth(true));
+ }
+
+ _foldoutStates[attribute.GetHashCode()] = EditorGUILayout.Foldout(_foldoutStates[attribute.GetHashCode()], foldoutContent, true, boldFoldoutStyle);
+
+ if (!string.IsNullOrEmpty(attribute.HelpURL))
+ {
+ GUILayout.FlexibleSpace();
+ RenderHelpIcon(attribute.HelpURL);
+ EditorGUILayout.EndHorizontal();
+ }
+
+ if (_foldoutStates[attribute.GetHashCode()])
+ {
+ RenderInputs(ref value);
+ }
+
+ return value;
+ }
+
+ static void HandleField(
+ object target,
+ ConfigFieldAttribute fieldDetails,
+ Func