#if UNITY_2021_3_OR_NEWER // MIRROR CHANGE #if UNITY_EDITOR using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; using System.Web; using Edgegap.Editor.Api; using Edgegap.Editor.Api.Models; using Edgegap.Editor.Api.Models.Requests; using Edgegap.Editor.Api.Models.Results; using Edgegap.Codice.Utils; using UnityEditor; using UnityEditor.Build.Reporting; using UnityEngine; using UnityEngine.UIElements; using Application = UnityEngine.Application; using HttpUtility = Edgegap.Codice.Utils.HttpUtility; // MIRROR CHANGE for Unity 2023 support #if !EDGEGAP_PLUGIN_SERVERS using UnityEditor.Build; #endif namespace Edgegap.Editor { /// /// Editor logic event handler for "UI Builder" EdgegapWindow.uxml, superceding` EdgegapWindow.cs`. /// public class EdgegapWindowV2 : EditorWindow { #region Vars #region Filepaths internal string ProjectRootPath => Directory.GetCurrentDirectory(); internal string ThisScriptPath => Directory.GetFiles( ProjectRootPath, GetType().Name + ".cs", SearchOption.AllDirectories )[0]; #endregion #region State Variables public static bool IsLogLevelDebug => EdgegapWindowMetadata.LOG_LEVEL == EdgegapWindowMetadata.LogLevel.Debug; private bool _isApiTokenVerified; // Toggles the rest of the UI private GetRegistryCredentialsResult _credentials; private string _userExternalIp; private string _containerRegistryUrl; private string _containerProject; private string _containerUsername; private string _containerToken; private List _localImages = null; private List _storedAppNames = null; private List _storedAppVersions = null; EdgegapDeploymentsApi _deployAPI; #endregion #region UI private float ProgressCounter = 0; #region UI / Containers private VisualTreeAsset _visualTree; internal string _stylesheetPath => Path.GetDirectoryName( AssetDatabase.GetAssetPath(MonoScript.FromScriptableObject(this)) ); private Button _debugBtn; private VisualElement _postAuthContainer; #endregion #region UI / Containers / Connect private VisualElement _preAuthContainer; private VisualElement _authContainer; private Button _joinEdgegapDiscordBtn; #endregion #region UI / Connect / Pre-Auth private Button _edgegapSignInBtn; #endregion #region UI / Connect / Auth private Button _signOutBtn; private TextField _apiTokenInput; private string _apiToken => _apiTokenInput is null ? "" : _apiTokenInput.value.Trim(); private Button _apiTokenVerifyBtn; private Button _apiTokenGetBtn; #endregion #region UI / Build private Foldout _serverBuildFoldout; private Button _infoLinuxRequirementsBtn; private Button _installLinuxRequirementsBtn; private Label _linuxRequirementsResultLabel; private Button _buildParamsBtn; private TextField _buildFolderNameInput; internal string _buildFolderNameInputDefault => "EdgegapServer"; private Button _serverBuildBtn; private Label _serverBuildResultLabel; #endregion #region UI / Containerize private Foldout _containerizeFoldout; private Button _infoDockerRequirementsBtn; private Button _validateDockerRequirementsBtn; private Label _dockerRequirementsResultLabel; private TextField _buildPathInput; internal string _buildPathInputDefault => $"Builds/{_buildFolderNameInput.value}"; private Button _buildPathResetBtn; private TextField _containerizeImageNameInput; public string _containerizeImageNameInputDefault => Tokenize(Application.productName.ToLowerInvariant()); private TextField _containerizeImageTagInput; internal string _containerizeImageTagInputDefault => EdgegapWindowMetadata.DEFAULT_VERSION_TAG; internal string nowUTC => $"{DateTime.UtcNow.ToString("yy.MM.dd-HH.mm.ss")}-UTC"; private TextField _dockerfilePathInput; internal string _dockerfilePathInputDefault => $"{Directory.GetParent(ThisScriptPath).FullName}{Path.DirectorySeparatorChar}Dockerfile"; private Button _dockerfilePathResetBtn; private TextField _optionalDockerParamsInput; private Button _containerizeServerBtn; private Label _containerizeServerResultLabel; #endregion #region UI / Test private Foldout _localTestFoldout; private TextField _localTestImageInput; private Button _localTestImageShowDropdownBtn; private TextField _localTestDockerRunInput; internal string _localTestDockerRunInputDefault => "-p 7777/udp"; private Button _localTestDeployBtn; private Button _localTestTerminateBtn; private Button _localTestDiscordHelpBtn; private Label _localTestResultLabel; private Button _localTestInfoConnectBtn; #endregion #region UI / Upload App private Foldout _createAppFoldout; private TextField _createAppNameInput; private static readonly Regex _appNameAllowedCharsRegex = new Regex( @"^[a-zA-Z0-9_\-+\.]*$" ); private TextField _serverImageNameInput; private TextField _serverImageTagInput; private Button _portMappingLabelLink; private Button _uploadImageCreateAppBtn; private Button _appInfoLabelLink; private Button _createAppNameShowDropdownBtn; #endregion #region UI / Deploy private Foldout _deployAppFoldout; private TextField _deployAppNameInput; private TextField _deployAppVersionInput; private Button _deployLimitLabelLink; private Button _deployAppBtn; private Button _stopLastDeployBtn; private Button _discordHelpBtn; private Label _deployResultLabel; private Button _deployAppNameShowDropdownBtn; private Button _deployAppVersionShowDropdownBtn; #endregion #region UI / Next private Foldout _nextStepsFoldout; private Button _serverConnectLink; private Button _gen2MatchmakerLabelLink; private Button _lifecycleManageLabelLink; #endregion #endregion #endregion #region Unity Integration [MenuItem("Tools/Edgegap Hosting")] public static void ShowEdgegapToolWindow() { EdgegapWindowV2 window = GetWindow(); window.titleContent = new GUIContent("Edgegap Hosting"); // MIRROR CHANGE: 'Edgegap Server Management' is too long for the tab space window.maxSize = new Vector2(600, 900); window.minSize = window.maxSize; } // Compiler symbols can be used by other plugin developers to detect presence of Edgegap plugin [InitializeOnLoadMethod] public static void AddDefineSymbols() { // check if defined first, otherwise adding the symbol causes an infinite loop of recompilation #if !EDGEGAP_PLUGIN_SERVERS // Get data about current target group bool standaloneAndServer = false; BuildTarget buildTarget = EditorUserBuildSettings.activeBuildTarget; BuildTargetGroup buildTargetGroup = BuildPipeline.GetBuildTargetGroup(buildTarget); if (buildTargetGroup == BuildTargetGroup.Standalone) { StandaloneBuildSubtarget standaloneSubTarget = EditorUserBuildSettings.standaloneBuildSubtarget; if (standaloneSubTarget == StandaloneBuildSubtarget.Server) standaloneAndServer = true; } // Prepare named target, depending on above stuff NamedBuildTarget namedBuildTarget; if (standaloneAndServer) namedBuildTarget = NamedBuildTarget.Server; else namedBuildTarget = NamedBuildTarget.FromBuildTargetGroup(buildTargetGroup); // Set universal compiler macro PlayerSettings.SetScriptingDefineSymbols( namedBuildTarget, $"{PlayerSettings.GetScriptingDefineSymbols(namedBuildTarget)};{EdgegapWindowMetadata.KEY_COMPILER_MACRO}" ); #endif } protected void OnEnable() { #if UNITY_2021_3_OR_NEWER // only load stylesheet in supported Unity versions, otherwise it shows errors in U2020 // Set root VisualElement and style: V2 still uses EdgegapWindow.[uxml|uss] // BEGIN MIRROR CHANGE _visualTree = AssetDatabase.LoadAssetAtPath( $"{_stylesheetPath}{Path.DirectorySeparatorChar}EdgegapWindow.uxml" ); StyleSheet styleSheet = AssetDatabase.LoadAssetAtPath( $"{_stylesheetPath}{Path.DirectorySeparatorChar}EdgegapWindow.uss" ); // END MIRROR CHANGE rootVisualElement.styleSheets.Add(styleSheet); #endif } public async void CreateGUI() { // the UI requires 'GroupBox', which is not available in Unity 2019/2020. // showing it will break all of Unity's Editor UIs, not just this one. // instead, show a warning that the Edgegap plugin only works on Unity 2021+ #if !UNITY_2021_3_OR_NEWER Debug.LogWarning( "The Edgegap Hosting plugin requires UIToolkit in Unity 2021.3 or newer. Please upgrade your Unity version to use this." ); #else // Get UI elements from UI Builder rootVisualElement.Clear(); _visualTree.CloneTree(rootVisualElement); // Register callbacks and sync UI builder elements to fields here InitUIElements(); // TODO: Load persistent data? // Only show the rest of the form if apiToken is verified _postAuthContainer.SetEnabled(_isApiTokenVerified); await InitializeState(); // API calls #endif } /// The user closed the window. Save the data. protected void OnDisable() { #if UNITY_2021_3_OR_NEWER // only load stylesheet in supported Unity versions, otherwise it shows errors in U2020 // sometimes this is called without having been registered, throwing NRE unregisterUICallbacks(); #endif } #endregion // Unity Funcs #region Init & Cleanup /// /// Binds the form inputs to the associated variables and initializes the inputs as required. /// Requires the VisualElements to be loaded before this call. Otherwise, the elements cannot be found. /// private void InitUIElements() { setVisualElementsToFields(); closeDisableGroups(); registerUICallbacks(); initToggleDynamicUI(); } /// Set fields referencing UI Builder's fields. In order of appearance from top-to-bottom. private void setVisualElementsToFields() { _debugBtn = rootVisualElement.Q