using System; using System.Collections.Generic; using System.Runtime.CompilerServices; using System.Threading.Tasks; using UnityEngine; namespace Unity.Services.Core { /// /// Utility to initialize all Unity services from a single endpoint. /// public static class UnityServices { /// /// Invoked when initialization completes successfully. /// public static event Action Initialized { add { if (Instance != null) { Instance.Initialized += value; } } remove { if (Instance != null) { Instance.Initialized -= value; } } } /// /// Invoked when initialization fails. /// public static event Action InitializeFailed { add { if (Instance != null) { Instance.InitializeFailed += value; } } remove { if (Instance != null) { Instance.InitializeFailed -= value; } } } /// /// The main runtime instance of unity services. /// public static IUnityServices Instance { get; set; } /// /// The custom instances of unity services. /// public static IReadOnlyDictionary Services => s_Services; internal static TaskCompletionSource InstantiationCompletion { get; set; } internal static ExternalUserIdProperty ExternalUserIdProperty = new ExternalUserIdProperty(); static Dictionary s_Services { get; } = new Dictionary(); /// /// Initialization state. /// public static ServicesInitializationState State { get { if (!UnityThreadUtils.IsRunningOnUnityThread) { throw new ServicesInitializationException("You are attempting to access UnityServices.State from a non-Unity Thread." + " UnityServices.State can only be accessed from Unity Thread"); } if (Instance != null) { return Instance.State; } if (InstantiationCompletion?.Task.Status == TaskStatus.WaitingForActivation) { return ServicesInitializationState.Initializing; } return ServicesInitializationState.Uninitialized; } } /// /// ExternalUserId. /// Use this property to pass a user ID from a 3rd party identity provider to Unity Gaming Services /// public static string ExternalUserId { get => ExternalUserIdProperty.UserId; set => ExternalUserIdProperty.UserId = value; } /// public static Task InitializeAsync() { return InitializeAsync(new InitializationOptions()); } /// /// Single entry point to initialize all used services. /// /// /// The options to customize services initialization. /// /// /// Exception when there's an error during services initialization /// /// /// Exception when the project is not linked to a cloud project id /// /// /// Exception when two registered depend on the other. /// /// /// Return a handle to the initialization operation. /// [PreserveDependency("Register()", "Unity.Services.Core.Registration.CorePackageInitializer", "Unity.Services.Core.Registration")] [PreserveDependency("CreateStaticInstance()", "Unity.Services.Core.Internal.UnityServicesInitializer", "Unity.Services.Core.Internal")] [PreserveDependency("EnableServicesInitializationAsync()", "Unity.Services.Core.Internal.UnityServicesInitializer", "Unity.Services.Core.Internal")] [PreserveDependency("CaptureUnityThreadInfo()", "Unity.Services.Core.UnityThreadUtils", "Unity.Services.Core")] public static async Task InitializeAsync(InitializationOptions options) { if (!UnityThreadUtils.IsRunningOnUnityThread) { throw new ServicesInitializationException("You are attempting to initialize Unity Services from a non-Unity Thread." + " Unity Services can only be initialized from Unity Thread"); } if (!Application.isPlaying) { throw new ServicesInitializationException("You are attempting to initialize Unity Services in Edit Mode." + " Unity Services can only be initialized in Play Mode"); } if (Instance == null) { if (InstantiationCompletion == null) { InstantiationCompletion = new TaskCompletionSource(); } await InstantiationCompletion.Task; } await Instance.InitializeAsync(options); } /// /// Create a new services registry. Uses a Guid as identifier. /// /// /// Thrown when the services registry could not be created. /// /// The services registry instance public static IUnityServices CreateServices() { return CreateServices(Guid.NewGuid().ToString()); } /// /// Create a new services registry. /// /// Unique identifier for the services registry. Defaults to a GUID. /// /// Thrown when the services identifier is invalid. /// /// /// Thrown when the services registry could not be created. /// /// The services registry instance public static IUnityServices CreateServices(string servicesId) { if (string.IsNullOrEmpty(servicesId)) { throw new ArgumentException($"The services identifier cannot be null or empty"); } if (s_Services.ContainsKey(servicesId)) { throw new ServicesCreationException($"The services identifier '{servicesId}' is already registered."); } var services = UnityServicesBuilder.Create(servicesId); s_Services[servicesId] = services; return services; } internal static void ClearServices() { s_Services.Clear(); } } }